Merge "Migrate IUsbGadget to AIDL"
diff --git a/audio/aidl/Android.bp b/audio/aidl/Android.bp
index d6e6f50..92d7d54 100644
--- a/audio/aidl/Android.bp
+++ b/audio/aidl/Android.bp
@@ -23,9 +23,18 @@
     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",
@@ -35,7 +44,6 @@
     imports: [
         "android.media.audio.common.types-V2",
     ],
-    stability: "vintf",
     backend: {
         cpp: {
             enabled: true,
@@ -87,19 +95,31 @@
     ],
 }
 
+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/IConfig.aidl",
         "android/hardware/audio/core/IModule.aidl",
         "android/hardware/audio/core/IStreamIn.aidl",
         "android/hardware/audio/core/IStreamOut.aidl",
+        "android/hardware/audio/core/ITelephony.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",
     ],
     imports: [
         "android.hardware.common-V2",
@@ -107,7 +127,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: {
@@ -145,17 +164,37 @@
 
 aidl_interface {
     name: "android.hardware.audio.effect",
-    vendor_available: true,
+    defaults: [
+        "android.hardware.audio_defaults",
+    ],
     srcs: [
+        "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/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/Parameter.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",
+        "android/hardware/audio/effect/Visualizer.aidl",
+        "android/hardware/audio/effect/Volume.aidl",
     ],
     imports: [
+        "android.hardware.common-V2",
+        "android.hardware.common.fmq-V1",
         "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/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/AudioMode.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/AudioMode.aidl
new file mode 100644
index 0000000..336f9b5
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/AudioMode.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.audio.core;
+@Backing(type="int") @VintfStability
+enum AudioMode {
+  NORMAL = 0,
+  RINGTONE = 1,
+  IN_CALL = 2,
+  IN_COMMUNICATION = 3,
+  CALL_SCREEN = 4,
+}
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 fd80715..163b7a0 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
@@ -34,4 +34,5 @@
 package android.hardware.audio.core;
 @VintfStability
 interface IConfig {
+  android.hardware.audio.core.SurroundSoundConfig getSurroundSoundConfig();
 }
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 a8bbb15..be382c5 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
@@ -35,6 +35,7 @@
 @VintfStability
 interface IModule {
   void setModuleDebug(in android.hardware.audio.core.ModuleDebug debug);
+  @nullable android.hardware.audio.core.ITelephony getTelephony();
   android.media.audio.common.AudioPort connectExternalDevice(in android.media.audio.common.AudioPort templateIdAndAdditionalData);
   void disconnectExternalDevice(int portId);
   android.hardware.audio.core.AudioPatch[] getAudioPatches();
@@ -49,6 +50,15 @@
   boolean setAudioPortConfig(in android.media.audio.common.AudioPortConfig requested, out android.media.audio.common.AudioPortConfig suggested);
   void resetAudioPatch(int patchId);
   void resetAudioPortConfig(int portConfigId);
+  boolean getMasterMute();
+  void setMasterMute(boolean mute);
+  float getMasterVolume();
+  void setMasterVolume(float volume);
+  boolean getMicMute();
+  void setMicMute(boolean mute);
+  void updateAudioMode(android.hardware.audio.core.AudioMode mode);
+  void updateScreenRotation(android.hardware.audio.core.IModule.ScreenRotation rotation);
+  void updateScreenState(boolean isTurnedOn);
   @VintfStability
   parcelable OpenInputStreamArguments {
     int portConfigId;
@@ -72,4 +82,11 @@
     android.hardware.audio.core.IStreamOut stream;
     android.hardware.audio.core.StreamDescriptor desc;
   }
+  @Backing(type="int") @VintfStability
+  enum ScreenRotation {
+    DEG_0 = 0,
+    DEG_90 = 1,
+    DEG_180 = 2,
+    DEG_270 = 3,
+  }
 }
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
new file mode 100644
index 0000000..a8c58c1
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ITelephony.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 ITelephony {
+  android.hardware.audio.core.AudioMode[] getSupportedAudioModes();
+  void switchAudioMode(android.hardware.audio.core.AudioMode mode);
+}
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 db1ac22..3a77ad1 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,16 +39,31 @@
   int frameSizeBytes;
   long bufferSizeFrames;
   android.hardware.audio.core.StreamDescriptor.AudioBuffer audio;
-  const int COMMAND_BURST = 1;
+  const int LATENCY_UNKNOWN = -1;
   @FixedSize @VintfStability
   parcelable Position {
     long frames;
     long timeNs;
   }
+  @Backing(type="int") @VintfStability
+  enum State {
+    STANDBY = 1,
+    IDLE = 2,
+    ACTIVE = 3,
+    PAUSED = 4,
+    DRAINING = 5,
+    DRAIN_PAUSED = 6,
+    ERROR = 100,
+  }
   @FixedSize @VintfStability
-  parcelable Command {
-    int code;
-    int fmqByteCount;
+  union Command {
+    int hal_reserved_exit;
+    android.media.audio.common.Void start;
+    int burst;
+    android.media.audio.common.Void drain;
+    android.media.audio.common.Void standby;
+    android.media.audio.common.Void pause;
+    android.media.audio.common.Void flush;
   }
   @FixedSize @VintfStability
   parcelable Reply {
@@ -57,6 +72,8 @@
     android.hardware.audio.core.StreamDescriptor.Position observable;
     android.hardware.audio.core.StreamDescriptor.Position hardware;
     int latencyMs;
+    int xrunFrames;
+    android.hardware.audio.core.StreamDescriptor.State state = android.hardware.audio.core.StreamDescriptor.State.STANDBY;
   }
   @VintfStability
   union AudioBuffer {
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/SurroundSoundConfig.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/SurroundSoundConfig.aidl
new file mode 100644
index 0000000..08a1537
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/SurroundSoundConfig.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;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable SurroundSoundConfig {
+  android.hardware.audio.core.SurroundSoundConfig.SurroundFormatFamily[] formatFamilies;
+  @VintfStability
+  parcelable SurroundFormatFamily {
+    android.media.audio.common.AudioFormatDescription primaryFormat;
+    android.media.audio.common.AudioFormatDescription[] subFormats;
+  }
+}
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
new file mode 100644
index 0000000..979ebb8
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/BassBoost.aidl
@@ -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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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 BassBoost {
+  android.hardware.audio.effect.VendorExtension vendor;
+  int strengthPm;
+  @VintfStability
+  union Id {
+    int vendorExtensionTag;
+    android.hardware.audio.effect.BassBoost.Tag commonTag;
+  }
+  @VintfStability
+  parcelable Capability {
+    ParcelableHolder extension;
+    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
new file mode 100644
index 0000000..06f2bfe
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Capability.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.audio.effect;
+@VintfStability
+union Capability {
+  android.hardware.audio.effect.VendorExtension vendorExtension;
+  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.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.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/CommandId.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/CommandId.aidl
new file mode 100644
index 0000000..79299ee
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/CommandId.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.audio.effect;
+@Backing(type="int") @VintfStability
+enum CommandId {
+  START = 0,
+  STOP = 1,
+  RESET = 2,
+  VENDOR_COMMAND_0 = 256,
+  VENDOR_COMMAND_1 = 257,
+  VENDOR_COMMAND_2 = 258,
+  VENDOR_COMMAND_3 = 259,
+  VENDOR_COMMAND_4 = 260,
+  VENDOR_COMMAND_5 = 261,
+  VENDOR_COMMAND_6 = 262,
+  VENDOR_COMMAND_7 = 263,
+  VENDOR_COMMAND_8 = 264,
+  VENDOR_COMMAND_9 = 265,
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Descriptor.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Descriptor.aidl
index 94cacd9..990d369 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Descriptor.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Descriptor.aidl
@@ -35,6 +35,7 @@
 @VintfStability
 parcelable Descriptor {
   android.hardware.audio.effect.Descriptor.Common common;
+  android.hardware.audio.effect.Capability capability;
   const String EFFECT_TYPE_UUID_ENV_REVERB = "c2e5d5f0-94bd-4763-9cac-4e234d06839e";
   const String EFFECT_TYPE_UUID_PRESET_REVERB = "47382d60-ddd8-11db-bf3a-0002a5d5c51b";
   const String EFFECT_TYPE_UUID_EQUALIZER = "0bed4300-ddd6-11db-8f34-0002a5d5c51b";
@@ -52,9 +53,15 @@
   parcelable Identity {
     android.media.audio.common.AudioUuid type;
     android.media.audio.common.AudioUuid uuid;
+    @nullable android.media.audio.common.AudioUuid proxy;
   }
   @VintfStability
   parcelable Common {
     android.hardware.audio.effect.Descriptor.Identity id;
+    android.hardware.audio.effect.Flags flags;
+    int cpuLoad;
+    int memoryUsage;
+    @utf8InCpp String name;
+    @utf8InCpp String implementor;
   }
 }
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Downmix.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Downmix.aidl
new file mode 100644
index 0000000..76f8ce5
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Downmix.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.audio.effect;
+@VintfStability
+union Downmix {
+  android.hardware.audio.effect.VendorExtension vendor;
+  android.hardware.audio.effect.Downmix.Type type;
+  @VintfStability
+  union Id {
+    int vendorExtensionTag;
+    android.hardware.audio.effect.Downmix.Tag commonTag;
+  }
+  @VintfStability
+  parcelable Capability {
+    ParcelableHolder extension;
+  }
+  @VintfStability
+  enum Type {
+    STRIP = 0,
+    FOLD = 1,
+  }
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/DynamicsProcessing.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/DynamicsProcessing.aidl
new file mode 100644
index 0000000..ed4dc80
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/DynamicsProcessing.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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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 DynamicsProcessing {
+  android.hardware.audio.effect.VendorExtension vendorExtension;
+  android.hardware.audio.effect.DynamicsProcessing.EngineArchitecture engineArchitecture;
+  android.hardware.audio.effect.DynamicsProcessing.BandChannelConfig preEq;
+  android.hardware.audio.effect.DynamicsProcessing.BandChannelConfig postEq;
+  android.hardware.audio.effect.DynamicsProcessing.EqBandConfig preEqBand;
+  android.hardware.audio.effect.DynamicsProcessing.EqBandConfig postEqBand;
+  android.hardware.audio.effect.DynamicsProcessing.BandChannelConfig mbc;
+  android.hardware.audio.effect.DynamicsProcessing.MbcBandConfig mbcBand;
+  android.hardware.audio.effect.DynamicsProcessing.LimiterConfig limiter;
+  float inputGainDb;
+  @VintfStability
+  union Id {
+    int vendorExtensionTag;
+    android.hardware.audio.effect.DynamicsProcessing.Tag commonTag;
+  }
+  @VintfStability
+  parcelable Capability {
+    ParcelableHolder extension;
+  }
+  enum ResolutionPreference {
+    FAVOR_FREQUENCY_RESOLUTION = 0,
+    FAVOR_TIME_RESOLUTION = 1,
+  }
+  @VintfStability
+  parcelable BandEnablement {
+    boolean inUse;
+    int bandCount;
+  }
+  @VintfStability
+  parcelable EngineArchitecture {
+    android.hardware.audio.effect.DynamicsProcessing.ResolutionPreference resolutionPreference = android.hardware.audio.effect.DynamicsProcessing.ResolutionPreference.FAVOR_FREQUENCY_RESOLUTION;
+    float preferredFrameDurationMs;
+    android.hardware.audio.effect.DynamicsProcessing.BandEnablement preEqBand;
+    android.hardware.audio.effect.DynamicsProcessing.BandEnablement postEqBand;
+    android.hardware.audio.effect.DynamicsProcessing.BandEnablement mbcBand;
+    boolean limiterInUse;
+  }
+  @VintfStability
+  parcelable BandChannelConfig {
+    int channel;
+    android.hardware.audio.effect.DynamicsProcessing.BandEnablement enablement;
+  }
+  @VintfStability
+  parcelable EqBandConfig {
+    int channel;
+    int band;
+    boolean enable;
+    float cutoffFrequency;
+    float gain;
+  }
+  @VintfStability
+  parcelable MbcBandConfig {
+    int channel;
+    int band;
+    boolean enable;
+    float cutoffFrequencyHz;
+    float gainDb;
+    float attackTimeMs;
+    float releaseTimeMs;
+    float ratio;
+    float thresholdDb;
+    float kneeWidthDb;
+    float noiseGateThresholdDb;
+    float expanderRatio;
+    float preGainDb;
+    float postGainDb;
+  }
+  @VintfStability
+  parcelable LimiterConfig {
+    int channel;
+    boolean enable;
+    boolean inUse;
+    int linkGroup;
+    float attackTimeMs;
+    float releaseTimeMs;
+    float ratio;
+    float thresholdDb;
+    float postGainDb;
+  }
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Equalizer.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Equalizer.aidl
new file mode 100644
index 0000000..d825eac
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Equalizer.aidl
@@ -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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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 Equalizer {
+  android.hardware.audio.effect.VendorExtension vendorExtension;
+  android.hardware.audio.effect.Equalizer.BandLevel[] bandLevels;
+  int preset;
+  @VintfStability
+  union Id {
+    int vendorExtensionTag;
+    android.hardware.audio.effect.Equalizer.Tag commonTag;
+  }
+  @VintfStability
+  parcelable Capability {
+    ParcelableHolder extension;
+    android.hardware.audio.effect.Equalizer.BandFrequency[] bandFrequencies;
+    android.hardware.audio.effect.Equalizer.Preset[] presets;
+  }
+  @VintfStability
+  parcelable BandLevel {
+    int index;
+    int levelMb;
+  }
+  @VintfStability
+  parcelable BandFrequency {
+    int index;
+    int minMh;
+    int maxMh;
+  }
+  @VintfStability
+  parcelable Preset {
+    int index;
+    @utf8InCpp String name;
+  }
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Flags.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Flags.aidl
new file mode 100644
index 0000000..285ff18
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Flags.aidl
@@ -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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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
+parcelable Flags {
+  android.hardware.audio.effect.Flags.Type type = android.hardware.audio.effect.Flags.Type.INSERT;
+  android.hardware.audio.effect.Flags.Insert insert = android.hardware.audio.effect.Flags.Insert.ANY;
+  android.hardware.audio.effect.Flags.Volume volume = android.hardware.audio.effect.Flags.Volume.NONE;
+  android.hardware.audio.effect.Flags.HardwareAccelerator hwAcceleratorMode = android.hardware.audio.effect.Flags.HardwareAccelerator.NONE;
+  boolean offloadIndication;
+  boolean deviceIndication;
+  boolean audioModeIndication;
+  boolean audioSourceIndication;
+  boolean noProcessing;
+  @Backing(type="byte") @VintfStability
+  enum Type {
+    INSERT = 0,
+    AUXILIARY = 1,
+    REPLACE = 2,
+    PRE_PROC = 3,
+    POST_PROC = 4,
+  }
+  @Backing(type="byte") @VintfStability
+  enum Insert {
+    ANY = 0,
+    FIRST = 1,
+    LAST = 2,
+    EXCLUSIVE = 3,
+  }
+  @Backing(type="byte") @VintfStability
+  enum Volume {
+    NONE = 0,
+    CTRL = 1,
+    IND = 2,
+    MONITOR = 3,
+  }
+  @Backing(type="byte") @VintfStability
+  enum HardwareAccelerator {
+    NONE = 0,
+    SIMPLE = 1,
+    TUNNEL = 2,
+  }
+}
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
new file mode 100644
index 0000000..40a8d72
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/HapticGenerator.aidl
@@ -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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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 HapticGenerator {
+  android.hardware.audio.effect.VendorExtension vendorExtension;
+  android.hardware.audio.effect.HapticGenerator.HapticScale hapticScale;
+  android.hardware.audio.effect.HapticGenerator.VibratorInformation vibratorInfo;
+  @VintfStability
+  union Id {
+    int vendorExtensionTag;
+    android.hardware.audio.effect.HapticGenerator.Tag commonTag;
+  }
+  @VintfStability
+  parcelable Capability {
+    android.hardware.audio.effect.VendorExtension extension;
+  }
+  @Backing(type="int") @VintfStability
+  enum VibratorScale {
+    MUTE = -100,
+    VERY_LOW = -2,
+    LOW = -1,
+    NONE = 0,
+    HIGH = 1,
+    VERY_HIGH = 2,
+  }
+  @VintfStability
+  parcelable HapticScale {
+    int id;
+    android.hardware.audio.effect.HapticGenerator.VibratorScale scale = android.hardware.audio.effect.HapticGenerator.VibratorScale.MUTE;
+  }
+  @VintfStability
+  parcelable VibratorInformation {
+    float resonantFrequencyHz;
+    float qFactor;
+    float maxAmplitude;
+  }
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/IEffect.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/IEffect.aidl
index 7f868ad..8c196e7 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/IEffect.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/IEffect.aidl
@@ -34,7 +34,23 @@
 package android.hardware.audio.effect;
 @VintfStability
 interface IEffect {
-  void open();
+  android.hardware.audio.effect.IEffect.OpenEffectReturn open(in android.hardware.audio.effect.Parameter.Common common, in @nullable android.hardware.audio.effect.Parameter.Specific specific);
   void close();
   android.hardware.audio.effect.Descriptor getDescriptor();
+  void command(in android.hardware.audio.effect.CommandId commandId);
+  android.hardware.audio.effect.State getState();
+  void setParameter(in android.hardware.audio.effect.Parameter param);
+  android.hardware.audio.effect.Parameter getParameter(in android.hardware.audio.effect.Parameter.Id paramId);
+  @FixedSize @VintfStability
+  parcelable Status {
+    int status;
+    int fmqConsumed;
+    int fmqProduced;
+  }
+  @VintfStability
+  parcelable OpenEffectReturn {
+    android.hardware.common.fmq.MQDescriptor<android.hardware.audio.effect.IEffect.Status,android.hardware.common.fmq.SynchronizedReadWrite> statusMQ;
+    android.hardware.common.fmq.MQDescriptor<float,android.hardware.common.fmq.SynchronizedReadWrite> inputDataMQ;
+    android.hardware.common.fmq.MQDescriptor<float,android.hardware.common.fmq.SynchronizedReadWrite> outputDataMQ;
+  }
 }
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 db06475..5b85d33 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,8 @@
 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);
+  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.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/LoudnessEnhancer.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/LoudnessEnhancer.aidl
new file mode 100644
index 0000000..5c6ca16
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/LoudnessEnhancer.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.audio.effect;
+@VintfStability
+union LoudnessEnhancer {
+  android.hardware.audio.effect.VendorExtension vendor;
+  int gainMb;
+  @VintfStability
+  union Id {
+    int vendorExtensionTag;
+    android.hardware.audio.effect.LoudnessEnhancer.Tag commonTag;
+  }
+  @VintfStability
+  parcelable Capability {
+    android.hardware.audio.effect.VendorExtension extension;
+  }
+}
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
new file mode 100644
index 0000000..321c286
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Parameter.aidl
@@ -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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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 Parameter {
+  android.hardware.audio.effect.Parameter.Common common;
+  android.media.audio.common.AudioDeviceDescription deviceDescription;
+  android.media.audio.common.AudioMode mode;
+  android.media.audio.common.AudioSource source;
+  android.hardware.audio.effect.Parameter.VolumeStereo volumeStereo;
+  android.hardware.audio.effect.Parameter.Specific specific;
+  @VintfStability
+  union Id {
+    int vendorEffectTag;
+    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.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.Virtualizer.Id virtualizerTag;
+    android.hardware.audio.effect.Visualizer.Id visualizerTag;
+    android.hardware.audio.effect.Volume.Id volumeTag;
+    android.hardware.audio.effect.Parameter.Tag commonTag;
+  }
+  @VintfStability
+  parcelable Common {
+    int session;
+    int ioHandle;
+    android.media.audio.common.AudioConfig input;
+    android.media.audio.common.AudioConfig output;
+  }
+  @VintfStability
+  parcelable VolumeStereo {
+    float left;
+    float right;
+  }
+  @VintfStability
+  union Specific {
+    android.hardware.audio.effect.VendorExtension vendorEffect;
+    android.hardware.audio.effect.BassBoost bassBoost;
+    android.hardware.audio.effect.Downmix downmix;
+    android.hardware.audio.effect.DynamicsProcessing dynamicsProcessing;
+    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.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/Processing.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Processing.aidl
new file mode 100644
index 0000000..a779ae4
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Processing.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.audio.effect;
+@VintfStability
+parcelable Processing {
+  android.hardware.audio.effect.Processing.Type type;
+  android.hardware.audio.effect.Descriptor.Identity[] ids;
+  @VintfStability
+  union Type {
+    android.media.audio.common.AudioStreamType streamType = android.media.audio.common.AudioStreamType.INVALID;
+    android.media.audio.common.AudioSource source;
+  }
+}
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
new file mode 100644
index 0000000..8ad4848
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.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 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/State.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/State.aidl
new file mode 100644
index 0000000..3176b01
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/State.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.effect;
+@Backing(type="byte") @VintfStability
+enum State {
+  INIT = 0,
+  IDLE = 1,
+  PROCESSING = 2,
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/VendorExtension.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/VendorExtension.aidl
new file mode 100644
index 0000000..b806334
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/VendorExtension.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.effect;
+@VintfStability
+parcelable VendorExtension {
+  ParcelableHolder extension;
+}
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
new file mode 100644
index 0000000..d4fb9e0
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Virtualizer.aidl
@@ -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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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 Virtualizer {
+  android.hardware.audio.effect.VendorExtension vendor;
+  int strengthPm;
+  @VintfStability
+  union Id {
+    int vendorExtensionTag;
+    android.hardware.audio.effect.Virtualizer.Tag commonTag;
+  }
+  @VintfStability
+  parcelable Capability {
+    android.hardware.audio.effect.VendorExtension extension;
+    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
new file mode 100644
index 0000000..9ee19f0
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Visualizer.aidl
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 Visualizer {
+  android.hardware.audio.effect.Visualizer.Id id;
+  android.hardware.audio.effect.VendorExtension vendor;
+  android.hardware.audio.effect.Visualizer.GetOnlyParameters getOnlyParameters;
+  android.hardware.audio.effect.Visualizer.SetOnlyParameters setOnlyParameters;
+  int captureSizeBytes;
+  android.hardware.audio.effect.Visualizer.ScalingMode scalingMode;
+  android.hardware.audio.effect.Visualizer.MeasurementMode measurementMode;
+  @VintfStability
+  union Id {
+    int vendorExtensionTag;
+    android.hardware.audio.effect.Visualizer.GetOnlyParameters.Tag getOnlyParamTag;
+    android.hardware.audio.effect.Visualizer.SetOnlyParameters.Tag setOnlyParamTag;
+    android.hardware.audio.effect.Visualizer.Tag commonTag;
+  }
+  @VintfStability
+  parcelable Capability {
+    android.hardware.audio.effect.VendorExtension extension;
+    int maxLatencyMs;
+    android.hardware.audio.effect.Visualizer.CaptureSizeRange captureSizeRange;
+  }
+  @VintfStability
+  parcelable CaptureSizeRange {
+    int minBytes;
+    int maxBytes;
+  }
+  @VintfStability
+  enum ScalingMode {
+    NORMALIZED = 0,
+    AS_PLAYED = 1,
+  }
+  @VintfStability
+  enum MeasurementMode {
+    NONE = 0,
+    PEAK_RMS = 1,
+  }
+  @VintfStability
+  union GetOnlyParameters {
+    android.hardware.audio.effect.Visualizer.GetOnlyParameters.Measurement measurement;
+    byte[] captureBytes;
+    @VintfStability
+    parcelable Measurement {
+      int rms;
+      int peak;
+    }
+  }
+  @VintfStability
+  union SetOnlyParameters {
+    int latencyMs;
+  }
+}
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
new file mode 100644
index 0000000..8c836b0
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Volume.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.audio.effect;
+@VintfStability
+union Volume {
+  android.hardware.audio.effect.VendorExtension vendor;
+  int levelDb;
+  boolean mute;
+  @VintfStability
+  union Id {
+    int vendorExtensionTag;
+    android.hardware.audio.effect.Volume.Tag commonTag;
+  }
+  @VintfStability
+  parcelable Capability {
+    android.hardware.audio.effect.VendorExtension extension;
+    int maxLevel;
+  }
+}
diff --git a/audio/aidl/android/hardware/audio/core/AudioMode.aidl b/audio/aidl/android/hardware/audio/core/AudioMode.aidl
new file mode 100644
index 0000000..0943a55
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/AudioMode.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.
+ */
+
+package android.hardware.audio.core;
+
+/**
+ * The audio mode describes states of the audio system of the device that
+ * can significantly affect the rules of audio routing, volume control, etc.
+ * The audio mode is controlled by the framework, however the HAL has some
+ * flexibility in the choice of modes to support, see 'IModule.updateAudioMode'.
+ */
+@VintfStability
+@Backing(type="int")
+enum AudioMode {
+    /** No active calls. */
+    NORMAL = 0,
+    /** The device is playing the ringtone. */
+    RINGTONE = 1,
+    /** The call is handled by the telephony stack ("voice call"). */
+    IN_CALL = 2,
+    /** The call is handled by an application ("VoIP call"). */
+    IN_COMMUNICATION = 3,
+    /** Call screening is in progress. */
+    CALL_SCREEN = 4,
+}
diff --git a/audio/aidl/android/hardware/audio/core/IConfig.aidl b/audio/aidl/android/hardware/audio/core/IConfig.aidl
index c7bb414..c8ba6be 100644
--- a/audio/aidl/android/hardware/audio/core/IConfig.aidl
+++ b/audio/aidl/android/hardware/audio/core/IConfig.aidl
@@ -16,9 +16,22 @@
 
 package android.hardware.audio.core;
 
+import android.hardware.audio.core.SurroundSoundConfig;
+
 /**
  * This interface provides system-wide configuration parameters for audio I/O
  * (by "system" here we mean the device running Android).
  */
 @VintfStability
-interface IConfig {}
+interface IConfig {
+    /**
+     * Returns the surround sound configuration used for the Audio Policy
+     * Manager initial configuration.
+     *
+     * This method will only be called during the initialization of the Audio
+     * Policy Manager, and must always return the same result.
+     *
+     * @return The surround sound configuration
+     */
+    SurroundSoundConfig getSurroundSoundConfig();
+}
diff --git a/audio/aidl/android/hardware/audio/core/IModule.aidl b/audio/aidl/android/hardware/audio/core/IModule.aidl
index 735f87f..be40051 100644
--- a/audio/aidl/android/hardware/audio/core/IModule.aidl
+++ b/audio/aidl/android/hardware/audio/core/IModule.aidl
@@ -18,10 +18,12 @@
 
 import android.hardware.audio.common.SinkMetadata;
 import android.hardware.audio.common.SourceMetadata;
+import android.hardware.audio.core.AudioMode;
 import android.hardware.audio.core.AudioPatch;
 import android.hardware.audio.core.AudioRoute;
 import android.hardware.audio.core.IStreamIn;
 import android.hardware.audio.core.IStreamOut;
+import android.hardware.audio.core.ITelephony;
 import android.hardware.audio.core.ModuleDebug;
 import android.hardware.audio.core.StreamDescriptor;
 import android.media.audio.common.AudioOffloadInfo;
@@ -60,6 +62,19 @@
     void setModuleDebug(in ModuleDebug debug);
 
     /**
+     * Retrieve the interface to control telephony audio.
+     *
+     * If the HAL module supports telephony functions, it must return an
+     * instance of the ITelephony interface. The same instance must be returned
+     * during the lifetime of the HAL module. If the HAL module does not support
+     * telephony, a null must be returned, without throwing any errors.
+     *
+     * @return An instance of the ITelephony interface implementation.
+     * @throws EX_ILLEGAL_STATE If there was an error creating an instance.
+     */
+    @nullable ITelephony getTelephony();
+
+    /**
      * 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
@@ -263,6 +278,9 @@
      * be completing with an error, although data (zero filled) will still be
      * provided.
      *
+     * After the stream has been opened, it remains in the STANDBY state, see
+     * StreamDescriptor for more details.
+     *
      * @return An opened input stream and the associated descriptor.
      * @param args The pack of arguments, see 'OpenInputStreamArguments' parcelable.
      * @throws EX_ILLEGAL_ARGUMENT In the following cases:
@@ -325,6 +343,9 @@
      * StreamDescriptor will be completing with an error, although the data
      * will still be accepted and immediately discarded.
      *
+     * After the stream has been opened, it remains in the STANDBY state, see
+     * StreamDescriptor for more details.
+     *
      * @return An opened output stream and the associated descriptor.
      * @param args The pack of arguments, see 'OpenOutputStreamArguments' parcelable.
      * @throws EX_ILLEGAL_ARGUMENT In the following cases:
@@ -481,4 +502,140 @@
      *                          - If the port config is used by a patch.
      */
     void resetAudioPortConfig(int portConfigId);
+
+    /**
+     * Get the current state of audio output muting.
+     *
+     * If the HAL module supports muting its combined output completely,
+     * this method returns whether muting is currently enabled.
+     *
+     * Note that muting operates independently from the master volume.
+     *
+     * @return Whether the output from the module is muted.
+     * @throws EX_UNSUPPORTED_OPERATION If muting of combined output
+     *                                  is not supported by the module.
+     */
+    boolean getMasterMute();
+
+    /**
+     * Set the current value of the audio output muting.
+     *
+     * If the HAL module supports muting its combined output completely, this
+     * method controls the mute. Note that for modules supporting telephony,
+     * muting does not affect the voice call.
+     *
+     * For HAL modules not supporting this operation, it's functionality is
+     * typically emulated by the client, in the digital domain.
+     *
+     * @param mute Whether the output from the module is muted.
+     * @throws EX_UNSUPPORTED_OPERATION If muting of combined output
+     *                                  is not supported by the module.
+     */
+    void setMasterMute(boolean mute);
+
+    /**
+     * Get the current value of the audio output attenuation.
+     *
+     * If the HAL module supports attenuating the level its combined output,
+     * this method returns the current attenuation value.
+     *
+     * @return Volume 1.0f means no attenuation (unity), 0.0f is mute.
+     * @throws EX_UNSUPPORTED_OPERATION If attenuation of combined output
+     *                                  is not supported by the module.
+     */
+    float getMasterVolume();
+
+    /**
+     * Set the current value of the audio output attenuation.
+     *
+     * If the HAL module supports attenuating the level its combined output,
+     * this method sets the attenuation value. Note that for modules supporting
+     * telephony, the attenuation of the voice call volume is set separately
+     * via ITelephony interface.
+     *
+     * For HAL modules not supporting this operation, it's functionality is
+     * typically emulated by the client, in the digital domain.
+     *
+     * @param volume The new value, 1.0f means no attenuation (unity), 0.0f is mute.
+     * @throws EX_ILLEGAL_ARGUMENT If the value of the volume is outside of
+     *                             accepted range.
+     * @throws EX_UNSUPPORTED_OPERATION If attenuation of combined output
+     *                                  is not supported by the module.
+     */
+    void setMasterVolume(float volume);
+
+    /**
+     * Get the current state of audio input muting.
+     *
+     * If the HAL module supports muting its external input, this method returns
+     * whether muting is currently enabled.
+     *
+     * @return Whether the input is muted.
+     * @throws EX_UNSUPPORTED_OPERATION If muting of input is not supported by
+     *                                  the module.
+     */
+    boolean getMicMute();
+
+    /**
+     * Set the current value of the audio input muting.
+     *
+     * If the HAL module supports muting its external input, this method
+     * controls the mute.
+     *
+     * For HAL modules not supporting this operation, it's functionality is
+     * emulated by the client.
+     *
+     * @param mute Whether input is muted.
+     * @throws EX_UNSUPPORTED_OPERATION If muting of input is not supported by
+     *                                  the module.
+     */
+    void setMicMute(boolean mute);
+
+    /**
+     * 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
+     * informative notification sent to all modules, no reply is needed. The HAL
+     * module should silently ignore this notification if it does not need to
+     * be aware of the current audio mode.
+     *
+     * The client sends this notification to all HAL modules after successfully
+     * switching the telephony module by calling the 'ITelephony.switchAudioMode'
+     * method.
+     *
+     * @param mode The current mode.
+     */
+    void updateAudioMode(AudioMode mode);
+
+    @VintfStability
+    @Backing(type="int")
+    enum ScreenRotation {
+        /** Natural orientation. */
+        DEG_0 = 0,
+        DEG_90 = 1,
+        /** Upside down. */
+        DEG_180 = 2,
+        DEG_270 = 3,
+    }
+    /**
+     * Notify the HAL module on the change of the screen rotation.
+     *
+     * Informs the HAL of the current orientation of the device screen. This
+     * information can be used to optimize the output of built-in speakers.
+     * This is an informative notification sent to all modules, no reply is
+     * needed.
+     *
+     * @param rotation The current rotation.
+     */
+    void updateScreenRotation(ScreenRotation rotation);
+
+    /**
+     * Notify the HAL module on the change of the screen state.
+     *
+     * Informs the HAL whether the screen of the device is turned on. This is an
+     * informative notification sent to all modules, no reply is needed.
+     *
+     * @param isTurnedOn True if the screen is turned on.
+     */
+    void updateScreenState(boolean isTurnedOn);
 }
diff --git a/audio/aidl/android/hardware/audio/core/ITelephony.aidl b/audio/aidl/android/hardware/audio/core/ITelephony.aidl
new file mode 100644
index 0000000..a872c7c
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/ITelephony.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.audio.core;
+
+import android.hardware.audio.core.AudioMode;
+
+/**
+ * An instance of ITelephony manages settings which are specific to voice calls
+ * and SMS messaging functionality. This interface is optional to implement and
+ * provide by the vendor. It needs to be provided only if the device actually
+ * supports telephony.
+ */
+@VintfStability
+interface ITelephony {
+    /**
+     * Return the list of supported audio modes.
+     *
+     * The first 4 AudioModes: NORMAL, RINGTONE, IN_CALL, IN_COMMUNICATION must
+     * be supported by all implementations.
+     *
+     * This method is only called once, during the audio system initialization,
+     * and must return the same result all the time.
+     *
+     * @return The list of supported audio modes.
+     */
+    AudioMode[] getSupportedAudioModes();
+
+    /**
+     * Switch the HAL into a new audio mode.
+     *
+     * The current audio mode is always controlled by the client. The HAL must
+     * accept all modes returned by 'getSupportedAudioModes' and reject the
+     * rest. The HAL must return from this method only after switching itself
+     * to the specified mode, or throw an error if there was a problem during
+     * switching.
+     *
+     * @param mode The mode to switch to.
+     * @throws EX_UNSUPPORTED_OPERATION If the HAL does not support the specified mode.
+     * @throws EX_ILLEGAL_STATE If there was an error during switching.
+     */
+    void switchAudioMode(AudioMode mode);
+}
diff --git a/audio/aidl/android/hardware/audio/core/StreamDescriptor.aidl b/audio/aidl/android/hardware/audio/core/StreamDescriptor.aidl
index 2b1ed8c..2b1fc99 100644
--- a/audio/aidl/android/hardware/audio/core/StreamDescriptor.aidl
+++ b/audio/aidl/android/hardware/audio/core/StreamDescriptor.aidl
@@ -19,6 +19,7 @@
 import android.hardware.audio.core.MmapBufferDescriptor;
 import android.hardware.common.fmq.MQDescriptor;
 import android.hardware.common.fmq.SynchronizedReadWrite;
+import android.media.audio.common.Void;
 
 /**
  * Stream descriptor contains fast message queues and buffers used for sending
@@ -33,6 +34,72 @@
  * internal components of the stream while serving commands invoked via the
  * stream's AIDL interface and commands invoked via the command queue of the
  * descriptor.
+ *
+ * There is a state machine defined for the stream, which executes on the
+ * thread handling the commands from the queue. The states are defined based
+ * on the model of idealized producer and consumer connected via a ring buffer.
+ * For input streams, the "producer" is hardware, the "consumer" is software,
+ * for outputs streams it's the opposite. When the producer is active, but
+ * the buffer is full, the following actions are possible:
+ *  - if the consumer is active, the producer blocks until there is space,
+ *    this behavior is only possible for software producers;
+ *  - if the consumer is passive:
+ *    - the producer can preserve the buffer contents—a s/w producer can
+ *      keep the data on their side, while a h/w producer can only drop captured
+ *      data in this case;
+ *    - or the producer overwrites old data in the buffer.
+ * Similarly, when an active consumer faces an empty buffer, it can:
+ *  - block until there is data (producer must be active), only possible
+ *    for software consumers;
+ *  - walk away with no data; when the consumer is hardware, it must emit
+ *    silence in this case.
+ *
+ * The model is defined below, note the asymmetry regarding the 'IDLE' state
+ * between input and output streams:
+ *
+ *  Producer | Buffer state | Consumer | Applies | State
+ *  active?  |              | active?  | to      |
+ * ==========|==============|==========|=========|==============================
+ *  No       | Empty        | No       | Both    | STANDBY
+ * ----------|--------------|----------|---------|-----------------------------
+ *  Yes      | Filling up   | No       | Input   | IDLE, overwrite behavior
+ * ----------|--------------|----------|---------|-----------------------------
+ *  No       | Empty        | Yes†     | Output  | IDLE, h/w emits silence
+ * ----------|--------------|----------|---------|-----------------------------
+ *  Yes      | Not empty    | Yes      | Both    | ACTIVE, s/w x-runs counted
+ * ----------|--------------|----------|---------|-----------------------------
+ *  Yes      | Filling up   | No       | Input   | PAUSED, drop behavior
+ * ----------|--------------|----------|---------|-----------------------------
+ *  Yes      | Filling up   | No†      | Output  | PAUSED, s/w stops writing once
+ *           |              |          |         | the buffer is filled up;
+ *           |              |          |         | h/w emits silence.
+ * ----------|--------------|----------|---------|-----------------------------
+ *  No       | Not empty    | Yes      | Both    | DRAINING
+ * ----------|--------------|----------|---------|-----------------------------
+ *  No       | Not empty    | No†      | Output  | DRAIN_PAUSED,
+ *           |              |          |         | h/w emits silence.
+ *
+ * † - note that for output, "buffer empty, h/w consuming" has the same outcome
+ *     as "buffer not empty, h/w not consuming", but logically these conditions
+ *     are different.
+ *
+ * State machines of both input and output streams start from the 'STANDBY'
+ * 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.
+ *
+ * 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
+ * commands (from the enum 'CommandCode') trigger state changes. The full list
+ * of states and commands is defined by constants of the 'State' enum. Note that
+ * the 'CLOSED' state does not have a constant in the interface because the
+ * 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.
  */
 @JavaDerive(equals=true, toString=true)
 @VintfStability
@@ -55,30 +122,97 @@
         long timeNs;
     }
 
-    /**
-     * The command used for audio I/O, see 'AudioBuffer'. For MMap No IRQ mode
-     * this command only provides updated positions and latency because actual
-     * audio I/O is done via the 'AudioBuffer.mmap' shared buffer.
-     */
-    const int COMMAND_BURST = 1;
+    @VintfStability
+    @Backing(type="int")
+    enum State {
+        /**
+         * 'STANDBY' is the initial state of the stream, entered after
+         * opening. Since both the producer and the consumer are inactive in
+         * this state, it allows the HAL module to put associated hardware into
+         * "standby" mode to save power.
+         */
+        STANDBY = 1,
+        /**
+         * In the 'IDLE' state the audio hardware is active. For input streams,
+         * the hardware is filling buffer with captured data, overwriting old
+         * contents on buffer wraparounds. For output streams, the buffer is
+         * still empty, and the hardware is outputting zeroes. The HAL module
+         * must not account for any under- or overruns as the client is not
+         * expected to perform audio I/O.
+         */
+        IDLE = 2,
+        /**
+         * The active state of the stream in which it handles audio I/O. The HAL
+         * module can assume that the audio I/O will be periodic, thus inability
+         * of the client to provide or consume audio data on time must be
+         * considered as an under- or overrun and indicated via the 'xrunFrames'
+         * field of the reply.
+         */
+        ACTIVE = 3,
+        /**
+         * In the 'PAUSED' state the consumer is inactive. For input streams,
+         * the hardware stops updating the buffer as soon as it fills up (this
+         * is the difference from the 'IDLE' state). For output streams,
+         * "inactivity" of hardware means that it does not consume audio data,
+         * but rather emits silence.
+         */
+        PAUSED = 4,
+        /**
+         * In the 'DRAINING' state the producer is inactive, the consumer is
+         * finishing up on the buffer contents, emptying it up. As soon as it
+         * gets empty, the stream transfers itself into the next state.
+         */
+        DRAINING = 5,
+        /**
+         * 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
+         * into the regular 'PAUSED' state.
+         */
+        DRAIN_PAUSED = 6,
+        /**
+         * 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.
+         */
+        ERROR = 100,
+    }
 
     /**
      * 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
      * command.
+     *
+     * Variants of type 'Void' correspond to commands without
+     * arguments. Variants of other types correspond to commands with an
+     * argument. Would in future a need for a command with multiple argument
+     * arise, a Parcelable type should be used for the corresponding variant.
      */
     @VintfStability
     @FixedSize
-    parcelable Command {
+    union Command {
         /**
-         * One of COMMAND_* codes.
+         * Reserved for the HAL implementation to allow unblocking the wait on a
+         * command and exiting the I/O thread. A command of this variant must
+         * never be sent from the client side. To prevent that, the
+         * implementation must pass a random cookie as the command argument,
+         * which is only known to the implementation.
          */
-        int code;
+        int hal_reserved_exit;
         /**
-         * For output streams: the amount of bytes that the client requests the
-         *   HAL module to read from the 'audio.fmq' queue.
-         * For input streams: the amount of bytes requested by the client to
-         *   read from the hardware into the 'audio.fmq' queue.
+         * See the state machines on the applicability of this command to
+         * different states.
+         */
+        Void start;
+        /**
+         * The 'burst' command used for audio I/O, see 'AudioBuffer'. The value
+         * specifies:
+         *
+         *  - for output streams: the amount of bytes that the client requests the
+         *    HAL module to use out of the data contained in the 'audio.fmq' queue.
+         *
+         *  - for input streams: the amount of bytes requested by the client to
+         *    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
@@ -90,12 +224,54 @@
          * 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:
+         *
+         *  - this command only provides updated positions and latency because
+         *    actual audio I/O is done via the 'AudioBuffer.mmap' shared buffer.
+         *    The client does not synchronize reads and writes into the buffer
+         *    with sending of this command.
+         *
+         *  - the value must always be set to 0.
          */
-        int fmqByteCount;
+        int burst;
+        /**
+         * See the state machines on the applicability of this command to
+         * different states.
+         */
+        Void drain;
+        /**
+         * See the state machines on the applicability of this command to
+         * different states.
+         *
+         * Note that it's left on the discretion of the HAL implementation to
+         * assess all the necessary conditions that could prevent hardware from
+         * being suspended. Even if it can not be suspended, the state machine
+         * must still enter the 'STANDBY' state for consistency. Since the
+         * buffer must remain empty in this state, even if capturing hardware is
+         * still active, captured data must be discarded.
+         */
+        Void standby;
+        /**
+         * See the state machines on the applicability of this command to
+         * different states.
+         */
+        Void pause;
+        /**
+         * See the state machines on the applicability of this command to
+         * different states.
+         */
+        Void flush;
     }
     MQDescriptor<Command, SynchronizedReadWrite> command;
 
     /**
+     * The value used for the 'Reply.latencyMs' field when the effective
+     * latency can not be reported by the HAL module.
+     */
+    const int LATENCY_UNKNOWN = -1;
+
+    /**
      * Used for providing replies to commands. The HAL module writes into
      * the queue, the client reads. The queue can only contain a single reply,
      * corresponding to the last command sent by the client.
@@ -107,29 +283,42 @@
          * 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_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;
-         *
          */
         int status;
         /**
-         * For output streams: the amount of bytes actually consumed by the HAL
-         *   module from the 'audio.fmq' queue.
+         * Used with the 'burst' command only.
+         *
+         * For output streams: the amount of bytes of data actually consumed
+         *   by the HAL module.
          * For input streams: the amount of bytes actually provided by the HAL
          *   in the 'audio.fmq' queue.
          *
-         * The returned value must not exceed the value passed in the
-         * 'fmqByteCount' field of the corresponding command or be negative.
+         * The returned value must not exceed the value passed as the
+         * argument of the corresponding command, or be negative.
          */
         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'.
+         *
          * For output streams: the moment when the specified stream position
          *   was presented to an external observer (i.e. presentation position).
          * For input streams: the moment when data at the specified stream position
          *   was acquired (i.e. capture position).
+         *
+         * The observable position must never be reset by the HAL module.
+         * The data type of the frame counter is large enough to support
+         * continuous counting for years of operation.
          */
         Position observable;
         /**
@@ -138,9 +327,22 @@
          */
         Position hardware;
         /**
-         * Current latency reported by the hardware.
+         * Current latency reported by the hardware. It is recommended to
+         * report the current latency for any command. If the value of latency
+         * can not be determined, this field must be set to 'LATENCY_UNKNOWN'.
          */
         int latencyMs;
+        /**
+         * Number of frames lost due to an underrun (for input streams),
+         * or not provided on time (for output streams) for the **previous**
+         * transfer operation.
+         */
+        int xrunFrames;
+        /**
+         * The state that the stream was in while the HAL module was sending the
+         * reply.
+         */
+        State state = State.STANDBY;
     }
     MQDescriptor<Reply, SynchronizedReadWrite> reply;
 
@@ -170,42 +372,59 @@
     @VintfStability
     union AudioBuffer {
         /**
-         * The fast message queue used for all modes except MMap No IRQ.  Both
-         * reads and writes into this queue are non-blocking because access to
-         * this queue is synchronized via the 'command' and 'reply' queues as
-         * described below. The queue nevertheless uses 'SynchronizedReadWrite'
-         * because there is only one reader, and the reading position must be
-         * shared.
+         * The fast message queue used for BURST commands in all modes except
+         * MMap No IRQ. Both reads and writes into this queue are non-blocking
+         * because access to this queue is synchronized via the 'command' and
+         * 'reply' queues as described below. The queue nevertheless uses
+         * 'SynchronizedReadWrite' because there is only one reader, and the
+         * reading position must be shared.
+         *
+         * Note that the fast message queue is a transient buffer, only used for
+         * data transfer. Neither of the sides can use it to store any data
+         * outside of the 'BURST' operation. The consumer must always retrieve
+         * all data available in the fast message queue, even if it can not use
+         * it. The producer must re-send any unconsumed data on the next
+         * transfer operation. This restriction is posed in order to make the
+         * fast message queue fully transparent from the latency perspective.
          *
          * For output streams the following sequence of operations is used:
          *  1. The client writes audio data into the 'audio.fmq' queue.
-         *  2. The client writes the 'BURST' command into the 'command' queue,
+         *  2. The client writes the BURST command into the 'command' queue,
          *     and hangs on waiting on a read from the 'reply' queue.
          *  3. The high priority thread in the HAL module wakes up due to 2.
-         *  4. The HAL module reads the command and audio data.
+         *  4. The HAL module reads the command and audio data. According
+         *     to the statement above, the HAL module must always read
+         *     from the FMQ all the data it contains. The amount of data that
+         *     the HAL module has actually consumed is indicated to the client
+         *     via the 'reply.fmqByteCount' field.
          *  5. The HAL module writes the command status and current positions
          *     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.
          *
          * For input streams the following sequence of operations is used:
-         *  1. The client writes the 'BURST' command into the 'command' queue,
+         *  1. The client writes the BURST command into the 'command' queue,
          *     and hangs on waiting on a read from the 'reply' queue.
          *  2. The high priority thread in the HAL module wakes up due to 1.
          *  3. The HAL module writes audio data into the 'audio.fmq' queue.
+         *     The value of 'reply.fmqByteCount' must be the equal to the amount
+         *     of data in the queue.
          *  4. The HAL module writes the command status and current positions
          *     into 'reply' queue, and hangs on waiting on a read from
          *     the 'command' queue.
          *  5. The client wakes up due to 4.
-         *  6. The client reads the reply and audio data.
+         *  6. The client reads the reply and audio data. The client must
+         *     always read from the FMQ all the data it contains.
+         *
          */
         MQDescriptor<byte, SynchronizedReadWrite> fmq;
         /**
          * MMap buffers are shared directly with the DSP, which operates
-         * independently from the CPU. Writes and reads into these buffers
-         * are not synchronized with 'command' and 'reply' queues. However,
-         * the client still uses the 'BURST' command for obtaining current
-         * positions from the HAL module.
+         * independently from the CPU. Writes and reads into these buffers are
+         * not synchronized with 'command' and 'reply' queues. However, the
+         * client still uses the same commands for controlling the audio data
+         * exchange and for obtaining current positions and latency from the HAL
+         * module.
          */
         MmapBufferDescriptor mmap;
     }
diff --git a/audio/aidl/android/hardware/audio/core/SurroundSoundConfig.aidl b/audio/aidl/android/hardware/audio/core/SurroundSoundConfig.aidl
new file mode 100644
index 0000000..eeda12a
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/SurroundSoundConfig.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.audio.core;
+
+import android.media.audio.common.AudioFormatDescription;
+
+/**
+ * SurroundSoundConfig defines the multi-channel formats that can be enabled on
+ * (primarily TV) devices.
+ */
+@JavaDerive(equals=true, toString=true)
+@VintfStability
+parcelable SurroundSoundConfig {
+    @VintfStability
+    parcelable SurroundFormatFamily {
+        /**
+         * A primaryFormat shall get an entry in the Surround Settings dialog on TV
+         * devices. There must be a corresponding Java ENCODING_... constant
+         * defined in AudioFormat.java, and a display name defined in
+         * AudioFormat.toDisplayName.
+         */
+        AudioFormatDescription primaryFormat;
+        /**
+         * List of formats that shall be equivalent to the primaryFormat from the
+         * users' point of view and don't need a dedicated Surround Settings
+         * dialog entry.
+         */
+        AudioFormatDescription[] subFormats;
+    }
+    SurroundFormatFamily[] formatFamilies;
+}
diff --git a/audio/aidl/android/hardware/audio/core/stream-in-sm.gv b/audio/aidl/android/hardware/audio/core/stream-in-sm.gv
new file mode 100644
index 0000000..805dc32
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/stream-in-sm.gv
@@ -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.
+
+// To render: dot -Tpng stream-in-sm.gv -o stream-in-sm.png
+digraph stream_in_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];
+    I -> STANDBY;
+    STANDBY -> IDLE [label="start"];    // producer -> active
+    IDLE -> STANDBY [label="standby"];  // producer -> passive, buffer is cleared
+    IDLE -> ACTIVE [label="burst"];     // consumer -> active
+    ACTIVE -> ACTIVE [label="burst"];
+    ACTIVE -> PAUSED [label="pause"];   // consumer -> passive
+    ACTIVE -> DRAINING [label="drain"]; // producer -> passive
+    PAUSED -> ACTIVE [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="<hardware failure>"];
+    ACTIVE -> ERROR [label="<hardware failure>"];
+    PAUSED -> ERROR [label="<hardware failure>"];
+    ANY_STATE -> CLOSED [label="→IStream*.close"];
+    CLOSED -> F;
+}
diff --git a/audio/aidl/android/hardware/audio/core/stream-out-sm.gv b/audio/aidl/android/hardware/audio/core/stream-out-sm.gv
new file mode 100644
index 0000000..6aa5c61
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/stream-out-sm.gv
@@ -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.
+
+// To render: dot -Tpng stream-out-sm.gv -o stream-out-sm.png
+digraph stream_out_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];
+    I -> STANDBY;
+    STANDBY -> IDLE [label="start"];           // consumer -> active
+    STANDBY -> PAUSED [label="burst"];         // producer -> active
+    IDLE -> STANDBY [label="standby"];         // consumer -> passive
+    IDLE -> ACTIVE [label="burst"];            // producer -> active
+    ACTIVE -> ACTIVE [label="burst"];
+    ACTIVE -> PAUSED [label="pause"];          // consumer -> passive (not consuming)
+    ACTIVE -> DRAINING [label="drain"];        // producer -> passive
+    PAUSED -> PAUSED [label="burst"];
+    PAUSED -> ACTIVE [label="start"];          // consumer -> active
+    PAUSED -> IDLE [label="flush"];            // producer -> passive, buffer is cleared
+    DRAINING -> IDLE [label="<empty buffer>"];
+    DRAINING -> ACTIVE [label="burst"];        // producer -> active
+    DRAINING -> DRAIN_PAUSED [label="pause"];  // consumer -> passive (not consuming)
+    DRAIN_PAUSED -> DRAINING [label="start"];  // consumer -> active
+    DRAIN_PAUSED -> PAUSED [label="burst"];    // producer -> active
+    DRAIN_PAUSED -> IDLE [label="flush"];      // buffer is cleared
+    IDLE -> ERROR [label="<hardware failure>"];
+    ACTIVE -> ERROR [label="<hardware failure>"];
+    DRAINING -> ERROR [label="<hardware failure>"];
+    ANY_STATE -> CLOSED [label="→IStream*.close"];
+    CLOSED -> F;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/BassBoost.aidl b/audio/aidl/android/hardware/audio/effect/BassBoost.aidl
new file mode 100644
index 0000000..810c188
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/BassBoost.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;
+
+/**
+ * Bass boost is an audio effect to boost or amplify low frequencies of the sound. It is comparable
+ * to a simple equalizer but limited to one band amplification in the low frequency range.
+ *
+ * All parameters defined in union BassBoost must be gettable and settable. The capabilities defined
+ * in BassBoost.Capability can only acquired with IEffect.getDescriptor() and not settable.
+ */
+@VintfStability
+union BassBoost {
+    /**
+     * Effect parameter tag to identify the parameters for getParameter().
+     */
+    @VintfStability
+    union Id {
+        int vendorExtensionTag;
+        BassBoost.Tag commonTag;
+    }
+
+    /**
+     * Vendor BassBoost implementation definition for additional parameters.
+     */
+    VendorExtension vendor;
+
+    /**
+     * Capability supported by BassBoost implementation.
+     */
+    @VintfStability
+    parcelable Capability {
+        /**
+         * BassBoost capability extension, vendor can use this extension in case existing capability
+         * definition not enough.
+         */
+        ParcelableHolder extension;
+        /**
+         * Indicates whether setting strength is supported. False value indicates only one strength
+         * is supported and setParameter() method will return EX_ILLEGAL_ARGUMENT.
+         */
+        boolean strengthSupported;
+    }
+
+    /**
+     * The per mille strength of the bass boost effect.
+     *
+     * If the implementation does not support per mille accuracy for setting the strength, it is
+     * 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].
+     */
+    int strengthPm;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/Capability.aidl b/audio/aidl/android/hardware/audio/effect/Capability.aidl
new file mode 100644
index 0000000..f741f33
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/Capability.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.audio.effect;
+
+import android.hardware.audio.effect.BassBoost;
+import android.hardware.audio.effect.Downmix;
+import android.hardware.audio.effect.DynamicsProcessing;
+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.VendorExtension;
+import android.hardware.audio.effect.Virtualizer;
+import android.hardware.audio.effect.Visualizer;
+import android.hardware.audio.effect.Volume;
+
+/**
+ * Effect capability definitions.
+ * This data structure is used as part of effect Descriptor to identify effect capabilities which
+ * not meant to change at runtime.
+ */
+@VintfStability
+union Capability {
+    /**
+     * Vendor defined effect capability.
+     * This extension can be used when vendor have a new effect implementated and need
+     * capability definition for this new type of effect.
+     * If vendor want to extend existing effect capabilities, it is recommended to expose though
+     * the ParcelableHolder in each effect capability definition. For example:
+     * Equalizer.Capability.extension.
+     */
+    VendorExtension vendorExtension;
+
+    /**
+     * Effect capabilities.
+     */
+    BassBoost.Capability bassBoost;
+    Downmix.Capability downmix;
+    DynamicsProcessing.Capability dynamicsProcessing;
+    Equalizer.Capability equalizer;
+    HapticGenerator.Capability hapticGenerator;
+    LoudnessEnhancer.Capability loudnessEnhancer;
+    Reverb.Capability reverb;
+    Virtualizer.Capability virtualizer;
+    Visualizer.Capability visualizer;
+    Volume.Capability volume;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/CommandId.aidl b/audio/aidl/android/hardware/audio/effect/CommandId.aidl
new file mode 100644
index 0000000..d940b42
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/CommandId.aidl
@@ -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.
+ */
+
+package android.hardware.audio.effect;
+
+/**
+ * Defines all commands supported by the effect instance.
+ *
+ * There are three groups of commands:
+ * 1. Common part which MUST be supported by all effects.
+ * 2. Commands MUST be supported by a specific type of effect.
+ * 3. Extension commands for vendor.
+ */
+@VintfStability
+@Backing(type="int")
+enum CommandId {
+    /**
+     * Commands MUST be supported by all effects.
+     */
+    /**
+     * Start effect engine processing.
+     * An effect instance must start processing data and transfer to PROCESSING state if it is in
+     * IDLE state and have all necessary information. Otherwise it must:
+     * 1. Throw a EX_ILLEGAL_STATE exception if effect is not in IDLE state, or
+     * 2. Throw a EX_TRANSACTION_FAILED for all other errors.
+     *
+     * Depending on parameters set to the effect instance, effect may do process or reverse
+     * process after START command.
+     */
+    START = 0,
+    /**
+     * Stop effect engine processing with all resource kept.
+     * The currently processed audio data will be discarded if the effect engine is in PROCESSING
+     * state.
+     * Effect instance must do nothing and return ok when it receive STOP command in IDLE state.
+     */
+    STOP = 1,
+    /**
+     * Keep all parameter settings but reset the buffer content, stop engine processing, and transit
+     * instance state to IDLE if its in PROCESSING state.
+     * Effect instance must be able to handle RESET command at IDLE and PROCESSING states.
+     */
+    RESET = 2,
+
+    /**
+     * Commands MUST be supported by a specific type of effect.
+     */
+
+    /**
+     * Extension commands for vendor.
+     */
+    VENDOR_COMMAND_0 = 0x100,
+    VENDOR_COMMAND_1,
+    VENDOR_COMMAND_2,
+    VENDOR_COMMAND_3,
+    VENDOR_COMMAND_4,
+    VENDOR_COMMAND_5,
+    VENDOR_COMMAND_6,
+    VENDOR_COMMAND_7,
+    VENDOR_COMMAND_8,
+    VENDOR_COMMAND_9,
+}
diff --git a/audio/aidl/android/hardware/audio/effect/Descriptor.aidl b/audio/aidl/android/hardware/audio/effect/Descriptor.aidl
index 51b31c2..47c88dc 100644
--- a/audio/aidl/android/hardware/audio/effect/Descriptor.aidl
+++ b/audio/aidl/android/hardware/audio/effect/Descriptor.aidl
@@ -16,43 +16,77 @@
 
 package android.hardware.audio.effect;
 
+import android.hardware.audio.effect.Capability;
+import android.hardware.audio.effect.Flags;
 import android.media.audio.common.AudioUuid;
 
 /**
- * Effect descriptor contains all information (capabilities, attributes, and ownership) for an
- * effect implemented in the Audio Effect HAL. Framework uses this information to decide when and
- * how to apply the effect.
+ * Descriptor contains all information (capabilities, attributes, etc) for an effect implementation.
+ * The client uses this information to decide when and how to apply an effect implementation.
+ *
+ * Each type of effect can have more than one implementation (differentiated by implementation
+ * UUID), the effect proxy act as a combination of two implementations (usually one software and
+ * one offload implementation), so effect processing can be seamlessly switched between
+ * implementations in same proxy depending on the configuration and/or use case. If the optional
+ * proxy UUID is specified in Descriptor.Identity, then client must consider the effect instance as
+ * part of the effect proxy.
  */
 @VintfStability
 parcelable Descriptor {
     /**
      * UUID for effect types, these definitions are in sync with SDK, see @c AudioEffect.java.
      */
-    // UUID for environmental reverberation effect type.
+    /**
+     * UUID for environmental reverberation effect type.
+     */
     const String EFFECT_TYPE_UUID_ENV_REVERB = "c2e5d5f0-94bd-4763-9cac-4e234d06839e";
-    // UUID for preset reverberation effect type.
+    /**
+     * UUID for preset reverberation effect type.
+     */
     const String EFFECT_TYPE_UUID_PRESET_REVERB = "47382d60-ddd8-11db-bf3a-0002a5d5c51b";
-    // UUID for equalizer effect type.
+    /**
+     * UUID for equalizer effect type.
+     */
     const String EFFECT_TYPE_UUID_EQUALIZER = "0bed4300-ddd6-11db-8f34-0002a5d5c51b";
-    // UUID for bass boost effect type.
+    /**
+     * UUID for bass boost effect type.
+     */
     const String EFFECT_TYPE_UUID_BASS_BOOST = "0634f220-ddd4-11db-a0fc-0002a5d5c51b";
-    // UUID for virtualizer effect type.
+    /**
+     * UUID for virtualizer effect type.
+     */
     const String EFFECT_TYPE_UUID_VIRTUALIZER = "37cc2c00-dddd-11db-8577-0002a5d5c51b";
-    // UUID for Automatic Gain Control (AGC) type.
+    /**
+     * UUID for Automatic Gain Control (AGC) type.
+     */
     const String EFFECT_TYPE_UUID_AGC = "0a8abfe0-654c-11e0-ba26-0002a5d5c51b";
-    // UUID for Acoustic Echo Canceler (AEC) type.
+    /**
+     * UUID for Acoustic Echo Canceler (AEC) type.
+     */
     const String EFFECT_TYPE_UUID_AEC = "7b491460-8d4d-11e0-bd61-0002a5d5c51b";
-    // UUID for Noise Suppressor (NS) type.
+    /**
+     * UUID for Noise Suppressor (NS) type.
+     */
     const String EFFECT_TYPE_UUID_NS = "58b4b260-8e06-11e0-aa8e-0002a5d5c51b";
-    // UUID for Loudness Enhancer type.
+    /**
+     * UUID for Loudness Enhancer type.
+     */
     const String EFFECT_TYPE_UUID_LOUDNESS_ENHANCER = "fe3199be-aed0-413f-87bb-11260eb63cf1";
-    // UUID for Dynamics Processing type.
+    /**
+     * UUID for Dynamics Processing type.
+     */
     const String EFFECT_TYPE_UUID_DYNAMICS_PROCESSING = "7261676f-6d75-7369-6364-28e2fd3ac39e";
-    // UUID for Haptic Generator type.
+    /**
+     * UUID for Haptic Generator type.
+     */
     const String EFFECT_TYPE_UUID_HAPTIC_GENERATOR = "1411e6d6-aecd-4021-a1cf-a6aceb0d71e5";
-    // UUID for Spatializer type.
+    /**
+     * UUID for Spatializer type.
+     */
     const String EFFECT_TYPE_UUID_SPATIALIZER = "ccd4cf09-a79d-46c2-9aae-06a1698d6c8f";
-    // UUID for Volume type. The volume effect is used for automated tests only.
+    /**
+     * UUID for Volume type. The volume effect is used for automated tests only.
+     */
     const String EFFECT_TYPE_UUID_VOLUME = "09e8ede0-ddde-11db-b4f6-0002a5d5c51b";
 
     /**
@@ -68,15 +102,48 @@
          * UUID for this particular implementation.
          */
         AudioUuid uuid;
+        /**
+         * Optional proxy UUID. This field must be set to the proxy effect type UUID if the effect
+         * implementation is part of a proxy effect.
+         */
+        @nullable AudioUuid proxy;
     }
 
-    // Common attributes of all effect implementation.
+    /**
+     * Common attributes of all effect implementation.
+     */
     @VintfStability
     parcelable Common {
         /**
          * Identity of effect implementation.
          */
         Identity id;
+        /**
+         * Capability flags defined for the effect implementation.
+         */
+        Flags flags;
+        /**
+         * CPU load indication expressed in 0.1 MIPS units as estimated on an ARM9E core (ARMv5TE)
+         * with 0 WS.
+         */
+        int cpuLoad;
+        /**
+         * Data memory usage expressed in KB and includes only dynamically allocated memory.
+         */
+        int memoryUsage;
+        /**
+         * Human readable effect name, no intended to display on UI directly.
+         */
+        @utf8InCpp String name;
+        /**
+         * Human readable effect implementor name, no intended to display on UI directly.
+         */
+        @utf8InCpp String implementor;
     }
     Common common;
+
+    /**
+     * Effect implementation capability.
+     */
+    Capability capability;
 }
diff --git a/audio/aidl/android/hardware/audio/effect/Downmix.aidl b/audio/aidl/android/hardware/audio/effect/Downmix.aidl
new file mode 100644
index 0000000..ee57baf
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/Downmix.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;
+
+/**
+ * Downmix specific definitions.
+ *
+ * All parameters defined in union Downmix must be gettable and settable. The capabilities defined
+ * in Downmix.Capability can only acquired with IEffect.getDescriptor() and not settable.
+ */
+@VintfStability
+union Downmix {
+    /**
+     * Effect parameter tag to identify the parameters for getParameter().
+     */
+    @VintfStability
+    union Id {
+        int vendorExtensionTag;
+        Downmix.Tag commonTag;
+    }
+
+    /**
+     * Vendor Downmix implementation definition for additional parameters.
+     */
+    VendorExtension vendor;
+
+    /**
+     * Capability supported by Downmix implementation.
+     */
+    @VintfStability
+    parcelable Capability {
+        /**
+         * Downmix capability extension, vendor can use this extension in case existing capability
+         * definition not enough.
+         */
+        ParcelableHolder extension;
+    }
+
+    @VintfStability
+    enum Type {
+        /**
+         * Throw away the extra channels.
+         */
+        STRIP,
+        /**
+         * Mix the extra channels with FL/FR.
+         */
+        FOLD,
+    }
+
+    /**
+     * Type of downmix.
+     */
+    Type type;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/DynamicsProcessing.aidl b/audio/aidl/android/hardware/audio/effect/DynamicsProcessing.aidl
new file mode 100644
index 0000000..ee5dcad
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/DynamicsProcessing.aidl
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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;
+
+/**
+ * DynamicsProcessing specific definitions.
+ *
+ * All parameters defined in union DynamicsProcessing must be gettable and settable. The
+ * capabilities defined in DynamicsProcessing.Capability can only acquired with
+ * IEffect.getDescriptor() and not settable.
+ */
+@VintfStability
+union DynamicsProcessing {
+    /**
+     * Effect parameter tag to identify the parameters for getParameter().
+     */
+    @VintfStability
+    union Id {
+        int vendorExtensionTag;
+        DynamicsProcessing.Tag commonTag;
+    }
+
+    /**
+     * Vendor DynamicsProcessing implementation definition for additional parameters.
+     */
+    VendorExtension vendorExtension;
+
+    /**
+     * Capability supported by DynamicsProcessing implementation.
+     */
+    @VintfStability
+    parcelable Capability {
+        /**
+         * DynamicsProcessing capability extension, vendor can use this extension in case existing
+         * capability definition not enough.
+         */
+        ParcelableHolder extension;
+    }
+
+    /**
+     * Resolution preference definition.
+     */
+    enum ResolutionPreference {
+        /**
+         * Favors frequency domain based implementation.
+         */
+        FAVOR_FREQUENCY_RESOLUTION,
+        /**
+         * Favors tme domain based implementation.
+         */
+        FAVOR_TIME_RESOLUTION,
+    }
+
+    /**
+     * Band enablement configuration.
+     */
+    @VintfStability
+    parcelable BandEnablement {
+        /**
+         * True if multi-band stage is in use.
+         */
+        boolean inUse;
+        /**
+         * Number of bands configured for this stage.
+         */
+        int bandCount;
+    }
+
+    /**
+     * Effect engine configuration. Set the enablement of all stages.
+     */
+    @VintfStability
+    parcelable EngineArchitecture {
+        /**
+         * Resolution preference.
+         */
+        ResolutionPreference resolutionPreference = ResolutionPreference.FAVOR_FREQUENCY_RESOLUTION;
+        /**
+         * Preferred frame duration in milliseconds (ms).
+         */
+        float preferredFrameDurationMs;
+        /**
+         * PreEq stage (Multi-band Equalizer) configuration.
+         */
+        BandEnablement preEqBand;
+        /**
+         * PostEq stage (Multi-band Equalizer) configuration.
+         */
+        BandEnablement postEqBand;
+        /**
+         * MBC stage (Multi-band Compressor) configuration.
+         */
+        BandEnablement mbcBand;
+        /**
+         * True if Limiter stage is in use.
+         */
+        boolean limiterInUse;
+    }
+
+    /**
+     * Band enablement configuration for a specific channel.
+     */
+    @VintfStability
+    parcelable BandChannelConfig {
+        /**
+         * Channel index.
+         */
+        int channel;
+        /**
+         * Channel index.
+         */
+        BandEnablement enablement;
+    }
+
+    /**
+     * Equalizer band configuration for a specific channel and band.
+     */
+    @VintfStability
+    parcelable EqBandConfig {
+        /**
+         * Channel index.
+         */
+        int channel;
+        /**
+         * Band index, must in the range of [0, bandCount-1].
+         */
+        int band;
+        /**
+         * True if EQ stage is enabled.
+         */
+        boolean enable;
+        /**
+         * Topmost frequency number (in Hz) this band will process.
+         */
+        float cutoffFrequency;
+        /**
+         * Gain factor in decibels (dB).
+         */
+        float gain;
+    }
+
+    /**
+     * MBC configuration for a specific channel and band.
+     */
+    @VintfStability
+    parcelable MbcBandConfig {
+        /**
+         * Channel index.
+         */
+        int channel;
+        /**
+         * Band index, must in the range of [0, bandCount-1].
+         */
+        int band;
+        /**
+         * True if MBC stage is enabled.
+         */
+        boolean enable;
+        /**
+         * Topmost frequency number (in Hz) this band will process.
+         */
+        float cutoffFrequencyHz;
+        /**
+         * Gain factor in decibels (dB).
+         */
+        float gainDb;
+        /**
+         * Attack Time for compressor in milliseconds (ms).
+         */
+        float attackTimeMs;
+        /**
+         * Release Time for compressor in milliseconds (ms).
+         */
+        float releaseTimeMs;
+        /**
+         * Compressor ratio (N:1) (input:output).
+         */
+        float ratio;
+        /**
+         * Compressor threshold measured in decibels (dB) from 0 dB Full Scale (dBFS).
+         */
+        float thresholdDb;
+        /**
+         * Width in decibels (dB) around compressor threshold point.
+         */
+        float kneeWidthDb;
+        /**
+         * Noise gate threshold in decibels (dB) from 0 dB Full Scale (dBFS).
+         */
+        float noiseGateThresholdDb;
+        /**
+         * Expander ratio (1:N) (input:output) for signals below the Noise Gate Threshold.
+         */
+        float expanderRatio;
+        /**
+         * Gain applied to the signal BEFORE the compression in dB.
+         */
+        float preGainDb;
+        /**
+         * Gain applied to the signal AFTER compression in dB.
+         */
+        float postGainDb;
+    }
+
+    /**
+     * Limiter configuration for a specific channel.
+     */
+    @VintfStability
+    parcelable LimiterConfig {
+        /**
+         * Channel index.
+         */
+        int channel;
+        /**
+         * True if Limiter stage is enabled.
+         */
+        boolean enable;
+        /**
+         * True if Limiter stage is in use.
+         */
+        boolean inUse;
+        /**
+         * Index of group assigned to this Limiter. Only limiters that share the same linkGroup
+         * index will react together.
+         */
+        int linkGroup;
+        /**
+         * Attack Time for compressor in milliseconds (ms).
+         */
+        float attackTimeMs;
+        /**
+         * Release Time for compressor in milliseconds (ms).
+         */
+        float releaseTimeMs;
+        /**
+         * Compressor ratio (N:1) (input:output).
+         */
+        float ratio;
+        /**
+         * Compressor threshold measured in decibels (dB) from 0 dB Full Scale (dBFS).
+         */
+        float thresholdDb;
+        /**
+         * Gain applied to the signal AFTER compression in dB.
+         */
+        float postGainDb;
+    }
+
+    /**
+     * Effect engine architecture.
+     */
+    EngineArchitecture engineArchitecture;
+    /**
+     * PreEq stage per channel configuration.
+     */
+    BandChannelConfig preEq;
+    /**
+     * PostEq stage per channel configuration.
+     */
+    BandChannelConfig postEq;
+    /**
+     * PreEq stage per band configuration.
+     */
+    EqBandConfig preEqBand;
+    /**
+     * PostEq stage per band configuration.
+     */
+    EqBandConfig postEqBand;
+    /**
+     * MBC stage per channel configuration.
+     */
+    BandChannelConfig mbc;
+    /**
+     * PostEq stage per band configuration.
+     */
+    MbcBandConfig mbcBand;
+    /**
+     * Limiter stage configuration.
+     */
+    LimiterConfig limiter;
+    /**
+     * Input gain factor in decibels (dB). 0 dB means no change in level.
+     */
+    float inputGainDb;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/Equalizer.aidl b/audio/aidl/android/hardware/audio/effect/Equalizer.aidl
new file mode 100644
index 0000000..79a1c4f
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/Equalizer.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.effect;
+
+import android.hardware.audio.effect.VendorExtension;
+
+/**
+ * Equalizer specific definitions.
+ *
+ * All parameters defined in union Equalizer must be gettable and settable. The capabilities defined
+ * in Equalizer.Capability can only acquired with IEffect.getDescriptor() and not settable.
+ */
+@VintfStability
+union Equalizer {
+    /**
+     * Effect parameter tag to identify the parameters for getParameter().
+     */
+    @VintfStability
+    union Id {
+        int vendorExtensionTag;
+        Equalizer.Tag commonTag;
+    }
+
+    /**
+     * Vendor Equalizer implementation definition for additional parameters.
+     */
+    VendorExtension vendorExtension;
+
+    /**
+     * Capability MUST be supported by Equalizer implementation.
+     */
+    @VintfStability
+    parcelable Capability {
+        /**
+         * Equalizer capability extension, vendor can use this extension in case existing capability
+         * definition not enough.
+         */
+        ParcelableHolder extension;
+
+        /**
+         * Bands frequency ranges supported.
+         */
+        BandFrequency[] bandFrequencies;
+
+        /**
+         * Presets name and index.
+         */
+        Preset[] presets;
+    }
+
+    /**
+     * Level setting for each band in millibels.
+     */
+    @VintfStability
+    parcelable BandLevel {
+        int index;
+        int levelMb;
+    }
+
+    /**
+     * Supported minimal and maximal frequency for each band in millihertz.
+     */
+    @VintfStability
+    parcelable BandFrequency {
+        int index;
+        int minMh;
+        int maxMh;
+    }
+
+    /**
+     * Factory presets supported.
+     */
+    @VintfStability
+    parcelable Preset {
+        int index;
+        /**
+         * Preset name, used to identify presets but no intended to display on UI directly.
+         */
+        @utf8InCpp String name;
+    }
+
+    /**
+     * Level for each band.
+     */
+    BandLevel[] bandLevels;
+    /**
+     * Index of current preset.
+     */
+    int preset;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/Flags.aidl b/audio/aidl/android/hardware/audio/effect/Flags.aidl
new file mode 100644
index 0000000..f449c2d
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/Flags.aidl
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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;
+
+/**
+ * Some common capability for an effect instance.
+ */
+@VintfStability
+parcelable Flags {
+    /**
+     * Type of connection.
+     */
+    @VintfStability
+    @Backing(type="byte")
+    enum Type {
+        /**
+         * After track process.
+         */
+        INSERT = 0,
+        /**
+         * Connect to track auxiliary output and use send level.
+         */
+        AUXILIARY = 1,
+        /**
+         * Rreplaces track process function; must implement SRC, volume and mono to stereo.
+         */
+        REPLACE = 2,
+        /**
+         * Applied below audio HAL on in.
+         */
+        PRE_PROC = 3,
+        /**
+         * Applied below audio HAL on out.
+         */
+        POST_PROC = 4,
+    }
+    Type type = Type.INSERT;
+
+    /**
+     * Insertion preference.
+     */
+    @VintfStability
+    @Backing(type="byte")
+    enum Insert {
+        ANY = 0,
+        /**
+         * First of the chain.
+         */
+        FIRST = 1,
+        /**
+         * Last of the chain.
+         */
+        LAST = 2,
+        /**
+         * Exclusive (only effect in the insert chain.
+         */
+        EXCLUSIVE = 3,
+    }
+    Insert insert = Insert.ANY;
+
+    @VintfStability
+    @Backing(type="byte")
+    enum Volume {
+        NONE = 0,
+        /**
+         * Implements volume control.
+         */
+        CTRL = 1,
+        /**
+         * Requires volume indication.
+         */
+        IND = 2,
+        /**
+         * Monitors requested volume.
+         */
+        MONITOR = 3,
+    }
+    Volume volume = Volume.NONE;
+
+    @VintfStability
+    @Backing(type="byte")
+    enum HardwareAccelerator {
+        /**
+         * No hardware acceleration
+         */
+        NONE = 0,
+        /**
+         * Non tunneled hw acceleration: effect reads the samples, send them to HW accelerated
+         * effect processor, reads back the processed samples and returns them to the output buffer.
+         */
+        SIMPLE = 1,
+        /**
+         * The effect interface is only used to control the effect engine. This mode is relevant for
+         * global effects actually applied by the audio hardware on the output stream.
+         */
+        TUNNEL = 2,
+    }
+    HardwareAccelerator hwAcceleratorMode = HardwareAccelerator.NONE;
+
+    /**
+     * Effect instance set this flag to true if it requires update on if the playback thread the
+     * effect attached to is offloaded or not. In this case the framework must call
+     * IEffect.setParameter(Parameter.offload) to notify effect instance when playback thread
+     * offload changes.
+     */
+    boolean offloadIndication;
+
+    /**
+     * Effect instance set this flag to true if it requires device change update. In this case the
+     * framework must call IEffect.setParameter(Parameter.device) to notify effect instance when the
+     * device changes.
+     */
+    boolean deviceIndication;
+
+    /**
+     * Effect instance set this flag to true if it requires audio mode change update. In this case
+     * the framework must call IEffect.setParameter(Parameter.mode) to notify effect instance when
+     * the audio mode changes.
+     */
+    boolean audioModeIndication;
+
+    /**
+     * Effect instance set this flag to true if it requires audio source change update. In this case
+     * the framework must call IEffect.setParameter(Parameter.source) to notify effect instance when
+     * the audio source changes.
+     */
+    boolean audioSourceIndication;
+
+    /**
+     * Set to true if no processing done for this effect instance.
+     */
+    boolean noProcessing;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/HapticGenerator.aidl b/audio/aidl/android/hardware/audio/effect/HapticGenerator.aidl
new file mode 100644
index 0000000..944155f
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/HapticGenerator.aidl
@@ -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.
+ */
+
+package android.hardware.audio.effect;
+
+import android.hardware.audio.effect.VendorExtension;
+
+/**
+ * HapticGenerator specific definitions. HapticGenerator effect provide HapticGenerator control and
+ * mute/unmute functionality.
+ *
+ * All parameters defined in union HapticGenerator must be gettable and settable. The capabilities
+ * defined in HapticGenerator.Capability can only acquired with IEffect.getDescriptor() and not
+ * settable.
+ */
+@VintfStability
+union HapticGenerator {
+    /**
+     * Effect parameter tag to identify the parameters for getParameter().
+     */
+    @VintfStability
+    union Id {
+        int vendorExtensionTag;
+        HapticGenerator.Tag commonTag;
+    }
+
+    /**
+     * Vendor HapticGenerator implementation definition for additional parameters.
+     */
+    VendorExtension vendorExtension;
+
+    /**
+     * Capability supported by HapticGenerator implementation.
+     */
+    @VintfStability
+    parcelable Capability {
+        /**
+         * HapticGenerator capability extension, vendor can use this extension in case existing
+         * capability definition not enough.
+         */
+        VendorExtension extension;
+    }
+
+    @VintfStability
+    @Backing(type="int")
+    enum VibratorScale {
+        MUTE = -100,
+        VERY_LOW = -2,
+        LOW = -1,
+        NONE = 0,
+        HIGH = 1,
+        VERY_HIGH = 2,
+    }
+
+    @VintfStability
+    parcelable HapticScale {
+        /**
+         * Audio track ID.
+         */
+        int id;
+        /**
+         * Haptic intensity.
+         */
+        VibratorScale scale = VibratorScale.MUTE;
+    }
+
+    /**
+     * Vibrator information including resonant frequency, Q factor.
+     */
+    @VintfStability
+    parcelable VibratorInformation {
+        /**
+         * Resonant frequency in Hz.
+         */
+        float resonantFrequencyHz;
+        float qFactor;
+        float maxAmplitude;
+    }
+
+    HapticScale hapticScale;
+    VibratorInformation vibratorInfo;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/IEffect.aidl b/audio/aidl/android/hardware/audio/effect/IEffect.aidl
index d7a9501..3b957d7 100644
--- a/audio/aidl/android/hardware/audio/effect/IEffect.aidl
+++ b/audio/aidl/android/hardware/audio/effect/IEffect.aidl
@@ -16,24 +16,80 @@
 
 package android.hardware.audio.effect;
 
+import android.hardware.audio.effect.CommandId;
 import android.hardware.audio.effect.Descriptor;
+import android.hardware.audio.effect.Parameter;
+import android.hardware.audio.effect.State;
+import android.hardware.common.fmq.MQDescriptor;
+import android.hardware.common.fmq.SynchronizedReadWrite;
 
 /**
  * Effect interfaces definitions to configure and control the effect instance.
  */
 @VintfStability
 interface IEffect {
+    @VintfStability
+    @FixedSize
+    parcelable Status {
+        /**
+         * 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;
+         *
+         */
+        int status;
+        /**
+         * The amount of audio data samples in the floating point format consumed by the effect
+         * instance.
+         */
+        int fmqConsumed;
+        /**
+         * The amount of audio data samples in the floating point format produced by the effect
+         * instance.
+         */
+        int fmqProduced;
+    }
+
     /**
-     * Open an effect instance, effect should not start processing data before receive START
-     * command. All necessary information should be allocated and instance should transfer to IDLE
-     * state after open() call has been handled successfully.
-     * After open, the effect instance should be able to handle all IEffect interface calls.
+     * Return data structure of IEffect.open() interface.
+     */
+    @VintfStability
+    parcelable OpenEffectReturn {
+        /**
+         * Message queue for effect processing status.
+         */
+        MQDescriptor<Status, SynchronizedReadWrite> statusMQ;
+        /**
+         * Message queue for input data buffer.
+         */
+        MQDescriptor<float, SynchronizedReadWrite> inputDataMQ;
+        /**
+         * Message queue for output data buffer.
+         */
+        MQDescriptor<float, SynchronizedReadWrite> outputDataMQ;
+    }
+
+    /**
+     * Open an effect instance, effect must not start processing data before receive
+     * CommandId::START command. All necessary information should be allocated and instance must
+     * transfer to State::IDLE state after open() call has been handled successfully. After open,
+     * the effect instance must be able to handle all IEffect interface calls.
      *
+     * @param common Parameters which MUST pass from client at open time.
+     * @param specific Effect specific parameters which can optional pass from client at open time.
+     *
+     * @throws EX_ILLEGAL_ARGUMENT if the effect instance receive unsupported command.
      * @throws a EX_UNSUPPORTED_OPERATION if device capability/resource is not enough or system
      *         failure happens.
      * @note Open an already-opened effect instance should do nothing and should not throw an error.
      */
-    void open();
+    OpenEffectReturn open(
+            in Parameter.Common common, in @nullable Parameter.Specific specific);
 
     /**
      * Called by the client to close the effect instance, processing thread should be destroyed and
@@ -45,7 +101,7 @@
      *
      * Effect instance close interface should always succeed unless:
      * 1. The effect instance is not in a proper state to be closed, for example it's still in
-     * processing state.
+     * State::PROCESSING state.
      * 2. There is system/hardware related failure when close.
      *
      * @throws EX_ILLEGAL_STATE if the effect instance is not in a proper state to be closed.
@@ -62,4 +118,53 @@
      * @return Descriptor The @c Descriptor of this effect instance.
      */
     Descriptor getDescriptor();
+
+    /**
+     * Send a command (defined in enum CommandId) to the effect instance, instance state can be
+     * changed as result of command handling.
+     *
+     * Must be available for the effect instance after it has been open().
+     *
+     * @param commandId ID of the command send to the effect instance.
+     *
+     * @throws EX_ILLEGAL_STATE if the effect instance is not in a proper state to handle the
+     * command.
+     * @throws EX_ILLEGAL_ARGUMENT if the effect instance receive unsupported command.
+     */
+    void command(in CommandId commandId);
+
+    /**
+     * Get current state of the effect instance.
+     *
+     * Must be available for the effect instance at anytime and should always succeed.
+     *
+     * @return Current effect instance state.
+     */
+    State getState();
+
+    /**
+     * Set a parameter to the effect instance.
+     *
+     * Must be available for the effect instance after open().
+     *
+     * @param param Parameter data to set to the effect instance.
+     *
+     * @throws EX_ILLEGAL_ARGUMENT if the effect instance receive unsupported parameter.
+     */
+    void setParameter(in Parameter param);
+
+    /**
+     * Get a parameter from the effect instance with parameter ID.
+     *
+     * This interface must return the current parameter of the effect instance, if no parameter
+     * has been set by client yet, the default value must be returned.
+     *
+     * Must be available for the effect instance after open().
+     *
+     * @param paramId The tag enum of parameter to get.
+     * @return Parameter The parameter to get from the effect instance.
+     *
+     * @throws EX_ILLEGAL_ARGUMENT if the effect instance receive unsupported parameter tag.
+     */
+    Parameter getParameter(in Parameter.Id paramId);
 }
diff --git a/audio/aidl/android/hardware/audio/effect/IFactory.aidl b/audio/aidl/android/hardware/audio/effect/IFactory.aidl
index 4873d3a..5943359 100644
--- a/audio/aidl/android/hardware/audio/effect/IFactory.aidl
+++ b/audio/aidl/android/hardware/audio/effect/IFactory.aidl
@@ -18,6 +18,7 @@
 
 import android.hardware.audio.effect.Descriptor;
 import android.hardware.audio.effect.IEffect;
+import android.hardware.audio.effect.Processing;
 import android.media.audio.common.AudioUuid;
 
 /**
@@ -38,11 +39,24 @@
      *        null, used as a filter for effect type UUIDs.
      * @param implementation Indicates the particular implementation of the effect in that type.
      *        This is an optional parameter, pass in null if this parameter is not necessary; if
-     *        non null, used as a filter for effect type UUIDs.
+     *        non null, used as a filter for effect implementation UUIDs.
+     * @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.
      */
-    Descriptor.Identity[] queryEffects(
-            in @nullable AudioUuid type, in @nullable AudioUuid implementation);
+    Descriptor.Identity[] queryEffects(in @nullable AudioUuid type,
+            in @nullable AudioUuid implementation, in @nullable AudioUuid proxy);
+
+    /**
+     * Return a list of defined processings, with the optional filter by Processing type.
+     * An effect can exist more than once in the returned list, which means this effect must be used
+     * in more than one processing type.
+     *
+     * @param type Type of processing to query, can be AudioStreamType, AudioSource, or null.
+     * @return list of processing defined with the optional filter by Processing.Type.
+     */
+    Processing[] queryProcessing(in @nullable Processing.Type type);
 
     /**
      * Called by the audio framework to create the effect (identified by the implementation UUID
diff --git a/audio/aidl/android/hardware/audio/effect/LoudnessEnhancer.aidl b/audio/aidl/android/hardware/audio/effect/LoudnessEnhancer.aidl
new file mode 100644
index 0000000..0441f10
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/LoudnessEnhancer.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.audio.effect;
+
+import android.hardware.audio.effect.VendorExtension;
+
+/**
+ * LoudnessEnhancer specific definitions.
+ *
+ * All parameters defined in union LoudnessEnhancer must be gettable and settable. The capabilities
+ * defined in LoudnessEnhancer.Capability can only acquired with IEffect.getDescriptor() and not
+ * settable.
+ */
+@VintfStability
+union LoudnessEnhancer {
+    /**
+     * Effect parameter tag to identify the parameters for getParameter().
+     */
+    @VintfStability
+    union Id {
+        int vendorExtensionTag;
+        LoudnessEnhancer.Tag commonTag;
+    }
+
+    /**
+     * Vendor LoudnessEnhancer implementation definition for additional parameters.
+     */
+    VendorExtension vendor;
+
+    /**
+     * Capability supported by LoudnessEnhancer implementation.
+     */
+    @VintfStability
+    parcelable Capability {
+        /**
+         * LoudnessEnhancer capability extension, vendor can use this extension in case existing
+         * capability definition not enough.
+         */
+        VendorExtension extension;
+    }
+
+    /**
+     * The maximum gain in millibels (mB) applied to the signal to process, default value is 0 which
+     * corresponds to no amplification.
+     */
+    int gainMb;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/Parameter.aidl b/audio/aidl/android/hardware/audio/effect/Parameter.aidl
new file mode 100644
index 0000000..e7d3d5e
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/Parameter.aidl
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.BassBoost;
+import android.hardware.audio.effect.Downmix;
+import android.hardware.audio.effect.DynamicsProcessing;
+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.VendorExtension;
+import android.hardware.audio.effect.Virtualizer;
+import android.hardware.audio.effect.Visualizer;
+import android.hardware.audio.effect.Volume;
+import android.media.audio.common.AudioConfig;
+import android.media.audio.common.AudioDeviceDescription;
+import android.media.audio.common.AudioMode;
+import android.media.audio.common.AudioSource;
+
+/**
+ * Defines all parameters supported by the effect instance.
+ *
+ * There are three groups of parameters:
+ * 1. Common parameters are essential parameters, MUST pass to effects at open() interface.
+ * 2. Parameters defined for a specific effect type.
+ * 3. Extension parameters ParcelableHolder can be used for vendor effect definition.
+ *
+ */
+@VintfStability
+union Parameter {
+    /**
+     * Client can pass in Parameter.Id with the corresponding tag value in IEffect.getParameter()
+     * call to get android.hardware.audio.effect.Parameter.
+     *
+     * As an example, if a client want to get audio.hardware.audio.effect.Specific.Equalizer, the
+     * value of Id should be audio.hardware.audio.effect.Parameter.Specific.equalizer.
+     */
+    @VintfStability
+    union Id {
+        /**
+         * Parameter tag defined for vendor effects. Use int here so there is flexibility for vendor
+         * to define different tag.
+         */
+        int vendorEffectTag;
+        /**
+         * Parameter tag defined for nested parameters. Can be used to get any parameter defined in
+         * nested Union structure.
+         *
+         * Example:
+         * To get BassBoost strength in param from effectInstance:
+         *  IEffect effectInstance;
+         *  Parameter param;
+         *  BassBoost::Id bassId = BassBoost::Id::make<BassBoost::Id::tag>(BassBoost::strengthPm);
+         *  Parameter::Id id = Parameter::Id::make<Parameter::Id::bassBoostTag>(bassId);
+         *  effectInstance.getParameter(id, &param);
+         *
+         */
+        BassBoost.Id bassBoostTag;
+        Downmix.Id downmixTag;
+        DynamicsProcessing.Id dynamicsProcessingTag;
+        Equalizer.Id equalizerTag;
+        HapticGenerator.Id hapticGeneratorTag;
+        LoudnessEnhancer.Id loudnessEnhancerTag;
+        Reverb.Id reverbTag;
+        Virtualizer.Id virtualizerTag;
+        Visualizer.Id visualizerTag;
+        Volume.Id volumeTag;
+        /**
+         * Non-nested parameter tag. Can be used to get any parameter defined in Union Parameter
+         * directly.
+         */
+        Parameter.Tag commonTag;
+    }
+
+    /**
+     * Common parameters MUST be supported by all effect implementations.
+     */
+    @VintfStability
+    parcelable Common {
+        /**
+         * Type of Audio device.
+         */
+        int session;
+        /**
+         * I/O Handle.
+         */
+        int ioHandle;
+        /**
+         * Input config.
+         */
+        AudioConfig input;
+        /**
+         * Output config.
+         */
+        AudioConfig output;
+    }
+    Common common;
+
+    /**
+     * Used by audio framework to set the device type to effect engine.
+     * Effect must implement setParameter(device) if Flags.deviceIndication set to true.
+     */
+    AudioDeviceDescription deviceDescription;
+    /**
+     * Used by audio framework to set the audio mode to effect engine.
+     * Effect must implement setParameter(mode) if Flags.audioModeIndication set to true.
+     */
+    AudioMode mode;
+    /**
+     * Used by audio framework to set the audio source to effect engine.
+     * Effect must implement setParameter(source) if Flags.audioSourceIndication set to true.
+     */
+    AudioSource source;
+
+    /**
+     * The volume gain for left and right channel, left and right equals to same value if it's mono.
+     */
+    @VintfStability
+    parcelable VolumeStereo {
+        float left;
+        float right;
+    }
+    /**
+     * Used by audio framework to delegate volume control to effect engine.
+     * Effect must implement setParameter(volume) if Flags.volume set to Volume.IND.
+     */
+    VolumeStereo volumeStereo;
+
+    /**
+     * Parameters MUST be supported by a Specific type of effect.
+     */
+    @VintfStability
+    union Specific {
+        VendorExtension vendorEffect;
+        BassBoost bassBoost;
+        Downmix downmix;
+        DynamicsProcessing dynamicsProcessing;
+        Equalizer equalizer;
+        LoudnessEnhancer loudnessEnhancer;
+        HapticGenerator hapticGenerator;
+        Reverb reverb;
+        Virtualizer virtualizer;
+        Visualizer visualizer;
+        Volume volume;
+    }
+    Specific specific;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/Processing.aidl b/audio/aidl/android/hardware/audio/effect/Processing.aidl
new file mode 100644
index 0000000..ef32e8c
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/Processing.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.effect;
+
+import android.hardware.audio.effect.Descriptor;
+import android.media.audio.common.AudioSource;
+import android.media.audio.common.AudioStreamType;
+import android.media.audio.common.AudioUuid;
+
+/**
+ * List of effects which must be used for certain pre-processing or post-processing.
+ */
+@VintfStability
+parcelable Processing {
+    @VintfStability
+    union Type {
+        AudioStreamType streamType = AudioStreamType.INVALID;
+        AudioSource source;
+    }
+
+    /**
+     * Specifies the type of processing by referring to the output stream type (AudioStreamType) or
+     * the input stream source (AudioSource).
+     */
+    Type type;
+    /**
+     * List of effect identities for this processing.
+     */
+    Descriptor.Identity[] ids;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/Reverb.aidl b/audio/aidl/android/hardware/audio/effect/Reverb.aidl
new file mode 100644
index 0000000..f60c2ea
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/Reverb.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.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/State.aidl b/audio/aidl/android/hardware/audio/effect/State.aidl
new file mode 100644
index 0000000..85a4afc
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/State.aidl
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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;
+
+/**
+ * Possible states of an effect instance.
+ * A typical effect instance will be in INIT state when it is created with IFactory.createEffect()
+ * interface, transfer to IDLE after open(), and to PROCESSING after
+ * IEffect.command(Command.Id.START) command. When an effect instance receive STOP or RESET command,
+ * it should transfer to IDLE state after handle the command successfully. Effect instance should
+ * consume minimal resource and transfer to INIT state after it was close().
+ *
+ * Refer to State.gv for detailed state diagram.
+ */
+@VintfStability
+@Backing(type="byte")
+enum State {
+
+    /**
+     * An effect instance is in INIT state by default after it was created with
+     * IFactory.createEffect(). When an effect instance is in INIT state, it should have instance
+     * context initialized, and ready to handle IEffect.setParameter(), IEffect.open() as well as
+     * all getter interfaces.
+     *
+     * In INIT state, effect instance must:
+     * 1. Not handle any IEffect.command() and return EX_ILLEGAL_STATE with any Command.Id.
+     * 2. Be able to handle all parameter setting with IEffect.setParameter().
+     * 3. Be able to handle all getter interface calls like IEffect.getParameter() and
+     * IEffect.getState().
+     * 4. Be able to handle IEffect.open() successfully after configuration.
+     *
+     * Client is expected to do necessary configuration with IEffect.setParameter(), get all
+     * resource ready with IEffect.open(), and make sure effect instance transfer to IDLE state
+     * before sending commands with IEffect.command() interface. Effect instance must transfer
+     * from INIT to IDLE state after handle IEffect.open() call successfully.
+     */
+    INIT,
+    /**
+     * An effect instance transfer to IDLE state after it was open successfully with IEffect.open()
+     * in INIT state, or after it was stop/reset with Command.Id.STOP/RESET in PROCESSING state.
+     *
+     * In IDLE state, effect instance must:
+     * 1. Be able to start effect processing engine with IEffect.command(Command.Id.START) call.
+     * 2. Be able to handle all parameter setting with IEffect.setParameter().
+     * 3. Be able to handle all getter interface calls like IEffect.getParameter() and
+     * IEffect.getState().
+     *
+     * The following state transfer can happen in IDLE state:
+     * 1. Transfer to PROCESSING if instance receive an START command and start processing data
+     * successfully.
+     * 2. Transfer to INIT if instance receive a close() call.
+     */
+    IDLE,
+    /**
+     * An effect instance is in PROCESSING state after it receive an START command and start
+     * processing data successfully. Effect instance will transfer from PROCESSING to IDLE state if
+     * it receive an STOP or RESET command and handle the command successfully.
+     *
+     * When an instance is in PROCESSING state, client should try not to close() it directly,
+     * instead client should try to stop processing data first with STOP command before close(). In
+     * the case of a close() call received when instance in PROCESSING state, it should try to stop
+     * processing and transfer to IDLE first before close().
+     *
+     * In PROCESSING state, effect instance must:
+     * 1. Return EX_ILLEGAL_STATE if it's not able to handle any parameter settings at runtime.
+     * 2. Be able to handle STOP and RESET for IEffect.command() interface, and return
+     * EX_ILLEGAL_STATE for all other commands.
+     * 3. Must be able to handle all get* interface calls like IEffect.getParameter() and
+     * IEffect.getState().
+     */
+    PROCESSING,
+}
diff --git a/audio/aidl/android/hardware/audio/effect/VendorExtension.aidl b/audio/aidl/android/hardware/audio/effect/VendorExtension.aidl
new file mode 100644
index 0000000..c60f01a
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/VendorExtension.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.audio.effect;
+
+/**
+ * Vendor exntension implementation definition, can be used for additional parameters.
+ */
+@VintfStability
+parcelable VendorExtension {
+    ParcelableHolder extension;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/Virtualizer.aidl b/audio/aidl/android/hardware/audio/effect/Virtualizer.aidl
new file mode 100644
index 0000000..9d039bc
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/Virtualizer.aidl
@@ -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.
+ */
+
+package android.hardware.audio.effect;
+
+import android.hardware.audio.effect.VendorExtension;
+
+/**
+ * Virtualizer specific definitions. An audio virtualizer is a general name for an effect to
+ * spatialize audio channels.
+ *
+ * All parameters defined in union Virtualizer must be gettable and settable. The capabilities
+ * defined in Virtualizer.Capability can only acquired with IEffect.getDescriptor() and not
+ * settable.
+ */
+@VintfStability
+union Virtualizer {
+    /**
+     * Effect parameter tag to identify the parameters for getParameter().
+     */
+    @VintfStability
+    union Id {
+        int vendorExtensionTag;
+        Virtualizer.Tag commonTag;
+    }
+
+    /**
+     * Vendor Virtualizer implementation definition for additional parameters.
+     */
+    VendorExtension vendor;
+
+    /**
+     * Capability supported by Virtualizer implementation.
+     */
+    @VintfStability
+    parcelable Capability {
+        /**
+         * Virtualizer capability extension, vendor can use this extension in case existing
+         * capability definition not enough.
+         */
+        VendorExtension extension;
+        /**
+         * Indicates whether setting strength is supported. False value indicates only one strength
+         * is supported and setParameter() method will always return EX_ILLEGAL_ARGUMENT.
+         */
+        boolean strengthSupported;
+    }
+
+    /**
+     * The per mille strength of the virtualizer effect.
+     *
+     * If the implementation does not support per mille accuracy for setting the strength, it is
+     * 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].
+     */
+    int strengthPm;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/Visualizer.aidl b/audio/aidl/android/hardware/audio/effect/Visualizer.aidl
new file mode 100644
index 0000000..4c1b71a
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/Visualizer.aidl
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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;
+
+/**
+ * Visualizer specific definitions. Visualizer enables application to retrieve part of the currently
+ * playing audio for visualization purpose
+ *
+ * All parameters defined in union Visualizer other than these in GetOnlyParameters and
+ * SetOnlyParameters must be gettable and settable. The capabilities defined in
+ * Visualizer.Capability can only acquired with IEffect.getDescriptor() and not settable.
+ *
+ */
+@VintfStability
+union Visualizer {
+    /**
+     * Effect parameter tag to identify the parameters for getParameter().
+     */
+    @VintfStability
+    union Id {
+        int vendorExtensionTag;
+        GetOnlyParameters.Tag getOnlyParamTag;
+        SetOnlyParameters.Tag setOnlyParamTag;
+        Visualizer.Tag commonTag;
+    }
+    Id id;
+
+    /**
+     * Vendor Visualizer implementation definition for additional parameters.
+     */
+    VendorExtension vendor;
+
+    /**
+     * Capability supported by Visualizer implementation.
+     */
+    @VintfStability
+    parcelable Capability {
+        /**
+         * Visualizer capability extension, vendor can use this extension in case existing
+         * capability definition not enough.
+         */
+        VendorExtension extension;
+        /**
+         * Max latency supported in millseconds.
+         */
+        int maxLatencyMs;
+        /**
+         *  Capture size range.
+         */
+        CaptureSizeRange captureSizeRange;
+    }
+
+    /**
+     * Supported capture size range in bytes.
+     */
+    @VintfStability
+    parcelable CaptureSizeRange {
+        int minBytes;
+        int maxBytes;
+    }
+
+    /**
+     * Type of scaling applied on the captured visualization data.
+     */
+    @VintfStability
+    enum ScalingMode {
+        /**
+         * Defines a capture mode where amplification is applied based on the content of the
+         * captured data. This is the default Visualizer mode, and is suitable for music
+         * visualization.
+         */
+        NORMALIZED = 0,
+        /**
+         * Defines a capture mode where the playback volume will affect (scale) the range of the
+         * captured data. A low playback volume will lead to low sample and fft values, and
+         * vice-versa.
+         */
+        AS_PLAYED,
+    }
+
+    /**
+     * Measurement modes to be performed.
+     */
+    @VintfStability
+    enum MeasurementMode {
+        /**
+         * No measurements are performed.
+         */
+        NONE = 0,
+        /**
+         * Defines a measurement mode which computes the peak and RMS value in mB below the "full
+         * scale", where 0mB is normally the maximum sample value (but see the note below). Minimum
+         * value depends on the resolution of audio samples used by the audio framework. The value
+         * of -9600mB is the minimum value for 16-bit audio systems and -14400mB or below for "high
+         * resolution" systems. Values for peak and RMS can be retrieved with {@link
+         * #getMeasurementPeakRms(MeasurementPeakRms)}.
+         */
+        PEAK_RMS,
+    }
+
+    /**
+     * Any parameter defined in this union must be gettable via getParameter(), but must not
+     * settable.
+     */
+    @VintfStability
+    union GetOnlyParameters {
+        /**
+         * Get the current measurements.
+         */
+        @VintfStability
+        parcelable Measurement {
+            int rms;
+            int peak;
+        }
+        Measurement measurement;
+
+        /**
+         * Gets the latest PCM capture, size of returned vector equals to @c captureSize.
+         */
+        byte[] captureBytes;
+    }
+    GetOnlyParameters getOnlyParameters;
+
+    /**
+     * Any parameter defined in this union must be settable via setParameter(), but must not
+     * gettable.
+     */
+    @VintfStability
+    union SetOnlyParameters {
+        /**
+         * Used by framework to inform the visualizer about the downstream latency (audio hardware
+         * driver estimated latency in milliseconds).
+         */
+        int latencyMs;
+    }
+    SetOnlyParameters setOnlyParameters;
+
+    /**
+     * Current capture size in bytes. The capture size must be a power of 2 in the range
+     * Capability.captureSizeRange.
+     */
+    int captureSizeBytes;
+    /**
+     * Visualizer capture mode
+     */
+    ScalingMode scalingMode;
+    /**
+     * Visualizer measurement mode.
+     */
+    MeasurementMode measurementMode;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/Volume.aidl b/audio/aidl/android/hardware/audio/effect/Volume.aidl
new file mode 100644
index 0000000..a3ce2f6
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/Volume.aidl
@@ -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.
+ */
+
+package android.hardware.audio.effect;
+
+import android.hardware.audio.effect.VendorExtension;
+
+/**
+ * Volume specific definitions. Volume effect provide volume control and mute/unmute functionality.
+ *
+ * All parameters defined in union Volume must be gettable and settable. The capabilities defined in
+ * Volume.Capability can only acquired with IEffect.getDescriptor() and not settable.
+ */
+@VintfStability
+union Volume {
+    /**
+     * Effect parameter tag to identify the parameters for getParameter().
+     */
+    @VintfStability
+    union Id {
+        int vendorExtensionTag;
+        Volume.Tag commonTag;
+    }
+
+    /**
+     * Vendor Volume implementation definition for additional parameters.
+     */
+    VendorExtension vendor;
+
+    /**
+     * Capability supported by Volume implementation.
+     */
+    @VintfStability
+    parcelable Capability {
+        /**
+         * Volume capability extension, vendor can use this extension in case existing capability
+         * definition not enough.
+         */
+        VendorExtension extension;
+
+        /**
+         * Volume strength supported in dB.
+         */
+        int maxLevel;
+    }
+
+    /**
+     * Current level in dB.
+     */
+    int levelDb;
+    /**
+     * Mute volume if true, when volume set to mute, the current level still saved and take effect
+     * when unmute.
+     */
+    boolean mute;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/state.gv b/audio/aidl/android/hardware/audio/effect/state.gv
new file mode 100644
index 0000000..e19e6c7
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/state.gv
@@ -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.
+ */
+
+// 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;
+
+    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
diff --git a/audio/aidl/common/StreamWorker.cpp b/audio/aidl/common/StreamWorker.cpp
index 9bca760..dda0e4a 100644
--- a/audio/aidl/common/StreamWorker.cpp
+++ b/audio/aidl/common/StreamWorker.cpp
@@ -44,6 +44,10 @@
             mWorkerStateChangeRequest = true;
         }
     }
+    join();
+}
+
+void ThreadController::join() {
     if (mWorker.joinable()) {
         mWorker.join();
     }
diff --git a/audio/aidl/common/include/StreamWorker.h b/audio/aidl/common/include/StreamWorker.h
index 6260eca..ab2ec26 100644
--- a/audio/aidl/common/include/StreamWorker.h
+++ b/audio/aidl/common/include/StreamWorker.h
@@ -39,6 +39,9 @@
     ~ThreadController() { stop(); }
 
     bool start(const std::string& name, int priority);
+    // Note: 'pause' and 'resume' methods should only be used on the "driving" side.
+    // In the case of audio HAL I/O, the driving side is the client, because the HAL
+    // implementation always blocks on getting a command.
     void pause() { switchWorkerStateSync(WorkerState::RUNNING, WorkerState::PAUSE_REQUESTED); }
     void resume() { switchWorkerStateSync(WorkerState::PAUSED, WorkerState::RESUME_REQUESTED); }
     bool hasError() {
@@ -50,6 +53,10 @@
         return mError;
     }
     void stop();
+    // Direct use of 'join' assumes that the StreamLogic is not intended
+    // to run forever, and is guaranteed to exit by itself. This normally
+    // only happen in tests.
+    void join();
     bool waitForAtLeastOneCycle();
 
     // Only used by unit tests.
@@ -133,7 +140,8 @@
     void resume() { mThread.resume(); }
     bool hasError() { return mThread.hasError(); }
     std::string getError() { return mThread.getError(); }
-    void stop() { return mThread.stop(); }
+    void stop() { mThread.stop(); }
+    void join() { mThread.join(); }
     bool waitForAtLeastOneCycle() { return mThread.waitForAtLeastOneCycle(); }
 
     // Only used by unit tests.
diff --git a/audio/aidl/common/tests/streamworker_tests.cpp b/audio/aidl/common/tests/streamworker_tests.cpp
index e3e484d..8ea8424 100644
--- a/audio/aidl/common/tests/streamworker_tests.cpp
+++ b/audio/aidl/common/tests/streamworker_tests.cpp
@@ -160,6 +160,14 @@
     EXPECT_TRUE(worker.hasNoWorkerCycleCalled(kWorkerIdleCheckTime));
 }
 
+TEST_P(StreamWorkerTest, WorkerJoin) {
+    ASSERT_TRUE(worker.start());
+    stream.setStopStatus();
+    worker.join();
+    EXPECT_FALSE(worker.hasError());
+    EXPECT_TRUE(worker.hasNoWorkerCycleCalled(kWorkerIdleCheckTime));
+}
+
 TEST_P(StreamWorkerTest, WorkerError) {
     ASSERT_TRUE(worker.start());
     stream.setErrorStatus();
diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp
index 53ed908..2b9ed5b 100644
--- a/audio/aidl/default/Android.bp
+++ b/audio/aidl/default/Android.bp
@@ -21,6 +21,9 @@
         "android.hardware.common-V2-ndk",
         "android.hardware.common.fmq-V1-ndk",
     ],
+    header_libs: [
+        "libaudioaidl_headers",
+    ],
 }
 
 cc_library_static {
@@ -36,6 +39,7 @@
         "Configuration.cpp",
         "Module.cpp",
         "Stream.cpp",
+        "Telephony.cpp",
     ],
     visibility: [
         ":__subpackages__",
@@ -62,13 +66,24 @@
     name: "aidlaudioeffectservice_defaults",
     defaults: [
         "latest_android_media_audio_common_types_ndk_shared",
+        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     vendor: true,
     shared_libs: [
+        "libaudioaidlcommon",
         "libbase",
         "libbinder_ndk",
-        "android.hardware.audio.effect-V1-ndk",
-        "libequalizer",
+        "libcutils",
+        "libfmq",
+        "liblog",
+        "libutils",
+        "android.hardware.common-V2-ndk",
+        "android.hardware.common.fmq-V1-ndk",
+    ],
+    header_libs: [
+        "libaudioaidl_headers",
+        "libaudio_system_headers",
+        "libsystem_headers",
     ],
     cflags: [
         "-Wall",
@@ -78,18 +93,11 @@
     ],
 }
 
-cc_library_static {
-    name: "libaudioeffectserviceexampleimpl",
-    defaults: ["aidlaudioeffectservice_defaults"],
-    export_include_dirs: [
-        "include",
-        "include/equalizer-impl/",
-    ],
+filegroup {
+    name: "effectCommonFile",
     srcs: [
-        "EffectFactory.cpp",
-    ],
-    visibility: [
-        ":__subpackages__",
+        "EffectThread.cpp",
+        "EffectImpl.cpp",
     ],
 }
 
@@ -99,8 +107,30 @@
     init_rc: ["android.hardware.audio.effect.service-aidl.example.rc"],
     vintf_fragments: ["android.hardware.audio.effect.service-aidl.xml"],
     defaults: ["aidlaudioeffectservice_defaults"],
-    static_libs: [
-        "libaudioeffectserviceexampleimpl",
+    shared_libs: [
+        "libbassboostsw",
+        "libbundleaidl",
+        "libdynamicsprocessingsw",
+        "libenvreverbsw",
+        "libequalizersw",
+        "libhapticgeneratorsw",
+        "libloudnessenhancersw",
+        "libpresetreverbsw",
+        "libtinyxml2",
+        "libvirtualizersw",
+        "libvisualizersw",
+        "libvolumesw",
     ],
-    srcs: ["EffectMain.cpp"],
+    srcs: [
+        "EffectConfig.cpp",
+        "EffectFactory.cpp",
+        "EffectMain.cpp",
+    ],
+}
+
+cc_library_headers {
+    name: "libaudioaidl_headers",
+    export_include_dirs: ["include"],
+    vendor_available: true,
+    host_supported: true,
 }
diff --git a/audio/aidl/default/Config.cpp b/audio/aidl/default/Config.cpp
index 3f7a3d3..0fdd5b4 100644
--- a/audio/aidl/default/Config.cpp
+++ b/audio/aidl/default/Config.cpp
@@ -13,7 +13,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#define LOG_TAG "AHAL_Module"
+#include <android-base/logging.h>
 
 #include "core-impl/Config.h"
 
-namespace aidl::android::hardware::audio::core {}  // namespace aidl::android::hardware::audio::core
+namespace aidl::android::hardware::audio::core {
+ndk::ScopedAStatus Config::getSurroundSoundConfig(SurroundSoundConfig* _aidl_return) {
+    SurroundSoundConfig surroundSoundConfig;
+    // TODO: parse from XML; for now, use empty config as default
+    *_aidl_return = std::move(surroundSoundConfig);
+    LOG(DEBUG) << __func__ << ": returning " << _aidl_return->toString();
+    return ndk::ScopedAStatus::ok();
+}
+}  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/EffectConfig.cpp b/audio/aidl/default/EffectConfig.cpp
new file mode 100644
index 0000000..e1427ec
--- /dev/null
+++ b/audio/aidl/default/EffectConfig.cpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_EffectConfig"
+#include <android-base/logging.h>
+
+#include "effectFactory-impl/EffectConfig.h"
+
+using aidl::android::media::audio::common::AudioUuid;
+
+namespace aidl::android::hardware::audio::effect {
+
+EffectConfig::EffectConfig(const std::string& file) {
+    tinyxml2::XMLDocument doc;
+    doc.LoadFile(file.c_str());
+    LOG(DEBUG) << __func__ << " loading " << file;
+    // parse the xml file into maps
+    if (doc.Error()) {
+        LOG(ERROR) << __func__ << " tinyxml2 failed to load " << file
+                   << " error: " << doc.ErrorStr();
+        return;
+    }
+
+    auto registerFailure = [&](bool result) { mSkippedElements += result ? 0 : 1; };
+
+    for (auto& xmlConfig : getChildren(doc, "audio_effects_conf")) {
+        // Parse library
+        for (auto& xmlLibraries : getChildren(xmlConfig, "libraries")) {
+            for (auto& xmlLibrary : getChildren(xmlLibraries, "library")) {
+                registerFailure(parseLibrary(xmlLibrary));
+            }
+        }
+
+        // Parse effects
+        for (auto& xmlEffects : getChildren(xmlConfig, "effects")) {
+            for (auto& xmlEffect : getChildren(xmlEffects)) {
+                registerFailure(parseEffect(xmlEffect));
+            }
+        }
+
+        // Parse pre processing chains
+        for (auto& xmlPreprocess : getChildren(xmlConfig, "preprocess")) {
+            for (auto& xmlStream : getChildren(xmlPreprocess, "stream")) {
+                registerFailure(parseStream(xmlStream));
+            }
+        }
+
+        // Parse post processing chains
+        for (auto& xmlPostprocess : getChildren(xmlConfig, "postprocess")) {
+            for (auto& xmlStream : getChildren(xmlPostprocess, "stream")) {
+                registerFailure(parseStream(xmlStream));
+            }
+        }
+    }
+    LOG(DEBUG) << __func__ << " successfully parsed " << file << ", skipping " << mSkippedElements
+               << " element(s)";
+}
+
+std::vector<std::reference_wrapper<const tinyxml2::XMLElement>> EffectConfig::getChildren(
+        const tinyxml2::XMLNode& node, const char* childTag) {
+    std::vector<std::reference_wrapper<const tinyxml2::XMLElement>> children;
+    for (auto* child = node.FirstChildElement(childTag); child != nullptr;
+         child = child->NextSiblingElement(childTag)) {
+        children.emplace_back(*child);
+    }
+    return children;
+}
+
+bool EffectConfig::parseLibrary(const tinyxml2::XMLElement& xml) {
+    const char* name = xml.Attribute("name");
+    RETURN_VALUE_IF(!name, false, "noNameAttribute");
+    const char* path = xml.Attribute("path");
+    RETURN_VALUE_IF(!path, false, "noPathAttribute");
+
+    mLibraryMap[name] = path;
+    LOG(DEBUG) << __func__ << " " << name << " : " << path;
+    return true;
+}
+
+bool EffectConfig::parseEffect(const tinyxml2::XMLElement& xml) {
+    struct EffectLibraries effectLibraries;
+    std::vector<LibraryUuid> libraryUuids;
+    std::string name = xml.Attribute("name");
+    RETURN_VALUE_IF(name == "", false, "effectsNoName");
+
+    LOG(DEBUG) << __func__ << dump(xml);
+    struct LibraryUuid libraryUuid;
+    if (std::strcmp(xml.Name(), "effectProxy") == 0) {
+        // proxy lib and uuid
+        RETURN_VALUE_IF(!parseLibraryUuid(xml, libraryUuid, true), false, "parseProxyLibFailed");
+        effectLibraries.proxyLibrary = libraryUuid;
+        // proxy effect libs and UUID
+        auto xmlProxyLib = xml.FirstChildElement();
+        RETURN_VALUE_IF(!xmlProxyLib, false, "noLibForProxy");
+        while (xmlProxyLib) {
+            struct LibraryUuid tempLibraryUuid;
+            RETURN_VALUE_IF(!parseLibraryUuid(*xmlProxyLib, tempLibraryUuid), false,
+                            "parseEffectLibFailed");
+            libraryUuids.push_back(std::move(tempLibraryUuid));
+            xmlProxyLib = xmlProxyLib->NextSiblingElement();
+        }
+    } else {
+        // expect only one library if not proxy
+        RETURN_VALUE_IF(!parseLibraryUuid(xml, libraryUuid), false, "parseEffectLibFailed");
+        libraryUuids.push_back(std::move(libraryUuid));
+    }
+
+    effectLibraries.libraries = std::move(libraryUuids);
+    mEffectsMap[name] = std::move(effectLibraries);
+    return true;
+}
+
+bool EffectConfig::parseStream(const tinyxml2::XMLElement& xml) {
+    LOG(DEBUG) << __func__ << dump(xml);
+    const char* type = xml.Attribute("type");
+    RETURN_VALUE_IF(!type, false, "noTypeInProcess");
+    RETURN_VALUE_IF(0 != mProcessingMap.count(type), false, "duplicateType");
+
+    for (auto& apply : getChildren(xml, "apply")) {
+        const char* name = apply.get().Attribute("effect");
+        RETURN_VALUE_IF(!name, false, "noEffectAttribute");
+        mProcessingMap[type].push_back(name);
+        LOG(DEBUG) << __func__ << " " << type << " : " << name;
+    }
+    return true;
+}
+
+bool EffectConfig::parseLibraryUuid(const tinyxml2::XMLElement& xml,
+                                    struct LibraryUuid& libraryUuid, bool isProxy) {
+    // Retrieve library name only if not effectProxy element
+    if (!isProxy) {
+        const char* name = xml.Attribute("library");
+        RETURN_VALUE_IF(!name, false, "noLibraryAttribute");
+        libraryUuid.name = name;
+    }
+
+    const char* uuid = xml.Attribute("uuid");
+    RETURN_VALUE_IF(!uuid, false, "noUuidAttribute");
+    RETURN_VALUE_IF(!stringToUuid(uuid, &libraryUuid.uuid), false, "invalidUuidAttribute");
+
+    LOG(DEBUG) << __func__ << (isProxy ? " proxy " : libraryUuid.name) << " : "
+               << libraryUuid.uuid.toString();
+    return true;
+}
+
+const char* EffectConfig::dump(const tinyxml2::XMLElement& element,
+                               tinyxml2::XMLPrinter&& printer) const {
+    element.Accept(&printer);
+    return printer.CStr();
+}
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/EffectFactory.cpp b/audio/aidl/default/EffectFactory.cpp
index a9848fd..820b447 100644
--- a/audio/aidl/default/EffectFactory.cpp
+++ b/audio/aidl/default/EffectFactory.cpp
@@ -16,57 +16,209 @@
 
 #define LOG_TAG "AHAL_EffectFactory"
 #include <android-base/logging.h>
+#include <dlfcn.h>
+#include <unordered_set>
 
+#include "effect-impl/EffectTypes.h"
+#include "effect-impl/EffectUUID.h"
 #include "effectFactory-impl/EffectFactory.h"
-#include "equalizer-impl/Equalizer.h"
-#include "visualizer-impl/Visualizer.h"
 
 using aidl::android::media::audio::common::AudioUuid;
 
 namespace aidl::android::hardware::audio::effect {
 
-Factory::Factory() {
-    // TODO: implement this with xml parser on audio_effect.xml, and filter with optional
-    // parameters.
-    Descriptor::Identity id;
-    id.type = EqualizerTypeUUID;
-    id.uuid = EqualizerSwImplUUID;
-    mIdentityList.push_back(id);
+Factory::Factory(const std::string& file) : mConfig(EffectConfig(file)) {
+    LOG(DEBUG) << __func__ << " with config file: " << file;
+    loadEffectLibs();
 }
 
-ndk::ScopedAStatus Factory::queryEffects(const std::optional<AudioUuid>& in_type,
-                                         const std::optional<AudioUuid>& in_instance,
+Factory::~Factory() {
+    if (auto count = mEffectUuidMap.size()) {
+        LOG(ERROR) << __func__ << " remaining " << count
+                   << " effect instances not destroyed indicating resource leak!";
+        for (const auto& it : mEffectUuidMap) {
+            if (auto spEffect = it.first.lock()) {
+                LOG(ERROR) << __func__ << " erase remaining instance UUID " << it.second.toString();
+                destroyEffectImpl(spEffect);
+            }
+        }
+    }
+}
+
+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(mIdentityList.begin(), mIdentityList.end(), std::back_inserter(*_aidl_return),
-                 [&](auto& desc) {
-                     return (!in_type.has_value() || in_type.value() == desc.type) &&
-                            (!in_instance.has_value() || in_instance.value() == desc.uuid);
-                 });
+    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()));
+            });
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Factory::createEffect(
-        const AudioUuid& in_impl_uuid,
-        std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>* _aidl_return) {
+ndk::ScopedAStatus Factory::queryProcessing(const std::optional<Processing::Type>& in_type,
+                                            std::vector<Processing>* _aidl_return) {
+    // TODO: implement this with audio_effect.xml.
+    if (in_type.has_value()) {
+        // return all matching process filter
+        LOG(DEBUG) << __func__ << " process type: " << in_type.value().toString();
+    }
+    LOG(DEBUG) << __func__ << " return " << _aidl_return->size();
+    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 (in_impl_uuid == EqualizerSwImplUUID) {
-        *_aidl_return = ndk::SharedRefBase::make<Equalizer>();
+    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& libInterface = lib.second;
+        std::shared_ptr<IEffect> effectSp;
+        RETURN_IF_BINDER_EXCEPTION(libInterface->createEffectFunc(&in_impl_uuid, &effectSp));
+        if (!effectSp) {
+            LOG(ERROR) << __func__ << ": library created null instance without return error!";
+            return ndk::ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
+        }
+        *_aidl_return = effectSp;
+        mEffectUuidMap[std::weak_ptr<IEffect>(effectSp)] = in_impl_uuid;
+        LOG(DEBUG) << __func__ << ": instance " << effectSp.get() << " created successfully";
+        return ndk::ScopedAStatus::ok();
     } else {
-        LOG(ERROR) << __func__ << ": UUID "
-                   << " not supported";
+        LOG(ERROR) << __func__ << ": library doesn't exist";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Factory::destroyEffect(
-        const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_handle) {
-    if (in_handle) {
-        // TODO: b/245393900 need check the instance state with IEffect.getState before destroy.
+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 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));
+            }
+        } else {
+            LOG(ERROR) << __func__ << ": UUID " << uuid.toString() << " does not exist in libMap!";
+            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+        }
+        mEffectUuidMap.erase(uuidIt);
         return ndk::ScopedAStatus::ok();
     } else {
+        LOG(ERROR) << __func__ << ": instance " << in_handle << " does not exist!";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
 }
 
+// go over the map and cleanup all expired weak_ptrs.
+void Factory::cleanupEffectMap() {
+    for (auto it = mEffectUuidMap.begin(); it != mEffectUuidMap.end();) {
+        if (nullptr == it->first.lock()) {
+            it = mEffectUuidMap.erase(it);
+        } else {
+            ++it;
+        }
+    }
+}
+
+ndk::ScopedAStatus Factory::destroyEffect(const std::shared_ptr<IEffect>& in_handle) {
+    LOG(DEBUG) << __func__ << ": instance " << in_handle.get();
+    ndk::ScopedAStatus status = destroyEffectImpl(in_handle);
+    // always do the cleanup
+    cleanupEffectMap();
+    return status;
+}
+
+void Factory::openEffectLibrary(const AudioUuid& impl, const std::string& libName) {
+    std::function<void(void*)> dlClose = [](void* handle) -> void {
+        if (handle && dlclose(handle)) {
+            LOG(ERROR) << "dlclose failed " << dlerror();
+        }
+    };
+
+    auto libHandle =
+            std::unique_ptr<void, decltype(dlClose)>{dlopen(libName.c_str(), RTLD_LAZY), dlClose};
+    if (!libHandle) {
+        LOG(ERROR) << __func__ << ": dlopen failed, err: " << dlerror();
+        return;
+    }
+
+    LOG(DEBUG) << __func__ << " dlopen lib:" << libName << "\nimpl:" << impl.toString()
+               << "\nhandle:" << libHandle;
+    mEffectLibMap.insert({impl, std::make_pair(std::move(libHandle), nullptr)});
+}
+
+void Factory::createIdentityWithConfig(const EffectConfig::LibraryUuid& configLib,
+                                       const AudioUuid& typeUuid,
+                                       const std::optional<AudioUuid> proxyUuid) {
+    static const auto& libMap = mConfig.getLibraryMap();
+    const std::string& libName = configLib.name;
+    if (auto path = libMap.find(libName); path != libMap.end()) {
+        Descriptor::Identity id;
+        id.type = typeUuid;
+        id.uuid = configLib.uuid;
+        id.proxy = proxyUuid;
+        LOG(DEBUG) << __func__ << ": typeUuid " << id.type.toString() << "\nimplUuid "
+                   << id.uuid.toString() << " proxyUuid "
+                   << (proxyUuid.has_value() ? proxyUuid->toString() : "null");
+        openEffectLibrary(id.uuid, path->second);
+        mIdentitySet.insert(std::move(id));
+    } else {
+        LOG(ERROR) << __func__ << ": library " << libName << " not exist!";
+        return;
+    }
+}
+
+void Factory::loadEffectLibs() {
+    const auto& configEffectsMap = mConfig.getEffectsMap();
+    for (const auto& configEffects : configEffectsMap) {
+        if (auto typeUuid = kUuidNameTypeMap.find(configEffects.first /* effect name */);
+            typeUuid != kUuidNameTypeMap.end()) {
+            const auto& configLibs = configEffects.second;
+            std::optional<AudioUuid> proxyUuid;
+            if (configLibs.proxyLibrary.has_value()) {
+                const auto& proxyLib = configLibs.proxyLibrary.value();
+                proxyUuid = proxyLib.uuid;
+            }
+            for (const auto& configLib : configLibs.libraries) {
+                createIdentityWithConfig(configLib, typeUuid->second, proxyUuid);
+            }
+        } else {
+            LOG(ERROR) << __func__ << ": can not find type UUID for effect " << configEffects.first
+                       << " skipping!";
+        }
+    }
+}
+
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/EffectImpl.cpp b/audio/aidl/default/EffectImpl.cpp
new file mode 100644
index 0000000..2754bb6
--- /dev/null
+++ b/audio/aidl/default/EffectImpl.cpp
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_EffectImpl"
+#include "effect-impl/EffectImpl.h"
+#include "effect-impl/EffectTypes.h"
+#include "include/effect-impl/EffectTypes.h"
+
+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);
+    }
+
+    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,
+              "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");
+    RETURN_IF(releaseContext() != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
+              "FailedToCreateWorker");
+    mState = State::INIT;
+    LOG(DEBUG) << __func__;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EffectImpl::setParameter(const Parameter& param) {
+    LOG(DEBUG) << __func__ << " with: " << param.toString();
+
+    auto tag = param.getTag();
+    switch (tag) {
+        case Parameter::common:
+        case Parameter::deviceDescription:
+        case Parameter::mode:
+        case Parameter::source:
+            FALLTHROUGH_INTENDED;
+        case Parameter::volumeStereo:
+            return setParameterCommon(param);
+        case Parameter::specific: {
+            return setParameterSpecific(param.get<Parameter::specific>());
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupportedParameterTag " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "ParameterNotSupported");
+        }
+    }
+}
+
+ndk::ScopedAStatus EffectImpl::getParameter(const Parameter::Id& id, Parameter* param) {
+    LOG(DEBUG) << __func__ << id.toString();
+    auto tag = id.getTag();
+    switch (tag) {
+        case Parameter::Id::commonTag: {
+            RETURN_IF_ASTATUS_NOT_OK(getParameterCommon(id.get<Parameter::Id::commonTag>(), param),
+                                     "CommonParamNotSupported");
+            break;
+        }
+        case Parameter::Id::vendorEffectTag: {
+            LOG(DEBUG) << __func__ << " noop for vendor tag";
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "vendortagNotSupported");
+        }
+        default: {
+            Parameter::Specific specific;
+            RETURN_IF_ASTATUS_NOT_OK(getParameterSpecific(id, &specific), "SpecParamNotSupported");
+            param->set<Parameter::specific>(specific);
+            break;
+        }
+    }
+    LOG(DEBUG) << __func__ << param->toString();
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EffectImpl::setParameterCommon(const Parameter& param) {
+    std::lock_guard lg(mMutex);
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+    auto tag = param.getTag();
+    switch (tag) {
+        case Parameter::common:
+            RETURN_IF(mContext->setCommon(param.get<Parameter::common>()) != RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setCommFailed");
+            break;
+        case Parameter::deviceDescription:
+            RETURN_IF(mContext->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,
+                      EX_ILLEGAL_ARGUMENT, "setModeFailed");
+            break;
+        case Parameter::source:
+            RETURN_IF(mContext->setAudioSource(param.get<Parameter::source>()) != RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setSourceFailed");
+            break;
+        case Parameter::volumeStereo:
+            RETURN_IF(mContext->setVolumeStereo(param.get<Parameter::volumeStereo>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setVolumeStereoFailed");
+            break;
+        default: {
+            LOG(ERROR) << __func__ << " unsupportedParameterTag " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "commonParamNotSupported");
+        }
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EffectImpl::getParameterCommon(const Parameter::Tag& tag, Parameter* param) {
+    std::lock_guard lg(mMutex);
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+    switch (tag) {
+        case Parameter::common: {
+            param->set<Parameter::common>(mContext->getCommon());
+            break;
+        }
+        case Parameter::deviceDescription: {
+            param->set<Parameter::deviceDescription>(mContext->getOutputDevice());
+            break;
+        }
+        case Parameter::mode: {
+            param->set<Parameter::mode>(mContext->getAudioMode());
+            break;
+        }
+        case Parameter::source: {
+            param->set<Parameter::source>(mContext->getAudioSource());
+            break;
+        }
+        case Parameter::volumeStereo: {
+            param->set<Parameter::volumeStereo>(mContext->getVolumeStereo());
+            break;
+        }
+        default: {
+            LOG(DEBUG) << __func__ << " unsupported tag " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "tagNotSupported");
+        }
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+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);
+    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;
+            startThread();
+            return ndk::ScopedAStatus::ok();
+        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();
+        default:
+            LOG(ERROR) << __func__ << " instance still processing";
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "CommandIdNotSupported");
+    }
+    LOG(DEBUG) << __func__ << " transfer to state: " << toString(mState);
+    return ndk::ScopedAStatus::ok();
+}
+
+void EffectImpl::cleanUp() {
+    command(CommandId::STOP);
+    close();
+}
+
+IEffect::Status EffectImpl::status(binder_status_t status, size_t consumed, size_t produced) {
+    IEffect::Status ret;
+    ret.status = status;
+    ret.fmqConsumed = consumed;
+    ret.fmqProduced = produced;
+    return ret;
+}
+
+// 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++) {
+        *out++ = *in++;
+    }
+    LOG(DEBUG) << __func__ << " done processing " << processSamples << " samples";
+    return {STATUS_OK, processSamples, processSamples};
+}
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/EffectMain.cpp b/audio/aidl/default/EffectMain.cpp
index 3219dd6..ca81204 100644
--- a/audio/aidl/default/EffectMain.cpp
+++ b/audio/aidl/default/EffectMain.cpp
@@ -19,21 +19,31 @@
 #include <android-base/logging.h>
 #include <android/binder_manager.h>
 #include <android/binder_process.h>
+#include <system/audio_config.h>
+
+/** Default name of effect configuration file. */
+static const char* kDefaultConfigName = "audio_effects_config.xml";
 
 int main() {
     // This is a debug implementation, always enable debug logging.
     android::base::SetMinimumLogSeverity(::android::base::DEBUG);
     ABinderProcess_setThreadPoolMaxThreadCount(0);
 
+    auto configFile = android::audio_find_readable_configuration_file(kDefaultConfigName);
+    if (configFile == "") {
+        LOG(ERROR) << __func__ << ": config file " << kDefaultConfigName << " not found!";
+        return EXIT_FAILURE;
+    }
+    LOG(DEBUG) << __func__ << ": start factory with configFile:" << configFile;
     auto effectFactory =
-            ndk::SharedRefBase::make<aidl::android::hardware::audio::effect::Factory>();
+            ndk::SharedRefBase::make<aidl::android::hardware::audio::effect::Factory>(configFile);
 
     std::string serviceName = std::string() + effectFactory->descriptor + "/default";
     binder_status_t status =
             AServiceManager_addService(effectFactory->asBinder().get(), serviceName.c_str());
     CHECK_EQ(STATUS_OK, status);
-    LOG(DEBUG) << __func__ << ": effectFactoryName:" << serviceName;
 
+    LOG(DEBUG) << __func__ << ": effectFactory: " << serviceName << " start";
     ABinderProcess_joinThreadPool();
     return EXIT_FAILURE;  // should not reach
 }
diff --git a/audio/aidl/default/EffectThread.cpp b/audio/aidl/default/EffectThread.cpp
new file mode 100644
index 0000000..80f120b
--- /dev/null
+++ b/audio/aidl/default/EffectThread.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_EffectThread"
+#include <android-base/logging.h>
+#include <pthread.h>
+#include <sys/resource.h>
+
+#include "effect-impl/EffectThread.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+EffectThread::EffectThread() {
+    LOG(DEBUG) << __func__;
+}
+
+EffectThread::~EffectThread() {
+    destroyThread();
+    LOG(DEBUG) << __func__ << " done";
+};
+
+RetCode EffectThread::createThread(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;
+    mThread = std::thread(&EffectThread::threadLoop, this);
+    LOG(DEBUG) << __func__ << " " << name << " priority " << mPriority << " done";
+    return RetCode::SUCCESS;
+}
+
+RetCode EffectThread::destroyThread() {
+    {
+        std::lock_guard lg(mMutex);
+        mStop = mExit = true;
+    }
+    mCv.notify_one();
+
+    if (mThread.joinable()) {
+        mThread.join();
+    }
+    LOG(DEBUG) << __func__ << " done";
+    return RetCode::SUCCESS;
+}
+
+RetCode EffectThread::startThread() {
+    if (!mThread.joinable()) {
+        LOG(ERROR) << __func__ << " thread already destroyed";
+        return RetCode::ERROR_THREAD;
+    }
+
+    {
+        std::lock_guard lg(mMutex);
+        if (!mStop) {
+            LOG(WARNING) << __func__ << " already start";
+            return RetCode::SUCCESS;
+        }
+        mStop = false;
+    }
+
+    mCv.notify_one();
+    LOG(DEBUG) << __func__ << " done";
+    return RetCode::SUCCESS;
+}
+
+RetCode EffectThread::stopThread() {
+    if (!mThread.joinable()) {
+        LOG(ERROR) << __func__ << " thread already destroyed";
+        return RetCode::ERROR_THREAD;
+    }
+
+    {
+        std::lock_guard lg(mMutex);
+        if (mStop) {
+            LOG(WARNING) << __func__ << " already stop";
+            return RetCode::SUCCESS;
+        }
+        mStop = true;
+    }
+    LOG(DEBUG) << __func__ << " done";
+    return RetCode::SUCCESS;
+}
+
+void EffectThread::threadLoop() {
+    pthread_setname_np(pthread_self(), mName.substr(0, MAX_TASK_COMM_LEN - 1).c_str());
+    setpriority(PRIO_PROCESS, 0, mPriority);
+    while (true) {
+        bool needExit = false;
+        {
+            std::unique_lock l(mMutex);
+            mCv.wait(l, [&]() REQUIRES(mMutex) {
+                needExit = mExit;
+                return mExit || !mStop;
+            });
+        }
+        if (needExit) {
+            LOG(WARNING) << __func__ << " EXIT!";
+            return;
+        }
+        // process without lock
+        process();
+    }
+}
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp
index deaca49..6863fe3 100644
--- a/audio/aidl/default/Module.cpp
+++ b/audio/aidl/default/Module.cpp
@@ -25,6 +25,7 @@
 #include <aidl/android/media/audio/common/AudioOutputFlags.h>
 
 #include "core-impl/Module.h"
+#include "core-impl/Telephony.h"
 #include "core-impl/utils.h"
 
 using aidl::android::hardware::audio::common::SinkMetadata;
@@ -245,6 +246,15 @@
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus Module::getTelephony(std::shared_ptr<ITelephony>* _aidl_return) {
+    if (mTelephony == nullptr) {
+        mTelephony = ndk::SharedRefBase::make<Telephony>();
+    }
+    *_aidl_return = mTelephony;
+    LOG(DEBUG) << __func__ << ": returning instance of ITelephony: " << _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;
@@ -779,4 +789,60 @@
     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
 }
 
+ndk::ScopedAStatus Module::getMasterMute(bool* _aidl_return) {
+    *_aidl_return = mMasterMute;
+    LOG(DEBUG) << __func__ << ": returning " << *_aidl_return;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::setMasterMute(bool in_mute) {
+    LOG(DEBUG) << __func__ << ": " << in_mute;
+    mMasterMute = in_mute;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::getMasterVolume(float* _aidl_return) {
+    *_aidl_return = mMasterVolume;
+    LOG(DEBUG) << __func__ << ": returning " << *_aidl_return;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::setMasterVolume(float in_volume) {
+    LOG(DEBUG) << __func__ << ": " << in_volume;
+    if (in_volume >= 0.0f && in_volume <= 1.0f) {
+        mMasterVolume = in_volume;
+        return ndk::ScopedAStatus::ok();
+    }
+    LOG(ERROR) << __func__ << ": invalid master volume value: " << in_volume;
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+}
+
+ndk::ScopedAStatus Module::getMicMute(bool* _aidl_return) {
+    *_aidl_return = mMicMute;
+    LOG(DEBUG) << __func__ << ": returning " << *_aidl_return;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::setMicMute(bool in_mute) {
+    LOG(DEBUG) << __func__ << ": " << in_mute;
+    mMicMute = in_mute;
+    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);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::updateScreenRotation(ScreenRotation in_rotation) {
+    LOG(DEBUG) << __func__ << ": " << toString(in_rotation);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::updateScreenState(bool in_isTurnedOn) {
+    LOG(DEBUG) << __func__ << ": " << in_isTurnedOn;
+    return ndk::ScopedAStatus::ok();
+}
+
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp
index 312df72..21dc4b6 100644
--- a/audio/aidl/default/Stream.cpp
+++ b/audio/aidl/default/Stream.cpp
@@ -85,126 +85,344 @@
     return "";
 }
 
+void StreamWorkerCommonLogic::populateReply(StreamDescriptor::Reply* reply,
+                                            bool isConnected) const {
+    if (isConnected) {
+        reply->status = STATUS_OK;
+        reply->observable.frames = mFrameCount;
+        reply->observable.timeNs = ::android::elapsedRealtimeNano();
+    } else {
+        reply->status = STATUS_NO_INIT;
+    }
+}
+
 const std::string StreamInWorkerLogic::kThreadName = "reader";
 
 StreamInWorkerLogic::Status StreamInWorkerLogic::cycle() {
     StreamDescriptor::Command command{};
     if (!mCommandMQ->readBlocking(&command, 1)) {
         LOG(ERROR) << __func__ << ": reading of command from MQ failed";
+        mState = StreamDescriptor::State::ERROR;
         return Status::ABORT;
     }
     StreamDescriptor::Reply reply{};
-    if (command.code == StreamContext::COMMAND_EXIT &&
-        command.fmqByteCount == mInternalCommandCookie) {
-        LOG(DEBUG) << __func__ << ": received EXIT command";
-        // This is an internal command, no need to reply.
-        return Status::EXIT;
-    } else if (command.code == StreamDescriptor::COMMAND_BURST && command.fmqByteCount >= 0) {
-        LOG(DEBUG) << __func__ << ": received BURST read command for " << command.fmqByteCount
-                   << " bytes";
-        usleep(3000);  // Simulate a blocking call into the driver.
-        const size_t byteCount = std::min({static_cast<size_t>(command.fmqByteCount),
-                                           mDataMQ->availableToWrite(), mDataBufferSize});
-        const bool isConnected = mIsConnected;
-        // Simulate reading of data, or provide zeroes if the stream is not connected.
-        for (size_t i = 0; i < byteCount; ++i) {
-            using buffer_type = decltype(mDataBuffer)::element_type;
-            constexpr int kBufferValueRange = std::numeric_limits<buffer_type>::max() -
-                                              std::numeric_limits<buffer_type>::min() + 1;
-            mDataBuffer[i] = isConnected ? (std::rand() % kBufferValueRange) +
-                                                   std::numeric_limits<buffer_type>::min()
-                                         : 0;
-        }
-        bool success = byteCount > 0 ? mDataMQ->write(&mDataBuffer[0], byteCount) : true;
-        if (success) {
-            LOG(DEBUG) << __func__ << ": writing of " << byteCount << " bytes into data MQ"
-                       << " succeeded; connected? " << isConnected;
-            // Frames are provided and counted regardless of connection status.
-            reply.fmqByteCount = byteCount;
-            mFrameCount += byteCount / mFrameSize;
-            if (isConnected) {
-                reply.status = STATUS_OK;
-                reply.observable.frames = mFrameCount;
-                reply.observable.timeNs = ::android::elapsedRealtimeNano();
+    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>();
+                cookie == mInternalCommandCookie) {
+                LOG(DEBUG) << __func__ << ": received EXIT command";
+                setClosed();
+                // This is an internal command, no need to reply.
+                return Status::EXIT;
             } else {
+                LOG(WARNING) << __func__ << ": EXIT command has a bad cookie: " << cookie;
+            }
+            break;
+        case Tag::start:
+            LOG(DEBUG) << __func__ << ": received START read command";
+            if (mState == StreamDescriptor::State::STANDBY ||
+                mState == StreamDescriptor::State::DRAINING) {
+                populateReply(&reply, mIsConnected);
+                mState = mState == StreamDescriptor::State::STANDBY
+                                 ? 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;
             }
-        } else {
-            LOG(WARNING) << __func__ << ": writing of " << byteCount
-                         << " bytes of data to MQ failed";
-            reply.status = STATUS_NOT_ENOUGH_DATA;
-        }
-        reply.latencyMs = Module::kLatencyMs;
-    } else {
-        LOG(WARNING) << __func__ << ": invalid command (" << command.toString()
-                     << ") or count: " << command.fmqByteCount;
-        reply.status = STATUS_BAD_VALUE;
+            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";
+                if (mState == StreamDescriptor::State::IDLE ||
+                    mState == StreamDescriptor::State::ACTIVE ||
+                    mState == StreamDescriptor::State::PAUSED ||
+                    mState == StreamDescriptor::State::DRAINING) {
+                    if (!read(fmqByteCount, &reply)) {
+                        mState = StreamDescriptor::State::ERROR;
+                    }
+                    if (mState == StreamDescriptor::State::IDLE ||
+                        mState == StreamDescriptor::State::PAUSED) {
+                        mState = StreamDescriptor::State::ACTIVE;
+                    } 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.
+                        mState = StreamDescriptor::State::STANDBY;
+                    }
+                } else {
+                    LOG(WARNING) << __func__ << ": BURST command can not be handled in the state "
+                                 << toString(mState);
+                    reply.status = STATUS_INVALID_OPERATION;
+                }
+            } 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;
+            } else {
+                LOG(WARNING) << __func__ << ": DRAIN command can not be handled in the state "
+                             << toString(mState);
+                reply.status = STATUS_INVALID_OPERATION;
+            }
+            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;
+            }
+            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;
+            }
+            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;
+            }
+            break;
     }
+    reply.state = mState;
     LOG(DEBUG) << __func__ << ": writing reply " << reply.toString();
     if (!mReplyMQ->writeBlocking(&reply, 1)) {
         LOG(ERROR) << __func__ << ": writing of reply " << reply.toString() << " to MQ failed";
+        mState = StreamDescriptor::State::ERROR;
         return Status::ABORT;
     }
     return Status::CONTINUE;
 }
 
+bool StreamInWorkerLogic::read(size_t clientSize, StreamDescriptor::Reply* reply) {
+    // Can switch the state to ERROR if a driver error occurs.
+    const size_t byteCount = std::min({clientSize, mDataMQ->availableToWrite(), mDataBufferSize});
+    const bool isConnected = mIsConnected;
+    bool fatal = false;
+    // Simulate reading of data, or provide zeroes if the stream is not connected.
+    for (size_t i = 0; i < byteCount; ++i) {
+        using buffer_type = decltype(mDataBuffer)::element_type;
+        constexpr int kBufferValueRange = std::numeric_limits<buffer_type>::max() -
+                                          std::numeric_limits<buffer_type>::min() + 1;
+        mDataBuffer[i] = isConnected ? (std::rand() % kBufferValueRange) +
+                                               std::numeric_limits<buffer_type>::min()
+                                     : 0;
+    }
+    usleep(3000);  // Simulate a blocking call into the driver.
+    // Set 'fatal = true' if a driver error occurs.
+    if (bool success = byteCount > 0 ? mDataMQ->write(&mDataBuffer[0], byteCount) : true; success) {
+        LOG(DEBUG) << __func__ << ": writing of " << byteCount << " bytes into data MQ"
+                   << " succeeded; connected? " << isConnected;
+        // Frames are provided and counted regardless of connection status.
+        reply->fmqByteCount += byteCount;
+        mFrameCount += byteCount / mFrameSize;
+        populateReply(reply, isConnected);
+    } else {
+        LOG(WARNING) << __func__ << ": writing of " << byteCount << " bytes of data to MQ failed";
+        reply->status = STATUS_NOT_ENOUGH_DATA;
+    }
+    reply->latencyMs = Module::kLatencyMs;
+    return !fatal;
+}
+
 const std::string StreamOutWorkerLogic::kThreadName = "writer";
 
 StreamOutWorkerLogic::Status StreamOutWorkerLogic::cycle() {
     StreamDescriptor::Command command{};
     if (!mCommandMQ->readBlocking(&command, 1)) {
         LOG(ERROR) << __func__ << ": reading of command from MQ failed";
+        mState = StreamDescriptor::State::ERROR;
         return Status::ABORT;
     }
     StreamDescriptor::Reply reply{};
-    if (command.code == StreamContext::COMMAND_EXIT &&
-        command.fmqByteCount == mInternalCommandCookie) {
-        LOG(DEBUG) << __func__ << ": received EXIT command";
-        // This is an internal command, no need to reply.
-        return Status::EXIT;
-    } else if (command.code == StreamDescriptor::COMMAND_BURST && command.fmqByteCount >= 0) {
-        LOG(DEBUG) << __func__ << ": received BURST write command for " << command.fmqByteCount
-                   << " bytes";
-        const size_t byteCount = std::min({static_cast<size_t>(command.fmqByteCount),
-                                           mDataMQ->availableToRead(), mDataBufferSize});
-        bool success = byteCount > 0 ? mDataMQ->read(&mDataBuffer[0], byteCount) : true;
-        if (success) {
-            const bool isConnected = mIsConnected;
-            LOG(DEBUG) << __func__ << ": reading of " << byteCount << " bytes from data MQ"
-                       << " succeeded; connected? " << isConnected;
-            // Frames are consumed and counted regardless of connection status.
-            reply.fmqByteCount = byteCount;
-            mFrameCount += byteCount / mFrameSize;
-            if (isConnected) {
-                reply.status = STATUS_OK;
-                reply.observable.frames = mFrameCount;
-                reply.observable.timeNs = ::android::elapsedRealtimeNano();
+    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>();
+                cookie == mInternalCommandCookie) {
+                LOG(DEBUG) << __func__ << ": received EXIT command";
+                setClosed();
+                // This is an internal command, no need to reply.
+                return Status::EXIT;
             } else {
+                LOG(WARNING) << __func__ << ": EXIT command has a bad cookie: " << cookie;
+            }
+            break;
+        case Tag::start:
+            LOG(DEBUG) << __func__ << ": received START write command";
+            switch (mState) {
+                case StreamDescriptor::State::STANDBY:
+                    mState = StreamDescriptor::State::IDLE;
+                    break;
+                case StreamDescriptor::State::PAUSED:
+                    mState = StreamDescriptor::State::ACTIVE;
+                    break;
+                case StreamDescriptor::State::DRAIN_PAUSED:
+                    mState = StreamDescriptor::State::PAUSED;
+                    break;
+                default:
+                    LOG(WARNING) << __func__ << ": START command can not be handled in the state "
+                                 << toString(mState);
+                    reply.status = STATUS_INVALID_OPERATION;
+            }
+            if (reply.status != STATUS_INVALID_OPERATION) {
+                populateReply(&reply, mIsConnected);
+            }
+            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
+                    if (!write(fmqByteCount, &reply)) {
+                        mState = StreamDescriptor::State::ERROR;
+                    }
+                    if (mState == StreamDescriptor::State::STANDBY ||
+                        mState == StreamDescriptor::State::DRAIN_PAUSED) {
+                        mState = StreamDescriptor::State::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.
+                } else {
+                    LOG(WARNING) << __func__ << ": BURST command can not be handled in the state "
+                                 << toString(mState);
+                    reply.status = STATUS_INVALID_OPERATION;
+                }
+            } 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.
+            } else {
+                LOG(WARNING) << __func__ << ": DRAIN command can not be handled in the state "
+                             << toString(mState);
                 reply.status = STATUS_INVALID_OPERATION;
             }
-            usleep(3000);  // Simulate a blocking call into the driver.
-        } else {
-            LOG(WARNING) << __func__ << ": reading of " << byteCount
-                         << " bytes of data from MQ failed";
-            reply.status = STATUS_NOT_ENOUGH_DATA;
-        }
-        reply.latencyMs = Module::kLatencyMs;
-    } else {
-        LOG(WARNING) << __func__ << ": invalid command (" << command.toString()
-                     << ") or count: " << command.fmqByteCount;
-        reply.status = STATUS_BAD_VALUE;
+            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;
+            }
+            break;
+        case Tag::pause:
+            LOG(DEBUG) << __func__ << ": received PAUSE write command";
+            if (mState == StreamDescriptor::State::ACTIVE ||
+                mState == StreamDescriptor::State::DRAINING) {
+                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;
+        case Tag::flush:
+            LOG(DEBUG) << __func__ << ": received FLUSH write command";
+            if (mState == StreamDescriptor::State::PAUSED ||
+                mState == StreamDescriptor::State::DRAIN_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;
+            }
+            break;
     }
+    reply.state = mState;
     LOG(DEBUG) << __func__ << ": writing reply " << reply.toString();
     if (!mReplyMQ->writeBlocking(&reply, 1)) {
         LOG(ERROR) << __func__ << ": writing of reply " << reply.toString() << " to MQ failed";
+        mState = StreamDescriptor::State::ERROR;
         return Status::ABORT;
     }
     return Status::CONTINUE;
 }
 
+bool StreamOutWorkerLogic::write(size_t clientSize, StreamDescriptor::Reply* reply) {
+    const size_t readByteCount = mDataMQ->availableToRead();
+    // Amount of data that the HAL module is going to actually use.
+    const size_t byteCount = std::min({clientSize, readByteCount, mDataBufferSize});
+    bool fatal = false;
+    if (bool success = readByteCount > 0 ? mDataMQ->read(&mDataBuffer[0], readByteCount) : true) {
+        const bool isConnected = mIsConnected;
+        LOG(DEBUG) << __func__ << ": reading of " << readByteCount << " bytes from data MQ"
+                   << " succeeded; connected? " << isConnected;
+        // Frames are consumed and counted regardless of connection status.
+        reply->fmqByteCount += byteCount;
+        mFrameCount += byteCount / mFrameSize;
+        populateReply(reply, isConnected);
+        usleep(3000);  // Simulate a blocking call into the driver.
+        // Set 'fatal = true' if a driver error occurs.
+    } else {
+        LOG(WARNING) << __func__ << ": reading of " << readByteCount
+                     << " bytes of data from MQ failed";
+        reply->status = STATUS_NOT_ENOUGH_DATA;
+    }
+    reply->latencyMs = Module::kLatencyMs;
+    return !fatal;
+}
+
 template <class Metadata, class StreamWorker>
 StreamCommon<Metadata, StreamWorker>::~StreamCommon() {
-    if (!mIsClosed) {
+    if (!isClosed()) {
         LOG(ERROR) << __func__ << ": stream was not closed prior to destruction, resource leak";
         stopWorker();
         // The worker and the context should clean up by themselves via destructors.
@@ -214,13 +432,13 @@
 template <class Metadata, class StreamWorker>
 ndk::ScopedAStatus StreamCommon<Metadata, StreamWorker>::close() {
     LOG(DEBUG) << __func__;
-    if (!mIsClosed) {
+    if (!isClosed()) {
         stopWorker();
         LOG(DEBUG) << __func__ << ": joining the worker thread...";
         mWorker.stop();
         LOG(DEBUG) << __func__ << ": worker thread joined";
         mContext.reset();
-        mIsClosed = true;
+        mWorker.setClosed();
         return ndk::ScopedAStatus::ok();
     } else {
         LOG(ERROR) << __func__ << ": stream was already closed";
@@ -231,13 +449,14 @@
 template <class Metadata, class StreamWorker>
 void StreamCommon<Metadata, StreamWorker>::stopWorker() {
     if (auto commandMQ = mContext.getCommandMQ(); commandMQ != nullptr) {
-        LOG(DEBUG) << __func__ << ": asking the worker to stop...";
-        StreamDescriptor::Command cmd;
-        cmd.code = StreamContext::COMMAND_EXIT;
-        cmd.fmqByteCount = mContext.getInternalCommandCookie();
-        // FIXME: This can block in the case when the client wrote a command
-        // while the stream worker's cycle is not running. Need to revisit
-        // when implementing standby and pause/resume.
+        LOG(DEBUG) << __func__ << ": asking the worker to exit...";
+        auto cmd =
+                StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::hal_reserved_exit>(
+                        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
+        // on the HAL side can cause a deadlock.
         if (!commandMQ->writeBlocking(&cmd, 1)) {
             LOG(ERROR) << __func__ << ": failed to write exit command to the MQ";
         }
@@ -248,7 +467,7 @@
 template <class Metadata, class StreamWorker>
 ndk::ScopedAStatus StreamCommon<Metadata, StreamWorker>::updateMetadata(const Metadata& metadata) {
     LOG(DEBUG) << __func__;
-    if (!mIsClosed) {
+    if (!isClosed()) {
         mMetadata = metadata;
         return ndk::ScopedAStatus::ok();
     }
diff --git a/audio/aidl/default/Telephony.cpp b/audio/aidl/default/Telephony.cpp
new file mode 100644
index 0000000..1854b35
--- /dev/null
+++ b/audio/aidl/default/Telephony.cpp
@@ -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.
+ */
+
+#include <android/binder_to_string.h>
+#define LOG_TAG "AHAL_Telephony"
+#include <android-base/logging.h>
+
+#include "core-impl/Telephony.h"
+
+namespace aidl::android::hardware::audio::core {
+
+ndk::ScopedAStatus Telephony::getSupportedAudioModes(std::vector<AudioMode>* _aidl_return) {
+    *_aidl_return = mSupportedAudioModes;
+    LOG(DEBUG) << __func__ << ": returning " << ::android::internal::ToString(*_aidl_return);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Telephony::switchAudioMode(AudioMode in_mode) {
+    if (std::find(mSupportedAudioModes.begin(), mSupportedAudioModes.end(), in_mode) !=
+        mSupportedAudioModes.end()) {
+        LOG(DEBUG) << __func__ << ": " << toString(in_mode);
+        return ndk::ScopedAStatus::ok();
+    }
+    LOG(ERROR) << __func__ << ": unsupported mode " << toString(in_mode);
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+}  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/audio_effects_config.xml b/audio/aidl/default/audio_effects_config.xml
new file mode 100644
index 0000000..f4ac8fe
--- /dev/null
+++ b/audio/aidl/default/audio_effects_config.xml
@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<audio_effects_conf version="2.0" xmlns="http://schemas.android.com/audio/audio_effects_conf/v2_0">
+    <!-- Overview.
+         This example config file was copy from existing one: frameworks/av/media/libeffects/data/
+         audio_effects.xml, with effect library names updated to AIDL libraries we currently have.
+
+         All "library" attributes in "effect" element must must match a "library" element with the
+         same value of the "name" attribute.
+         All "effect" attributes in "preprocess" and "postprocess" element must match an "effect"
+         element with the same value of the "name" attribute.
+
+         AIDL EffectFactory are relying on the "name" attribute in "effect" element to identify the
+         effect type, so it's necessary to have the mapping from name to effect type UUID. Make
+         sure to either use existing effect name as key of
+         ::android::hardware::audio::effect::kUuidNameTypeMap, or add a new {name, typeUUID} map
+         item to the kUuidNameTypeMap.
+
+         Existing audio_effects.xml should working without any change as long as:
+         1. "path" attribute of "library" element matches with the actual effect library name.
+         2. "name" attribute of "effect" and "effectProxy" element correctly added as key of
+            kUuidNameTypeMap, with value matches Identity.type in Descriptor.aidl.
+         3. "uuid" attribute of "effect" element matches Identity.uuid in Descriptor.aidl.
+         4. "uuid" attribute of "effectProxy" element matches Identity.proxy in Descriptor.aidl.
+    -->
+
+    <!-- List of effect libraries to load.
+         Each library element must contain a "name" attribute and a "path" attribute giving the
+         name of a library .so file on the target device.
+    -->
+    <libraries>
+        <library name="bassboostsw" path="libbassboostsw.so"/>
+        <library name="bundle" path="libbundleaidl.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="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="volumesw" path="libvolumesw.so"/>
+    </libraries>
+
+    <!-- list of effects to load.
+         Each "effect" element must contain a "name", "library" and a "uuid" attribute.
+         The value of the "library" attribute must correspond to the name of one library element in
+         the "libraries" element.
+         The "name" attribute used to specific effect type, and should be mapping to a key of
+         aidl::android::hardware::audio::effect::kUuidNameTypeMap.
+         The "uuid" attribute is the implementation specific UUID as specified by the effect vendor.
+
+         Effect proxy can be supported with "effectProxy" element, each sub-element should contain
+         "library" and "uuid" attribute, all other attributes were ignored. Framework side use
+         result of IFactory.queryEffects() to decide which effect implementation should be part of
+         proxy and which not.
+
+         Only "name", "library", and "uuid" attributes in "effects" element are meaningful and
+         parsed out by EffectConfig class, all other attributes are ignored.
+         Only "name" and "uuid" attributes in "effectProxy" element are meaningful and parsed out
+         by EffectConfig class, all other attributes are ignored.
+    -->
+
+    <effects>
+        <effect name="bassboost" library="bassboostsw" uuid="fa8181f2-588b-11ed-9b6a-0242ac120002"/>
+        <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="env_reverb" library="env_reverbsw" uuid="fa819886-588b-11ed-9b6a-0242ac120002"/>
+        <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="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"/>
+        </effectProxy>
+    </effects>
+
+    <!-- Audio pre processor configurations.
+         The pre processor configuration is described in a "preprocess" element and consists in a
+         list of elements each describing pre processor settings for a given use case or "stream".
+         Each stream element has a "type" attribute corresponding to the input source used.
+         Valid types are these defined in system/hardware/interfaces/media/aidl/android/media/audio/
+         common/AudioSource.aidl.
+         Each "stream" element contains a list of "apply" elements indicating one effect to apply.
+         The effect to apply is designated by its name in the "effects" elements.
+         If there are more than one effect apply to one stream, the audio framework will apply them
+         in the same equence as they listed in "stream" element.
+
+        <preprocess>
+            <stream type="voice_communication">
+                <apply effect="aec"/>
+                <apply effect="ns"/>
+            </stream>
+        </preprocess>
+    -->
+
+    <!-- Audio post processor configurations.
+         The post processor configuration is described in a "postprocess" element and consists in a
+         list of elements each describing post processor settings for a given use case or "stream".
+         Each stream element has a "type" attribute corresponding to the stream type used.
+         Valid types are these defined in system/hardware/interfaces/media/aidl/android/media/audio/
+         common/AudioStreamType.aidl.
+         Each "stream" element contains a list of "apply" elements indicating one effect to apply.
+         The effect to apply is designated by its name in the "effects" elements.
+         If there are more than one effect apply to one stream, the audio framework will apply them
+         in the same equence as they listed in "stream" element.
+
+        <postprocess>
+            <stream type="music">
+                <apply effect="music_post_proc"/>
+            </stream>
+            <stream type="voice_call">
+                <apply effect="voice_post_proc"/>
+            </stream>
+            <stream type="notification">
+                <apply effect="notification_post_proc"/>
+            </stream>
+        </postprocess>
+    -->
+
+</audio_effects_conf>
diff --git a/audio/aidl/default/bassboost/Android.bp b/audio/aidl/default/bassboost/Android.bp
new file mode 100644
index 0000000..f22eb95
--- /dev/null
+++ b/audio/aidl/default/bassboost/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: "libbassboostsw",
+    defaults: [
+        "aidlaudioeffectservice_defaults",
+        "latest_android_media_audio_common_types_ndk_shared",
+        "latest_android_hardware_audio_effect_ndk_shared",
+    ],
+    srcs: [
+        "BassBoostSw.cpp",
+        ":effectCommonFile",
+    ],
+    visibility: [
+        "//hardware/interfaces/audio/aidl/default",
+    ],
+}
diff --git a/audio/aidl/default/bassboost/BassBoostSw.cpp b/audio/aidl/default/bassboost/BassBoostSw.cpp
new file mode 100644
index 0000000..c52d16f
--- /dev/null
+++ b/audio/aidl/default/bassboost/BassBoostSw.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 <cstddef>
+#define LOG_TAG "AHAL_BassBoostSw"
+#include <Utils.h>
+#include <algorithm>
+#include <unordered_set>
+
+#include <android-base/logging.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include "BassBoostSw.h"
+
+using aidl::android::hardware::audio::effect::BassBoostSw;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kBassBoostSwImplUUID;
+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 != kBassBoostSwImplUUID) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    if (instanceSpp) {
+        *instanceSpp = ndk::SharedRefBase::make<BassBoostSw>();
+        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 destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
+    if (!instanceSp) {
+        return EX_NONE;
+    }
+    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 BassBoostSw::getDescriptor(Descriptor* _aidl_return) {
+    LOG(DEBUG) << __func__ << kDescriptor.toString();
+    *_aidl_return = kDescriptor;
+    return ndk::ScopedAStatus::ok();
+}
+
+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();
+}
+
+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);
+    return ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EffectContext> BassBoostSw::createContext(const Parameter::Common& common) {
+    if (mContext) {
+        LOG(DEBUG) << __func__ << " context already exist";
+        return mContext;
+    }
+    mContext = std::make_shared<BassBoostSwContext>(1 /* statusFmqDepth */, common);
+    return mContext;
+}
+
+RetCode BassBoostSw::releaseContext() {
+    if (mContext) {
+        mContext.reset();
+    }
+    return RetCode::SUCCESS;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status BassBoostSw::effectProcessImpl(float* in, float* out, int process) {
+    // TODO: get data buffer and process.
+    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
+    for (int i = 0; i < process; i++) {
+        *out++ = *in++;
+    }
+    return {STATUS_OK, process, process};
+}
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/bassboost/BassBoostSw.h b/audio/aidl/default/bassboost/BassBoostSw.h
new file mode 100644
index 0000000..90a8887
--- /dev/null
+++ b/audio/aidl/default/bassboost/BassBoostSw.h
@@ -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.
+ */
+
+#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 BassBoostSwContext final : public EffectContext {
+  public:
+    BassBoostSwContext(int statusDepth, const Parameter::Common& common)
+        : EffectContext(statusDepth, common) {
+        LOG(DEBUG) << __func__;
+    }
+    // TODO: add specific context here
+};
+
+class BassBoostSw final : public EffectImpl {
+  public:
+    BassBoostSw() { LOG(DEBUG) << __func__; }
+    ~BassBoostSw() {
+        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;
+    IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+    RetCode releaseContext() 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;
+};
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/config/audio_policy_configuration.xsd b/audio/aidl/default/config/audio_policy_configuration.xsd
new file mode 100644
index 0000000..2c18a1e
--- /dev/null
+++ b/audio/aidl/default/config/audio_policy_configuration.xsd
@@ -0,0 +1,829 @@
+<?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: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: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/dynamicProcessing/Android.bp b/audio/aidl/default/dynamicProcessing/Android.bp
new file mode 100644
index 0000000..3697ba3
--- /dev/null
+++ b/audio/aidl/default/dynamicProcessing/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: "libdynamicsprocessingsw",
+    defaults: [
+        "aidlaudioeffectservice_defaults",
+        "latest_android_media_audio_common_types_ndk_shared",
+        "latest_android_hardware_audio_effect_ndk_shared",
+    ],
+    srcs: [
+        "DynamicsProcessingSw.cpp",
+        ":effectCommonFile",
+    ],
+    visibility: [
+        "//hardware/interfaces/audio/aidl/default",
+    ],
+}
diff --git a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp
new file mode 100644
index 0000000..3920a58
--- /dev/null
+++ b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.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.
+ */
+
+#include <cstddef>
+#define LOG_TAG "AHAL_DynamicsProcessingSw"
+#include <Utils.h>
+#include <algorithm>
+#include <unordered_set>
+
+#include <android-base/logging.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include "DynamicsProcessingSw.h"
+
+using aidl::android::hardware::audio::effect::DynamicsProcessingSw;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kDynamicsProcessingSwImplUUID;
+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 != kDynamicsProcessingSwImplUUID) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    if (instanceSpp) {
+        *instanceSpp = ndk::SharedRefBase::make<DynamicsProcessingSw>();
+        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 destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
+    if (!instanceSp) {
+        return EX_NONE;
+    }
+    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 DynamicsProcessingSw::getDescriptor(Descriptor* _aidl_return) {
+    LOG(DEBUG) << __func__ << kDescriptor.toString();
+    *_aidl_return = kDescriptor;
+    return ndk::ScopedAStatus::ok();
+}
+
+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();
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus DynamicsProcessingSw::getParameterSpecific(const Parameter::Id& id,
+                                                              Parameter::Specific* specific) {
+    auto tag = id.getTag();
+    RETURN_IF(Parameter::Id::dynamicsProcessingTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
+    specific->set<Parameter::Specific::dynamicsProcessing>(mSpecificParam);
+    return ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EffectContext> DynamicsProcessingSw::createContext(
+        const Parameter::Common& common) {
+    if (mContext) {
+        LOG(DEBUG) << __func__ << " context already exist";
+        return mContext;
+    }
+    mContext = std::make_shared<DynamicsProcessingSwContext>(1 /* statusFmqDepth */, common);
+    return mContext;
+}
+
+RetCode DynamicsProcessingSw::releaseContext() {
+    if (mContext) {
+        mContext.reset();
+    }
+    return RetCode::SUCCESS;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status DynamicsProcessingSw::effectProcessImpl(float* in, float* out, int process) {
+    // TODO: get data buffer and process.
+    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
+    for (int i = 0; i < process; i++) {
+        *out++ = *in++;
+    }
+    return {STATUS_OK, process, process};
+}
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h
new file mode 100644
index 0000000..2bc2762
--- /dev/null
+++ b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h
@@ -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.
+ */
+
+#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 DynamicsProcessingSwContext final : public EffectContext {
+  public:
+    DynamicsProcessingSwContext(int statusDepth, const Parameter::Common& common)
+        : EffectContext(statusDepth, common) {
+        LOG(DEBUG) << __func__;
+    }
+    // TODO: add specific context here
+};
+
+class DynamicsProcessingSw final : public EffectImpl {
+  public:
+    DynamicsProcessingSw() { LOG(DEBUG) << __func__; }
+    ~DynamicsProcessingSw() {
+        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;
+    IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+    RetCode releaseContext() override;
+
+  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;
+};
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/envReverb/Android.bp b/audio/aidl/default/envReverb/Android.bp
new file mode 100644
index 0000000..c239ee5
--- /dev/null
+++ b/audio/aidl/default/envReverb/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: "libenvreverbsw",
+    defaults: [
+        "aidlaudioeffectservice_defaults",
+        "latest_android_media_audio_common_types_ndk_shared",
+        "latest_android_hardware_audio_effect_ndk_shared",
+    ],
+    srcs: [
+        "EnvReverbSw.cpp",
+        ":effectCommonFile",
+    ],
+    visibility: [
+        "//hardware/interfaces/audio/aidl/default",
+    ],
+}
diff --git a/audio/aidl/default/envReverb/EnvReverbSw.cpp b/audio/aidl/default/envReverb/EnvReverbSw.cpp
new file mode 100644
index 0000000..ad447ab
--- /dev/null
+++ b/audio/aidl/default/envReverb/EnvReverbSw.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 <cstddef>
+#define LOG_TAG "AHAL_EnvReverbSw"
+#include <Utils.h>
+#include <algorithm>
+#include <unordered_set>
+
+#include <android-base/logging.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include "EnvReverbSw.h"
+
+using aidl::android::hardware::audio::effect::EnvReverbSw;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kEnvReverbSwImplUUID;
+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 != kEnvReverbSwImplUUID) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    if (instanceSpp) {
+        *instanceSpp = ndk::SharedRefBase::make<EnvReverbSw>();
+        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 destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
+    if (!instanceSp) {
+        return EX_NONE;
+    }
+    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 EnvReverbSw::getDescriptor(Descriptor* _aidl_return) {
+    LOG(DEBUG) << __func__ << kDescriptor.toString();
+    *_aidl_return = kDescriptor;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EnvReverbSw::setParameterSpecific(const Parameter::Specific& specific) {
+    RETURN_IF(Parameter::Specific::reverb != 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();
+}
+
+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 ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EffectContext> EnvReverbSw::createContext(const Parameter::Common& common) {
+    if (mContext) {
+        LOG(DEBUG) << __func__ << " context already exist";
+        return mContext;
+    }
+    mContext = std::make_shared<EnvReverbSwContext>(1 /* statusFmqDepth */, common);
+    return mContext;
+}
+
+RetCode EnvReverbSw::releaseContext() {
+    if (mContext) {
+        mContext.reset();
+    }
+    return RetCode::SUCCESS;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status EnvReverbSw::effectProcessImpl(float* in, float* out, int process) {
+    // TODO: get data buffer and process.
+    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
+    for (int i = 0; i < process; i++) {
+        *out++ = *in++;
+    }
+    return {STATUS_OK, process, process};
+}
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/envReverb/EnvReverbSw.h b/audio/aidl/default/envReverb/EnvReverbSw.h
new file mode 100644
index 0000000..5a9ab27
--- /dev/null
+++ b/audio/aidl/default/envReverb/EnvReverbSw.h
@@ -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.
+ */
+
+#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 EnvReverbSwContext final : public EffectContext {
+  public:
+    EnvReverbSwContext(int statusDepth, const Parameter::Common& common)
+        : EffectContext(statusDepth, common) {
+        LOG(DEBUG) << __func__;
+    }
+    // TODO: add specific context here
+};
+
+class EnvReverbSw final : public EffectImpl {
+  public:
+    EnvReverbSw() { LOG(DEBUG) << __func__; }
+    ~EnvReverbSw() {
+        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;
+    IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+    RetCode releaseContext() override;
+
+  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;
+};
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/equalizer/Android.bp b/audio/aidl/default/equalizer/Android.bp
index b842149..8de6b1a 100644
--- a/audio/aidl/default/equalizer/Android.bp
+++ b/audio/aidl/default/equalizer/Android.bp
@@ -24,20 +24,15 @@
 }
 
 cc_library_shared {
-    name: "libequalizer",
-    vendor: true,
-    shared_libs: [
-        "libbase",
-        "libbinder_ndk",
-        "libstagefright_foundation",
-    ],
+    name: "libequalizersw",
     defaults: [
+        "aidlaudioeffectservice_defaults",
         "latest_android_media_audio_common_types_ndk_shared",
         "latest_android_hardware_audio_effect_ndk_shared",
     ],
-    include_dirs: ["hardware/interfaces/audio/aidl/default/include/equalizer-impl"],
     srcs: [
-        "Equalizer.cpp",
+        "EqualizerSw.cpp",
+        ":effectCommonFile",
     ],
     visibility: [
         "//hardware/interfaces/audio/aidl/default",
diff --git a/audio/aidl/default/equalizer/Equalizer.cpp b/audio/aidl/default/equalizer/Equalizer.cpp
deleted file mode 100644
index 8b157fa..0000000
--- a/audio/aidl/default/equalizer/Equalizer.cpp
+++ /dev/null
@@ -1,40 +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.
- */
-
-#define LOG_TAG "AHAL_Equalizer"
-#include <android-base/logging.h>
-
-#include "Equalizer.h"
-
-namespace aidl::android::hardware::audio::effect {
-
-ndk::ScopedAStatus Equalizer::open() {
-    LOG(DEBUG) << __func__;
-    return ndk::ScopedAStatus::ok();
-}
-
-ndk::ScopedAStatus Equalizer::close() {
-    LOG(DEBUG) << __func__;
-    return ndk::ScopedAStatus::ok();
-}
-
-ndk::ScopedAStatus Equalizer::getDescriptor(Descriptor* _aidl_return) {
-    LOG(DEBUG) << __func__ << "descriptor " << mDesc.toString();
-    *_aidl_return = mDesc;
-    return ndk::ScopedAStatus::ok();
-}
-
-}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/equalizer/EqualizerSw.cpp b/audio/aidl/default/equalizer/EqualizerSw.cpp
new file mode 100644
index 0000000..d61ef97
--- /dev/null
+++ b/audio/aidl/default/equalizer/EqualizerSw.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_EqualizerSw"
+#include <Utils.h>
+#include <algorithm>
+#include <unordered_set>
+
+#include <android-base/logging.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include "EqualizerSw.h"
+
+using aidl::android::hardware::audio::effect::EqualizerSw;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kEqualizerSwImplUUID;
+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 != kEqualizerSwImplUUID) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    if (instanceSpp) {
+        *instanceSpp = ndk::SharedRefBase::make<EqualizerSw>();
+        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 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 EqualizerSw::getDescriptor(Descriptor* _aidl_return) {
+    LOG(DEBUG) << __func__ << kDesc.toString();
+    *_aidl_return = kDesc;
+    return ndk::ScopedAStatus::ok();
+}
+
+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>();
+    auto tag = eqParam.getTag();
+    switch (tag) {
+        case Equalizer::preset: {
+            RETURN_IF(mContext->setEqPreset(eqParam.get<Equalizer::preset>()) != RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setBandLevelsFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        case Equalizer::bandLevels: {
+            RETURN_IF(mContext->setEqBandLevels(eqParam.get<Equalizer::bandLevels>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setBandLevelsFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "EqTagNotSupported");
+        }
+    }
+
+    LOG(ERROR) << __func__ << " unsupported eq param tag: " << toString(tag);
+    return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                            "ParamNotSupported");
+}
+
+ndk::ScopedAStatus EqualizerSw::getParameterSpecific(const Parameter::Id& id,
+                                                     Parameter::Specific* specific) {
+    auto tag = id.getTag();
+    RETURN_IF(Parameter::Id::equalizerTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
+    auto eqId = id.get<Parameter::Id::equalizerTag>();
+    auto eqIdTag = eqId.getTag();
+    switch (eqIdTag) {
+        case Equalizer::Id::commonTag:
+            return getParameterEqualizer(eqId.get<Equalizer::Id::commonTag>(), specific);
+        default:
+            LOG(ERROR) << __func__ << " tag " << toString(eqIdTag) << " not supported";
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "EqualizerTagNotSupported");
+    }
+}
+
+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;
+    switch (tag) {
+        case Equalizer::bandLevels: {
+            eqParam.set<Equalizer::bandLevels>(mContext->getEqBandLevels());
+            break;
+        }
+        case Equalizer::preset: {
+            eqParam.set<Equalizer::preset>(mContext->getEqPreset());
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << " not handled tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "unsupportedTag");
+        }
+    }
+
+    specific->set<Parameter::Specific::equalizer>(eqParam);
+    return ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EffectContext> EqualizerSw::createContext(const Parameter::Common& common) {
+    if (mContext) {
+        LOG(DEBUG) << __func__ << " context already exist";
+        return mContext;
+    }
+    mContext = std::make_shared<EqualizerSwContext>(1 /* statusFmqDepth */, common);
+    return mContext;
+}
+
+RetCode EqualizerSw::releaseContext() {
+    if (mContext) {
+        mContext.reset();
+    }
+    return RetCode::SUCCESS;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status EqualizerSw::effectProcessImpl(float* in, float* out, int process) {
+    // TODO: get data buffer and process.
+    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
+    for (int i = 0; i < process; i++) {
+        *out++ = *in++;
+    }
+    return {STATUS_OK, process, process};
+}
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/equalizer/EqualizerSw.h b/audio/aidl/default/equalizer/EqualizerSw.h
new file mode 100644
index 0000000..aa4587a
--- /dev/null
+++ b/audio/aidl/default/equalizer/EqualizerSw.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 EqualizerSwContext final : public EffectContext {
+  public:
+    EqualizerSwContext(int statusDepth, const Parameter::Common& common)
+        : EffectContext(statusDepth, common) {
+        LOG(DEBUG) << __func__;
+    }
+
+    RetCode setEqPreset(const int& presetIdx) {
+        if (presetIdx < 0 || presetIdx >= NUM_OF_PRESETS) {
+            return RetCode::ERROR_ILLEGAL_PARAMETER;
+        }
+        mPreset = presetIdx;
+        return RetCode::SUCCESS;
+    }
+    int getEqPreset() { return mPreset; }
+
+    RetCode setEqBandLevels(const std::vector<Equalizer::BandLevel>& bandLevels) {
+        if (bandLevels.size() > NUM_OF_BANDS) {
+            LOG(ERROR) << __func__ << " return because size exceed " << NUM_OF_BANDS;
+            return RetCode::ERROR_ILLEGAL_PARAMETER;
+        }
+        RetCode ret = RetCode::SUCCESS;
+        for (auto& it : bandLevels) {
+            if (it.index >= NUM_OF_BANDS || it.index < 0) {
+                LOG(ERROR) << __func__ << " index illegal, skip: " << it.index << " - "
+                           << it.levelMb;
+                ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+            }
+            mBandLevels[it.index] = it.levelMb;
+        }
+        return ret;
+    }
+
+    std::vector<Equalizer::BandLevel> getEqBandLevels() {
+        std::vector<Equalizer::BandLevel> bandLevels;
+        for (int i = 0; i < NUM_OF_BANDS; i++) {
+            bandLevels.push_back({i, mBandLevels[i]});
+        }
+        return bandLevels;
+    }
+
+  private:
+    static const int NUM_OF_BANDS = 5;
+    static const int NUM_OF_PRESETS = 10;
+    static const int PRESET_CUSTOM = -1;
+    // preset band level
+    int mPreset = PRESET_CUSTOM;
+    int32_t mBandLevels[NUM_OF_BANDS] = {3, 0, 0, 0, 3};
+
+    // Add equalizer specific context for processing here
+};
+
+class EqualizerSw final : public EffectImpl {
+  public:
+    EqualizerSw() { LOG(DEBUG) << __func__; }
+    ~EqualizerSw() {
+        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;
+    IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+    RetCode releaseContext() override;
+
+  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);
+};
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/hapticGenerator/Android.bp b/audio/aidl/default/hapticGenerator/Android.bp
new file mode 100644
index 0000000..a632130
--- /dev/null
+++ b/audio/aidl/default/hapticGenerator/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: "libhapticgeneratorsw",
+    defaults: [
+        "aidlaudioeffectservice_defaults",
+        "latest_android_media_audio_common_types_ndk_shared",
+        "latest_android_hardware_audio_effect_ndk_shared",
+    ],
+    srcs: [
+        "HapticGeneratorSw.cpp",
+        ":effectCommonFile",
+    ],
+    visibility: [
+        "//hardware/interfaces/audio/aidl/default",
+    ],
+}
diff --git a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp
new file mode 100644
index 0000000..fd5ea34
--- /dev/null
+++ b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.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 <cstddef>
+#define LOG_TAG "AHAL_HapticGeneratorSw"
+#include <Utils.h>
+#include <algorithm>
+#include <unordered_set>
+
+#include <android-base/logging.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include "HapticGeneratorSw.h"
+
+using aidl::android::hardware::audio::effect::HapticGeneratorSw;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kHapticGeneratorSwImplUUID;
+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 != kHapticGeneratorSwImplUUID) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    if (instanceSpp) {
+        *instanceSpp = ndk::SharedRefBase::make<HapticGeneratorSw>();
+        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 destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
+    if (!instanceSp) {
+        return EX_NONE;
+    }
+    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 HapticGeneratorSw::getDescriptor(Descriptor* _aidl_return) {
+    LOG(DEBUG) << __func__ << kDescriptor.toString();
+    *_aidl_return = kDescriptor;
+    return ndk::ScopedAStatus::ok();
+}
+
+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();
+}
+
+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);
+    return ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EffectContext> HapticGeneratorSw::createContext(const Parameter::Common& common) {
+    if (mContext) {
+        LOG(DEBUG) << __func__ << " context already exist";
+        return mContext;
+    }
+    mContext = std::make_shared<HapticGeneratorSwContext>(1 /* statusFmqDepth */, common);
+    return mContext;
+}
+
+RetCode HapticGeneratorSw::releaseContext() {
+    if (mContext) {
+        mContext.reset();
+    }
+    return RetCode::SUCCESS;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status HapticGeneratorSw::effectProcessImpl(float* in, float* out, int process) {
+    // TODO: get data buffer and process.
+    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
+    for (int i = 0; i < process; i++) {
+        *out++ = *in++;
+    }
+    return {STATUS_OK, process, process};
+}
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h
new file mode 100644
index 0000000..518aa87
--- /dev/null
+++ b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h
@@ -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.
+ */
+
+#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 HapticGeneratorSwContext final : public EffectContext {
+  public:
+    HapticGeneratorSwContext(int statusDepth, const Parameter::Common& common)
+        : EffectContext(statusDepth, common) {
+        LOG(DEBUG) << __func__;
+    }
+    // TODO: add specific context here
+};
+
+class HapticGeneratorSw final : public EffectImpl {
+  public:
+    HapticGeneratorSw() { LOG(DEBUG) << __func__; }
+    ~HapticGeneratorSw() {
+        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;
+    IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+    RetCode releaseContext() override;
+
+  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;
+};
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/core-impl/Config.h b/audio/aidl/default/include/core-impl/Config.h
index b62a14b..4555efd 100644
--- a/audio/aidl/default/include/core-impl/Config.h
+++ b/audio/aidl/default/include/core-impl/Config.h
@@ -20,6 +20,8 @@
 
 namespace aidl::android::hardware::audio::core {
 
-class Config : public BnConfig {};
+class Config : public BnConfig {
+    ndk::ScopedAStatus getSurroundSoundConfig(SurroundSoundConfig* _aidl_return) override;
+};
 
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/Module.h b/audio/aidl/default/include/core-impl/Module.h
index 61516b2..0086743 100644
--- a/audio/aidl/default/include/core-impl/Module.h
+++ b/audio/aidl/default/include/core-impl/Module.h
@@ -35,6 +35,7 @@
   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 connectExternalDevice(
             const ::aidl::android::media::audio::common::AudioPort& in_templateIdAndAdditionalData,
             ::aidl::android::media::audio::common::AudioPort* _aidl_return) override;
@@ -70,6 +71,17 @@
             bool* _aidl_return) override;
     ndk::ScopedAStatus resetAudioPatch(int32_t in_patchId) override;
     ndk::ScopedAStatus resetAudioPortConfig(int32_t in_portConfigId) override;
+    ndk::ScopedAStatus getMasterMute(bool* _aidl_return) override;
+    ndk::ScopedAStatus setMasterMute(bool in_mute) override;
+    ndk::ScopedAStatus getMasterVolume(float* _aidl_return) override;
+    ndk::ScopedAStatus setMasterVolume(float in_volume) override;
+    ndk::ScopedAStatus getMicMute(bool* _aidl_return) override;
+    ndk::ScopedAStatus setMicMute(bool in_mute) 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;
 
     void cleanUpPatch(int32_t patchId);
     ndk::ScopedAStatus createStreamContext(
@@ -88,12 +100,18 @@
 
     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.
+    std::shared_ptr<ITelephony> mTelephony;
     // ids of ports created at runtime via 'connectExternalDevice'.
     std::set<int32_t> mConnectedDevicePorts;
     Streams mStreams;
     // Maps port ids and port config ids to patch ids.
     // Multimap because both ports and configs can be used by multiple patches.
     std::multimap<int32_t, int32_t> mPatches;
+    bool mMasterMute = false;
+    float mMasterVolume = 1.0f;
+    bool mMicMute = false;
 };
 
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h
index 488edf1..5ee0f82 100644
--- a/audio/aidl/default/include/core-impl/Stream.h
+++ b/audio/aidl/default/include/core-impl/Stream.h
@@ -54,8 +54,8 @@
             int8_t, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
             DataMQ;
 
-    // Ensure that this value is not used by any of StreamDescriptor.COMMAND_*
-    static constexpr int COMMAND_EXIT = -1;
+    // Ensure that this value is not used by any of StreamDescriptor.State enums
+    static constexpr int32_t STATE_CLOSED = -1;
 
     StreamContext() = default;
     StreamContext(std::unique_ptr<CommandMQ> commandMQ, std::unique_ptr<ReplyMQ> replyMQ,
@@ -99,6 +99,10 @@
 
 class StreamWorkerCommonLogic : public ::android::hardware::audio::common::StreamLogic {
   public:
+    bool isClosed() const {
+        return static_cast<int32_t>(mState.load()) == StreamContext::STATE_CLOSED;
+    }
+    void setClosed() { mState = static_cast<StreamDescriptor::State>(StreamContext::STATE_CLOSED); }
     void setIsConnected(bool connected) { mIsConnected = connected; }
 
   protected:
@@ -109,9 +113,12 @@
           mReplyMQ(context.getReplyMQ()),
           mDataMQ(context.getDataMQ()) {}
     std::string init() override;
+    void populateReply(StreamDescriptor::Reply* reply, bool isConnected) const;
 
-    // Used both by the main and worker threads.
+    // Atomic fields are used both by the main and worker threads.
     std::atomic<bool> mIsConnected = false;
+    static_assert(std::atomic<StreamDescriptor::State>::is_always_lock_free);
+    std::atomic<StreamDescriptor::State> mState = StreamDescriptor::State::STANDBY;
     // All fields are used on the worker thread only.
     const int mInternalCommandCookie;
     const size_t mFrameSize;
@@ -132,6 +139,9 @@
 
   protected:
     Status cycle() override;
+
+  private:
+    bool read(size_t clientSize, StreamDescriptor::Reply* reply);
 };
 using StreamInWorker = ::android::hardware::audio::common::StreamWorker<StreamInWorkerLogic>;
 
@@ -143,6 +153,9 @@
 
   protected:
     Status cycle() override;
+
+  private:
+    bool write(size_t clientSize, StreamDescriptor::Reply* reply);
 };
 using StreamOutWorker = ::android::hardware::audio::common::StreamWorker<StreamOutWorkerLogic>;
 
@@ -155,7 +168,7 @@
                        ? ndk::ScopedAStatus::ok()
                        : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
     }
-    bool isClosed() const { return mIsClosed; }
+    bool isClosed() const { return mWorker.isClosed(); }
     void setIsConnected(bool connected) { mWorker.setIsConnected(connected); }
     ndk::ScopedAStatus updateMetadata(const Metadata& metadata);
 
@@ -168,9 +181,6 @@
     Metadata mMetadata;
     StreamContext mContext;
     StreamWorker mWorker;
-    // This variable is checked in the destructor which can be called on an arbitrary Binder thread,
-    // thus we need to ensure that any changes made by other threads are sequentially consistent.
-    std::atomic<bool> mIsClosed = false;
 };
 
 class StreamIn
diff --git a/audio/aidl/default/include/core-impl/Telephony.h b/audio/aidl/default/include/core-impl/Telephony.h
new file mode 100644
index 0000000..597f3d6
--- /dev/null
+++ b/audio/aidl/default/include/core-impl/Telephony.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/binder_enums.h>
+
+#include <aidl/android/hardware/audio/core/BnTelephony.h>
+
+namespace aidl::android::hardware::audio::core {
+
+class Telephony : public BnTelephony {
+  private:
+    ndk::ScopedAStatus getSupportedAudioModes(std::vector<AudioMode>* _aidl_return) override;
+    ndk::ScopedAStatus switchAudioMode(AudioMode in_mode) override;
+
+    const std::vector<AudioMode> mSupportedAudioModes = {::ndk::enum_range<AudioMode>().begin(),
+                                                         ::ndk::enum_range<AudioMode>().end()};
+};
+
+}  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/effect-impl/EffectContext.h b/audio/aidl/default/include/effect-impl/EffectContext.h
new file mode 100644
index 0000000..f608e12
--- /dev/null
+++ b/audio/aidl/default/include/effect-impl/EffectContext.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <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 <fmq/AidlMessageQueue.h>
+#include "EffectTypes.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+class EffectContext {
+  public:
+    typedef ::android::AidlMessageQueue<
+            IEffect::Status, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
+            StatusMQ;
+    typedef ::android::AidlMessageQueue<
+            float, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
+            DataMQ;
+
+    EffectContext(size_t statusDepth, const Parameter::Common& common) {
+        mSessionId = common.session;
+        auto& input = common.input;
+        auto& output = common.output;
+
+        LOG_ALWAYS_FATAL_IF(
+                input.base.format.pcm != aidl::android::media::audio::common::PcmType::FLOAT_32_BIT,
+                "inputFormatNotFloat");
+        LOG_ALWAYS_FATAL_IF(output.base.format.pcm !=
+                                    aidl::android::media::audio::common::PcmType::FLOAT_32_BIT,
+                            "outputFormatNotFloat");
+        mInputFrameSize = ::android::hardware::audio::common::getFrameSizeInBytes(
+                input.base.format, input.base.channelMask);
+        mOutputFrameSize = ::android::hardware::audio::common::getFrameSizeInBytes(
+                output.base.format, output.base.channelMask);
+        // in/outBuffer size in float (FMQ data format defined for DataMQ)
+        size_t inBufferSizeInFloat = input.frameCount * mInputFrameSize / sizeof(float);
+        size_t outBufferSizeInFloat = output.frameCount * mOutputFrameSize / sizeof(float);
+
+        mStatusMQ = std::make_shared<StatusMQ>(statusDepth, true /*configureEventFlagWord*/);
+        mInputMQ = std::make_shared<DataMQ>(inBufferSizeInFloat);
+        mOutputMQ = std::make_shared<DataMQ>(outBufferSizeInFloat);
+
+        if (!mStatusMQ->isValid() || !mInputMQ->isValid() || !mOutputMQ->isValid()) {
+            LOG(ERROR) << __func__ << " created invalid FMQ";
+        }
+        mWorkBuffer.reserve(std::max(inBufferSizeInFloat, outBufferSizeInFloat));
+    }
+    virtual ~EffectContext() {}
+
+    std::shared_ptr<StatusMQ> getStatusFmq() { return mStatusMQ; }
+    std::shared_ptr<DataMQ> getInputDataFmq() { return mInputMQ; }
+    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
+    void resetBuffer() {
+        auto buffer = getWorkBuffer();
+        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();
+        }
+    }
+    size_t getInputFrameSize() { return mInputFrameSize; }
+    size_t getOutputFrameSize() { return mOutputFrameSize; }
+    int getSessionId() { return mSessionId; }
+
+    virtual RetCode setOutputDevice(
+            const aidl::android::media::audio::common::AudioDeviceDescription& device) {
+        mOutputDevice = device;
+        return RetCode::SUCCESS;
+    }
+    virtual aidl::android::media::audio::common::AudioDeviceDescription getOutputDevice() {
+        return mOutputDevice;
+    }
+
+    virtual RetCode setAudioMode(const aidl::android::media::audio::common::AudioMode& mode) {
+        mMode = mode;
+        return RetCode::SUCCESS;
+    }
+    virtual aidl::android::media::audio::common::AudioMode getAudioMode() { return mMode; }
+
+    virtual RetCode setAudioSource(const aidl::android::media::audio::common::AudioSource& source) {
+        mSource = source;
+        return RetCode::SUCCESS;
+    }
+    virtual aidl::android::media::audio::common::AudioSource getAudioSource() { return mSource; }
+
+    virtual RetCode setVolumeStereo(const Parameter::VolumeStereo& volumeStereo) {
+        mVolumeStereo = volumeStereo;
+        return RetCode::SUCCESS;
+    }
+    virtual Parameter::VolumeStereo getVolumeStereo() { return mVolumeStereo; }
+
+    virtual RetCode setCommon(const Parameter::Common& common) {
+        mCommon = common;
+        LOG(ERROR) << __func__ << mCommon.toString();
+        return RetCode::SUCCESS;
+    }
+    virtual Parameter::Common getCommon() {
+        LOG(ERROR) << __func__ << mCommon.toString();
+        return mCommon;
+    }
+
+  protected:
+    // common parameters
+    int mSessionId = INVALID_AUDIO_SESSION_ID;
+    size_t mInputFrameSize, mOutputFrameSize;
+    Parameter::Common mCommon;
+    aidl::android::media::audio::common::AudioDeviceDescription mOutputDevice;
+    aidl::android::media::audio::common::AudioMode mMode;
+    aidl::android::media::audio::common::AudioSource mSource;
+    Parameter::VolumeStereo mVolumeStereo;
+
+  private:
+    // fmq and buffers
+    std::shared_ptr<StatusMQ> mStatusMQ;
+    std::shared_ptr<DataMQ> mInputMQ;
+    std::shared_ptr<DataMQ> mOutputMQ;
+    // TODO handle effect process input and output
+    // work buffer set by effect instances, the access and update are in same thread
+    std::vector<float> mWorkBuffer;
+};
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/effect-impl/EffectImpl.h b/audio/aidl/default/include/effect-impl/EffectImpl.h
new file mode 100644
index 0000000..d9825da
--- /dev/null
+++ b/audio/aidl/default/include/effect-impl/EffectImpl.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <mutex>
+
+#include "EffectTypes.h"
+#include "effect-impl/EffectContext.h"
+#include "effect-impl/EffectTypes.h"
+#include "effect-impl/EffectWorker.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+class EffectImpl : public BnEffect, public EffectWorker {
+  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);
+
+    /* Methods MUST be implemented by each effect instances */
+    virtual ndk::ScopedAStatus getDescriptor(Descriptor* desc) = 0;
+    virtual ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) = 0;
+    virtual ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
+                                                    Parameter::Specific* specific) = 0;
+    virtual std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) = 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;
+
+    IEffect::Status status(binder_status_t status, size_t consumed, size_t produced);
+    void cleanUp();
+
+  private:
+    std::shared_ptr<EffectContext> mContext GUARDED_BY(mMutex);
+};
+}  // 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
new file mode 100644
index 0000000..09a0000
--- /dev/null
+++ b/audio/aidl/default/include/effect-impl/EffectThread.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.
+ */
+
+#pragma once
+#include <atomic>
+#include <string>
+#include <thread>
+
+#include <android-base/thread_annotations.h>
+#include <system/thread_defs.h>
+
+#include "effect-impl/EffectTypes.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+class EffectThread {
+  public:
+    // default priority is same as HIDL: ANDROID_PRIORITY_URGENT_AUDIO
+    EffectThread();
+    virtual ~EffectThread();
+
+    // called by effect implementation.
+    RetCode createThread(const std::string& name,
+                         const int priority = ANDROID_PRIORITY_URGENT_AUDIO);
+    RetCode destroyThread();
+    RetCode startThread();
+    RetCode stopThread();
+
+    // 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;
+
+  private:
+    std::mutex mMutex;
+    std::condition_variable mCv;
+    bool mExit GUARDED_BY(mMutex) = false;
+    bool mStop GUARDED_BY(mMutex) = true;
+    std::thread mThread;
+    int mPriority;
+    std::string mName;
+};
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/effect-impl/EffectTypes.h b/audio/aidl/default/include/effect-impl/EffectTypes.h
new file mode 100644
index 0000000..fc6a01d
--- /dev/null
+++ b/audio/aidl/default/include/effect-impl/EffectTypes.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 <ostream>
+#include <string>
+
+#include <aidl/android/hardware/audio/effect/BnEffect.h>
+#include <android-base/logging.h>
+
+typedef binder_exception_t (*EffectCreateFunctor)(
+        const ::aidl::android::media::audio::common::AudioUuid*,
+        std::shared_ptr<aidl::android::hardware::audio::effect::IEffect>*);
+typedef binder_exception_t (*EffectDestroyFunctor)(
+        const std::shared_ptr<aidl::android::hardware::audio::effect::IEffect>&);
+
+struct effect_dl_interface_s {
+    EffectCreateFunctor createEffectFunc;
+    EffectDestroyFunctor destroyEffectFunc;
+};
+
+namespace aidl::android::hardware::audio::effect {
+
+enum class RetCode {
+    SUCCESS,
+    ERROR_ILLEGAL_PARAMETER, /* Illegal parameter */
+    ERROR_THREAD,            /* Effect thread error */
+    ERROR_NULL_POINTER,      /* NULL pointer */
+    ERROR_ALIGNMENT_ERROR,   /* Memory alignment error */
+    ERROR_BLOCK_SIZE_EXCEED, /* Maximum block size exceeded */
+    ERROR_EFFECT_LIB_ERROR
+};
+
+static const int INVALID_AUDIO_SESSION_ID = -1;
+
+inline std::ostream& operator<<(std::ostream& out, const RetCode& code) {
+    switch (code) {
+        case RetCode::SUCCESS:
+            return out << "SUCCESS";
+        case RetCode::ERROR_ILLEGAL_PARAMETER:
+            return out << "ERROR_ILLEGAL_PARAMETER";
+        case RetCode::ERROR_THREAD:
+            return out << "ERROR_THREAD";
+        case RetCode::ERROR_NULL_POINTER:
+            return out << "ERROR_NULL_POINTER";
+        case RetCode::ERROR_ALIGNMENT_ERROR:
+            return out << "ERROR_ALIGNMENT_ERROR";
+        case RetCode::ERROR_BLOCK_SIZE_EXCEED:
+            return out << "ERROR_BLOCK_SIZE_EXCEED";
+        case RetCode::ERROR_EFFECT_LIB_ERROR:
+            return out << "ERROR_EFFECT_LIB_ERROR";
+    }
+
+    return out << "EnumError: " << code;
+}
+
+#define RETURN_IF_ASTATUS_NOT_OK(status, message)                                              \
+    do {                                                                                       \
+        const ::ndk::ScopedAStatus curr_status = (status);                                     \
+        if (!curr_status.isOk()) {                                                             \
+            LOG(ERROR) << __func__ << ":" << __LINE__                                          \
+                       << "return with status: " << curr_status.getDescription() << (message); \
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(                           \
+                    curr_status.getExceptionCode(), (message));                                \
+        }                                                                                      \
+    } while (0)
+
+#define RETURN_IF(expr, exception, message)                                                  \
+    do {                                                                                     \
+        if (expr) {                                                                          \
+            LOG(ERROR) << __func__ << ":" << __LINE__ << " return with expr " << #expr;      \
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage((exception), (message)); \
+        }                                                                                    \
+    } while (0)
+
+#define RETURN_OK_IF(expr)                                                             \
+    do {                                                                               \
+        if (expr) {                                                                    \
+            LOG(INFO) << __func__ << ":" << __LINE__ << " return with expr " << #expr; \
+            return ndk::ScopedAStatus::ok();                                           \
+        }                                                                              \
+    } while (0)
+
+#define RETURN_VALUE_IF(expr, ret, log)                                                          \
+    do {                                                                                         \
+        if (expr) {                                                                              \
+            LOG(ERROR) << __func__ << ":" << __LINE__ << " return with expr " << #expr << (log); \
+            return ret;                                                                          \
+        }                                                                                        \
+    } while (0)
+
+static inline bool stringToUuid(const char* str,
+                                ::aidl::android::media::audio::common::AudioUuid* uuid) {
+    RETURN_VALUE_IF(!uuid || !str, false, "nullPtr");
+
+    uint32_t tmp[10];
+    if (sscanf(str, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x", tmp, tmp + 1, tmp + 2, tmp + 3,
+               tmp + 4, tmp + 5, tmp + 6, tmp + 7, tmp + 8, tmp + 9) < 10) {
+        return false;
+    }
+
+    uuid->timeLow = (uint32_t)tmp[0];
+    uuid->timeMid = (uint16_t)tmp[1];
+    uuid->timeHiAndVersion = (uint16_t)tmp[2];
+    uuid->clockSeq = (uint16_t)tmp[3];
+    uuid->node.insert(uuid->node.end(), {(uint8_t)tmp[4], (uint8_t)tmp[5], (uint8_t)tmp[6],
+                                         (uint8_t)tmp[7], (uint8_t)tmp[8], (uint8_t)tmp[9]});
+    return true;
+}
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/effect-impl/EffectUUID.h b/audio/aidl/default/include/effect-impl/EffectUUID.h
new file mode 100644
index 0000000..7709eab
--- /dev/null
+++ b/audio/aidl/default/include/effect-impl/EffectUUID.h
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <aidl/android/media/audio/common/AudioUuid.h>
+
+namespace aidl::android::hardware::audio::effect {
+
+using ::aidl::android::media::audio::common::AudioUuid;
+
+// ec7178ec-e5e1-4432-a3f4-4657e6795210
+static const AudioUuid kEffectNullUuid = {static_cast<int32_t>(0xec7178ec),
+                                          0xe5e1,
+                                          0x4432,
+                                          0xa3f4,
+                                          {0x46, 0x57, 0xe6, 0x79, 0x52, 0x10}};
+// Zero UUID
+static const AudioUuid kEffectZeroUuid = {
+        static_cast<int32_t>(0x0), 0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
+
+// 0634f220-ddd4-11db-a0fc-0002a5d5c51b
+static const AudioUuid kBassBoostTypeUUID = {static_cast<int32_t>(0x0634f220),
+                                             0xddd4,
+                                             0x11db,
+                                             0xa0fc,
+                                             {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+// fa8181f2-588b-11ed-9b6a-0242ac120002
+static const AudioUuid kBassBoostSwImplUUID = {static_cast<int32_t>(0xfa8181f2),
+                                               0x588b,
+                                               0x11ed,
+                                               0x9b6a,
+                                               {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// fa81862a-588b-11ed-9b6a-0242ac120002
+static const AudioUuid kDownmixTypeUUID = {static_cast<int32_t>(0xfa81862a),
+                                           0x588b,
+                                           0x11ed,
+                                           0x9b6a,
+                                           {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// fa8187ba-588b-11ed-9b6a-0242ac120002
+static const AudioUuid kDownmixSwImplUUID = {static_cast<int32_t>(0xfa8187ba),
+                                             0x588b,
+                                             0x11ed,
+                                             0x9b6a,
+                                             {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// 0bed4300-ddd6-11db-8f34-0002a5d5c51b.
+static const AudioUuid kEqualizerTypeUUID = {static_cast<int32_t>(0x0bed4300),
+                                             0xddd6,
+                                             0x11db,
+                                             0x8f34,
+                                             {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+// 0bed4300-847d-11df-bb17-0002a5d5c51b
+static const AudioUuid kEqualizerSwImplUUID = {static_cast<int32_t>(0x0bed4300),
+                                               0x847d,
+                                               0x11df,
+                                               0xbb17,
+                                               {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+// ce772f20-847d-11df-bb17-0002a5d5c51b
+static const AudioUuid kEqualizerBundleImplUUID = {static_cast<int32_t>(0xce772f20),
+                                                   0x847d,
+                                                   0x11df,
+                                                   0xbb17,
+                                                   {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+// c8e70ecd-48ca-456e-8a4f-0002a5d5c51b
+static const AudioUuid kEqualizerProxyUUID = {static_cast<int32_t>(0xc8e70ecd),
+                                              0x48ca,
+                                              0x456e,
+                                              0x8a4f,
+                                              {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+// 7261676f-6d75-7369-6364-28e2fd3ac39e
+static const AudioUuid kDynamicsProcessingTypeUUID = {static_cast<int32_t>(0x7261676f),
+                                                      0x6d75,
+                                                      0x7369,
+                                                      0x6364,
+                                                      {0x28, 0xe2, 0xfd, 0x3a, 0xc3, 0x9e}};
+// fa818d78-588b-11ed-9b6a-0242ac120002
+static const AudioUuid kDynamicsProcessingSwImplUUID = {static_cast<int32_t>(0xfa818d78),
+                                                        0x588b,
+                                                        0x11ed,
+                                                        0x9b6a,
+                                                        {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// 1411e6d6-aecd-4021-a1cf-a6aceb0d71e5
+static const AudioUuid kHapticGeneratorTypeUUID = {static_cast<int32_t>(0x1411e6d6),
+                                                   0xaecd,
+                                                   0x4021,
+                                                   0xa1cf,
+                                                   {0xa6, 0xac, 0xeb, 0x0d, 0x71, 0xe5}};
+// fa819110-588b-11ed-9b6a-0242ac120002
+static const AudioUuid kHapticGeneratorSwImplUUID = {static_cast<int32_t>(0xfa819110),
+                                                     0x588b,
+                                                     0x11ed,
+                                                     0x9b6a,
+                                                     {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// fe3199be-aed0-413f-87bb-11260eb63cf1
+static const AudioUuid kLoudnessEnhancerTypeUUID = {static_cast<int32_t>(0xfe3199be),
+                                                    0xaed0,
+                                                    0x413f,
+                                                    0x87bb,
+                                                    {0x11, 0x26, 0x0e, 0xb6, 0x3c, 0xf1}};
+// fa819610-588b-11ed-9b6a-0242ac120002
+static const AudioUuid kLoudnessEnhancerSwImplUUID = {static_cast<int32_t>(0xfa819610),
+                                                      0x588b,
+                                                      0x11ed,
+                                                      0x9b6a,
+                                                      {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// c2e5d5f0-94bd-4763-9cac-4e234d06839e
+static const AudioUuid kEnvReverbTypeUUID = {static_cast<int32_t>(0xc2e5d5f0),
+                                             0x94bd,
+                                             0x4763,
+                                             0x9cac,
+                                             {0x4e, 0x23, 0x4d, 0x06, 0x83, 0x9e}};
+// fa819886-588b-11ed-9b6a-0242ac120002
+static const AudioUuid kEnvReverbSwImplUUID = {static_cast<int32_t>(0xfa819886),
+                                               0x588b,
+                                               0x11ed,
+                                               0x9b6a,
+                                               {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// 47382d60-ddd8-11db-bf3a-0002a5d5c51b
+static const AudioUuid kPresetReverbTypeUUID = {static_cast<int32_t>(0x47382d60),
+                                                0xddd8,
+                                                0x11db,
+                                                0xbf3a,
+                                                {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+// fa8199c6-588b-11ed-9b6a-0242ac120002
+static const AudioUuid kPresetReverbSwImplUUID = {static_cast<int32_t>(0xfa8199c6),
+                                                  0x588b,
+                                                  0x11ed,
+                                                  0x9b6a,
+                                                  {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// 37cc2c00-dddd-11db-8577-0002a5d5c51b
+static const AudioUuid kVirtualizerTypeUUID = {static_cast<int32_t>(0x37cc2c00),
+                                               0xdddd,
+                                               0x11db,
+                                               0x8577,
+                                               {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+// fa819d86-588b-11ed-9b6a-0242ac120002
+static const AudioUuid kVirtualizerSwImplUUID = {static_cast<int32_t>(0xfa819d86),
+                                                 0x588b,
+                                                 0x11ed,
+                                                 0x9b6a,
+                                                 {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// fa819f3e-588b-11ed-9b6a-0242ac120002
+static const AudioUuid kVisualizerTypeUUID = {static_cast<int32_t>(0xfa819f3e),
+                                              0x588b,
+                                              0x11ed,
+                                              0x9b6a,
+                                              {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// fa81a0f6-588b-11ed-9b6a-0242ac120002
+static const AudioUuid kVisualizerSwImplUUID = {static_cast<int32_t>(0xfa81a0f6),
+                                                0x588b,
+                                                0x11ed,
+                                                0x9b6a,
+                                                {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// fa81a2b8-588b-11ed-9b6a-0242ac120002
+static const AudioUuid kVolumeTypeUUID = {static_cast<int32_t>(0xfa81a2b8),
+                                          0x588b,
+                                          0x11ed,
+                                          0x9b6a,
+                                          {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// fa81a718-588b-11ed-9b6a-0242ac120002
+static const AudioUuid kVolumeSwImplUUID = {static_cast<int32_t>(0xfa81a718),
+                                            0x588b,
+                                            0x11ed,
+                                            0x9b6a,
+                                            {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+
+/**
+ * @brief A map between effect name and effect type UUID.
+ * All <name> attribution in effect/effectProxy of audio_effects.xml should be listed in this map.
+ * 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 = {
+        {"bassboost", kBassBoostTypeUUID},
+        {"downmix", kDownmixTypeUUID},
+        {"dynamics_processing", kDynamicsProcessingTypeUUID},
+        {"equalizer", kEqualizerTypeUUID},
+        {"haptic_generator", kHapticGeneratorTypeUUID},
+        {"loudness_enhancer", kLoudnessEnhancerTypeUUID},
+        {"env_reverb", kEnvReverbTypeUUID},
+        {"preset_reverb", kPresetReverbTypeUUID},
+        {"reverb_env_aux", kEnvReverbTypeUUID},
+        {"reverb_env_ins", kEnvReverbTypeUUID},
+        {"reverb_pre_aux", kPresetReverbTypeUUID},
+        {"reverb_pre_ins", kPresetReverbTypeUUID},
+        {"virtualizer", kVirtualizerTypeUUID},
+        {"visualizer", kVisualizerTypeUUID},
+        {"volume", kVolumeTypeUUID},
+};
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/effect-impl/EffectWorker.h b/audio/aidl/default/include/effect-impl/EffectWorker.h
new file mode 100644
index 0000000..6a78eab
--- /dev/null
+++ b/audio/aidl/default/include/effect-impl/EffectWorker.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.
+ */
+
+#pragma once
+#include <algorithm>
+#include <memory>
+#include <mutex>
+#include <string>
+
+#include "EffectContext.h"
+#include "EffectThread.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+std::string toString(RetCode& code);
+
+class EffectWorker : public EffectThread {
+  public:
+    // set effect context for worker, suppose to only happen once here
+    void setContext(std::shared_ptr<EffectContext> context) {
+        std::call_once(mOnceFlag, [&]() { mContext = context; });
+    };
+
+    // handle FMQ and call effect implemented virtual function
+    void process() override {
+        RETURN_VALUE_IF(!mContext, void(), "nullContext");
+        std::shared_ptr<EffectContext::StatusMQ> statusMQ = mContext->getStatusFmq();
+        std::shared_ptr<EffectContext::DataMQ> inputMQ = mContext->getInputDataFmq();
+        std::shared_ptr<EffectContext::DataMQ> outputMQ = mContext->getOutputDataFmq();
+
+        // 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;
+
+            auto buffer = mContext->getWorkBuffer();
+            inputMQ->read(buffer, processSamples);
+
+            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
+        }
+    }
+
+    // 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;
+
+  private:
+    // make sure the context only set once.
+    std::once_flag mOnceFlag;
+    std::shared_ptr<EffectContext> mContext;
+};
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/effectFactory-impl/EffectConfig.h b/audio/aidl/default/include/effectFactory-impl/EffectConfig.h
new file mode 100644
index 0000000..2b904f5
--- /dev/null
+++ b/audio/aidl/default/include/effectFactory-impl/EffectConfig.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <functional>
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include <cutils/properties.h>
+#include <tinyxml2.h>
+
+#include "effect-impl/EffectTypes.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+/**
+ *  Library contains a mapping from library name to path.
+ *  Effect contains a mapping from effect name to Libraries and implementation UUID.
+ *  Pre/post processor contains a mapping from processing name to effect names.
+ */
+class EffectConfig {
+  public:
+    explicit EffectConfig(const std::string& file);
+
+    // <library>
+    struct Library {
+        std::string name;
+        std::string path;
+    };
+    struct LibraryUuid {
+        std::string name;  // library name
+        ::aidl::android::media::audio::common::AudioUuid uuid;
+    };
+    // <effects>
+    struct EffectLibraries {
+        std::optional<struct LibraryUuid> proxyLibrary;
+        std::vector<struct LibraryUuid> libraries;
+    };
+
+    int getSkippedElements() const { return mSkippedElements; }
+    const std::unordered_map<std::string, std::string> getLibraryMap() const { return mLibraryMap; }
+    const std::unordered_map<std::string, struct EffectLibraries> getEffectsMap() const {
+        return mEffectsMap;
+    }
+    const std::unordered_map<std::string, std::vector<std::string>> getProcessingMap() const {
+        return mProcessingMap;
+    }
+
+  private:
+    int mSkippedElements;
+    /* Parsed Libraries result */
+    std::unordered_map<std::string, std::string> mLibraryMap;
+    /* Parsed Effects result */
+    std::unordered_map<std::string, struct EffectLibraries> mEffectsMap;
+    /* Parsed pre/post processing result */
+    std::unordered_map<std::string, std::vector<std::string>> mProcessingMap;
+
+    /** @return all `node`s children that are elements and match the tag if provided. */
+    std::vector<std::reference_wrapper<const tinyxml2::XMLElement>> getChildren(
+            const tinyxml2::XMLNode& node, const char* childTag = nullptr);
+
+    /** Parse a library xml note and push the result in mLibraryMap or return false on failure. */
+    bool parseLibrary(const tinyxml2::XMLElement& xml);
+
+    /** Parse an effect from an xml element describing it.
+     * @return true and pushes the effect in mEffectsMap on success, false on failure.
+     */
+    bool parseEffect(const tinyxml2::XMLElement& xml);
+
+    bool parseStream(const tinyxml2::XMLElement& xml);
+
+    // Function to parse effect.library name and effect.uuid from xml
+    bool parseLibraryUuid(const tinyxml2::XMLElement& xml, struct LibraryUuid& libraryUuid,
+                          bool isProxy = false);
+
+    const char* dump(const tinyxml2::XMLElement& element,
+                     tinyxml2::XMLPrinter&& printer = {}) const;
+};
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/effectFactory-impl/EffectFactory.h b/audio/aidl/default/include/effectFactory-impl/EffectFactory.h
index 8da5525..7edace0 100644
--- a/audio/aidl/default/include/effectFactory-impl/EffectFactory.h
+++ b/audio/aidl/default/include/effectFactory-impl/EffectFactory.h
@@ -16,31 +16,47 @@
 
 #pragma once
 
+#include <any>
+#include <map>
 #include <optional>
+#include <set>
 #include <vector>
 
 #include <aidl/android/hardware/audio/effect/BnFactory.h>
+#include "EffectConfig.h"
 
 namespace aidl::android::hardware::audio::effect {
 
 class Factory : public BnFactory {
   public:
-    Factory();
+    explicit Factory(const std::string& file);
     /**
      * @brief Get identity of all effects supported by the device, with the optional filter by type
      * and/or by instance UUID.
      *
      * @param in_type Type UUID.
      * @param in_instance Instance UUID.
+     * @param in_proxy Proxy UUID.
      * @param out_descriptor List of identities .
      * @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;
 
     /**
+     * @brief Query list of defined processing, with the optional filter by AudioStreamType
+     *
+     * @param in_type Type of processing, could be AudioStreamType or AudioSource. Optional.
+     * @param _aidl_return List of processing filtered by in_type.
+     * @return ndk::ScopedAStatus
+     */
+    ndk::ScopedAStatus queryProcessing(const std::optional<Processing::Type>& in_type,
+                                       std::vector<Processing>* _aidl_return) override;
+
+    /**
      * @brief Create an effect instance for a certain implementation (identified by UUID).
      *
      * @param in_impl_uuid Effect implementation UUID.
@@ -63,7 +79,28 @@
             override;
 
   private:
-    // List of effect descriptors supported by the devices.
-    std::vector<Descriptor::Identity> mIdentityList;
+    const EffectConfig mConfig;
+    ~Factory();
+    // Set of effect descriptors supported by the devices.
+    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;
+
+    ndk::ScopedAStatus destroyEffectImpl(const std::shared_ptr<IEffect>& in_handle);
+    void cleanupEffectMap();
+    void openEffectLibrary(const ::aidl::android::media::audio::common::AudioUuid& impl,
+                           const std::string& libName);
+    void createIdentityWithConfig(
+            const EffectConfig::LibraryUuid& configLib,
+            const ::aidl::android::media::audio::common::AudioUuid& typeUuid,
+            const std::optional<::aidl::android::media::audio::common::AudioUuid> proxyUuid);
+    void loadEffectLibs();
 };
+
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/equalizer-impl/Equalizer.h b/audio/aidl/default/include/equalizer-impl/Equalizer.h
deleted file mode 100644
index ea16cb9..0000000
--- a/audio/aidl/default/include/equalizer-impl/Equalizer.h
+++ /dev/null
@@ -1,51 +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.
- */
-
-#pragma once
-
-#include <aidl/android/hardware/audio/effect/BnEffect.h>
-#include <cstdlib>
-
-namespace aidl::android::hardware::audio::effect {
-
-// Equalizer type UUID.
-static const ::aidl::android::media::audio::common::AudioUuid EqualizerTypeUUID = {
-        static_cast<int32_t>(0x0bed4300),
-        0xddd6,
-        0x11db,
-        0x8f34,
-        {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
-
-// Equalizer implementation UUID.
-static const ::aidl::android::media::audio::common::AudioUuid EqualizerSwImplUUID = {
-        static_cast<int32_t>(0x0bed4300),
-        0x847d,
-        0x11df,
-        0xbb17,
-        {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
-
-class Equalizer : public BnEffect {
-  public:
-    Equalizer() = default;
-    ndk::ScopedAStatus open() override;
-    ndk::ScopedAStatus close() override;
-    ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
-
-  private:
-    // Effect descriptor.
-    Descriptor mDesc = {.common = {.id = {.type = EqualizerTypeUUID, .uuid = EqualizerSwImplUUID}}};
-};
-}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/visualizer-impl/Visualizer.h b/audio/aidl/default/include/visualizer-impl/Visualizer.h
deleted file mode 100644
index 4b82dd0..0000000
--- a/audio/aidl/default/include/visualizer-impl/Visualizer.h
+++ /dev/null
@@ -1,31 +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.
- */
-
-#pragma once
-
-#include <cstdlib>
-
-namespace aidl::android::hardware::audio::effect {
-
-// Visualizer implementation UUID.
-static const ::aidl::android::media::audio::common::AudioUuid VisualizerUUID = {
-        static_cast<int32_t>(0x1d4033c0),
-        0x8557,
-        0x11df,
-        0x9f2d,
-        {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
-
-}  // namespace aidl::android::hardware::audio::effect
\ No newline at end of file
diff --git a/audio/aidl/default/loudnessEnhancer/Android.bp b/audio/aidl/default/loudnessEnhancer/Android.bp
new file mode 100644
index 0000000..3a0ac73
--- /dev/null
+++ b/audio/aidl/default/loudnessEnhancer/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: "libloudnessenhancersw",
+    defaults: [
+        "aidlaudioeffectservice_defaults",
+        "latest_android_media_audio_common_types_ndk_shared",
+        "latest_android_hardware_audio_effect_ndk_shared",
+    ],
+    srcs: [
+        "LoudnessEnhancerSw.cpp",
+        ":effectCommonFile",
+    ],
+    visibility: [
+        "//hardware/interfaces/audio/aidl/default",
+    ],
+}
diff --git a/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.cpp b/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.cpp
new file mode 100644
index 0000000..9d2b978
--- /dev/null
+++ b/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.cpp
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_LoudnessEnhancerSw"
+#include <Utils.h>
+#include <algorithm>
+#include <unordered_set>
+
+#include <android-base/logging.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include "LoudnessEnhancerSw.h"
+
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kLoudnessEnhancerSwImplUUID;
+using aidl::android::hardware::audio::effect::LoudnessEnhancerSw;
+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 != kLoudnessEnhancerSwImplUUID) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    if (instanceSpp) {
+        *instanceSpp = ndk::SharedRefBase::make<LoudnessEnhancerSw>();
+        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 destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
+    if (!instanceSp) {
+        return EX_NONE;
+    }
+    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 LoudnessEnhancerSw::getDescriptor(Descriptor* _aidl_return) {
+    LOG(DEBUG) << __func__ << kDescriptor.toString();
+    *_aidl_return = kDescriptor;
+    return ndk::ScopedAStatus::ok();
+}
+
+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>();
+    auto tag = leParam.getTag();
+
+    switch (tag) {
+        case LoudnessEnhancer::gainMb: {
+            RETURN_IF(mContext->setLeGainMb(leParam.get<LoudnessEnhancer::gainMb>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setGainMbFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "LoudnessEnhancerTagNotSupported");
+        }
+    }
+}
+
+ndk::ScopedAStatus LoudnessEnhancerSw::getParameterSpecific(const Parameter::Id& id,
+                                                            Parameter::Specific* specific) {
+    auto tag = id.getTag();
+    RETURN_IF(Parameter::Id::loudnessEnhancerTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
+    auto leId = id.get<Parameter::Id::loudnessEnhancerTag>();
+    auto leIdTag = leId.getTag();
+    switch (leIdTag) {
+        case LoudnessEnhancer::Id::commonTag:
+            return getParameterLoudnessEnhancer(leId.get<LoudnessEnhancer::Id::commonTag>(),
+                                                specific);
+        default:
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(leIdTag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "LoudnessEnhancerTagNotSupported");
+    }
+}
+
+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;
+    switch (tag) {
+        case LoudnessEnhancer::gainMb: {
+            leParam.set<LoudnessEnhancer::gainMb>(mContext->getLeGainMb());
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "LoudnessEnhancerTagNotSupported");
+        }
+    }
+
+    specific->set<Parameter::Specific::loudnessEnhancer>(leParam);
+    return ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EffectContext> LoudnessEnhancerSw::createContext(const Parameter::Common& common) {
+    if (mContext) {
+        LOG(DEBUG) << __func__ << " context already exist";
+        return mContext;
+    }
+    mContext = std::make_shared<LoudnessEnhancerSwContext>(1 /* statusFmqDepth */, common);
+    return mContext;
+}
+
+RetCode LoudnessEnhancerSw::releaseContext() {
+    if (mContext) {
+        mContext.reset();
+    }
+    return RetCode::SUCCESS;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status LoudnessEnhancerSw::effectProcessImpl(float* in, float* out, int process) {
+    // TODO: get data buffer and process.
+    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
+    for (int i = 0; i < process; i++) {
+        *out++ = *in++;
+    }
+    return {STATUS_OK, process, process};
+}
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.h b/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.h
new file mode 100644
index 0000000..856bf0b
--- /dev/null
+++ b/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.h
@@ -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.
+ */
+
+#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 LoudnessEnhancerSwContext final : public EffectContext {
+  public:
+    LoudnessEnhancerSwContext(int statusDepth, const Parameter::Common& common)
+        : EffectContext(statusDepth, common) {
+        LOG(DEBUG) << __func__;
+    }
+
+    RetCode setLeGainMb(int gainMb) {
+        // TODO : Add implementation to apply new gain
+        mGainMb = gainMb;
+        return RetCode::SUCCESS;
+    }
+    int getLeGainMb() const { return mGainMb; }
+
+  private:
+    int mGainMb = 0;  // Default Gain
+};
+
+class LoudnessEnhancerSw final : public EffectImpl {
+  public:
+    LoudnessEnhancerSw() { LOG(DEBUG) << __func__; }
+    ~LoudnessEnhancerSw() {
+        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;
+    IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+    RetCode releaseContext() override;
+
+  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);
+};
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/presetReverb/Android.bp b/audio/aidl/default/presetReverb/Android.bp
new file mode 100644
index 0000000..4148511
--- /dev/null
+++ b/audio/aidl/default/presetReverb/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: "libpresetreverbsw",
+    defaults: [
+        "aidlaudioeffectservice_defaults",
+        "latest_android_media_audio_common_types_ndk_shared",
+        "latest_android_hardware_audio_effect_ndk_shared",
+    ],
+    srcs: [
+        "PresetReverbSw.cpp",
+        ":effectCommonFile",
+    ],
+    visibility: [
+        "//hardware/interfaces/audio/aidl/default",
+    ],
+}
diff --git a/audio/aidl/default/presetReverb/PresetReverbSw.cpp b/audio/aidl/default/presetReverb/PresetReverbSw.cpp
new file mode 100644
index 0000000..069d0ff
--- /dev/null
+++ b/audio/aidl/default/presetReverb/PresetReverbSw.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 <cstddef>
+#define LOG_TAG "AHAL_PresetReverbSw"
+#include <Utils.h>
+#include <algorithm>
+#include <unordered_set>
+
+#include <android-base/logging.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include "PresetReverbSw.h"
+
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kPresetReverbSwImplUUID;
+using aidl::android::hardware::audio::effect::PresetReverbSw;
+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 != kPresetReverbSwImplUUID) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    if (instanceSpp) {
+        *instanceSpp = ndk::SharedRefBase::make<PresetReverbSw>();
+        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 destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
+    if (!instanceSp) {
+        return EX_NONE;
+    }
+    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 PresetReverbSw::getDescriptor(Descriptor* _aidl_return) {
+    LOG(DEBUG) << __func__ << kDescriptor.toString();
+    *_aidl_return = kDescriptor;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus PresetReverbSw::setParameterSpecific(const Parameter::Specific& specific) {
+    RETURN_IF(Parameter::Specific::reverb != 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();
+}
+
+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 ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EffectContext> PresetReverbSw::createContext(const Parameter::Common& common) {
+    if (mContext) {
+        LOG(DEBUG) << __func__ << " context already exist";
+        return mContext;
+    }
+    mContext = std::make_shared<PresetReverbSwContext>(1 /* statusFmqDepth */, common);
+    return mContext;
+}
+
+RetCode PresetReverbSw::releaseContext() {
+    if (mContext) {
+        mContext.reset();
+    }
+    return RetCode::SUCCESS;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status PresetReverbSw::effectProcessImpl(float* in, float* out, int process) {
+    // TODO: get data buffer and process.
+    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
+    for (int i = 0; i < process; i++) {
+        *out++ = *in++;
+    }
+    return {STATUS_OK, process, process};
+}
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/presetReverb/PresetReverbSw.h b/audio/aidl/default/presetReverb/PresetReverbSw.h
new file mode 100644
index 0000000..75a5a94
--- /dev/null
+++ b/audio/aidl/default/presetReverb/PresetReverbSw.h
@@ -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.
+ */
+
+#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 PresetReverbSwContext final : public EffectContext {
+  public:
+    PresetReverbSwContext(int statusDepth, const Parameter::Common& common)
+        : EffectContext(statusDepth, common) {
+        LOG(DEBUG) << __func__;
+    }
+    // TODO: add specific context here
+};
+
+class PresetReverbSw final : public EffectImpl {
+  public:
+    PresetReverbSw() { LOG(DEBUG) << __func__; }
+    ~PresetReverbSw() {
+        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;
+    IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+    RetCode releaseContext() override;
+
+  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;
+};
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/virtualizer/Android.bp b/audio/aidl/default/virtualizer/Android.bp
new file mode 100644
index 0000000..ba38f5c
--- /dev/null
+++ b/audio/aidl/default/virtualizer/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: "libvirtualizersw",
+    defaults: [
+        "aidlaudioeffectservice_defaults",
+        "latest_android_media_audio_common_types_ndk_shared",
+        "latest_android_hardware_audio_effect_ndk_shared",
+    ],
+    srcs: [
+        "VirtualizerSw.cpp",
+        ":effectCommonFile",
+    ],
+    visibility: [
+        "//hardware/interfaces/audio/aidl/default",
+    ],
+}
diff --git a/audio/aidl/default/virtualizer/VirtualizerSw.cpp b/audio/aidl/default/virtualizer/VirtualizerSw.cpp
new file mode 100644
index 0000000..9688fc8
--- /dev/null
+++ b/audio/aidl/default/virtualizer/VirtualizerSw.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 <cstddef>
+#define LOG_TAG "AHAL_VirtualizerSw"
+#include <Utils.h>
+#include <algorithm>
+#include <unordered_set>
+
+#include <android-base/logging.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include "VirtualizerSw.h"
+
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kVirtualizerSwImplUUID;
+using aidl::android::hardware::audio::effect::State;
+using aidl::android::hardware::audio::effect::VirtualizerSw;
+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 != kVirtualizerSwImplUUID) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    if (instanceSpp) {
+        *instanceSpp = ndk::SharedRefBase::make<VirtualizerSw>();
+        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 destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
+    if (!instanceSp) {
+        return EX_NONE;
+    }
+    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 VirtualizerSw::getDescriptor(Descriptor* _aidl_return) {
+    LOG(DEBUG) << __func__ << kDescriptor.toString();
+    *_aidl_return = kDescriptor;
+    return ndk::ScopedAStatus::ok();
+}
+
+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();
+}
+
+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);
+    return ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EffectContext> VirtualizerSw::createContext(const Parameter::Common& common) {
+    if (mContext) {
+        LOG(DEBUG) << __func__ << " context already exist";
+        return mContext;
+    }
+    mContext = std::make_shared<VirtualizerSwContext>(1 /* statusFmqDepth */, common);
+    return mContext;
+}
+
+RetCode VirtualizerSw::releaseContext() {
+    if (mContext) {
+        mContext.reset();
+    }
+    return RetCode::SUCCESS;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status VirtualizerSw::effectProcessImpl(float* in, float* out, int process) {
+    // TODO: get data buffer and process.
+    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
+    for (int i = 0; i < process; i++) {
+        *out++ = *in++;
+    }
+    return {STATUS_OK, process, process};
+}
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/virtualizer/VirtualizerSw.h b/audio/aidl/default/virtualizer/VirtualizerSw.h
new file mode 100644
index 0000000..e4de8b3
--- /dev/null
+++ b/audio/aidl/default/virtualizer/VirtualizerSw.h
@@ -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.
+ */
+
+#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 VirtualizerSwContext final : public EffectContext {
+  public:
+    VirtualizerSwContext(int statusDepth, const Parameter::Common& common)
+        : EffectContext(statusDepth, common) {
+        LOG(DEBUG) << __func__;
+    }
+    // TODO: add specific context here
+};
+
+class VirtualizerSw final : public EffectImpl {
+  public:
+    VirtualizerSw() { LOG(DEBUG) << __func__; }
+    ~VirtualizerSw() {
+        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;
+    IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+    RetCode releaseContext() override;
+
+  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;
+};
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/visualizer/Android.bp b/audio/aidl/default/visualizer/Android.bp
new file mode 100644
index 0000000..5041be8
--- /dev/null
+++ b/audio/aidl/default/visualizer/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: "libvisualizersw",
+    defaults: [
+        "aidlaudioeffectservice_defaults",
+        "latest_android_media_audio_common_types_ndk_shared",
+        "latest_android_hardware_audio_effect_ndk_shared",
+    ],
+    srcs: [
+        "VisualizerSw.cpp",
+        ":effectCommonFile",
+    ],
+    visibility: [
+        "//hardware/interfaces/audio/aidl/default",
+    ],
+}
diff --git a/audio/aidl/default/visualizer/VisualizerSw.cpp b/audio/aidl/default/visualizer/VisualizerSw.cpp
new file mode 100644
index 0000000..24a7bef
--- /dev/null
+++ b/audio/aidl/default/visualizer/VisualizerSw.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 <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::IEffect;
+using aidl::android::hardware::audio::effect::kVisualizerSwImplUUID;
+using aidl::android::hardware::audio::effect::State;
+using aidl::android::hardware::audio::effect::VisualizerSw;
+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 != kVisualizerSwImplUUID) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    if (instanceSpp) {
+        *instanceSpp = ndk::SharedRefBase::make<VisualizerSw>();
+        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 destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
+    if (!instanceSp) {
+        return EX_NONE;
+    }
+    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 VisualizerSw::getDescriptor(Descriptor* _aidl_return) {
+    LOG(DEBUG) << __func__ << kDescriptor.toString();
+    *_aidl_return = kDescriptor;
+    return ndk::ScopedAStatus::ok();
+}
+
+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();
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus VisualizerSw::getParameterSpecific(const Parameter::Id& id,
+                                                      Parameter::Specific* specific) {
+    auto tag = id.getTag();
+    RETURN_IF(Parameter::Id::visualizerTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
+    specific->set<Parameter::Specific::visualizer>(mSpecificParam);
+    return ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EffectContext> VisualizerSw::createContext(const Parameter::Common& common) {
+    if (mContext) {
+        LOG(DEBUG) << __func__ << " context already exist";
+        return mContext;
+    }
+    mContext = std::make_shared<VisualizerSwContext>(1 /* statusFmqDepth */, common);
+    return mContext;
+}
+
+RetCode VisualizerSw::releaseContext() {
+    if (mContext) {
+        mContext.reset();
+    }
+    return RetCode::SUCCESS;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status VisualizerSw::effectProcessImpl(float* in, float* out, int process) {
+    // TODO: get data buffer and process.
+    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
+    for (int i = 0; i < process; i++) {
+        *out++ = *in++;
+    }
+    return {STATUS_OK, process, process};
+}
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/visualizer/VisualizerSw.h b/audio/aidl/default/visualizer/VisualizerSw.h
new file mode 100644
index 0000000..bccd6e9
--- /dev/null
+++ b/audio/aidl/default/visualizer/VisualizerSw.h
@@ -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.
+ */
+
+#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 VisualizerSwContext final : public EffectContext {
+  public:
+    VisualizerSwContext(int statusDepth, const Parameter::Common& common)
+        : EffectContext(statusDepth, common) {
+        LOG(DEBUG) << __func__;
+    }
+    // TODO: add specific context here
+};
+
+class VisualizerSw final : public EffectImpl {
+  public:
+    VisualizerSw() { LOG(DEBUG) << __func__; }
+    ~VisualizerSw() {
+        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;
+    IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+    RetCode releaseContext() override;
+
+  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;
+};
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/volume/Android.bp b/audio/aidl/default/volume/Android.bp
new file mode 100644
index 0000000..505ee67
--- /dev/null
+++ b/audio/aidl/default/volume/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: "libvolumesw",
+    defaults: [
+        "aidlaudioeffectservice_defaults",
+        "latest_android_media_audio_common_types_ndk_shared",
+        "latest_android_hardware_audio_effect_ndk_shared",
+    ],
+    srcs: [
+        "VolumeSw.cpp",
+        ":effectCommonFile",
+    ],
+    visibility: [
+        "//hardware/interfaces/audio/aidl/default",
+    ],
+}
diff --git a/audio/aidl/default/volume/VolumeSw.cpp b/audio/aidl/default/volume/VolumeSw.cpp
new file mode 100644
index 0000000..b8af921
--- /dev/null
+++ b/audio/aidl/default/volume/VolumeSw.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 <cstddef>
+#define LOG_TAG "AHAL_VolumeSw"
+#include <Utils.h>
+#include <algorithm>
+#include <unordered_set>
+
+#include <android-base/logging.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include "VolumeSw.h"
+
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kVolumeSwImplUUID;
+using aidl::android::hardware::audio::effect::State;
+using aidl::android::hardware::audio::effect::VolumeSw;
+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 != kVolumeSwImplUUID) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    if (instanceSpp) {
+        *instanceSpp = ndk::SharedRefBase::make<VolumeSw>();
+        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 destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
+    if (!instanceSp) {
+        return EX_NONE;
+    }
+    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 VolumeSw::getDescriptor(Descriptor* _aidl_return) {
+    LOG(DEBUG) << __func__ << kDescriptor.toString();
+    *_aidl_return = kDescriptor;
+    return ndk::ScopedAStatus::ok();
+}
+
+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();
+}
+
+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);
+    return ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EffectContext> VolumeSw::createContext(const Parameter::Common& common) {
+    if (mContext) {
+        LOG(DEBUG) << __func__ << " context already exist";
+        return mContext;
+    }
+    mContext = std::make_shared<VolumeSwContext>(1 /* statusFmqDepth */, common);
+    return mContext;
+}
+
+RetCode VolumeSw::releaseContext() {
+    if (mContext) {
+        mContext.reset();
+    }
+    return RetCode::SUCCESS;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status VolumeSw::effectProcessImpl(float* in, float* out, int process) {
+    // TODO: get data buffer and process.
+    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
+    for (int i = 0; i < process; i++) {
+        *out++ = *in++;
+    }
+    return {STATUS_OK, process, process};
+}
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/volume/VolumeSw.h b/audio/aidl/default/volume/VolumeSw.h
new file mode 100644
index 0000000..86e01c1
--- /dev/null
+++ b/audio/aidl/default/volume/VolumeSw.h
@@ -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.
+ */
+
+#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 VolumeSwContext final : public EffectContext {
+  public:
+    VolumeSwContext(int statusDepth, const Parameter::Common& common)
+        : EffectContext(statusDepth, common) {
+        LOG(DEBUG) << __func__;
+    }
+    // TODO: add specific context here
+};
+
+class VolumeSw final : public EffectImpl {
+  public:
+    VolumeSw() { LOG(DEBUG) << __func__; }
+    ~VolumeSw() {
+        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;
+    IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+    RetCode releaseContext() override;
+
+  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;
+};
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/vts/Android.bp b/audio/aidl/vts/Android.bp
index 6ea7cef..03e9fca 100644
--- a/audio/aidl/vts/Android.bp
+++ b/audio/aidl/vts/Android.bp
@@ -7,35 +7,31 @@
     default_applicable_licenses: ["hardware_interfaces_license"],
 }
 
-cc_test {
-    name: "VtsHalAudioCoreTargetTest",
+cc_defaults {
+    name: "VtsHalAudioTargetTestDefaults",
     defaults: [
-        "VtsHalTargetTestDefaults",
-        "use_libaidlvintf_gtest_helper_static",
         "latest_android_hardware_audio_common_ndk_static",
-        "latest_android_hardware_audio_core_ndk_static",
         "latest_android_media_audio_common_types_ndk_static",
+        "use_libaidlvintf_gtest_helper_static",
+        "VtsHalTargetTestDefaults",
     ],
     shared_libs: [
         "libbinder_ndk",
-        "libcutils",
         "libfmq",
     ],
     static_libs: [
+        "android.hardware.audio.effect-V1-ndk",
         "android.hardware.common-V2-ndk",
         "android.hardware.common.fmq-V1-ndk",
         "libaudioaidlcommon",
     ],
+    header_libs: ["libaudioaidl_headers"],
     cflags: [
         "-Wall",
         "-Wextra",
         "-Werror",
         "-Wthread-safety",
     ],
-    srcs: [
-        "ModuleConfig.cpp",
-        "VtsHalAudioCoreTargetTest.cpp",
-    ],
     test_suites: [
         "general-tests",
         "vts",
@@ -43,29 +39,40 @@
 }
 
 cc_test {
-    name: "VtsHalAudioEffectTargetTest",
+    name: "VtsHalAudioCoreTargetTest",
     defaults: [
-        "latest_android_media_audio_common_types_ndk_static",
-        "VtsHalTargetTestDefaults",
-        "use_libaidlvintf_gtest_helper_static",
-    ],
-    srcs: [
-        "VtsHalAudioEffectTargetTest.cpp",
+        "VtsHalAudioTargetTestDefaults",
+        "latest_android_hardware_audio_core_ndk_static",
     ],
     shared_libs: [
-        "libbinder_ndk",
+        "libcutils",
     ],
-    static_libs: [
-        "android.hardware.audio.effect-V1-ndk",
+    srcs: [
+        "ModuleConfig.cpp",
+        "VtsHalAudioCoreTargetTest.cpp",
     ],
-    cflags: [
-        "-Wall",
-        "-Wextra",
-        "-Werror",
-        "-Wthread-safety",
-    ],
-    test_suites: [
-        "general-tests",
-        "vts",
-    ],
+}
+
+cc_test {
+    name: "VtsHalAudioEffectFactoryTargetTest",
+    defaults: ["VtsHalAudioTargetTestDefaults"],
+    srcs: ["VtsHalAudioEffectFactoryTargetTest.cpp"],
+}
+
+cc_test {
+    name: "VtsHalAudioEffectTargetTest",
+    defaults: ["VtsHalAudioTargetTestDefaults"],
+    srcs: ["VtsHalAudioEffectTargetTest.cpp"],
+}
+
+cc_test {
+    name: "VtsHalEqualizerTargetTest",
+    defaults: ["VtsHalAudioTargetTestDefaults"],
+    srcs: ["VtsHalEqualizerTargetTest.cpp"],
+}
+
+cc_test {
+    name: "VtsHalLoudnessEnhancerTargetTest",
+    defaults: ["VtsHalAudioTargetTestDefaults"],
+    srcs: ["VtsHalLoudnessEnhancerTargetTest.cpp"],
 }
diff --git a/audio/aidl/vts/AudioHalBinderServiceUtil.h b/audio/aidl/vts/AudioHalBinderServiceUtil.h
index e928286..c8d81b1 100644
--- a/audio/aidl/vts/AudioHalBinderServiceUtil.h
+++ b/audio/aidl/vts/AudioHalBinderServiceUtil.h
@@ -21,6 +21,7 @@
 #include <mutex>
 
 #include <android-base/properties.h>
+#include <android/binder_auto_utils.h>
 #include <android/binder_manager.h>
 #include <android/binder_process.h>
 
@@ -34,7 +35,7 @@
         if (mBinder == nullptr) {
             LOG(ERROR) << "Failed to get service " << serviceName;
         } else {
-            LOG(DEBUG) << "succeed to get service " << serviceName;
+            LOG(DEBUG) << "Succeeded to get service " << serviceName;
         }
         return mBinder;
     }
diff --git a/audio/aidl/vts/EffectFactoryHelper.h b/audio/aidl/vts/EffectFactoryHelper.h
new file mode 100644
index 0000000..dc766dd
--- /dev/null
+++ b/audio/aidl/vts/EffectFactoryHelper.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include <android/binder_auto_utils.h>
+
+#include "TestUtils.h"
+#include "effect-impl/EffectUUID.h"
+
+using namespace android;
+
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::media::audio::common::AudioUuid;
+
+class EffectFactoryHelper {
+  public:
+    explicit EffectFactoryHelper(const std::string& name) : mServiceName(name) {}
+
+    void ConnectToFactoryService() {
+        mEffectFactory = IFactory::fromBinder(binderUtil.connectToService(mServiceName));
+        ASSERT_NE(mEffectFactory, nullptr);
+    }
+
+    void RestartFactoryService() {
+        ASSERT_NE(mEffectFactory, nullptr);
+        mEffectFactory = IFactory::fromBinder(binderUtil.restartService());
+        ASSERT_NE(mEffectFactory, nullptr);
+    }
+
+    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) {
+        AudioHalBinderServiceUtil util;
+        auto names = android::getAidlHalInstanceNames(serviceName);
+        std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor::Identity>> 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()) {
+                            continue;
+                        }
+                        result.emplace_back(factory, id);
+                    }
+                }
+            }
+        }
+
+        return result;
+    }
+
+  private:
+    std::shared_ptr<IFactory> mEffectFactory;
+    std::string mServiceName;
+    AudioHalBinderServiceUtil binderUtil;
+};
diff --git a/audio/aidl/vts/EffectHelper.h b/audio/aidl/vts/EffectHelper.h
new file mode 100644
index 0000000..73a1f49
--- /dev/null
+++ b/audio/aidl/vts/EffectHelper.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <algorithm>
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include <aidl/android/hardware/audio/effect/IEffect.h>
+#include <aidl/android/hardware/audio/effect/IFactory.h>
+#include <aidl/android/media/audio/common/AudioChannelLayout.h>
+#include <android/binder_auto_utils.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include "AudioHalBinderServiceUtil.h"
+#include "EffectFactoryHelper.h"
+#include "TestUtils.h"
+
+using namespace android;
+using aidl::android::hardware::audio::effect::CommandId;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::Parameter;
+using aidl::android::hardware::audio::effect::State;
+using aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using aidl::android::media::audio::common::AudioChannelLayout;
+using aidl::android::media::audio::common::AudioFormatDescription;
+using aidl::android::media::audio::common::AudioFormatType;
+using aidl::android::media::audio::common::AudioUuid;
+using aidl::android::media::audio::common::PcmType;
+
+const AudioFormatDescription kDefaultFormatDescription = {
+        .type = AudioFormatType::PCM, .pcm = PcmType::FLOAT_32_BIT, .encoding = ""};
+
+typedef ::android::AidlMessageQueue<IEffect::Status,
+                                    ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
+        StatusMQ;
+typedef ::android::AidlMessageQueue<float,
+                                    ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
+        DataMQ;
+
+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) {
+        ASSERT_NE(factory, nullptr);
+        EXPECT_STATUS(status, factory->createEffect(id.uuid, &effect));
+        if (status == EX_NONE) {
+            ASSERT_NE(effect, nullptr) << id.uuid.toString();
+        }
+    }
+
+    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));
+    }
+
+    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));
+    }
+
+    static void open(std::shared_ptr<IEffect> effect, int session = 0,
+                     binder_status_t status = EX_NONE) {
+        ASSERT_NE(effect, nullptr);
+        Parameter::Common common = EffectHelper::createParamCommon(session);
+        IEffect::OpenEffectReturn ret;
+        open(effect, common, std::nullopt /* specific */, &ret, status);
+    }
+
+    static void close(std::shared_ptr<IEffect> effect, binder_status_t status = EX_NONE) {
+        if (effect) {
+            EXPECT_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));
+    }
+    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);
+    }
+    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));
+    }
+    static void allocateInputData(const Parameter::Common common, std::unique_ptr<DataMQ>& mq,
+                                  std::vector<float>& buffer) {
+        ASSERT_NE(mq, nullptr);
+        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));
+        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);
+        auto bufferFloats = buffer.size();
+        auto floatsToWrite = std::min(available, bufferFloats);
+        EXPECT_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);
+        if (statusNum != 0) {
+            EXPECT_EQ(expectFloats, (unsigned)status.fmqProduced);
+            EXPECT_EQ(expectFloats, dataMq->availableToRead());
+            if (expectFloats != 0) {
+                EXPECT_TRUE(dataMq->read(buffer.data(), expectFloats));
+            }
+        }
+    }
+    static Parameter::Common createParamCommon(
+            int session = 0, int ioHandle = -1, int iSampleRate = 48000, int oSampleRate = 48000,
+            long iFrameCount = 0x100, long oFrameCount = 0x100,
+            AudioChannelLayout inputChannelLayout =
+                    AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
+                            AudioChannelLayout::LAYOUT_STEREO),
+            AudioChannelLayout outputChannelLayout =
+                    AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
+                            AudioChannelLayout::LAYOUT_STEREO)) {
+        Parameter::Common common;
+        common.session = session;
+        common.ioHandle = ioHandle;
+
+        auto& input = common.input;
+        auto& output = common.output;
+        input.base.sampleRate = iSampleRate;
+        input.base.channelMask = inputChannelLayout;
+        input.base.format = kDefaultFormatDescription;
+        input.frameCount = iFrameCount;
+        output.base.sampleRate = oSampleRate;
+        output.base.channelMask = outputChannelLayout;
+        output.base.format = kDefaultFormatDescription;
+        output.frameCount = oFrameCount;
+        return common;
+    }
+
+    typedef ::android::AidlMessageQueue<
+            IEffect::Status, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
+            StatusMQ;
+    typedef ::android::AidlMessageQueue<
+            float, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
+            DataMQ;
+
+    class EffectParam {
+      public:
+        std::unique_ptr<StatusMQ> statusMQ;
+        std::unique_ptr<DataMQ> inputMQ;
+        std::unique_ptr<DataMQ> outputMQ;
+    };
+};
diff --git a/audio/aidl/vts/TestUtils.h b/audio/aidl/vts/TestUtils.h
index 2fc109a..5e4d56a 100644
--- a/audio/aidl/vts/TestUtils.h
+++ b/audio/aidl/vts/TestUtils.h
@@ -21,15 +21,6 @@
 #include <android/binder_auto_utils.h>
 #include <gtest/gtest_pred_impl.h>
 
-namespace ndk {
-
-std::ostream& operator<<(std::ostream& str, const ScopedAStatus& status) {
-    str << status.getDescription();
-    return str;
-}
-
-}  // namespace ndk
-
 namespace android::hardware::audio::common::testing {
 
 namespace detail {
diff --git a/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp
index 2381200..5e9aa7f 100644
--- a/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <algorithm>
+#include <cmath>
 #include <limits>
 #include <memory>
 #include <optional>
@@ -29,11 +30,12 @@
 #include <Utils.h>
 #include <aidl/Gtest.h>
 #include <aidl/Vintf.h>
-#include <aidl/android/hardware/audio/core/IConfig.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"
@@ -45,11 +47,13 @@
 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;
@@ -66,9 +70,11 @@
 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>
@@ -171,25 +177,49 @@
     AudioPortConfig mConfig;
 };
 
-class AudioCoreModule : public testing::TestWithParam<std::string> {
+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 SetUp() override {
-        ASSERT_NO_FATAL_FAILURE(ConnectToService());
+    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 TearDown() override {
+    void TearDownImpl() {
         if (module != nullptr) {
             EXPECT_IS_OK(module->setModuleDebug(ModuleDebug{}));
         }
     }
 
-    void ConnectToService() {
-        module = IModule::fromBinder(binderUtil.connectToService(GetParam()));
+    void ConnectToService(const std::string& moduleName) {
+        module = IModule::fromBinder(binderUtil.connectToService(moduleName));
         ASSERT_NE(module, nullptr);
     }
 
@@ -269,6 +299,13 @@
     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) {}
@@ -352,21 +389,36 @@
     std::unique_ptr<DataMQ> mDataMQ;
 };
 
-class StreamCommonLogic : public StreamLogic {
+class StreamLogicDriver {
   public:
-    StreamDescriptor::Position getLastObservablePosition() {
-        std::lock_guard<std::mutex> lock(mLock);
-        return mLastReply.observable;
-    }
+    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:
-    explicit StreamCommonLogic(const StreamContext& context)
+    StreamCommonLogic(const StreamContext& context, StreamLogicDriver* driver)
         : mCommandMQ(context.getCommandMQ()),
           mReplyMQ(context.getReplyMQ()),
           mDataMQ(context.getDataMQ()),
-          mData(context.getBufferSizeBytes()) {}
+          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 ""; }
 
@@ -374,19 +426,20 @@
     StreamContext::ReplyMQ* mReplyMQ;
     StreamContext::DataMQ* mDataMQ;
     std::vector<int8_t> mData;
-    std::mutex mLock;
-    StreamDescriptor::Reply mLastReply GUARDED_BY(mLock);
+    StreamLogicDriver* const mDriver;
 };
 
 class StreamReaderLogic : public StreamCommonLogic {
   public:
-    explicit StreamReaderLogic(const StreamContext& context) : StreamCommonLogic(context) {}
+    StreamReaderLogic(const StreamContext& context, StreamLogicDriver* driver)
+        : StreamCommonLogic(context, driver) {}
 
   protected:
     Status cycle() override {
-        StreamDescriptor::Command command{};
-        command.code = StreamDescriptor::COMMAND_BURST;
-        command.fmqByteCount = mData.size();
+        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;
@@ -396,25 +449,55 @@
             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 || reply.fmqByteCount > command.fmqByteCount) {
+        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;
         }
-        {
-            std::lock_guard<std::mutex> lock(mLock);
-            mLastReply = reply;
+        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();
         }
-        const size_t readCount = std::min({mDataMQ->availableToRead(),
-                                           static_cast<size_t>(reply.fmqByteCount), mData.size()});
-        if (readCount == 0 || mDataMQ->read(mData.data(), readCount)) {
+        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__ << ": reading of " << readCount << " data bytes from MQ failed";
+        LOG(ERROR) << __func__ << ": unacceptable reply: " << reply.toString();
         return Status::ABORT;
     }
 };
@@ -422,17 +505,20 @@
 
 class StreamWriterLogic : public StreamCommonLogic {
   public:
-    explicit StreamWriterLogic(const StreamContext& context) : StreamCommonLogic(context) {}
+    StreamWriterLogic(const StreamContext& context, StreamLogicDriver* driver)
+        : StreamCommonLogic(context, driver) {}
 
   protected:
     Status cycle() override {
-        if (!mDataMQ->write(mData.data(), mData.size())) {
+        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;
         }
-        StreamDescriptor::Command command{};
-        command.code = StreamDescriptor::COMMAND_BURST;
-        command.fmqByteCount = mData.size();
         if (!mCommandMQ->writeBlocking(&command, 1)) {
             LOG(ERROR) << __func__ << ": writing of command into MQ failed";
             return Status::ABORT;
@@ -442,20 +528,45 @@
             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 || reply.fmqByteCount > command.fmqByteCount) {
+        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;
         }
-        {
-            std::lock_guard<std::mutex> lock(mLock);
-            mLastReply = reply;
+        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;
         }
-        return Status::CONTINUE;
+        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>;
@@ -466,52 +577,6 @@
     using Worker = std::conditional_t<is_input, StreamReader, StreamWriter>;
 };
 
-// A dedicated version to test replies to invalid commands.
-class StreamInvalidCommandLogic : public StreamCommonLogic {
-  public:
-    StreamInvalidCommandLogic(const StreamContext& context,
-                              const std::vector<StreamDescriptor::Command>& commands)
-        : StreamCommonLogic(context), mCommands(commands) {}
-
-    std::vector<std::string> getUnexpectedStatuses() {
-        std::lock_guard<std::mutex> lock(mLock);
-        return mUnexpectedStatuses;
-    }
-
-  protected:
-    Status cycle() override {
-        // Send all commands in one cycle to simplify testing.
-        // Extra logging helps to sort out issues with unexpected HAL behavior.
-        for (const auto& command : mCommands) {
-            LOG(INFO) << __func__ << ": writing command " << command.toString() << " into MQ...";
-            if (!getCommandMQ()->writeBlocking(&command, 1)) {
-                LOG(ERROR) << __func__ << ": writing of command into MQ failed";
-                return Status::ABORT;
-            }
-            StreamDescriptor::Reply reply{};
-            LOG(INFO) << __func__ << ": reading reply for command " << command.toString() << "...";
-            if (!getReplyMQ()->readBlocking(&reply, 1)) {
-                LOG(ERROR) << __func__ << ": reading of reply from MQ failed";
-                return Status::ABORT;
-            }
-            LOG(INFO) << __func__ << ": received status " << statusToString(reply.status)
-                      << " for command " << command.toString();
-            if (reply.status != STATUS_BAD_VALUE) {
-                std::string s = command.toString();
-                s.append(", ").append(statusToString(reply.status));
-                std::lock_guard<std::mutex> lock(mLock);
-                mUnexpectedStatuses.push_back(std::move(s));
-            }
-        };
-        return Status::EXIT;
-    }
-
-  private:
-    const std::vector<StreamDescriptor::Command> mCommands;
-    std::mutex mLock;
-    std::vector<std::string> mUnexpectedStatuses GUARDED_BY(mLock);
-};
-
 template <typename Stream>
 class WithStream {
   public:
@@ -1208,6 +1273,152 @@
     }
 }
 
+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:
@@ -1315,19 +1526,6 @@
         EXPECT_NO_FATAL_FAILURE(OpenTwiceSamePortConfigImpl(portConfig.value()));
     }
 
-    void ReadOrWrite(bool useSetupSequence2, bool validateObservablePosition) {
-        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) {
-            EXPECT_NO_FATAL_FAILURE(
-                    ReadOrWriteImpl(portConfig, useSetupSequence2, validateObservablePosition))
-                    << portConfig.toString();
-        }
-    }
-
     void ResetPortConfigWithOpenStream() {
         const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
         if (!portConfig.has_value()) {
@@ -1357,131 +1555,40 @@
                 << stream1.getPortId();
     }
 
-    template <class Worker>
-    void WaitForObservablePositionAdvance(Worker& worker) {
-        static constexpr int kWriteDurationUs = 50 * 1000;
-        static constexpr std::chrono::milliseconds kPositionChangeTimeout{10000};
-        int64_t framesInitial;
-        framesInitial = worker.getLastObservablePosition().frames;
-        ASSERT_FALSE(worker.hasError());
-        bool timedOut = false;
-        int64_t frames = framesInitial;
-        for (android::base::Timer elapsed;
-             frames <= framesInitial && !worker.hasError() &&
-             !(timedOut = (elapsed.duration() >= kPositionChangeTimeout));) {
-            usleep(kWriteDurationUs);
-            frames = worker.getLastObservablePosition().frames;
-        }
-        EXPECT_FALSE(timedOut);
-        EXPECT_FALSE(worker.hasError()) << worker.getError();
-        EXPECT_GT(frames, framesInitial);
-    }
-
-    void ReadOrWriteImpl(const AudioPortConfig& portConfig, bool useSetupSequence2,
-                         bool validateObservablePosition) {
-        if (!useSetupSequence2) {
-            ASSERT_NO_FATAL_FAILURE(
-                    ReadOrWriteSetupSequence1(portConfig, validateObservablePosition));
-        } else {
-            ASSERT_NO_FATAL_FAILURE(
-                    ReadOrWriteSetupSequence2(portConfig, validateObservablePosition));
-        }
-    }
-
-    // Set up a patch first, then open a stream.
-    void ReadOrWriteSetupSequence1(const AudioPortConfig& portConfig,
-                                   bool validateObservablePosition) {
-        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));
-        typename IOTraits<Stream>::Worker worker(*stream.getContext());
-
-        ASSERT_TRUE(worker.start());
-        ASSERT_TRUE(worker.waitForAtLeastOneCycle());
-        if (validateObservablePosition) {
-            ASSERT_NO_FATAL_FAILURE(WaitForObservablePositionAdvance(worker));
-        }
-    }
-
-    // Open a stream, then set up a patch for it.
-    void ReadOrWriteSetupSequence2(const AudioPortConfig& portConfig,
-                                   bool validateObservablePosition) {
-        WithStream<Stream> stream(portConfig);
-        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
-        typename IOTraits<Stream>::Worker worker(*stream.getContext());
-
-        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());
-        ASSERT_TRUE(worker.waitForAtLeastOneCycle());
-        if (validateObservablePosition) {
-            ASSERT_NO_FATAL_FAILURE(WaitForObservablePositionAdvance(worker));
-        }
-    }
-
     void SendInvalidCommandImpl(const AudioPortConfig& portConfig) {
-        std::vector<StreamDescriptor::Command> commands(6);
-        commands[0].code = -1;
-        commands[1].code = StreamDescriptor::COMMAND_BURST - 1;
-        commands[2].code = std::numeric_limits<int32_t>::min();
-        commands[3].code = std::numeric_limits<int32_t>::max();
-        commands[4].code = StreamDescriptor::COMMAND_BURST;
-        commands[4].fmqByteCount = -1;
-        commands[5].code = StreamDescriptor::COMMAND_BURST;
-        commands[5].fmqByteCount = std::numeric_limits<int32_t>::min();
+        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));
-        StreamWorker<StreamInvalidCommandLogic> writer(*stream.getContext(), commands);
-        ASSERT_TRUE(writer.start());
-        writer.waitForAtLeastOneCycle();
-        auto unexpectedStatuses = writer.getUnexpectedStatuses();
-        EXPECT_EQ(0UL, unexpectedStatuses.size())
-                << "Pairs of (command, actual status): "
-                << android::internal::ToString(unexpectedStatuses);
+        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_IO_STREAM(method_name)                                                \
+#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()); }
-#define TEST_IO_STREAM_2(method_name, arg1, arg2)           \
-    TEST_P(AudioStreamIn, method_name##_##arg1##_##arg2) {  \
-        ASSERT_NO_FATAL_FAILURE(method_name(arg1, arg2));   \
-    }                                                       \
-    TEST_P(AudioStreamOut, method_name##_##arg1##_##arg2) { \
-        ASSERT_NO_FATAL_FAILURE(method_name(arg1, arg2));   \
-    }
 
-TEST_IO_STREAM(CloseTwice);
-TEST_IO_STREAM(OpenAllConfigs);
-TEST_IO_STREAM(OpenInvalidBufferSize);
-TEST_IO_STREAM(OpenInvalidDirection);
-TEST_IO_STREAM(OpenOverMaxCount);
-TEST_IO_STREAM(OpenTwiceSamePortConfig);
-// Use of constants makes comprehensible test names.
-constexpr bool SetupSequence1 = false;
-constexpr bool SetupSequence2 = true;
-constexpr bool SetupOnly = false;
-constexpr bool ValidateObservablePosition = true;
-TEST_IO_STREAM_2(ReadOrWrite, SetupSequence1, SetupOnly);
-TEST_IO_STREAM_2(ReadOrWrite, SetupSequence2, SetupOnly);
-TEST_IO_STREAM_2(ReadOrWrite, SetupSequence1, ValidateObservablePosition);
-TEST_IO_STREAM_2(ReadOrWrite, SetupSequence2, ValidateObservablePosition);
-TEST_IO_STREAM(ResetPortConfigWithOpenStream);
-TEST_IO_STREAM(SendInvalidCommand);
+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);
@@ -1523,6 +1630,165 @@
             << "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 {
@@ -1696,6 +1962,10 @@
                          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);
@@ -1704,6 +1974,117 @@
                          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);
diff --git a/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp b/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp
new file mode 100644
index 0000000..8ae963e
--- /dev/null
+++ b/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp
@@ -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.
+ */
+
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+#define LOG_TAG "VtsHalAudioEffectFactory"
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android/binder_interface_utils.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+#include <aidl/android/hardware/audio/effect/IFactory.h>
+
+#include "AudioHalBinderServiceUtil.h"
+#include "EffectFactoryHelper.h"
+#include "TestUtils.h"
+
+using namespace android;
+
+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::kEffectZeroUuid;
+using aidl::android::hardware::audio::effect::Processing;
+using aidl::android::media::audio::common::AudioSource;
+using aidl::android::media::audio::common::AudioStreamType;
+using aidl::android::media::audio::common::AudioUuid;
+
+/// Effect factory testing.
+class EffectFactoryTest : public testing::TestWithParam<std::string> {
+  public:
+    void SetUp() override {
+        mFactoryHelper = std::make_unique<EffectFactoryHelper>(GetParam());
+        connectAndGetFactory();
+    }
+
+    void TearDown() override {
+        for (auto& effect : mEffects) {
+            const auto status = mEffectFactory->destroyEffect(effect);
+            EXPECT_STATUS(EX_NONE, status);
+        }
+    }
+
+    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};
+
+    template <typename Functor>
+    void ForEachId(const std::vector<Descriptor::Identity> ids, Functor functor) {
+        for (const auto& id : ids) {
+            SCOPED_TRACE(id.toString());
+            functor(id);
+        }
+    }
+    template <typename Functor>
+    void ForEachEffect(std::vector<std::shared_ptr<IEffect>> effects, Functor functor) {
+        for (auto& effect : effects) {
+            functor(effect);
+        }
+    }
+
+    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>> effects;
+        for (const auto& id : ids) {
+            std::shared_ptr<IEffect> effect;
+            EXPECT_STATUS(expectStatus, mEffectFactory->createEffect(id.uuid, &effect));
+            if (expectStatus == EX_NONE) {
+                EXPECT_NE(effect, nullptr) << " null effect with uuid: " << id.uuid.toString();
+                effects.push_back(std::move(effect));
+            }
+        }
+        return effects;
+    }
+    void destroyEffects(std::vector<std::shared_ptr<IEffect>> effects,
+                        const binder_status_t expectStatus = EX_NONE) {
+        for (const auto& effect : effects) {
+            EXPECT_STATUS(expectStatus, mEffectFactory->destroyEffect(effect));
+        }
+    }
+    void creatAndDestroyIds(const std::vector<Descriptor::Identity> ids) {
+        for (const auto& id : ids) {
+            auto effects = createWithIds({id});
+            ASSERT_NO_FATAL_FAILURE(destroyEffects(effects));
+        }
+    }
+    void connectAndGetFactory() {
+        ASSERT_NO_FATAL_FAILURE(mFactoryHelper->ConnectToFactoryService());
+        mEffectFactory = mFactoryHelper->GetFactory();
+        ASSERT_NE(mEffectFactory, nullptr);
+    }
+};
+
+TEST_P(EffectFactoryTest, SetupAndTearDown) {
+    // Intentionally empty test body.
+}
+
+TEST_P(EffectFactoryTest, CanBeRestarted) {
+    ASSERT_NO_FATAL_FAILURE(mFactoryHelper->RestartFactoryService());
+}
+
+/**
+ * @brief Check at least support list of effect must be supported by aosp:
+ * https://developer.android.com/reference/android/media/audiofx/AudioEffect
+ */
+TEST_P(EffectFactoryTest, ExpectAllAospEffectTypes) {
+    std::vector<Descriptor::Identity> ids;
+    std::set<AudioUuid> typeUuidSet(
+            {aidl::android::hardware::audio::effect::kBassBoostTypeUUID,
+             aidl::android::hardware::audio::effect::kEqualizerTypeUUID,
+             aidl::android::hardware::audio::effect::kEnvReverbTypeUUID,
+             aidl::android::hardware::audio::effect::kPresetReverbTypeUUID,
+             aidl::android::hardware::audio::effect::kDynamicsProcessingTypeUUID,
+             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);
+    }
+    std::string msg = " missing type UUID:\n";
+    for (const auto& uuid : typeUuidSet) {
+        msg += (uuid.toString() + "\n");
+    }
+    SCOPED_TRACE(msg);
+    EXPECT_EQ(0UL, typeUuidSet.size());
+}
+
+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);
+}
+
+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);
+}
+
+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);
+}
+
+// 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<std::shared_ptr<IEffect>> effects;
+    effects = createWithIds(ids);
+    EXPECT_EQ(ids.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<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());
+
+    destroyEffects(effects);
+    destroyEffects(effects2);
+    destroyEffects(effects3);
+}
+
+// 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);
+
+    creatAndDestroyIds(ids);
+}
+
+// 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);
+
+    creatAndDestroyIds(ids);
+    creatAndDestroyIds(ids);
+    creatAndDestroyIds(ids);
+}
+
+// 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);
+    EXPECT_EQ(effects.size(), 0UL);
+}
+
+// Expect EX_ILLEGAL_ARGUMENT when destroy null interface.
+TEST_P(EffectFactoryTest, DestroyWithInvalidInterface) {
+    std::shared_ptr<IEffect> spDummyEffect(nullptr);
+    destroyEffects({spDummyEffect}, EX_ILLEGAL_ARGUMENT);
+}
+
+// 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);
+
+    mFactoryHelper->RestartFactoryService();
+
+    connectAndGetFactory();
+    creatAndDestroyIds(ids);
+}
+
+// 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);
+
+    ASSERT_NO_FATAL_FAILURE(mFactoryHelper->RestartFactoryService());
+
+    connectAndGetFactory();
+    destroyEffects(effects, EX_ILLEGAL_ARGUMENT);
+}
+
+// expect no error with the queryProcessing interface, but don't check number of processing
+TEST_P(EffectFactoryTest, QueryProcess) {
+    std::vector<Processing> processing;
+    EXPECT_IS_OK(mEffectFactory->queryProcessing(std::nullopt, &processing));
+
+    Processing::Type streamType =
+            Processing::Type::make<Processing::Type::streamType>(AudioStreamType::SYSTEM);
+    std::vector<Processing> processingFilteredByStream;
+    EXPECT_IS_OK(mEffectFactory->queryProcessing(streamType, &processingFilteredByStream));
+
+    Processing::Type source =
+            Processing::Type::make<Processing::Type::source>(AudioSource::DEFAULT);
+    std::vector<Processing> processingFilteredBySource;
+    EXPECT_IS_OK(mEffectFactory->queryProcessing(source, &processingFilteredBySource));
+
+    EXPECT_TRUE(processing.size() >= processingFilteredByStream.size());
+    EXPECT_TRUE(processing.size() >= processingFilteredBySource.size());
+}
+
+INSTANTIATE_TEST_SUITE_P(EffectFactoryTest, EffectFactoryTest,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(IFactory::descriptor)),
+                         android::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EffectFactoryTest);
+
+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/VtsHalAudioEffectTargetTest.cpp b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
index 8b5eb13..8212149 100644
--- a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
@@ -14,303 +14,763 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "VtsHalAudioEffectTargetTest"
+
+#include <chrono>
 #include <memory>
 #include <string>
-#include <unordered_map>
-#include <unordered_set>
 #include <vector>
 
-#define LOG_TAG "VtsHalAudioEffect"
-
+#include <Utils.h>
 #include <aidl/Gtest.h>
 #include <aidl/Vintf.h>
+#include <aidl/android/hardware/audio/effect/IEffect.h>
+#include <aidl/android/hardware/audio/effect/IFactory.h>
 #include <android-base/logging.h>
-#include <android-base/properties.h>
 #include <android/binder_interface_utils.h>
 #include <android/binder_manager.h>
 #include <android/binder_process.h>
-
-#include <aidl/android/hardware/audio/effect/IFactory.h>
+#include <fmq/AidlMessageQueue.h>
 
 #include "AudioHalBinderServiceUtil.h"
+#include "EffectFactoryHelper.h"
+#include "EffectHelper.h"
 #include "TestUtils.h"
 
 using namespace android;
 
 using ndk::ScopedAStatus;
 
+using aidl::android::hardware::audio::effect::CommandId;
 using aidl::android::hardware::audio::effect::Descriptor;
 using aidl::android::hardware::audio::effect::IEffect;
 using aidl::android::hardware::audio::effect::IFactory;
-using aidl::android::media::audio::common::AudioUuid;
+using aidl::android::hardware::audio::effect::Parameter;
+using aidl::android::hardware::audio::effect::State;
 
-class EffectFactoryHelper {
+enum ParamName { PARAM_INSTANCE_NAME };
+using EffectTestParam = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor::Identity>>;
+
+class AudioEffectTest : public testing::TestWithParam<EffectTestParam>, public EffectHelper {
   public:
-    explicit EffectFactoryHelper(const std::string& name) : mServiceName(name) {}
+    AudioEffectTest() { std::tie(mFactory, mIdentity) = std::get<PARAM_INSTANCE_NAME>(GetParam()); }
 
-    void ConnectToFactoryService() {
-        mEffectFactory = IFactory::fromBinder(binderUtil.connectToService(mServiceName));
-        ASSERT_NE(mEffectFactory, nullptr);
-    }
+    void SetUp() override {}
+    void TearDown() override {}
 
-    void RestartFactoryService() {
-        ASSERT_NE(mEffectFactory, nullptr);
-        mEffectFactory = IFactory::fromBinder(binderUtil.restartService());
-        ASSERT_NE(mEffectFactory, nullptr);
-    }
-
-    void QueryAllEffects() {
-        EXPECT_NE(mEffectFactory, nullptr);
-        EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, &mCompleteIds));
-    }
-
-    void QueryEffects(const std::optional<AudioUuid>& in_type,
-                      const std::optional<AudioUuid>& in_instance,
-                      std::vector<Descriptor::Identity>* _aidl_return) {
-        EXPECT_NE(mEffectFactory, nullptr);
-        EXPECT_IS_OK(mEffectFactory->queryEffects(in_type, in_instance, _aidl_return));
-        mIds = *_aidl_return;
-    }
-
-    void CreateEffects() {
-        EXPECT_NE(mEffectFactory, nullptr);
-        for (const auto& id : mIds) {
-            std::shared_ptr<IEffect> effect;
-            EXPECT_IS_OK(mEffectFactory->createEffect(id.uuid, &effect));
-            EXPECT_NE(effect, nullptr) << id.toString();
-            mEffectIdMap[effect] = id;
-        }
-    }
-
-    void DestroyEffects() {
-        EXPECT_NE(mEffectFactory, nullptr);
-        for (const auto& it : mEffectIdMap) {
-            EXPECT_IS_OK(mEffectFactory->destroyEffect(it.first));
-        }
-        mEffectIdMap.clear();
-    }
-
-    std::shared_ptr<IFactory> GetFactory() { return mEffectFactory; }
-    const std::vector<Descriptor::Identity>& GetEffectIds() { return mIds; }
-    const std::vector<Descriptor::Identity>& GetCompleteEffectIdList() { return mCompleteIds; }
-    const std::unordered_map<std::shared_ptr<IEffect>, Descriptor::Identity>& GetEffectMap() {
-        return mEffectIdMap;
-    }
-
-  private:
-    std::shared_ptr<IFactory> mEffectFactory;
-    std::string mServiceName;
-    AudioHalBinderServiceUtil binderUtil;
-    std::vector<Descriptor::Identity> mIds;
-    std::vector<Descriptor::Identity> mCompleteIds;
-    std::unordered_map<std::shared_ptr<IEffect>, Descriptor::Identity> mEffectIdMap;
+    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+    std::shared_ptr<IFactory> mFactory;
+    Descriptor::Identity mIdentity;
 };
 
-/// Effect factory testing.
-class EffectFactoryTest : public testing::TestWithParam<std::string> {
-  public:
-    void SetUp() override { ASSERT_NO_FATAL_FAILURE(mFactory.ConnectToFactoryService()); }
-
-    void TearDown() override { mFactory.DestroyEffects(); }
-
-    EffectFactoryHelper mFactory = EffectFactoryHelper(GetParam());
-
-    // TODO: these UUID can get from config file
-    // ec7178ec-e5e1-4432-a3f4-4657e6795210
-    const AudioUuid nullUuid = {static_cast<int32_t>(0xec7178ec),
-                                0xe5e1,
-                                0x4432,
-                                0xa3f4,
-                                {0x46, 0x57, 0xe6, 0x79, 0x52, 0x10}};
-    const AudioUuid zeroUuid = {
-            static_cast<int32_t>(0x0), 0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
-};
-
-TEST_P(EffectFactoryTest, SetupAndTearDown) {
+TEST_P(AudioEffectTest, SetupAndTearDown) {
     // Intentionally empty test body.
 }
 
-TEST_P(EffectFactoryTest, CanBeRestarted) {
-    ASSERT_NO_FATAL_FAILURE(mFactory.RestartFactoryService());
+TEST_P(AudioEffectTest, CreateAndDestroy) {
+    std::shared_ptr<IEffect> effect;
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
 }
 
-TEST_P(EffectFactoryTest, QueriedDescriptorList) {
-    std::vector<Descriptor::Identity> descriptors;
-    mFactory.QueryEffects(std::nullopt, std::nullopt, &descriptors);
-    EXPECT_NE(descriptors.size(), 0UL);
+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));
 }
 
-TEST_P(EffectFactoryTest, DescriptorUUIDNotNull) {
-    std::vector<Descriptor::Identity> descriptors;
-    mFactory.QueryEffects(std::nullopt, std::nullopt, &descriptors);
-    // TODO: Factory eventually need to return the full list of MUST supported AOSP effects.
-    for (auto& desc : descriptors) {
-        EXPECT_NE(desc.type, zeroUuid);
-        EXPECT_NE(desc.uuid, zeroUuid);
-    }
+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));
 }
 
-TEST_P(EffectFactoryTest, QueriedDescriptorNotExistType) {
-    std::vector<Descriptor::Identity> descriptors;
-    mFactory.QueryEffects(nullUuid, std::nullopt, &descriptors);
-    EXPECT_EQ(descriptors.size(), 0UL);
+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(open(effect1));
+    ASSERT_NO_FATAL_FAILURE(open(effect2, 1 /* session */));
+    ASSERT_NO_FATAL_FAILURE(close(effect1));
+    ASSERT_NO_FATAL_FAILURE(close(effect2));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect1));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect2));
 }
 
-TEST_P(EffectFactoryTest, QueriedDescriptorNotExistInstance) {
-    std::vector<Descriptor::Identity> descriptors;
-    mFactory.QueryEffects(std::nullopt, nullUuid, &descriptors);
-    EXPECT_EQ(descriptors.size(), 0UL);
+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(open(effect1));
+    ASSERT_NO_FATAL_FAILURE(open(effect2, 1 /* session */));
+    ASSERT_NO_FATAL_FAILURE(open(effect3, 2 /* session */));
+    ASSERT_NO_FATAL_FAILURE(close(effect1));
+    ASSERT_NO_FATAL_FAILURE(close(effect2));
+    ASSERT_NO_FATAL_FAILURE(close(effect3));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect1));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect2));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect3));
 }
 
-TEST_P(EffectFactoryTest, CreateAndDestroyRepeat) {
-    std::vector<Descriptor::Identity> descriptors;
-    mFactory.QueryEffects(std::nullopt, std::nullopt, &descriptors);
-    auto numIds = mFactory.GetEffectIds().size();
-    EXPECT_NE(numIds, 0UL);
-
-    EXPECT_EQ(mFactory.GetEffectMap().size(), 0UL);
-    mFactory.CreateEffects();
-    EXPECT_EQ(mFactory.GetEffectMap().size(), numIds);
-    mFactory.DestroyEffects();
-    EXPECT_EQ(mFactory.GetEffectMap().size(), 0UL);
-
-    // Create and destroy again
-    mFactory.CreateEffects();
-    EXPECT_EQ(mFactory.GetEffectMap().size(), numIds);
-    mFactory.DestroyEffects();
-    EXPECT_EQ(mFactory.GetEffectMap().size(), 0UL);
+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());
+    EXPECT_NE("", desc.common.name);
+    EXPECT_NE("", desc.common.implementor);
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
 }
 
-TEST_P(EffectFactoryTest, CreateMultipleInstanceOfSameEffect) {
-    std::vector<Descriptor::Identity> descriptors;
-    mFactory.QueryEffects(std::nullopt, std::nullopt, &descriptors);
-    auto numIds = mFactory.GetEffectIds().size();
-    EXPECT_NE(numIds, 0UL);
-
-    EXPECT_EQ(mFactory.GetEffectMap().size(), 0UL);
-    mFactory.CreateEffects();
-    EXPECT_EQ(mFactory.GetEffectMap().size(), numIds);
-    // Create effect instances of same implementation
-    mFactory.CreateEffects();
-    EXPECT_EQ(mFactory.GetEffectMap().size(), 2 * numIds);
-
-    mFactory.CreateEffects();
-    EXPECT_EQ(mFactory.GetEffectMap().size(), 3 * numIds);
-
-    mFactory.DestroyEffects();
-    EXPECT_EQ(mFactory.GetEffectMap().size(), 0UL);
+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));
+    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));
+    EXPECT_EQ(beforeOpen.toString(), afterClose.toString()) << "\n"
+                                                            << beforeOpen.toString() << "\n"
+                                                            << afterClose.toString();
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
 }
 
-INSTANTIATE_TEST_SUITE_P(EffectFactoryTest, EffectFactoryTest,
-                         testing::ValuesIn(android::getAidlHalInstanceNames(IFactory::descriptor)),
-                         android::PrintInstanceNameToString);
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EffectFactoryTest);
+TEST_P(AudioEffectTest, DescriptorExistAndUnique) {
+    std::shared_ptr<IEffect> effect;
+    Descriptor desc;
 
-/// Effect testing.
-class AudioEffect : public testing::TestWithParam<std::string> {
-  public:
-    void SetUp() override {
-        ASSERT_NO_FATAL_FAILURE(mFactory.ConnectToFactoryService());
-        ASSERT_NO_FATAL_FAILURE(mFactory.CreateEffects());
+    auto descList = EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor);
+    std::set<Descriptor::Identity> idSet;
+    for (const auto& it : descList) {
+        auto& id = it.second;
+        EXPECT_EQ(0ul, idSet.count(id));
+        idSet.insert(id);
     }
 
-    void TearDown() override {
-        CloseEffects();
-        ASSERT_NO_FATAL_FAILURE(mFactory.DestroyEffects());
-    }
-
-    void OpenEffects() {
-        auto open = [](const std::shared_ptr<IEffect>& effect) { EXPECT_IS_OK(effect->open()); };
-        EXPECT_NO_FATAL_FAILURE(ForEachEffect(open));
-    }
-
-    void CloseEffects() {
-        auto close = [](const std::shared_ptr<IEffect>& effect) { EXPECT_IS_OK(effect->close()); };
-        EXPECT_NO_FATAL_FAILURE(ForEachEffect(close));
-    }
-
-    void GetEffectDescriptors() {
-        auto get = [](const std::shared_ptr<IEffect>& effect) {
-            Descriptor desc;
-            EXPECT_IS_OK(effect->getDescriptor(&desc));
-        };
-        EXPECT_NO_FATAL_FAILURE(ForEachEffect(get));
-    }
-
-    template <typename Functor>
-    void ForEachEffect(Functor functor) {
-        auto effectMap = mFactory.GetEffectMap();
-        for (const auto& it : effectMap) {
-            SCOPED_TRACE(it.second.toString());
-            functor(it.first);
-        }
-    }
-
-    EffectFactoryHelper mFactory = EffectFactoryHelper(GetParam());
-};
-
-TEST_P(AudioEffect, OpenEffectTest) {
-    EXPECT_NO_FATAL_FAILURE(OpenEffects());
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(getDescriptor(effect, desc));
+    EXPECT_EQ(1ul, idSet.count(desc.common.id));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
 }
 
-TEST_P(AudioEffect, OpenAndCloseEffect) {
-    EXPECT_NO_FATAL_FAILURE(OpenEffects());
-    EXPECT_NO_FATAL_FAILURE(CloseEffects());
+/// 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));
 }
 
-TEST_P(AudioEffect, CloseUnopenedEffectTest) {
-    EXPECT_NO_FATAL_FAILURE(CloseEffects());
+// 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));
 }
 
-TEST_P(AudioEffect, DoubleOpenCloseEffects) {
-    EXPECT_NO_FATAL_FAILURE(OpenEffects());
-    EXPECT_NO_FATAL_FAILURE(CloseEffects());
-    EXPECT_NO_FATAL_FAILURE(OpenEffects());
-    EXPECT_NO_FATAL_FAILURE(CloseEffects());
-
-    EXPECT_NO_FATAL_FAILURE(OpenEffects());
-    EXPECT_NO_FATAL_FAILURE(OpenEffects());
-    EXPECT_NO_FATAL_FAILURE(CloseEffects());
-
-    EXPECT_NO_FATAL_FAILURE(OpenEffects());
-    EXPECT_NO_FATAL_FAILURE(CloseEffects());
-    EXPECT_NO_FATAL_FAILURE(CloseEffects());
+// 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));
 }
 
-TEST_P(AudioEffect, GetDescriptors) {
-    EXPECT_NO_FATAL_FAILURE(GetEffectDescriptors());
+// 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));
 }
 
-TEST_P(AudioEffect, DescriptorIdExistAndUnique) {
-    auto checker = [&](const std::shared_ptr<IEffect>& effect) {
-        Descriptor desc;
-        std::vector<Descriptor::Identity> idList;
-        EXPECT_IS_OK(effect->getDescriptor(&desc));
-        mFactory.QueryEffects(desc.common.id.type, desc.common.id.uuid, &idList);
-        EXPECT_EQ(idList.size(), 1UL);
-    };
-    EXPECT_NO_FATAL_FAILURE(ForEachEffect(checker));
-
-    // Check unique with a set
-    auto stringHash = [](const Descriptor::Identity& id) {
-        return std::hash<std::string>()(id.toString());
-    };
-    auto vec = mFactory.GetCompleteEffectIdList();
-    std::unordered_set<Descriptor::Identity, decltype(stringHash)> idSet(0, stringHash);
-    for (auto it : vec) {
-        EXPECT_EQ(idSet.count(it), 0UL);
-        idSet.insert(it);
-    }
+// 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));
 }
 
-INSTANTIATE_TEST_SUITE_P(AudioEffectTest, AudioEffect,
-                         testing::ValuesIn(android::getAidlHalInstanceNames(IFactory::descriptor)),
-                         android::PrintInstanceNameToString);
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioEffect);
+// 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));
+}
+
+// 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));
+}
+
+// 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));
+}
+
+// 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));
+}
+
+// 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(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));
+}
+
+// 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(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));
+}
+
+// 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(close(effect, 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));
+}
+
+// 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(destroy(mFactory, effect, EX_ILLEGAL_STATE));
+}
+
+// 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(destroy(mFactory, effect, EX_ILLEGAL_STATE));
+}
+
+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));
+}
+
+/// 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));
+
+    Parameter::Common common = EffectHelper::createParamCommon();
+    IEffect::OpenEffectReturn ret;
+    ASSERT_NO_FATAL_FAILURE(open(effect, 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_EQ(expect, get) << expect.toString() << " vs " << get.toString();
+
+    ASSERT_NO_FATAL_FAILURE(close(effect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+// 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));
+
+    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));
+
+    Parameter::Id id;
+    id.set<Parameter::Id::commonTag>(Parameter::common);
+    EXPECT_IS_OK(effect->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));
+}
+
+// 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));
+
+    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));
+
+    Parameter::Id id;
+    id.set<Parameter::Id::commonTag>(Parameter::common);
+    EXPECT_IS_OK(effect->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));
+}
+
+// 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));
+
+    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));
+
+    Parameter::Id id;
+    id.set<Parameter::Id::commonTag>(Parameter::common);
+    EXPECT_IS_OK(effect->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));
+}
+
+// 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));
+
+    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));
+
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+
+    Parameter::Id id;
+    id.set<Parameter::Id::commonTag>(Parameter::common);
+    EXPECT_IS_OK(effect->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));
+}
+
+// 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(command(effect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, 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));
+
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+
+    Parameter::Id id;
+    id.set<Parameter::Id::commonTag>(Parameter::common);
+    EXPECT_IS_OK(effect->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));
+}
+
+/// 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));
+
+    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));
+    auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
+    auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+    auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+
+    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect, 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(close(effect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+// 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));
+
+    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));
+    auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
+    auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+    auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+
+    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));
+
+    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(close(effect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+// 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));
+
+    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));
+    auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
+    auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+    auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+
+    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));
+
+    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(close(effect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+// Send data multiple times.
+TEST_P(AudioEffectTest, ProcessDataMultipleTimes) {
+    std::shared_ptr<IEffect> effect;
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+
+    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));
+    auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
+    auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+    auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+
+    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));
+
+    EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer);
+    // expect no status and data after consume
+    EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer);
+
+    EffectHelper::writeToFmq(inputMQ, buffer);
+    EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer);
+    // 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(close(effect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+// 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));
+
+    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));
+    auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
+    auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+    auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+
+    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));
+
+    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));
+    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(close(effect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+// 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));
+
+    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));
+
+    auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
+    auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+    auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+
+    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));
+}
+
+// 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));
+
+    Parameter::Common common1 = EffectHelper::createParamCommon(
+            0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+            kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+    Parameter::Common common2 = EffectHelper::createParamCommon(
+            1 /* session */, 1 /* ioHandle */, 48000 /* iSampleRate */, 48000 /* oSampleRate */,
+            2 * kInputFrameCount /* iFrameCount */, 2 * kOutputFrameCount /* oFrameCount */);
+    IEffect::OpenEffectReturn ret1, ret2;
+    ASSERT_NO_FATAL_FAILURE(open(effect1, common1, std::nullopt /* specific */, &ret1, EX_NONE));
+    ASSERT_NO_FATAL_FAILURE(open(effect2, common2, std::nullopt /* specific */, &ret2, EX_NONE));
+    ASSERT_NO_FATAL_FAILURE(command(effect1, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect1, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(effect2, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect2, State::PROCESSING));
+
+    auto statusMQ1 = std::make_unique<EffectHelper::StatusMQ>(ret1.statusMQ);
+    auto inputMQ1 = std::make_unique<EffectHelper::DataMQ>(ret1.inputDataMQ);
+    auto outputMQ1 = std::make_unique<EffectHelper::DataMQ>(ret1.outputDataMQ);
+
+    std::vector<float> buffer1, buffer2;
+    EffectHelper::allocateInputData(common1, inputMQ1, buffer1);
+    EffectHelper::writeToFmq(inputMQ1, buffer1);
+    EffectHelper::readFromFmq(statusMQ1, 1, outputMQ1, buffer1.size(), buffer1);
+
+    auto statusMQ2 = std::make_unique<EffectHelper::StatusMQ>(ret2.statusMQ);
+    auto inputMQ2 = std::make_unique<EffectHelper::DataMQ>(ret2.inputDataMQ);
+    auto outputMQ2 = std::make_unique<EffectHelper::DataMQ>(ret2.outputDataMQ);
+    EffectHelper::allocateInputData(common2, inputMQ2, buffer2);
+    EffectHelper::writeToFmq(inputMQ2, buffer2);
+    EffectHelper::readFromFmq(statusMQ2, 1, outputMQ2, buffer2.size(), buffer2);
+
+    ASSERT_NO_FATAL_FAILURE(command(effect1, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect1, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(close(effect1));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect1));
+
+    ASSERT_NO_FATAL_FAILURE(command(effect2, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(effect2, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(close(effect2));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect2));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        SingleEffectInstanceTest, AudioEffectTest,
+        ::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);
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioEffectTest);
 
 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/VtsHalEqualizerTargetTest.cpp b/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp
new file mode 100644
index 0000000..f19dff6
--- /dev/null
+++ b/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <limits>
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#define LOG_TAG "VtsHalEqualizerTest"
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android/binder_interface_utils.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <gtest/gtest.h>
+
+#include <Utils.h>
+#include <aidl/android/hardware/audio/effect/IEffect.h>
+#include <aidl/android/hardware/audio/effect/IFactory.h>
+
+#include "AudioHalBinderServiceUtil.h"
+#include "EffectHelper.h"
+#include "TestUtils.h"
+#include "effect-impl/EffectUUID.h"
+
+using namespace android;
+
+using aidl::android::hardware::audio::effect::Capability;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::Equalizer;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::kEqualizerTypeUUID;
+using aidl::android::hardware::audio::effect::Parameter;
+
+/**
+ * Here we focus on specific effect (equalizer) parameter checking, general IEffect interfaces
+ * testing performed in VtsAudioEfectTargetTest.
+ */
+
+enum ParamName { PARAM_INSTANCE_NAME, PARAM_BAND_LEVEL };
+using EqualizerParamTestParam =
+        std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor::Identity>, int>;
+
+/*
+Testing parameter range, assuming the parameter supported by effect is in this range.
+This range is verified with IEffect.getDescriptor(), for any index supported vts expect EX_NONE
+from IEffect.setParameter(), otherwise expect EX_ILLEGAL_ARGUMENT.
+*/
+const std::vector<int> kBandLevels = {0, -10, 10};  // needs update with implementation
+
+class EqualizerTest : public ::testing::TestWithParam<EqualizerParamTestParam>,
+                      public EffectHelper {
+  public:
+    EqualizerTest() : mBandLevel(std::get<PARAM_BAND_LEVEL>(GetParam())) {
+        std::tie(mFactory, mIdentity) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+    }
+
+    void SetUp() override {
+        ASSERT_NE(nullptr, mFactory);
+        ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mIdentity));
+
+        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);
+        ASSERT_NO_FATAL_FAILURE(setTagRange());
+    }
+    void TearDown() override {
+        ASSERT_NO_FATAL_FAILURE(close(mEffect));
+        ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+    }
+
+    std::pair<int, int> setPresetIndexRange(const Equalizer::Capability& cap) const {
+        const auto [min, max] =
+                std::minmax_element(cap.presets.begin(), cap.presets.end(),
+                                    [](const auto& a, const auto& b) { return a.index < b.index; });
+        return {min->index, max->index};
+    }
+    std::pair<int, int> setBandIndexRange(const Equalizer::Capability& cap) const {
+        const auto [min, max] =
+                std::minmax_element(cap.bandFrequencies.begin(), cap.bandFrequencies.end(),
+                                    [](const auto& a, const auto& b) { return a.index < b.index; });
+        return {min->index, max->index};
+    }
+    void setTagRange() {
+        Descriptor desc;
+        ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
+        Equalizer::Capability& eqCap = desc.capability.get<Capability::equalizer>();
+        mPresetIndex = setPresetIndexRange(eqCap);
+        mBandIndex = setBandIndexRange(eqCap);
+    }
+
+    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+    std::shared_ptr<IFactory> mFactory;
+    std::shared_ptr<IEffect> mEffect;
+    Descriptor::Identity mIdentity;
+    std::pair<int, int> mPresetIndex;
+    std::pair<int, int> mBandIndex;
+    const int mBandLevel;
+    Descriptor mDesc;
+
+    void SetAndGetEqualizerParameters() {
+        ASSERT_NE(nullptr, mEffect);
+        for (auto& it : mTags) {
+            auto& tag = it.first;
+            auto& eq = it.second;
+
+            // validate parameter
+            const bool valid = isTagInRange(it.first, it.second);
+            const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
+
+            // set
+            Parameter expectParam;
+            Parameter::Specific specific;
+            specific.set<Parameter::Specific::equalizer>(eq);
+            expectParam.set<Parameter::specific>(specific);
+            EXPECT_STATUS(expected, mEffect->setParameter(expectParam))
+                    << expectParam.toString() << "\n"
+                    << mDesc.toString();
+
+            // only get if parameter in range and set success
+            if (expected == EX_NONE) {
+                Parameter getParam;
+                Parameter::Id id;
+                Equalizer::Id eqId;
+                eqId.set<Equalizer::Id::commonTag>(tag);
+                id.set<Parameter::Id::equalizerTag>(eqId);
+                // if set success, then get should match
+                EXPECT_STATUS(expected, mEffect->getParameter(id, &getParam));
+                EXPECT_TRUE(isEqParameterExpected(expectParam, getParam))
+                        << "\nexpect:" << expectParam.toString()
+                        << "\ngetParam:" << getParam.toString();
+            }
+        }
+    }
+
+    bool isEqParameterExpected(const Parameter& expect, const Parameter& target) {
+        // if parameter same, then for sure they are matched
+        if (expect == target) return true;
+
+        // if not, see if target include the expect parameter, and others all default (0).
+        /*
+         * This is to verify the case of client setParameter to a single bandLevel ({3, -1} for
+         * example), and return of getParameter must be [{0, 0}, {1, 0}, {2, 0}, {3, -1}, {4, 0}]
+         */
+        EXPECT_EQ(expect.getTag(), Parameter::specific);
+        EXPECT_EQ(target.getTag(), Parameter::specific);
+
+        Parameter::Specific expectSpec = expect.get<Parameter::specific>(),
+                            targetSpec = target.get<Parameter::specific>();
+        EXPECT_EQ(expectSpec.getTag(), Parameter::Specific::equalizer);
+        EXPECT_EQ(targetSpec.getTag(), Parameter::Specific::equalizer);
+
+        Equalizer expectEq = expectSpec.get<Parameter::Specific::equalizer>(),
+                  targetEq = targetSpec.get<Parameter::Specific::equalizer>();
+        EXPECT_EQ(expectEq.getTag(), targetEq.getTag());
+
+        auto eqTag = targetEq.getTag();
+        switch (eqTag) {
+            case Equalizer::bandLevels: {
+                auto expectBl = expectEq.get<Equalizer::bandLevels>();
+                std::sort(expectBl.begin(), expectBl.end(),
+                          [](const auto& a, const auto& b) { return a.index < b.index; });
+                expectBl.erase(std::unique(expectBl.begin(), expectBl.end()), expectBl.end());
+                auto targetBl = targetEq.get<Equalizer::bandLevels>();
+                return std::includes(targetBl.begin(), targetBl.end(), expectBl.begin(),
+                                     expectBl.end());
+            }
+            case Equalizer::preset: {
+                return expectEq.get<Equalizer::preset>() == targetEq.get<Equalizer::preset>();
+            }
+            default:
+                return false;
+        }
+        return false;
+    }
+
+    void addPresetParam(int preset) {
+        Equalizer eq;
+        eq.set<Equalizer::preset>(preset);
+        mTags.push_back({Equalizer::preset, eq});
+    }
+
+    void addBandLevelsParam(std::vector<Equalizer::BandLevel>& bandLevels) {
+        Equalizer eq;
+        eq.set<Equalizer::bandLevels>(bandLevels);
+        mTags.push_back({Equalizer::bandLevels, eq});
+    }
+
+    bool isTagInRange(const Equalizer::Tag& tag, const Equalizer& eq) const {
+        switch (tag) {
+            case Equalizer::preset: {
+                int index = eq.get<Equalizer::preset>();
+                return index >= mPresetIndex.first && index <= mPresetIndex.second;
+            }
+            case Equalizer::bandLevels: {
+                auto& bandLevel = eq.get<Equalizer::bandLevels>();
+                return isBandInRange(bandLevel);
+            }
+            default:
+                return false;
+        }
+        return false;
+    }
+
+    bool isBandInRange(const std::vector<Equalizer::BandLevel>& bandLevel) const {
+        for (auto& it : bandLevel) {
+            if (it.index < mBandIndex.first || it.index > mBandIndex.second) return false;
+        }
+        return true;
+    }
+
+    Parameter::Specific getDefaultParamSpecific() {
+        Equalizer eq = Equalizer::make<Equalizer::preset>(0);
+        Parameter::Specific specific =
+                Parameter::Specific::make<Parameter::Specific::equalizer>(eq);
+        return specific;
+    }
+
+  private:
+    std::vector<std::pair<Equalizer::Tag, Equalizer>> mTags;
+
+    bool validCapabilityTag(Capability& cap) { return cap.getTag() == Capability::equalizer; }
+
+    void CleanUp() { mTags.clear(); }
+};
+
+TEST_P(EqualizerTest, SetAndGetPresetOutOfLowerBound) {
+    addPresetParam(mPresetIndex.second - 1);
+    ASSERT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
+}
+
+TEST_P(EqualizerTest, SetAndGetPresetOutOfUpperBound) {
+    addPresetParam(mPresetIndex.second + 1);
+    EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
+}
+
+TEST_P(EqualizerTest, SetAndGetPresetAtLowerBound) {
+    addPresetParam(mPresetIndex.first);
+    EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
+}
+
+TEST_P(EqualizerTest, SetAndGetPresetAtHigherBound) {
+    addPresetParam(mPresetIndex.second);
+    EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
+}
+
+TEST_P(EqualizerTest, SetAndGetPresetInBound) {
+    addPresetParam((mPresetIndex.first + mPresetIndex.second) >> 1);
+    EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
+}
+
+TEST_P(EqualizerTest, SetAndGetBandOutOfLowerBound) {
+    std::vector<Equalizer::BandLevel> bandLevels{{mBandIndex.first - 1, mBandLevel}};
+    addBandLevelsParam(bandLevels);
+    EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
+}
+
+TEST_P(EqualizerTest, SetAndGetBandOutOfUpperBound) {
+    std::vector<Equalizer::BandLevel> bandLevels{{mBandIndex.second + 1, mBandLevel}};
+    addBandLevelsParam(bandLevels);
+    EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
+}
+
+TEST_P(EqualizerTest, SetAndGetBandAtLowerBound) {
+    std::vector<Equalizer::BandLevel> bandLevels{{mBandIndex.first, mBandLevel}};
+    addBandLevelsParam(bandLevels);
+    EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
+}
+
+TEST_P(EqualizerTest, SetAndGetBandAtHigherBound) {
+    std::vector<Equalizer::BandLevel> bandLevels{{mBandIndex.second, mBandLevel}};
+    addBandLevelsParam(bandLevels);
+    EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
+}
+
+TEST_P(EqualizerTest, SetAndGetBandInBound) {
+    std::vector<Equalizer::BandLevel> bandLevels{
+            {(mBandIndex.first + mBandIndex.second) >> 1, mBandLevel}};
+    addBandLevelsParam(bandLevels);
+    EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
+}
+
+TEST_P(EqualizerTest, SetAndGetMultiBands) {
+    addPresetParam(mPresetIndex.first);
+    std::vector<Equalizer::BandLevel> bandLevels{
+            {mBandIndex.first, mBandLevel},
+            {mBandIndex.second, mBandLevel},
+            {(mBandIndex.first + mBandIndex.second) >> 1, mBandLevel}};
+    addBandLevelsParam(bandLevels);
+    EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
+}
+
+TEST_P(EqualizerTest, SetAndGetMultipleParams) {
+    std::vector<Equalizer::BandLevel> bandLevels{
+            {(mBandIndex.first + mBandIndex.second) >> 1, mBandLevel}};
+    addBandLevelsParam(bandLevels);
+    addPresetParam((mPresetIndex.first + mPresetIndex.second) >> 1);
+    EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        EqualizerTest, EqualizerTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   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);
+            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::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EqualizerTest);
+
+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
new file mode 100644
index 0000000..1485657
--- /dev/null
+++ b/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "VtsHalLoudnessEnhancerTest"
+
+#include <Utils.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::kLoudnessEnhancerTypeUUID;
+using aidl::android::hardware::audio::effect::LoudnessEnhancer;
+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_GAIN_MB };
+using LoudnessEnhancerParamTestParam =
+        std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor::Identity>, 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.
+const std::vector<int> kGainMbValues = {std::numeric_limits<int>::min(), 100,
+                                        std::numeric_limits<int>::max()};
+
+class LoudnessEnhancerParamTest : public ::testing::TestWithParam<LoudnessEnhancerParamTestParam>,
+                                  public EffectHelper {
+  public:
+    LoudnessEnhancerParamTest() : mParamGainMb(std::get<PARAM_GAIN_MB>(GetParam())) {
+        std::tie(mFactory, mIdentity) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+    }
+
+    void SetUp() override {
+        ASSERT_NE(nullptr, mFactory);
+        ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mIdentity));
+
+        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() {
+        LoudnessEnhancer le = LoudnessEnhancer::make<LoudnessEnhancer::gainMb>(0);
+        Parameter::Specific specific =
+                Parameter::Specific::make<Parameter::Specific::loudnessEnhancer>(le);
+        return specific;
+    }
+
+    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+    std::shared_ptr<IFactory> mFactory;
+    std::shared_ptr<IEffect> mEffect;
+    Descriptor::Identity mIdentity;
+    int mParamGainMb = 0;
+
+    void SetAndGetParameters() {
+        for (auto& it : mTags) {
+            auto& tag = it.first;
+            auto& le = it.second;
+
+            // set parameter
+            Parameter expectParam;
+            Parameter::Specific specific;
+            specific.set<Parameter::Specific::loudnessEnhancer>(le);
+            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;
+            LoudnessEnhancer::Id leId;
+            leId.set<LoudnessEnhancer::Id::commonTag>(tag);
+            id.set<Parameter::Id::loudnessEnhancerTag>(leId);
+            EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam));
+
+            EXPECT_EQ(expectParam, getParam) << "\nexpect:" << expectParam.toString()
+                                             << "\ngetParam:" << getParam.toString();
+        }
+    }
+
+    void addGainMbParam(int gainMb) {
+        LoudnessEnhancer le;
+        le.set<LoudnessEnhancer::gainMb>(gainMb);
+        mTags.push_back({LoudnessEnhancer::gainMb, le});
+    }
+
+  private:
+    std::vector<std::pair<LoudnessEnhancer::Tag, LoudnessEnhancer>> mTags;
+    void CleanUp() { mTags.clear(); }
+};
+
+TEST_P(LoudnessEnhancerParamTest, SetAndGetGainMb) {
+    EXPECT_NO_FATAL_FAILURE(addGainMbParam(mParamGainMb));
+    SetAndGetParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        LoudnessEnhancerTest, LoudnessEnhancerParamTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   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);
+            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::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(LoudnessEnhancerParamTest);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
index e46e5b4..98e49a2 100644
--- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
+++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
@@ -1014,9 +1014,8 @@
         if (mDataPosition == 0) mOnDataStart();
         const size_t dataSize = std::min(mData.size() - mDataPosition, mDataMQ->availableToWrite());
         bool success = mDataMQ->write(mData.data() + mDataPosition, dataSize);
+        bool wrapped = false;
         ALOGE_IF(!success, "data message queue write failed");
-        mDataPosition += dataSize;
-        if (mDataPosition >= mData.size()) mDataPosition = 0;
         mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
 
         uint32_t efState = 0;
@@ -1034,6 +1033,11 @@
                 ALOGE("bad write status: %d", writeStatus.retval);
                 success = false;
             }
+            mDataPosition += writeStatus.reply.written;
+            if (mDataPosition >= mData.size()) {
+                mDataPosition = 0;
+                wrapped = true;
+            }
         }
         if (ret == -EAGAIN || ret == -EINTR) {
             // Spurious wakeup. This normally retries no more than once.
@@ -1042,7 +1046,7 @@
             ALOGE("bad wait status: %d", ret);
             success = false;
         }
-        if (success && mDataPosition == 0) {
+        if (wrapped) {
             success = mOnDataWrap();
         }
         return success;
@@ -1270,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/effect/all-versions/default/Effect.cpp b/audio/effect/all-versions/default/Effect.cpp
index b57dc63..5dc42dc 100644
--- a/audio/effect/all-versions/default/Effect.cpp
+++ b/audio/effect/all-versions/default/Effect.cpp
@@ -700,8 +700,21 @@
 
     void* dataPtr = halDataSize > 0 ? &halData[0] : NULL;
     void* resultPtr = halResultSize > 0 ? &halResult[0] : NULL;
-    status_t status =
-        (*mHandle)->command(mHandle, commandId, halDataSize, dataPtr, &halResultSize, resultPtr);
+    status_t status = BAD_VALUE;
+    switch (commandId) {
+        case 'gtid':  // retrieve the tid, used for spatializer priority boost
+            if (halDataSize == 0 && resultMaxSize == sizeof(int32_t)) {
+                auto ptid = (int32_t*)resultPtr;
+                ptid[0] = mProcessThread ? mProcessThread->getTid() : -1;
+                status = OK;
+                break;  // we have handled 'gtid' here.
+            }
+            [[fallthrough]];  // allow 'gtid' overload (checked halDataSize and resultMaxSize).
+        default:
+            status = (*mHandle)->command(mHandle, commandId, halDataSize, dataPtr, &halResultSize,
+                                         resultPtr);
+            break;
+    }
     hidl_vec<uint8_t> result;
     if (status == OK && resultPtr != NULL) {
         result.setToExternal(&halResult[0], halResultSize);
diff --git a/automotive/evs/aidl/Android.bp b/automotive/evs/aidl/Android.bp
index 1c908aa..8aaa1ce 100644
--- a/automotive/evs/aidl/Android.bp
+++ b/automotive/evs/aidl/Android.bp
@@ -30,7 +30,7 @@
     stability: "vintf",
     imports: [
         "android.hardware.common-V2",
-        "android.hardware.graphics.common-V3",
+        "android.hardware.graphics.common-V4",
     ],
     backend: {
         java: {
@@ -53,7 +53,7 @@
             version: "1",
             imports: [
                 "android.hardware.common-V2",
-                "android.hardware.graphics.common-V3",
+                "android.hardware.graphics.common-V4",
             ],
         },
     ],
diff --git a/automotive/remoteaccess/hal/default/Android.bp b/automotive/remoteaccess/hal/default/Android.bp
new file mode 100644
index 0000000..a2bf86c
--- /dev/null
+++ b/automotive/remoteaccess/hal/default/Android.bp
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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_binary {
+    name: "android.hardware.automotive.remoteaccess@V1-default-service",
+    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: [
+        "RemoteAccessService",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "liblog",
+        "libutils",
+        "libgrpc++",
+        "libprotobuf-cpp-full",
+    ],
+    defaults: [
+        "vhalclient_defaults",
+    ],
+    cflags: [
+        "-Wno-unused-parameter",
+        "-DGRPC_SERVICE_ADDRESS=\"localhost:50051\"",
+    ],
+}
+
+cc_library {
+    name: "RemoteAccessService",
+    vendor_available: true,
+    local_include_dirs: ["include"],
+    export_include_dirs: ["include"],
+    srcs: [
+        "src/RemoteAccessService.cpp",
+    ],
+    whole_static_libs: [
+        "android.hardware.automotive.remoteaccess-V1-ndk",
+        "wakeup_client_protos",
+        "libvhalclient",
+    ],
+    defaults: [
+        "vhalclient_defaults",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "libcutils",
+        "liblog",
+        "libutils",
+        "libgrpc++",
+        "libprotobuf-cpp-full",
+    ],
+    cflags: [
+        "-Wno-unused-parameter",
+    ],
+}
+
+cc_fuzz {
+    name: "android.hardware.automotive.remoteaccess@V1-default-service.aidl_fuzzer",
+    srcs: ["fuzzer/fuzzer.cpp"],
+    whole_static_libs: [
+        "RemoteAccessService",
+    ],
+    static_libs: [
+        "libgtest",
+        "libgmock",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "liblog",
+        "libutils",
+        "libgrpc++",
+        "libprotobuf-cpp-full",
+    ],
+    defaults: [
+        "vhalclient_defaults",
+        "service_fuzzer_defaults",
+    ],
+    cflags: [
+        "-Wno-unused-parameter",
+        "-DGRPC_SERVICE_ADDRESS=\"localhost:50051\"",
+    ],
+    fuzz_config: {
+        cc: [
+            "shanyu@google.com",
+        ],
+    },
+}
diff --git a/automotive/remoteaccess/hal/default/fuzzer/fuzzer.cpp b/automotive/remoteaccess/hal/default/fuzzer/fuzzer.cpp
new file mode 100644
index 0000000..292c80e
--- /dev/null
+++ b/automotive/remoteaccess/hal/default/fuzzer/fuzzer.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <RemoteAccessService.h>
+#include <fuzzbinder/libbinder_ndk_driver.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <gmock/gmock.h>
+#include <grpcpp/test/mock_stream.h>
+#include <wakeup_client.grpc.pb.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace remoteaccess {
+
+using ::grpc::ClientAsyncReaderInterface;
+using ::grpc::ClientAsyncResponseReaderInterface;
+using ::grpc::ClientContext;
+using ::grpc::ClientReader;
+using ::grpc::ClientReaderInterface;
+using ::grpc::CompletionQueue;
+using ::grpc::Status;
+using ::grpc::testing::MockClientReader;
+using ::testing::_;
+using ::testing::Return;
+
+class MockGrpcClientStub : public WakeupClient::StubInterface {
+  public:
+    ClientReaderInterface<GetRemoteTasksResponse>* GetRemoteTasksRaw(
+            [[maybe_unused]] ClientContext* context,
+            [[maybe_unused]] const GetRemoteTasksRequest& request) override {
+        MockClientReader<GetRemoteTasksResponse>* mockClientReader =
+                new MockClientReader<GetRemoteTasksResponse>();
+        ON_CALL(*mockClientReader, Finish()).WillByDefault(Return(Status::OK));
+        ON_CALL(*mockClientReader, Read(_)).WillByDefault(Return(false));
+        return mockClientReader;
+    }
+
+    Status NotifyWakeupRequired([[maybe_unused]] ClientContext* context,
+                                [[maybe_unused]] const NotifyWakeupRequiredRequest& request,
+                                [[maybe_unused]] NotifyWakeupRequiredResponse* response) {
+        return Status::OK;
+    }
+
+    // Async methods which we do not care.
+    ClientAsyncReaderInterface<GetRemoteTasksResponse>* AsyncGetRemoteTasksRaw(
+            [[maybe_unused]] ClientContext* context,
+            [[maybe_unused]] const GetRemoteTasksRequest& request,
+            [[maybe_unused]] CompletionQueue* cq, [[maybe_unused]] void* tag) {
+        return nullptr;
+    }
+
+    ClientAsyncReaderInterface<GetRemoteTasksResponse>* PrepareAsyncGetRemoteTasksRaw(
+            [[maybe_unused]] ClientContext* context,
+            [[maybe_unused]] const GetRemoteTasksRequest& request,
+            [[maybe_unused]] CompletionQueue* cq) {
+        return nullptr;
+    }
+
+    ClientAsyncResponseReaderInterface<NotifyWakeupRequiredResponse>* AsyncNotifyWakeupRequiredRaw(
+            [[maybe_unused]] ClientContext* context,
+            [[maybe_unused]] const NotifyWakeupRequiredRequest& request,
+            [[maybe_unused]] CompletionQueue* cq) {
+        return nullptr;
+    }
+
+    ClientAsyncResponseReaderInterface<NotifyWakeupRequiredResponse>*
+    PrepareAsyncNotifyWakeupRequiredRaw([[maybe_unused]] ClientContext* context,
+                                        [[maybe_unused]] const NotifyWakeupRequiredRequest& request,
+                                        [[maybe_unused]] CompletionQueue* c) {
+        return nullptr;
+    }
+};
+
+}  // namespace remoteaccess
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    android::hardware::automotive::remoteaccess::MockGrpcClientStub stub;
+    std::shared_ptr<android::hardware::automotive::remoteaccess::RemoteAccessService> service =
+            ndk::SharedRefBase::make<
+                    android::hardware::automotive::remoteaccess::RemoteAccessService>(&stub);
+    android::fuzzService(service->asBinder().get(), FuzzedDataProvider(data, size));
+
+    return 0;
+}
diff --git a/automotive/remoteaccess/hal/default/include/RemoteAccessService.h b/automotive/remoteaccess/hal/default/include/RemoteAccessService.h
new file mode 100644
index 0000000..74c2af4
--- /dev/null
+++ b/automotive/remoteaccess/hal/default/include/RemoteAccessService.h
@@ -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.
+ */
+
+#pragma once
+
+#include <IVhalClient.h>
+#include <aidl/android/hardware/automotive/remoteaccess/ApState.h>
+#include <aidl/android/hardware/automotive/remoteaccess/BnRemoteAccess.h>
+#include <aidl/android/hardware/automotive/remoteaccess/BnRemoteTaskCallback.h>
+#include <aidl/android/hardware/automotive/remoteaccess/IRemoteTaskCallback.h>
+#include <android-base/thread_annotations.h>
+#include <android/binder_auto_utils.h>
+#include <utils/SystemClock.h>
+#include <wakeup_client.grpc.pb.h>
+
+#include <string>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace remoteaccess {
+
+// A IRemoteTaskCallback implementation for debug purpose.
+class DebugRemoteTaskCallback final
+    : public aidl::android::hardware::automotive::remoteaccess::BnRemoteTaskCallback {
+  public:
+    DebugRemoteTaskCallback() { mStartTimeMillis = android::uptimeMillis(); };
+
+    ndk::ScopedAStatus onRemoteTaskRequested(const std::string& clientId,
+                                             const std::vector<uint8_t>& data) override;
+    std::string printTasks();
+
+  private:
+    struct TaskData {
+        std::string clientId;
+        std::vector<uint8_t> data;
+    };
+
+    std::mutex mLock;
+    int64_t mStartTimeMillis;
+    std::vector<TaskData> mTasks;
+};
+
+class RemoteAccessService
+    : public aidl::android::hardware::automotive::remoteaccess::BnRemoteAccess {
+  public:
+    explicit RemoteAccessService(WakeupClient::StubInterface* grpcStub);
+
+    ~RemoteAccessService();
+
+    ndk::ScopedAStatus getDeviceId(std::string* deviceId) override;
+
+    ndk::ScopedAStatus getWakeupServiceName(std::string* wakeupServiceName) override;
+
+    ndk::ScopedAStatus setRemoteTaskCallback(
+            const std::shared_ptr<
+                    aidl::android::hardware::automotive::remoteaccess::IRemoteTaskCallback>&
+                    callback) override;
+
+    ndk::ScopedAStatus clearRemoteTaskCallback() override;
+
+    ndk::ScopedAStatus notifyApStateChange(
+            const aidl::android::hardware::automotive::remoteaccess::ApState& newState) override;
+
+    binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
+
+  private:
+    // For testing.
+    friend class RemoteAccessServiceUnitTest;
+
+    static bool checkDumpPermission();
+
+    WakeupClient::StubInterface* mGrpcStub;
+    std::thread mThread;
+    std::mutex mLock;
+    std::condition_variable mCv;
+    std::shared_ptr<aidl::android::hardware::automotive::remoteaccess::IRemoteTaskCallback>
+            mRemoteTaskCallback GUARDED_BY(mLock);
+    std::unique_ptr<grpc::ClientContext> mGetRemoteTasksContext GUARDED_BY(mLock);
+    // Associated with mCv to notify the task loop to stop waiting and exit.
+    bool mTaskWaitStopped GUARDED_BY(mLock);
+    // A mutex to make sure startTaskLoop does not overlap with stopTaskLoop.
+    std::mutex mStartStopTaskLoopLock;
+    bool mTaskLoopRunning GUARDED_BY(mStartStopTaskLoopLock);
+    // Default wait time before retry connecting to remote access client is 10s.
+    size_t mRetryWaitInMs = 10'000;
+    std::shared_ptr<DebugRemoteTaskCallback> mDebugCallback;
+
+    void runTaskLoop();
+    void maybeStartTaskLoop();
+    void maybeStopTaskLoop();
+    ndk::ScopedAStatus getDeviceIdWithClient(
+            android::frameworks::automotive::vhal::IVhalClient& client, std::string* deviceId);
+
+    void setRetryWaitInMs(size_t retryWaitInMs) { mRetryWaitInMs = retryWaitInMs; }
+    void dumpHelp(int fd);
+};
+
+}  // namespace remoteaccess
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/remoteaccess/hal/default/proto/Android.bp b/automotive/remoteaccess/hal/default/proto/Android.bp
new file mode 100644
index 0000000..3e0dba1
--- /dev/null
+++ b/automotive/remoteaccess/hal/default/proto/Android.bp
@@ -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.
+
+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"],
+}
+
+genrule {
+    name: "wakeup_client_pb_h",
+    tools: [
+        "aprotoc",
+        "protoc-gen-grpc-cpp-plugin",
+    ],
+    cmd: "$(location aprotoc) -I$$(dirname $(in)) -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)",
+    srcs: [
+        "wakeup_client.proto",
+    ],
+    out: [
+        "wakeup_client.pb.h",
+        "wakeup_client.grpc.pb.h",
+    ],
+}
+
+genrule {
+    name: "wakeup_client_pb_cc",
+    tools: [
+        "aprotoc",
+        "protoc-gen-grpc-cpp-plugin",
+    ],
+    cmd: "$(location aprotoc) -I$$(dirname $(in)) -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)",
+    srcs: [
+        "wakeup_client.proto",
+    ],
+    out: [
+        "wakeup_client.pb.cc",
+        "wakeup_client.grpc.pb.cc",
+    ],
+}
+
+cc_library_static {
+    name: "wakeup_client_protos",
+    vendor_available: true,
+    host_supported: true,
+    include_dirs: [
+        "external/protobuf/src",
+    ],
+    generated_headers: [
+        "wakeup_client_pb_h",
+    ],
+    export_generated_headers: [
+        "wakeup_client_pb_h",
+    ],
+    generated_sources: [
+        "wakeup_client_pb_cc",
+    ],
+    shared_libs: [
+        "libgrpc++",
+        "libprotobuf-cpp-full",
+    ],
+    cflags: [
+        "-Wno-unused-parameter",
+    ],
+}
diff --git a/automotive/remoteaccess/impl/default/proto/wakeup_client.proto b/automotive/remoteaccess/hal/default/proto/wakeup_client.proto
similarity index 100%
rename from automotive/remoteaccess/impl/default/proto/wakeup_client.proto
rename to automotive/remoteaccess/hal/default/proto/wakeup_client.proto
diff --git a/automotive/remoteaccess/impl/default/client/remoteaccess-default-service.rc b/automotive/remoteaccess/hal/default/remoteaccess-default-service.rc
similarity index 100%
rename from automotive/remoteaccess/impl/default/client/remoteaccess-default-service.rc
rename to automotive/remoteaccess/hal/default/remoteaccess-default-service.rc
diff --git a/automotive/remoteaccess/impl/default/client/remoteaccess-default-service.xml b/automotive/remoteaccess/hal/default/remoteaccess-default-service.xml
similarity index 100%
rename from automotive/remoteaccess/impl/default/client/remoteaccess-default-service.xml
rename to automotive/remoteaccess/hal/default/remoteaccess-default-service.xml
diff --git a/automotive/remoteaccess/hal/default/src/RemoteAccessImpl.cpp b/automotive/remoteaccess/hal/default/src/RemoteAccessImpl.cpp
new file mode 100644
index 0000000..8720c2f
--- /dev/null
+++ b/automotive/remoteaccess/hal/default/src/RemoteAccessImpl.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.
+ */
+
+#define LOG_TAG "RemoteAccessImpl"
+
+#include "RemoteAccessService.h"
+
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <grpcpp/create_channel.h>
+#include <stdlib.h>
+#include <utils/Log.h>
+
+constexpr char SERVICE_NAME[] = "android.hardware.automotive.remoteaccess.IRemoteAccess/default";
+
+int main(int /* argc */, char* /* argv */[]) {
+    ALOGI("Registering RemoteAccessService as service...");
+
+#ifndef GRPC_SERVICE_ADDRESS
+    ALOGE("GRPC_SERVICE_ADDRESS is not defined, exiting");
+    exit(1);
+#endif
+    auto channel = grpc::CreateChannel(GRPC_SERVICE_ADDRESS, grpc::InsecureChannelCredentials());
+    auto clientStub = android::hardware::automotive::remoteaccess::WakeupClient::NewStub(channel);
+    auto service = ndk::SharedRefBase::make<
+            android::hardware::automotive::remoteaccess::RemoteAccessService>(clientStub.get());
+
+    binder_exception_t err = AServiceManager_addService(service->asBinder().get(), SERVICE_NAME);
+    if (err != EX_NONE) {
+        ALOGE("failed to register android.hardware.automotive.remote.IRemoteAccess service, "
+              "exception: %d",
+              err);
+        exit(1);
+    }
+
+    if (!ABinderProcess_setThreadPoolMaxThreadCount(1)) {
+        ALOGE("%s", "failed to set thread pool max thread count");
+        exit(1);
+    }
+    ABinderProcess_startThreadPool();
+
+    ALOGI("RemoteAccess service Ready");
+
+    ABinderProcess_joinThreadPool();
+
+    ALOGW("Should not reach here");
+
+    return 0;
+}
diff --git a/automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp b/automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp
new file mode 100644
index 0000000..5cd58d3
--- /dev/null
+++ b/automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp
@@ -0,0 +1,355 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "RemoteAccessService.h"
+
+#include <VehicleUtils.h>
+#include <aidl/android/hardware/automotive/vehicle/VehicleProperty.h>
+#include <android-base/stringprintf.h>
+#include <android/binder_status.h>
+#include <grpc++/grpc++.h>
+#include <private/android_filesystem_config.h>
+#include <utils/Log.h>
+#include <chrono>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace remoteaccess {
+
+namespace {
+
+using ::aidl::android::hardware::automotive::remoteaccess::ApState;
+using ::aidl::android::hardware::automotive::remoteaccess::IRemoteTaskCallback;
+using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
+using ::android::base::ScopedLockAssertion;
+using ::android::base::StringAppendF;
+using ::android::base::StringPrintf;
+using ::android::frameworks::automotive::vhal::IVhalClient;
+using ::android::hardware::automotive::vehicle::toInt;
+using ::grpc::ClientContext;
+using ::grpc::ClientReaderInterface;
+using ::grpc::Status;
+using ::grpc::StatusCode;
+using ::ndk::ScopedAStatus;
+
+const std::string WAKEUP_SERVICE_NAME = "com.google.vehicle.wakeup";
+constexpr char COMMAND_SET_AP_STATE[] = "--set-ap-state";
+constexpr char COMMAND_START_DEBUG_CALLBACK[] = "--start-debug-callback";
+constexpr char COMMAND_STOP_DEBUG_CALLBACK[] = "--stop-debug-callback";
+constexpr char COMMAND_SHOW_TASK[] = "--show-task";
+constexpr char COMMAND_GET_DEVICE_ID[] = "--get-device-id";
+
+std::vector<uint8_t> stringToBytes(const std::string& s) {
+    const char* data = s.data();
+    return std::vector<uint8_t>(data, data + s.size());
+}
+
+ScopedAStatus rpcStatusToScopedAStatus(const Status& status, const std::string& errorMsg) {
+    return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+            status.error_code(), (errorMsg + ", error: " + status.error_message()).c_str());
+}
+
+std::string printBytes(const std::vector<uint8_t>& bytes) {
+    std::string s;
+    for (size_t i = 0; i < bytes.size(); i++) {
+        StringAppendF(&s, "%02x", bytes[i]);
+    }
+    return s;
+}
+
+bool checkBoolFlag(const char* flag) {
+    return !strcmp(flag, "1") || !strcmp(flag, "0");
+}
+
+void dprintErrorStatus(int fd, const char* detail, const ScopedAStatus& status) {
+    dprintf(fd, "%s, code: %d, error: %s\n", detail, status.getStatus(), status.getMessage());
+}
+
+}  // namespace
+
+RemoteAccessService::RemoteAccessService(WakeupClient::StubInterface* grpcStub)
+    : mGrpcStub(grpcStub){};
+
+RemoteAccessService::~RemoteAccessService() {
+    maybeStopTaskLoop();
+}
+
+void RemoteAccessService::maybeStartTaskLoop() {
+    std::lock_guard<std::mutex> lockGuard(mStartStopTaskLoopLock);
+    if (mTaskLoopRunning) {
+        return;
+    }
+
+    mThread = std::thread([this]() { runTaskLoop(); });
+
+    mTaskLoopRunning = true;
+}
+
+void RemoteAccessService::maybeStopTaskLoop() {
+    std::lock_guard<std::mutex> lockGuard(mStartStopTaskLoopLock);
+    if (!mTaskLoopRunning) {
+        return;
+    }
+
+    {
+        std::lock_guard<std::mutex> lockGuard(mLock);
+        // Try to stop the reading stream.
+        if (mGetRemoteTasksContext) {
+            mGetRemoteTasksContext->TryCancel();
+            mGetRemoteTasksContext.reset();
+        }
+        mTaskWaitStopped = true;
+        mCv.notify_all();
+    }
+    if (mThread.joinable()) {
+        mThread.join();
+    }
+
+    mTaskLoopRunning = false;
+}
+
+void RemoteAccessService::runTaskLoop() {
+    GetRemoteTasksRequest request = {};
+    std::unique_ptr<ClientReaderInterface<GetRemoteTasksResponse>> reader;
+    while (true) {
+        {
+            std::lock_guard<std::mutex> lockGuard(mLock);
+            mGetRemoteTasksContext.reset(new ClientContext());
+            reader = mGrpcStub->GetRemoteTasks(mGetRemoteTasksContext.get(), request);
+        }
+        GetRemoteTasksResponse response;
+        while (reader->Read(&response)) {
+            ALOGI("Receiving one task from remote task client");
+
+            std::shared_ptr<IRemoteTaskCallback> callback;
+            {
+                std::lock_guard<std::mutex> lockGuard(mLock);
+                callback = mRemoteTaskCallback;
+            }
+            if (callback == nullptr) {
+                ALOGD("No callback registered, task ignored");
+                continue;
+            }
+            ALOGD("Calling onRemoteTaskRequested callback for client ID: %s",
+                  response.clientid().c_str());
+            ScopedAStatus callbackStatus = callback->onRemoteTaskRequested(
+                    response.clientid(), stringToBytes(response.data()));
+            if (!callbackStatus.isOk()) {
+                ALOGE("Failed to call onRemoteTaskRequested callback, status: %d, message: %s",
+                      callbackStatus.getStatus(), callbackStatus.getMessage());
+            }
+        }
+        Status status = reader->Finish();
+
+        ALOGE("GetRemoteTasks stream breaks, code: %d, message: %s, sleeping for 10s and retry",
+              status.error_code(), status.error_message().c_str());
+        // The long lasting connection should not return. But if the server returns, retry after
+        // 10s.
+        {
+            std::unique_lock lk(mLock);
+            if (mCv.wait_for(lk, std::chrono::milliseconds(mRetryWaitInMs), [this] {
+                    ScopedLockAssertion lockAssertion(mLock);
+                    return mTaskWaitStopped;
+                })) {
+                // If the stopped flag is set, we are quitting, exit the loop.
+                break;
+            }
+        }
+    }
+}
+
+ScopedAStatus RemoteAccessService::getDeviceId(std::string* deviceId) {
+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+    auto vhalClient = IVhalClient::tryCreate();
+    if (vhalClient == nullptr) {
+        ALOGE("Failed to connect to VHAL");
+        return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                /*errorCode=*/0, "Failed to connect to VHAL to get device ID");
+    }
+    return getDeviceIdWithClient(*vhalClient.get(), deviceId);
+#else
+    // Don't use VHAL client in fuzzing since IPC is not allowed.
+    return ScopedAStatus::ok();
+#endif
+}
+
+ScopedAStatus RemoteAccessService::getDeviceIdWithClient(IVhalClient& vhalClient,
+                                                         std::string* deviceId) {
+    auto result = vhalClient.getValueSync(
+            *vhalClient.createHalPropValue(toInt(VehicleProperty::INFO_VIN)));
+    if (!result.ok()) {
+        return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                /*errorCode=*/0,
+                ("failed to get INFO_VIN from VHAL: " + result.error().message()).c_str());
+    }
+    *deviceId = (*result)->getStringValue();
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus RemoteAccessService::getWakeupServiceName(std::string* wakeupServiceName) {
+    *wakeupServiceName = WAKEUP_SERVICE_NAME;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus RemoteAccessService::setRemoteTaskCallback(
+        const std::shared_ptr<IRemoteTaskCallback>& callback) {
+    std::lock_guard<std::mutex> lockGuard(mLock);
+    mRemoteTaskCallback = callback;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus RemoteAccessService::clearRemoteTaskCallback() {
+    std::lock_guard<std::mutex> lockGuard(mLock);
+    mRemoteTaskCallback.reset();
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus RemoteAccessService::notifyApStateChange(const ApState& newState) {
+    ClientContext context;
+    NotifyWakeupRequiredRequest request = {};
+    request.set_iswakeuprequired(newState.isWakeupRequired);
+    NotifyWakeupRequiredResponse response = {};
+    Status status = mGrpcStub->NotifyWakeupRequired(&context, request, &response);
+    if (!status.ok()) {
+        return rpcStatusToScopedAStatus(status, "Failed to notify isWakeupRequired");
+    }
+
+    if (newState.isReadyForRemoteTask) {
+        maybeStartTaskLoop();
+    } else {
+        maybeStopTaskLoop();
+    }
+    return ScopedAStatus::ok();
+}
+
+bool RemoteAccessService::checkDumpPermission() {
+    uid_t uid = AIBinder_getCallingUid();
+    return uid == AID_ROOT || uid == AID_SHELL || uid == AID_SYSTEM;
+}
+
+void RemoteAccessService::dumpHelp(int fd) {
+    dprintf(fd, "%s",
+            (std::string("RemoteAccess HAL debug interface, Usage: \n") + COMMAND_SET_AP_STATE +
+             " [0/1](isReadyForRemoteTask) [0/1](isWakeupRequired)  Set the new AP state\n" +
+             COMMAND_START_DEBUG_CALLBACK +
+             " Start a debug callback that will record the received tasks\n" +
+             COMMAND_STOP_DEBUG_CALLBACK + " Stop the debug callback\n" + COMMAND_SHOW_TASK +
+             " Show tasks received by debug callback\n" + COMMAND_GET_DEVICE_ID +
+             " Get device id\n")
+                    .c_str());
+}
+
+binder_status_t RemoteAccessService::dump(int fd, const char** args, uint32_t numArgs) {
+    if (!checkDumpPermission()) {
+        dprintf(fd, "Caller must be root, system or shell\n");
+        return STATUS_PERMISSION_DENIED;
+    }
+
+    if (numArgs == 0) {
+        dumpHelp(fd);
+        return STATUS_OK;
+    }
+
+    if (!strcmp(args[0], COMMAND_SET_AP_STATE)) {
+        if (numArgs < 3) {
+            dumpHelp(fd);
+            return STATUS_OK;
+        }
+        ApState apState = {};
+        const char* remoteTaskFlag = args[1];
+        if (!strcmp(remoteTaskFlag, "1") && !strcmp(remoteTaskFlag, "0")) {
+            dumpHelp(fd);
+            return STATUS_OK;
+        }
+        if (!checkBoolFlag(args[1])) {
+            dumpHelp(fd);
+            return STATUS_OK;
+        }
+        if (!strcmp(args[1], "1")) {
+            apState.isReadyForRemoteTask = true;
+        }
+        if (!checkBoolFlag(args[2])) {
+            dumpHelp(fd);
+            return STATUS_OK;
+        }
+        if (!strcmp(args[2], "1")) {
+            apState.isWakeupRequired = true;
+        }
+        auto status = notifyApStateChange(apState);
+        if (!status.isOk()) {
+            dprintErrorStatus(fd, "Failed to set AP state", status);
+        } else {
+            dprintf(fd, "successfully set the new AP state\n");
+        }
+    } else if (!strcmp(args[0], COMMAND_START_DEBUG_CALLBACK)) {
+        mDebugCallback = ndk::SharedRefBase::make<DebugRemoteTaskCallback>();
+        setRemoteTaskCallback(mDebugCallback);
+        dprintf(fd, "Debug callback registered\n");
+    } else if (!strcmp(args[0], COMMAND_STOP_DEBUG_CALLBACK)) {
+        if (mDebugCallback) {
+            mDebugCallback.reset();
+        }
+        clearRemoteTaskCallback();
+        dprintf(fd, "Debug callback unregistered\n");
+    } else if (!strcmp(args[0], COMMAND_SHOW_TASK)) {
+        if (mDebugCallback) {
+            dprintf(fd, "%s", mDebugCallback->printTasks().c_str());
+        } else {
+            dprintf(fd, "Debug callback is not currently used, use \"%s\" first.\n",
+                    COMMAND_START_DEBUG_CALLBACK);
+        }
+    } else if (!strcmp(args[0], COMMAND_GET_DEVICE_ID)) {
+        std::string deviceId;
+        auto status = getDeviceId(&deviceId);
+        if (!status.isOk()) {
+            dprintErrorStatus(fd, "Failed to get device ID", status);
+        } else {
+            dprintf(fd, "Device Id: %s\n", deviceId.c_str());
+        }
+    } else {
+        dumpHelp(fd);
+    }
+
+    return STATUS_OK;
+}
+
+ScopedAStatus DebugRemoteTaskCallback::onRemoteTaskRequested(const std::string& clientId,
+                                                             const std::vector<uint8_t>& data) {
+    std::lock_guard<std::mutex> lockGuard(mLock);
+    mTasks.push_back({
+            .clientId = clientId,
+            .data = data,
+    });
+    return ScopedAStatus::ok();
+}
+
+std::string DebugRemoteTaskCallback::printTasks() {
+    std::lock_guard<std::mutex> lockGuard(mLock);
+    std::string s = StringPrintf("Received %zu tasks in %f seconds", mTasks.size(),
+                                 (android::uptimeMillis() - mStartTimeMillis) / 1000.);
+    for (size_t i = 0; i < mTasks.size(); i++) {
+        StringAppendF(&s, "Client Id: %s, Data: %s\n", mTasks[i].clientId.c_str(),
+                      printBytes(mTasks[i].data).c_str());
+    }
+    return s;
+}
+
+}  // namespace remoteaccess
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/remoteaccess/hal/default/test/Android.bp b/automotive/remoteaccess/hal/default/test/Android.bp
new file mode 100644
index 0000000..227175a
--- /dev/null
+++ b/automotive/remoteaccess/hal/default/test/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 {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_test {
+    name: "RemoteAccessServiceUnitTest",
+    vendor: true,
+    srcs: ["*.cpp"],
+    whole_static_libs: [
+        "RemoteAccessService",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "liblog",
+        "libutils",
+        "libgrpc++",
+        "libprotobuf-cpp-full",
+    ],
+    // libgrpc++.so is installed as root, require root to access it.
+    require_root: true,
+    static_libs: [
+        "libgtest",
+        "libgmock",
+    ],
+    defaults: [
+        "vhalclient_defaults",
+    ],
+    cflags: [
+        "-Wno-unused-parameter",
+    ],
+    test_suites: ["device-tests"],
+}
diff --git a/automotive/remoteaccess/hal/default/test/RemoteAccessServiceUnitTest.cpp b/automotive/remoteaccess/hal/default/test/RemoteAccessServiceUnitTest.cpp
new file mode 100644
index 0000000..8c4fa08
--- /dev/null
+++ b/automotive/remoteaccess/hal/default/test/RemoteAccessServiceUnitTest.cpp
@@ -0,0 +1,373 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "RemoteAccessService.h"
+
+#include <AidlHalPropValue.h>
+#include <IVhalClient.h>
+#include <aidl/android/hardware/automotive/remoteaccess/ApState.h>
+#include <aidl/android/hardware/automotive/remoteaccess/BnRemoteTaskCallback.h>
+#include <aidl/android/hardware/automotive/vehicle/VehiclePropValue.h>
+#include <gmock/gmock.h>
+#include <grpcpp/test/mock_stream.h>
+#include <gtest/gtest.h>
+#include <wakeup_client.grpc.pb.h>
+#include <chrono>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace remoteaccess {
+
+namespace {
+
+using ::android::base::ScopedLockAssertion;
+using ::android::frameworks::automotive::vhal::AidlHalPropValue;
+using ::android::frameworks::automotive::vhal::IHalPropConfig;
+using ::android::frameworks::automotive::vhal::IHalPropValue;
+using ::android::frameworks::automotive::vhal::ISubscriptionCallback;
+using ::android::frameworks::automotive::vhal::ISubscriptionClient;
+using ::android::frameworks::automotive::vhal::IVhalClient;
+using ::android::frameworks::automotive::vhal::VhalClientResult;
+
+using ::aidl::android::hardware::automotive::remoteaccess::ApState;
+using ::aidl::android::hardware::automotive::remoteaccess::BnRemoteTaskCallback;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
+
+using ::grpc::ClientAsyncReaderInterface;
+using ::grpc::ClientAsyncResponseReaderInterface;
+using ::grpc::ClientContext;
+using ::grpc::ClientReader;
+using ::grpc::ClientReaderInterface;
+using ::grpc::CompletionQueue;
+using ::grpc::Status;
+using ::grpc::testing::MockClientReader;
+using ::ndk::ScopedAStatus;
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::Return;
+using ::testing::SetArgPointee;
+
+constexpr char kTestVin[] = "test_VIN";
+
+}  // namespace
+
+class MockGrpcClientStub : public WakeupClient::StubInterface {
+  public:
+    MOCK_METHOD(ClientReaderInterface<GetRemoteTasksResponse>*, GetRemoteTasksRaw,
+                (ClientContext * context, const GetRemoteTasksRequest& request));
+    MOCK_METHOD(Status, NotifyWakeupRequired,
+                (ClientContext * context, const NotifyWakeupRequiredRequest& request,
+                 NotifyWakeupRequiredResponse* response));
+    // Async methods which we do not care.
+    MOCK_METHOD(ClientAsyncReaderInterface<GetRemoteTasksResponse>*, AsyncGetRemoteTasksRaw,
+                (ClientContext * context, const GetRemoteTasksRequest& request, CompletionQueue* cq,
+                 void* tag));
+    MOCK_METHOD(ClientAsyncReaderInterface<GetRemoteTasksResponse>*, PrepareAsyncGetRemoteTasksRaw,
+                (ClientContext * context, const GetRemoteTasksRequest& request,
+                 CompletionQueue* cq));
+    MOCK_METHOD(ClientAsyncResponseReaderInterface<NotifyWakeupRequiredResponse>*,
+                AsyncNotifyWakeupRequiredRaw,
+                (ClientContext * context, const NotifyWakeupRequiredRequest& request,
+                 CompletionQueue* cq));
+    MOCK_METHOD(ClientAsyncResponseReaderInterface<NotifyWakeupRequiredResponse>*,
+                PrepareAsyncNotifyWakeupRequiredRaw,
+                (ClientContext * context, const NotifyWakeupRequiredRequest& request,
+                 CompletionQueue* cq));
+};
+
+class FakeVhalClient final : public android::frameworks::automotive::vhal::IVhalClient {
+  public:
+    inline bool isAidlVhal() { return true; }
+
+    VhalClientResult<std::unique_ptr<IHalPropValue>> getValueSync(
+            const IHalPropValue& requestValue) override {
+        auto propValue = std::make_unique<AidlHalPropValue>(requestValue.getPropId());
+        propValue->setStringValue(kTestVin);
+        return propValue;
+    }
+
+    std::unique_ptr<IHalPropValue> createHalPropValue(int32_t propId) override {
+        return std::make_unique<AidlHalPropValue>(propId);
+    }
+
+    // Functions we do not care.
+    std::unique_ptr<IHalPropValue> createHalPropValue([[maybe_unused]] int32_t propId,
+                                                      [[maybe_unused]] int32_t areaId) override {
+        return nullptr;
+    }
+
+    void getValue([[maybe_unused]] const IHalPropValue& requestValue,
+                  [[maybe_unused]] std::shared_ptr<GetValueCallbackFunc> callback) override {}
+
+    void setValue([[maybe_unused]] const IHalPropValue& requestValue,
+                  [[maybe_unused]] std::shared_ptr<SetValueCallbackFunc> callback) override {}
+
+    VhalClientResult<void> setValueSync([[maybe_unused]] const IHalPropValue& requestValue) {
+        return {};
+    }
+
+    VhalClientResult<void> addOnBinderDiedCallback(
+            [[maybe_unused]] std::shared_ptr<OnBinderDiedCallbackFunc> callback) override {
+        return {};
+    }
+
+    VhalClientResult<void> removeOnBinderDiedCallback(
+            [[maybe_unused]] std::shared_ptr<OnBinderDiedCallbackFunc> callback) override {
+        return {};
+    }
+
+    VhalClientResult<std::vector<std::unique_ptr<IHalPropConfig>>> getAllPropConfigs() override {
+        return std::vector<std::unique_ptr<IHalPropConfig>>();
+    }
+
+    VhalClientResult<std::vector<std::unique_ptr<IHalPropConfig>>> getPropConfigs(
+            [[maybe_unused]] std::vector<int32_t> propIds) override {
+        return std::vector<std::unique_ptr<IHalPropConfig>>();
+    }
+
+    std::unique_ptr<ISubscriptionClient> getSubscriptionClient(
+            [[maybe_unused]] std::shared_ptr<ISubscriptionCallback> callback) override {
+        return nullptr;
+    }
+};
+
+class FakeRemoteTaskCallback : public BnRemoteTaskCallback {
+  public:
+    ScopedAStatus onRemoteTaskRequested(const std::string& clientId,
+                                        const std::vector<uint8_t>& data) override {
+        std::lock_guard<std::mutex> lockGuard(mLock);
+        mDataByClientId[clientId] = data;
+        mTaskCount++;
+        mCv.notify_all();
+        return ScopedAStatus::ok();
+    }
+
+    std::vector<uint8_t> getData(const std::string& clientId) { return mDataByClientId[clientId]; }
+
+    bool wait(size_t taskCount, size_t timeoutInSec) {
+        std::unique_lock<std::mutex> lock(mLock);
+        return mCv.wait_for(lock, std::chrono::seconds(timeoutInSec), [taskCount, this] {
+            ScopedLockAssertion lockAssertion(mLock);
+            return mTaskCount >= taskCount;
+        });
+    }
+
+  private:
+    std::mutex mLock;
+    std::unordered_map<std::string, std::vector<uint8_t>> mDataByClientId GUARDED_BY(mLock);
+    size_t mTaskCount GUARDED_BY(mLock) = 0;
+    std::condition_variable mCv;
+};
+
+class RemoteAccessServiceUnitTest : public ::testing::Test {
+  public:
+    virtual void SetUp() override {
+        mGrpcWakeupClientStub = std::make_unique<MockGrpcClientStub>();
+        mService = ndk::SharedRefBase::make<RemoteAccessService>(mGrpcWakeupClientStub.get());
+    }
+
+    MockGrpcClientStub* getGrpcWakeupClientStub() { return mGrpcWakeupClientStub.get(); }
+
+    RemoteAccessService* getService() { return mService.get(); }
+
+    void setRetryWaitInMs(size_t retryWaitInMs) { mService->setRetryWaitInMs(retryWaitInMs); }
+
+    ScopedAStatus getDeviceIdWithClient(IVhalClient& vhalClient, std::string* deviceId) {
+        return mService->getDeviceIdWithClient(vhalClient, deviceId);
+    }
+
+  private:
+    std::unique_ptr<MockGrpcClientStub> mGrpcWakeupClientStub;
+    std::shared_ptr<RemoteAccessService> mService;
+};
+
+TEST_F(RemoteAccessServiceUnitTest, TestGetWakeupServiceName) {
+    std::string serviceName;
+
+    ScopedAStatus status = getService()->getWakeupServiceName(&serviceName);
+
+    EXPECT_TRUE(status.isOk());
+    EXPECT_EQ(serviceName, "com.google.vehicle.wakeup");
+}
+
+TEST_F(RemoteAccessServiceUnitTest, TestNotifyApStateChangeWakeupRequired) {
+    bool isWakeupRequired = false;
+    EXPECT_CALL(*getGrpcWakeupClientStub(), NotifyWakeupRequired)
+            .WillOnce([&isWakeupRequired]([[maybe_unused]] ClientContext* context,
+                                          const NotifyWakeupRequiredRequest& request,
+                                          [[maybe_unused]] NotifyWakeupRequiredResponse* response) {
+                isWakeupRequired = request.iswakeuprequired();
+                return Status();
+            });
+
+    ApState newState = {
+            .isWakeupRequired = true,
+    };
+    ScopedAStatus status = getService()->notifyApStateChange(newState);
+
+    EXPECT_TRUE(status.isOk());
+    EXPECT_TRUE(isWakeupRequired);
+}
+
+TEST_F(RemoteAccessServiceUnitTest, TestGetRemoteTasks) {
+    GetRemoteTasksResponse response1;
+    std::vector<uint8_t> testData = {0xde, 0xad, 0xbe, 0xef};
+    response1.set_clientid("1");
+    response1.set_data(testData.data(), testData.size());
+    GetRemoteTasksResponse response2;
+    response2.set_clientid("2");
+    std::shared_ptr<FakeRemoteTaskCallback> callback =
+            ndk::SharedRefBase::make<FakeRemoteTaskCallback>();
+
+    ON_CALL(*getGrpcWakeupClientStub(), GetRemoteTasksRaw)
+            .WillByDefault(
+                    [response1, response2]([[maybe_unused]] ClientContext* context,
+                                           [[maybe_unused]] const GetRemoteTasksRequest& request) {
+                        // mockReader ownership will be transferred to the client so we don't own it
+                        // here.
+                        MockClientReader<GetRemoteTasksResponse>* mockClientReader =
+                                new MockClientReader<GetRemoteTasksResponse>();
+                        EXPECT_CALL(*mockClientReader, Finish()).WillOnce(Return(Status::OK));
+                        EXPECT_CALL(*mockClientReader, Read(_))
+                                .WillOnce(DoAll(SetArgPointee<0>(response1), Return(true)))
+                                .WillOnce(DoAll(SetArgPointee<0>(response2), Return(true)))
+                                .WillRepeatedly(Return(false));
+                        return mockClientReader;
+                    });
+
+    getService()->setRemoteTaskCallback(callback);
+    // Start the long live connection to receive tasks.
+    ApState newState = {
+            .isReadyForRemoteTask = true,
+    };
+    ASSERT_TRUE(getService()->notifyApStateChange(newState).isOk());
+
+    ASSERT_TRUE(callback->wait(/*taskCount=*/2, /*timeoutInSec=*/10))
+            << "Did not receive enough tasks";
+    EXPECT_EQ(callback->getData("1"), testData);
+    EXPECT_EQ(callback->getData("2"), std::vector<uint8_t>());
+}
+
+TEST_F(RemoteAccessServiceUnitTest, TestGetRemoteTasksRetryConnection) {
+    GetRemoteTasksResponse response;
+    std::shared_ptr<FakeRemoteTaskCallback> callback =
+            ndk::SharedRefBase::make<FakeRemoteTaskCallback>();
+
+    ON_CALL(*getGrpcWakeupClientStub(), GetRemoteTasksRaw)
+            .WillByDefault([response]([[maybe_unused]] ClientContext* context,
+                                      [[maybe_unused]] const GetRemoteTasksRequest& request) {
+                // mockReader ownership will be transferred to the client so we don't own it here.
+                MockClientReader<GetRemoteTasksResponse>* mockClientReader =
+                        new MockClientReader<GetRemoteTasksResponse>();
+                EXPECT_CALL(*mockClientReader, Finish()).WillOnce(Return(Status::OK));
+                // Connection fails after receiving one task. Should retry after some time.
+                EXPECT_CALL(*mockClientReader, Read(_))
+                        .WillOnce(DoAll(SetArgPointee<0>(response), Return(true)))
+                        .WillRepeatedly(Return(false));
+                return mockClientReader;
+            });
+
+    getService()->setRemoteTaskCallback(callback);
+    setRetryWaitInMs(100);
+    // Start the long live connection to receive tasks.
+    ApState newState = {
+            .isReadyForRemoteTask = true,
+    };
+    ASSERT_TRUE(getService()->notifyApStateChange(newState).isOk());
+
+    ASSERT_TRUE(callback->wait(/*taskCount=*/2, /*timeoutInSec=*/10))
+            << "Did not receive enough tasks";
+}
+
+TEST_F(RemoteAccessServiceUnitTest, TestGetRemoteTasksDefaultNotReady) {
+    GetRemoteTasksResponse response1;
+    std::vector<uint8_t> testData = {0xde, 0xad, 0xbe, 0xef};
+    response1.set_clientid("1");
+    response1.set_data(testData.data(), testData.size());
+    GetRemoteTasksResponse response2;
+    response2.set_clientid("2");
+    std::shared_ptr<FakeRemoteTaskCallback> callback =
+            ndk::SharedRefBase::make<FakeRemoteTaskCallback>();
+
+    EXPECT_CALL(*getGrpcWakeupClientStub(), GetRemoteTasksRaw).Times(0);
+
+    // Default state is not ready for remote tasks, so no callback will be called.
+    getService()->setRemoteTaskCallback(callback);
+
+    std::this_thread::sleep_for(std::chrono::milliseconds(100));
+}
+
+TEST_F(RemoteAccessServiceUnitTest, TestGetRemoteTasksNotReadyAfterReady) {
+    GetRemoteTasksResponse response1;
+    std::vector<uint8_t> testData = {0xde, 0xad, 0xbe, 0xef};
+    response1.set_clientid("1");
+    response1.set_data(testData.data(), testData.size());
+    GetRemoteTasksResponse response2;
+    response2.set_clientid("2");
+    std::shared_ptr<FakeRemoteTaskCallback> callback =
+            ndk::SharedRefBase::make<FakeRemoteTaskCallback>();
+
+    ON_CALL(*getGrpcWakeupClientStub(), GetRemoteTasksRaw)
+            .WillByDefault(
+                    [response1, response2]([[maybe_unused]] ClientContext* context,
+                                           [[maybe_unused]] const GetRemoteTasksRequest& request) {
+                        // mockReader ownership will be transferred to the client so we don't own it
+                        // here.
+                        MockClientReader<GetRemoteTasksResponse>* mockClientReader =
+                                new MockClientReader<GetRemoteTasksResponse>();
+                        EXPECT_CALL(*mockClientReader, Finish()).WillOnce(Return(Status::OK));
+                        EXPECT_CALL(*mockClientReader, Read(_))
+                                .WillOnce(DoAll(SetArgPointee<0>(response1), Return(true)))
+                                .WillOnce(DoAll(SetArgPointee<0>(response2), Return(true)))
+                                .WillRepeatedly(Return(false));
+                        return mockClientReader;
+                    });
+    // Should only be called once when is is ready for remote task.
+    EXPECT_CALL(*getGrpcWakeupClientStub(), GetRemoteTasksRaw).Times(1);
+
+    getService()->setRemoteTaskCallback(callback);
+    setRetryWaitInMs(100);
+    // Start the long live connection to receive tasks.
+    ApState newState = {
+            .isReadyForRemoteTask = true,
+    };
+    ASSERT_TRUE(getService()->notifyApStateChange(newState).isOk());
+    ASSERT_TRUE(callback->wait(/*taskCount=*/2, /*timeoutInSec=*/10))
+            << "Did not receive enough tasks";
+
+    // Stop the long live connection.
+    newState.isReadyForRemoteTask = false;
+    ASSERT_TRUE(getService()->notifyApStateChange(newState).isOk());
+
+    // Wait for the retry delay, but the loop should already exit.
+    std::this_thread::sleep_for(std::chrono::milliseconds(150));
+}
+
+TEST_F(RemoteAccessServiceUnitTest, testGetDeviceId) {
+    std::string deviceId;
+
+    FakeVhalClient vhalClient;
+
+    ASSERT_TRUE(getDeviceIdWithClient(vhalClient, &deviceId).isOk());
+    ASSERT_EQ(deviceId, kTestVin);
+}
+
+}  // namespace remoteaccess
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/remoteaccess/impl/default/client/Android.bp b/automotive/remoteaccess/impl/default/client/Android.bp
deleted file mode 100644
index 6327637..0000000
--- a/automotive/remoteaccess/impl/default/client/Android.bp
+++ /dev/null
@@ -1,66 +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 {
-    default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-cc_binary {
-    name: "android.hardware.automotive.remoteaccess@V1-default-service",
-    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: [
-        "RemoteAccessService",
-    ],
-    shared_libs: [
-        "libbinder_ndk",
-        "liblog",
-        "libutils",
-        "libgrpc++",
-        "libprotobuf-cpp-full",
-    ],
-    cflags: [
-        "-Wno-unused-parameter",
-    ],
-}
-
-cc_library {
-    name: "RemoteAccessService",
-    vendor: true,
-    local_include_dirs: ["include"],
-    export_include_dirs: ["include"],
-    srcs: [
-        "src/RemoteAccessService.cpp",
-    ],
-    whole_static_libs: [
-        "android.hardware.automotive.remoteaccess-V1-ndk",
-        "wakeup_client_protos",
-    ],
-    shared_libs: [
-        "libbase",
-        "libbinder_ndk",
-        "liblog",
-        "libutils",
-        "libgrpc++",
-        "libprotobuf-cpp-full",
-    ],
-    cflags: [
-        "-Wno-unused-parameter",
-    ],
-}
diff --git a/automotive/remoteaccess/impl/default/client/include/RemoteAccessService.h b/automotive/remoteaccess/impl/default/client/include/RemoteAccessService.h
deleted file mode 100644
index 806440a..0000000
--- a/automotive/remoteaccess/impl/default/client/include/RemoteAccessService.h
+++ /dev/null
@@ -1,83 +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.
- */
-
-#pragma once
-
-#include <aidl/android/hardware/automotive/remoteaccess/ApState.h>
-#include <aidl/android/hardware/automotive/remoteaccess/BnRemoteAccess.h>
-#include <aidl/android/hardware/automotive/remoteaccess/IRemoteTaskCallback.h>
-#include <android-base/thread_annotations.h>
-#include <wakeup_client.grpc.pb.h>
-
-#include <string>
-#include <thread>
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace remoteaccess {
-
-class RemoteAccessService
-    : public aidl::android::hardware::automotive::remoteaccess::BnRemoteAccess {
-  public:
-    explicit RemoteAccessService(WakeupClient::StubInterface* grpcStub);
-
-    ~RemoteAccessService();
-
-    ndk::ScopedAStatus getDeviceId(std::string* deviceId) override;
-
-    ndk::ScopedAStatus getWakeupServiceName(std::string* wakeupServiceName) override;
-
-    ndk::ScopedAStatus setRemoteTaskCallback(
-            const std::shared_ptr<
-                    aidl::android::hardware::automotive::remoteaccess::IRemoteTaskCallback>&
-                    callback) override;
-
-    ndk::ScopedAStatus clearRemoteTaskCallback() override;
-
-    ndk::ScopedAStatus notifyApStateChange(
-            const aidl::android::hardware::automotive::remoteaccess::ApState& newState) override;
-
-  private:
-    // For testing.
-    friend class RemoteAccessServiceUnitTest;
-
-    WakeupClient::StubInterface* mGrpcStub;
-    std::thread mThread;
-    std::mutex mLock;
-    std::condition_variable mCv;
-    std::shared_ptr<aidl::android::hardware::automotive::remoteaccess::IRemoteTaskCallback>
-            mRemoteTaskCallback GUARDED_BY(mLock);
-    std::unique_ptr<grpc::ClientContext> mGetRemoteTasksContext GUARDED_BY(mLock);
-    // Associated with mCv to notify the task loop to stop waiting and exit.
-    bool mTaskWaitStopped GUARDED_BY(mLock);
-    // A mutex to make sure startTaskLoop does not overlap with stopTaskLoop.
-    std::mutex mStartStopTaskLoopLock;
-    bool mTaskLoopRunning GUARDED_BY(mStartStopTaskLoopLock);
-    // Default wait time before retry connecting to remote access client is 10s.
-    size_t mRetryWaitInMs = 10'000;
-
-    void runTaskLoop();
-    void maybeStartTaskLoop();
-    void maybeStopTaskLoop();
-
-    void setRetryWaitInMs(size_t retryWaitInMs) { mRetryWaitInMs = retryWaitInMs; }
-};
-
-}  // namespace remoteaccess
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
diff --git a/automotive/remoteaccess/impl/default/client/src/RemoteAccessImpl.cpp b/automotive/remoteaccess/impl/default/client/src/RemoteAccessImpl.cpp
deleted file mode 100644
index 7431898..0000000
--- a/automotive/remoteaccess/impl/default/client/src/RemoteAccessImpl.cpp
+++ /dev/null
@@ -1,54 +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.
- */
-
-#define LOG_TAG "RemoteAccessImpl"
-
-#include "RemoteAccessService.h"
-
-#include <android/binder_manager.h>
-#include <android/binder_process.h>
-#include <utils/Log.h>
-
-int main(int /* argc */, char* /* argv */[]) {
-    ALOGI("Registering RemoteAccessService as service...");
-
-    // TODO(b/241483300): Create GrpcClientStub here.
-    auto service = ndk::SharedRefBase::make<
-            android::hardware::automotive::remoteaccess::RemoteAccessService>(nullptr);
-
-    binder_exception_t err = AServiceManager_addService(
-            service->asBinder().get(), "android.hardware.automotive.remote.IRemoteAccess/default");
-    if (err != EX_NONE) {
-        ALOGE("failed to register android.hardware.automotive.remote.IRemoteAccess service, "
-              "exception: %d",
-              err);
-        return 1;
-    }
-
-    if (!ABinderProcess_setThreadPoolMaxThreadCount(1)) {
-        ALOGE("%s", "failed to set thread pool max thread count");
-        return 1;
-    }
-    ABinderProcess_startThreadPool();
-
-    ALOGI("RemoteAccess service Ready");
-
-    ABinderProcess_joinThreadPool();
-
-    ALOGW("Should not reach here");
-
-    return 0;
-}
diff --git a/automotive/remoteaccess/impl/default/client/src/RemoteAccessService.cpp b/automotive/remoteaccess/impl/default/client/src/RemoteAccessService.cpp
deleted file mode 100644
index 6b97840..0000000
--- a/automotive/remoteaccess/impl/default/client/src/RemoteAccessService.cpp
+++ /dev/null
@@ -1,185 +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 "RemoteAccessService.h"
-
-#include <android/binder_status.h>
-#include <grpc++/grpc++.h>
-#include <utils/Log.h>
-#include <chrono>
-#include <thread>
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace remoteaccess {
-
-namespace {
-
-using ::aidl::android::hardware::automotive::remoteaccess::ApState;
-using ::aidl::android::hardware::automotive::remoteaccess::IRemoteTaskCallback;
-using ::android::base::ScopedLockAssertion;
-using ::grpc::ClientContext;
-using ::grpc::ClientReaderInterface;
-using ::grpc::Status;
-using ::grpc::StatusCode;
-using ::ndk::ScopedAStatus;
-
-const std::string WAKEUP_SERVICE_NAME = "com.google.vehicle.wakeup";
-
-std::vector<uint8_t> stringToBytes(const std::string& s) {
-    const char* data = s.data();
-    return std::vector<uint8_t>(data, data + s.size());
-}
-
-ScopedAStatus rpcStatusToScopedAStatus(const Status& status, const std::string& errorMsg) {
-    return ScopedAStatus::fromServiceSpecificErrorWithMessage(
-            status.error_code(), (errorMsg + ", error: " + status.error_message()).c_str());
-}
-
-}  // namespace
-
-RemoteAccessService::RemoteAccessService(WakeupClient::StubInterface* grpcStub)
-    : mGrpcStub(grpcStub){};
-
-RemoteAccessService::~RemoteAccessService() {
-    maybeStopTaskLoop();
-}
-
-void RemoteAccessService::maybeStartTaskLoop() {
-    std::lock_guard<std::mutex> lockGuard(mStartStopTaskLoopLock);
-    if (mTaskLoopRunning) {
-        return;
-    }
-
-    mThread = std::thread([this]() { runTaskLoop(); });
-
-    mTaskLoopRunning = true;
-}
-
-void RemoteAccessService::maybeStopTaskLoop() {
-    std::lock_guard<std::mutex> lockGuard(mStartStopTaskLoopLock);
-    if (!mTaskLoopRunning) {
-        return;
-    }
-
-    {
-        std::lock_guard<std::mutex> lockGuard(mLock);
-        // Try to stop the reading stream.
-        if (mGetRemoteTasksContext) {
-            mGetRemoteTasksContext->TryCancel();
-            mGetRemoteTasksContext.reset();
-        }
-        mTaskWaitStopped = true;
-        mCv.notify_all();
-    }
-    if (mThread.joinable()) {
-        mThread.join();
-    }
-
-    mTaskLoopRunning = false;
-}
-
-void RemoteAccessService::runTaskLoop() {
-    GetRemoteTasksRequest request = {};
-    std::unique_ptr<ClientReaderInterface<GetRemoteTasksResponse>> reader;
-    while (true) {
-        {
-            std::lock_guard<std::mutex> lockGuard(mLock);
-            mGetRemoteTasksContext.reset(new ClientContext());
-            reader = mGrpcStub->GetRemoteTasks(mGetRemoteTasksContext.get(), request);
-        }
-        GetRemoteTasksResponse response;
-        while (reader->Read(&response)) {
-            std::shared_ptr<IRemoteTaskCallback> callback;
-            {
-                std::lock_guard<std::mutex> lockGuard(mLock);
-                callback = mRemoteTaskCallback;
-            }
-            if (callback == nullptr) {
-                continue;
-            }
-            ScopedAStatus callbackStatus = callback->onRemoteTaskRequested(
-                    response.clientid(), stringToBytes(response.data()));
-            if (!callbackStatus.isOk()) {
-                ALOGE("Failed to call onRemoteTaskRequested callback, status: %d, message: %s",
-                      callbackStatus.getStatus(), callbackStatus.getMessage());
-            }
-        }
-        Status status = reader->Finish();
-
-        ALOGE("GetRemoteTasks stream breaks, code: %d, message: %s, sleeping for 10s and retry",
-              status.error_code(), status.error_message().c_str());
-        // The long lasting connection should not return. But if the server returns, retry after
-        // 10s.
-        {
-            std::unique_lock lk(mLock);
-            if (mCv.wait_for(lk, std::chrono::milliseconds(mRetryWaitInMs), [this] {
-                    ScopedLockAssertion lockAssertion(mLock);
-                    return mTaskWaitStopped;
-                })) {
-                // If the stopped flag is set, we are quitting, exit the loop.
-                break;
-            }
-        }
-    }
-}
-
-ScopedAStatus RemoteAccessService::getDeviceId(std::string* deviceId) {
-    // TODO(b/241483300): Call VHAL to get VIN.
-    return ScopedAStatus::ok();
-}
-
-ScopedAStatus RemoteAccessService::getWakeupServiceName(std::string* wakeupServiceName) {
-    *wakeupServiceName = WAKEUP_SERVICE_NAME;
-    return ScopedAStatus::ok();
-}
-
-ScopedAStatus RemoteAccessService::setRemoteTaskCallback(
-        [[maybe_unused]] const std::shared_ptr<IRemoteTaskCallback>& callback) {
-    std::lock_guard<std::mutex> lockGuard(mLock);
-    mRemoteTaskCallback = callback;
-    return ScopedAStatus::ok();
-}
-
-ScopedAStatus RemoteAccessService::clearRemoteTaskCallback() {
-    std::lock_guard<std::mutex> lockGuard(mLock);
-    mRemoteTaskCallback.reset();
-    return ScopedAStatus::ok();
-}
-
-ScopedAStatus RemoteAccessService::notifyApStateChange(const ApState& newState) {
-    ClientContext context;
-    NotifyWakeupRequiredRequest request = {};
-    request.set_iswakeuprequired(newState.isWakeupRequired);
-    NotifyWakeupRequiredResponse response = {};
-    Status status = mGrpcStub->NotifyWakeupRequired(&context, request, &response);
-    if (!status.ok()) {
-        return rpcStatusToScopedAStatus(status, "Failed to notify isWakeupRequired");
-    }
-
-    if (newState.isReadyForRemoteTask) {
-        maybeStartTaskLoop();
-    } else {
-        maybeStopTaskLoop();
-    }
-    return ScopedAStatus::ok();
-}
-
-}  // namespace remoteaccess
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
diff --git a/automotive/remoteaccess/impl/default/proto/Android.bp b/automotive/remoteaccess/impl/default/proto/Android.bp
deleted file mode 100644
index 31b9d0e..0000000
--- a/automotive/remoteaccess/impl/default/proto/Android.bp
+++ /dev/null
@@ -1,81 +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 {
-    // 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"],
-}
-
-genrule {
-    name: "wakeup_client_pb_h",
-    tools: [
-        "aprotoc",
-        "protoc-gen-grpc-cpp-plugin",
-    ],
-    cmd: "$(location aprotoc) -I$$(dirname $(in)) -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)",
-    srcs: [
-        "wakeup_client.proto",
-    ],
-    out: [
-        "wakeup_client.pb.h",
-        "wakeup_client.grpc.pb.h",
-    ],
-    vendor: true,
-}
-
-genrule {
-    name: "wakeup_client_pb_cc",
-    tools: [
-        "aprotoc",
-        "protoc-gen-grpc-cpp-plugin",
-    ],
-    cmd: "$(location aprotoc) -I$$(dirname $(in)) -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)",
-    srcs: [
-        "wakeup_client.proto",
-    ],
-    out: [
-        "wakeup_client.pb.cc",
-        "wakeup_client.grpc.pb.cc",
-    ],
-    vendor: true,
-}
-
-cc_library_static {
-    name: "wakeup_client_protos",
-    vendor: true,
-    host_supported: true,
-    include_dirs: [
-        "external/protobuf/src",
-    ],
-    generated_headers: [
-        "wakeup_client_pb_h",
-    ],
-    export_generated_headers: [
-        "wakeup_client_pb_h",
-    ],
-    generated_sources: [
-        "wakeup_client_pb_cc",
-    ],
-    shared_libs: [
-        "libgrpc++",
-        "libprotobuf-cpp-full",
-    ],
-    cflags: [
-        "-Wno-unused-parameter",
-    ],
-}
diff --git a/automotive/remoteaccess/impl/default/test/Android.bp b/automotive/remoteaccess/impl/default/test/Android.bp
deleted file mode 100644
index e92440f..0000000
--- a/automotive/remoteaccess/impl/default/test/Android.bp
+++ /dev/null
@@ -1,43 +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 {
-    default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-cc_test {
-    name: "RemoteAccessServiceUnitTest",
-    vendor: true,
-    srcs: ["*.cpp"],
-    whole_static_libs: [
-        "RemoteAccessService",
-    ],
-    shared_libs: [
-        "libbinder_ndk",
-        "liblog",
-        "libutils",
-        "libgrpc++",
-        "libprotobuf-cpp-full",
-    ],
-    // libgrpc++.so is installed as root, require root to access it.
-    require_root: true,
-    static_libs: [
-        "libgtest",
-        "libgmock",
-    ],
-    cflags: [
-        "-Wno-unused-parameter",
-    ],
-    test_suites: ["device-tests"],
-}
diff --git a/automotive/remoteaccess/impl/default/test/RemoteAccessServiceUnitTest.cpp b/automotive/remoteaccess/impl/default/test/RemoteAccessServiceUnitTest.cpp
deleted file mode 100644
index 11523f6..0000000
--- a/automotive/remoteaccess/impl/default/test/RemoteAccessServiceUnitTest.cpp
+++ /dev/null
@@ -1,288 +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 "RemoteAccessService.h"
-
-#include <aidl/android/hardware/automotive/remoteaccess/ApState.h>
-#include <aidl/android/hardware/automotive/remoteaccess/BnRemoteTaskCallback.h>
-#include <gmock/gmock.h>
-#include <grpcpp/test/mock_stream.h>
-#include <gtest/gtest.h>
-#include <wakeup_client.grpc.pb.h>
-#include <chrono>
-#include <thread>
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace remoteaccess {
-
-using ::android::base::ScopedLockAssertion;
-
-using ::aidl::android::hardware::automotive::remoteaccess::ApState;
-using ::aidl::android::hardware::automotive::remoteaccess::BnRemoteTaskCallback;
-
-using ::grpc::ClientAsyncReaderInterface;
-using ::grpc::ClientAsyncResponseReaderInterface;
-using ::grpc::ClientContext;
-using ::grpc::ClientReader;
-using ::grpc::ClientReaderInterface;
-using ::grpc::CompletionQueue;
-using ::grpc::Status;
-using ::grpc::testing::MockClientReader;
-using ::ndk::ScopedAStatus;
-using ::testing::_;
-using ::testing::DoAll;
-using ::testing::Return;
-using ::testing::SetArgPointee;
-
-class MockGrpcClientStub : public WakeupClient::StubInterface {
-  public:
-    MOCK_METHOD(ClientReaderInterface<GetRemoteTasksResponse>*, GetRemoteTasksRaw,
-                (ClientContext * context, const GetRemoteTasksRequest& request));
-    MOCK_METHOD(Status, NotifyWakeupRequired,
-                (ClientContext * context, const NotifyWakeupRequiredRequest& request,
-                 NotifyWakeupRequiredResponse* response));
-    // Async methods which we do not care.
-    MOCK_METHOD(ClientAsyncReaderInterface<GetRemoteTasksResponse>*, AsyncGetRemoteTasksRaw,
-                (ClientContext * context, const GetRemoteTasksRequest& request, CompletionQueue* cq,
-                 void* tag));
-    MOCK_METHOD(ClientAsyncReaderInterface<GetRemoteTasksResponse>*, PrepareAsyncGetRemoteTasksRaw,
-                (ClientContext * context, const GetRemoteTasksRequest& request,
-                 CompletionQueue* cq));
-    MOCK_METHOD(ClientAsyncResponseReaderInterface<NotifyWakeupRequiredResponse>*,
-                AsyncNotifyWakeupRequiredRaw,
-                (ClientContext * context, const NotifyWakeupRequiredRequest& request,
-                 CompletionQueue* cq));
-    MOCK_METHOD(ClientAsyncResponseReaderInterface<NotifyWakeupRequiredResponse>*,
-                PrepareAsyncNotifyWakeupRequiredRaw,
-                (ClientContext * context, const NotifyWakeupRequiredRequest& request,
-                 CompletionQueue* cq));
-};
-
-class FakeRemoteTaskCallback : public BnRemoteTaskCallback {
-  public:
-    ScopedAStatus onRemoteTaskRequested(const std::string& clientId,
-                                        const std::vector<uint8_t>& data) override {
-        std::lock_guard<std::mutex> lockGuard(mLock);
-        mDataByClientId[clientId] = data;
-        mTaskCount++;
-        mCv.notify_all();
-        return ScopedAStatus::ok();
-    }
-
-    std::vector<uint8_t> getData(const std::string& clientId) { return mDataByClientId[clientId]; }
-
-    bool wait(size_t taskCount, size_t timeoutInSec) {
-        std::unique_lock<std::mutex> lock(mLock);
-        return mCv.wait_for(lock, std::chrono::seconds(timeoutInSec), [taskCount, this] {
-            ScopedLockAssertion lockAssertion(mLock);
-            return mTaskCount >= taskCount;
-        });
-    }
-
-  private:
-    std::mutex mLock;
-    std::unordered_map<std::string, std::vector<uint8_t>> mDataByClientId GUARDED_BY(mLock);
-    size_t mTaskCount GUARDED_BY(mLock) = 0;
-    std::condition_variable mCv;
-};
-
-class RemoteAccessServiceUnitTest : public ::testing::Test {
-  public:
-    virtual void SetUp() override {
-        mGrpcWakeupClientStub = std::make_unique<MockGrpcClientStub>();
-        mService = ndk::SharedRefBase::make<RemoteAccessService>(mGrpcWakeupClientStub.get());
-    }
-
-    MockGrpcClientStub* getGrpcWakeupClientStub() { return mGrpcWakeupClientStub.get(); }
-
-    RemoteAccessService* getService() { return mService.get(); }
-
-    void setRetryWaitInMs(size_t retryWaitInMs) { mService->setRetryWaitInMs(retryWaitInMs); }
-
-  private:
-    std::unique_ptr<MockGrpcClientStub> mGrpcWakeupClientStub;
-    std::shared_ptr<RemoteAccessService> mService;
-    MockClientReader<GetRemoteTasksResponse>* mMockTaskReader;
-};
-
-TEST_F(RemoteAccessServiceUnitTest, TestGetWakeupServiceName) {
-    std::string serviceName;
-
-    ScopedAStatus status = getService()->getWakeupServiceName(&serviceName);
-
-    EXPECT_TRUE(status.isOk());
-    EXPECT_EQ(serviceName, "com.google.vehicle.wakeup");
-}
-
-TEST_F(RemoteAccessServiceUnitTest, TestNotifyApStateChangeWakeupRequired) {
-    bool isWakeupRequired = false;
-    EXPECT_CALL(*getGrpcWakeupClientStub(), NotifyWakeupRequired)
-            .WillOnce([&isWakeupRequired]([[maybe_unused]] ClientContext* context,
-                                          const NotifyWakeupRequiredRequest& request,
-                                          [[maybe_unused]] NotifyWakeupRequiredResponse* response) {
-                isWakeupRequired = request.iswakeuprequired();
-                return Status();
-            });
-
-    ApState newState = {
-            .isWakeupRequired = true,
-    };
-    ScopedAStatus status = getService()->notifyApStateChange(newState);
-
-    EXPECT_TRUE(status.isOk());
-    EXPECT_TRUE(isWakeupRequired);
-}
-
-TEST_F(RemoteAccessServiceUnitTest, TestGetRemoteTasks) {
-    GetRemoteTasksResponse response1;
-    std::vector<uint8_t> testData = {0xde, 0xad, 0xbe, 0xef};
-    response1.set_clientid("1");
-    response1.set_data(testData.data(), testData.size());
-    GetRemoteTasksResponse response2;
-    response2.set_clientid("2");
-    std::shared_ptr<FakeRemoteTaskCallback> callback =
-            ndk::SharedRefBase::make<FakeRemoteTaskCallback>();
-
-    ON_CALL(*getGrpcWakeupClientStub(), GetRemoteTasksRaw)
-            .WillByDefault(
-                    [response1, response2]([[maybe_unused]] ClientContext* context,
-                                           [[maybe_unused]] const GetRemoteTasksRequest& request) {
-                        // mockReader ownership will be transferred to the client so we don't own it
-                        // here.
-                        MockClientReader<GetRemoteTasksResponse>* mockClientReader =
-                                new MockClientReader<GetRemoteTasksResponse>();
-                        EXPECT_CALL(*mockClientReader, Finish()).WillOnce(Return(Status::OK));
-                        EXPECT_CALL(*mockClientReader, Read(_))
-                                .WillOnce(DoAll(SetArgPointee<0>(response1), Return(true)))
-                                .WillOnce(DoAll(SetArgPointee<0>(response2), Return(true)))
-                                .WillRepeatedly(Return(false));
-                        return mockClientReader;
-                    });
-
-    getService()->setRemoteTaskCallback(callback);
-    // Start the long live connection to receive tasks.
-    ApState newState = {
-            .isReadyForRemoteTask = true,
-    };
-    ASSERT_TRUE(getService()->notifyApStateChange(newState).isOk());
-
-    ASSERT_TRUE(callback->wait(/*taskCount=*/2, /*timeoutInSec=*/10))
-            << "Did not receive enough tasks";
-    EXPECT_EQ(callback->getData("1"), testData);
-    EXPECT_EQ(callback->getData("2"), std::vector<uint8_t>());
-}
-
-TEST_F(RemoteAccessServiceUnitTest, TestGetRemoteTasksRetryConnection) {
-    GetRemoteTasksResponse response;
-    std::shared_ptr<FakeRemoteTaskCallback> callback =
-            ndk::SharedRefBase::make<FakeRemoteTaskCallback>();
-
-    ON_CALL(*getGrpcWakeupClientStub(), GetRemoteTasksRaw)
-            .WillByDefault([response]([[maybe_unused]] ClientContext* context,
-                                      [[maybe_unused]] const GetRemoteTasksRequest& request) {
-                // mockReader ownership will be transferred to the client so we don't own it here.
-                MockClientReader<GetRemoteTasksResponse>* mockClientReader =
-                        new MockClientReader<GetRemoteTasksResponse>();
-                EXPECT_CALL(*mockClientReader, Finish()).WillOnce(Return(Status::OK));
-                // Connection fails after receiving one task. Should retry after some time.
-                EXPECT_CALL(*mockClientReader, Read(_))
-                        .WillOnce(DoAll(SetArgPointee<0>(response), Return(true)))
-                        .WillRepeatedly(Return(false));
-                return mockClientReader;
-            });
-
-    getService()->setRemoteTaskCallback(callback);
-    setRetryWaitInMs(100);
-    // Start the long live connection to receive tasks.
-    ApState newState = {
-            .isReadyForRemoteTask = true,
-    };
-    ASSERT_TRUE(getService()->notifyApStateChange(newState).isOk());
-
-    ASSERT_TRUE(callback->wait(/*taskCount=*/2, /*timeoutInSec=*/10))
-            << "Did not receive enough tasks";
-}
-
-TEST_F(RemoteAccessServiceUnitTest, TestGetRemoteTasksDefaultNotReady) {
-    GetRemoteTasksResponse response1;
-    std::vector<uint8_t> testData = {0xde, 0xad, 0xbe, 0xef};
-    response1.set_clientid("1");
-    response1.set_data(testData.data(), testData.size());
-    GetRemoteTasksResponse response2;
-    response2.set_clientid("2");
-    std::shared_ptr<FakeRemoteTaskCallback> callback =
-            ndk::SharedRefBase::make<FakeRemoteTaskCallback>();
-
-    EXPECT_CALL(*getGrpcWakeupClientStub(), GetRemoteTasksRaw).Times(0);
-
-    // Default state is not ready for remote tasks, so no callback will be called.
-    getService()->setRemoteTaskCallback(callback);
-
-    std::this_thread::sleep_for(std::chrono::milliseconds(100));
-}
-
-TEST_F(RemoteAccessServiceUnitTest, TestGetRemoteTasksNotReadyAfterReady) {
-    GetRemoteTasksResponse response1;
-    std::vector<uint8_t> testData = {0xde, 0xad, 0xbe, 0xef};
-    response1.set_clientid("1");
-    response1.set_data(testData.data(), testData.size());
-    GetRemoteTasksResponse response2;
-    response2.set_clientid("2");
-    std::shared_ptr<FakeRemoteTaskCallback> callback =
-            ndk::SharedRefBase::make<FakeRemoteTaskCallback>();
-
-    ON_CALL(*getGrpcWakeupClientStub(), GetRemoteTasksRaw)
-            .WillByDefault(
-                    [response1, response2]([[maybe_unused]] ClientContext* context,
-                                           [[maybe_unused]] const GetRemoteTasksRequest& request) {
-                        // mockReader ownership will be transferred to the client so we don't own it
-                        // here.
-                        MockClientReader<GetRemoteTasksResponse>* mockClientReader =
-                                new MockClientReader<GetRemoteTasksResponse>();
-                        EXPECT_CALL(*mockClientReader, Finish()).WillOnce(Return(Status::OK));
-                        EXPECT_CALL(*mockClientReader, Read(_))
-                                .WillOnce(DoAll(SetArgPointee<0>(response1), Return(true)))
-                                .WillOnce(DoAll(SetArgPointee<0>(response2), Return(true)))
-                                .WillRepeatedly(Return(false));
-                        return mockClientReader;
-                    });
-    // Should only be called once when is is ready for remote task.
-    EXPECT_CALL(*getGrpcWakeupClientStub(), GetRemoteTasksRaw).Times(1);
-
-    getService()->setRemoteTaskCallback(callback);
-    setRetryWaitInMs(100);
-    // Start the long live connection to receive tasks.
-    ApState newState = {
-            .isReadyForRemoteTask = true,
-    };
-    ASSERT_TRUE(getService()->notifyApStateChange(newState).isOk());
-    ASSERT_TRUE(callback->wait(/*taskCount=*/2, /*timeoutInSec=*/10))
-            << "Did not receive enough tasks";
-
-    // Stop the long live connection.
-    newState.isReadyForRemoteTask = false;
-    ASSERT_TRUE(getService()->notifyApStateChange(newState).isOk());
-
-    // Wait for the retry delay, but the loop should already exit.
-    std::this_thread::sleep_for(std::chrono::milliseconds(150));
-}
-
-}  // namespace remoteaccess
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
diff --git a/automotive/remoteaccess/test_grpc_server/README.md b/automotive/remoteaccess/test_grpc_server/README.md
new file mode 100644
index 0000000..6bc1829
--- /dev/null
+++ b/automotive/remoteaccess/test_grpc_server/README.md
@@ -0,0 +1,314 @@
+# Test GRPC Server.
+
+A test GRPC server that implements wakeup_client.proto. This test server acts
+as a reference implementation for a remote wakeup client running on TCU. The
+test server does not communicate with any actual network server. It has the
+following behavior:
+
+* It starts a GRPC server on 'DGRPC_SERVICE_ADDRESS' compile flag which is
+  localhost:50051. The GRPC server provides the service according to
+  hardware/interfaces/automotive/remoteaccess/hal/default/proto/wakeup_client.proto.
+
+  In real implementation, DGRPC_SERVICE_ADDRESS can be specified to any IP
+  address where the TCU can be exposed to Application Processor. The default
+  remote access HAL implementation
+  (hardware/interfaces/automotive/remoteaccess/hal/default/Android.bp) also
+  uses DGRPC_SERVICE_ADDRESS to find this GRPC server, so it must have the
+  same IP address.
+
+* It generates a fake task using FakeTaskGenerator every 'kTaskIntervalInMs' ms.
+
+  In real implementation, it should receive task from the remote server.
+
+* Each fake task has an increasing unique client ID. The task data is always
+  what's defined for 'DATA' variable.
+
+  In real implementation, the client ID and task data should come from the
+  remote server.
+
+* The generated tasks are put into a task queue which is a priority queue sorted
+  by task received time.
+
+  In real implementation, if the server provides a task timestamp, then this
+  queue can be sorted by that task timestamp instead.
+
+* When the Application processor is started, the remote access HAL running on
+  Android will call 'GetRemoteTasks' to establish a long-live connection. This
+  connection is used to deliver all task data from remote wakeup client to
+  remote access HAL, which eventually to car service and applications.
+
+  When the 'GetRemoteTasks' is called, the wakeup client must send all the
+  pending tasks through the 'ServerWriter'. If no task is pending, then it must
+  block and wait for a new task to arrive.
+
+  If one task data fails to be sent through the channel, it likely means
+  the other side (Application processor) is shutting down or has closed the
+  channel. The wakeup client must put the task back to the pending queue and
+  wait for a new 'GetRemoteTasks' request to retry sending the task.
+
+* When a new task arrives, if 'WakeupRequired' is true, then try to wakeup
+  the Application Processor by sending a specific CAN message. It is possible that
+  the waking up is already in progress. This is okay since Vehicle Processor
+  should ignore wakeup message if a wakeup is already in progress.
+
+* When 'WakeupRequired' is updated from false to true, if there are unexpired
+  pending tasks in the task queue, try to wakeup Application Processor.
+
+  This is to handle the situation when a task arrives while the device is
+  shutting down. During the device shutdown, the channel to deliver the remote
+  tasks to Application Processor is shutdown so the new task will be added to the
+  task queue. 'WakeupRequired' will be set to false to prevent the wakeup
+  message preventing the shutdown. After the shutdown is complete,
+  'WakeupRequired' will be set to true and this wakeup client must try to wake
+  up the device again to execute the pending tasks.
+
+* Every pending task has a timeout: 'kTaskTimeoutInMs'. If the pending task
+  is not delivered to remote access HAL before the timeout (through
+  GetRemoteTasks), the task timed out and a warning message is logged.
+
+  In real implementation, this kTaskTimeoutInMs has to be set long enough to
+  allow an Android bootup to happen. 20s is a reasonable value. When a task
+  timed out, the wakeup client should also report to remote task server about
+  the task timeout failure.
+
+## How to build the test wakeup client
+
+* Under android root: `source build/envsetup.sh`
+
+* `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:
+
+  `adb root`
+
+  `adb remount` (remount might take a while)
+
+  `adb reboot`
+
+  `adb root`
+
+  `adb remount`
+
+* Under android root: `cd $ANDROID_PRODUCT_OUT`
+
+* `adb push vendor/bin/TestWakeupClientServer /vendor/bin`
+
+* `adb push vendor/lib/ApPowerControlLib.so /vendor/lib`
+
+* `adb shell`
+
+* `su`
+
+* `/vendor/bin/TestWakeupClientServer`
+
+## How to build and test the test wakeup client using one car emulator.
+
+In this test setup we will use one car emulator
+(sdk_car_x86_64-userdebug). We assume both the TCU and the remote access HAL
+runs on the same Android system, and they communicate through local loopback
+interface.
+
+* Under android root, `source build/envsetup.sh`
+
+* `lunch sdk_car_x86_64-userdebug`
+
+* `m -j`
+
+* Run the emulator, the '-read-only' flag is required to run multiple instances:
+
+  `emulator -writable-system -read-only`
+
+* The android lunch target: sdk_car_x86_64-userdebug and
+  cf_x86_64_auto-userdebug already contains the default remote access HAL. For
+  other lunch target, you can add the default remote access HAL by adding
+  'android.hardware.automotive.remoteaccess@V1-default-service' to
+  'PRODUCT_PACKAGES' variable in mk file, see `device/generic/car/common/car.mk`
+  as example.
+
+  To verify whether remote access HAL is running, you can use the following
+  command to check:
+
+  `dumpsys android.hardware.automotive.remoteaccess.IRemoteAccess/default`
+
+* Make the target device writable:
+
+  `adb root`
+
+  `adb remount` (remount might take a while)
+
+  `adb reboot`
+
+  `adb root`
+
+  `adb remount`
+
+* `make -j TestWakeupClientServer`
+
+* `adb push $ANDROID_PRODUCT_OUT/vendor/bin/TestWakeupClientServer /vendor/bin`
+
+* `adb shell`
+
+* `emulator_car_x86_64:/ # su`
+
+* `emulator_car_x86_64:/ # /vendor/bin/TestWakeupClientServer`
+
+* Remote access HAL should start by default when the car emulator starts. Now
+  the test wake up client should also be running and generating fake tasks.
+
+  Start a new session under android root
+
+  `source build/envsetup.sh`
+
+  `lunch sdk_car_x86_64-userdebug`
+
+  `adb shell`
+
+  `emulator_car_x86_64:/ # su`
+
+* Issue the command to start a simple debug callback that will capture all the
+  received tasks at the remote access HAL side:
+
+  `emulator_car_x86_64:/ # dumpsys android.hardware.automotive.remoteaccess.IRemoteAccess/default --start-debug-callback`
+
+* Issue the following debug command to remote access HAL to establish the
+  communication channel between it and the test wakeup client. This command
+  also notifies that wakeup is not required:
+
+  `emulator_car_x86_64:/ # dumpsys android.hardware.automotive.remoteaccess.IRemoteAccess/default --set-ap-state 1 0`
+
+* Wait for a while, issue the following command to show the received fake tasks:
+
+  `emulator_car_x86_64:/ # dumpsys android.hardware.automotive.remoteaccess.IRemoteAccess/default --show-task`
+
+  You should expect to see some received tasks printed out.
+
+* Simulate the Application Processor is shutting down by issuing the following
+  command:
+
+  `emulator_car_x86_64:/ # dumpsys android.hardware.automotive.remoteaccess.IRemoteAccess/default --set-ap-state 0 0`
+
+* Wait for a while, issue the following command to show received tasks again:
+
+  `emulator_car_x86_64:/ # dumpsys android.hardware.automotive.remoteaccess.IRemoteAccess/default --show-task`
+
+  You should expect to see no new tasks received since remote access HAL already
+  closed the communication channel.
+
+* Simulate the Application Processor is already shutdown and wake up is required
+  now:
+
+  `emulator_car_x86_64:/ # dumpsys android.hardware.automotive.remoteaccess.IRemoteAccess/default --set-ap-state 0 1`
+
+  Now you should expect to see the test wakeup client printing out messages
+  that it is trying to wake up application processor.
+
+* Simulate the Application Processor is waken up:
+
+  `emulator_car_x86_64:/ # dumpsys android.hardware.automotive.remoteaccess.IRemoteAccess/default --set-ap-state 1 0`
+
+* A new communication channel should have been established and all pending
+  non-expired tasks should be delivered to the remote access HAL.
+
+  `emulator_car_x86_64:/ # dumpsys android.hardware.automotive.remoteaccess.IRemoteAccess/default --show-task`
+
+* Now you can issue `ctrl c` on the first adb shell to stop the test wakeup
+  client.
+
+* After the test, you can use `ctrl D` to exit the adb shell.
+
+## How to build and test the test wakeup client using two car emulators.
+
+In this test case, we are going to use two car emulators, one as the
+Application Processor, one as the TCU.
+
+* Change the IP address to allow IP communication between different emulator
+  instances. For detail about why we change it this way, see [interconnecting
+  emulator instance](https://developer.android.com/studio/run/emulator-networking#connecting).
+
+  Change 'DGRPC_SERVICE_ADDRESS' in `[android_root]/hardware/interfaces/automotive/remoteaccess/test_grpc_server/impl/Android.bp` to
+  `10.0.2.15:50051`.
+
+  Change `DGRPC_SERVICE_ADDRESS` in '[android_root]/hardware/interfaces/automotive/remoteaccess/hal/defaut/Android.bp' to
+  `10.0.2.2:50051`.
+
+* Under android root: `source build/envsetup.sh`
+
+* `lunch sdk_car_x86_64-userdebug`
+
+*  `m -j`
+
+* Start one car emulator as TCU
+
+  `emulator -writable-system -read-only`
+
+* Start a new shell session. Connect to the emulator's console,
+  see [Start and stop a console session](https://developer.android.com/studio/run/emulator-console#console-session)
+  for detail.
+
+  `telnet localhost 5554`
+
+* `auth auth_token` where auth_token must match the contents of the
+  `~/.emulator_console_auth_token` file.
+
+* `redir add tcp:50051:50051`
+
+* Exit the telnet session using 'ctrl-C'
+
+  Make the target device writable:
+
+  Under android root:
+
+  `source build/envsetup.sh`
+
+  `lunch sdk_car_x86_64-userdebug`
+
+  `adb root`
+
+  `adb remount` (remount might take a while)
+
+  `adb reboot`
+
+  `adb root`
+
+  `adb remount`
+
+* `make -j TestWakeupClientServer`
+
+* `adb push $ANDROID_PRODUCT_OUT/vendor/bin/TestWakeupClientServer /vendor/bin`
+
+* `adb shell`
+
+* `emulator_car_x86_64:/ # su`
+
+* `emulator_car_x86_64:/ # /vendor/bin/TestWakeupClientServer`
+
+* Start a new shell under android root, start another car emulator as the Application Processor:
+
+  `source build/envsetup.sh`
+
+  `lunch sdk_car_x86_64-userdebug`
+
+  `emulator -writable-system -read-only`
+
+* Open a new shell under android root:
+
+  `source build/envsetup.sh`
+
+  `lunch sdk_car_x86_64-userdebug`
+
+* Connect to adb shell for the application processor:
+
+  `adb -s emulator-5556 shell`
+
+  `emulator_car_x86_64:/ # su`
+
+* Follow the test instructions for one car emulator using the 'dumpsys'
+  commands.
+
+* After the test, you can use `ctrl D` to exit the adb shell.
diff --git a/automotive/remoteaccess/test_grpc_server/impl/Android.bp b/automotive/remoteaccess/test_grpc_server/impl/Android.bp
new file mode 100644
index 0000000..152b528
--- /dev/null
+++ b/automotive/remoteaccess/test_grpc_server/impl/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: "TestWakeupClientServer",
+    vendor: true,
+    srcs: ["src/*.cpp"],
+    local_include_dirs: ["include"],
+    shared_libs: [
+        "libbase",
+        "libutils",
+        "libgrpc++",
+        "libprotobuf-cpp-full",
+        "//hardware/interfaces/automotive/remoteaccess/test_grpc_server/lib:ApPowerControlLib",
+    ],
+    whole_static_libs: [
+        "wakeup_client_protos",
+    ],
+    cflags: [
+        "-Wno-unused-parameter",
+        "-DGRPC_SERVICE_ADDRESS=\"localhost:50051\"",
+    ],
+}
diff --git a/automotive/remoteaccess/test_grpc_server/impl/include/TestWakeupClientServiceImpl.h b/automotive/remoteaccess/test_grpc_server/impl/include/TestWakeupClientServiceImpl.h
new file mode 100644
index 0000000..6b86b35
--- /dev/null
+++ b/automotive/remoteaccess/test_grpc_server/impl/include/TestWakeupClientServiceImpl.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/thread_annotations.h>
+#include <utils/Looper.h>
+#include <wakeup_client.grpc.pb.h>
+#include <condition_variable>
+#include <mutex>
+#include <queue>
+#include <string>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace remoteaccess {
+
+// A class to generate fake task for testing. Not required for real implementation. In real
+// implementation, the task should come from remote task server. This class is thread-safe.
+class FakeTaskGenerator final {
+  public:
+    GetRemoteTasksResponse generateTask();
+
+  private:
+    // Simulates the client ID for each task.
+    std::atomic<int> mCurrentClientId = 0;
+    constexpr static uint8_t DATA[] = {0xde, 0xad, 0xbe, 0xef};
+};
+
+struct TaskInfo {
+    // This is unique per-task. Note that a task might be popped and put back into the task queue,
+    // it will have a new task ID but the same clientId in the task data.
+    int taskId;
+    int64_t timestampInMs;
+    GetRemoteTasksResponse taskData;
+};
+
+struct TaskInfoComparator {
+    // We want the smallest timestamp and smallest task ID on top.
+    bool operator()(const TaskInfo& l, const TaskInfo& r) {
+        return l.timestampInMs > r.timestampInMs ||
+               (l.timestampInMs == r.timestampInMs && l.taskId > r.taskId);
+    }
+};
+
+// forward-declaration.
+class TaskQueue;
+
+class TaskTimeoutMessageHandler final : public android::MessageHandler {
+  public:
+    TaskTimeoutMessageHandler(TaskQueue* taskQueue);
+    void handleMessage(const android::Message& message) override;
+
+  private:
+    TaskQueue* mTaskQueue;
+};
+
+// TaskQueue is thread-safe.
+class TaskQueue final {
+  public:
+    TaskQueue();
+    ~TaskQueue();
+
+    void add(const GetRemoteTasksResponse& response);
+    std::optional<GetRemoteTasksResponse> maybePopOne();
+    void waitForTask();
+    void stopWait();
+    void handleTaskTimeout();
+    bool isEmpty();
+
+  private:
+    std::thread mCheckTaskTimeoutThread;
+    std::mutex mLock;
+    std::priority_queue<TaskInfo, std::vector<TaskInfo>, TaskInfoComparator> mTasks
+            GUARDED_BY(mLock);
+    // A variable to notify mTasks is not empty.
+    std::condition_variable mTasksNotEmptyCv;
+    bool mStopped GUARDED_BY(mLock);
+    android::sp<Looper> mLooper;
+    android::sp<TaskTimeoutMessageHandler> mTaskTimeoutMessageHandler;
+    std::atomic<int> mTaskIdCounter = 0;
+
+    void checkForTestTimeoutLoop();
+    void waitForTaskWithLock(std::unique_lock<std::mutex>& lock);
+};
+
+class TestWakeupClientServiceImpl final : public WakeupClient::Service {
+  public:
+    TestWakeupClientServiceImpl();
+
+    ~TestWakeupClientServiceImpl();
+
+    grpc::Status GetRemoteTasks(grpc::ServerContext* context, const GetRemoteTasksRequest* request,
+                                grpc::ServerWriter<GetRemoteTasksResponse>* writer) override;
+
+    grpc::Status NotifyWakeupRequired(grpc::ServerContext* context,
+                                      const NotifyWakeupRequiredRequest* request,
+                                      NotifyWakeupRequiredResponse* response) override;
+
+  private:
+    // This is a thread for communicating with remote wakeup server (via network) and receive tasks
+    // from it.
+    std::thread mThread;
+    // A variable to notify server is stopping.
+    std::condition_variable mServerStoppedCv;
+    // Whether wakeup AP is required for executing tasks.
+    std::atomic<bool> mWakeupRequired = true;
+    std::mutex mLock;
+    bool mServerStopped GUARDED_BY(mLock);
+
+    // Thread-safe. For test impl only.
+    FakeTaskGenerator mFakeTaskGenerator;
+    // Thread-sfae.
+    TaskQueue mTaskQueue;
+
+    void fakeTaskGenerateLoop();
+
+    void wakeupApplicationProcessor();
+};
+
+}  // namespace remoteaccess
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/remoteaccess/test_grpc_server/impl/src/TestWakeupClientServiceImpl.cpp b/automotive/remoteaccess/test_grpc_server/impl/src/TestWakeupClientServiceImpl.cpp
new file mode 100644
index 0000000..7dcd31e
--- /dev/null
+++ b/automotive/remoteaccess/test_grpc_server/impl/src/TestWakeupClientServiceImpl.cpp
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "TestWakeupClientServiceImpl.h"
+
+#include "ApPowerControl.h"
+
+#include <android-base/stringprintf.h>
+#include <inttypes.h>
+#include <utils/Looper.h>
+#include <utils/SystemClock.h>
+#include <chrono>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace remoteaccess {
+
+namespace {
+
+using ::android::uptimeMillis;
+using ::android::base::ScopedLockAssertion;
+using ::android::base::StringPrintf;
+using ::grpc::ServerContext;
+using ::grpc::ServerWriter;
+using ::grpc::Status;
+
+constexpr int kTaskIntervalInMs = 5'000;
+constexpr int64_t KTaskTimeoutInMs = 20'000;
+
+}  // namespace
+
+GetRemoteTasksResponse FakeTaskGenerator::generateTask() {
+    int clientId = mCurrentClientId++;
+    GetRemoteTasksResponse response;
+    response.set_data(std::string(reinterpret_cast<const char*>(DATA), sizeof(DATA)));
+    std::string clientIdStr = StringPrintf("%d", clientId);
+    response.set_clientid(clientIdStr);
+    return response;
+}
+
+TaskTimeoutMessageHandler::TaskTimeoutMessageHandler(TaskQueue* taskQueue)
+    : mTaskQueue(taskQueue) {}
+
+void TaskTimeoutMessageHandler::handleMessage(const android::Message& message) {
+    mTaskQueue->handleTaskTimeout();
+}
+
+TaskQueue::TaskQueue() {
+    mTaskTimeoutMessageHandler = android::sp<TaskTimeoutMessageHandler>::make(this);
+    mLooper = Looper::prepare(/*opts=*/0);
+    mCheckTaskTimeoutThread = std::thread([this] { checkForTestTimeoutLoop(); });
+}
+
+TaskQueue::~TaskQueue() {
+    {
+        std::lock_guard<std::mutex> lockGuard(mLock);
+        mStopped = true;
+    }
+    while (true) {
+        // Remove all pending timeout handlers from queue.
+        if (!maybePopOne().has_value()) {
+            break;
+        }
+    }
+    if (mCheckTaskTimeoutThread.joinable()) {
+        mCheckTaskTimeoutThread.join();
+    }
+}
+
+std::optional<GetRemoteTasksResponse> TaskQueue::maybePopOne() {
+    std::lock_guard<std::mutex> lockGuard(mLock);
+    if (mTasks.size() == 0) {
+        return std::nullopt;
+    }
+    TaskInfo response = std::move(mTasks.top());
+    mTasks.pop();
+    mLooper->removeMessages(mTaskTimeoutMessageHandler, response.taskId);
+    return std::move(response.taskData);
+}
+
+void TaskQueue::add(const GetRemoteTasksResponse& task) {
+    std::lock_guard<std::mutex> lockGuard(mLock);
+    if (mStopped) {
+        return;
+    }
+    int taskId = mTaskIdCounter++;
+    mTasks.push(TaskInfo{
+            .taskId = taskId,
+            .timestampInMs = uptimeMillis(),
+            .taskData = task,
+    });
+    android::Message message(taskId);
+    mLooper->sendMessageDelayed(KTaskTimeoutInMs * 1000, mTaskTimeoutMessageHandler, message);
+    mTasksNotEmptyCv.notify_all();
+}
+
+void TaskQueue::waitForTask() {
+    std::unique_lock<std::mutex> lock(mLock);
+    waitForTaskWithLock(lock);
+}
+
+void TaskQueue::waitForTaskWithLock(std::unique_lock<std::mutex>& lock) {
+    mTasksNotEmptyCv.wait(lock, [this] {
+        ScopedLockAssertion lockAssertion(mLock);
+        return mTasks.size() > 0 || mStopped;
+    });
+}
+
+void TaskQueue::stopWait() {
+    std::lock_guard<std::mutex> lockGuard(mLock);
+    mStopped = true;
+    mTasksNotEmptyCv.notify_all();
+}
+
+bool TaskQueue::isEmpty() {
+    std::lock_guard<std::mutex> lockGuard(mLock);
+    return mTasks.size() == 0 || mStopped;
+}
+
+void TaskQueue::checkForTestTimeoutLoop() {
+    Looper::setForThread(mLooper);
+
+    while (true) {
+        {
+            std::unique_lock<std::mutex> lock(mLock);
+            if (mStopped) {
+                return;
+            }
+        }
+
+        mLooper->pollAll(/*timeoutMillis=*/-1);
+    }
+}
+
+void TaskQueue::handleTaskTimeout() {
+    // We know which task timed-out from the taskId in the message. However, there is no easy way
+    // to remove a specific task with the task ID from the priority_queue, so we just check from
+    // the top of the queue (which have the oldest tasks).
+    std::lock_guard<std::mutex> lockGuard(mLock);
+    int64_t now = uptimeMillis();
+    while (mTasks.size() > 0) {
+        const TaskInfo& taskInfo = mTasks.top();
+        if (taskInfo.timestampInMs + KTaskTimeoutInMs > now) {
+            break;
+        }
+        // In real implementation, this should report task failure to remote wakeup server.
+        printf("Task for client ID: %s timed-out, added at %" PRId64 " ms, now %" PRId64 " ms",
+               taskInfo.taskData.clientid().c_str(), taskInfo.timestampInMs, now);
+        mTasks.pop();
+    }
+}
+
+TestWakeupClientServiceImpl::TestWakeupClientServiceImpl() {
+    mThread = std::thread([this] { fakeTaskGenerateLoop(); });
+}
+
+TestWakeupClientServiceImpl::~TestWakeupClientServiceImpl() {
+    {
+        std::lock_guard<std::mutex> lockGuard(mLock);
+        mServerStopped = true;
+        mServerStoppedCv.notify_all();
+    }
+    mTaskQueue.stopWait();
+    if (mThread.joinable()) {
+        mThread.join();
+    }
+}
+
+void TestWakeupClientServiceImpl::fakeTaskGenerateLoop() {
+    // In actual implementation, this should communicate with the remote server and receives tasks
+    // from it. Here we simulate receiving one remote task every {kTaskIntervalInMs}ms.
+    while (true) {
+        mTaskQueue.add(mFakeTaskGenerator.generateTask());
+        printf("Received a new task\n");
+        if (mWakeupRequired) {
+            wakeupApplicationProcessor();
+        }
+
+        printf("Sleeping for %d seconds until next task\n", kTaskIntervalInMs);
+
+        std::unique_lock lk(mLock);
+        if (mServerStoppedCv.wait_for(lk, std::chrono::milliseconds(kTaskIntervalInMs), [this] {
+                ScopedLockAssertion lockAssertion(mLock);
+                return mServerStopped;
+            })) {
+            // If the stopped flag is set, we are quitting, exit the loop.
+            return;
+        }
+    }
+}
+
+Status TestWakeupClientServiceImpl::GetRemoteTasks(ServerContext* context,
+                                                   const GetRemoteTasksRequest* request,
+                                                   ServerWriter<GetRemoteTasksResponse>* writer) {
+    printf("GetRemoteTasks called\n");
+    while (true) {
+        mTaskQueue.waitForTask();
+
+        while (true) {
+            auto maybeTask = mTaskQueue.maybePopOne();
+            if (!maybeTask.has_value()) {
+                // No task left, loop again and wait for another task(s).
+                break;
+            }
+            // Loop through all the task in the queue but obtain lock for each element so we don't
+            // hold lock while writing the response.
+            const GetRemoteTasksResponse& response = maybeTask.value();
+            if (!writer->Write(response)) {
+                // Broken stream, maybe the client is shutting down.
+                printf("Failed to deliver remote task to remote access HAL\n");
+                // The task failed to be sent, add it back to the queue. The order might change, but
+                // it is okay.
+                mTaskQueue.add(response);
+                return Status::CANCELLED;
+            }
+        }
+    }
+    return Status::OK;
+}
+
+Status TestWakeupClientServiceImpl::NotifyWakeupRequired(ServerContext* context,
+                                                         const NotifyWakeupRequiredRequest* request,
+                                                         NotifyWakeupRequiredResponse* response) {
+    if (request->iswakeuprequired() && !mWakeupRequired && !mTaskQueue.isEmpty()) {
+        // If wakeup is now required and previously not required, this means we have finished
+        // shutting down the device. If there are still pending tasks, try waking up AP again
+        // to finish executing those tasks.
+        wakeupApplicationProcessor();
+    }
+    mWakeupRequired = request->iswakeuprequired();
+    return Status::OK;
+}
+
+void TestWakeupClientServiceImpl::wakeupApplicationProcessor() {
+    wakeupAp();
+}
+
+}  // namespace remoteaccess
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/remoteaccess/test_grpc_server/impl/src/main.cpp b/automotive/remoteaccess/test_grpc_server/impl/src/main.cpp
new file mode 100644
index 0000000..52698b5
--- /dev/null
+++ b/automotive/remoteaccess/test_grpc_server/impl/src/main.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 <string>
+
+#include "TestWakeupClientServiceImpl.h"
+
+#include <grpc/grpc.h>
+#include <grpcpp/security/server_credentials.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+
+using ::android::hardware::automotive::remoteaccess::TestWakeupClientServiceImpl;
+using ::grpc::Server;
+using ::grpc::ServerBuilder;
+using ::grpc::ServerWriter;
+
+void RunServer() {
+    std::string serverAddress(GRPC_SERVICE_ADDRESS);
+    std::shared_ptr<TestWakeupClientServiceImpl> service =
+            std::make_unique<TestWakeupClientServiceImpl>();
+
+    ServerBuilder builder;
+    builder.AddListeningPort(serverAddress, 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());
+    server->Wait();
+}
+
+int main(int argc, char** argv) {
+    RunServer();
+    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..9e4f252 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
@@ -5326,10 +5324,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/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleApPowerBootupReason.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleApPowerBootupReason.aidl
new file mode 100644
index 0000000..9720aca
--- /dev/null
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleApPowerBootupReason.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.automotive.vehicle;
+@Backing(type="int") @VintfStability
+enum VehicleApPowerBootupReason {
+  USER_POWER_ON = 0,
+  SYSTEM_USER_DETECTION = 1,
+  SYSTEM_REMOTE_ACCESS = 2,
+}
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 64c7ce7..24fd518 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
@@ -119,12 +119,15 @@
   DOOR_POS = 373295872,
   DOOR_MOVE = 373295873,
   DOOR_LOCK = 371198722,
+  DOOR_CHILD_LOCK_ENABLED = 371198723,
   MIRROR_Z_POS = 339741504,
   MIRROR_Z_MOVE = 339741505,
   MIRROR_Y_POS = 339741506,
   MIRROR_Y_MOVE = 339741507,
   MIRROR_LOCK = 287312708,
   MIRROR_FOLD = 287312709,
+  MIRROR_AUTO_FOLD_ENABLED = 337644358,
+  MIRROR_AUTO_TILT_ENABLED = 337644359,
   SEAT_MEMORY_SELECT = 356518784,
   SEAT_MEMORY_SET = 356518785,
   SEAT_BELT_BUCKLED = 354421634,
@@ -152,10 +155,23 @@
   SEAT_HEADREST_ANGLE_MOVE = 356518808,
   SEAT_HEADREST_FORE_AFT_POS = 356518809,
   SEAT_HEADREST_FORE_AFT_MOVE = 356518810,
+  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_OCCUPANCY = 356518832,
   WINDOW_POS = 322964416,
   WINDOW_MOVE = 322964417,
   WINDOW_LOCK = 320867268,
+  STEERING_WHEEL_DEPTH_POS = 289410016,
+  STEERING_WHEEL_DEPTH_MOVE = 289410017,
+  STEERING_WHEEL_HEIGHT_POS = 289410018,
+  STEERING_WHEEL_HEIGHT_MOVE = 289410019,
+  STEERING_WHEEL_THEFT_LOCK_ENABLED = 287312868,
+  STEERING_WHEEL_LOCKED = 287312869,
+  STEERING_WHEEL_EASY_ACCESS_ENABLED = 287312870,
   VEHICLE_MAP_SERVICE = 299895808,
   OBD2_LIVE_FRAME = 299896064,
   OBD2_FREEZE_FRAME = 299896065,
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleApPowerBootupReason.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleApPowerBootupReason.aidl
new file mode 100644
index 0000000..e325b38
--- /dev/null
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleApPowerBootupReason.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.automotive.vehicle;
+
+/**
+ * Vehicle AP power bootup reason.
+ */
+@VintfStability
+@Backing(type="int")
+enum VehicleApPowerBootupReason {
+    /**
+     * Power on due to user's pressing of power key or rotating of ignition
+     * switch.
+     */
+    USER_POWER_ON = 0,
+    /**
+     * Automatic power on triggered by door unlock or any other kind of automatic
+     * user detection.
+     */
+    SYSTEM_USER_DETECTION = 1,
+    /**
+     * Automatic power on to execute a remote task. This is triggered by
+     * receiving a wakeup message from TCU wakeup client.
+     */
+    SYSTEM_REMOTE_ACCESS = 2,
+}
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl
index 11cda3d..b6886c0 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl
@@ -16,6 +16,8 @@
 
 package android.hardware.automotive.vehicle;
 
+import android.hardware.automotive.vehicle.VehicleArea;
+import android.hardware.automotive.vehicle.VehiclePropertyGroup;
 import android.hardware.automotive.vehicle.VehiclePropertyType;
 /**
  * Declares all vehicle properties. VehicleProperty has a bitwise structure.
@@ -457,6 +459,9 @@
     /**
      * Parking brake state.
      *
+     * This property is true indicates that the car's parking brake is currently engaged. False
+     * implies that the car's parking brake is currently disengaged.
+     *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      */
@@ -465,6 +470,15 @@
     /**
      * Auto-apply parking brake.
      *
+     * This property is true indicates that the car's automatic parking brake feature is currently
+     * enabled. False indicates that the car's automatic parking brake feature is currently
+     * disabled.
+     *
+     * This property is often confused with PARKING_BRAKE_ON. The difference is that
+     * PARKING_BRAKE_ON describes whether the actual parking brake is currently on/off, whereas
+     * PARKING_BRAKE_AUTO_APPLY describes whether the feature of automatic parking brake is enabled/
+     * disabled, and does not describe the current state of the actual parking brake.
+     *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      */
@@ -1306,6 +1320,18 @@
     DOOR_LOCK = 0x0B02 + 0x10000000 + 0x06000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:DOOR,VehiclePropertyType:BOOLEAN
     /**
+     * Door child lock feature enabled
+     *
+     * Returns true if the door child lock feature is enabled and false if it is disabled.
+     *
+     * If enabled, the door is unable to be opened from the inside.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     */
+    DOOR_CHILD_LOCK_ENABLED =
+            0x0B03 + VehiclePropertyGroup.SYSTEM + VehicleArea.DOOR + VehiclePropertyType.BOOLEAN,
+    /**
      * Mirror Z Position
      *
      * Positive value indicates tilt upwards, negative value is downwards
@@ -1365,6 +1391,35 @@
      */
     MIRROR_FOLD = 0x0B45 + 0x10000000 + 0x01000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
+
+    /**
+     * Represents property for Mirror Auto Fold feature.
+     *
+     * This property is true when the feature for automatically folding the vehicle's side mirrors
+     * (for example, when the mirrors fold inward automatically when one exits and locks the
+     * vehicle) is enabled.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     */
+
+    MIRROR_AUTO_FOLD_ENABLED =
+            0x0B46 + VehiclePropertyGroup.SYSTEM + VehicleArea.MIRROR + VehiclePropertyType.BOOLEAN,
+
+    /**
+     * Represents property for Mirror Auto Tilt feature.
+     *
+     * This property is true when the feature for automatically tilting the vehicle's side mirrors
+     * (for example, when the mirrors tilt downward automatically when one reverses the vehicle) is
+     * enabled.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     */
+
+    MIRROR_AUTO_TILT_ENABLED =
+            0x0B47 + VehiclePropertyGroup.SYSTEM + VehicleArea.MIRROR + VehiclePropertyType.BOOLEAN,
+
     /**
      * Seat memory select
      *
@@ -1667,6 +1722,102 @@
     SEAT_HEADREST_FORE_AFT_MOVE = 0x0B9A + 0x10000000 + 0x05000000
             + 0x00400000, // 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
+     * exit the vehicle.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     */
+    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.
+     */
+    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
+     * between minInt32Value and maxInt32Value are supported.
+     *
+     * maxInt32Value indicates the widest cushion side support setting (i.e. least support).
+     * minInt32Value indicates the thinnest cushion side support setting (i.e most support).
+     *
+     * 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_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,
+    /**
      * Seat Occupancy
      *
      * Indicates whether a particular seat is occupied or not, to the best of the car's ability
@@ -1736,6 +1887,111 @@
     WINDOW_LOCK = 0x0BC4 + 0x10000000 + 0x03000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:WINDOW,VehiclePropertyType:BOOLEAN
     /**
+     * Steering wheel depth position
+     *
+     * All steering wheel properties' unique ids start from 0x0BE0.
+     *
+     * The maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All values between
+     * minInt32Value and maxInt32Value must be supported.
+     *
+     * The maxInt32Value in default area's VehicleAreaConfig indicates the steering wheel position
+     * closest to the driver. The minInt32Value in default area's VehicleAreaConfig indicates the
+     * steering wheel position furthest to the driver.
+     *
+     * This value is not in any particular unit but in a specified range of steps.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     */
+    STEERING_WHEEL_DEPTH_POS =
+            0x0BE0 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
+    /**
+     * Steering wheel depth movement
+     *
+     * The maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All values between
+     * minInt32Value and maxInt32Value must be supported.
+     *
+     * The maxInt32Value in default area's VehicleAreaConfig indicates the steering wheel moving
+     * towards the driver. The minInt32Value in default area's VehicleAreaConfig indicates the
+     * steering wheel moving away from the driver. Larger integers, either positive or negative,
+     * indicate a faster movement speed. Once the steering wheel 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
+     */
+    STEERING_WHEEL_DEPTH_MOVE =
+            0x0BE1 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
+    /**
+     * Steering wheel height position
+     *
+     * The maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All values between
+     * minInt32Value and maxInt32Value must be supported.
+     *
+     * The maxInt32Value in default area's VehicleAreaConfig indicates the steering wheel being in
+     * the highest position. The minInt32Value in default area's VehicleAreaConfig indicates the
+     * steering wheel being in 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
+     */
+    STEERING_WHEEL_HEIGHT_POS =
+            0x0BE2 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
+    /**
+     * Steering wheel height movement
+     *
+     * The maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All values between
+     * minInt32Value and maxInt32Value must be supported.
+     *
+     * The maxInt32Value in default area's VehicleAreaConfig indicates the steering wheel moving
+     * upwards. The minInt32Value in default area's VehicleAreaConfig indicates the steering wheel
+     * moving downwards. Larger integers, either positive or negative, indicate a faster movement
+     * speed. Once the steering wheel 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
+     */
+    STEERING_WHEEL_HEIGHT_MOVE =
+            0x0BE3 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
+    /**
+     * Steering wheel theft lock feature enabled
+     *
+     * If true, the steering wheel will lock automatically to prevent theft in certain
+     * situations.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     */
+    STEERING_WHEEL_THEFT_LOCK_ENABLED =
+            0x0BE4 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+    /**
+     * Steering wheel locked
+     *
+     * If true, the steering wheel's position is locked and not changeable.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     */
+    STEERING_WHEEL_LOCKED =
+            0x0BE5 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+    /**
+     * Steering wheel easy access feature enabled
+     *
+     * If true, the driver’s steering wheel will automatically adjust to make it easier for the
+     * driver to enter and exit the vehicle.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     */
+    STEERING_WHEEL_EASY_ACCESS_ENABLED =
+            0x0BE6 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+    /**
      * Vehicle Maps Service (VMS) message
      *
      * This property uses MIXED data to communicate vms messages.
@@ -2877,5 +3133,4 @@
      */
     SUPPORTED_PROPERTY_IDS = 0x0F48 + 0x10000000 + 0x01000000
             + 0x00410000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
-
 }
diff --git a/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h b/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h
index c91afe2..d5182dd 100644
--- a/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h
+++ b/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h
@@ -119,12 +119,15 @@
         {VehicleProperty::DOOR_POS, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::DOOR_MOVE, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::DOOR_LOCK, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::DOOR_CHILD_LOCK_ENABLED, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::MIRROR_Z_POS, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::MIRROR_Z_MOVE, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::MIRROR_Y_POS, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::MIRROR_Y_MOVE, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::MIRROR_LOCK, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::MIRROR_FOLD, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::MIRROR_AUTO_FOLD_ENABLED, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::MIRROR_AUTO_TILT_ENABLED, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::SEAT_MEMORY_SELECT, VehiclePropertyAccess::WRITE},
         {VehicleProperty::SEAT_MEMORY_SET, VehiclePropertyAccess::WRITE},
         {VehicleProperty::SEAT_BELT_BUCKLED, VehiclePropertyAccess::READ_WRITE},
@@ -152,10 +155,23 @@
         {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_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_OCCUPANCY, VehiclePropertyAccess::READ},
         {VehicleProperty::WINDOW_POS, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::WINDOW_MOVE, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::WINDOW_LOCK, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::STEERING_WHEEL_DEPTH_POS, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::STEERING_WHEEL_DEPTH_MOVE, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::STEERING_WHEEL_HEIGHT_POS, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::STEERING_WHEEL_HEIGHT_MOVE, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::STEERING_WHEEL_THEFT_LOCK_ENABLED, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::STEERING_WHEEL_LOCKED, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::STEERING_WHEEL_EASY_ACCESS_ENABLED, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::VEHICLE_MAP_SERVICE, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::OBD2_LIVE_FRAME, VehiclePropertyAccess::READ},
         {VehicleProperty::OBD2_FREEZE_FRAME, VehiclePropertyAccess::READ},
diff --git a/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h b/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h
index 807be5d..47bad2c 100644
--- a/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h
+++ b/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h
@@ -119,12 +119,15 @@
         {VehicleProperty::DOOR_POS, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::DOOR_MOVE, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::DOOR_LOCK, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::DOOR_CHILD_LOCK_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::MIRROR_Z_POS, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::MIRROR_Z_MOVE, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::MIRROR_Y_POS, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::MIRROR_Y_MOVE, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::MIRROR_LOCK, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::MIRROR_FOLD, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::MIRROR_AUTO_FOLD_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::MIRROR_AUTO_TILT_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::SEAT_MEMORY_SELECT, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::SEAT_MEMORY_SET, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::SEAT_BELT_BUCKLED, VehiclePropertyChangeMode::ON_CHANGE},
@@ -152,10 +155,23 @@
         {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_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_OCCUPANCY, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::WINDOW_POS, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::WINDOW_MOVE, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::WINDOW_LOCK, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::STEERING_WHEEL_DEPTH_POS, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::STEERING_WHEEL_DEPTH_MOVE, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::STEERING_WHEEL_HEIGHT_POS, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::STEERING_WHEEL_HEIGHT_MOVE, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::STEERING_WHEEL_THEFT_LOCK_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::STEERING_WHEEL_LOCKED, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::STEERING_WHEEL_EASY_ACCESS_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::VEHICLE_MAP_SERVICE, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::OBD2_LIVE_FRAME, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::OBD2_FREEZE_FRAME, VehiclePropertyChangeMode::ON_CHANGE},
diff --git a/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java b/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java
index e698f84..85a62d3 100644
--- a/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java
+++ b/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java
@@ -111,12 +111,15 @@
         Map.entry(VehicleProperty.DOOR_POS, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.DOOR_MOVE, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.DOOR_LOCK, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.DOOR_CHILD_LOCK_ENABLED, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.MIRROR_Z_POS, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.MIRROR_Z_MOVE, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.MIRROR_Y_POS, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.MIRROR_Y_MOVE, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.MIRROR_LOCK, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.MIRROR_FOLD, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.MIRROR_AUTO_FOLD_ENABLED, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.MIRROR_AUTO_TILT_ENABLED, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.SEAT_MEMORY_SELECT, VehiclePropertyAccess.WRITE),
         Map.entry(VehicleProperty.SEAT_MEMORY_SET, VehiclePropertyAccess.WRITE),
         Map.entry(VehicleProperty.SEAT_BELT_BUCKLED, VehiclePropertyAccess.READ_WRITE),
@@ -144,10 +147,23 @@
         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_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_OCCUPANCY, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.WINDOW_POS, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.WINDOW_MOVE, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.WINDOW_LOCK, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.STEERING_WHEEL_DEPTH_POS, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.STEERING_WHEEL_DEPTH_MOVE, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.STEERING_WHEEL_HEIGHT_POS, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.STEERING_WHEEL_HEIGHT_MOVE, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.STEERING_WHEEL_THEFT_LOCK_ENABLED, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.STEERING_WHEEL_LOCKED, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.STEERING_WHEEL_EASY_ACCESS_ENABLED, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.VEHICLE_MAP_SERVICE, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.OBD2_LIVE_FRAME, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.OBD2_FREEZE_FRAME, VehiclePropertyAccess.READ),
diff --git a/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java b/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java
index fe69450..46b9663 100644
--- a/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java
+++ b/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java
@@ -111,12 +111,15 @@
         Map.entry(VehicleProperty.DOOR_POS, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.DOOR_MOVE, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.DOOR_LOCK, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.DOOR_CHILD_LOCK_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.MIRROR_Z_POS, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.MIRROR_Z_MOVE, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.MIRROR_Y_POS, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.MIRROR_Y_MOVE, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.MIRROR_LOCK, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.MIRROR_FOLD, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.MIRROR_AUTO_FOLD_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.MIRROR_AUTO_TILT_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.SEAT_MEMORY_SELECT, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.SEAT_MEMORY_SET, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.SEAT_BELT_BUCKLED, VehiclePropertyChangeMode.ON_CHANGE),
@@ -144,10 +147,23 @@
         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_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_OCCUPANCY, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.WINDOW_POS, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.WINDOW_MOVE, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.WINDOW_LOCK, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.STEERING_WHEEL_DEPTH_POS, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.STEERING_WHEEL_DEPTH_MOVE, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.STEERING_WHEEL_HEIGHT_POS, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.STEERING_WHEEL_HEIGHT_MOVE, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.STEERING_WHEEL_THEFT_LOCK_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.STEERING_WHEEL_LOCKED, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.STEERING_WHEEL_EASY_ACCESS_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.VEHICLE_MAP_SERVICE, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.OBD2_LIVE_FRAME, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.OBD2_FREEZE_FRAME, VehiclePropertyChangeMode.ON_CHANGE),
diff --git a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
index b6811b6..bd80ad5 100644
--- a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
+++ b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
@@ -1036,6 +1036,178 @@
             ]
         },
         {
+            "property": "VehicleProperty::SEAT_EASY_ACCESS_ENABLED",
+            "defaultValue": {
+                "int32Values": [
+                    1
+                ]
+            },
+            "areas": [
+                {
+                    "areaId": "Constants::SEAT_1_LEFT"
+                },
+                {
+                    "areaId": "Constants::SEAT_1_RIGHT"
+                }
+            ]
+        },
+        {
+            "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": [
+                    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_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_OCCUPANCY",
             "areas": [
                 {
@@ -1929,6 +2101,22 @@
             ]
         },
         {
+            "property": "VehicleProperty::DOOR_CHILD_LOCK_ENABLED",
+            "defaultValue": {
+                "int32Values": [
+                    0
+                ]
+            },
+            "areas": [
+                {
+                    "areaId": "Constants::DOOR_2_LEFT"
+                },
+                {
+                    "areaId": "Constants::DOOR_2_RIGHT"
+                }
+            ]
+        },
+        {
             "property": "VehicleProperty::DOOR_POS",
             "defaultValue": {
                 "int32Values": [
@@ -1964,6 +2152,36 @@
             ]
         },
         {
+            "property": "VehicleProperty::DOOR_MOVE",
+            "defaultValue": {
+                "int32Values": [
+                    0
+                ]
+            },
+            "areas": [
+                {
+                    "areaId": "Constants::DOOR_1_LEFT",
+                    "minInt32Value": -1,
+                    "maxInt32Value": 1
+                },
+                {
+                    "areaId": "Constants::DOOR_1_RIGHT",
+                    "minInt32Value": -1,
+                    "maxInt32Value": 1
+                },
+                {
+                    "areaId": "Constants::DOOR_2_LEFT",
+                    "minInt32Value": -1,
+                    "maxInt32Value": 1
+                },
+                {
+                    "areaId": "Constants::DOOR_2_RIGHT",
+                    "minInt32Value": -1,
+                    "maxInt32Value": 1
+                }
+            ]
+        },
+        {
             "property": "VehicleProperty::MIRROR_Z_POS",
             "defaultValue": {
                 "int32Values": [
@@ -2080,6 +2298,32 @@
             }
         },
         {
+            "property": "VehicleProperty::MIRROR_AUTO_FOLD_ENABLED",
+            "defaultValue": {
+                "int32Values": [
+                    1
+                ]
+            },
+            "areas": [
+                {
+                    "areaId": "Constants::MIRROR_DRIVER_LEFT_RIGHT"
+                }
+            ]
+        },
+        {
+            "property": "VehicleProperty::MIRROR_AUTO_TILT_ENABLED",
+            "defaultValue": {
+                "int32Values": [
+                    1
+                ]
+            },
+            "areas": [
+                {
+                    "areaId": "Constants::MIRROR_DRIVER_LEFT_RIGHT"
+                }
+            ]
+        },
+        {
             "property": "VehicleProperty::WINDOW_LOCK",
             "areas": [
                 {
@@ -2163,6 +2407,90 @@
             ]
         },
         {
+            "property": "VehicleProperty::STEERING_WHEEL_DEPTH_POS",
+            "defaultValue": {
+                "int32Values": [
+                    0
+                ]
+            },
+            "areas": [
+                {
+                    "areaId": 0,
+                    "minInt32Value": 0,
+                    "maxInt32Value": 10
+                }
+            ]
+        },
+        {
+            "property": "VehicleProperty::STEERING_WHEEL_DEPTH_MOVE",
+            "defaultValue": {
+                "int32Values": [
+                    0
+                ]
+            },
+            "areas": [
+                {
+                    "areaId": 0,
+                    "minInt32Value": -2,
+                    "maxInt32Value": 2
+                }
+            ]
+        },
+        {
+            "property": "VehicleProperty::STEERING_WHEEL_HEIGHT_POS",
+            "defaultValue": {
+                "int32Values": [
+                    0
+                ]
+            },
+            "areas": [
+                {
+                    "areaId": 0,
+                    "minInt32Value": 0,
+                    "maxInt32Value": 10
+                }
+            ]
+        },
+        {
+            "property": "VehicleProperty::STEERING_WHEEL_HEIGHT_MOVE",
+            "defaultValue": {
+                "int32Values": [
+                    0
+                ]
+            },
+            "areas": [
+                {
+                    "areaId": 0,
+                    "minInt32Value": -2,
+                    "maxInt32Value": 2
+                }
+            ]
+        },
+        {
+            "property": "VehicleProperty::STEERING_WHEEL_THEFT_LOCK_ENABLED",
+            "defaultValue": {
+                "int32Values": [
+                    0
+                ]
+            }
+        },
+        {
+            "property": "VehicleProperty::STEERING_WHEEL_LOCKED",
+            "defaultValue": {
+                "int32Values": [
+                    0
+                ]
+            }
+        },
+        {
+            "property": "VehicleProperty::STEERING_WHEEL_EASY_ACCESS_ENABLED",
+            "defaultValue": {
+                "int32Values": [
+                    0
+                ]
+            }
+        },
+        {
             "property": "VehicleProperty::WHEEL_TICK",
             "defaultValue": {
                 "int64Values": [
diff --git a/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
index 5de206b..7eefe2a 100644
--- a/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
+++ b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
@@ -44,6 +44,8 @@
 using ::aidl::android::hardware::automotive::vehicle::VehicleArea;
 using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyAccess;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyChangeMode;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyGroup;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyType;
 using ::android::getAidlHalInstanceNames;
 using ::android::base::ScopedLockAssertion;
@@ -114,6 +116,9 @@
 
 class VtsHalAutomotiveVehicleTargetTest : public testing::TestWithParam<ServiceDescriptor> {
   public:
+    void verifyProperty(VehicleProperty propId, VehiclePropertyAccess access,
+                        VehiclePropertyChangeMode changeMode, VehiclePropertyGroup group,
+                        VehicleArea area, VehiclePropertyType propertyType);
     virtual void SetUp() override {
         auto descriptor = GetParam();
         if (descriptor.isAidlService) {
@@ -420,6 +425,158 @@
     }
 }
 
+// Helper function to compare actual vs expected property config
+void VtsHalAutomotiveVehicleTargetTest::verifyProperty(VehicleProperty propId,
+                                                       VehiclePropertyAccess access,
+                                                       VehiclePropertyChangeMode changeMode,
+                                                       VehiclePropertyGroup group, VehicleArea area,
+                                                       VehiclePropertyType propertyType) {
+    int expectedPropId = toInt(propId);
+    int expectedAccess = toInt(access);
+    int expectedChangeMode = toInt(changeMode);
+    int expectedGroup = toInt(group);
+    int expectedArea = toInt(area);
+    int expectedPropertyType = toInt(propertyType);
+
+    auto result = mVhalClient->getPropConfigs({expectedPropId});
+    ASSERT_TRUE(result.ok()) << "Failed to get required property config, error: "
+                             << result.error().message();
+
+    if (result.value().size() == 0) {
+        GTEST_SKIP() << "Property has not been implemented";
+    }
+    ASSERT_EQ(result.value().size(), 1u)
+            << StringPrintf("Expect to get exactly 1 config, got %zu", result.value().size());
+
+    const auto& config = result.value().at(0);
+    int actualPropId = config->getPropId();
+    int actualAccess = config->getAccess();
+    int actualChangeMode = config->getChangeMode();
+    int actualGroup = actualPropId & toInt(VehiclePropertyGroup::MASK);
+    int actualArea = actualPropId & toInt(VehicleArea::MASK);
+    int actualPropertyType = actualPropId & toInt(VehiclePropertyType::MASK);
+
+    ASSERT_EQ(actualPropId, expectedPropId)
+            << StringPrintf("Expect to get property ID: %i, got %i", expectedPropId, actualPropId);
+
+    if (expectedAccess == toInt(VehiclePropertyAccess::READ_WRITE)) {
+        ASSERT_TRUE(actualAccess == expectedAccess ||
+                    actualAccess == toInt(VehiclePropertyAccess::READ))
+                << StringPrintf("Expect to get VehiclePropertyAccess: %i or %i, got %i",
+                                expectedAccess, toInt(VehiclePropertyAccess::READ), actualAccess);
+    } else {
+        ASSERT_EQ(actualAccess, expectedAccess) << StringPrintf(
+                "Expect to get VehiclePropertyAccess: %i, got %i", expectedAccess, actualAccess);
+    }
+
+    ASSERT_EQ(actualChangeMode, expectedChangeMode)
+            << StringPrintf("Expect to get VehiclePropertyChangeMode: %i, got %i",
+                            expectedChangeMode, actualChangeMode);
+    ASSERT_EQ(actualGroup, expectedGroup) << StringPrintf(
+            "Expect to get VehiclePropertyGroup: %i, got %i", expectedGroup, actualGroup);
+    ASSERT_EQ(actualArea, expectedArea)
+            << StringPrintf("Expect to get VehicleArea: %i, got %i", expectedArea, actualArea);
+    ASSERT_EQ(actualPropertyType, expectedPropertyType)
+            << StringPrintf("Expect to get VehiclePropertyType: %i, got %i", expectedPropertyType,
+                            actualPropertyType);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyDoorChildLockEnabledConfig) {
+    verifyProperty(VehicleProperty::DOOR_CHILD_LOCK_ENABLED, VehiclePropertyAccess::READ_WRITE,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::DOOR, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySteeringWheelDepthPosConfig) {
+    verifyProperty(VehicleProperty::STEERING_WHEEL_DEPTH_POS, VehiclePropertyAccess::READ_WRITE,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::GLOBAL, VehiclePropertyType::INT32);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySteeringWheelDepthMoveConfig) {
+    verifyProperty(VehicleProperty::STEERING_WHEEL_DEPTH_MOVE, VehiclePropertyAccess::READ_WRITE,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::GLOBAL, VehiclePropertyType::INT32);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySteeringWheelHeightPosConfig) {
+    verifyProperty(VehicleProperty::STEERING_WHEEL_HEIGHT_POS, VehiclePropertyAccess::READ_WRITE,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::GLOBAL, VehiclePropertyType::INT32);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySteeringWheelHeightMoveConfig) {
+    verifyProperty(VehicleProperty::STEERING_WHEEL_HEIGHT_MOVE, VehiclePropertyAccess::READ_WRITE,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::GLOBAL, VehiclePropertyType::INT32);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySteeringWheelTheftLockEnabledConfig) {
+    verifyProperty(VehicleProperty::STEERING_WHEEL_THEFT_LOCK_ENABLED,
+                   VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
+                   VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySteeringWheelLockedConfig) {
+    verifyProperty(VehicleProperty::STEERING_WHEEL_LOCKED, VehiclePropertyAccess::READ_WRITE,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySteeringWheelEasyAccessEnabledConfig) {
+    verifyProperty(VehicleProperty::STEERING_WHEEL_EASY_ACCESS_ENABLED,
+                   VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
+                   VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyMirrorAutoFoldEnabledConfig) {
+    verifyProperty(VehicleProperty::MIRROR_AUTO_FOLD_ENABLED, VehiclePropertyAccess::READ_WRITE,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::MIRROR, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyMirrorAutoTiltEnabledConfig) {
+    verifyProperty(VehicleProperty::MIRROR_AUTO_TILT_ENABLED, VehiclePropertyAccess::READ_WRITE,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::MIRROR, VehiclePropertyType::BOOLEAN);
+}
+
+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);
+}
+
 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 167e0c7..3cd76fd 100644
--- a/biometrics/common/aidl/Android.bp
+++ b/biometrics/common/aidl/Android.bp
@@ -31,7 +31,5 @@
             version: "2",
             imports: [],
         },
-
     ],
-
 }
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/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/CommonProps.aidl b/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/CommonProps.aidl
index d4433c5..1eb8541 100644
--- a/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/CommonProps.aidl
+++ b/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/CommonProps.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.biometrics.common;
+/* @hide */
 @VintfStability
 parcelable CommonProps {
   int sensorId;
diff --git a/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/ComponentInfo.aidl b/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/ComponentInfo.aidl
index ad11dda..471ed2b 100644
--- a/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/ComponentInfo.aidl
+++ b/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/ComponentInfo.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.biometrics.common;
+/* @hide */
 @VintfStability
 parcelable ComponentInfo {
   String componentId;
diff --git a/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/ICancellationSignal.aidl b/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/ICancellationSignal.aidl
index 2bc6a6d..670114f 100644
--- a/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/ICancellationSignal.aidl
+++ b/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/ICancellationSignal.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.biometrics.common;
+/* @hide */
 @VintfStability
 interface ICancellationSignal {
   oneway void cancel();
diff --git a/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/OperationContext.aidl b/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/OperationContext.aidl
index 9d1cb8f..5e184bc 100644
--- a/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/OperationContext.aidl
+++ b/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/OperationContext.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.biometrics.common;
+/* @hide */
 @VintfStability
 parcelable OperationContext {
   int id = 0;
diff --git a/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/OperationReason.aidl b/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/OperationReason.aidl
index 3da3a6a..a5b2990 100644
--- a/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/OperationReason.aidl
+++ b/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/OperationReason.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.biometrics.common;
+/* @hide */
 @Backing(type="byte") @VintfStability
 enum OperationReason {
   UNKNOWN = 0,
diff --git a/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/SensorStrength.aidl b/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/SensorStrength.aidl
index 6675d09..aa77322 100644
--- a/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/SensorStrength.aidl
+++ b/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/SensorStrength.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.biometrics.common;
+/* @hide */
 @Backing(type="byte") @VintfStability
 enum SensorStrength {
   CONVENIENCE = 0,
diff --git a/biometrics/common/aidl/android/hardware/biometrics/common/CommonProps.aidl b/biometrics/common/aidl/android/hardware/biometrics/common/CommonProps.aidl
index 2f5af5d..cdedf4f 100644
--- a/biometrics/common/aidl/android/hardware/biometrics/common/CommonProps.aidl
+++ b/biometrics/common/aidl/android/hardware/biometrics/common/CommonProps.aidl
@@ -18,7 +18,9 @@
 
 import android.hardware.biometrics.common.ComponentInfo;
 import android.hardware.biometrics.common.SensorStrength;
-
+/**
+ * @hide
+ */
 @VintfStability
 parcelable CommonProps {
     /**
diff --git a/biometrics/common/aidl/android/hardware/biometrics/common/ComponentInfo.aidl b/biometrics/common/aidl/android/hardware/biometrics/common/ComponentInfo.aidl
index b268eef..1da9cf6 100644
--- a/biometrics/common/aidl/android/hardware/biometrics/common/ComponentInfo.aidl
+++ b/biometrics/common/aidl/android/hardware/biometrics/common/ComponentInfo.aidl
@@ -15,7 +15,9 @@
  */
 
 package android.hardware.biometrics.common;
-
+/**
+ * @hide
+ */
 @VintfStability
 parcelable ComponentInfo {
     /**
diff --git a/biometrics/common/aidl/android/hardware/biometrics/common/ICancellationSignal.aidl b/biometrics/common/aidl/android/hardware/biometrics/common/ICancellationSignal.aidl
index 1010256..b9b1f39 100644
--- a/biometrics/common/aidl/android/hardware/biometrics/common/ICancellationSignal.aidl
+++ b/biometrics/common/aidl/android/hardware/biometrics/common/ICancellationSignal.aidl
@@ -15,9 +15,10 @@
  */
 
 package android.hardware.biometrics.common;
-
+/**
+ * @hide
+ */
 @VintfStability
 oneway interface ICancellationSignal {
     void cancel();
 }
-
diff --git a/biometrics/common/aidl/android/hardware/biometrics/common/OperationContext.aidl b/biometrics/common/aidl/android/hardware/biometrics/common/OperationContext.aidl
index 72fe660..a1c7a1f 100644
--- a/biometrics/common/aidl/android/hardware/biometrics/common/OperationContext.aidl
+++ b/biometrics/common/aidl/android/hardware/biometrics/common/OperationContext.aidl
@@ -20,6 +20,7 @@
 
 /**
  * Additional context associated with an operation.
+ * @hide
  */
 @VintfStability
 parcelable OperationContext {
diff --git a/biometrics/common/aidl/android/hardware/biometrics/common/OperationReason.aidl b/biometrics/common/aidl/android/hardware/biometrics/common/OperationReason.aidl
index abc25ed..a93cebc 100644
--- a/biometrics/common/aidl/android/hardware/biometrics/common/OperationReason.aidl
+++ b/biometrics/common/aidl/android/hardware/biometrics/common/OperationReason.aidl
@@ -15,7 +15,9 @@
  */
 
 package android.hardware.biometrics.common;
-
+/**
+ * @hide
+ */
 @VintfStability
 @Backing(type="byte")
 enum OperationReason {
diff --git a/biometrics/common/aidl/android/hardware/biometrics/common/SensorStrength.aidl b/biometrics/common/aidl/android/hardware/biometrics/common/SensorStrength.aidl
index 790691c..b5c0999 100644
--- a/biometrics/common/aidl/android/hardware/biometrics/common/SensorStrength.aidl
+++ b/biometrics/common/aidl/android/hardware/biometrics/common/SensorStrength.aidl
@@ -15,7 +15,9 @@
  */
 
 package android.hardware.biometrics.common;
-
+/**
+ * @hide
+ */
 @VintfStability
 @Backing(type="byte")
 enum SensorStrength {
@@ -40,4 +42,4 @@
      * HardwareAuthToken(s).
      */
     STRONG,
-}
\ No newline at end of file
+}
diff --git a/biometrics/common/util/Android.bp b/biometrics/common/util/Android.bp
index 918ef72..b990812 100644
--- a/biometrics/common/util/Android.bp
+++ b/biometrics/common/util/Android.bp
@@ -13,6 +13,6 @@
     shared_libs: [
         "libbase",
         "libbinder_ndk",
-        "android.hardware.biometrics.common-V2-ndk",
+        "android.hardware.biometrics.common-V3-ndk",
     ],
 }
diff --git a/biometrics/common/util/include/util/Util.h b/biometrics/common/util/include/util/Util.h
index 29ec0f8..da19dc6 100644
--- a/biometrics/common/util/include/util/Util.h
+++ b/biometrics/common/util/include/util/Util.h
@@ -40,7 +40,7 @@
 // by parts of the UI or fail if there is no latency. For example, the
 // Face settings page constantly runs auth and the enrollment UI uses a
 // cancel/restart cycle that requires some latency while the activities change.
-#define DEFAULT_LATENCY 800
+#define DEFAULT_LATENCY 400
 
 class Util {
   public:
@@ -66,4 +66,4 @@
     }
 };
 
-}  // namespace aidl::android::hardware::biometrics
\ No newline at end of file
+}  // namespace aidl::android::hardware::biometrics
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/Android.bp b/biometrics/face/aidl/Android.bp
index 0bec0c5..7b11335 100644
--- a/biometrics/face/aidl/Android.bp
+++ b/biometrics/face/aidl/Android.bp
@@ -14,9 +14,9 @@
         "android/hardware/biometrics/face/**/*.aidl",
     ],
     imports: [
-        "android.hardware.biometrics.common",
+        "android.hardware.biometrics.common-V3",
         "android.hardware.common-V2",
-        "android.hardware.keymaster-V3",
+        "android.hardware.keymaster-V4",
     ],
     stability: "vintf",
     backend: {
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/face/aidl/default/Android.bp b/biometrics/face/aidl/default/Android.bp
index 63a3645..876a91f 100644
--- a/biometrics/face/aidl/default/Android.bp
+++ b/biometrics/face/aidl/default/Android.bp
@@ -16,8 +16,8 @@
     shared_libs: [
         "libbase",
         "libbinder_ndk",
-        "android.hardware.biometrics.face-V2-ndk",
-        "android.hardware.biometrics.common-V2-ndk",
+        "android.hardware.biometrics.face-V3-ndk",
+        "android.hardware.biometrics.common-V3-ndk",
         "android.hardware.biometrics.common.thread",
         "android.hardware.biometrics.common.util",
     ],
@@ -49,9 +49,9 @@
     ],
     static_libs: [
         "libandroid.hardware.biometrics.face.VirtualProps",
-        "android.hardware.biometrics.face-V2-ndk",
-        "android.hardware.biometrics.common-V2-ndk",
-        "android.hardware.keymaster-V3-ndk",
+        "android.hardware.biometrics.face-V3-ndk",
+        "android.hardware.biometrics.common-V3-ndk",
+        "android.hardware.keymaster-V4-ndk",
         "android.hardware.biometrics.common.util",
     ],
     vendor: true,
diff --git a/biometrics/face/aidl/default/face-default.xml b/biometrics/face/aidl/default/face-default.xml
index e6ef842..8f2fbb8 100644
--- a/biometrics/face/aidl/default/face-default.xml
+++ b/biometrics/face/aidl/default/face-default.xml
@@ -1,7 +1,7 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.biometrics.face</name>
-        <version>2</version>
+        <version>3</version>
         <fqname>IFace/default</fqname>
     </hal>
 </manifest>
diff --git a/biometrics/face/aidl/vts/Android.bp b/biometrics/face/aidl/vts/Android.bp
index 4171ac3..f62c4e4 100644
--- a/biometrics/face/aidl/vts/Android.bp
+++ b/biometrics/face/aidl/vts/Android.bp
@@ -15,10 +15,10 @@
     ],
     srcs: ["VtsHalBiometricsFaceTargetTest.cpp"],
     static_libs: [
-        "android.hardware.biometrics.common-V2-ndk",
-        "android.hardware.biometrics.face-V2-ndk",
+        "android.hardware.biometrics.common-V3-ndk",
+        "android.hardware.biometrics.face-V3-ndk",
         "android.hardware.common-V2-ndk",
-        "android.hardware.keymaster-V3-ndk",
+        "android.hardware.keymaster-V4-ndk",
     ],
     shared_libs: [
         "libbinder_ndk",
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/Android.bp b/biometrics/fingerprint/aidl/Android.bp
index 0bd6422..f749822 100644
--- a/biometrics/fingerprint/aidl/Android.bp
+++ b/biometrics/fingerprint/aidl/Android.bp
@@ -14,8 +14,8 @@
         "android/hardware/biometrics/fingerprint/**/*.aidl",
     ],
     imports: [
-        "android.hardware.biometrics.common",
-        "android.hardware.keymaster-V3",
+        "android.hardware.biometrics.common-V3",
+        "android.hardware.keymaster-V4",
     ],
     stability: "vintf",
     backend: {
@@ -41,7 +41,5 @@
                 "android.hardware.keymaster-V3",
             ],
         },
-
     ],
-
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/AcquiredInfo.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/AcquiredInfo.aidl
index c51aa03..0cc619f 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/AcquiredInfo.aidl
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/AcquiredInfo.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.biometrics.fingerprint;
+/* @hide */
 @Backing(type="byte") @VintfStability
 enum AcquiredInfo {
   UNKNOWN = 0,
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/Error.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/Error.aidl
index af7bc3c..45ce2eb 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/Error.aidl
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/Error.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.biometrics.fingerprint;
+/* @hide */
 @Backing(type="byte") @VintfStability
 enum Error {
   UNKNOWN = 0,
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/FingerprintSensorType.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/FingerprintSensorType.aidl
index 9c208c4..67af20d 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/FingerprintSensorType.aidl
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/FingerprintSensorType.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.biometrics.fingerprint;
+/* @hide */
 @Backing(type="byte") @VintfStability
 enum FingerprintSensorType {
   UNKNOWN = 0,
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IFingerprint.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IFingerprint.aidl
index 5d3df6f..0b6f300 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IFingerprint.aidl
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IFingerprint.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.biometrics.fingerprint;
+/* @hide */
 @VintfStability
 interface IFingerprint {
   android.hardware.biometrics.fingerprint.SensorProps[] getSensorProps();
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISession.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISession.aidl
index 30f299d..f305855 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISession.aidl
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISession.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.biometrics.fingerprint;
+/* @hide */
 @VintfStability
 interface ISession {
   void generateChallenge();
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISessionCallback.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISessionCallback.aidl
index 3c40ad6..be18ffe 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISessionCallback.aidl
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISessionCallback.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.biometrics.fingerprint;
+/* @hide */
 @VintfStability
 interface ISessionCallback {
   void onChallengeGenerated(in long challenge);
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/PointerContext.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/PointerContext.aidl
index 43db6cf..999b324 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/PointerContext.aidl
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/PointerContext.aidl
@@ -32,7 +32,8 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.biometrics.fingerprint;
-@VintfStability
+/* @hide */
+@JavaDerive(equals=true) @VintfStability
 parcelable PointerContext {
   int pointerId = -1;
   float x = 0.000000f;
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/SensorLocation.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/SensorLocation.aidl
index 295fde9..dc6a62d 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/SensorLocation.aidl
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/SensorLocation.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.biometrics.fingerprint;
+/* @hide */
 @VintfStability
 parcelable SensorLocation {
   int displayId;
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/SensorProps.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/SensorProps.aidl
index 782d289..a77d5f2 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/SensorProps.aidl
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/SensorProps.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.biometrics.fingerprint;
+/* @hide */
 @VintfStability
 parcelable SensorProps {
   android.hardware.biometrics.common.CommonProps commonProps;
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfo.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfo.aidl
index 8ec8574..d3aa98a 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfo.aidl
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfo.aidl
@@ -15,7 +15,9 @@
  */
 
 package android.hardware.biometrics.fingerprint;
-
+/**
+ * @hide
+ */
 @VintfStability
 @Backing(type="byte")
 enum AcquiredInfo {
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/Error.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/Error.aidl
index e69859a..d8d47fa 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/Error.aidl
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/Error.aidl
@@ -15,7 +15,9 @@
  */
 
 package android.hardware.biometrics.fingerprint;
-
+/**
+ * @hide
+ */
 @VintfStability
 @Backing(type="byte")
 enum Error {
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/FingerprintSensorType.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/FingerprintSensorType.aidl
index dbe7137..7caa154 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/FingerprintSensorType.aidl
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/FingerprintSensorType.aidl
@@ -15,7 +15,9 @@
  */
 
 package android.hardware.biometrics.fingerprint;
-
+/**
+ * @hide
+ */
 @VintfStability
 @Backing(type="byte")
 enum FingerprintSensorType {
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IFingerprint.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IFingerprint.aidl
index 75f90a1..f4febad 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IFingerprint.aidl
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IFingerprint.aidl
@@ -19,7 +19,9 @@
 import android.hardware.biometrics.fingerprint.ISession;
 import android.hardware.biometrics.fingerprint.ISessionCallback;
 import android.hardware.biometrics.fingerprint.SensorProps;
-
+/**
+ * @hide
+ */
 @VintfStability
 interface IFingerprint {
     /**
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISession.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISession.aidl
index db01145..f4f7804 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISession.aidl
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISession.aidl
@@ -45,6 +45,7 @@
  * ISession only supports execution of one non-interrupting operation at a time, regardless of
  * whether it's cancellable. The framework must wait for a callback indicating the end of the
  * current non-interrupting operation before a new non-interrupting operation can be started.
+ * @hide
  */
 @VintfStability
 interface ISession {
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISessionCallback.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISessionCallback.aidl
index f699966..24b169e 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISessionCallback.aidl
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISessionCallback.aidl
@@ -19,7 +19,9 @@
 import android.hardware.biometrics.fingerprint.AcquiredInfo;
 import android.hardware.biometrics.fingerprint.Error;
 import android.hardware.keymaster.HardwareAuthToken;
-
+/**
+ * @hide
+ */
 @VintfStability
 interface ISessionCallback {
     /**
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/PointerContext.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/PointerContext.aidl
index e025d34..582e6cf 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/PointerContext.aidl
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/PointerContext.aidl
@@ -18,7 +18,9 @@
 
 /**
  * Additional context associated with a pointer event.
+ * @hide
  */
+@JavaDerive(equals=true)
 @VintfStability
 parcelable PointerContext {
     /**
@@ -64,7 +66,7 @@
     boolean isAod = false;
 
     /**
-     * The time of the user interaction that produced this event, in milliseconds.
+     * The time when this event was created, in milliseconds.
      *
      * This is obtained from MotionEvent#getEventTime, which uses SystemClock.uptimeMillis() as
      * the clock.
@@ -74,10 +76,10 @@
     long time = 0;
 
     /**
-     * The time of the first user interaction in this gesture, in milliseconds.
+     * This event is part of some gesture. This is the time when MotionEvent#ACTION_DOWN was
+     * created for that gesture, in milliseconds.
      *
-     * If this event is MotionEvent#ACTION_DOWN, it means it's the first event in this gesture,
-     * and `gestureStart` will be equal to `time`.
+     * If this event is MotionEvent#ACTION_DOWN, then this value is equal to `time`.
      *
      * This is obtained from MotionEvent#getDownTime, which uses SystemClock.uptimeMillis() as
      * the clock.
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/SensorLocation.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/SensorLocation.aidl
index d12605c..a065a7c 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/SensorLocation.aidl
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/SensorLocation.aidl
@@ -15,7 +15,9 @@
  */
 
 package android.hardware.biometrics.fingerprint;
-
+/**
+ * @hide
+ */
 @VintfStability
 parcelable SensorLocation {
     /**
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/SensorProps.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/SensorProps.aidl
index fb516da..d4e9ec6 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/SensorProps.aidl
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/SensorProps.aidl
@@ -19,7 +19,9 @@
 import android.hardware.biometrics.common.CommonProps;
 import android.hardware.biometrics.fingerprint.FingerprintSensorType;
 import android.hardware.biometrics.fingerprint.SensorLocation;
-
+/**
+ * @hide
+ */
 @VintfStability
 parcelable SensorProps {
     /**
diff --git a/biometrics/fingerprint/aidl/default/Android.bp b/biometrics/fingerprint/aidl/default/Android.bp
index dc0199c..fe224c9 100644
--- a/biometrics/fingerprint/aidl/default/Android.bp
+++ b/biometrics/fingerprint/aidl/default/Android.bp
@@ -15,6 +15,7 @@
     vintf_fragments: ["fingerprint-example.xml"],
     local_include_dirs: ["include"],
     srcs: [
+        "FakeLockoutTracker.cpp",
         "FakeFingerprintEngine.cpp",
         "FakeFingerprintEngineRear.cpp",
         "FakeFingerprintEngineUdfps.cpp",
@@ -26,8 +27,8 @@
     shared_libs: [
         "libbase",
         "libbinder_ndk",
-        "android.hardware.biometrics.fingerprint-V2-ndk",
-        "android.hardware.biometrics.common-V2-ndk",
+        "android.hardware.biometrics.fingerprint-V3-ndk",
+        "android.hardware.biometrics.common-V3-ndk",
         "android.hardware.biometrics.common.thread",
         "android.hardware.biometrics.common.util",
     ],
@@ -40,6 +41,7 @@
     srcs: [
         "tests/FakeFingerprintEngineTest.cpp",
         "FakeFingerprintEngine.cpp",
+        "FakeLockoutTracker.cpp",
     ],
     shared_libs: [
         "libbase",
@@ -48,9 +50,9 @@
     ],
     static_libs: [
         "libandroid.hardware.biometrics.fingerprint.VirtualProps",
-        "android.hardware.biometrics.fingerprint-V2-ndk",
-        "android.hardware.biometrics.common-V2-ndk",
-        "android.hardware.keymaster-V3-ndk",
+        "android.hardware.biometrics.fingerprint-V3-ndk",
+        "android.hardware.biometrics.common-V3-ndk",
+        "android.hardware.keymaster-V4-ndk",
         "android.hardware.biometrics.common.util",
     ],
     vendor: true,
@@ -65,6 +67,7 @@
         "tests/FakeFingerprintEngineUdfpsTest.cpp",
         "FakeFingerprintEngineUdfps.cpp",
         "FakeFingerprintEngine.cpp",
+        "FakeLockoutTracker.cpp",
     ],
     shared_libs: [
         "libbase",
@@ -73,9 +76,33 @@
     ],
     static_libs: [
         "libandroid.hardware.biometrics.fingerprint.VirtualProps",
-        "android.hardware.biometrics.fingerprint-V2-ndk",
-        "android.hardware.biometrics.common-V2-ndk",
-        "android.hardware.keymaster-V3-ndk",
+        "android.hardware.biometrics.fingerprint-V3-ndk",
+        "android.hardware.biometrics.common-V3-ndk",
+        "android.hardware.keymaster-V4-ndk",
+        "android.hardware.biometrics.common.util",
+    ],
+    vendor: true,
+    test_suites: ["general-tests"],
+    require_root: true,
+}
+
+cc_test {
+    name: "android.hardware.biometrics.fingerprint.FakeLockoutTrackerTest",
+    local_include_dirs: ["include"],
+    srcs: [
+        "tests/FakeLockoutTrackerTest.cpp",
+        "FakeLockoutTracker.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "android.hardware.biometrics.common.thread",
+    ],
+    static_libs: [
+        "libandroid.hardware.biometrics.fingerprint.VirtualProps",
+        "android.hardware.biometrics.fingerprint-V3-ndk",
+        "android.hardware.biometrics.common-V3-ndk",
+        "android.hardware.keymaster-V4-ndk",
         "android.hardware.biometrics.common.util",
     ],
     vendor: true,
diff --git a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
index 68a1f26..90ec8f2 100644
--- a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
+++ b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,6 +15,7 @@
  */
 
 #include "FakeFingerprintEngine.h"
+#include <regex>
 #include "Fingerprint.h"
 
 #include <android-base/logging.h>
@@ -47,7 +48,7 @@
 void FakeFingerprintEngine::enrollImpl(ISessionCallback* cb,
                                        const keymaster::HardwareAuthToken& hat,
                                        const std::future<void>& cancel) {
-    BEGIN_OP(FingerprintHalProperties::operation_enroll_latency().value_or(DEFAULT_LATENCY));
+    BEGIN_OP(getLatency(FingerprintHalProperties::operation_enroll_latency()));
 
     // Do proper HAT verification in the real implementation.
     if (hat.mac.empty()) {
@@ -56,43 +57,58 @@
         return;
     }
 
-    if (FingerprintHalProperties::operation_enroll_fails().value_or(false)) {
-        LOG(ERROR) << "Fail: operation_enroll_fails";
-        cb->onError(Error::VENDOR, 0 /* vendorError */);
+    // Force error-out
+    auto err = FingerprintHalProperties::operation_enroll_error().value_or(0);
+    if (err != 0) {
+        LOG(ERROR) << "Fail: operation_enroll_error";
+        auto ec = convertError(err);
+        cb->onError(ec.first, ec.second);
         return;
     }
 
-    // format is "<id>:<progress_ms>,<progress_ms>,...:<result>
+    // Format is "<id>:<progress_ms-[acquiredInfo..]>,...:<result>
     auto nextEnroll = FingerprintHalProperties::next_enrollment().value_or("");
     auto parts = Util::split(nextEnroll, ":");
     if (parts.size() != 3) {
-        LOG(ERROR) << "Fail: invalid next_enrollment";
+        LOG(ERROR) << "Fail: invalid next_enrollment:" << nextEnroll;
         cb->onError(Error::VENDOR, 0 /* vendorError */);
         return;
     }
     auto enrollmentId = std::stoi(parts[0]);
-    auto progress = Util::split(parts[1], ",");
-    for (size_t i = 0; i < progress.size(); i++) {
-        auto left = progress.size() - i - 1;
-        SLEEP_MS(std::stoi(progress[i]));
+    auto progress = parseEnrollmentCapture(parts[1]);
+    for (size_t i = 0; i < progress.size(); i += 2) {
+        auto left = (progress.size() - i) / 2 - 1;
+        auto duration = progress[i][0];
+        auto acquired = progress[i + 1];
+        auto N = acquired.size();
 
-        if (shouldCancel(cancel)) {
-            LOG(ERROR) << "Fail: cancel";
-            cb->onError(Error::CANCELED, 0 /* vendorCode */);
-            return;
+        for (int j = 0; j < N; j++) {
+            SLEEP_MS(duration / N);
+
+            if (shouldCancel(cancel)) {
+                LOG(ERROR) << "Fail: cancel";
+                cb->onError(Error::CANCELED, 0 /* vendorCode */);
+                return;
+            }
+            auto ac = convertAcquiredInfo(acquired[j]);
+            cb->onAcquired(ac.first, ac.second);
         }
 
-        cb->onAcquired(AcquiredInfo::GOOD, 0 /* vendorCode */);
         if (left == 0 && !IS_TRUE(parts[2])) {  // end and failed
             LOG(ERROR) << "Fail: requested by caller: " << nextEnroll;
             FingerprintHalProperties::next_enrollment({});
             cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
         } else {  // progress and update props if last time
+            LOG(INFO) << "onEnroll: " << enrollmentId << " left: " << left;
             if (left == 0) {
                 auto enrollments = FingerprintHalProperties::enrollments();
                 enrollments.emplace_back(enrollmentId);
                 FingerprintHalProperties::enrollments(enrollments);
                 FingerprintHalProperties::next_enrollment({});
+                // change authenticatorId after new enrollment
+                auto id = FingerprintHalProperties::authenticator_id().value_or(0);
+                auto newId = id + 1;
+                FingerprintHalProperties::authenticator_id(newId);
                 LOG(INFO) << "Enrolled: " << enrollmentId;
             }
             cb->onEnrollmentProgress(enrollmentId, left);
@@ -102,14 +118,46 @@
 
 void FakeFingerprintEngine::authenticateImpl(ISessionCallback* cb, int64_t /* operationId */,
                                              const std::future<void>& cancel) {
-    BEGIN_OP(FingerprintHalProperties::operation_authenticate_latency().value_or(DEFAULT_LATENCY));
+    BEGIN_OP(getLatency(FingerprintHalProperties::operation_authenticate_latency()));
 
-    auto now = Util::getSystemNanoTime();
-    int64_t duration = FingerprintHalProperties::operation_authenticate_duration().value_or(0);
+    int64_t now = Util::getSystemNanoTime();
+    int64_t duration = FingerprintHalProperties::operation_authenticate_duration().value_or(10);
+    auto acquired = FingerprintHalProperties::operation_authenticate_acquired().value_or("1");
+    auto acquiredInfos = parseIntSequence(acquired);
+    int N = acquiredInfos.size();
+
+    if (N == 0) {
+        LOG(ERROR) << "Fail to parse authentiate acquired info: " + acquired;
+        cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
+        return;
+    }
+
+    // got lockout?
+    FakeLockoutTracker::LockoutMode lockoutMode = mLockoutTracker.getMode();
+    if (lockoutMode == FakeLockoutTracker::LockoutMode::kPermanent) {
+        LOG(ERROR) << "Fail: lockout permanent";
+        cb->onLockoutPermanent();
+        return;
+    } else if (lockoutMode == FakeLockoutTracker::LockoutMode::kTimed) {
+        int64_t timeLeft = mLockoutTracker.getLockoutTimeLeft();
+        LOG(ERROR) << "Fail: lockout timed " << timeLeft;
+        cb->onLockoutTimed(timeLeft);
+    }
+
+    int i = 0;
     do {
         if (FingerprintHalProperties::operation_authenticate_fails().value_or(false)) {
             LOG(ERROR) << "Fail: operation_authenticate_fails";
-            cb->onError(Error::VENDOR, 0 /* vendorError */);
+            mLockoutTracker.addFailedAttempt();
+            cb->onAuthenticationFailed();
+            return;
+        }
+
+        auto err = FingerprintHalProperties::operation_authenticate_error().value_or(0);
+        if (err != 0) {
+            LOG(ERROR) << "Fail: operation_authenticate_error";
+            auto ec = convertError(err);
+            cb->onError(ec.first, ec.second);
             return;
         }
 
@@ -126,39 +174,79 @@
             return;
         }
 
-        auto id = FingerprintHalProperties::enrollment_hit().value_or(0);
-        auto enrolls = FingerprintHalProperties::enrollments();
-        auto isEnrolled = std::find(enrolls.begin(), enrolls.end(), id) != enrolls.end();
-        if (id > 0 && isEnrolled) {
-            cb->onAuthenticationSucceeded(id, {} /* hat */);
-            return;
+        if (i < N) {
+            auto ac = convertAcquiredInfo(acquiredInfos[i]);
+            cb->onAcquired(ac.first, ac.second);
+            i++;
         }
 
-        SLEEP_MS(100);
+        SLEEP_MS(duration / N);
     } while (!Util::hasElapsed(now, duration));
 
-    LOG(ERROR) << "Fail: not enrolled";
-    cb->onAuthenticationFailed();
-    cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
+    auto id = FingerprintHalProperties::enrollment_hit().value_or(0);
+    auto enrolls = FingerprintHalProperties::enrollments();
+    auto isEnrolled = std::find(enrolls.begin(), enrolls.end(), id) != enrolls.end();
+    if (id > 0 && isEnrolled) {
+        cb->onAuthenticationSucceeded(id, {} /* hat */);
+        mLockoutTracker.reset();
+        return;
+    } else {
+        LOG(ERROR) << "Fail: fingerprint not enrolled";
+        cb->onAuthenticationFailed();
+        mLockoutTracker.addFailedAttempt();
+    }
 }
 
 void FakeFingerprintEngine::detectInteractionImpl(ISessionCallback* cb,
                                                   const std::future<void>& cancel) {
-    BEGIN_OP(FingerprintHalProperties::operation_detect_interaction_latency().value_or(
-            DEFAULT_LATENCY));
+    BEGIN_OP(getLatency(FingerprintHalProperties::operation_detect_interaction_latency()));
 
-    if (FingerprintHalProperties::operation_detect_interaction_fails().value_or(false)) {
-        LOG(ERROR) << "Fail: operation_detect_interaction_fails";
-        cb->onError(Error::VENDOR, 0 /* vendorError */);
+    int64_t duration =
+            FingerprintHalProperties::operation_detect_interaction_duration().value_or(10);
+
+    auto detectInteractionSupported =
+            FingerprintHalProperties::detect_interaction().value_or(false);
+    if (!detectInteractionSupported) {
+        LOG(ERROR) << "Detect interaction is not supported";
+        cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
         return;
     }
 
-    if (shouldCancel(cancel)) {
-        LOG(ERROR) << "Fail: cancel";
-        cb->onError(Error::CANCELED, 0 /* vendorCode */);
+    auto acquired = FingerprintHalProperties::operation_detect_interaction_acquired().value_or("1");
+    auto acquiredInfos = parseIntSequence(acquired);
+    int N = acquiredInfos.size();
+    int64_t now = Util::getSystemNanoTime();
+
+    if (N == 0) {
+        LOG(ERROR) << "Fail to parse detect interaction acquired info: " + acquired;
+        cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
         return;
     }
 
+    int i = 0;
+    do {
+        auto err = FingerprintHalProperties::operation_detect_interaction_error().value_or(0);
+        if (err != 0) {
+            LOG(ERROR) << "Fail: operation_detect_interaction_error";
+            auto ec = convertError(err);
+            cb->onError(ec.first, ec.second);
+            return;
+        }
+
+        if (shouldCancel(cancel)) {
+            LOG(ERROR) << "Fail: cancel";
+            cb->onError(Error::CANCELED, 0 /* vendorCode */);
+            return;
+        }
+
+        if (i < N) {
+            auto ac = convertAcquiredInfo(acquiredInfos[i]);
+            cb->onAcquired(ac.first, ac.second);
+            i++;
+        }
+        SLEEP_MS(duration / N);
+    } while (!Util::hasElapsed(now, duration));
+
     auto id = FingerprintHalProperties::enrollment_hit().value_or(0);
     auto enrolls = FingerprintHalProperties::enrollments();
     auto isEnrolled = std::find(enrolls.begin(), enrolls.end(), id) != enrolls.end();
@@ -211,26 +299,40 @@
 
 void FakeFingerprintEngine::getAuthenticatorIdImpl(ISessionCallback* cb) {
     BEGIN_OP(0);
-    int64_t authenticatorId = FingerprintHalProperties::authenticator_id().value_or(0);
-    if (FingerprintHalProperties::enrollments().size() > 0 && authenticatorId == 0) {
-        authenticatorId = 99999999;  // default authenticatorId, TODO(b/230515082)
+    int64_t authenticatorId;
+    if (FingerprintHalProperties::enrollments().size() == 0) {
+        authenticatorId = 0;
+    } else {
+        authenticatorId = FingerprintHalProperties::authenticator_id().value_or(0);
+        if (authenticatorId == 0) authenticatorId = 1;
     }
     cb->onAuthenticatorIdRetrieved(authenticatorId);
 }
 
 void FakeFingerprintEngine::invalidateAuthenticatorIdImpl(ISessionCallback* cb) {
     BEGIN_OP(0);
-    auto id = FingerprintHalProperties::authenticator_id().value_or(0);
-    auto newId = id + 1;
+    int64_t newId;
+    if (FingerprintHalProperties::enrollments().size() == 0) {
+        newId = 0;
+    } else {
+        auto id = FingerprintHalProperties::authenticator_id().value_or(0);
+        newId = id + 1;
+    }
     FingerprintHalProperties::authenticator_id(newId);
     cb->onAuthenticatorIdInvalidated(newId);
 }
 
 void FakeFingerprintEngine::resetLockoutImpl(ISessionCallback* cb,
-                                             const keymaster::HardwareAuthToken& /*hat*/) {
+                                             const keymaster::HardwareAuthToken& hat) {
     BEGIN_OP(0);
+    if (hat.mac.empty()) {
+        LOG(ERROR) << "Fail: hat in resetLockout()";
+        cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
+        return;
+    }
     FingerprintHalProperties::lockout(false);
     cb->onLockoutCleared();
+    mLockoutTracker.reset();
 }
 
 ndk::ScopedAStatus FakeFingerprintEngine::onPointerDownImpl(int32_t /*pointerId*/, int32_t /*x*/,
@@ -286,4 +388,129 @@
     return {0 /* displayId (not used) */, 0 /* sensorLocationX */, 0 /* sensorLocationY */,
             0 /* sensorRadius */, "" /* display */};
 }
+
+std::vector<int32_t> FakeFingerprintEngine::parseIntSequence(const std::string& str,
+                                                             const std::string& sep) {
+    std::vector<std::string> seqs = Util::split(str, sep);
+    std::vector<int32_t> res;
+
+    for (const auto& seq : seqs) {
+        int32_t val;
+        if (ParseInt(seq, &val)) {
+            res.push_back(val);
+        } else {
+            LOG(WARNING) << "Invalid int sequence:" + str;
+            res.clear();
+            break;
+        }
+    }
+
+    return res;
+}
+
+bool FakeFingerprintEngine::parseEnrollmentCaptureSingle(const std::string& str,
+                                                         std::vector<std::vector<int32_t>>& res) {
+    std::vector<int32_t> defaultAcquiredInfo = {(int32_t)AcquiredInfo::GOOD};
+    bool aborted = true;
+
+    do {
+        std::smatch sms;
+        // Parses strings like "1000-[5,1]" or "500"
+        std::regex ex("((\\d+)(-\\[([\\d|,]+)\\])?)");
+        if (!regex_match(str.cbegin(), str.cend(), sms, ex)) break;
+        int32_t duration;
+        if (!ParseInt(sms.str(2), &duration)) break;
+        res.push_back({duration});
+        if (!sms.str(4).empty()) {
+            auto acqv = parseIntSequence(sms.str(4));
+            if (acqv.empty()) break;
+            res.push_back(acqv);
+        } else
+            res.push_back(defaultAcquiredInfo);
+        aborted = false;
+    } while (0);
+
+    return !aborted;
+}
+
+std::vector<std::vector<int32_t>> FakeFingerprintEngine::parseEnrollmentCapture(
+        const std::string& str) {
+    std::vector<std::vector<int32_t>> res;
+
+    std::string s(str);
+    s.erase(std::remove_if(s.begin(), s.end(), ::isspace), s.end());
+    bool aborted = false;
+    std::smatch sms;
+    // Parses strings like "1000-[5,1],500,800-[6,5,1]"
+    //                      ---------- --- -----------
+    //  into parts:             A       B       C
+    while (regex_search(s, sms, std::regex("^(,)?(\\d+(-\\[[\\d|,]+\\])?)"))) {
+        if (!parseEnrollmentCaptureSingle(sms.str(2), res)) {
+            aborted = true;
+            break;
+        }
+        s = sms.suffix();
+    }
+    if (aborted || s.length() != 0) {
+        res.clear();
+        LOG(ERROR) << "Failed to parse enrollment captures:" + str;
+    }
+
+    return res;
+}
+
+std::pair<AcquiredInfo, int32_t> FakeFingerprintEngine::convertAcquiredInfo(int32_t code) {
+    std::pair<AcquiredInfo, int32_t> res;
+    if (code > FINGERPRINT_ACQUIRED_VENDOR_BASE) {
+        res.first = AcquiredInfo::VENDOR;
+        res.second = code - FINGERPRINT_ACQUIRED_VENDOR_BASE;
+    } else {
+        res.first = (AcquiredInfo)code;
+        res.second = 0;
+    }
+    return res;
+}
+
+std::pair<Error, int32_t> FakeFingerprintEngine::convertError(int32_t code) {
+    std::pair<Error, int32_t> res;
+    if (code > FINGERPRINT_ERROR_VENDOR_BASE) {
+        res.first = Error::VENDOR;
+        res.second = code - FINGERPRINT_ERROR_VENDOR_BASE;
+    } else {
+        res.first = (Error)code;
+        res.second = 0;
+    }
+    return res;
+}
+
+int32_t FakeFingerprintEngine::getLatency(
+        const std::vector<std::optional<std::int32_t>>& latencyIn) {
+    int32_t res = DEFAULT_LATENCY;
+
+    std::vector<int32_t> latency;
+    for (auto x : latencyIn)
+        if (x.has_value()) latency.push_back(*x);
+
+    switch (latency.size()) {
+        case 0:
+            break;
+        case 1:
+            res = latency[0];
+            break;
+        case 2:
+            res = getRandomInRange(latency[0], latency[1]);
+            break;
+        default:
+            LOG(ERROR) << "ERROR: unexpected input of size " << latency.size();
+            break;
+    }
+
+    return res;
+}
+
+int32_t FakeFingerprintEngine::getRandomInRange(int32_t bound1, int32_t bound2) {
+    std::uniform_int_distribution<int32_t> dist(std::min(bound1, bound2), std::max(bound1, bound2));
+    return dist(mRandom);
+}
+
 }  // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/FakeFingerprintEngineUdfps.cpp b/biometrics/fingerprint/aidl/default/FakeFingerprintEngineUdfps.cpp
index d8579a4..3cdfc70 100644
--- a/biometrics/fingerprint/aidl/default/FakeFingerprintEngineUdfps.cpp
+++ b/biometrics/fingerprint/aidl/default/FakeFingerprintEngineUdfps.cpp
@@ -23,10 +23,16 @@
 #include "util/CancellationSignal.h"
 #include "util/Util.h"
 
+#undef LOG_TAG
+#define LOG_TAG "FingerprintVirtualHalUdfps"
+
 using namespace ::android::fingerprint::virt;
 
 namespace aidl::android::hardware::biometrics::fingerprint {
 
+FakeFingerprintEngineUdfps::FakeFingerprintEngineUdfps()
+    : FakeFingerprintEngine(), mWorkMode(WorkMode::kIdle), mPointerDownTime(0), mUiReadyTime(0) {}
+
 SensorLocation FakeFingerprintEngineUdfps::defaultSensorLocation() {
     return {0 /* displayId (not used) */, defaultSensorLocationX /* sensorLocationX */,
             defaultSensorLocationY /* sensorLocationY */, defaultSensorRadius /* sensorRadius */,
@@ -37,22 +43,95 @@
                                                                  int32_t /*x*/, int32_t /*y*/,
                                                                  float /*minor*/, float /*major*/) {
     BEGIN_OP(0);
-
-    // TODO(b/230515082): if need to handle display touch events
-
+    // verify whetehr touch coordinates/area matching sensor location ?
+    mPointerDownTime = Util::getSystemNanoTime();
+    if (FingerprintHalProperties::control_illumination().value_or(false)) {
+        fingerDownAction();
+    }
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus FakeFingerprintEngineUdfps::onPointerUpImpl(int32_t /*pointerId*/) {
     BEGIN_OP(0);
-    // TODO(b/230515082)
+    mUiReadyTime = 0;
+    mPointerDownTime = 0;
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus FakeFingerprintEngineUdfps::onUiReadyImpl() {
     BEGIN_OP(0);
-    // TODO(b/230515082)
+
+    if (Util::hasElapsed(mPointerDownTime, uiReadyTimeoutInMs * 100)) {
+        LOG(ERROR) << "onUiReady() arrives too late after onPointerDown()";
+    } else {
+        fingerDownAction();
+    }
     return ndk::ScopedAStatus::ok();
 }
 
+void FakeFingerprintEngineUdfps::fingerDownAction() {
+    switch (mWorkMode) {
+        case WorkMode::kAuthenticate:
+            onAuthenticateFingerDown();
+            break;
+        case WorkMode::kEnroll:
+            onEnrollFingerDown();
+            break;
+        case WorkMode::kDetectInteract:
+            onDetectInteractFingerDown();
+            break;
+        default:
+            LOG(WARNING) << "unexpected call: onUiReady()";
+            break;
+    }
+
+    mUiReadyTime = 0;
+    mPointerDownTime = 0;
+}
+
+void FakeFingerprintEngineUdfps::onAuthenticateFingerDown() {
+    FakeFingerprintEngine::authenticateImpl(mCb, mOperationId, mCancelVec[0]);
+}
+
+void FakeFingerprintEngineUdfps::onEnrollFingerDown() {
+    // Any use case to emulate display touch for each capture during enrollment?
+    FakeFingerprintEngine::enrollImpl(mCb, mHat, mCancelVec[0]);
+}
+
+void FakeFingerprintEngineUdfps::onDetectInteractFingerDown() {
+    FakeFingerprintEngine::detectInteractionImpl(mCb, mCancelVec[0]);
+}
+
+void FakeFingerprintEngineUdfps::enrollImpl(ISessionCallback* cb,
+                                            const keymaster::HardwareAuthToken& hat,
+                                            const std::future<void>& cancel) {
+    updateContext(WorkMode::kEnroll, cb, const_cast<std::future<void>&>(cancel), 0, hat);
+}
+
+void FakeFingerprintEngineUdfps::authenticateImpl(ISessionCallback* cb, int64_t operationId,
+                                                  const std::future<void>& cancel) {
+    updateContext(WorkMode::kAuthenticate, cb, const_cast<std::future<void>&>(cancel), operationId,
+                  keymaster::HardwareAuthToken());
+}
+
+void FakeFingerprintEngineUdfps::detectInteractionImpl(ISessionCallback* cb,
+                                                       const std::future<void>& cancel) {
+    updateContext(WorkMode::kDetectInteract, cb, const_cast<std::future<void>&>(cancel), 0,
+                  keymaster::HardwareAuthToken());
+}
+
+void FakeFingerprintEngineUdfps::updateContext(WorkMode mode, ISessionCallback* cb,
+                                               std::future<void>& cancel, int64_t operationId,
+                                               const keymaster::HardwareAuthToken& hat) {
+    mPointerDownTime = 0;
+    mUiReadyTime = 0;
+    mCancelVec.clear();
+
+    mCancelVec.push_back(std::move(cancel));
+    mWorkMode = mode;
+    mCb = cb;
+    mOperationId = operationId;
+    mHat = hat;
+}
+
 }  // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/FakeLockoutTracker.cpp b/biometrics/fingerprint/aidl/default/FakeLockoutTracker.cpp
new file mode 100644
index 0000000..5996406
--- /dev/null
+++ b/biometrics/fingerprint/aidl/default/FakeLockoutTracker.cpp
@@ -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.
+ */
+
+#include "FakeLockoutTracker.h"
+#include <fingerprint.sysprop.h>
+#include "util/Util.h"
+
+using namespace ::android::fingerprint::virt;
+
+namespace aidl::android::hardware::biometrics::fingerprint {
+
+void FakeLockoutTracker::reset() {
+    mFailedCount = 0;
+    mLockoutTimedStart = 0;
+    mCurrentMode = LockoutMode::kNone;
+}
+
+void FakeLockoutTracker::addFailedAttempt() {
+    bool enabled = FingerprintHalProperties::lockout_enable().value_or(false);
+    if (enabled) {
+        mFailedCount++;
+        int32_t lockoutTimedThreshold =
+                FingerprintHalProperties::lockout_timed_threshold().value_or(5);
+        int32_t lockoutPermanetThreshold =
+                FingerprintHalProperties::lockout_permanent_threshold().value_or(20);
+        if (mFailedCount >= lockoutPermanetThreshold) {
+            mCurrentMode = LockoutMode::kPermanent;
+            FingerprintHalProperties::lockout(true);
+        } else if (mFailedCount >= lockoutTimedThreshold) {
+            if (mCurrentMode == LockoutMode::kNone) {
+                mCurrentMode = LockoutMode::kTimed;
+                mLockoutTimedStart = Util::getSystemNanoTime();
+            }
+        }
+    } else {
+        reset();
+    }
+}
+
+FakeLockoutTracker::LockoutMode FakeLockoutTracker::getMode() {
+    if (mCurrentMode == LockoutMode::kTimed) {
+        int32_t lockoutTimedDuration =
+                FingerprintHalProperties::lockout_timed_duration().value_or(10 * 100);
+        if (Util::hasElapsed(mLockoutTimedStart, lockoutTimedDuration)) {
+            mCurrentMode = LockoutMode::kNone;
+            mLockoutTimedStart = 0;
+        }
+    }
+
+    return mCurrentMode;
+}
+
+int64_t FakeLockoutTracker::getLockoutTimeLeft() {
+    int64_t res = 0;
+
+    if (mLockoutTimedStart > 0) {
+        auto now = Util::getSystemNanoTime();
+        auto left = now - mLockoutTimedStart;
+        res = (left > 0) ? (left / 1000000LL) : 0;
+    }
+
+    return res;
+}
+}  // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/Fingerprint.cpp b/biometrics/fingerprint/aidl/default/Fingerprint.cpp
index 922781c..be93224 100644
--- a/biometrics/fingerprint/aidl/default/Fingerprint.cpp
+++ b/biometrics/fingerprint/aidl/default/Fingerprint.cpp
@@ -15,11 +15,13 @@
  */
 
 #include "Fingerprint.h"
-
-#include <fingerprint.sysprop.h>
 #include "Session.h"
 
+#include <fingerprint.sysprop.h>
+
+#include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/stringprintf.h>
 
 using namespace ::android::fingerprint::virt;
 
@@ -64,19 +66,31 @@
             {HW_COMPONENT_ID, HW_VERSION, FW_VERSION, SERIAL_NUMBER, "" /* softwareVersion */},
             {SW_COMPONENT_ID, "" /* hardwareVersion */, "" /* firmwareVersion */,
              "" /* serialNumber */, SW_VERSION}};
+    auto sensorId = FingerprintHalProperties::sensor_id().value_or(SENSOR_ID);
+    auto sensorStrength =
+            FingerprintHalProperties::sensor_strength().value_or((int)SENSOR_STRENGTH);
+    auto maxEnrollments =
+            FingerprintHalProperties::max_enrollments().value_or(MAX_ENROLLMENTS_PER_USER);
+    auto navigationGuesture = FingerprintHalProperties::navigation_guesture().value_or(false);
+    auto detectInteraction = FingerprintHalProperties::detect_interaction().value_or(false);
+    auto displayTouch = FingerprintHalProperties::display_touch().value_or(true);
+    auto controlIllumination = FingerprintHalProperties::control_illumination().value_or(false);
 
-    common::CommonProps commonProps = {SENSOR_ID, SENSOR_STRENGTH, MAX_ENROLLMENTS_PER_USER,
-                                       componentInfo};
+    common::CommonProps commonProps = {sensorId, (common::SensorStrength)sensorStrength,
+                                       maxEnrollments, componentInfo};
 
     SensorLocation sensorLocation = mEngine->getSensorLocation();
 
-    LOG(INFO) << "sensor type:" << (int)mSensorType << " location:" << sensorLocation.toString();
+    LOG(INFO) << "sensor type:" << ::android::internal::ToString(mSensorType)
+              << " location:" << sensorLocation.toString();
 
     *out = {{commonProps,
              mSensorType,
              {sensorLocation},
-             SUPPORTS_NAVIGATION_GESTURES,
-             false /* supportsDetectInteraction */}};
+             navigationGuesture,
+             detectInteraction,
+             displayTouch,
+             controlIllumination}};
     return ndk::ScopedAStatus::ok();
 }
 
@@ -92,4 +106,96 @@
     return ndk::ScopedAStatus::ok();
 }
 
+binder_status_t Fingerprint::dump(int fd, const char** /*args*/, uint32_t numArgs) {
+    if (fd < 0) {
+        LOG(ERROR) << "Fingerprint::dump fd invalid: " << fd;
+        return STATUS_BAD_VALUE;
+    } else {
+        LOG(INFO) << "Fingerprint::dump fd:" << fd << "numArgs:" << numArgs;
+    }
+
+    dprintf(fd, "----- FingerprintVirtualHal::dump -----\n");
+    std::vector<SensorProps> sps(1);
+    getSensorProps(&sps);
+    for (auto& sp : sps) {
+        ::android::base::WriteStringToFd(sp.toString(), fd);
+    }
+    ::android::base::WriteStringToFd(mEngine->toString(), fd);
+
+    fsync(fd);
+    return STATUS_OK;
+}
+
+binder_status_t Fingerprint::handleShellCommand(int in, int out, int err, const char** args,
+                                                uint32_t numArgs) {
+    LOG(INFO) << "Fingerprint::handleShellCommand in:" << in << " out:" << out << " err:" << err
+              << " numArgs:" << numArgs;
+
+    if (numArgs == 0) {
+        LOG(INFO) << "Fingerprint::handleShellCommand: available commands";
+        onHelp(out);
+        return STATUS_OK;
+    }
+
+    for (auto&& str : std::vector<std::string_view>(args, args + numArgs)) {
+        std::string option = str.data();
+        if (option.find("clearconfig") != std::string::npos ||
+            option.find("resetconfig") != std::string::npos) {
+            resetConfigToDefault();
+        }
+        if (option.find("help") != std::string::npos) {
+            onHelp(out);
+        }
+    }
+
+    return STATUS_OK;
+}
+
+void Fingerprint::onHelp(int fd) {
+    dprintf(fd, "Virtual HAL commands:\n");
+    dprintf(fd, "         help: print this help\n");
+    dprintf(fd, "  resetconfig: reset all configuration to default\n");
+    dprintf(fd, "\n");
+    fsync(fd);
+}
+
+void Fingerprint::resetConfigToDefault() {
+    LOG(INFO) << "reset virtual HAL configuration to default";
+#define RESET_CONFIG_O(__NAME__) \
+    if (FingerprintHalProperties::__NAME__()) FingerprintHalProperties::__NAME__(std::nullopt)
+#define RESET_CONFIG_V(__NAME__)                       \
+    if (!FingerprintHalProperties::__NAME__().empty()) \
+    FingerprintHalProperties::__NAME__({std::nullopt})
+
+    RESET_CONFIG_O(type);
+    RESET_CONFIG_V(enrollments);
+    RESET_CONFIG_O(enrollment_hit);
+    RESET_CONFIG_O(authenticator_id);
+    RESET_CONFIG_O(challenge);
+    RESET_CONFIG_O(lockout);
+    RESET_CONFIG_O(operation_authenticate_fails);
+    RESET_CONFIG_O(operation_detect_interaction_error);
+    RESET_CONFIG_O(operation_enroll_error);
+    RESET_CONFIG_V(operation_authenticate_latency);
+    RESET_CONFIG_V(operation_detect_interaction_latency);
+    RESET_CONFIG_V(operation_enroll_latency);
+    RESET_CONFIG_O(operation_authenticate_duration);
+    RESET_CONFIG_O(operation_authenticate_error);
+    RESET_CONFIG_O(sensor_location);
+    RESET_CONFIG_O(operation_authenticate_acquired);
+    RESET_CONFIG_O(operation_detect_interaction_duration);
+    RESET_CONFIG_O(operation_detect_interaction_acquired);
+    RESET_CONFIG_O(sensor_id);
+    RESET_CONFIG_O(sensor_strength);
+    RESET_CONFIG_O(max_enrollments);
+    RESET_CONFIG_O(navigation_guesture);
+    RESET_CONFIG_O(detect_interaction);
+    RESET_CONFIG_O(display_touch);
+    RESET_CONFIG_O(control_illumination);
+    RESET_CONFIG_O(lockout_enable);
+    RESET_CONFIG_O(lockout_timed_threshold);
+    RESET_CONFIG_O(lockout_timed_duration);
+    RESET_CONFIG_O(lockout_permanent_threshold);
+}
+
 }  // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/README.md b/biometrics/fingerprint/aidl/default/README.md
index bb6bb48..49b6c9d 100644
--- a/biometrics/fingerprint/aidl/default/README.md
+++ b/biometrics/fingerprint/aidl/default/README.md
@@ -57,6 +57,7 @@
       ```shell
       $ adb shell setprop vendor.fingerprint.virtual.next_enrollment 1:100,100,100:true
       ```
+
 3. Navigate to `Settings -> Security -> Fingerprint Unlock` and follow the
    prompts.
 4. Verify the enrollments in the UI:
@@ -65,7 +66,7 @@
       $ adb shell getprop persist.vendor.fingerprint.virtual.enrollments
       ```
 
-### Authenticate
+## Authenticate
 
 To authenticate successfully set the enrolled id that should succeed. Unset it
 or change the value to make authenticate operations fail:
@@ -74,10 +75,91 @@
 $ adb shell setprop vendor.fingerprint.virtual.enrollment_hit 1
 ````
 
-### View HAL State
+## Acquired Info Insertion
+
+Fingerprint image acquisition states at HAL are reported to framework via onAcquired() callback. The valid acquired state info for AIDL HAL include
+
+{UNKNOWN(0), GOOD(1), PARTIAL(2), INSUFFICIENT(3), SENSOR_DIRTY(4), TOO_SLOW(5), TOO_FAST(6), VENDOR(7), START(8), TOO_DARK(9), TOO_BRIGHT(10), IMMOBILE(11), RETRYING_CAPTURE(12)}
+
+Refer to [AcquiredInfo.aidl](../android/hardware/biometrics/fingerprint/AcquiredInfo.aidl) for details
+
+
+The states can be specified in sequence for the HAL operations involving fingerprint image captures, namely authenticate, enrollment and detectInteraction
+
+```shell
+$ adb shell setprop vendor.fingerprint.virtual.operation_authenticate_acquired 6,9,1
+$ adb shell setprop vendor.fingerprint.virtual.operation_detect_interaction_acquired 6,1
+$ adb shell setprop vendor.fingerprint.virtual.next_enrollment 2:1000-[5,1],500:true
+
+#next_enrollment format example:
+.---------------------- enrollment id (2)
+|   .------------------ the image capture 1 duration (1000ms)
+|   |   .--------------   acquired info first (TOO_SLOW)
+|   |   | .------------   acquired info second (GOOD)
+|   |   | |   .-------- the image capture 2 duration (500ms)
+|   |   | |   |   .---- enrollment end status (success)
+|   |   | |   |   |
+|   |   | |   |   |
+|   |   | |   |   |
+2:1000-[5,1],500:true
+```
+For vendor specific acquired info, acquiredInfo = 1000 + vendorAcquiredInfo
+
+## Error Insertion
+The valid error codes for AIDL HAL include
+
+{UNKNOWN(0), HW_UNAVAILABLE(1), UNABLE_TO_PROCESS(2), TIMEOUT(3), NO_SPACE(4), CANCELED(5), UNABLE_TO_REMOVE(6), VENDOR(7), BAD_CALIBRATION(8)}
+
+Refer to [Error.aidl](../android/hardware/biometrics/fingerprint/Error.aidl) for details
+
+
+There are many HAL operations which can result in errors, refer to [here](fingerprint.sysprop) file for details.
+
+```shell
+$ adb shell setprop vendor.fingerprint.virtual.operation_authenticate_error 8
+```
+For vendor specific error, errorCode = 1000 + vendorErrorCode
+
+## Latency Insertion
+Three HAL operations (authenticate, enrollment and detect interaction) latency can be optionally specified in multiple ways
+1. default latency is fixed at 400 ms if not specified via sysprop
+2. specify authenticate operation latency to 900 ms
+      ```shell adb shell setprop vendor.fingerprint.virtual.operation_authenticate_latency 900```
+3. specify authenticate operation latency between 600 to 1200 ms in unifrom distribution
+      ```shelladb shell setprop vendor.fingerprint.virtual.operation_authenticate_latency 600,1200```
+
+## Lockout
+To force the device into lockout state
+```shell
+$ adb shell setprop persist.vendor.fingerprint.virtual.lockout true
+```
+To test permanent lockout based on the failed authentication attempts (e.g. 7)
+```shell
+$ adb shell setprop persist.vendor.fingerprint.virtual.lockout_permanent_threshold 7
+$ adb shell setprop persist.vendor.fingerprint.virtual.lockout_enable true
+```
+To test timed lockout based on the failed authentication attempts (e.g. 8 seconds on 5 attempts)
+```shell
+$ adb shell setprop persist.vendor.fingerprint.virtual.lockout_timed_duration 8000
+$ adb shell setprop persist.vendor.fingerprint.virtual.lockout_timed_threshold 5
+$ adb shell setprop persist.vendor.fingerprint.virtual.lockout_enable true
+```
+
+## Reset all configurations to default
+The following command will reset virtual configurations (related system properties) to default value.
+```shell
+$ adb shell cmd android.hardware.biometrics.fingerprint.IFingerprint/virtual resetconfig
+$ adb reboot
+```
+
+## View HAL State
 
 To view all the properties of the HAL (see `fingerprint.sysprop` file for the API):
 
 ```shell
 $ adb shell getprop | grep vendor.fingerprint.virtual
 ```
+To dump virtual HAL internal data
+```shell
+adb shell dumpsys android.hardware.biometrics.fingerprint.IFingerprint/virtual
+```
diff --git a/biometrics/fingerprint/aidl/default/Session.cpp b/biometrics/fingerprint/aidl/default/Session.cpp
index e51f677..7ab5af3 100644
--- a/biometrics/fingerprint/aidl/default/Session.cpp
+++ b/biometrics/fingerprint/aidl/default/Session.cpp
@@ -20,6 +20,9 @@
 
 #include "util/CancellationSignal.h"
 
+#undef LOG_TAG
+#define LOG_TAG "FingerprintVirtualHalSession"
+
 namespace aidl::android::hardware::biometrics::fingerprint {
 
 Session::Session(int sensorId, int userId, std::shared_ptr<ISessionCallback> cb,
diff --git a/biometrics/fingerprint/aidl/default/api/android.hardware.biometrics.fingerprint.VirtualProps-current.txt b/biometrics/fingerprint/aidl/default/api/android.hardware.biometrics.fingerprint.VirtualProps-current.txt
index 9dfb74d..e69de29 100644
--- a/biometrics/fingerprint/aidl/default/api/android.hardware.biometrics.fingerprint.VirtualProps-current.txt
+++ b/biometrics/fingerprint/aidl/default/api/android.hardware.biometrics.fingerprint.VirtualProps-current.txt
@@ -1,91 +0,0 @@
-props {
-  owner: Vendor
-  module: "android.fingerprint.virt.FingerprintHalProperties"
-  prop {
-    api_name: "authenticator_id"
-    type: Long
-    access: ReadWrite
-    prop_name: "vendor.fingerprint.virtual.authenticator_id"
-  }
-  prop {
-    api_name: "challenge"
-    type: Long
-    access: ReadWrite
-    prop_name: "vendor.fingerprint.virtual.challenge"
-  }
-  prop {
-    api_name: "enrollment_hit"
-    type: Integer
-    access: ReadWrite
-    prop_name: "vendor.fingerprint.virtual.enrollment_hit"
-  }
-  prop {
-    api_name: "enrollments"
-    type: IntegerList
-    access: ReadWrite
-    prop_name: "persist.vendor.fingerprint.virtual.enrollments"
-  }
-  prop {
-    api_name: "lockout"
-    access: ReadWrite
-    prop_name: "vendor.fingerprint.virtual.lockout"
-  }
-  prop {
-    api_name: "next_enrollment"
-    type: String
-    access: ReadWrite
-    prop_name: "vendor.fingerprint.virtual.next_enrollment"
-  }
-  prop {
-    api_name: "operation_authenticate_duration"
-    type: Integer
-    access: ReadWrite
-    prop_name: "vendor.fingerprint.virtual.operation_authenticate_duration"
-  }
-  prop {
-    api_name: "operation_authenticate_fails"
-    access: ReadWrite
-    prop_name: "vendor.fingerprint.virtual.operation_authenticate_fails"
-  }
-  prop {
-    api_name: "operation_authenticate_latency"
-    type: Integer
-    access: ReadWrite
-    prop_name: "vendor.fingerprint.virtual.operation_authenticate_latency"
-  }
-  prop {
-    api_name: "operation_detect_interaction_fails"
-    access: ReadWrite
-    prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_fails"
-  }
-  prop {
-    api_name: "operation_detect_interaction_latency"
-    type: Integer
-    access: ReadWrite
-    prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_latency"
-  }
-  prop {
-    api_name: "operation_enroll_fails"
-    access: ReadWrite
-    prop_name: "vendor.fingerprint.virtual.operation_enroll_fails"
-  }
-  prop {
-    api_name: "operation_enroll_latency"
-    type: Integer
-    access: ReadWrite
-    prop_name: "vendor.fingerprint.virtual.operation_enroll_latency"
-  }
-  prop {
-    api_name: "sensor_location"
-    type: String
-    access: ReadWrite
-    prop_name: "persist.vendor.fingerprint.virtual.sensor_location"
-  }
-  prop {
-    api_name: "type"
-    type: String
-    access: ReadWrite
-    prop_name: "persist.vendor.fingerprint.virtual.type"
-    enum_values: "default|rear|udfps|side"
-  }
-}
diff --git a/biometrics/fingerprint/aidl/default/fingerprint-example.xml b/biometrics/fingerprint/aidl/default/fingerprint-example.xml
index 05d1279..e977b98 100644
--- a/biometrics/fingerprint/aidl/default/fingerprint-example.xml
+++ b/biometrics/fingerprint/aidl/default/fingerprint-example.xml
@@ -1,7 +1,7 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.biometrics.fingerprint</name>
-        <version>2</version>
+        <version>3</version>
         <fqname>IFingerprint/virtual</fqname>
     </hal>
 </manifest>
diff --git a/biometrics/fingerprint/aidl/default/fingerprint.sysprop b/biometrics/fingerprint/aidl/default/fingerprint.sysprop
index 85e93b0..6a6c297 100644
--- a/biometrics/fingerprint/aidl/default/fingerprint.sysprop
+++ b/biometrics/fingerprint/aidl/default/fingerprint.sysprop
@@ -7,7 +7,7 @@
 prop {
     prop_name: "persist.vendor.fingerprint.virtual.type"
     type: String
-    scope: Public
+    scope: Internal
     access: ReadWrite
     enum_values: "default|rear|udfps|side"
     api_name: "type"
@@ -17,7 +17,7 @@
 prop {
     prop_name: "persist.vendor.fingerprint.virtual.enrollments"
     type: IntegerList
-    scope: Public
+    scope: Internal
     access: ReadWrite
     api_name: "enrollments"
 }
@@ -27,27 +27,31 @@
 prop {
     prop_name: "vendor.fingerprint.virtual.enrollment_hit"
     type: Integer
-    scope: Public
+    scope: Internal
     access: ReadWrite
     api_name: "enrollment_hit"
 }
 
-# the next enrollment in the format: "<id>:<delay>,<delay>,...:<result>"
-# for example: "2:0:true"
+# the next enrollment in the format of:
+# "<id>:<delay>,<delay>,...:<result>"
+# <delay> = <duration-[acquiredInfos]>
+# [acquiredInfos] = [acquiredInfo1, acquiredInfo2, ...]
+# (refer to README.md file for acquiredInfo values)
+# e.g. "2:100,20:true", "2:100-[5,1],20:true"
 # this property is reset after enroll completes
 prop {
     prop_name: "vendor.fingerprint.virtual.next_enrollment"
     type: String
-    scope: Public
+    scope: Internal
     access: ReadWrite
     api_name: "next_enrollment"
 }
 
 # value for getAuthenticatorId or 0
 prop {
-    prop_name: "vendor.fingerprint.virtual.authenticator_id"
+    prop_name: "persist.vendor.fingerprint.virtual.authenticator_id"
     type: Long
-    scope: Public
+    scope: Internal
     access: ReadWrite
     api_name: "authenticator_id"
 }
@@ -56,70 +60,71 @@
 prop {
     prop_name: "vendor.fingerprint.virtual.challenge"
     type: Long
-    scope: Public
+    scope: Internal
     access: ReadWrite
     api_name: "challenge"
 }
 
-# if locked out
-prop {
-    prop_name: "vendor.fingerprint.virtual.lockout"
-    type: Boolean
-    scope: Public
-    access: ReadWrite
-    api_name: "lockout"
-}
-
 # force all authenticate operations to fail
 prop {
     prop_name: "vendor.fingerprint.virtual.operation_authenticate_fails"
     type: Boolean
-    scope: Public
+    scope: Internal
     access: ReadWrite
     api_name: "operation_authenticate_fails"
 }
 
-# force all detectInteraction operations to fail
+# force all detectInteraction operations to error out
+# error consists of errorCode and vendorErrorCode
+# valid errorCodes are listed in README.md file
+# vendorErrorCode = (error>1000) ? error-1000 : 0
+# e.g. error(1002) --> errorCode(7) and vendorErrorCode(2)
 prop {
-    prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_fails"
-    type: Boolean
-    scope: Public
+    prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_error"
+    type: Integer
+    scope: Internal
     access: ReadWrite
-    api_name: "operation_detect_interaction_fails"
+    api_name: "operation_detect_interaction_error"
 }
 
-# force all enroll operations to fail
+# force all enroll operations to result in error
 prop {
-    prop_name: "vendor.fingerprint.virtual.operation_enroll_fails"
-    type: Boolean
-    scope: Public
+    prop_name: "vendor.fingerprint.virtual.operation_enroll_error"
+    type: Integer
+    scope: Internal
     access: ReadWrite
-    api_name: "operation_enroll_fails"
+    api_name: "operation_enroll_error"
 }
 
 # add a latency to authentication operations
+#   default to 400ms
+#   [x] = x ms
+#   [x,y] = randomly between x and y ms
+#   others = invalid
 prop {
     prop_name: "vendor.fingerprint.virtual.operation_authenticate_latency"
-    type: Integer
-    scope: Public
+    type: IntegerList
+    scope: Internal
     access: ReadWrite
     api_name: "operation_authenticate_latency"
 }
 
 # add a latency to detectInteraction operations
+#   refer to `operation_authenticate_latency` above for usage
 prop {
     prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_latency"
-    type: Integer
-    scope: Public
+    type: IntegerList
+    scope: Internal
     access: ReadWrite
     api_name: "operation_detect_interaction_latency"
 }
 
 # add a latency to enroll operations
+#   refer to `operation_authenticate_latency` above for usage
 prop {
     prop_name: "vendor.fingerprint.virtual.operation_enroll_latency"
-    type: Integer
-    scope: Public
+    type: IntegerList
+    scope: Internal
     access: ReadWrite
     api_name: "operation_enroll_latency"
 }
@@ -129,17 +134,167 @@
 prop {
     prop_name: "vendor.fingerprint.virtual.operation_authenticate_duration"
     type: Integer
-    scope: Public
+    scope: Internal
     access: ReadWrite
     api_name: "operation_authenticate_duration"
 }
 
+# insert error for authenticate operations
+prop {
+    prop_name: "vendor.fingerprint.virtual.operation_authenticate_error"
+    type: Integer
+    scope: Internal
+    access: ReadWrite
+    api_name: "operation_authenticate_error"
+}
+
 # sensor location
 #    <x>:<y>:<radius> in pixel
 prop {
     prop_name: "persist.vendor.fingerprint.virtual.sensor_location"
     type: String
-    scope: Public
+    scope: Internal
     access: ReadWrite
     api_name: "sensor_location"
 }
+
+# acquired info during authentication in format of sequence
+prop {
+    prop_name: "vendor.fingerprint.virtual.operation_authenticate_acquired"
+    type: String
+    scope: Internal
+    access: ReadWrite
+    api_name: "operation_authenticate_acquired"
+}
+
+# millisecond duration for detect interaction operations
+# (waits for changes to enrollment_hit)
+prop {
+    prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_duration"
+    type: Integer
+    scope: Internal
+    access: ReadWrite
+    api_name: "operation_detect_interaction_duration"
+}
+
+# acquired info during detect interaction operation in format of sequence
+# e.g. 5,6,1  (TOO_SLOW, TOO_FAST, GOOD)
+# onAcquired() callback will be invoked in sequence
+# vendorAcquiredCode = (acquired>1000) ? acquired-1000 : 0
+prop {
+    prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_acquired"
+    type: String
+    scope: Internal
+    access: ReadWrite
+    api_name: "operation_detect_interaction_acquired"
+}
+
+# sensor id (default: 5)
+prop {
+    prop_name: "persist.vendor.fingerprint.virtual.sensor_id"
+    type: Integer
+    scope: Internal
+    access: ReadWrite
+    api_name: "sensor_id"
+}
+
+# sensor strength (default: 2)
+# [0=CONVENECE, 1=WEAK, 2=STRONG]
+prop {
+    prop_name: "persist.vendor.fingerprint.virtual.sensor_strength"
+    type: Integer
+    scope: Internal
+    access: ReadWrite
+    api_name: "sensor_strength"
+}
+
+# max enrollments per user (default: 5)
+#
+prop {
+    prop_name: "persist.vendor.fingerprint.virtual.max_enrollments"
+    type: Integer
+    scope: Internal
+    access: ReadWrite
+    api_name: "max_enrollments"
+}
+
+# whether support navigation guestures (default: false)
+prop {
+    prop_name: "persist.vendor.fingerprint.virtual.navigation_guesture"
+    type: Boolean
+    scope: Internal
+    access: ReadWrite
+    api_name: "navigation_guesture"
+}
+
+# whether support detect interaction (default: false)
+prop {
+    prop_name: "persist.vendor.fingerprint.virtual.detect_interaction"
+    type: Boolean
+    scope: Internal
+    access: ReadWrite
+    api_name: "detect_interaction"
+}
+
+# whether support display touch by hal (default: true)
+prop {
+    prop_name: "persist.vendor.fingerprint.virtual.udfps.display_touch"
+    type: Boolean
+    scope: Internal
+    access: ReadWrite
+    api_name: "display_touch"
+}
+
+# whether support illumination control  by hal (default: false)
+prop {
+    prop_name: "persist.vendor.fingerprint.virtual.udfps.control_illumination"
+    type: Boolean
+    scope: Internal
+    access: ReadWrite
+    api_name: "control_illumination"
+}
+
+# force to be locked out (default: false)
+prop {
+    prop_name: "persist.vendor.fingerprint.virtual.lockout"
+    type: Boolean
+    scope: Internal
+    access: ReadWrite
+    api_name: "lockout"
+}
+
+# whether support lockout based on the failed auth attempts (default: false)
+prop {
+    prop_name: "persist.vendor.fingerprint.virtual.lockout_enable"
+    type: Boolean
+    scope: Internal
+    access: ReadWrite
+    api_name: "lockout_enable"
+}
+
+# temporarily lockout threshold in number of consecutive failed auth attempts (default: 5)
+prop {
+    prop_name: "persist.vendor.fingerprint.virtual.lockout_timed_threshold"
+    type: Integer
+    scope: Internal
+    access: ReadWrite
+    api_name: "lockout_timed_threshold"
+}
+
+# temporary lockout duration in ms (default: 10000ms)
+prop {
+    prop_name: "persist.vendor.fingerprint.virtual.lockout_timed_duration"
+    type: Integer
+    scope: Internal
+    access: ReadWrite
+    api_name: "lockout_timed_duration"
+}
+
+# permanently lockout threshold  in number of consecutive failed auth attempts (default: 20)
+prop {
+    prop_name: "persist.vendor.fingerprint.virtual.lockout_permanent_threshold"
+    type: Integer
+    scope: Internal
+    access: ReadWrite
+    api_name: "lockout_permanent_threshold"
+}
diff --git a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
index d7df818..1279cd9 100644
--- a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
+++ b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,8 +15,13 @@
  */
 
 #pragma once
+
+#define LOG_TAG "FingerprintVirtualHal"
+
 #include <aidl/android/hardware/biometrics/common/SensorStrength.h>
 #include <aidl/android/hardware/biometrics/fingerprint/ISessionCallback.h>
+#include <android/binder_to_string.h>
+#include <string>
 
 #include <random>
 
@@ -24,6 +29,8 @@
 #include <future>
 #include <vector>
 
+#include "FakeLockoutTracker.h"
+
 using namespace ::aidl::android::hardware::biometrics::common;
 
 namespace aidl::android::hardware::biometrics::fingerprint {
@@ -36,11 +43,11 @@
 
     void generateChallengeImpl(ISessionCallback* cb);
     void revokeChallengeImpl(ISessionCallback* cb, int64_t challenge);
-    void enrollImpl(ISessionCallback* cb, const keymaster::HardwareAuthToken& hat,
-                    const std::future<void>& cancel);
-    void authenticateImpl(ISessionCallback* cb, int64_t operationId,
-                          const std::future<void>& cancel);
-    void detectInteractionImpl(ISessionCallback* cb, const std::future<void>& cancel);
+    virtual void enrollImpl(ISessionCallback* cb, const keymaster::HardwareAuthToken& hat,
+                            const std::future<void>& cancel);
+    virtual void authenticateImpl(ISessionCallback* cb, int64_t operationId,
+                                  const std::future<void>& cancel);
+    virtual void detectInteractionImpl(ISessionCallback* cb, const std::future<void>& cancel);
     void enumerateEnrollmentsImpl(ISessionCallback* cb);
     void removeEnrollmentsImpl(ISessionCallback* cb, const std::vector<int32_t>& enrollmentIds);
     void getAuthenticatorIdImpl(ISessionCallback* cb);
@@ -59,7 +66,33 @@
 
     virtual SensorLocation defaultSensorLocation();
 
+    std::vector<int32_t> parseIntSequence(const std::string& str, const std::string& sep = ",");
+
+    std::vector<std::vector<int32_t>> parseEnrollmentCapture(const std::string& str);
+
+    int32_t getLatency(const std::vector<std::optional<std::int32_t>>& latencyVec);
+
     std::mt19937 mRandom;
+
+    virtual std::string toString() const {
+        std::ostringstream os;
+        os << "----- FakeFingerprintEngine:: -----" << std::endl;
+        os << "acquiredVendorInfoBase:" << FINGERPRINT_ACQUIRED_VENDOR_BASE;
+        os << ", errorVendorBase:" << FINGERPRINT_ERROR_VENDOR_BASE << std::endl;
+        os << mLockoutTracker.toString();
+        return os.str();
+    }
+
+  private:
+    static constexpr int32_t FINGERPRINT_ACQUIRED_VENDOR_BASE = 1000;
+    static constexpr int32_t FINGERPRINT_ERROR_VENDOR_BASE = 1000;
+    std::pair<AcquiredInfo, int32_t> convertAcquiredInfo(int32_t code);
+    std::pair<Error, int32_t> convertError(int32_t code);
+    bool parseEnrollmentCaptureSingle(const std::string& str,
+                                      std::vector<std::vector<int32_t>>& res);
+    int32_t getRandomInRange(int32_t bound1, int32_t bound2);
+
+    FakeLockoutTracker mLockoutTracker;
 };
 
 }  // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngineRear.h b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngineRear.h
index 1600a4b..14d5399 100644
--- a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngineRear.h
+++ b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngineRear.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngineSide.h b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngineSide.h
index 4e44d16..c2fc005 100644
--- a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngineSide.h
+++ b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngineSide.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngineUdfps.h b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngineUdfps.h
index b86af73..c5e93e7 100644
--- a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngineUdfps.h
+++ b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngineUdfps.h
@@ -28,17 +28,55 @@
     static constexpr int32_t defaultSensorLocationY = 1600;
     static constexpr int32_t defaultSensorRadius = 150;
 
-    FakeFingerprintEngineUdfps() : FakeFingerprintEngine() {}
+    static constexpr int32_t uiReadyTimeoutInMs = 5000;
+
+    FakeFingerprintEngineUdfps();
     ~FakeFingerprintEngineUdfps() {}
 
-    virtual ndk::ScopedAStatus onPointerDownImpl(int32_t pointerId, int32_t x, int32_t y,
-                                                 float minor, float major) override;
+    ndk::ScopedAStatus onPointerDownImpl(int32_t pointerId, int32_t x, int32_t y, float minor,
+                                         float major) override;
 
-    virtual ndk::ScopedAStatus onPointerUpImpl(int32_t pointerId) override;
+    ndk::ScopedAStatus onPointerUpImpl(int32_t pointerId) override;
 
-    virtual ndk::ScopedAStatus onUiReadyImpl() override;
+    ndk::ScopedAStatus onUiReadyImpl() override;
 
-    virtual SensorLocation defaultSensorLocation() override;
+    SensorLocation defaultSensorLocation() override;
+
+    void enrollImpl(ISessionCallback* cb, const keymaster::HardwareAuthToken& hat,
+                    const std::future<void>& cancel);
+    void authenticateImpl(ISessionCallback* cb, int64_t operationId,
+                          const std::future<void>& cancel);
+    void detectInteractionImpl(ISessionCallback* cb, const std::future<void>& cancel);
+
+    enum class WorkMode : int8_t { kIdle = 0, kAuthenticate, kEnroll, kDetectInteract };
+
+    WorkMode getWorkMode() { return mWorkMode; }
+
+    std::string toString() const {
+        std::ostringstream os;
+        os << FakeFingerprintEngine::toString();
+        os << "----- FakeFingerprintEngineUdfps -----" << std::endl;
+        os << "mWorkMode:" << (int)mWorkMode;
+        os << ", mUiReadyTime:" << mUiReadyTime;
+        os << ", mPointerDownTime:" << mPointerDownTime << std::endl;
+        return os.str();
+    }
+
+  private:
+    void onAuthenticateFingerDown();
+    void onEnrollFingerDown();
+    void onDetectInteractFingerDown();
+    void fingerDownAction();
+    void updateContext(WorkMode mode, ISessionCallback* cb, std::future<void>& cancel,
+                       int64_t operationId, const keymaster::HardwareAuthToken& hat);
+
+    WorkMode mWorkMode;
+    ISessionCallback* mCb;
+    keymaster::HardwareAuthToken mHat;
+    std::vector<std::future<void>> mCancelVec;
+    int64_t mOperationId;
+    int64_t mPointerDownTime;
+    int64_t mUiReadyTime;
 };
 
 }  // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/include/FakeLockoutTracker.h b/biometrics/fingerprint/aidl/default/include/FakeLockoutTracker.h
new file mode 100644
index 0000000..a1b6128
--- /dev/null
+++ b/biometrics/fingerprint/aidl/default/include/FakeLockoutTracker.h
@@ -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.
+ */
+
+#pragma once
+
+#include <android/binder_to_string.h>
+#include <stdint.h>
+#include <string>
+
+namespace aidl::android::hardware::biometrics::fingerprint {
+
+class FakeLockoutTracker {
+  public:
+    FakeLockoutTracker() : mFailedCount(0) {}
+    ~FakeLockoutTracker() {}
+
+    enum class LockoutMode : int8_t { kNone = 0, kTimed, kPermanent };
+
+    void reset();
+    LockoutMode getMode();
+    void addFailedAttempt();
+    int64_t getLockoutTimeLeft();
+    inline std::string toString() const {
+        std::ostringstream os;
+        os << "----- FakeLockoutTracker:: -----" << std::endl;
+        os << "FakeLockoutTracker::mFailedCount:" << mFailedCount;
+        os << ", FakeLockoutTracker::mCurrentMode:" << (int)mCurrentMode;
+        os << std::endl;
+        return os.str();
+    }
+
+  private:
+    int32_t mFailedCount;
+    int64_t mLockoutTimedStart;
+    LockoutMode mCurrentMode;
+};
+
+}  // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/include/Fingerprint.h b/biometrics/fingerprint/aidl/default/include/Fingerprint.h
index 64aafa3..fc4fb8d 100644
--- a/biometrics/fingerprint/aidl/default/include/Fingerprint.h
+++ b/biometrics/fingerprint/aidl/default/include/Fingerprint.h
@@ -16,8 +16,6 @@
 
 #pragma once
 
-#define LOG_TAG "FingerprintVirtualHal"
-
 #include <aidl/android/hardware/biometrics/fingerprint/BnFingerprint.h>
 
 #include "FakeFingerprintEngine.h"
@@ -39,8 +37,13 @@
     ndk::ScopedAStatus createSession(int32_t sensorId, int32_t userId,
                                      const std::shared_ptr<ISessionCallback>& cb,
                                      std::shared_ptr<ISession>* out) override;
+    binder_status_t dump(int fd, const char** args, uint32_t numArgs);
+    binder_status_t handleShellCommand(int in, int out, int err, const char** argv, uint32_t argc);
 
   private:
+    void resetConfigToDefault();
+    void onHelp(int);
+
     std::unique_ptr<FakeFingerprintEngine> mEngine;
     WorkerThread mWorker;
     std::shared_ptr<Session> mSession;
diff --git a/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp b/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp
index 8696d26..a200b39 100644
--- a/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp
+++ b/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@
 #include <aidl/android/hardware/biometrics/fingerprint/BnSessionCallback.h>
 
 #include "FakeFingerprintEngine.h"
+#include "util/Util.h"
 
 using namespace ::android::fingerprint::virt;
 using namespace ::aidl::android::hardware::biometrics::fingerprint;
@@ -38,8 +39,9 @@
         mLastChallengeRevoked = challenge;
         return ndk::ScopedAStatus::ok();
     };
-    ::ndk::ScopedAStatus onError(fingerprint::Error error, int32_t) override {
+    ::ndk::ScopedAStatus onError(fingerprint::Error error, int32_t vendorCode) override {
         mError = error;
+        mErrorVendorCode = vendorCode;
         return ndk::ScopedAStatus::ok();
     };
     ::ndk::ScopedAStatus onEnrollmentProgress(int32_t enrollmentId, int32_t remaining) override {
@@ -62,7 +64,10 @@
         mInteractionDetectedCount++;
         return ndk::ScopedAStatus::ok();
     };
-    ndk::ScopedAStatus onAcquired(AcquiredInfo /*info*/, int32_t /*vendorCode*/) override {
+    ndk::ScopedAStatus onAcquired(AcquiredInfo info, int32_t vendorCode) override {
+        mLastAcquiredInfo = (int32_t)info;
+        mLastAcquiredVendorCode = vendorCode;
+        mLastAcquiredCount++;
         return ndk::ScopedAStatus::ok();
     }
     ::ndk::ScopedAStatus onEnrollmentsEnumerated(
@@ -94,6 +99,7 @@
     ndk::ScopedAStatus onSessionClosed() override { return ndk::ScopedAStatus::ok(); }
 
     Error mError = Error::UNKNOWN;
+    int32_t mErrorVendorCode = 0;
     int64_t mLastChallenge = -1;
     int64_t mLastChallengeRevoked = -1;
     int32_t mLastEnrolled = -1;
@@ -105,17 +111,29 @@
     bool mAuthenticatorIdInvalidated = false;
     bool mLockoutPermanent = false;
     int mInteractionDetectedCount = 0;
+    int32_t mLastAcquiredInfo = -1;
+    int32_t mLastAcquiredVendorCode = -1;
+    int32_t mLastAcquiredCount = 0;
 };
 
 class FakeFingerprintEngineTest : public ::testing::Test {
   protected:
     void SetUp() override {
-        FingerprintHalProperties::operation_enroll_latency(0);
-        FingerprintHalProperties::operation_authenticate_latency(0);
-        FingerprintHalProperties::operation_detect_interaction_latency(0);
+        FingerprintHalProperties::operation_enroll_latency({0});
+        FingerprintHalProperties::operation_authenticate_latency({0});
+        FingerprintHalProperties::operation_detect_interaction_latency({0});
         mCallback = ndk::SharedRefBase::make<TestSessionCallback>();
     }
 
+    void TearDown() override {
+        FingerprintHalProperties::operation_authenticate_error(0);
+        FingerprintHalProperties::operation_detect_interaction_error(0);
+        FingerprintHalProperties::operation_authenticate_acquired("");
+        FingerprintHalProperties::operation_enroll_latency({});
+        FingerprintHalProperties::operation_authenticate_latency({});
+        FingerprintHalProperties::operation_detect_interaction_latency({});
+    }
+
     FakeFingerprintEngine mEngine;
     std::shared_ptr<TestSessionCallback> mCallback;
     std::promise<void> mCancel;
@@ -135,11 +153,13 @@
 
 TEST_F(FakeFingerprintEngineTest, ResetLockout) {
     FingerprintHalProperties::lockout(true);
-    mEngine.resetLockoutImpl(mCallback.get(), {});
+    keymaster::HardwareAuthToken hat{.mac = {2, 4}};
+    mEngine.resetLockoutImpl(mCallback.get(), hat);
     ASSERT_FALSE(FingerprintHalProperties::lockout().value_or(true));
 }
 
 TEST_F(FakeFingerprintEngineTest, AuthenticatorId) {
+    FingerprintHalProperties::enrollments({1});
     FingerprintHalProperties::authenticator_id(50);
     mEngine.getAuthenticatorIdImpl(mCallback.get());
     ASSERT_EQ(50, mCallback->mLastAuthenticatorId);
@@ -162,6 +182,7 @@
     ASSERT_EQ(1, FingerprintHalProperties::enrollments().size());
     ASSERT_EQ(4, FingerprintHalProperties::enrollments()[0].value());
     ASSERT_EQ(4, mCallback->mLastEnrolled);
+    ASSERT_EQ(1, mCallback->mLastAcquiredInfo);
 }
 
 TEST_F(FakeFingerprintEngineTest, EnrollCancel) {
@@ -189,12 +210,28 @@
     ASSERT_FALSE(FingerprintHalProperties::next_enrollment().has_value());
 }
 
+TEST_F(FakeFingerprintEngineTest, EnrollAcquired) {
+    FingerprintHalProperties::enrollments({});
+    FingerprintHalProperties::next_enrollment("4:0,5-[12,1013]:true");
+    keymaster::HardwareAuthToken hat{.mac = {2, 4}};
+    int32_t prevCnt = mCallback->mLastAcquiredCount;
+    mEngine.enrollImpl(mCallback.get(), hat, mCancel.get_future());
+    ASSERT_FALSE(FingerprintHalProperties::next_enrollment().has_value());
+    ASSERT_EQ(1, FingerprintHalProperties::enrollments().size());
+    ASSERT_EQ(4, FingerprintHalProperties::enrollments()[0].value());
+    ASSERT_EQ(4, mCallback->mLastEnrolled);
+    ASSERT_EQ(prevCnt + 3, mCallback->mLastAcquiredCount);
+    ASSERT_EQ(7, mCallback->mLastAcquiredInfo);
+    ASSERT_EQ(13, mCallback->mLastAcquiredVendorCode);
+}
+
 TEST_F(FakeFingerprintEngineTest, Authenticate) {
     FingerprintHalProperties::enrollments({1, 2});
     FingerprintHalProperties::enrollment_hit(2);
     mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
     ASSERT_FALSE(mCallback->mAuthenticateFailed);
     ASSERT_EQ(2, mCallback->mLastAuthenticated);
+    ASSERT_EQ(1, mCallback->mLastAcquiredInfo);
 }
 
 TEST_F(FakeFingerprintEngineTest, AuthenticateCancel) {
@@ -211,7 +248,6 @@
     FingerprintHalProperties::enrollment_hit({});
     mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
     ASSERT_TRUE(mCallback->mAuthenticateFailed);
-    ASSERT_EQ(mCallback->mError, Error::UNABLE_TO_PROCESS);
 }
 
 TEST_F(FakeFingerprintEngineTest, AuthenticateNotEnrolled) {
@@ -219,7 +255,6 @@
     FingerprintHalProperties::enrollment_hit(3);
     mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
     ASSERT_TRUE(mCallback->mAuthenticateFailed);
-    ASSERT_EQ(mCallback->mError, Error::UNABLE_TO_PROCESS);
 }
 
 TEST_F(FakeFingerprintEngineTest, AuthenticateLockout) {
@@ -231,14 +266,46 @@
     ASSERT_NE(mCallback->mError, Error::UNKNOWN);
 }
 
-TEST_F(FakeFingerprintEngineTest, InteractionDetect) {
+TEST_F(FakeFingerprintEngineTest, AuthenticateError8) {
+    FingerprintHalProperties::operation_authenticate_error(8);
+    mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
+    ASSERT_EQ(mCallback->mError, (Error)8);
+    ASSERT_EQ(mCallback->mErrorVendorCode, 0);
+}
+
+TEST_F(FakeFingerprintEngineTest, AuthenticateError9) {
+    FingerprintHalProperties::operation_authenticate_error(1009);
+    mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
+    ASSERT_EQ(mCallback->mError, (Error)7);
+    ASSERT_EQ(mCallback->mErrorVendorCode, 9);
+}
+
+TEST_F(FakeFingerprintEngineTest, AuthenticateAcquired) {
+    FingerprintHalProperties::lockout(false);
     FingerprintHalProperties::enrollments({1, 2});
     FingerprintHalProperties::enrollment_hit(2);
+    FingerprintHalProperties::operation_authenticate_acquired("4,1009");
+    int32_t prevCount = mCallback->mLastAcquiredCount;
+    mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
+    ASSERT_FALSE(mCallback->mAuthenticateFailed);
+    ASSERT_EQ(2, mCallback->mLastAuthenticated);
+    ASSERT_EQ(prevCount + 2, mCallback->mLastAcquiredCount);
+    ASSERT_EQ(7, mCallback->mLastAcquiredInfo);
+    ASSERT_EQ(9, mCallback->mLastAcquiredVendorCode);
+}
+
+TEST_F(FakeFingerprintEngineTest, InteractionDetect) {
+    FingerprintHalProperties::detect_interaction(true);
+    FingerprintHalProperties::enrollments({1, 2});
+    FingerprintHalProperties::enrollment_hit(2);
+    FingerprintHalProperties::operation_detect_interaction_acquired("");
     mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
     ASSERT_EQ(1, mCallback->mInteractionDetectedCount);
+    ASSERT_EQ(1, mCallback->mLastAcquiredInfo);
 }
 
 TEST_F(FakeFingerprintEngineTest, InteractionDetectCancel) {
+    FingerprintHalProperties::detect_interaction(true);
     FingerprintHalProperties::enrollments({1, 2});
     FingerprintHalProperties::enrollment_hit(2);
     mCancel.set_value();
@@ -248,6 +315,7 @@
 }
 
 TEST_F(FakeFingerprintEngineTest, InteractionDetectNotSet) {
+    FingerprintHalProperties::detect_interaction(true);
     FingerprintHalProperties::enrollments({1, 2});
     FingerprintHalProperties::enrollment_hit({});
     mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
@@ -261,6 +329,28 @@
     ASSERT_EQ(0, mCallback->mInteractionDetectedCount);
 }
 
+TEST_F(FakeFingerprintEngineTest, InteractionDetectError) {
+    FingerprintHalProperties::detect_interaction(true);
+    FingerprintHalProperties::operation_detect_interaction_error(8);
+    mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
+    ASSERT_EQ(0, mCallback->mInteractionDetectedCount);
+    ASSERT_EQ(mCallback->mError, (Error)8);
+    ASSERT_EQ(mCallback->mErrorVendorCode, 0);
+}
+
+TEST_F(FakeFingerprintEngineTest, InteractionDetectAcquired) {
+    FingerprintHalProperties::detect_interaction(true);
+    FingerprintHalProperties::enrollments({1, 2});
+    FingerprintHalProperties::enrollment_hit(2);
+    FingerprintHalProperties::operation_detect_interaction_acquired("4,1013");
+    int32_t prevCount = mCallback->mLastAcquiredCount;
+    mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
+    ASSERT_EQ(1, mCallback->mInteractionDetectedCount);
+    ASSERT_EQ(prevCount + 2, mCallback->mLastAcquiredCount);
+    ASSERT_EQ(7, mCallback->mLastAcquiredInfo);
+    ASSERT_EQ(13, mCallback->mLastAcquiredVendorCode);
+}
+
 TEST_F(FakeFingerprintEngineTest, EnumerateEnrolled) {
     FingerprintHalProperties::enrollments({2, 4, 8});
     mEngine.enumerateEnrollmentsImpl(mCallback.get());
@@ -290,6 +380,93 @@
     }
 }
 
+TEST_F(FakeFingerprintEngineTest, parseIntSequence) {
+    std::vector<int32_t> seqV;
+    seqV = mEngine.parseIntSequence("");
+    ASSERT_EQ(0, seqV.size());
+    seqV = mEngine.parseIntSequence("2");
+    ASSERT_EQ(1, seqV.size());
+    ASSERT_EQ(2, seqV[0]);
+    seqV = mEngine.parseIntSequence("2,3,4");
+    std::vector<int32_t> expV{2, 3, 4};
+    ASSERT_EQ(expV, seqV);
+    seqV = mEngine.parseIntSequence("2,3,a");
+    ASSERT_EQ(0, seqV.size());
+    seqV = mEngine.parseIntSequence("2, 3, 4");
+    ASSERT_EQ(expV, seqV);
+    seqV = mEngine.parseIntSequence("123,456");
+    ASSERT_EQ(2, seqV.size());
+    std::vector<int32_t> expV1{123, 456};
+    ASSERT_EQ(expV1, seqV);
+    seqV = mEngine.parseIntSequence("12f3,456");
+    ASSERT_EQ(0, seqV.size());
+}
+
+TEST_F(FakeFingerprintEngineTest, parseEnrollmentCaptureOk) {
+    std::vector<std::vector<int32_t>> ecV;
+    ecV = mEngine.parseEnrollmentCapture("100,200,300");
+    ASSERT_EQ(6, ecV.size());
+    std::vector<std::vector<int32_t>> expE{{100}, {200}, {300}};
+    std::vector<int32_t> defC{1};
+    for (int i = 0; i < ecV.size(); i += 2) {
+        ASSERT_EQ(expE[i / 2], ecV[i]);
+        ASSERT_EQ(defC, ecV[i + 1]);
+    }
+    ecV = mEngine.parseEnrollmentCapture("100");
+    ASSERT_EQ(2, ecV.size());
+    ASSERT_EQ(expE[0], ecV[0]);
+    ASSERT_EQ(defC, ecV[1]);
+
+    ecV = mEngine.parseEnrollmentCapture("100-[5,6,7]");
+    std::vector<int32_t> expC{5, 6, 7};
+    ASSERT_EQ(2, ecV.size());
+    for (int i = 0; i < ecV.size(); i += 2) {
+        ASSERT_EQ(expE[i / 2], ecV[i]);
+        ASSERT_EQ(expC, ecV[i + 1]);
+    }
+    ecV = mEngine.parseEnrollmentCapture("100-[5,6,7], 200, 300-[9,10]");
+    std::vector<std::vector<int32_t>> expC1{{5, 6, 7}, {1}, {9, 10}};
+    ASSERT_EQ(6, ecV.size());
+    for (int i = 0; i < ecV.size(); i += 2) {
+        ASSERT_EQ(expE[i / 2], ecV[i]);
+        ASSERT_EQ(expC1[i / 2], ecV[i + 1]);
+    }
+    ecV = mEngine.parseEnrollmentCapture("100-[5,6,7], 200-[2,1], 300-[9]");
+    std::vector<std::vector<int32_t>> expC2{{5, 6, 7}, {2, 1}, {9}};
+    ASSERT_EQ(ecV.size(), 6);
+    for (int i = 0; i < ecV.size(); i += 2) {
+        ASSERT_EQ(expE[i / 2], ecV[i]);
+        ASSERT_EQ(expC2[i / 2], ecV[i + 1]);
+    }
+}
+
+TEST_F(FakeFingerprintEngineTest, parseEnrollmentCaptureFail) {
+    std::vector<std::string> badStr{"10c",         "100-5",   "100-[5,6,7", "100-5,6,7]",
+                                    "100,2x0,300", "200-[f]", "a,b"};
+    std::vector<std::vector<int32_t>> ecV;
+    for (const auto& s : badStr) {
+        ecV = mEngine.parseEnrollmentCapture(s);
+        ASSERT_EQ(ecV.size(), 0);
+    }
+}
+
+TEST_F(FakeFingerprintEngineTest, randomLatency) {
+    FingerprintHalProperties::operation_detect_interaction_latency({});
+    ASSERT_EQ(DEFAULT_LATENCY,
+              mEngine.getLatency(FingerprintHalProperties::operation_detect_interaction_latency()));
+    FingerprintHalProperties::operation_detect_interaction_latency({10});
+    ASSERT_EQ(10,
+              mEngine.getLatency(FingerprintHalProperties::operation_detect_interaction_latency()));
+    FingerprintHalProperties::operation_detect_interaction_latency({1, 1000});
+    std::set<int32_t> latencySet;
+    for (int i = 0; i < 100; i++) {
+        latencySet.insert(mEngine.getLatency(
+                FingerprintHalProperties::operation_detect_interaction_latency()));
+    }
+    ASSERT_TRUE(latencySet.size() > 95);
+    FingerprintHalProperties::operation_detect_interaction_latency({});
+}
+
 }  // namespace aidl::android::hardware::biometrics::fingerprint
 
 int main(int argc, char** argv) {
diff --git a/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineUdfpsTest.cpp b/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineUdfpsTest.cpp
index 485f401..f551899 100644
--- a/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineUdfpsTest.cpp
+++ b/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineUdfpsTest.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <aidl/android/hardware/biometrics/fingerprint/BnSessionCallback.h>
 #include <android/binder_process.h>
 #include <fingerprint.sysprop.h>
 #include <gtest/gtest.h>
@@ -29,6 +30,69 @@
 
 namespace aidl::android::hardware::biometrics::fingerprint {
 
+class TestSessionCallback : public BnSessionCallback {
+  public:
+    ndk::ScopedAStatus onChallengeGenerated(int64_t /*challenge*/) override {
+        return ndk::ScopedAStatus::ok();
+    };
+    ::ndk::ScopedAStatus onChallengeRevoked(int64_t /*challenge*/) override {
+        return ndk::ScopedAStatus::ok();
+    };
+    ::ndk::ScopedAStatus onError(fingerprint::Error /*error*/, int32_t /*vendorCode*/) override {
+        return ndk::ScopedAStatus::ok();
+    };
+    ::ndk::ScopedAStatus onEnrollmentProgress(int32_t /*enrollmentId*/,
+                                              int32_t /*remaining*/) override {
+        mEnrollmentProgress++;
+        return ndk::ScopedAStatus::ok();
+    };
+
+    ::ndk::ScopedAStatus onAuthenticationSucceeded(int32_t /*enrollmentId*/,
+                                                   const keymaster::HardwareAuthToken&) override {
+        mAuthenticationSuccess++;
+        return ndk::ScopedAStatus::ok();
+    };
+    ::ndk::ScopedAStatus onAuthenticationFailed() override {
+        mAuthenticationFailure++;
+        return ndk::ScopedAStatus::ok();
+    };
+    ::ndk::ScopedAStatus onInteractionDetected() override {
+        mDetectInteraction++;
+        return ndk::ScopedAStatus::ok();
+    };
+    ndk::ScopedAStatus onAcquired(AcquiredInfo /*info*/, int32_t /*vendorCode*/) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onEnrollmentsEnumerated(
+            const std::vector<int32_t>& /*enrollmentIds*/) override {
+        return ndk::ScopedAStatus::ok();
+    };
+    ::ndk::ScopedAStatus onEnrollmentsRemoved(
+            const std::vector<int32_t>& /*enrollmentIds*/) override {
+        return ndk::ScopedAStatus::ok();
+    };
+    ::ndk::ScopedAStatus onAuthenticatorIdRetrieved(int64_t /*authenticatorId*/) override {
+        return ndk::ScopedAStatus::ok();
+    };
+    ::ndk::ScopedAStatus onAuthenticatorIdInvalidated(int64_t /*authenticatorId*/) override {
+        return ndk::ScopedAStatus::ok();
+    };
+    ::ndk::ScopedAStatus onLockoutPermanent() override { return ndk::ScopedAStatus::ok(); };
+    ndk::ScopedAStatus onLockoutTimed(int64_t /* timeout */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus onLockoutCleared() override { return ndk::ScopedAStatus::ok(); }
+    ndk::ScopedAStatus onSessionClosed() override { return ndk::ScopedAStatus::ok(); }
+
+    int32_t getAuthenticationCount() { return mAuthenticationSuccess + mAuthenticationFailure; }
+    int32_t getDetectInteractionCount() { return mDetectInteraction; }
+
+    int32_t mAuthenticationSuccess = 0;
+    int32_t mAuthenticationFailure = 0;
+    int32_t mEnrollmentProgress = 0;
+    int32_t mDetectInteraction = 0;
+};
+
 class FakeFingerprintEngineUdfpsTest : public ::testing::Test {
   protected:
     void SetUp() override {}
@@ -47,14 +111,10 @@
             sc.sensorRadius == FakeFingerprintEngineUdfps::defaultSensorRadius && sc.display == "");
 }
 
-TEST_F(FakeFingerprintEngineUdfpsTest, getSensorLocation) {
-    FingerprintHalProperties::sensor_location("");
-    SensorLocation sc = mEngine.getSensorLocation();
-    ASSERT_TRUE(isDefaultLocation(sc));
-
+TEST_F(FakeFingerprintEngineUdfpsTest, getSensorLocationOk) {
     auto loc = "100:200:30";
     FingerprintHalProperties::sensor_location(loc);
-    sc = mEngine.getSensorLocation();
+    SensorLocation sc = mEngine.getSensorLocation();
     ASSERT_TRUE(sc.sensorLocationX == 100);
     ASSERT_TRUE(sc.sensorLocationY == 200);
     ASSERT_TRUE(sc.sensorRadius == 30);
@@ -66,27 +126,59 @@
     ASSERT_TRUE(sc.sensorLocationY == 200);
     ASSERT_TRUE(sc.sensorRadius == 30);
     ASSERT_TRUE(sc.display == "screen1");
-
-    loc = "100";
-    FingerprintHalProperties::sensor_location(loc);
-    sc = mEngine.getSensorLocation();
-    ASSERT_TRUE(isDefaultLocation(sc));
-
-    loc = "10:20";
-    FingerprintHalProperties::sensor_location(loc);
-    sc = mEngine.getSensorLocation();
-    ASSERT_TRUE(isDefaultLocation(sc));
-
-    loc = "10,20,5";
-    FingerprintHalProperties::sensor_location(loc);
-    sc = mEngine.getSensorLocation();
-    ASSERT_TRUE(isDefaultLocation(sc));
-
-    loc = "a:b:c";
-    FingerprintHalProperties::sensor_location(loc);
-    sc = mEngine.getSensorLocation();
-    ASSERT_TRUE(isDefaultLocation(sc));
 }
 
+TEST_F(FakeFingerprintEngineUdfpsTest, getSensorLocationBad) {
+    const std::vector<std::string> badStr{"", "100", "10:20", "10,20,5", "a:b:c"};
+    SensorLocation sc;
+    for (const auto& s : badStr) {
+        FingerprintHalProperties::sensor_location(s);
+        sc = mEngine.getSensorLocation();
+        ASSERT_TRUE(isDefaultLocation(sc));
+    }
+}
+
+TEST_F(FakeFingerprintEngineUdfpsTest, initialization) {
+    ASSERT_TRUE(mEngine.getWorkMode() == FakeFingerprintEngineUdfps::WorkMode::kIdle);
+}
+
+TEST_F(FakeFingerprintEngineUdfpsTest, authenticate) {
+    std::shared_ptr<TestSessionCallback> cb = ndk::SharedRefBase::make<TestSessionCallback>();
+    std::promise<void> cancel;
+    mEngine.authenticateImpl(cb.get(), 1, cancel.get_future());
+    ASSERT_TRUE(mEngine.getWorkMode() == FakeFingerprintEngineUdfps::WorkMode::kAuthenticate);
+    mEngine.onPointerDownImpl(1, 2, 3, 4.0, 5.0);
+    ASSERT_EQ(cb->getAuthenticationCount(), 0);
+    mEngine.onUiReadyImpl();
+    ASSERT_EQ(cb->getAuthenticationCount(), 1);
+}
+
+TEST_F(FakeFingerprintEngineUdfpsTest, enroll) {
+    std::shared_ptr<TestSessionCallback> cb = ndk::SharedRefBase::make<TestSessionCallback>();
+    std::promise<void> cancel;
+    keymaster::HardwareAuthToken hat{.mac = {5, 6}};
+    FingerprintHalProperties::next_enrollment("5:0,0:true");
+    mEngine.enrollImpl(cb.get(), hat, cancel.get_future());
+    ASSERT_TRUE(mEngine.getWorkMode() == FakeFingerprintEngineUdfps::WorkMode::kEnroll);
+    mEngine.onPointerDownImpl(1, 2, 3, 4.0, 5.0);
+    ASSERT_EQ(cb->mEnrollmentProgress, 0);
+    mEngine.onUiReadyImpl();
+    ASSERT_TRUE(cb->mEnrollmentProgress > 0);
+}
+
+TEST_F(FakeFingerprintEngineUdfpsTest, detectInteraction) {
+    FingerprintHalProperties::detect_interaction(true);
+    FingerprintHalProperties::enrollments({1, 2});
+    FingerprintHalProperties::enrollment_hit(2);
+    FingerprintHalProperties::operation_detect_interaction_acquired("");
+    std::shared_ptr<TestSessionCallback> cb = ndk::SharedRefBase::make<TestSessionCallback>();
+    std::promise<void> cancel;
+    mEngine.detectInteractionImpl(cb.get(), cancel.get_future());
+    ASSERT_TRUE(mEngine.getWorkMode() == FakeFingerprintEngineUdfps::WorkMode::kDetectInteract);
+    mEngine.onPointerDownImpl(1, 2, 3, 4.0, 5.0);
+    ASSERT_EQ(cb->getDetectInteractionCount(), 0);
+    mEngine.onUiReadyImpl();
+    ASSERT_EQ(cb->getDetectInteractionCount(), 1);
+}
 // More
 }  // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/tests/FakeLockoutTrackerTest.cpp b/biometrics/fingerprint/aidl/default/tests/FakeLockoutTrackerTest.cpp
new file mode 100644
index 0000000..1b071ee
--- /dev/null
+++ b/biometrics/fingerprint/aidl/default/tests/FakeLockoutTrackerTest.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 <android/binder_process.h>
+#include <fingerprint.sysprop.h>
+#include <gtest/gtest.h>
+
+#include <android-base/logging.h>
+
+#include "FakeLockoutTracker.h"
+#include "util/Util.h"
+
+using namespace ::android::fingerprint::virt;
+using namespace ::aidl::android::hardware::biometrics::fingerprint;
+
+namespace aidl::android::hardware::biometrics::fingerprint {
+
+class FakeLockoutTrackerTest : public ::testing::Test {
+  protected:
+    static constexpr int32_t LOCKOUT_TIMED_THRESHOLD = 3;
+    static constexpr int32_t LOCKOUT_PERMANENT_THRESHOLD = 5;
+    static constexpr int32_t LOCKOUT_TIMED_DURATION = 100;
+
+    void SetUp() override {
+        FingerprintHalProperties::lockout_timed_threshold(LOCKOUT_TIMED_THRESHOLD);
+        FingerprintHalProperties::lockout_timed_duration(LOCKOUT_TIMED_DURATION);
+        FingerprintHalProperties::lockout_permanent_threshold(LOCKOUT_PERMANENT_THRESHOLD);
+    }
+
+    void TearDown() override {
+        // reset to default
+        FingerprintHalProperties::lockout_timed_threshold(5);
+        FingerprintHalProperties::lockout_timed_duration(20);
+        FingerprintHalProperties::lockout_permanent_threshold(10000);
+        FingerprintHalProperties::lockout_enable(false);
+        FingerprintHalProperties::lockout(false);
+    }
+
+    FakeLockoutTracker mLockoutTracker;
+};
+
+TEST_F(FakeLockoutTrackerTest, addFailedAttemptDisable) {
+    FingerprintHalProperties::lockout_enable(false);
+    for (int i = 0; i < LOCKOUT_TIMED_THRESHOLD + 1; i++) mLockoutTracker.addFailedAttempt();
+    ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kNone);
+    mLockoutTracker.reset();
+}
+
+TEST_F(FakeLockoutTrackerTest, addFailedAttemptLockoutTimed) {
+    FingerprintHalProperties::lockout_enable(true);
+    for (int i = 0; i < LOCKOUT_TIMED_THRESHOLD; i++) mLockoutTracker.addFailedAttempt();
+    ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kTimed);
+    // time left
+    int N = 5;
+    int64_t prevTimeLeft = INT_MIN;
+    for (int i = 0; i < N; i++) {
+        SLEEP_MS(LOCKOUT_TIMED_DURATION / N + 1);
+        int64_t currTimeLeft = mLockoutTracker.getLockoutTimeLeft();
+        ASSERT_TRUE(currTimeLeft > prevTimeLeft);
+        prevTimeLeft = currTimeLeft;
+    }
+    ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kNone);
+    mLockoutTracker.reset();
+}
+
+TEST_F(FakeLockoutTrackerTest, addFailedAttemptPermanent) {
+    FingerprintHalProperties::lockout_enable(true);
+    for (int i = 0; i < LOCKOUT_PERMANENT_THRESHOLD - 1; i++) mLockoutTracker.addFailedAttempt();
+    ASSERT_NE(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kPermanent);
+    mLockoutTracker.addFailedAttempt();
+    ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kPermanent);
+    ASSERT_TRUE(FingerprintHalProperties::lockout());
+    mLockoutTracker.reset();
+}
+
+}  // namespace aidl::android::hardware::biometrics::fingerprint
+
+int main(int argc, char** argv) {
+    testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/biometrics/fingerprint/aidl/vts/Android.bp b/biometrics/fingerprint/aidl/vts/Android.bp
index a474f66..1652905 100644
--- a/biometrics/fingerprint/aidl/vts/Android.bp
+++ b/biometrics/fingerprint/aidl/vts/Android.bp
@@ -15,9 +15,9 @@
     ],
     srcs: ["VtsHalBiometricsFingerprintTargetTest.cpp"],
     static_libs: [
-        "android.hardware.biometrics.common-V2-ndk",
-        "android.hardware.biometrics.fingerprint-V2-ndk",
-        "android.hardware.keymaster-V3-ndk",
+        "android.hardware.biometrics.common-V3-ndk",
+        "android.hardware.biometrics.fingerprint-V3-ndk",
+        "android.hardware.keymaster-V4-ndk",
     ],
     shared_libs: [
         "libbinder_ndk",
diff --git a/bluetooth/1.0/default/OWNERS b/bluetooth/1.0/default/OWNERS
deleted file mode 100644
index 5df5bfe..0000000
--- a/bluetooth/1.0/default/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-eisenbach@google.com
-mylesgw@google.com
-pavlin@google.com
diff --git a/bluetooth/1.0/default/bluetooth_hci.cc b/bluetooth/1.0/default/bluetooth_hci.cc
index a2211f4..869c723 100644
--- a/bluetooth/1.0/default/bluetooth_hci.cc
+++ b/bluetooth/1.0/default/bluetooth_hci.cc
@@ -33,7 +33,8 @@
 
 class BluetoothDeathRecipient : public hidl_death_recipient {
  public:
-  BluetoothDeathRecipient(const sp<IBluetoothHci> hci) : mHci(hci) {}
+  BluetoothDeathRecipient(const sp<IBluetoothHci> hci)
+    : mHci(hci), has_died_(false) {}
 
   virtual void serviceDied(
       uint64_t /*cookie*/,
@@ -51,7 +52,7 @@
 };
 
 BluetoothHci::BluetoothHci()
-    : death_recipient_(new BluetoothDeathRecipient(this)) {}
+    : death_recipient_(new BluetoothDeathRecipient(this)) {bt_enabled = 0;}
 
 Return<void> BluetoothHci::initialize(
     const ::android::sp<IBluetoothHciCallbacks>& cb) {
@@ -61,8 +62,19 @@
     return Void();
   }
 
+  if (bt_enabled == 1) {
+    ALOGE("initialize was called!");
+    return Void();
+  }
+  bt_enabled = 1;
   death_recipient_->setHasDied(false);
   cb->linkToDeath(death_recipient_, 0);
+  unlink_cb_ = [cb](sp<BluetoothDeathRecipient>& death_recipient) {
+    if (death_recipient->getHasDied())
+      ALOGI("Skipping unlink call, service died.");
+    else
+      cb->unlinkToDeath(death_recipient);
+  };
 
   bool rc = VendorInterface::Initialize(
       [cb](bool status) {
@@ -112,6 +124,12 @@
 
 Return<void> BluetoothHci::close() {
   ALOGI("BluetoothHci::close()");
+
+  if (bt_enabled != 1) {
+    ALOGE("should initialize first!");
+    return Void();
+  }
+  bt_enabled = 0;
   unlink_cb_(death_recipient_);
   VendorInterface::Shutdown();
   return Void();
@@ -134,6 +152,11 @@
 
 void BluetoothHci::sendDataToController(const uint8_t type,
                                         const hidl_vec<uint8_t>& data) {
+  if (bt_enabled != 1) {
+    ALOGE("should initialize first!");
+    return;
+  }
+
   VendorInterface::get()->Send(type, data.data(), data.size());
 }
 
diff --git a/bluetooth/1.0/default/bluetooth_hci.h b/bluetooth/1.0/default/bluetooth_hci.h
index c966990..5130c87 100644
--- a/bluetooth/1.0/default/bluetooth_hci.h
+++ b/bluetooth/1.0/default/bluetooth_hci.h
@@ -48,6 +48,7 @@
   void sendDataToController(const uint8_t type, const hidl_vec<uint8_t>& data);
   ::android::sp<BluetoothDeathRecipient> death_recipient_;
   std::function<void(sp<BluetoothDeathRecipient>&)> unlink_cb_;
+  int bt_enabled;
 };
 
 extern "C" IBluetoothHci* HIDL_FETCH_IBluetoothHci(const char* name);
diff --git a/bluetooth/1.0/default/vendor_interface.cc b/bluetooth/1.0/default/vendor_interface.cc
index 1d15dd6..c23d667 100644
--- a/bluetooth/1.0/default/vendor_interface.cc
+++ b/bluetooth/1.0/default/vendor_interface.cc
@@ -36,6 +36,8 @@
     "BLUETOOTH_VENDOR_LIB_INTERFACE";
 
 static const int INVALID_FD = -1;
+std::mutex vendor_mutex_;
+std::mutex initcb_mutex_;
 
 namespace {
 
@@ -47,13 +49,25 @@
   uint16_t opcode;
 } internal_command;
 
+enum {
+  VENDOR_STATE_INIT = 1,
+  VENDOR_STATE_OPENING,	/* during opening */
+  VENDOR_STATE_OPENED,	/* open in fops_open */
+  VENDOR_STATE_CLOSING,	/* during closing */
+  VENDOR_STATE_CLOSED,	/* closed */
+
+  VENDOR_STATE_MSG_NUM
+} ;
+
+uint8_t vstate = VENDOR_STATE_INIT;
+
 // True when LPM is not enabled yet or wake is not asserted.
 bool lpm_wake_deasserted;
 uint32_t lpm_timeout_ms;
 bool recent_activity_flag;
 
 VendorInterface* g_vendor_interface = nullptr;
-std::mutex wakeup_mutex_;
+static VendorInterface vendor_interface;
 
 HC_BT_HDR* WrapPacketAndCopy(uint16_t event, const hidl_vec<uint8_t>& data) {
   size_t packet_size = data.size() + sizeof(HC_BT_HDR);
@@ -167,11 +181,8 @@
     InitializeCompleteCallback initialize_complete_cb,
     PacketReadCallback event_cb, PacketReadCallback acl_cb,
     PacketReadCallback sco_cb, PacketReadCallback iso_cb) {
-  if (g_vendor_interface) {
-    ALOGE("%s: No previous Shutdown()?", __func__);
-    return false;
-  }
-  g_vendor_interface = new VendorInterface();
+  ALOGI("%s: VendorInterface::Initialize", __func__);
+  g_vendor_interface = &vendor_interface;
   return g_vendor_interface->Open(initialize_complete_cb, event_cb, acl_cb,
                                   sco_cb, iso_cb);
 }
@@ -179,9 +190,8 @@
 void VendorInterface::Shutdown() {
   LOG_ALWAYS_FATAL_IF(!g_vendor_interface, "%s: No Vendor interface!",
                       __func__);
+  ALOGI("%s: VendorInterface::Shutdown", __func__);
   g_vendor_interface->Close();
-  delete g_vendor_interface;
-  g_vendor_interface = nullptr;
 }
 
 VendorInterface* VendorInterface::get() { return g_vendor_interface; }
@@ -191,144 +201,189 @@
                            PacketReadCallback acl_cb,
                            PacketReadCallback sco_cb,
                            PacketReadCallback iso_cb) {
-  initialize_complete_cb_ = initialize_complete_cb;
+  {
+    std::unique_lock<std::mutex> guard(vendor_mutex_);
+    if (vstate == VENDOR_STATE_OPENED) {
+      ALOGW("VendorInterface opened!");
+      return true;
+    }
 
-  // Initialize vendor interface
+    if ((vstate == VENDOR_STATE_CLOSING) ||
+        (vstate == VENDOR_STATE_OPENING)) {
+      ALOGW("VendorInterface open/close is on-going !");
+      return true;
+    }
 
-  lib_handle_ = dlopen(VENDOR_LIBRARY_NAME, RTLD_NOW);
-  if (!lib_handle_) {
-    ALOGE("%s unable to open %s (%s)", __func__, VENDOR_LIBRARY_NAME,
-          dlerror());
-    return false;
-  }
+    vstate = VENDOR_STATE_OPENING;
+    ALOGI("%s: VendorInterface::Open", __func__);
 
-  lib_interface_ = reinterpret_cast<bt_vendor_interface_t*>(
-      dlsym(lib_handle_, VENDOR_LIBRARY_SYMBOL_NAME));
-  if (!lib_interface_) {
-    ALOGE("%s unable to find symbol %s in %s (%s)", __func__,
-          VENDOR_LIBRARY_SYMBOL_NAME, VENDOR_LIBRARY_NAME, dlerror());
-    return false;
-  }
+    initialize_complete_cb_ = initialize_complete_cb;
+    // Initialize vendor interface
+
+    lib_handle_ = dlopen(VENDOR_LIBRARY_NAME, RTLD_NOW);
+    if (!lib_handle_) {
+      ALOGE("%s unable to open %s (%s)", __func__, VENDOR_LIBRARY_NAME,
+            dlerror());
+      return false;
+    }
+
+    lib_interface_ = reinterpret_cast<bt_vendor_interface_t*>(
+        dlsym(lib_handle_, VENDOR_LIBRARY_SYMBOL_NAME));
+    if (!lib_interface_) {
+      ALOGE("%s unable to find symbol %s in %s (%s)", __func__,
+            VENDOR_LIBRARY_SYMBOL_NAME, VENDOR_LIBRARY_NAME, dlerror());
+      return false;
+    }
 
   // Get the local BD address
 
-  uint8_t local_bda[BluetoothAddress::kBytes];
-  if (!BluetoothAddress::get_local_address(local_bda)) {
-    LOG_ALWAYS_FATAL("%s: No Bluetooth Address!", __func__);
-  }
-  int status = lib_interface_->init(&lib_callbacks, (unsigned char*)local_bda);
-  if (status) {
-    ALOGE("%s unable to initialize vendor library: %d", __func__, status);
-    return false;
-  }
+    uint8_t local_bda[BluetoothAddress::kBytes] = {0, 0, 0, 0, 0, 0};
+    if (!BluetoothAddress::get_local_address(local_bda)) {
+      // BT driver will get BD address from NVRAM for MTK solution
+      ALOGW("%s: No pre-set Bluetooth Address!", __func__);
+    }
+    int status = lib_interface_->init(&lib_callbacks, (unsigned char*)local_bda);
+    if (status) {
+      ALOGE("%s unable to initialize vendor library: %d", __func__, status);
+      return false;
+    }
 
-  ALOGD("%s vendor library loaded", __func__);
+    ALOGD("%s vendor library loaded", __func__);
 
   // Power on the controller
 
-  int power_state = BT_VND_PWR_ON;
-  lib_interface_->op(BT_VND_OP_POWER_CTRL, &power_state);
+    int power_state = BT_VND_PWR_ON;
+    lib_interface_->op(BT_VND_OP_POWER_CTRL, &power_state);
 
   // Get the UART socket(s)
 
-  int fd_list[CH_MAX] = {0};
-  int fd_count = lib_interface_->op(BT_VND_OP_USERIAL_OPEN, &fd_list);
+    int fd_list[CH_MAX] = {0};
+    int fd_count = lib_interface_->op(BT_VND_OP_USERIAL_OPEN, &fd_list);
 
-  if (fd_count < 1 || fd_count > CH_MAX - 1) {
-    ALOGE("%s: fd_count %d is invalid!", __func__, fd_count);
-    return false;
-  }
-
-  for (int i = 0; i < fd_count; i++) {
-    if (fd_list[i] == INVALID_FD) {
-      ALOGE("%s: fd %d is invalid!", __func__, fd_list[i]);
+    if (fd_count < 1 || fd_count > CH_MAX - 1) {
+      ALOGE("%s: fd_count %d is invalid!", __func__, fd_count);
       return false;
     }
-  }
 
-  event_cb_ = event_cb;
-  PacketReadCallback intercept_events = [this](const hidl_vec<uint8_t>& event) {
-    HandleIncomingEvent(event);
-  };
+    for (int i = 0; i < fd_count; i++) {
+      if (fd_list[i] == INVALID_FD) {
+        ALOGE("%s: fd %d is invalid!", __func__, fd_list[i]);
+        return false;
+      }
+    }
 
-  if (fd_count == 1) {
-    hci::H4Protocol* h4_hci =
-        new hci::H4Protocol(fd_list[0], intercept_events, acl_cb, sco_cb, iso_cb);
-    fd_watcher_.WatchFdForNonBlockingReads(
-        fd_list[0], [h4_hci](int fd) { h4_hci->OnDataReady(fd); });
-    hci_ = h4_hci;
-  } else {
-    hci::MctProtocol* mct_hci =
-        new hci::MctProtocol(fd_list, intercept_events, acl_cb);
-    fd_watcher_.WatchFdForNonBlockingReads(
-        fd_list[CH_EVT], [mct_hci](int fd) { mct_hci->OnEventDataReady(fd); });
-    fd_watcher_.WatchFdForNonBlockingReads(
-        fd_list[CH_ACL_IN], [mct_hci](int fd) { mct_hci->OnAclDataReady(fd); });
-    hci_ = mct_hci;
-  }
+    event_cb_ = event_cb;
+    PacketReadCallback intercept_events = [this](const hidl_vec<uint8_t>& event) {
+      HandleIncomingEvent(event);
+    };
+
+    if (fd_count == 1) {
+      hci::H4Protocol* h4_hci =
+          new hci::H4Protocol(fd_list[0], intercept_events, acl_cb, sco_cb, iso_cb);
+      fd_watcher_.WatchFdForNonBlockingReads(
+          fd_list[0], [h4_hci](int fd) { h4_hci->OnDataReady(fd); });
+      hci_ = h4_hci;
+    } else {
+      hci::MctProtocol* mct_hci =
+          new hci::MctProtocol(fd_list, intercept_events, acl_cb);
+      fd_watcher_.WatchFdForNonBlockingReads(
+          fd_list[CH_EVT], [mct_hci](int fd) { mct_hci->OnEventDataReady(fd); });
+      fd_watcher_.WatchFdForNonBlockingReads(
+          fd_list[CH_ACL_IN],
+          [mct_hci](int fd) { mct_hci->OnAclDataReady(fd); });
+      hci_ = mct_hci;
+    }
 
   // Initially, the power management is off.
-  lpm_wake_deasserted = true;
+    lpm_wake_deasserted = true;
 
   // Start configuring the firmware
-  firmware_startup_timer_ = new FirmwareStartupTimer();
-  lib_interface_->op(BT_VND_OP_FW_CFG, nullptr);
+    firmware_startup_timer_ = new FirmwareStartupTimer();
+    lib_interface_->op(BT_VND_OP_FW_CFG, nullptr);
 
+    vstate = VENDOR_STATE_OPENED;
+    ALOGI("%s: VendorInterface::Open done!!!", __func__);
+  }  // vendor_mutex_ done
   return true;
 }
 
 void VendorInterface::Close() {
   // These callbacks may send HCI events (vendor-dependent), so make sure to
   // StopWatching the file descriptor after this.
+
+  if (vstate != VENDOR_STATE_OPENED) {
+    ALOGW("VendorInterface is not allow close(%d)", vstate);
+    return;
+  }
+  vstate = VENDOR_STATE_CLOSING;
+  ALOGI("%s: VendorInterface::Close", __func__);
+
   if (lib_interface_ != nullptr) {
+    lib_interface_->cleanup();
     bt_vendor_lpm_mode_t mode = BT_VND_LPM_DISABLE;
     lib_interface_->op(BT_VND_OP_LPM_SET_MODE, &mode);
   }
 
-  fd_watcher_.StopWatchingFileDescriptors();
+  {
+    std::unique_lock<std::mutex> guard(vendor_mutex_);
 
-  if (hci_ != nullptr) {
-    delete hci_;
-    hci_ = nullptr;
-  }
+    fd_watcher_.StopWatchingFileDescriptors();
+    if (hci_ != nullptr) {
+      delete hci_;
+      hci_ = nullptr;
+    }
 
-  if (lib_interface_ != nullptr) {
-    lib_interface_->op(BT_VND_OP_USERIAL_CLOSE, nullptr);
+    if (lib_interface_ != nullptr) {
+      lib_interface_->op(BT_VND_OP_USERIAL_CLOSE, nullptr);
 
-    int power_state = BT_VND_PWR_OFF;
-    lib_interface_->op(BT_VND_OP_POWER_CTRL, &power_state);
+      int power_state = BT_VND_PWR_OFF;
+      lib_interface_->op(BT_VND_OP_POWER_CTRL, &power_state);
 
-    lib_interface_->cleanup();
-    lib_interface_ = nullptr;
-  }
+      lib_interface_ = nullptr;
+    }
 
-  if (lib_handle_ != nullptr) {
-    dlclose(lib_handle_);
-    lib_handle_ = nullptr;
-  }
+    if (lib_handle_ != nullptr) {
+      dlclose(lib_handle_);
+      lib_handle_ = nullptr;
+    }
 
-  if (firmware_startup_timer_ != nullptr) {
-    delete firmware_startup_timer_;
-    firmware_startup_timer_ = nullptr;
-  }
+    if (firmware_startup_timer_ != nullptr) {
+      delete firmware_startup_timer_;
+      firmware_startup_timer_ = nullptr;
+    }
+    vstate = VENDOR_STATE_CLOSED;
+  }  // vendor_mutex_ done
+  ALOGI("%s: VendorInterface::Close done!!!", __func__);
 }
 
 size_t VendorInterface::Send(uint8_t type, const uint8_t* data, size_t length) {
-  std::unique_lock<std::mutex> lock(wakeup_mutex_);
-  recent_activity_flag = true;
+  {
+    std::unique_lock<std::mutex> guard(vendor_mutex_);
 
-  if (lpm_wake_deasserted == true) {
-    // Restart the timer.
-    fd_watcher_.ConfigureTimeout(std::chrono::milliseconds(lpm_timeout_ms),
+    if (vstate != VENDOR_STATE_OPENED) {
+      ALOGW("VendorInterface is not open yet(%d)!", vstate);
+      return 0;
+    }
+    ALOGI("%s: VendorInterface::Send", __func__);
+
+    if (lib_interface_ == nullptr) {
+      ALOGE("lib_interface_ is null");
+      return 0;
+    }
+    recent_activity_flag = true;
+    if (lpm_wake_deasserted == true) {
+      // Restart the timer.
+      fd_watcher_.ConfigureTimeout(std::chrono::milliseconds(lpm_timeout_ms),
                                  [this]() { OnTimeout(); });
-    // Assert wake.
-    lpm_wake_deasserted = false;
-    bt_vendor_lpm_wake_state_t wakeState = BT_VND_LPM_WAKE_ASSERT;
-    lib_interface_->op(BT_VND_OP_LPM_WAKE_SET_STATE, &wakeState);
-    ALOGV("%s: Sent wake before (%02x)", __func__, data[0] | (data[1] << 8));
-  }
+      // Assert wake.
+      lpm_wake_deasserted = false;
+      bt_vendor_lpm_wake_state_t wakeState = BT_VND_LPM_WAKE_ASSERT;
+      lib_interface_->op(BT_VND_OP_LPM_WAKE_SET_STATE, &wakeState);
+      ALOGV("%s: Sent wake before (%02x)", __func__, data[0] | (data[1] << 8));
+    }
 
-  return hci_->Send(type, data, length);
+    return hci_ ? hci_->Send(type, data, length) : 0;
+  }  // vendor_mutex_ done
 }
 
 void VendorInterface::OnFirmwareConfigured(uint8_t result) {
@@ -339,25 +394,36 @@
     firmware_startup_timer_ = nullptr;
   }
 
-  if (initialize_complete_cb_ != nullptr) {
-    initialize_complete_cb_(result == 0);
-    initialize_complete_cb_ = nullptr;
+  {
+    std::unique_lock<std::mutex> guard(initcb_mutex_);
+    ALOGD("%s OnFirmwareConfigured get lock", __func__);
+    if (initialize_complete_cb_ != nullptr) {
+      LOG_ALWAYS_FATAL_IF((result != 0),
+          "%s: Failed to init firmware!", __func__);
+      initialize_complete_cb_(result == 0);
+    }
+  }  // initcb_mutex_ done
+
+  if (lib_interface_ != nullptr) {
+    lib_interface_->op(BT_VND_OP_GET_LPM_IDLE_TIMEOUT, &lpm_timeout_ms);
+    ALOGI("%s: lpm_timeout_ms %d", __func__, lpm_timeout_ms);
+
+    bt_vendor_lpm_mode_t mode = BT_VND_LPM_ENABLE;
+    lib_interface_->op(BT_VND_OP_LPM_SET_MODE, &mode);
+
+    ALOGD("%s Calling StartLowPowerWatchdog()", __func__);
+    fd_watcher_.ConfigureTimeout(std::chrono::milliseconds(lpm_timeout_ms),
+                                 [this]() { OnTimeout(); });
+  }
+  else {
+    ALOGE("lib_interface_ is null");
   }
 
-  lib_interface_->op(BT_VND_OP_GET_LPM_IDLE_TIMEOUT, &lpm_timeout_ms);
-  ALOGI("%s: lpm_timeout_ms %d", __func__, lpm_timeout_ms);
-
-  bt_vendor_lpm_mode_t mode = BT_VND_LPM_ENABLE;
-  lib_interface_->op(BT_VND_OP_LPM_SET_MODE, &mode);
-
-  ALOGD("%s Calling StartLowPowerWatchdog()", __func__);
-  fd_watcher_.ConfigureTimeout(std::chrono::milliseconds(lpm_timeout_ms),
-                               [this]() { OnTimeout(); });
+  initialize_complete_cb_ = nullptr;
 }
 
 void VendorInterface::OnTimeout() {
   ALOGV("%s", __func__);
-  std::unique_lock<std::mutex> lock(wakeup_mutex_);
   if (recent_activity_flag == false) {
     lpm_wake_deasserted = true;
     bt_vendor_lpm_wake_state_t wakeState = BT_VND_LPM_WAKE_DEASSERT;
diff --git a/bluetooth/1.0/default/vendor_interface.h b/bluetooth/1.0/default/vendor_interface.h
index 040f31a..2df3946 100644
--- a/bluetooth/1.0/default/vendor_interface.h
+++ b/bluetooth/1.0/default/vendor_interface.h
@@ -22,6 +22,8 @@
 #include "bt_vendor_lib.h"
 #include "hci_protocol.h"
 
+extern std::mutex initcb_mutex_;
+
 namespace android {
 namespace hardware {
 namespace bluetooth {
@@ -45,10 +47,9 @@
   size_t Send(uint8_t type, const uint8_t* data, size_t length);
 
   void OnFirmwareConfigured(uint8_t result);
-
- private:
   virtual ~VendorInterface() = default;
 
+ private:
   bool Open(InitializeCompleteCallback initialize_complete_cb,
             PacketReadCallback event_cb, PacketReadCallback acl_cb,
             PacketReadCallback sco_cb, PacketReadCallback iso_cb);
diff --git a/bluetooth/1.0/vts/OWNERS b/bluetooth/1.0/vts/OWNERS
deleted file mode 100644
index 58d3a66..0000000
--- a/bluetooth/1.0/vts/OWNERS
+++ /dev/null
@@ -1,8 +0,0 @@
-zachoverflow@google.com
-siyuanh@google.com
-mylesgw@google.com
-jpawlowski@google.com
-apanicke@google.com
-stng@google.com
-hsz@google.com
-
diff --git a/bluetooth/1.0/vts/functional/OWNERS b/bluetooth/1.0/vts/functional/OWNERS
deleted file mode 100644
index 7f02612..0000000
--- a/bluetooth/1.0/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 27441
-bluetooth-reviews@google.com
diff --git a/bluetooth/1.1/default/OWNERS b/bluetooth/1.1/default/OWNERS
deleted file mode 100644
index 0c01df6..0000000
--- a/bluetooth/1.1/default/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-zachoverflow@google.com
-mylesgw@google.com
-jpawlowski@google.com
diff --git a/bluetooth/1.1/vts/OWNERS b/bluetooth/1.1/vts/OWNERS
deleted file mode 100644
index ff6fd93..0000000
--- a/bluetooth/1.1/vts/OWNERS
+++ /dev/null
@@ -1,6 +0,0 @@
-zachoverflow@google.com
-siyuanh@google.com
-mylesgw@google.com
-jpawlowski@google.com
-hsz@google.com
-
diff --git a/bluetooth/OWNERS b/bluetooth/OWNERS
new file mode 100644
index 0000000..f401b8c
--- /dev/null
+++ b/bluetooth/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 27441
+
+henrichataing@google.com
+mylesgw@google.com
+siyuanh@google.com
diff --git a/bluetooth/aidl/Android.bp b/bluetooth/aidl/Android.bp
new file mode 100644
index 0000000..1788ed3
--- /dev/null
+++ b/bluetooth/aidl/Android.bp
@@ -0,0 +1,37 @@
+// 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.bluetooth",
+    vendor_available: true,
+    host_supported: true,
+    srcs: ["android/hardware/bluetooth/*.aidl"],
+    stability: "vintf",
+    backend: {
+        cpp: {
+            // FIXME should this be disabled?
+            // prefer NDK backend which can be used anywhere
+            // If you disable this, you also need to delete the C++
+            // translate code.
+            enabled: true,
+        },
+        java: {
+            sdk_version: "module_current",
+        },
+        ndk: {
+            apex_available: [
+                "//apex_available:platform",
+                "com.android.btservices",
+            ],
+            min_sdk_version: "33",
+        },
+    },
+}
diff --git a/bluetooth/aidl/aidl_api/android.hardware.bluetooth/current/android/hardware/bluetooth/IBluetoothHci.aidl b/bluetooth/aidl/aidl_api/android.hardware.bluetooth/current/android/hardware/bluetooth/IBluetoothHci.aidl
new file mode 100644
index 0000000..8b1cad2
--- /dev/null
+++ b/bluetooth/aidl/aidl_api/android.hardware.bluetooth/current/android/hardware/bluetooth/IBluetoothHci.aidl
@@ -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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth;
+@VintfStability
+interface IBluetoothHci {
+  void close();
+  void initialize(in android.hardware.bluetooth.IBluetoothHciCallbacks callback);
+  void sendAclData(in byte[] data);
+  void sendHciCommand(in byte[] command);
+  void sendIsoData(in byte[] data);
+  void sendScoData(in byte[] data);
+}
diff --git a/bluetooth/aidl/aidl_api/android.hardware.bluetooth/current/android/hardware/bluetooth/IBluetoothHciCallbacks.aidl b/bluetooth/aidl/aidl_api/android.hardware.bluetooth/current/android/hardware/bluetooth/IBluetoothHciCallbacks.aidl
new file mode 100644
index 0000000..aecff7f
--- /dev/null
+++ b/bluetooth/aidl/aidl_api/android.hardware.bluetooth/current/android/hardware/bluetooth/IBluetoothHciCallbacks.aidl
@@ -0,0 +1,42 @@
+/*
+ * 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.bluetooth;
+@VintfStability
+interface IBluetoothHciCallbacks {
+  void aclDataReceived(in byte[] data);
+  void hciEventReceived(in byte[] event);
+  void initializationComplete(in android.hardware.bluetooth.Status status);
+  void isoDataReceived(in byte[] data);
+  void scoDataReceived(in byte[] data);
+}
diff --git a/bluetooth/aidl/aidl_api/android.hardware.bluetooth/current/android/hardware/bluetooth/Status.aidl b/bluetooth/aidl/aidl_api/android.hardware.bluetooth/current/android/hardware/bluetooth/Status.aidl
new file mode 100644
index 0000000..da429b8
--- /dev/null
+++ b/bluetooth/aidl/aidl_api/android.hardware.bluetooth/current/android/hardware/bluetooth/Status.aidl
@@ -0,0 +1,42 @@
+/*
+ * 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.bluetooth;
+@Backing(type="int") @VintfStability
+enum Status {
+  SUCCESS = 0,
+  ALREADY_INITIALIZED = 1,
+  UNABLE_TO_OPEN_INTERFACE = 2,
+  HARDWARE_INITIALIZATION_ERROR = 3,
+  UNKNOWN = 4,
+}
diff --git a/bluetooth/aidl/android/hardware/bluetooth/IBluetoothHci.aidl b/bluetooth/aidl/android/hardware/bluetooth/IBluetoothHci.aidl
new file mode 100644
index 0000000..db12986
--- /dev/null
+++ b/bluetooth/aidl/android/hardware/bluetooth/IBluetoothHci.aidl
@@ -0,0 +1,73 @@
+/*
+ * 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.bluetooth;
+
+import android.hardware.bluetooth.IBluetoothHciCallbacks;
+
+/**
+ * The Host Controller Interface (HCI) is the layer defined by the Bluetooth
+ * specification between the software that runs on the host and the Bluetooth
+ * controller chip. This boundary is the natural choice for a Hardware
+ * Abstraction Layer (HAL). Dealing only in HCI packets and events simplifies
+ * the stack and abstracts away power management, initialization, and other
+ * implementation-specific details related to the hardware.
+ */
+@VintfStability
+interface IBluetoothHci {
+    /**
+     * Close the HCI interface
+     */
+    void close();
+
+    /**
+     * Initialize the Bluetooth interface and set the callbacks.
+     */
+    void initialize(in IBluetoothHciCallbacks callback);
+
+    /**
+     * Send an HCI ACL data packet (as specified in the Bluetooth Specification
+     * V4.2, Vol 2, Part 5, Section 5.4.2) to the Bluetooth controller.
+     * Packets must be processed in order.
+     * @param data HCI data packet to be sent
+     */
+    void sendAclData(in byte[] data);
+
+    /**
+     * Send an HCI command (as specified in the Bluetooth Specification
+     * V4.2, Vol 2, Part 5, Section 5.4.1) to the Bluetooth controller.
+     * Commands must be executed in order.
+     *
+     * @param command is the HCI command to be sent
+     */
+    void sendHciCommand(in byte[] command);
+
+    /**
+     * Send an ISO data packet (as specified in the Bluetooth Core
+     * Specification v5.2) to the Bluetooth controller.
+     * Packets must be processed in order.
+     * @param data HCI data packet to be sent
+     */
+    void sendIsoData(in byte[] data);
+
+    /**
+     * Send an SCO data packet (as specified in the Bluetooth Specification
+     * V4.2, Vol 2, Part 5, Section 5.4.3) to the Bluetooth controller.
+     * Packets must be processed in order.
+     * @param data HCI data packet to be sent
+     */
+    void sendScoData(in byte[] data);
+}
diff --git a/bluetooth/aidl/android/hardware/bluetooth/IBluetoothHciCallbacks.aidl b/bluetooth/aidl/android/hardware/bluetooth/IBluetoothHciCallbacks.aidl
new file mode 100644
index 0000000..000333e
--- /dev/null
+++ b/bluetooth/aidl/android/hardware/bluetooth/IBluetoothHciCallbacks.aidl
@@ -0,0 +1,56 @@
+/*
+ * 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.bluetooth;
+
+import android.hardware.bluetooth.Status;
+
+/**
+ * The interface from the Bluetooth Controller to the stack.
+ */
+@VintfStability
+interface IBluetoothHciCallbacks {
+    /**
+     * Send an ACL data packet from the controller to the host.
+     * @param data the ACL HCI packet to be passed to the host stack
+     */
+    void aclDataReceived(in byte[] data);
+
+    /**
+     * This function is invoked when an HCI event is received from the
+     * Bluetooth controller to be forwarded to the Bluetooth stack.
+     * @param event is the HCI event to be sent to the Bluetooth stack.
+     */
+    void hciEventReceived(in byte[] event);
+
+    /**
+     * Invoked when the Bluetooth controller initialization has been
+     * completed.
+     */
+    void initializationComplete(in Status status);
+
+    /**
+     * Send a ISO data packet from the controller to the host.
+     * @param data the ISO HCI packet to be passed to the host stack
+     */
+    void isoDataReceived(in byte[] data);
+
+    /**
+     * Send a SCO data packet from the controller to the host.
+     * @param data the SCO HCI packet to be passed to the host stack
+     */
+    void scoDataReceived(in byte[] data);
+}
diff --git a/bluetooth/aidl/android/hardware/bluetooth/Status.aidl b/bluetooth/aidl/android/hardware/bluetooth/Status.aidl
new file mode 100644
index 0000000..4ec251a
--- /dev/null
+++ b/bluetooth/aidl/android/hardware/bluetooth/Status.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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.bluetooth;
+
+@VintfStability
+@Backing(type="int")
+enum Status {
+    SUCCESS,
+    ALREADY_INITIALIZED,
+    UNABLE_TO_OPEN_INTERFACE,
+    HARDWARE_INITIALIZATION_ERROR,
+    UNKNOWN,
+}
diff --git a/bluetooth/aidl/default/Android.bp b/bluetooth/aidl/default/Android.bp
new file mode 100644
index 0000000..d1761f5
--- /dev/null
+++ b/bluetooth/aidl/default/Android.bp
@@ -0,0 +1,79 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_defaults {
+    name: "android.hardware.bluetooth-service-build-defaults",
+    cflags: [
+        "-Wall",
+        "-Wextra",
+    ],
+    shared_libs: [
+        "android.hardware.bluetooth-V1-ndk",
+        "libbase",
+        "libbinder_ndk",
+        "libcutils",
+        "libhidlbase",
+        "liblog",
+        "libutils",
+    ],
+    static_libs: [
+        "android.hardware.bluetooth.async",
+        "android.hardware.bluetooth.hci",
+    ],
+}
+
+cc_library_static {
+    name: "libbluetoothhcihalimpl",
+    vendor_available: true,
+    host_supported: true,
+    defaults: ["android.hardware.bluetooth-service-build-defaults"],
+    srcs: [
+        "BluetoothHci.cpp",
+    ],
+}
+
+cc_binary {
+    name: "android.hardware.bluetooth-service.default",
+    relative_install_path: "hw",
+    init_rc: ["bluetooth-service-default.rc"],
+    vintf_fragments: ["bluetooth-service-default.xml"],
+    vendor: true,
+    defaults: ["android.hardware.bluetooth-service-build-defaults"],
+    srcs: [
+        "service.cpp",
+    ],
+    shared_libs: [
+        "android.hardware.bluetooth-V1-ndk",
+        "libbase",
+        "libbinder_ndk",
+        "libhidlbase",
+        "libutils",
+        "liblog",
+    ],
+    static_libs: [
+        "libbluetoothhcihalimpl",
+    ],
+}
+
+cc_fuzz {
+    name: "android.hardware.bluetooth-service.default_fuzzer",
+    host_supported: true,
+    defaults: ["service_fuzzer_defaults"],
+    srcs: [
+        "test/fuzzer.cpp",
+    ],
+    static_libs: [
+        "android.hardware.bluetooth.async",
+        "android.hardware.bluetooth.hci",
+        "android.hardware.bluetooth-V1-ndk",
+        "libbluetoothhcihalimpl",
+        "liblog",
+    ],
+    fuzz_config: {
+        componentid: 27441,
+        cc: [
+            "mylesgw@google.com",
+        ],
+    },
+}
diff --git a/bluetooth/aidl/default/BluetoothHci.cpp b/bluetooth/aidl/default/BluetoothHci.cpp
new file mode 100644
index 0000000..4d4896d
--- /dev/null
+++ b/bluetooth/aidl/default/BluetoothHci.cpp
@@ -0,0 +1,194 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "android.hardware.bluetooth.service.default"
+
+#include "BluetoothHci.h"
+
+#include <cutils/properties.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <poll.h>
+#include <string.h>
+#include <sys/uio.h>
+#include <termios.h>
+
+#include "log/log.h"
+
+namespace {
+int SetTerminalRaw(int fd) {
+  termios terminal_settings;
+  int rval = tcgetattr(fd, &terminal_settings);
+  if (rval < 0) {
+    return rval;
+  }
+  cfmakeraw(&terminal_settings);
+  rval = tcsetattr(fd, TCSANOW, &terminal_settings);
+  return rval;
+}
+}  // namespace
+
+using namespace ::android::hardware::bluetooth::hci;
+using namespace ::android::hardware::bluetooth::async;
+
+namespace aidl::android::hardware::bluetooth::impl {
+
+void OnDeath(void* cookie);
+
+class BluetoothDeathRecipient {
+ public:
+  BluetoothDeathRecipient(BluetoothHci* hci) : mHci(hci) {}
+
+  void LinkToDeath(const std::shared_ptr<IBluetoothHciCallbacks>& cb) {
+    mCb = cb;
+    clientDeathRecipient_ = AIBinder_DeathRecipient_new(OnDeath);
+    auto linkToDeathReturnStatus = AIBinder_linkToDeath(
+        mCb->asBinder().get(), clientDeathRecipient_, this /* cookie */);
+    LOG_ALWAYS_FATAL_IF(linkToDeathReturnStatus != STATUS_OK,
+                        "Unable to link to death recipient");
+  }
+
+  void UnlinkToDeath(const std::shared_ptr<IBluetoothHciCallbacks>& cb) {
+    LOG_ALWAYS_FATAL_IF(cb != mCb, "Unable to unlink mismatched pointers");
+  }
+
+  void serviceDied() {
+    if (mCb != nullptr && !AIBinder_isAlive(mCb->asBinder().get())) {
+      ALOGE("Bluetooth remote service has died");
+    } else {
+      ALOGE("BluetoothDeathRecipient::serviceDied called but service not dead");
+      return;
+    }
+    has_died_ = true;
+    mHci->close();
+  }
+  BluetoothHci* mHci;
+  std::shared_ptr<IBluetoothHciCallbacks> mCb;
+  AIBinder_DeathRecipient* clientDeathRecipient_;
+  bool getHasDied() const { return has_died_; }
+
+ private:
+  bool has_died_{false};
+};
+
+void OnDeath(void* cookie) {
+  auto* death_recipient = static_cast<BluetoothDeathRecipient*>(cookie);
+  death_recipient->serviceDied();
+}
+
+BluetoothHci::BluetoothHci(const std::string& dev_path) {
+  char property_bytes[PROPERTY_VALUE_MAX];
+  property_get("vendor.ser.bt-uart", property_bytes, dev_path.c_str());
+  mDevPath = std::string(property_bytes);
+  mDeathRecipient = std::make_shared<BluetoothDeathRecipient>(this);
+}
+
+ndk::ScopedAStatus BluetoothHci::initialize(
+    const std::shared_ptr<IBluetoothHciCallbacks>& cb) {
+  ALOGI(__func__);
+
+  mFd = open(mDevPath.c_str(), O_RDWR);
+  if (mFd < 0) {
+    ALOGE("Could not connect to bt: %s (%s)", mDevPath.c_str(),
+          strerror(errno));
+    return ndk::ScopedAStatus::fromServiceSpecificError(STATUS_BAD_VALUE);
+  }
+  if (int ret = SetTerminalRaw(mFd) < 0) {
+    ALOGE("Could not make %s a raw terminal %d(%s)", mDevPath.c_str(), ret,
+          strerror(errno));
+    return ndk::ScopedAStatus::fromServiceSpecificError(STATUS_BAD_VALUE);
+  }
+
+  mCb = cb;
+  if (mCb == nullptr) {
+    ALOGE("cb == nullptr! -> Unable to call initializationComplete(ERR)");
+    return ndk::ScopedAStatus::fromServiceSpecificError(STATUS_BAD_VALUE);
+  }
+
+  mDeathRecipient->LinkToDeath(mCb);
+
+  auto init_ret = cb->initializationComplete(Status::SUCCESS);
+  if (!init_ret.isOk()) {
+    if (!mDeathRecipient->getHasDied()) {
+      ALOGE("Error sending init callback, but no death notification.");
+    }
+    return ndk::ScopedAStatus::fromServiceSpecificError(
+        STATUS_FAILED_TRANSACTION);
+  }
+  mH4 = std::make_shared<H4Protocol>(
+      mFd,
+      [](const std::vector<uint8_t>& /* raw_command */) {
+        LOG_ALWAYS_FATAL("Unexpected command!");
+      },
+      [this](const std::vector<uint8_t>& raw_event) {
+        mCb->hciEventReceived(raw_event);
+      },
+      [this](const std::vector<uint8_t>& raw_acl) {
+        mCb->hciEventReceived(raw_acl);
+      },
+      [this](const std::vector<uint8_t>& raw_sco) {
+        mCb->hciEventReceived(raw_sco);
+      },
+      [this](const std::vector<uint8_t>& raw_iso) {
+        mCb->hciEventReceived(raw_iso);
+      },
+      [this]() {
+        ALOGI("HCI socket device disconnected");
+        mFdWatcher.StopWatchingFileDescriptors();
+      });
+  mFdWatcher.WatchFdForNonBlockingReads(mFd,
+                                        [this](int) { mH4->OnDataReady(); });
+  return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus BluetoothHci::close() {
+  ALOGI(__func__);
+  mFdWatcher.StopWatchingFileDescriptors();
+  ::close(mFd);
+
+  return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus BluetoothHci::sendHciCommand(
+    const std::vector<uint8_t>& packet) {
+  send(PacketType::COMMAND, packet);
+  return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus BluetoothHci::sendAclData(
+    const std::vector<uint8_t>& packet) {
+  send(PacketType::ACL_DATA, packet);
+  return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus BluetoothHci::sendScoData(
+    const std::vector<uint8_t>& packet) {
+  send(PacketType::SCO_DATA, packet);
+  return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus BluetoothHci::sendIsoData(
+    const std::vector<uint8_t>& packet) {
+  send(PacketType::ISO_DATA, packet);
+  return ndk::ScopedAStatus::ok();
+}
+
+void BluetoothHci::send(PacketType type, const std::vector<uint8_t>& v) {
+  mH4->Send(type, v);
+}
+
+}  // namespace aidl::android::hardware::bluetooth::impl
diff --git a/bluetooth/aidl/default/BluetoothHci.h b/bluetooth/aidl/default/BluetoothHci.h
new file mode 100644
index 0000000..0ed0623
--- /dev/null
+++ b/bluetooth/aidl/default/BluetoothHci.h
@@ -0,0 +1,71 @@
+/*
+ * 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/bluetooth/BnBluetoothHci.h>
+#include <aidl/android/hardware/bluetooth/IBluetoothHciCallbacks.h>
+#include <log/log.h>
+
+#include <string>
+
+#include "async_fd_watcher.h"
+#include "h4_protocol.h"
+
+namespace aidl::android::hardware::bluetooth::impl {
+
+class BluetoothDeathRecipient;
+
+// This Bluetooth HAL implementation connects with a serial port at dev_path_.
+class BluetoothHci : public BnBluetoothHci {
+ public:
+  BluetoothHci(const std::string& dev_path = "/dev/hvc5");
+
+  ndk::ScopedAStatus initialize(
+      const std::shared_ptr<IBluetoothHciCallbacks>& cb) override;
+
+  ndk::ScopedAStatus sendHciCommand(
+      const std::vector<uint8_t>& packet) override;
+
+  ndk::ScopedAStatus sendAclData(const std::vector<uint8_t>& packet) override;
+
+  ndk::ScopedAStatus sendScoData(const std::vector<uint8_t>& packet) override;
+
+  ndk::ScopedAStatus sendIsoData(const std::vector<uint8_t>& packet) override;
+
+  ndk::ScopedAStatus close() override;
+
+  static void OnPacketReady();
+
+  static BluetoothHci* get();
+
+ private:
+  int mFd{-1};
+  std::shared_ptr<IBluetoothHciCallbacks> mCb = nullptr;
+
+  std::shared_ptr<::android::hardware::bluetooth::hci::H4Protocol> mH4;
+
+  std::shared_ptr<BluetoothDeathRecipient> mDeathRecipient;
+
+  std::string mDevPath;
+
+  ::android::hardware::bluetooth::async::AsyncFdWatcher mFdWatcher;
+
+  void send(::android::hardware::bluetooth::hci::PacketType type,
+            const std::vector<uint8_t>& packet);
+};
+
+}  // namespace aidl::android::hardware::bluetooth::impl
diff --git a/bluetooth/aidl/default/bluetooth-service-default.rc b/bluetooth/aidl/default/bluetooth-service-default.rc
new file mode 100644
index 0000000..1841c77
--- /dev/null
+++ b/bluetooth/aidl/default/bluetooth-service-default.rc
@@ -0,0 +1,6 @@
+service bluetooth_hal_service /vendor/bin/hw/android.hardware.bluetooth-service.default
+    class hal
+    capabilities BLOCK_SUSPEND NET_ADMIN SYS_NICE
+    user bluetooth
+    group bluetooth
+    task_profiles HighPerformance
diff --git a/bluetooth/aidl/default/bluetooth-service-default.xml b/bluetooth/aidl/default/bluetooth-service-default.xml
new file mode 100644
index 0000000..bb05995
--- /dev/null
+++ b/bluetooth/aidl/default/bluetooth-service-default.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.bluetooth</name>
+        <fqname>IBluetoothHci/default</fqname>
+    </hal>
+</manifest>
diff --git a/bluetooth/aidl/default/service.cpp b/bluetooth/aidl/default/service.cpp
new file mode 100644
index 0000000..9af2a08
--- /dev/null
+++ b/bluetooth/aidl/default/service.cpp
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "aidl.android.hardware.bluetooth.service.default"
+
+#include <aidl/android/hardware/bluetooth/IBluetoothHci.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include "BluetoothHci.h"
+
+using ::aidl::android::hardware::bluetooth::impl::BluetoothHci;
+using ::android::hardware::configureRpcThreadpool;
+using ::android::hardware::joinRpcThreadpool;
+
+int main(int /* argc */, char** /* argv */) {
+  ALOGI("Bluetooth HAL starting");
+  if (!ABinderProcess_setThreadPoolMaxThreadCount(1)) {
+    ALOGI("failed to set thread pool max thread count");
+    return 1;
+  }
+
+  std::shared_ptr<BluetoothHci> service =
+      ndk::SharedRefBase::make<BluetoothHci>();
+  std::string instance = std::string() + BluetoothHci::descriptor + "/default";
+  auto result =
+      AServiceManager_addService(service->asBinder().get(), instance.c_str());
+  if (result == STATUS_OK) {
+    ABinderProcess_joinThreadPool();
+  } else {
+    ALOGE("Could not register as a service!");
+  }
+  return 0;
+}
diff --git a/bluetooth/aidl/default/test/fuzzer.cpp b/bluetooth/aidl/default/test/fuzzer.cpp
new file mode 100644
index 0000000..e7a1eef
--- /dev/null
+++ b/bluetooth/aidl/default/test/fuzzer.cpp
@@ -0,0 +1,32 @@
+/*
+ * 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 <fuzzbinder/libbinder_ndk_driver.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+#include "BluetoothHci.h"
+
+using aidl::android::hardware::bluetooth::impl::BluetoothHci;
+using android::fuzzService;
+using ndk::SharedRefBase;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  auto service = SharedRefBase::make<BluetoothHci>();
+
+  fuzzService(service->asBinder().get(), FuzzedDataProvider(data, size));
+
+  return 0;
+}
diff --git a/bluetooth/async/Android.bp b/bluetooth/async/Android.bp
new file mode 100644
index 0000000..bd7d7b8
--- /dev/null
+++ b/bluetooth/async/Android.bp
@@ -0,0 +1,41 @@
+package {
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_static {
+    name: "android.hardware.bluetooth.async",
+    vendor_available: true,
+    host_supported: true,
+    srcs: [
+        "async_fd_watcher.cc",
+    ],
+    export_include_dirs: ["."],
+    shared_libs: [
+        "liblog",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+}
+
+cc_test {
+    name: "bluetooth-vendor-interface-async-test",
+    host_supported: true,
+    srcs: [
+        "test/async_fd_watcher_unittest.cc",
+    ],
+    shared_libs: [
+        "liblog",
+        "libutils",
+    ],
+    static_libs: [
+        "android.hardware.bluetooth.async",
+        "libgmock",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    test_suites: ["general-tests"],
+}
diff --git a/bluetooth/async/async_fd_watcher.cc b/bluetooth/async/async_fd_watcher.cc
new file mode 100644
index 0000000..fb634ff
--- /dev/null
+++ b/bluetooth/async/async_fd_watcher.cc
@@ -0,0 +1,176 @@
+/*
+ * 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 "async_fd_watcher.h"
+
+#include <string.h>
+
+#include <algorithm>
+#include <atomic>
+#include <condition_variable>
+#include <map>
+#include <mutex>
+#include <thread>
+#include <vector>
+
+#include "fcntl.h"
+#include "log/log.h"
+#include "sys/select.h"
+#include "unistd.h"
+
+static const int INVALID_FD = -1;
+
+namespace android::hardware::bluetooth::async {
+
+int AsyncFdWatcher::WatchFdForNonBlockingReads(
+    int file_descriptor, const ReadCallback& on_read_fd_ready_callback) {
+  // Add file descriptor and callback
+  {
+    std::unique_lock<std::mutex> guard(internal_mutex_);
+    watched_fds_[file_descriptor] = on_read_fd_ready_callback;
+  }
+
+  // Start the thread if not started yet
+  return tryStartThread();
+}
+
+int AsyncFdWatcher::ConfigureTimeout(
+    const std::chrono::milliseconds timeout,
+    const TimeoutCallback& on_timeout_callback) {
+  // Add timeout and callback
+  {
+    std::unique_lock<std::mutex> guard(timeout_mutex_);
+    timeout_cb_ = on_timeout_callback;
+    timeout_ms_ = timeout;
+  }
+
+  notifyThread();
+  return 0;
+}
+
+void AsyncFdWatcher::StopWatchingFileDescriptors() { stopThread(); }
+
+AsyncFdWatcher::~AsyncFdWatcher() {}
+
+// Make sure to call this with at least one file descriptor ready to be
+// watched upon or the thread routine will return immediately
+int AsyncFdWatcher::tryStartThread() {
+  if (std::atomic_exchange(&running_, true)) return 0;
+
+  // Set up the communication channel
+  int pipe_fds[2];
+  if (pipe2(pipe_fds, O_NONBLOCK)) return -1;
+
+  notification_listen_fd_ = pipe_fds[0];
+  notification_write_fd_ = pipe_fds[1];
+
+  thread_ = std::thread([this]() { ThreadRoutine(); });
+  if (!thread_.joinable()) return -1;
+
+  return 0;
+}
+
+int AsyncFdWatcher::stopThread() {
+  if (!std::atomic_exchange(&running_, false)) return 0;
+
+  notifyThread();
+  if (std::this_thread::get_id() != thread_.get_id()) {
+    thread_.join();
+  }
+
+  {
+    std::unique_lock<std::mutex> guard(internal_mutex_);
+    watched_fds_.clear();
+  }
+
+  {
+    std::unique_lock<std::mutex> guard(timeout_mutex_);
+    timeout_cb_ = nullptr;
+  }
+
+  close(notification_listen_fd_);
+  close(notification_write_fd_);
+
+  return 0;
+}
+
+int AsyncFdWatcher::notifyThread() {
+  uint8_t buffer[] = {0};
+  if (TEMP_FAILURE_RETRY(write(notification_write_fd_, &buffer, 1)) < 0) {
+    return -1;
+  }
+  return 0;
+}
+
+void AsyncFdWatcher::ThreadRoutine() {
+  while (running_) {
+    fd_set read_fds;
+    FD_ZERO(&read_fds);
+    FD_SET(notification_listen_fd_, &read_fds);
+    int max_read_fd = INVALID_FD;
+    for (auto& it : watched_fds_) {
+      FD_SET(it.first, &read_fds);
+      max_read_fd = std::max(max_read_fd, it.first);
+    }
+
+    struct timeval timeout;
+    struct timeval* timeout_ptr = NULL;
+    if (timeout_ms_ > std::chrono::milliseconds(0)) {
+      timeout.tv_sec = timeout_ms_.count() / 1000;
+      timeout.tv_usec = (timeout_ms_.count() % 1000) * 1000;
+      timeout_ptr = &timeout;
+    }
+
+    // Wait until there is data available to read on some FD.
+    int nfds = std::max(notification_listen_fd_, max_read_fd);
+    int retval = select(nfds + 1, &read_fds, NULL, NULL, timeout_ptr);
+
+    // There was some error.
+    if (retval < 0) continue;
+
+    // Timeout.
+    if (retval == 0) {
+      // Allow the timeout callback to modify the timeout.
+      TimeoutCallback saved_cb;
+      {
+        std::unique_lock<std::mutex> guard(timeout_mutex_);
+        if (timeout_ms_ > std::chrono::milliseconds(0)) saved_cb = timeout_cb_;
+      }
+      if (saved_cb != nullptr) saved_cb();
+      continue;
+    }
+
+    // Read data from the notification FD.
+    if (FD_ISSET(notification_listen_fd_, &read_fds)) {
+      char buffer[] = {0};
+      TEMP_FAILURE_RETRY(read(notification_listen_fd_, buffer, 1));
+      continue;
+    }
+
+    // Invoke the data ready callbacks if appropriate.
+    {
+      // Hold the mutex to make sure that the callbacks are still valid.
+      std::unique_lock<std::mutex> guard(internal_mutex_);
+      for (auto& it : watched_fds_) {
+        if (FD_ISSET(it.first, &read_fds)) {
+          it.second(it.first);
+        }
+      }
+    }
+  }
+}
+
+}  // namespace android::hardware::bluetooth::async
diff --git a/bluetooth/async/async_fd_watcher.h b/bluetooth/async/async_fd_watcher.h
new file mode 100644
index 0000000..b50a7a0
--- /dev/null
+++ b/bluetooth/async/async_fd_watcher.h
@@ -0,0 +1,60 @@
+/*
+ * 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 <map>
+#include <mutex>
+#include <thread>
+
+namespace android::hardware::bluetooth::async {
+
+using ReadCallback = std::function<void(int)>;
+using TimeoutCallback = std::function<void(void)>;
+
+class AsyncFdWatcher {
+ public:
+  AsyncFdWatcher() = default;
+  ~AsyncFdWatcher();
+
+  int WatchFdForNonBlockingReads(int file_descriptor,
+                                 const ReadCallback& on_read_fd_ready_callback);
+  int ConfigureTimeout(const std::chrono::milliseconds timeout,
+                       const TimeoutCallback& on_timeout_callback);
+  void StopWatchingFileDescriptors();
+
+ private:
+  AsyncFdWatcher(const AsyncFdWatcher&) = delete;
+  AsyncFdWatcher& operator=(const AsyncFdWatcher&) = delete;
+
+  int tryStartThread();
+  int stopThread();
+  int notifyThread();
+  void ThreadRoutine();
+
+  std::atomic_bool running_{false};
+  std::thread thread_;
+  std::mutex internal_mutex_;
+  std::mutex timeout_mutex_;
+
+  std::map<int, ReadCallback> watched_fds_;
+  int notification_listen_fd_;
+  int notification_write_fd_;
+  TimeoutCallback timeout_cb_;
+  std::chrono::milliseconds timeout_ms_;
+};
+
+}  // namespace android::hardware::bluetooth::async
diff --git a/bluetooth/async/test/async_fd_watcher_unittest.cc b/bluetooth/async/test/async_fd_watcher_unittest.cc
new file mode 100644
index 0000000..6d75f10
--- /dev/null
+++ b/bluetooth/async/test/async_fd_watcher_unittest.cc
@@ -0,0 +1,377 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "async_fd_watcher_unittest"
+
+#include "async_fd_watcher.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <log/log.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <cstdint>
+#include <cstring>
+#include <vector>
+
+namespace android::hardware::bluetooth::async_test {
+
+using android::hardware::bluetooth::async::AsyncFdWatcher;
+
+class AsyncFdWatcherSocketTest : public ::testing::Test {
+ public:
+  static const uint16_t kPort = 6111;
+  static const size_t kBufferSize = 16;
+
+  bool CheckBufferEquals() {
+    return strcmp(server_buffer_, client_buffer_) == 0;
+  }
+
+ protected:
+  int StartServer() {
+    ALOGD("%s", __func__);
+    struct sockaddr_in serv_addr;
+    int fd = socket(AF_INET, SOCK_STREAM, 0);
+    EXPECT_FALSE(fd < 0);
+
+    memset(&serv_addr, 0, sizeof(serv_addr));
+    serv_addr.sin_family = AF_INET;
+    serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+    serv_addr.sin_port = htons(kPort);
+    int reuse_flag = 1;
+    EXPECT_FALSE(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse_flag,
+                            sizeof(reuse_flag)) < 0);
+    EXPECT_FALSE(bind(fd, (sockaddr*)&serv_addr, sizeof(serv_addr)) < 0);
+
+    ALOGD("%s before listen", __func__);
+    listen(fd, 1);
+    return fd;
+  }
+
+  int AcceptConnection(int fd) {
+    ALOGD("%s", __func__);
+    struct sockaddr_in cli_addr;
+    memset(&cli_addr, 0, sizeof(cli_addr));
+    socklen_t clilen = sizeof(cli_addr);
+
+    int connection_fd = accept(fd, (struct sockaddr*)&cli_addr, &clilen);
+    EXPECT_FALSE(connection_fd < 0);
+
+    return connection_fd;
+  }
+
+  void ReadIncomingMessage(int fd) {
+    ALOGD("%s", __func__);
+    int n = TEMP_FAILURE_RETRY(read(fd, server_buffer_, kBufferSize - 1));
+    EXPECT_FALSE(n < 0);
+
+    if (n == 0) {  // got EOF
+      ALOGD("%s: EOF", __func__);
+    } else {
+      ALOGD("%s: Got something", __func__);
+      n = write(fd, "1", 1);
+    }
+  }
+
+  void SetUp() override {
+    ALOGD("%s", __func__);
+    memset(server_buffer_, 0, kBufferSize);
+    memset(client_buffer_, 0, kBufferSize);
+  }
+
+  void ConfigureServer() {
+    socket_fd_ = StartServer();
+
+    conn_watcher_.WatchFdForNonBlockingReads(socket_fd_, [this](int fd) {
+      int connection_fd = AcceptConnection(fd);
+      ALOGD("%s: Conn_watcher fd = %d", __func__, fd);
+
+      conn_watcher_.ConfigureTimeout(std::chrono::seconds(0), []() {
+        bool connection_timeout_cleared = false;
+        ASSERT_TRUE(connection_timeout_cleared);
+      });
+
+      ALOGD("%s: 3", __func__);
+      async_fd_watcher_.WatchFdForNonBlockingReads(
+          connection_fd, [this](int fd) { ReadIncomingMessage(fd); });
+
+      // Time out if it takes longer than a second.
+      SetTimeout(std::chrono::seconds(1));
+    });
+    conn_watcher_.ConfigureTimeout(std::chrono::seconds(1), []() {
+      bool connection_timeout = true;
+      ASSERT_FALSE(connection_timeout);
+    });
+  }
+
+  void CleanUpServer() {
+    async_fd_watcher_.StopWatchingFileDescriptors();
+    conn_watcher_.StopWatchingFileDescriptors();
+    close(socket_fd_);
+  }
+
+  void TearDown() override {
+    ALOGD("%s 3", __func__);
+    EXPECT_TRUE(CheckBufferEquals());
+  }
+
+  void OnTimeout() {
+    ALOGD("%s", __func__);
+    timed_out_ = true;
+  }
+
+  void ClearTimeout() {
+    ALOGD("%s", __func__);
+    timed_out_ = false;
+  }
+
+  bool TimedOut() {
+    ALOGD("%s %d", __func__, timed_out_ ? 1 : 0);
+    return timed_out_;
+  }
+
+  void SetTimeout(std::chrono::milliseconds timeout_ms) {
+    ALOGD("%s", __func__);
+    async_fd_watcher_.ConfigureTimeout(timeout_ms, [this]() { OnTimeout(); });
+    ClearTimeout();
+  }
+
+  int ConnectClient() {
+    ALOGD("%s", __func__);
+    int socket_cli_fd = socket(AF_INET, SOCK_STREAM, 0);
+    EXPECT_FALSE(socket_cli_fd < 0);
+
+    struct sockaddr_in serv_addr;
+    memset((void*)&serv_addr, 0, sizeof(serv_addr));
+    serv_addr.sin_family = AF_INET;
+    serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+    serv_addr.sin_port = htons(kPort);
+
+    int result =
+        connect(socket_cli_fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
+    EXPECT_FALSE(result < 0);
+
+    return socket_cli_fd;
+  }
+
+  void WriteFromClient(int socket_cli_fd) {
+    ALOGD("%s", __func__);
+    strcpy(client_buffer_, "1");
+    int n = write(socket_cli_fd, client_buffer_, strlen(client_buffer_));
+    EXPECT_TRUE(n > 0);
+  }
+
+  void AwaitServerResponse(int socket_cli_fd) {
+    ALOGD("%s", __func__);
+    int n = read(socket_cli_fd, client_buffer_, 1);
+    ALOGD("%s done", __func__);
+    EXPECT_TRUE(n > 0);
+  }
+
+ private:
+  AsyncFdWatcher async_fd_watcher_;
+  AsyncFdWatcher conn_watcher_;
+  int socket_fd_;
+  char server_buffer_[kBufferSize];
+  char client_buffer_[kBufferSize];
+  bool timed_out_;
+};
+
+// Use a single AsyncFdWatcher to signal a connection to the server socket.
+TEST_F(AsyncFdWatcherSocketTest, Connect) {
+  int socket_fd = StartServer();
+
+  AsyncFdWatcher conn_watcher;
+  conn_watcher.WatchFdForNonBlockingReads(socket_fd, [this](int fd) {
+    int connection_fd = AcceptConnection(fd);
+    close(connection_fd);
+  });
+
+  // Fail if the client doesn't connect within 1 second.
+  conn_watcher.ConfigureTimeout(std::chrono::seconds(1), []() {
+    bool connection_timeout = true;
+    ASSERT_FALSE(connection_timeout);
+  });
+
+  int socket_cli_fd = ConnectClient();
+  conn_watcher.StopWatchingFileDescriptors();
+  close(socket_fd);
+  close(socket_cli_fd);
+}
+
+// Use a single AsyncFdWatcher to signal a connection to the server socket.
+TEST_F(AsyncFdWatcherSocketTest, TimedOutConnect) {
+  int socket_fd = StartServer();
+  bool timed_out = false;
+  bool* timeout_ptr = &timed_out;
+
+  AsyncFdWatcher conn_watcher;
+  conn_watcher.WatchFdForNonBlockingReads(socket_fd, [this](int fd) {
+    int connection_fd = AcceptConnection(fd);
+    close(connection_fd);
+  });
+
+  // Set the timeout flag after 100ms.
+  conn_watcher.ConfigureTimeout(std::chrono::milliseconds(100),
+                                [timeout_ptr]() { *timeout_ptr = true; });
+  EXPECT_FALSE(timed_out);
+  sleep(1);
+  EXPECT_TRUE(timed_out);
+  conn_watcher.StopWatchingFileDescriptors();
+  close(socket_fd);
+}
+
+// Modify the timeout in a timeout callback.
+TEST_F(AsyncFdWatcherSocketTest, TimedOutSchedulesTimeout) {
+  int socket_fd = StartServer();
+  bool timed_out = false;
+  bool timed_out2 = false;
+
+  AsyncFdWatcher conn_watcher;
+  conn_watcher.WatchFdForNonBlockingReads(socket_fd, [this](int fd) {
+    int connection_fd = AcceptConnection(fd);
+    close(connection_fd);
+  });
+
+  // Set a timeout flag in each callback.
+  conn_watcher.ConfigureTimeout(std::chrono::milliseconds(500),
+                                [&conn_watcher, &timed_out, &timed_out2]() {
+                                  timed_out = true;
+                                  conn_watcher.ConfigureTimeout(
+                                      std::chrono::seconds(1),
+                                      [&timed_out2]() { timed_out2 = true; });
+                                });
+  EXPECT_FALSE(timed_out);
+  EXPECT_FALSE(timed_out2);
+  sleep(1);
+  EXPECT_TRUE(timed_out);
+  EXPECT_FALSE(timed_out2);
+  sleep(1);
+  EXPECT_TRUE(timed_out);
+  EXPECT_TRUE(timed_out2);
+  conn_watcher.StopWatchingFileDescriptors();
+  close(socket_fd);
+}
+
+MATCHER_P(ReadAndMatchSingleChar, byte,
+          "Reads a byte from the file descriptor and matches the value against "
+          "byte") {
+  char inbuf[1] = {0};
+
+  int n = TEMP_FAILURE_RETRY(read(arg, inbuf, 1));
+
+  TEMP_FAILURE_RETRY(write(arg, inbuf, 1));
+  if (n != 1) {
+    return false;
+  }
+  return inbuf[0] == byte;
+};
+
+// Use a single AsyncFdWatcher to watch two file descriptors.
+TEST_F(AsyncFdWatcherSocketTest, WatchTwoFileDescriptors) {
+  int sockfd1[2];
+  int sockfd2[2];
+  socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd1);
+  socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd2);
+
+  testing::MockFunction<void(int)> cb1;
+  testing::MockFunction<void(int)> cb2;
+
+  AsyncFdWatcher watcher;
+  watcher.WatchFdForNonBlockingReads(sockfd1[0], cb1.AsStdFunction());
+
+  watcher.WatchFdForNonBlockingReads(sockfd2[0], cb2.AsStdFunction());
+
+  EXPECT_CALL(cb1, Call(ReadAndMatchSingleChar('1')));
+  char one_buf[1] = {'1'};
+  TEMP_FAILURE_RETRY(write(sockfd1[1], one_buf, sizeof(one_buf)));
+
+  EXPECT_CALL(cb2, Call(ReadAndMatchSingleChar('2')));
+  char two_buf[1] = {'2'};
+  TEMP_FAILURE_RETRY(write(sockfd2[1], two_buf, sizeof(two_buf)));
+
+  // Blocking read instead of a flush.
+  TEMP_FAILURE_RETRY(read(sockfd1[1], one_buf, sizeof(one_buf)));
+  TEMP_FAILURE_RETRY(read(sockfd2[1], two_buf, sizeof(two_buf)));
+
+  watcher.StopWatchingFileDescriptors();
+}
+
+// Use two AsyncFdWatchers to set up a server socket.
+TEST_F(AsyncFdWatcherSocketTest, ClientServer) {
+  ConfigureServer();
+  int socket_cli_fd = ConnectClient();
+
+  WriteFromClient(socket_cli_fd);
+
+  AwaitServerResponse(socket_cli_fd);
+
+  close(socket_cli_fd);
+  CleanUpServer();
+}
+
+// Use two AsyncFdWatchers to set up a server socket, which times out.
+TEST_F(AsyncFdWatcherSocketTest, TimeOutTest) {
+  ConfigureServer();
+  int socket_cli_fd = ConnectClient();
+
+  while (!TimedOut()) sleep(1);
+
+  close(socket_cli_fd);
+  CleanUpServer();
+}
+
+// Use two AsyncFdWatchers to set up a server socket, which times out.
+TEST_F(AsyncFdWatcherSocketTest, RepeatedTimeOutTest) {
+  ConfigureServer();
+  int socket_cli_fd = ConnectClient();
+  ClearTimeout();
+
+  // Time out when there are no writes.
+  EXPECT_FALSE(TimedOut());
+  sleep(2);
+  EXPECT_TRUE(TimedOut());
+  ClearTimeout();
+
+  // Don't time out when there is a write.
+  WriteFromClient(socket_cli_fd);
+  AwaitServerResponse(socket_cli_fd);
+  EXPECT_FALSE(TimedOut());
+  ClearTimeout();
+
+  // Time out when the write is late.
+  sleep(2);
+  WriteFromClient(socket_cli_fd);
+  AwaitServerResponse(socket_cli_fd);
+  EXPECT_TRUE(TimedOut());
+  ClearTimeout();
+
+  // Time out when there is a pause after a write.
+  WriteFromClient(socket_cli_fd);
+  sleep(2);
+  AwaitServerResponse(socket_cli_fd);
+  EXPECT_TRUE(TimedOut());
+  ClearTimeout();
+
+  close(socket_cli_fd);
+  CleanUpServer();
+}
+
+}  // namespace android::hardware::bluetooth::async_test
diff --git a/bluetooth/audio/utils/Android.bp b/bluetooth/audio/utils/Android.bp
index 674dd11..70797a7 100644
--- a/bluetooth/audio/utils/Android.bp
+++ b/bluetooth/audio/utils/Android.bp
@@ -63,6 +63,31 @@
     generated_headers: ["le_audio_codec_capabilities"],
 }
 
+cc_test {
+    name: "BluetoothLeAudioCodecsProviderTest",
+    srcs: [
+        "aidl_session/BluetoothLeAudioCodecsProvider.cpp",
+        "aidl_session/BluetoothLeAudioCodecsProviderTest.cpp",
+    ],
+    header_libs: [
+        "libxsdc-utils",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "android.hardware.bluetooth.audio-V2-ndk",
+        "libxml2",
+    ],
+    test_suites: [
+        "general-tests",
+    ],
+    test_options: {
+        unit_test: false,
+    },
+    generated_sources: ["le_audio_codec_capabilities"],
+    generated_headers: ["le_audio_codec_capabilities"],
+}
+
 xsd_config {
     name: "le_audio_codec_capabilities",
     srcs: ["le_audio_codec_capabilities/le_audio_codec_capabilities.xsd"],
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
index 855dd28..faebbbf 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
@@ -398,8 +398,11 @@
   }
 
   if (kDefaultOffloadLeAudioCapabilities.empty()) {
+    auto le_audio_offload_setting =
+        BluetoothLeAudioCodecsProvider::ParseFromLeAudioOffloadSettingFile();
     kDefaultOffloadLeAudioCapabilities =
-        BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities();
+        BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities(
+            le_audio_offload_setting);
   }
 
   return kDefaultOffloadLeAudioCapabilities;
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp
index bf49270..1dec900 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp
@@ -34,20 +34,40 @@
 
 static std::vector<LeAudioCodecCapabilitiesSetting> leAudioCodecCapabilities;
 
-std::vector<LeAudioCodecCapabilitiesSetting>
-BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities() {
-  if (!leAudioCodecCapabilities.empty()) {
-    return leAudioCodecCapabilities;
-  }
+static bool isInvalidFileContent = false;
 
-  const auto le_audio_offload_setting =
+std::optional<setting::LeAudioOffloadSetting>
+BluetoothLeAudioCodecsProvider::ParseFromLeAudioOffloadSettingFile() {
+  if (!leAudioCodecCapabilities.empty() || isInvalidFileContent) {
+    return std::nullopt;
+  }
+  auto le_audio_offload_setting =
       setting::readLeAudioOffloadSetting(kLeAudioCodecCapabilitiesFile);
   if (!le_audio_offload_setting.has_value()) {
     LOG(ERROR) << __func__ << ": Failed to read "
                << kLeAudioCodecCapabilitiesFile;
+  }
+  return le_audio_offload_setting;
+}
+
+std::vector<LeAudioCodecCapabilitiesSetting>
+BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities(
+    const std::optional<setting::LeAudioOffloadSetting>&
+        le_audio_offload_setting) {
+  if (!leAudioCodecCapabilities.empty()) {
+    return leAudioCodecCapabilities;
+  }
+
+  if (!le_audio_offload_setting.has_value()) {
+    LOG(ERROR)
+        << __func__
+        << ": input le_audio_offload_setting content need to be non empty";
     return {};
   }
 
+  ClearLeAudioCodecCapabilities();
+  isInvalidFileContent = true;
+
   std::vector<setting::Scenario> supported_scenarios =
       GetScenarios(le_audio_offload_setting);
   if (supported_scenarios.empty()) {
@@ -79,9 +99,18 @@
 
   leAudioCodecCapabilities =
       ComposeLeAudioCodecCapabilities(supported_scenarios);
+  isInvalidFileContent = leAudioCodecCapabilities.empty();
+
   return leAudioCodecCapabilities;
 }
 
+void BluetoothLeAudioCodecsProvider::ClearLeAudioCodecCapabilities() {
+  leAudioCodecCapabilities.clear();
+  configuration_map_.clear();
+  codec_configuration_map_.clear();
+  strategy_configuration_map_.clear();
+}
+
 std::vector<setting::Scenario> BluetoothLeAudioCodecsProvider::GetScenarios(
     const std::optional<setting::LeAudioOffloadSetting>&
         le_audio_offload_setting) {
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h
index 402235f..e879984 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h
@@ -31,8 +31,13 @@
 
 class BluetoothLeAudioCodecsProvider {
  public:
+  static std::optional<setting::LeAudioOffloadSetting>
+  ParseFromLeAudioOffloadSettingFile();
   static std::vector<LeAudioCodecCapabilitiesSetting>
-  GetLeAudioCodecCapabilities();
+  GetLeAudioCodecCapabilities(
+      const std::optional<setting::LeAudioOffloadSetting>&
+          le_audio_offload_setting);
+  static void ClearLeAudioCodecCapabilities();
 
  private:
   static inline std::unordered_map<std::string, setting::Configuration>
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProviderTest.cpp b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProviderTest.cpp
new file mode 100644
index 0000000..5393cd7
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProviderTest.cpp
@@ -0,0 +1,373 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <optional>
+#include <tuple>
+
+#include "BluetoothLeAudioCodecsProvider.h"
+
+using aidl::android::hardware::bluetooth::audio::BluetoothLeAudioCodecsProvider;
+using aidl::android::hardware::bluetooth::audio::
+    LeAudioCodecCapabilitiesSetting;
+using aidl::android::hardware::bluetooth::audio::setting::AudioLocation;
+using aidl::android::hardware::bluetooth::audio::setting::CodecConfiguration;
+using aidl::android::hardware::bluetooth::audio::setting::
+    CodecConfigurationList;
+using aidl::android::hardware::bluetooth::audio::setting::CodecType;
+using aidl::android::hardware::bluetooth::audio::setting::Configuration;
+using aidl::android::hardware::bluetooth::audio::setting::ConfigurationList;
+using aidl::android::hardware::bluetooth::audio::setting::LeAudioOffloadSetting;
+using aidl::android::hardware::bluetooth::audio::setting::Scenario;
+using aidl::android::hardware::bluetooth::audio::setting::ScenarioList;
+using aidl::android::hardware::bluetooth::audio::setting::StrategyConfiguration;
+using aidl::android::hardware::bluetooth::audio::setting::
+    StrategyConfigurationList;
+
+typedef std::tuple<std::vector<ScenarioList>, std::vector<ConfigurationList>,
+                   std::vector<CodecConfigurationList>,
+                   std::vector<StrategyConfigurationList>>
+    OffloadSetting;
+
+// Define valid components for each list
+// Scenario
+static const Scenario kValidScenario(std::make_optional("OneChanStereo_16_1"),
+                                     std::make_optional("OneChanStereo_16_1"));
+// Configuration
+static const Configuration kValidConfigOneChanStereo_16_1(
+    std::make_optional("OneChanStereo_16_1"), std::make_optional("LC3_16k_1"),
+    std::make_optional("STEREO_ONE_CIS_PER_DEVICE"));
+// CodecConfiguration
+static const CodecConfiguration kValidCodecLC3_16k_1(
+    std::make_optional("LC3_16k_1"), std::make_optional(CodecType::LC3),
+    std::nullopt, std::make_optional(16000), std::make_optional(7500),
+    std::make_optional(30), std::nullopt);
+// StrategyConfiguration
+static const StrategyConfiguration kValidStrategyStereoOneCis(
+    std::make_optional("STEREO_ONE_CIS_PER_DEVICE"),
+    std::make_optional(AudioLocation::STEREO), std::make_optional(2),
+    std::make_optional(1));
+static const StrategyConfiguration kValidStrategyStereoTwoCis(
+    std::make_optional("STEREO_TWO_CISES_PER_DEVICE"),
+    std::make_optional(AudioLocation::STEREO), std::make_optional(1),
+    std::make_optional(2));
+static const StrategyConfiguration kValidStrategyMonoOneCis(
+    std::make_optional("MONO_ONE_CIS_PER_DEVICE"),
+    std::make_optional(AudioLocation::MONO), std::make_optional(1),
+    std::make_optional(1));
+
+// Define valid test list built from above valid components
+// Scenario, Configuration, CodecConfiguration, StrategyConfiguration
+static const std::vector<ScenarioList> kValidScenarioList = {
+    ScenarioList(std::vector<Scenario>{kValidScenario})};
+static const std::vector<ConfigurationList> kValidConfigurationList = {
+    ConfigurationList(
+        std::vector<Configuration>{kValidConfigOneChanStereo_16_1})};
+static const std::vector<CodecConfigurationList> kValidCodecConfigurationList =
+    {CodecConfigurationList(
+        std::vector<CodecConfiguration>{kValidCodecLC3_16k_1})};
+static const std::vector<StrategyConfigurationList>
+    kValidStrategyConfigurationList = {
+        StrategyConfigurationList(std::vector<StrategyConfiguration>{
+            kValidStrategyStereoOneCis, kValidStrategyStereoTwoCis,
+            kValidStrategyMonoOneCis})};
+
+class BluetoothLeAudioCodecsProviderTest
+    : public ::testing::TestWithParam<OffloadSetting> {
+ public:
+  static std::vector<OffloadSetting> CreateTestCases(
+      const std::vector<ScenarioList>& scenario_lists,
+      const std::vector<ConfigurationList>& configuration_lists,
+      const std::vector<CodecConfigurationList>& codec_configuration_lists,
+      const std::vector<StrategyConfigurationList>&
+          strategy_configuration_lists) {
+    // make each vector in output test_cases has only one element
+    // to match the input of test params
+    // normally only one vector in input has multiple elements
+    // we just split elements in this vector to several vector
+    std::vector<OffloadSetting> test_cases;
+    for (const auto& scenario_list : scenario_lists) {
+      for (const auto& configuration_list : configuration_lists) {
+        for (const auto& codec_configuration_list : codec_configuration_lists) {
+          for (const auto& strategy_configuration_list :
+               strategy_configuration_lists) {
+            test_cases.push_back(CreateTestCase(
+                scenario_list, configuration_list, codec_configuration_list,
+                strategy_configuration_list));
+          }
+        }
+      }
+    }
+    return test_cases;
+  }
+
+ protected:
+  void Initialize() {
+    BluetoothLeAudioCodecsProvider::ClearLeAudioCodecCapabilities();
+  }
+
+  std::vector<LeAudioCodecCapabilitiesSetting> RunTestCase() {
+    auto& [scenario_lists, configuration_lists, codec_configuration_lists,
+           strategy_configuration_lists] = GetParam();
+    LeAudioOffloadSetting le_audio_offload_setting(
+        scenario_lists, configuration_lists, codec_configuration_lists,
+        strategy_configuration_lists);
+    auto le_audio_codec_capabilities =
+        BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities(
+            std::make_optional(le_audio_offload_setting));
+    return le_audio_codec_capabilities;
+  }
+
+ private:
+  static inline OffloadSetting CreateTestCase(
+      const ScenarioList& scenario_list,
+      const ConfigurationList& configuration_list,
+      const CodecConfigurationList& codec_configuration_list,
+      const StrategyConfigurationList& strategy_configuration_list) {
+    return std::make_tuple(
+        std::vector<ScenarioList>{scenario_list},
+        std::vector<ConfigurationList>{configuration_list},
+        std::vector<CodecConfigurationList>{codec_configuration_list},
+        std::vector<StrategyConfigurationList>{strategy_configuration_list});
+  }
+};
+
+class GetScenariosTest : public BluetoothLeAudioCodecsProviderTest {
+ public:
+  static std::vector<ScenarioList> CreateInvalidScenarios() {
+    std::vector<ScenarioList> invalid_scenario_test_cases;
+    invalid_scenario_test_cases.push_back(ScenarioList(std::vector<Scenario>{
+        Scenario(std::nullopt, std::make_optional("OneChanStereo_16_1"))}));
+
+    invalid_scenario_test_cases.push_back(ScenarioList(std::vector<Scenario>{
+        Scenario(std::make_optional("OneChanStereo_16_1"), std::nullopt)}));
+
+    invalid_scenario_test_cases.push_back(ScenarioList(
+        std::vector<Scenario>{Scenario(std::nullopt, std::nullopt)}));
+
+    invalid_scenario_test_cases.push_back(
+        ScenarioList(std::vector<Scenario>{}));
+
+    return invalid_scenario_test_cases;
+  }
+};
+
+TEST_P(GetScenariosTest, InvalidScenarios) {
+  Initialize();
+  auto le_audio_codec_capabilities = RunTestCase();
+  ASSERT_TRUE(le_audio_codec_capabilities.empty());
+}
+
+class UpdateConfigurationsToMapTest
+    : public BluetoothLeAudioCodecsProviderTest {
+ public:
+  static std::vector<ConfigurationList> CreateInvalidConfigurations() {
+    std::vector<ConfigurationList> invalid_configuration_test_cases;
+    invalid_configuration_test_cases.push_back(
+        ConfigurationList(std::vector<Configuration>{
+            Configuration(std::nullopt, std::make_optional("LC3_16k_1"),
+                          std::make_optional("STEREO_ONE_CIS_PER_DEVICE"))}));
+
+    invalid_configuration_test_cases.push_back(
+        ConfigurationList(std::vector<Configuration>{Configuration(
+            std::make_optional("OneChanStereo_16_1"), std::nullopt,
+            std::make_optional("STEREO_ONE_CIS_PER_DEVICE"))}));
+
+    invalid_configuration_test_cases.push_back(
+        ConfigurationList(std::vector<Configuration>{
+            Configuration(std::make_optional("OneChanStereo_16_1"),
+                          std::make_optional("LC3_16k_1"), std::nullopt)}));
+
+    invalid_configuration_test_cases.push_back(
+        ConfigurationList(std::vector<Configuration>{}));
+
+    return invalid_configuration_test_cases;
+  }
+};
+
+TEST_P(UpdateConfigurationsToMapTest, InvalidConfigurations) {
+  Initialize();
+  auto le_audio_codec_capabilities = RunTestCase();
+  ASSERT_TRUE(le_audio_codec_capabilities.empty());
+}
+
+class UpdateCodecConfigurationsToMapTest
+    : public BluetoothLeAudioCodecsProviderTest {
+ public:
+  static std::vector<CodecConfigurationList>
+  CreateInvalidCodecConfigurations() {
+    std::vector<CodecConfigurationList> invalid_codec_configuration_test_cases;
+    invalid_codec_configuration_test_cases.push_back(CodecConfigurationList(
+        std::vector<CodecConfiguration>{CodecConfiguration(
+            std::nullopt, std::make_optional(CodecType::LC3), std::nullopt,
+            std::make_optional(16000), std::make_optional(7500),
+            std::make_optional(30), std::nullopt)}));
+
+    invalid_codec_configuration_test_cases.push_back(CodecConfigurationList(
+        std::vector<CodecConfiguration>{CodecConfiguration(
+            std::make_optional("LC3_16k_1"), std::nullopt, std::nullopt,
+            std::make_optional(16000), std::make_optional(7500),
+            std::make_optional(30), std::nullopt)}));
+
+    invalid_codec_configuration_test_cases.push_back(CodecConfigurationList(
+        std::vector<CodecConfiguration>{CodecConfiguration(
+            std::make_optional("LC3_16k_1"), std::make_optional(CodecType::LC3),
+            std::nullopt, std::nullopt, std::make_optional(7500),
+            std::make_optional(30), std::nullopt)}));
+
+    invalid_codec_configuration_test_cases.push_back(CodecConfigurationList(
+        std::vector<CodecConfiguration>{CodecConfiguration(
+            std::make_optional("LC3_16k_1"), std::make_optional(CodecType::LC3),
+            std::nullopt, std::make_optional(16000), std::nullopt,
+            std::make_optional(30), std::nullopt)}));
+
+    invalid_codec_configuration_test_cases.push_back(CodecConfigurationList(
+        std::vector<CodecConfiguration>{CodecConfiguration(
+            std::make_optional("LC3_16k_1"), std::make_optional(CodecType::LC3),
+            std::nullopt, std::make_optional(16000), std::make_optional(7500),
+            std::nullopt, std::nullopt)}));
+
+    invalid_codec_configuration_test_cases.push_back(
+        CodecConfigurationList(std::vector<CodecConfiguration>{}));
+
+    return invalid_codec_configuration_test_cases;
+  }
+};
+
+TEST_P(UpdateCodecConfigurationsToMapTest, InvalidCodecConfigurations) {
+  Initialize();
+  auto le_audio_codec_capabilities = RunTestCase();
+  ASSERT_TRUE(le_audio_codec_capabilities.empty());
+}
+
+class UpdateStrategyConfigurationsToMapTest
+    : public BluetoothLeAudioCodecsProviderTest {
+ public:
+  static std::vector<StrategyConfigurationList>
+  CreateInvalidStrategyConfigurations() {
+    std::vector<StrategyConfigurationList>
+        invalid_strategy_configuration_test_cases;
+    invalid_strategy_configuration_test_cases.push_back(
+        StrategyConfigurationList(
+            std::vector<StrategyConfiguration>{StrategyConfiguration(
+                std::make_optional("STEREO_ONE_CIS_PER_DEVICE"),
+                std::make_optional(AudioLocation::STEREO),
+                std::make_optional(2), std::make_optional(2))}));
+
+    invalid_strategy_configuration_test_cases.push_back(
+        StrategyConfigurationList(
+            std::vector<StrategyConfiguration>{StrategyConfiguration(
+                std::make_optional("MONO_ONE_CIS_PER_DEVICE"),
+                std::make_optional(AudioLocation::STEREO),
+                std::make_optional(2), std::make_optional(2))}));
+
+    invalid_strategy_configuration_test_cases.push_back(
+        StrategyConfigurationList(
+            std::vector<StrategyConfiguration>{StrategyConfiguration(
+                std::nullopt, std::make_optional(AudioLocation::STEREO),
+                std::make_optional(2), std::make_optional(1))}));
+
+    invalid_strategy_configuration_test_cases.push_back(
+        StrategyConfigurationList(
+            std::vector<StrategyConfiguration>{StrategyConfiguration(
+                std::make_optional("STEREO_ONE_CIS_PER_DEVICE"), std::nullopt,
+                std::make_optional(2), std::make_optional(1))}));
+
+    invalid_strategy_configuration_test_cases.push_back(
+        StrategyConfigurationList(
+            std::vector<StrategyConfiguration>{StrategyConfiguration(
+                std::make_optional("STEREO_ONE_CIS_PER_DEVICE"),
+                std::make_optional(AudioLocation::STEREO), std::nullopt,
+                std::make_optional(1))}));
+
+    invalid_strategy_configuration_test_cases.push_back(
+        StrategyConfigurationList(
+            std::vector<StrategyConfiguration>{StrategyConfiguration(
+                std::make_optional("STEREO_ONE_CIS_PER_DEVICE"),
+                std::make_optional(AudioLocation::STEREO),
+                std::make_optional(2), std::nullopt)}));
+
+    invalid_strategy_configuration_test_cases.push_back(
+        StrategyConfigurationList(std::vector<StrategyConfiguration>{}));
+
+    return invalid_strategy_configuration_test_cases;
+  }
+};
+
+TEST_P(UpdateStrategyConfigurationsToMapTest, InvalidStrategyConfigurations) {
+  Initialize();
+  auto le_audio_codec_capabilities = RunTestCase();
+  ASSERT_TRUE(le_audio_codec_capabilities.empty());
+}
+
+class ComposeLeAudioCodecCapabilitiesTest
+    : public BluetoothLeAudioCodecsProviderTest {
+ public:
+};
+
+TEST_P(ComposeLeAudioCodecCapabilitiesTest, CodecCapabilitiesNotEmpty) {
+  Initialize();
+  auto le_audio_codec_capabilities = RunTestCase();
+  ASSERT_TRUE(!le_audio_codec_capabilities.empty());
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GetScenariosTest);
+INSTANTIATE_TEST_SUITE_P(
+    BluetoothLeAudioCodecsProviderTest, GetScenariosTest,
+    ::testing::ValuesIn(BluetoothLeAudioCodecsProviderTest::CreateTestCases(
+        GetScenariosTest::CreateInvalidScenarios(), kValidConfigurationList,
+        kValidCodecConfigurationList, kValidStrategyConfigurationList)));
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(UpdateConfigurationsToMapTest);
+INSTANTIATE_TEST_SUITE_P(
+    BluetoothLeAudioCodecsProviderTest, UpdateConfigurationsToMapTest,
+    ::testing::ValuesIn(BluetoothLeAudioCodecsProviderTest::CreateTestCases(
+        kValidScenarioList,
+        UpdateConfigurationsToMapTest::CreateInvalidConfigurations(),
+        kValidCodecConfigurationList, kValidStrategyConfigurationList)));
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+    UpdateCodecConfigurationsToMapTest);
+INSTANTIATE_TEST_SUITE_P(
+    BluetoothLeAudioCodecsProviderTest, UpdateCodecConfigurationsToMapTest,
+    ::testing::ValuesIn(BluetoothLeAudioCodecsProviderTest::CreateTestCases(
+        kValidScenarioList, kValidConfigurationList,
+        UpdateCodecConfigurationsToMapTest::CreateInvalidCodecConfigurations(),
+        kValidStrategyConfigurationList)));
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+    UpdateStrategyConfigurationsToMapTest);
+INSTANTIATE_TEST_SUITE_P(
+    BluetoothLeAudioCodecsProviderTest, UpdateStrategyConfigurationsToMapTest,
+    ::testing::ValuesIn(BluetoothLeAudioCodecsProviderTest::CreateTestCases(
+        kValidScenarioList, kValidConfigurationList,
+        kValidCodecConfigurationList,
+        UpdateStrategyConfigurationsToMapTest::
+            CreateInvalidStrategyConfigurations())));
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+    ComposeLeAudioCodecCapabilitiesTest);
+INSTANTIATE_TEST_SUITE_P(
+    BluetoothLeAudioCodecsProviderTest, ComposeLeAudioCodecCapabilitiesTest,
+    ::testing::ValuesIn(BluetoothLeAudioCodecsProviderTest::CreateTestCases(
+        kValidScenarioList, kValidConfigurationList,
+        kValidCodecConfigurationList, kValidStrategyConfigurationList)));
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/bluetooth/hci/Android.bp b/bluetooth/hci/Android.bp
new file mode 100644
index 0000000..f0f6e8f
--- /dev/null
+++ b/bluetooth/hci/Android.bp
@@ -0,0 +1,46 @@
+package {
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_static {
+    name: "android.hardware.bluetooth.hci",
+    vendor_available: true,
+    host_supported: true,
+    defaults: ["hidl_defaults"],
+    srcs: [
+        "hci_packetizer.cc",
+        "h4_protocol.cc",
+    ],
+    export_include_dirs: ["."],
+    shared_libs: [
+        "libbase",
+        "libhidlbase",
+        "liblog",
+        "libutils",
+    ],
+}
+
+cc_test {
+    name: "bluetooth-vendor-interface-hci-test",
+    host_supported: true,
+    defaults: ["hidl_defaults"],
+    srcs: [
+        "test/h4_protocol_unittest.cc",
+    ],
+    shared_libs: [
+        "libbase",
+        "libhidlbase",
+        "liblog",
+        "libutils",
+    ],
+    static_libs: [
+        "android.hardware.bluetooth.async",
+        "android.hardware.bluetooth.hci",
+        "libgmock",
+    ],
+    sanitize: {
+        address: true,
+        cfi: true,
+    },
+    test_suites: ["general-tests"],
+}
diff --git a/bluetooth/hci/h4_protocol.cc b/bluetooth/hci/h4_protocol.cc
new file mode 100644
index 0000000..97ba7aa
--- /dev/null
+++ b/bluetooth/hci/h4_protocol.cc
@@ -0,0 +1,144 @@
+/*
+ * 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 "h4_protocol.h"
+
+#define LOG_TAG "android.hardware.bluetooth.hci-h4"
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/uio.h>
+
+#include "log/log.h"
+
+namespace android::hardware::bluetooth::hci {
+
+H4Protocol::H4Protocol(int fd, PacketReadCallback cmd_cb,
+                       PacketReadCallback acl_cb, PacketReadCallback sco_cb,
+                       PacketReadCallback event_cb, PacketReadCallback iso_cb,
+                       DisconnectCallback disconnect_cb)
+    : uart_fd_(fd),
+      cmd_cb_(std::move(cmd_cb)),
+      acl_cb_(std::move(acl_cb)),
+      sco_cb_(std::move(sco_cb)),
+      event_cb_(std::move(event_cb)),
+      iso_cb_(std::move(iso_cb)),
+      disconnect_cb_(std::move(disconnect_cb)) {}
+
+size_t H4Protocol::Send(PacketType type, const std::vector<uint8_t>& vector) {
+  return Send(type, vector.data(), vector.size());
+}
+
+size_t H4Protocol::Send(PacketType type, const uint8_t* data, size_t length) {
+  /* For HCI communication over USB dongle, multiple write results in
+   * response timeout as driver expect type + data at once to process
+   * the command, so using "writev"(for atomicity) here.
+   */
+  struct iovec iov[2];
+  ssize_t ret = 0;
+  iov[0].iov_base = &type;
+  iov[0].iov_len = sizeof(type);
+  iov[1].iov_base = (void*)data;
+  iov[1].iov_len = length;
+  while (1) {
+    ret = TEMP_FAILURE_RETRY(writev(uart_fd_, iov, 2));
+    if (ret == -1) {
+      if (errno == EAGAIN) {
+        ALOGE("%s error writing to UART (%s)", __func__, strerror(errno));
+        continue;
+      }
+    } else if (ret == 0) {
+      // Nothing written :(
+      ALOGE("%s zero bytes written - something went wrong...", __func__);
+      break;
+    }
+    break;
+  }
+  return ret;
+}
+
+size_t H4Protocol::OnPacketReady(const std::vector<uint8_t>& packet) {
+  switch (hci_packet_type_) {
+    case PacketType::COMMAND:
+      cmd_cb_(packet);
+      break;
+    case PacketType::ACL_DATA:
+      acl_cb_(packet);
+      break;
+    case PacketType::SCO_DATA:
+      sco_cb_(packet);
+      break;
+    case PacketType::EVENT:
+      event_cb_(packet);
+      break;
+    case PacketType::ISO_DATA:
+      iso_cb_(packet);
+      break;
+    default: {
+      LOG_ALWAYS_FATAL("Bad packet type 0x%x",
+                       static_cast<int>(hci_packet_type_));
+    }
+  }
+  return packet.size();
+}
+
+void H4Protocol::SendDataToPacketizer(uint8_t* buffer, size_t length) {
+  std::vector<uint8_t> input_buffer{buffer, buffer + length};
+  size_t buffer_offset = 0;
+  while (buffer_offset < input_buffer.size()) {
+    if (hci_packet_type_ == PacketType::UNKNOWN) {
+      hci_packet_type_ =
+          static_cast<PacketType>(input_buffer.data()[buffer_offset]);
+      buffer_offset += 1;
+    } else {
+      bool packet_ready = hci_packetizer_.OnDataReady(
+          hci_packet_type_, input_buffer, buffer_offset);
+      if (packet_ready) {
+        // Call packet callback and move offset.
+        buffer_offset += OnPacketReady(hci_packetizer_.GetPacket());
+        // Get ready for the next type byte.
+        hci_packet_type_ = PacketType::UNKNOWN;
+      } else {
+        // The data was consumed, but there wasn't a packet.
+        buffer_offset = input_buffer.size();
+      }
+    }
+  }
+}
+
+void H4Protocol::OnDataReady() {
+  if (disconnected_) {
+    return;
+  }
+  uint8_t buffer[kMaxPacketLength];
+  ssize_t bytes_read =
+      TEMP_FAILURE_RETRY(read(uart_fd_, buffer, kMaxPacketLength));
+  if (bytes_read == 0) {
+    ALOGI("No bytes read, calling the disconnect callback");
+    disconnected_ = true;
+    disconnect_cb_();
+    return;
+  }
+  if (bytes_read < 0) {
+    ALOGW("error reading from UART (%s)", strerror(errno));
+    return;
+  }
+  SendDataToPacketizer(buffer, bytes_read);
+}
+
+}  // namespace android::hardware::bluetooth::hci
diff --git a/bluetooth/hci/h4_protocol.h b/bluetooth/hci/h4_protocol.h
new file mode 100644
index 0000000..5daee83
--- /dev/null
+++ b/bluetooth/hci/h4_protocol.h
@@ -0,0 +1,68 @@
+/*
+ * 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 <memory>
+#include <vector>
+
+#include "hci_internals.h"
+#include "hci_packetizer.h"
+
+namespace android::hardware::bluetooth::hci {
+
+using PacketReadCallback = std::function<void(const std::vector<uint8_t>&)>;
+using DisconnectCallback = std::function<void(void)>;
+
+class H4Protocol {
+ public:
+  H4Protocol(int fd, PacketReadCallback cmd_cb, PacketReadCallback acl_cb,
+             PacketReadCallback sco_cb, PacketReadCallback event_cb,
+             PacketReadCallback iso_cb, DisconnectCallback disconnect_cb);
+
+  size_t Send(PacketType type, const uint8_t* data, size_t length);
+  size_t Send(PacketType type, const std::vector<uint8_t>& data);
+
+  void OnDataReady();
+
+ protected:
+  size_t OnPacketReady(const std::vector<uint8_t>& packet);
+  void SendDataToPacketizer(uint8_t* buffer, size_t length);
+
+ private:
+  int uart_fd_;
+  bool disconnected_{false};
+
+  PacketReadCallback cmd_cb_;
+  PacketReadCallback acl_cb_;
+  PacketReadCallback sco_cb_;
+  PacketReadCallback event_cb_;
+  PacketReadCallback iso_cb_;
+  DisconnectCallback disconnect_cb_;
+
+  PacketType hci_packet_type_{PacketType::UNKNOWN};
+  HciPacketizer hci_packetizer_;
+
+  /**
+   * Question : Why read in single chunk rather than multiple reads?
+   * Answer: Using multiple reads does not work with some BT USB dongles.
+   * Reading in single shot gives expected response.
+   * ACL max length is 2 bytes, so using 64K as the buffer length.
+   */
+  static constexpr size_t kMaxPacketLength = 64 * 1024;
+};
+
+}  // namespace android::hardware::bluetooth::hci
diff --git a/bluetooth/hci/hci_internals.h b/bluetooth/hci/hci_internals.h
new file mode 100644
index 0000000..71b6191
--- /dev/null
+++ b/bluetooth/hci/hci_internals.h
@@ -0,0 +1,55 @@
+/*
+ * 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 <cstdlib>
+
+namespace android::hardware::bluetooth::hci {
+
+// HCI UART transport packet types (Volume 4, Part A, 2)
+enum class PacketType : uint8_t {
+  UNKNOWN = 0,
+  COMMAND = 1,
+  ACL_DATA = 2,
+  SCO_DATA = 3,
+  EVENT = 4,
+  ISO_DATA = 5,
+};
+
+// 2 bytes for opcode, 1 byte for parameter length (Volume 4, Part E, 5.4.1)
+static constexpr size_t kCommandHeaderSize = 3;
+static constexpr size_t kCommandLengthOffset = 2;
+
+// 2 bytes for handle, 2 bytes for data length (Volume 4, Part E, 5.4.2)
+static constexpr size_t kAclHeaderSize = 4;
+static constexpr size_t kAclLengthOffset = 2;
+
+// 2 bytes for handle, 1 byte for data length (Volume 4, Part E, 5.4.3)
+static constexpr size_t kScoHeaderSize = 3;
+static constexpr size_t kScoLengthOffset = 2;
+
+// 1 byte for event code, 1 byte for parameter length (Volume 4, Part E, 5.4.4)
+static constexpr size_t kEventHeaderSize = 2;
+static constexpr size_t kEventLengthOffset = 1;
+
+// 2 bytes for handle, 2 bytes for data length (Volume 4, Part E, 5.4.5)
+static constexpr size_t kIsoHeaderSize = 4;
+static constexpr size_t kIsoLengthOffset = 2;
+
+static constexpr size_t kMaxHeaderSize = kAclHeaderSize;
+
+}  // namespace android::hardware::bluetooth::hci
diff --git a/bluetooth/hci/hci_packetizer.cc b/bluetooth/hci/hci_packetizer.cc
new file mode 100644
index 0000000..5b6c443
--- /dev/null
+++ b/bluetooth/hci/hci_packetizer.cc
@@ -0,0 +1,100 @@
+/*
+ * 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 "hci_packetizer.h"
+
+#define LOG_TAG "android.hardware.bluetooth.hci-packetizer"
+#include "log/log.h"
+
+namespace android::hardware::bluetooth::hci {
+
+namespace {
+
+const size_t header_size_for_type[] = {0,
+                                       kCommandHeaderSize,
+                                       kAclHeaderSize,
+                                       kScoHeaderSize,
+                                       kEventHeaderSize,
+                                       kIsoHeaderSize};
+const size_t packet_length_offset_for_type[] = {0,
+                                                kCommandLengthOffset,
+                                                kAclLengthOffset,
+                                                kScoLengthOffset,
+                                                kEventLengthOffset,
+                                                kIsoLengthOffset};
+
+size_t HciGetPacketLengthForType(PacketType type,
+                                 const std::vector<uint8_t>& header) {
+  size_t offset = packet_length_offset_for_type[static_cast<uint8_t>(type)];
+  if (type != PacketType::ACL_DATA && type != PacketType::ISO_DATA) {
+    return header[offset];
+  }
+  return (((header[offset + 1]) << 8) | header[offset]);
+}
+
+}  // namespace
+
+const std::vector<uint8_t>& HciPacketizer::GetPacket() const { return packet_; }
+
+bool HciPacketizer::OnDataReady(PacketType packet_type,
+                                const std::vector<uint8_t>& buffer,
+                                size_t offset) {
+  bool packet_completed = false;
+  size_t bytes_available = buffer.size() - offset;
+  switch (state_) {
+    case HCI_HEADER: {
+      size_t header_size =
+          header_size_for_type[static_cast<size_t>(packet_type)];
+      if (bytes_remaining_ == 0) {
+        bytes_remaining_ = header_size;
+        packet_.clear();
+      }
+      size_t bytes_to_copy = std::min(bytes_remaining_, bytes_available);
+      packet_.insert(packet_.end(), buffer.begin() + offset,
+                     buffer.begin() + offset + bytes_to_copy);
+      bytes_remaining_ -= bytes_to_copy;
+      bytes_available -= bytes_to_copy;
+      if (bytes_remaining_ == 0) {
+        bytes_remaining_ = HciGetPacketLengthForType(packet_type, packet_);
+        if (bytes_remaining_ > 0) {
+          state_ = HCI_PAYLOAD;
+          if (bytes_available > 0) {
+            packet_completed =
+                OnDataReady(packet_type, buffer, offset + bytes_to_copy);
+          }
+        } else {
+          packet_completed = true;
+        }
+      }
+      break;
+    }
+
+    case HCI_PAYLOAD: {
+      size_t bytes_to_copy = std::min(bytes_remaining_, bytes_available);
+      packet_.insert(packet_.end(), buffer.begin() + offset,
+                     buffer.begin() + offset + bytes_to_copy);
+      bytes_remaining_ -= bytes_to_copy;
+      if (bytes_remaining_ == 0) {
+        state_ = HCI_HEADER;
+        packet_completed = true;
+      }
+      break;
+    }
+  }
+  return packet_completed;
+}
+
+}  // namespace android::hardware::bluetooth::hci
diff --git a/bluetooth/hci/hci_packetizer.h b/bluetooth/hci/hci_packetizer.h
new file mode 100644
index 0000000..ba3e841
--- /dev/null
+++ b/bluetooth/hci/hci_packetizer.h
@@ -0,0 +1,41 @@
+/*
+ * 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 <functional>
+#include <memory>
+#include <vector>
+
+#include "hci_internals.h"
+
+namespace android::hardware::bluetooth::hci {
+
+class HciPacketizer {
+ public:
+  HciPacketizer() = default;
+  bool OnDataReady(PacketType packet_type, const std::vector<uint8_t>& data,
+                   size_t offset);
+  const std::vector<uint8_t>& GetPacket() const;
+
+ protected:
+  enum State { HCI_HEADER, HCI_PAYLOAD };
+  State state_{HCI_HEADER};
+  std::vector<uint8_t> packet_;
+  size_t bytes_remaining_{0};
+};
+
+}  // namespace android::hardware::bluetooth::hci
diff --git a/bluetooth/hci/test/h4_protocol_unittest.cc b/bluetooth/hci/test/h4_protocol_unittest.cc
new file mode 100644
index 0000000..d6f74fc
--- /dev/null
+++ b/bluetooth/hci/test/h4_protocol_unittest.cc
@@ -0,0 +1,441 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "bt_h4_unittest"
+
+#include "h4_protocol.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <log/log.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <cstdint>
+#include <cstring>
+#include <future>
+#include <vector>
+
+#include "async_fd_watcher.h"
+#include "log/log.h"
+
+using android::hardware::bluetooth::async::AsyncFdWatcher;
+using namespace android::hardware::bluetooth::hci;
+using ::testing::Eq;
+
+static char sample_data1[100] = "A point is that which has no part.";
+static char sample_data2[100] = "A line is breadthless length.";
+static char sample_data3[100] = "The ends of a line are points.";
+static char sample_data4[100] =
+    "A plane surface is a surface which lies evenly with the straight ...";
+static char acl_data[100] =
+    "A straight line is a line which lies evenly with the points on itself.";
+static char sco_data[100] =
+    "A surface is that which has length and breadth only.";
+static char event_data[100] = "The edges of a surface are lines.";
+static char iso_data[100] =
+    "A plane angle is the inclination to one another of two lines in a ...";
+
+MATCHER_P3(PacketMatches, header_, header_length, payload,
+           "Match header_length bytes of header and then the payload") {
+  size_t payload_length = strlen(payload);
+  if (header_length + payload_length != arg.size()) {
+    return false;
+  }
+
+  if (memcmp(header_, arg.data(), header_length) != 0) {
+    return false;
+  }
+
+  return memcmp(payload, arg.data() + header_length, payload_length) == 0;
+};
+
+ACTION_P(Notify, barrier) {
+  ALOGD("%s", __func__);
+  barrier->set_value();
+}
+
+class H4ProtocolTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    ALOGD("%s", __func__);
+
+    int sockfd[2];
+    socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd);
+    chip_uart_fd_ = sockfd[1];
+    stack_uart_fd_ = sockfd[0];
+    h4_hci_ = std::make_shared<H4Protocol>(
+        stack_uart_fd_, cmd_cb_.AsStdFunction(), acl_cb_.AsStdFunction(),
+        sco_cb_.AsStdFunction(), event_cb_.AsStdFunction(),
+        iso_cb_.AsStdFunction(), disconnect_cb_.AsStdFunction());
+  }
+
+  void TearDown() override {
+    close(stack_uart_fd_);
+    close(chip_uart_fd_);
+  }
+
+  virtual void CallDataReady() { h4_hci_->OnDataReady(); }
+
+  void SendAndReadUartOutbound(PacketType type, char* data) {
+    ALOGD("%s sending", __func__);
+    int data_length = strlen(data);
+    h4_hci_->Send(type, (uint8_t*)data, data_length);
+
+    int uart_length = data_length + 1;  // + 1 for data type code
+    int i;
+
+    ALOGD("%s reading", __func__);
+    for (i = 0; i < uart_length; i++) {
+      fd_set read_fds;
+      FD_ZERO(&read_fds);
+      FD_SET(chip_uart_fd_, &read_fds);
+      TEMP_FAILURE_RETRY(
+          select(chip_uart_fd_ + 1, &read_fds, nullptr, nullptr, nullptr));
+
+      char byte;
+      TEMP_FAILURE_RETRY(read(chip_uart_fd_, &byte, 1));
+
+      EXPECT_EQ(i == 0 ? static_cast<uint8_t>(type) : data[i - 1], byte);
+    }
+
+    EXPECT_EQ(i, uart_length);
+  }
+
+  void ExpectInboundAclData(char* payload, std::promise<void>* promise) {
+    // h4 type[1] + handle[2] + size[2]
+    header_[0] = static_cast<uint8_t>(PacketType::ACL_DATA);
+    header_[1] = 19;
+    header_[2] = 92;
+    int length = strlen(payload);
+    header_[3] = length & 0xFF;
+    header_[4] = (length >> 8) & 0xFF;
+    ALOGD("(%d bytes) %s", length, payload);
+
+    EXPECT_CALL(acl_cb_,
+                Call(PacketMatches(header_ + 1, kAclHeaderSize, payload)))
+        .WillOnce(Notify(promise));
+  }
+
+  void WaitForTimeout(size_t timeout_ms, std::promise<void>* promise) {
+    auto future = promise->get_future();
+    auto status = future.wait_for(std::chrono::milliseconds(timeout_ms));
+    EXPECT_EQ(status, std::future_status::ready);
+  }
+
+  void WriteInboundAclData(char* payload) {
+    // Use the header_ computed in ExpectInboundAclData
+    TEMP_FAILURE_RETRY(write(chip_uart_fd_, header_, kAclHeaderSize + 1));
+    TEMP_FAILURE_RETRY(write(chip_uart_fd_, payload, strlen(payload)));
+  }
+
+  void ExpectInboundScoData(char* payload, std::promise<void>* promise) {
+    // h4 type[1] + handle[2] + size[1]
+    header_[0] = static_cast<uint8_t>(PacketType::SCO_DATA);
+    header_[1] = 20;
+    header_[2] = 17;
+    header_[3] = strlen(payload) & 0xFF;
+    EXPECT_CALL(sco_cb_,
+                Call(PacketMatches(header_ + 1, kScoHeaderSize, payload)))
+        .WillOnce(Notify(promise));
+  }
+
+  void WriteInboundScoData(char* payload) {
+    // Use the header_ computed in ExpectInboundScoData
+    ALOGD("%s writing", __func__);
+    TEMP_FAILURE_RETRY(write(chip_uart_fd_, header_, kScoHeaderSize + 1));
+    TEMP_FAILURE_RETRY(write(chip_uart_fd_, payload, strlen(payload)));
+  }
+
+  void ExpectInboundEvent(char* payload, std::promise<void>* promise) {
+    // h4 type[1] + event_code[1] + size[1]
+    header_[0] = static_cast<uint8_t>(PacketType::EVENT);
+    header_[1] = 9;
+    header_[2] = strlen(payload) & 0xFF;
+    EXPECT_CALL(event_cb_,
+                Call(PacketMatches(header_ + 1, kEventHeaderSize, payload)))
+        .WillOnce(Notify(promise));
+  }
+
+  void WriteInboundEvent(char* payload) {
+    // Use the header_ computed in ExpectInboundEvent
+    char preamble[3] = {static_cast<uint8_t>(PacketType::EVENT), 9, 0};
+    preamble[2] = strlen(payload) & 0xFF;
+    ALOGD("%s writing", __func__);
+    TEMP_FAILURE_RETRY(write(chip_uart_fd_, header_, kEventHeaderSize + 1));
+    TEMP_FAILURE_RETRY(write(chip_uart_fd_, payload, strlen(payload)));
+  }
+
+  void ExpectInboundIsoData(char* payload, std::promise<void>* promise) {
+    // h4 type[1] + handle[2] + size[1]
+    header_[0] = static_cast<uint8_t>(PacketType::ISO_DATA);
+    header_[1] = 19;
+    header_[2] = 92;
+    int length = strlen(payload);
+    header_[3] = length & 0xFF;
+    header_[4] = (length >> 8) & 0x3F;
+
+    EXPECT_CALL(iso_cb_,
+                Call(PacketMatches(header_ + 1, kIsoHeaderSize, payload)))
+        .WillOnce(Notify(promise));
+  }
+
+  void WriteInboundIsoData(char* payload) {
+    // Use the header_ computed in ExpectInboundIsoData
+    ALOGD("%s writing", __func__);
+    TEMP_FAILURE_RETRY(write(chip_uart_fd_, header_, kIsoHeaderSize + 1));
+    TEMP_FAILURE_RETRY(write(chip_uart_fd_, payload, strlen(payload)));
+  }
+
+  void WriteAndExpectManyInboundAclDataPackets(char* payload) {
+    size_t kNumPackets = 20;
+    // h4 type[1] + handle[2] + size[2]
+    char preamble[5] = {static_cast<uint8_t>(PacketType::ACL_DATA), 19, 92, 0,
+                        0};
+    int length = strlen(payload);
+    preamble[3] = length & 0xFF;
+    preamble[4] = (length >> 8) & 0xFF;
+
+    EXPECT_CALL(acl_cb_, Call(PacketMatches(preamble + 1, sizeof(preamble) - 1,
+                                            payload)))
+        .Times(kNumPackets);
+
+    for (size_t i = 0; i < kNumPackets; i++) {
+      TEMP_FAILURE_RETRY(write(chip_uart_fd_, preamble, sizeof(preamble)));
+      TEMP_FAILURE_RETRY(write(chip_uart_fd_, payload, strlen(payload)));
+    }
+
+    CallDataReady();
+  }
+
+  testing::MockFunction<void(const std::vector<uint8_t>&)> cmd_cb_;
+  testing::MockFunction<void(const std::vector<uint8_t>&)> event_cb_;
+  testing::MockFunction<void(const std::vector<uint8_t>&)> acl_cb_;
+  testing::MockFunction<void(const std::vector<uint8_t>&)> sco_cb_;
+  testing::MockFunction<void(const std::vector<uint8_t>&)> iso_cb_;
+  testing::MockFunction<void(void)> disconnect_cb_;
+  std::shared_ptr<H4Protocol> h4_hci_;
+  int chip_uart_fd_;
+  int stack_uart_fd_;
+
+  char header_[5];
+};
+
+// Test sending data sends correct data onto the UART
+TEST_F(H4ProtocolTest, TestSends) {
+  SendAndReadUartOutbound(PacketType::COMMAND, sample_data1);
+  SendAndReadUartOutbound(PacketType::ACL_DATA, sample_data2);
+  SendAndReadUartOutbound(PacketType::SCO_DATA, sample_data3);
+  SendAndReadUartOutbound(PacketType::ISO_DATA, sample_data4);
+}
+
+// Ensure we properly parse data coming from the UART
+TEST_F(H4ProtocolTest, TestReads) {
+  std::promise<void> acl_promise;
+  std::promise<void> sco_promise;
+  std::promise<void> event_promise;
+  std::promise<void> iso_promise;
+
+  ExpectInboundAclData(acl_data, &acl_promise);
+  WriteInboundAclData(acl_data);
+  CallDataReady();
+  ExpectInboundScoData(sco_data, &sco_promise);
+  WriteInboundScoData(sco_data);
+  CallDataReady();
+  ExpectInboundEvent(event_data, &event_promise);
+  WriteInboundEvent(event_data);
+  CallDataReady();
+  ExpectInboundIsoData(iso_data, &iso_promise);
+  WriteInboundIsoData(iso_data);
+  CallDataReady();
+
+  WaitForTimeout(100, &acl_promise);
+  WaitForTimeout(100, &sco_promise);
+  WaitForTimeout(100, &event_promise);
+  WaitForTimeout(100, &iso_promise);
+}
+
+TEST_F(H4ProtocolTest, TestMultiplePackets) {
+  WriteAndExpectManyInboundAclDataPackets(sco_data);
+}
+
+TEST_F(H4ProtocolTest, TestDisconnect) {
+  EXPECT_CALL(disconnect_cb_, Call());
+  close(chip_uart_fd_);
+  CallDataReady();
+}
+
+TEST_F(H4ProtocolTest, TestPartialWrites) {
+  size_t payload_len = strlen(acl_data);
+  const size_t kNumIntervals = payload_len + 1;
+  // h4 type[1] + handle[2] + size[2]
+  header_[0] = static_cast<uint8_t>(PacketType::ACL_DATA);
+  header_[1] = 19;
+  header_[2] = 92;
+  header_[3] = payload_len & 0xFF;
+  header_[4] = (payload_len >> 8) & 0xFF;
+
+  EXPECT_CALL(acl_cb_,
+              Call(PacketMatches(header_ + 1, sizeof(header_) - 1, acl_data)))
+      .Times(kNumIntervals);
+
+  for (size_t interval = 1; interval < kNumIntervals + 1; interval++) {
+    // Use the header_ data that expect already set up.
+    if (interval < kAclHeaderSize) {
+      TEMP_FAILURE_RETRY(write(chip_uart_fd_, header_, interval));
+      CallDataReady();
+      TEMP_FAILURE_RETRY(write(chip_uart_fd_, header_ + interval,
+                               kAclHeaderSize + 1 - interval));
+      CallDataReady();
+    } else {
+      TEMP_FAILURE_RETRY(write(chip_uart_fd_, header_, kAclHeaderSize + 1));
+      CallDataReady();
+    }
+
+    for (size_t bytes = 0; bytes + interval <= payload_len; bytes += interval) {
+      TEMP_FAILURE_RETRY(write(chip_uart_fd_, acl_data + bytes, interval));
+      CallDataReady();
+    }
+    size_t extra_bytes = payload_len % interval;
+    if (extra_bytes) {
+      TEMP_FAILURE_RETRY(write(
+          chip_uart_fd_, acl_data + payload_len - extra_bytes, extra_bytes));
+      CallDataReady();
+    }
+  }
+}
+
+class H4ProtocolAsyncTest : public H4ProtocolTest {
+ protected:
+  void SetUp() override {
+    H4ProtocolTest::SetUp();
+    fd_watcher_.WatchFdForNonBlockingReads(
+        stack_uart_fd_, [this](int) { h4_hci_->OnDataReady(); });
+  }
+
+  void TearDown() override { fd_watcher_.StopWatchingFileDescriptors(); }
+
+  void CallDataReady() override {
+    // The Async test can't call data ready.
+    FAIL();
+  }
+
+  void SendAndReadUartOutbound(PacketType type, char* data) {
+    ALOGD("%s sending", __func__);
+    int data_length = strlen(data);
+    h4_hci_->Send(type, (uint8_t*)data, data_length);
+
+    int uart_length = data_length + 1;  // + 1 for data type code
+    int i;
+
+    ALOGD("%s reading", __func__);
+    for (i = 0; i < uart_length; i++) {
+      fd_set read_fds;
+      FD_ZERO(&read_fds);
+      FD_SET(chip_uart_fd_, &read_fds);
+      TEMP_FAILURE_RETRY(
+          select(chip_uart_fd_ + 1, &read_fds, nullptr, nullptr, nullptr));
+
+      char byte;
+      TEMP_FAILURE_RETRY(read(chip_uart_fd_, &byte, 1));
+
+      EXPECT_EQ(i == 0 ? static_cast<uint8_t>(type) : data[i - 1], byte);
+    }
+
+    EXPECT_EQ(i, uart_length);
+  }
+
+  void WriteAndExpectInboundAclData(char* payload) {
+    std::promise<void> promise;
+    ExpectInboundAclData(payload, &promise);
+    WriteInboundAclData(payload);
+    WaitForTimeout(100, &promise);
+  }
+
+  void WriteAndExpectInboundScoData(char* payload) {
+    std::promise<void> promise;
+    ExpectInboundScoData(payload, &promise);
+    WriteInboundScoData(payload);
+    WaitForTimeout(100, &promise);
+  }
+
+  void WriteAndExpectInboundEvent(char* payload) {
+    std::promise<void> promise;
+    ExpectInboundEvent(payload, &promise);
+    WriteInboundEvent(payload);
+    WaitForTimeout(100, &promise);
+  }
+
+  void WriteAndExpectInboundIsoData(char* payload) {
+    std::promise<void> promise;
+    ExpectInboundIsoData(payload, &promise);
+    WriteInboundIsoData(payload);
+    WaitForTimeout(100, &promise);
+  }
+
+  void WriteAndExpectManyInboundAclDataPackets(char* payload) {
+    const size_t kNumPackets = 20;
+    // h4 type[1] + handle[2] + size[2]
+    char preamble[5] = {static_cast<uint8_t>(PacketType::ACL_DATA), 19, 92, 0,
+                        0};
+    int length = strlen(payload);
+    preamble[3] = length & 0xFF;
+    preamble[4] = (length >> 8) & 0xFF;
+
+    EXPECT_CALL(acl_cb_, Call(PacketMatches(preamble + 1, sizeof(preamble) - 1,
+                                            payload)))
+        .Times(kNumPackets);
+
+    for (size_t i = 0; i < kNumPackets; i++) {
+      TEMP_FAILURE_RETRY(write(chip_uart_fd_, preamble, sizeof(preamble)));
+      TEMP_FAILURE_RETRY(write(chip_uart_fd_, payload, strlen(payload)));
+    }
+
+    WriteAndExpectInboundEvent(event_data);
+  }
+
+  AsyncFdWatcher fd_watcher_;
+};
+
+// Test sending data sends correct data onto the UART
+TEST_F(H4ProtocolAsyncTest, TestSends) {
+  SendAndReadUartOutbound(PacketType::COMMAND, sample_data1);
+  SendAndReadUartOutbound(PacketType::ACL_DATA, sample_data2);
+  SendAndReadUartOutbound(PacketType::SCO_DATA, sample_data3);
+  SendAndReadUartOutbound(PacketType::ISO_DATA, sample_data4);
+}
+
+// Ensure we properly parse data coming from the UART
+TEST_F(H4ProtocolAsyncTest, TestReads) {
+  WriteAndExpectInboundAclData(acl_data);
+  WriteAndExpectInboundScoData(sco_data);
+  WriteAndExpectInboundEvent(event_data);
+  WriteAndExpectInboundIsoData(iso_data);
+}
+
+TEST_F(H4ProtocolAsyncTest, TestMultiplePackets) {
+  WriteAndExpectManyInboundAclDataPackets(sco_data);
+}
+
+TEST_F(H4ProtocolAsyncTest, TestDisconnect) {
+  std::promise<void> promise;
+  EXPECT_CALL(disconnect_cb_, Call()).WillOnce(Notify(&promise));
+  close(chip_uart_fd_);
+
+  // Fail if it takes longer than 100 ms.
+  WaitForTimeout(100, &promise);
+}
diff --git a/boot/aidl/vts/functional/VtsHalBootAidlTargetTest.cpp b/boot/aidl/vts/functional/VtsHalBootAidlTargetTest.cpp
index ab3c789..93c8376 100644
--- a/boot/aidl/vts/functional/VtsHalBootAidlTargetTest.cpp
+++ b/boot/aidl/vts/functional/VtsHalBootAidlTargetTest.cpp
@@ -33,7 +33,7 @@
 using std::unordered_set;
 
 // The main test class for the Boot HIDL HAL.
-class BootHidlTest : public ::testing::TestWithParam<std::string> {
+class BootAidlTest : public ::testing::TestWithParam<std::string> {
   public:
     virtual void SetUp() override {
         const auto instance_name = GetParam();
@@ -48,14 +48,14 @@
 };
 
 // validity check Boot::getNumberSlots().
-TEST_P(BootHidlTest, GetNumberSlots) {
+TEST_P(BootAidlTest, GetNumberSlots) {
     int32_t slots{};
     boot->getNumberSlots(&slots);
     ASSERT_LE(2, slots);
 }
 
 // validity check Boot::getCurrentSlot().
-TEST_P(BootHidlTest, GetCurrentSlot) {
+TEST_P(BootAidlTest, GetCurrentSlot) {
     int curSlot = -1;
     boot->getCurrentSlot(&curSlot);
     int slots = 0;
@@ -64,7 +64,7 @@
 }
 
 // validity check Boot::markBootSuccessful().
-TEST_P(BootHidlTest, MarkBootSuccessful) {
+TEST_P(BootAidlTest, MarkBootSuccessful) {
     const auto result = boot->markBootSuccessful();
     ASSERT_TRUE(result.isOk());
     int curSlot = 0;
@@ -74,7 +74,7 @@
     ASSERT_TRUE(ret);
 }
 
-TEST_P(BootHidlTest, SetActiveBootSlot) {
+TEST_P(BootAidlTest, SetActiveBootSlot) {
     int curSlot = -1;
     boot->getCurrentSlot(&curSlot);
     ASSERT_GE(curSlot, 0);
@@ -107,7 +107,7 @@
     }
 }
 
-TEST_P(BootHidlTest, SetSlotAsUnbootable) {
+TEST_P(BootAidlTest, SetSlotAsUnbootable) {
     int curSlot = -1;
     boot->getCurrentSlot(&curSlot);
     ASSERT_GE(curSlot, 0);
@@ -139,7 +139,7 @@
 }
 
 // validity check Boot::isSlotBootable() on good and bad inputs.
-TEST_P(BootHidlTest, IsSlotBootable) {
+TEST_P(BootAidlTest, IsSlotBootable) {
     for (int s = 0; s < 2; s++) {
         bool bootable = false;
         const auto res = boot->isSlotBootable(s, &bootable);
@@ -153,7 +153,7 @@
 }
 
 // validity check Boot::isSlotMarkedSuccessful() on good and bad inputs.
-TEST_P(BootHidlTest, IsSlotMarkedSuccessful) {
+TEST_P(BootAidlTest, IsSlotMarkedSuccessful) {
     for (int32_t s = 0; s < 2; s++) {
         bool isSuccess = false;
         const auto res = boot->isSlotMarkedSuccessful(s, &isSuccess);
@@ -166,7 +166,7 @@
 }
 
 // validity check Boot::getSuffix() on good and bad inputs.
-TEST_P(BootHidlTest, GetSuffix) {
+TEST_P(BootAidlTest, GetSuffix) {
     string suffixStr;
     unordered_set<string> suffixes;
     int numSlots = 0;
@@ -190,5 +190,6 @@
 }
 
 INSTANTIATE_TEST_SUITE_P(
-        PerInstance, BootHidlTest,
+        PerInstance, BootAidlTest,
         testing::ValuesIn(android::getAidlHalInstanceNames(IBootControl::descriptor)));
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BootAidlTest);
diff --git a/camera/README.md b/camera/README.md
index 8ce3352..25badfd 100644
--- a/camera/README.md
+++ b/camera/README.md
@@ -10,3 +10,8 @@
 
 More complete information about the Android camera HAL and subsystem can be found at
 [source.android.com](http://source.android.com/devices/camera/index.html).
+
+### AIDL Camera HAL Interfaces
+
+The AIDL Camera HAL interfaces can be found in the respective <interface>/aidl
+directories.
diff --git a/camera/device/aidl/Android.bp b/camera/device/aidl/Android.bp
index 365a5ff..c184677 100644
--- a/camera/device/aidl/Android.bp
+++ b/camera/device/aidl/Android.bp
@@ -15,9 +15,9 @@
     imports: [
         "android.hardware.common-V2",
         "android.hardware.common.fmq-V1",
-        "android.hardware.camera.common",
-        "android.hardware.camera.metadata",
-        "android.hardware.graphics.common",
+        "android.hardware.camera.common-V1",
+        "android.hardware.camera.metadata-V2",
+        "android.hardware.graphics.common-V4",
     ],
     backend: {
         cpp: {
@@ -36,7 +36,7 @@
                 "android.hardware.common.fmq-V1",
                 "android.hardware.camera.common-V1",
                 "android.hardware.camera.metadata-V1",
-                "android.hardware.graphics.common-V3",
+                "android.hardware.graphics.common-V4",
             ],
         },
     ],
diff --git a/camera/device/aidl/aidl_api/android.hardware.camera.device/current/android/hardware/camera/device/Stream.aidl b/camera/device/aidl/aidl_api/android.hardware.camera.device/current/android/hardware/camera/device/Stream.aidl
index d2f295a..5057663 100644
--- a/camera/device/aidl/aidl_api/android.hardware.camera.device/current/android/hardware/camera/device/Stream.aidl
+++ b/camera/device/aidl/aidl_api/android.hardware.camera.device/current/android/hardware/camera/device/Stream.aidl
@@ -48,4 +48,5 @@
   android.hardware.camera.metadata.SensorPixelMode[] sensorPixelModesUsed;
   android.hardware.camera.metadata.RequestAvailableDynamicRangeProfilesMap dynamicRangeProfile;
   android.hardware.camera.metadata.ScalerAvailableStreamUseCases useCase;
+  int colorSpace;
 }
diff --git a/camera/device/aidl/android/hardware/camera/device/Stream.aidl b/camera/device/aidl/android/hardware/camera/device/Stream.aidl
index e35e4ff..457b1bc 100644
--- a/camera/device/aidl/android/hardware/camera/device/Stream.aidl
+++ b/camera/device/aidl/android/hardware/camera/device/Stream.aidl
@@ -98,14 +98,18 @@
      *
      * For most formats, dataSpace defines the color space of the image data.
      * In addition, for some formats, dataSpace indicates whether image- or
-     * depth-based data is requested. See
-     * android.hardware.graphics.common@1.0::types for details of formats and
-     * valid dataSpace values for each format.
+     * depth-based data is requested. For others, it merely describes an encoding
+     * scheme. See android.hardware.graphics.common@1.0::types for details of formats
+     * and valid dataSpace values for each format.
      *
      * The HAL must use this dataSpace to configure the stream to the correct
      * colorspace, or to select between color and depth outputs if
      * supported. The dataspace values are set using the V0 dataspace
      * definitions.
+     *
+     * The color space implied by dataSpace should be overridden by colorSpace if
+     * the device supports the REQUEST_AVAILABLE_CAPABILITIES_COLOR_SPACE_PROFILES
+     * capability.
      */
     android.hardware.graphics.common.Dataspace dataSpace;
 
@@ -222,4 +226,19 @@
      * DEFAULT.
      */
     android.hardware.camera.metadata.ScalerAvailableStreamUseCases useCase;
+
+    /**
+     * The color space of the stream.
+     *
+     * A client may not specify a color space. In this case, the value will be
+     * ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED, and the color space
+     * implied by dataSpace should be used instead.
+     *
+     * When specified, this field is the ultimate authority over the color space of the stream,
+     * regardless of dataSpace. The purpose of this field is to support specifying wide gamut
+     * color spaces for dataSpace values such as JFIF and HEIF.
+     *
+     * Possible values are the ordinals of the ColorSpace.Named enum in the public-facing API.
+     */
+    int colorSpace;
 }
diff --git a/camera/device/aidl/android/hardware/camera/device/StreamBuffer.aidl b/camera/device/aidl/android/hardware/camera/device/StreamBuffer.aidl
index e487494..29fec68 100644
--- a/camera/device/aidl/android/hardware/camera/device/StreamBuffer.aidl
+++ b/camera/device/aidl/android/hardware/camera/device/StreamBuffer.aidl
@@ -33,8 +33,8 @@
 parcelable StreamBuffer {
     /**
      * The ID of the stream this buffer is associated with. -1 indicates an
-     * invalid (empty) StreamBuffer, in which case buffer must also point to
-     * null and bufferId must be 0.
+     * invalid (empty) StreamBuffer, in which case buffer must be empty
+     * and bufferId must be 0.
      */
     int streamId;
 
@@ -48,7 +48,7 @@
      * corresponding stream is removed from stream configuration or until camera
      * device session is closed. After the first time a buffer is introduced to
      * HAL, in the future camera service must refer to the same buffer using
-     * only bufferId, and keep the buffer handle null.
+     * only bufferId, and keep the buffer handle empty.
      */
     long bufferId;
 
@@ -59,10 +59,10 @@
      * is not seen by the HAL before, this buffer handle is guaranteed to be a
      * valid handle to a graphics buffer, with dimensions and format matching
      * that of the stream. If the bufferId has been sent to the HAL before, this
-     * buffer handle must be null and HAL must look up the actual buffer handle
+     * buffer handle must be empty and HAL must look up the actual buffer handle
      * to use from its own bufferId to buffer handle map.
      *
-     * For StreamBuffers returned in a CaptureResult, this must be null, since
+     * For StreamBuffers returned in a CaptureResult, this must be empty, since
      * the handle to the buffer is already known to the client (since the client
      * sent it in the matching CaptureRequest), and the handle can be identified
      * by the combination of frame number and stream ID.
@@ -81,11 +81,11 @@
      * The acquire sync fence for this buffer. The HAL must wait on this fence
      * fd before attempting to read from or write to this buffer.
      *
-     * In a buffer included in a CaptureRequest, the client may set this to null
+     * In a buffer included in a CaptureRequest, the client may leave this empty
      * to indicate that no waiting is necessary for this buffer.
      *
      * When the HAL returns an input or output buffer to the framework with
-     * processCaptureResult(), the acquireFence must be set to null. If the HAL
+     * processCaptureResult(), the acquireFence must be empty. If the HAL
      * never waits on the acquireFence due to an error in filling or reading a
      * buffer, when calling processCaptureResult() the HAL must set the
      * releaseFence of the buffer to be the acquireFence passed to it by the
@@ -97,17 +97,17 @@
     /**
      * The release sync fence for this buffer. The HAL must set this to a valid
      * fence fd when returning the input buffer or output buffers to the client
-     * in a CaptureResult, or set it to null to indicate that no waiting is
+     * in a CaptureResult, or leave it empty to indicate that no waiting is
      * required for this buffer.
      *
-     * The client must set this to be null for all buffers included in a
+     * The client must leave this empty for all buffers included in a
      * processCaptureRequest call.
      *
      * After signaling the releaseFence for this buffer, the HAL
      * must not make any further attempts to access this buffer as the
      * ownership has been fully transferred back to the client.
      *
-     * If this is null, then the ownership of this buffer is transferred back
+     * If this is empty, then the ownership of the buffer is transferred back
      * immediately upon the call of processCaptureResult.
      */
     NativeHandle releaseFence;
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 9bb55d2..ecbfc93 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
@@ -92,6 +92,12 @@
   ANDROID_CONTROL_ZOOM_RATIO_RANGE = 65582,
   ANDROID_CONTROL_ZOOM_RATIO = 65583,
   ANDROID_CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS_MAXIMUM_RESOLUTION = 65584,
+  ANDROID_CONTROL_SETTINGS_OVERRIDE = 65588,
+  ANDROID_CONTROL_AVAILABLE_SETTINGS_OVERRIDES = 65589,
+  ANDROID_CONTROL_SETTINGS_OVERRIDING_FRAME_NUMBER = 65590,
+  ANDROID_CONTROL_AUTOFRAMING = 65591,
+  ANDROID_CONTROL_AUTOFRAMING_AVAILABLE = 65592,
+  ANDROID_CONTROL_AUTOFRAMING_STATE = 65593,
   ANDROID_DEMOSAIC_MODE = 131072,
   ANDROID_EDGE_MODE = 196608,
   ANDROID_EDGE_STRENGTH = 196609,
@@ -171,6 +177,7 @@
   ANDROID_REQUEST_CHARACTERISTIC_KEYS_NEEDING_PERMISSION = 786450,
   ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP = 786451,
   ANDROID_REQUEST_RECOMMENDED_TEN_BIT_DYNAMIC_RANGE_PROFILE = 786452,
+  ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP = 786453,
   ANDROID_SCALER_CROP_REGION = 851968,
   ANDROID_SCALER_AVAILABLE_FORMATS = 851969,
   ANDROID_SCALER_AVAILABLE_JPEG_MIN_DURATIONS = 851970,
diff --git a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ControlAutoframing.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ControlAutoframing.aidl
new file mode 100644
index 0000000..eeb7bcd
--- /dev/null
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ControlAutoframing.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.
+ *//*
+ * 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 ControlAutoframing {
+  ANDROID_CONTROL_AUTOFRAMING_OFF = 0,
+  ANDROID_CONTROL_AUTOFRAMING_ON = 1,
+  ANDROID_CONTROL_AUTOFRAMING_AUTO = 2,
+}
diff --git a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ControlAutoframingAvailable.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ControlAutoframingAvailable.aidl
new file mode 100644
index 0000000..b075c32
--- /dev/null
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ControlAutoframingAvailable.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 ControlAutoframingAvailable {
+  ANDROID_CONTROL_AUTOFRAMING_AVAILABLE_FALSE = 0,
+  ANDROID_CONTROL_AUTOFRAMING_AVAILABLE_TRUE = 1,
+}
diff --git a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ControlAutoframingState.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ControlAutoframingState.aidl
new file mode 100644
index 0000000..60df0d4
--- /dev/null
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ControlAutoframingState.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.
+ *//*
+ * 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 ControlAutoframingState {
+  ANDROID_CONTROL_AUTOFRAMING_STATE_INACTIVE = 0,
+  ANDROID_CONTROL_AUTOFRAMING_STATE_FRAMING = 1,
+  ANDROID_CONTROL_AUTOFRAMING_STATE_CONVERGED = 2,
+}
diff --git a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ControlSettingsOverride.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ControlSettingsOverride.aidl
new file mode 100644
index 0000000..ed5d46f
--- /dev/null
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ControlSettingsOverride.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.
+ *//*
+ * 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 ControlSettingsOverride {
+  ANDROID_CONTROL_SETTINGS_OVERRIDE_OFF = 0,
+  ANDROID_CONTROL_SETTINGS_OVERRIDE_ZOOM = 1,
+  ANDROID_CONTROL_SETTINGS_OVERRIDE_VENDOR_START = 16384,
+}
diff --git a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/RequestAvailableCapabilities.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/RequestAvailableCapabilities.aidl
index 8dc2aa2..37b1dec 100644
--- a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/RequestAvailableCapabilities.aidl
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/RequestAvailableCapabilities.aidl
@@ -58,4 +58,5 @@
   ANDROID_REQUEST_AVAILABLE_CAPABILITIES_REMOSAIC_REPROCESSING = 17,
   ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT = 18,
   ANDROID_REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE = 19,
+  ANDROID_REQUEST_AVAILABLE_CAPABILITIES_COLOR_SPACE_PROFILES = 20,
 }
diff --git a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/RequestAvailableColorSpaceProfilesMap.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/RequestAvailableColorSpaceProfilesMap.aidl
new file mode 100644
index 0000000..0d59ab0
--- /dev/null
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/RequestAvailableColorSpaceProfilesMap.aidl
@@ -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.
+ *//*
+ * 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="long") @VintfStability
+enum RequestAvailableColorSpaceProfilesMap {
+  ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED = -1,
+  ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_SRGB = 0,
+  ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_LINEAR_SRGB = 1,
+  ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_EXTENDED_SRGB = 2,
+  ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_LINEAR_EXTENDED_SRGB = 3,
+  ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_BT709 = 4,
+  ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_BT2020 = 5,
+  ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_DCI_P3 = 6,
+  ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_DISPLAY_P3 = 7,
+  ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_NTSC_1953 = 8,
+  ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_SMPTE_C = 9,
+  ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_ADOBE_RGB = 10,
+  ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_PRO_PHOTO_RGB = 11,
+  ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_ACES = 12,
+  ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_ACESCG = 13,
+  ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_CIE_XYZ = 14,
+  ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_CIE_LAB = 15,
+}
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl
index 48b1ee4..2e9bde9 100644
--- a/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl
@@ -450,6 +450,46 @@
      */
     ANDROID_CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS_MAXIMUM_RESOLUTION,
     /**
+     * android.control.settingsOverride [dynamic, enum, public]
+     *
+     * <p>The desired CaptureRequest settings override with which certain keys are
+     * applied earlier so that they can take effect sooner.</p>
+     */
+    ANDROID_CONTROL_SETTINGS_OVERRIDE = 65588,
+    /**
+     * android.control.availableSettingsOverrides [static, int32[], public]
+     *
+     * <p>List of available settings overrides supported by the camera device that can
+     * be used to speed up certain controls.</p>
+     */
+    ANDROID_CONTROL_AVAILABLE_SETTINGS_OVERRIDES,
+    /**
+     * android.control.settingsOverridingFrameNumber [dynamic, int32, system]
+     *
+     * <p>The frame number of the newer request overriding this capture.</p>
+     */
+    ANDROID_CONTROL_SETTINGS_OVERRIDING_FRAME_NUMBER,
+    /**
+     * android.control.autoframing [dynamic, enum, public]
+     *
+     * <p>Automatic crop, pan and zoom to keep objects in the center of the frame.</p>
+     */
+    ANDROID_CONTROL_AUTOFRAMING,
+    /**
+     * android.control.autoframingAvailable [static, enum, public]
+     *
+     * <p>Whether the camera device supports ANDROID_CONTROL_AUTOFRAMING.</p>
+     *
+     * @see ANDROID_CONTROL_AUTOFRAMING
+     */
+    ANDROID_CONTROL_AUTOFRAMING_AVAILABLE,
+    /**
+     * android.control.autoframingState [dynamic, enum, public]
+     *
+     * <p>Current state of auto-framing.</p>
+     */
+    ANDROID_CONTROL_AUTOFRAMING_STATE,
+    /**
      * android.demosaic.mode [controls, enum, system]
      *
      * <p>Controls the quality of the demosaicing
@@ -1030,6 +1070,12 @@
      */
     ANDROID_REQUEST_RECOMMENDED_TEN_BIT_DYNAMIC_RANGE_PROFILE,
     /**
+     * android.request.availableColorSpaceProfilesMap [static, enum[], ndk_public]
+     *
+     * <p>A list of all possible color space profiles supported by a camera device.</p>
+     */
+    ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP,
+    /**
      * android.scaler.cropRegion [dynamic, int32[], public]
      *
      * <p>The desired region of the sensor to read out for this capture.</p>
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/ControlAutoframing.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/ControlAutoframing.aidl
new file mode 100644
index 0000000..0fef373
--- /dev/null
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/ControlAutoframing.aidl
@@ -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.
+ */
+
+/*
+ * Autogenerated from camera metadata definitions in
+ * /system/media/camera/docs/metadata_definitions.xml
+ * *** DO NOT EDIT BY HAND ***
+ */
+
+package android.hardware.camera.metadata;
+
+/**
+ * android.control.autoframing enumeration values
+ * @see ANDROID_CONTROL_AUTOFRAMING
+ */
+@VintfStability
+@Backing(type="int")
+enum ControlAutoframing {
+    ANDROID_CONTROL_AUTOFRAMING_OFF,
+    ANDROID_CONTROL_AUTOFRAMING_ON,
+    ANDROID_CONTROL_AUTOFRAMING_AUTO,
+}
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/ControlAutoframingAvailable.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/ControlAutoframingAvailable.aidl
new file mode 100644
index 0000000..da0d348
--- /dev/null
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/ControlAutoframingAvailable.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.control.autoframingAvailable enumeration values
+ * @see ANDROID_CONTROL_AUTOFRAMING_AVAILABLE
+ */
+@VintfStability
+@Backing(type="int")
+enum ControlAutoframingAvailable {
+    ANDROID_CONTROL_AUTOFRAMING_AVAILABLE_FALSE,
+    ANDROID_CONTROL_AUTOFRAMING_AVAILABLE_TRUE,
+}
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/ControlAutoframingState.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/ControlAutoframingState.aidl
new file mode 100644
index 0000000..13183a5
--- /dev/null
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/ControlAutoframingState.aidl
@@ -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.
+ */
+
+/*
+ * Autogenerated from camera metadata definitions in
+ * /system/media/camera/docs/metadata_definitions.xml
+ * *** DO NOT EDIT BY HAND ***
+ */
+
+package android.hardware.camera.metadata;
+
+/**
+ * android.control.autoframingState enumeration values
+ * @see ANDROID_CONTROL_AUTOFRAMING_STATE
+ */
+@VintfStability
+@Backing(type="int")
+enum ControlAutoframingState {
+    ANDROID_CONTROL_AUTOFRAMING_STATE_INACTIVE,
+    ANDROID_CONTROL_AUTOFRAMING_STATE_FRAMING,
+    ANDROID_CONTROL_AUTOFRAMING_STATE_CONVERGED,
+}
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/ControlSettingsOverride.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/ControlSettingsOverride.aidl
new file mode 100644
index 0000000..d97f7c8
--- /dev/null
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/ControlSettingsOverride.aidl
@@ -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.
+ */
+
+/*
+ * Autogenerated from camera metadata definitions in
+ * /system/media/camera/docs/metadata_definitions.xml
+ * *** DO NOT EDIT BY HAND ***
+ */
+
+package android.hardware.camera.metadata;
+
+/**
+ * android.control.settingsOverride enumeration values
+ * @see ANDROID_CONTROL_SETTINGS_OVERRIDE
+ */
+@VintfStability
+@Backing(type="int")
+enum ControlSettingsOverride {
+    ANDROID_CONTROL_SETTINGS_OVERRIDE_OFF,
+    ANDROID_CONTROL_SETTINGS_OVERRIDE_ZOOM,
+    ANDROID_CONTROL_SETTINGS_OVERRIDE_VENDOR_START = 0x4000,
+}
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/RequestAvailableCapabilities.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/RequestAvailableCapabilities.aidl
index f5c77eb..ebe0b4c 100644
--- a/camera/metadata/aidl/android/hardware/camera/metadata/RequestAvailableCapabilities.aidl
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/RequestAvailableCapabilities.aidl
@@ -49,4 +49,5 @@
     ANDROID_REQUEST_AVAILABLE_CAPABILITIES_REMOSAIC_REPROCESSING,
     ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT,
     ANDROID_REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE,
+    ANDROID_REQUEST_AVAILABLE_CAPABILITIES_COLOR_SPACE_PROFILES,
 }
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/RequestAvailableColorSpaceProfilesMap.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/RequestAvailableColorSpaceProfilesMap.aidl
new file mode 100644
index 0000000..1423305
--- /dev/null
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/RequestAvailableColorSpaceProfilesMap.aidl
@@ -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.
+ */
+
+/*
+ * Autogenerated from camera metadata definitions in
+ * /system/media/camera/docs/metadata_definitions.xml
+ * *** DO NOT EDIT BY HAND ***
+ */
+
+package android.hardware.camera.metadata;
+
+/**
+ * android.request.availableColorSpaceProfilesMap enumeration values
+ * @see ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP
+ */
+@VintfStability
+@Backing(type="long")
+enum RequestAvailableColorSpaceProfilesMap {
+    ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED = -1L,
+    ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_SRGB = 0L,
+    ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_LINEAR_SRGB = 1L,
+    ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_EXTENDED_SRGB = 2L,
+    ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_LINEAR_EXTENDED_SRGB = 3L,
+    ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_BT709 = 4L,
+    ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_BT2020 = 5L,
+    ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_DCI_P3 = 6L,
+    ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_DISPLAY_P3 = 7L,
+    ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_NTSC_1953 = 8L,
+    ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_SMPTE_C = 9L,
+    ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_ADOBE_RGB = 10L,
+    ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_PRO_PHOTO_RGB = 11L,
+    ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_ACES = 12L,
+    ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_ACESCG = 13L,
+    ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_CIE_XYZ = 14L,
+    ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_CIE_LAB = 15L,
+}
diff --git a/camera/provider/README.md b/camera/provider/README.md
index 0718fb1..7666a58 100644
--- a/camera/provider/README.md
+++ b/camera/provider/README.md
@@ -35,3 +35,9 @@
 First HIDL version of the camara provider HAL callback interface, closely
 matching the feature set and operation of the pre-HIDL camera HAL module
 callbacks v2.4.
+
+### AIDL Camera HAL Default Implementation ###
+
+The default implementation can be found at
+$ANDROID_BUILD_TOP/hardware/google/camera/common/hal/aidl_service and
+$ANDROID_BUILD_TOP/hardware/google/camera/devices/EmulatedCamera
diff --git a/camera/provider/aidl/Android.bp b/camera/provider/aidl/Android.bp
index 87a94b2..d7e613e 100644
--- a/camera/provider/aidl/Android.bp
+++ b/camera/provider/aidl/Android.bp
@@ -14,9 +14,10 @@
         "android/hardware/camera/provider/*.aidl",
     ],
     imports: [
-        "android.hardware.camera.device",
-        "android.hardware.camera.common",
+        "android.hardware.camera.device-V2",
+        "android.hardware.camera.common-V1",
     ],
+    frozen: false,
     stability: "vintf",
     backend: {
         java: {
diff --git a/camera/provider/aidl/vts/Android.bp b/camera/provider/aidl/vts/Android.bp
index 32da2fe..8429b21 100644
--- a/camera/provider/aidl/vts/Android.bp
+++ b/camera/provider/aidl/vts/Android.bp
@@ -59,9 +59,9 @@
     static_libs: [
         "android.hardware.camera.common@1.0-helper",
         "android.hardware.camera.common-V1-ndk",
-        "android.hardware.camera.device-V1-ndk",
-        "android.hardware.camera.metadata-V1-ndk",
-        "android.hardware.camera.provider-V1-ndk",
+        "android.hardware.camera.device-V2-ndk",
+        "android.hardware.camera.metadata-V2-ndk",
+        "android.hardware.camera.provider-V2-ndk",
         "android.hidl.allocator@1.0",
         "libgrallocusage",
         "libhidlmemory",
diff --git a/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
index 3fef089..747ea33 100644
--- a/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
+++ b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
@@ -36,6 +36,7 @@
 using ::aidl::android::hardware::camera::common::TorchModeStatus;
 using ::aidl::android::hardware::camera::common::VendorTagSection;
 using ::aidl::android::hardware::camera::device::ICameraDevice;
+using ::aidl::android::hardware::camera::metadata::RequestAvailableColorSpaceProfilesMap;
 using ::aidl::android::hardware::camera::metadata::RequestAvailableDynamicRangeProfilesMap;
 using ::aidl::android::hardware::camera::metadata::SensorPixelMode;
 using ::aidl::android::hardware::camera::provider::CameraIdAndStreamCombination;
@@ -386,22 +387,6 @@
                 mTorchStatus = TorchModeStatus::NOT_AVAILABLE;
             }
 
-            // register a new callback; make sure it receives the
-            // flash-on callback.
-            std::shared_ptr<TorchProviderCb> cb2 = ndk::SharedRefBase::make<TorchProviderCb>(this);
-            ret = mProvider->setCallback(cb2);
-            ASSERT_TRUE(ret.isOk());
-            ASSERT_NE(cb2, nullptr);
-            {
-                std::unique_lock<std::mutex> l(mTorchLock);
-                while (TorchModeStatus::NOT_AVAILABLE == mTorchStatus) {
-                    auto timeout = std::chrono::system_clock::now() +
-                                   std::chrono::seconds(kTorchTimeoutSec);
-                    ASSERT_NE(std::cv_status::timeout, mTorchCond.wait_until(l, timeout));
-                }
-                ASSERT_EQ(TorchModeStatus::AVAILABLE_ON, mTorchStatus);
-            }
-
             ret = device->setTorchMode(false);
             ASSERT_TRUE(ret.isOk());
             {
@@ -2037,6 +2022,71 @@
     }
 }
 
+TEST_P(CameraAidlTest, process8BitColorSpaceRequests) {
+    static int profiles[] = {
+        ColorSpaceNamed::BT709,
+        ColorSpaceNamed::DCI_P3,
+        ColorSpaceNamed::DISPLAY_P3,
+        ColorSpaceNamed::EXTENDED_SRGB,
+        ColorSpaceNamed::LINEAR_EXTENDED_SRGB,
+        ColorSpaceNamed::NTSC_1953,
+        ColorSpaceNamed::SMPTE_C,
+        ColorSpaceNamed::SRGB
+    };
+
+    for (int32_t i = 0; i < sizeof(profiles) / sizeof(profiles[0]); i++) {
+        processColorSpaceRequest(static_cast<RequestAvailableColorSpaceProfilesMap>(profiles[i]),
+                static_cast<RequestAvailableDynamicRangeProfilesMap>(
+                ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD));
+    }
+}
+
+TEST_P(CameraAidlTest, process10BitColorSpaceRequests) {
+    static const camera_metadata_enum_android_request_available_dynamic_range_profiles_map
+            dynamicRangeProfiles[] = {
+        ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HLG10,
+        ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10,
+        ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10_PLUS,
+        ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF,
+        ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF_PO,
+        ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM,
+        ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM_PO,
+        ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF,
+        ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF_PO,
+        ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM,
+        ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM_PO
+    };
+
+    // Process all dynamic range profiles with BT2020
+    for (int32_t i = 0; i < sizeof(dynamicRangeProfiles) / sizeof(dynamicRangeProfiles[0]); i++) {
+        processColorSpaceRequest(
+                static_cast<RequestAvailableColorSpaceProfilesMap>(ColorSpaceNamed::BT2020),
+                static_cast<RequestAvailableDynamicRangeProfilesMap>(dynamicRangeProfiles[i]));
+    }
+}
+
+TEST_P(CameraAidlTest, processZoomSettingsOverrideRequests) {
+    const int32_t kFrameCount = 5;
+    const int32_t kTestCases = 2;
+    const bool kOverrideSequence[kTestCases][kFrameCount] = {
+        // ZOOM, ZOOM, ZOOM, ZOOM, ZOOM;
+        { true, true, true, true, true },
+        // OFF, OFF, ZOOM, ZOOM, OFF;
+        { false, false, true, true, false } };
+    const bool kExpectedOverrideResults[kTestCases][kFrameCount] = {
+        // All resuls should be overridden except the last one. The last result's
+        // zoom doesn't have speed-up.
+        { true, true, true, true, false },
+        // Because we require at least 2 frames speed-up, request #1, #2 and #3
+        // will be overridden.
+        { true, true, true, false, false } };
+
+    for (int i = 0; i < kTestCases; i++) {
+        processZoomSettingsOverrideRequests(kFrameCount, kOverrideSequence[i],
+                kExpectedOverrideResults[i]);
+    }
+}
+
 // Generate and verify a burst containing alternating sensor sensitivity values
 TEST_P(CameraAidlTest, processCaptureRequestBurstISO) {
     std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
diff --git a/camera/provider/aidl/vts/camera_aidl_test.cpp b/camera/provider/aidl/vts/camera_aidl_test.cpp
index 2c2f1b2..b9e30ab 100644
--- a/camera/provider/aidl/vts/camera_aidl_test.cpp
+++ b/camera/provider/aidl/vts/camera_aidl_test.cpp
@@ -22,6 +22,7 @@
 #include <HandleImporter.h>
 #include <aidl/android/hardware/camera/device/ICameraDevice.h>
 #include <aidl/android/hardware/camera/metadata/CameraMetadataTag.h>
+#include <aidl/android/hardware/camera/metadata/RequestAvailableColorSpaceProfilesMap.h>
 #include <aidl/android/hardware/camera/metadata/RequestAvailableDynamicRangeProfilesMap.h>
 #include <aidl/android/hardware/camera/metadata/SensorInfoColorFilterArrangement.h>
 #include <aidl/android/hardware/camera/metadata/SensorPixelMode.h>
@@ -43,6 +44,7 @@
 using ::aidl::android::hardware::camera::device::CameraMetadata;
 using ::aidl::android::hardware::camera::device::ICameraDevice;
 using ::aidl::android::hardware::camera::metadata::CameraMetadataTag;
+using ::aidl::android::hardware::camera::metadata::RequestAvailableColorSpaceProfilesMap;
 using ::aidl::android::hardware::camera::metadata::RequestAvailableDynamicRangeProfilesMap;
 using ::aidl::android::hardware::camera::metadata::SensorInfoColorFilterArrangement;
 using ::aidl::android::hardware::camera::metadata::SensorPixelMode;
@@ -329,6 +331,69 @@
     ASSERT_EQ(hasStreamUseCaseCap, supportMandatoryUseCases);
 }
 
+void CameraAidlTest::verifySettingsOverrideCharacteristics(const camera_metadata_t* metadata) {
+    camera_metadata_ro_entry entry;
+    int retcode = find_camera_metadata_ro_entry(metadata,
+            ANDROID_CONTROL_AVAILABLE_SETTINGS_OVERRIDES, &entry);
+    bool supportSettingsOverride = false;
+    if ((0 == retcode) && (entry.count > 0)) {
+        supportSettingsOverride = true;
+        bool hasOff = false;
+        for (size_t i = 0; i < entry.count; i++) {
+            if (entry.data.u8[i] == ANDROID_CONTROL_SETTINGS_OVERRIDE_OFF) {
+                hasOff = true;
+            }
+        }
+        ASSERT_TRUE(hasOff);
+    }
+
+    // Check availableRequestKeys
+    retcode = find_camera_metadata_ro_entry(metadata,
+            ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS, &entry);
+    bool hasSettingsOverrideRequestKey = false;
+    if ((0 == retcode) && (entry.count > 0)) {
+        hasSettingsOverrideRequestKey =
+                std::find(entry.data.i32, entry.data.i32 + entry.count,
+                        ANDROID_CONTROL_SETTINGS_OVERRIDE) != entry.data.i32 + entry.count;
+    } else {
+        ADD_FAILURE() << "Get camera availableRequestKeys failed!";
+    }
+
+    // Check availableResultKeys
+    retcode = find_camera_metadata_ro_entry(metadata,
+            ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, &entry);
+    bool hasSettingsOverrideResultKey = false;
+    bool hasOverridingFrameNumberKey = false;
+    if ((0 == retcode) && (entry.count > 0)) {
+        hasSettingsOverrideResultKey =
+                std::find(entry.data.i32, entry.data.i32 + entry.count,
+                        ANDROID_CONTROL_SETTINGS_OVERRIDE) != entry.data.i32 + entry.count;
+        hasOverridingFrameNumberKey =
+                std::find(entry.data.i32, entry.data.i32 + entry.count,
+                        ANDROID_CONTROL_SETTINGS_OVERRIDING_FRAME_NUMBER)
+                        != entry.data.i32 + entry.count;
+    } else {
+        ADD_FAILURE() << "Get camera availableResultKeys failed!";
+    }
+
+    // Check availableCharacteristicKeys
+    retcode = find_camera_metadata_ro_entry(metadata,
+            ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, &entry);
+    bool hasSettingsOverrideCharacteristicsKey= false;
+    if ((0 == retcode) && (entry.count > 0)) {
+        hasSettingsOverrideCharacteristicsKey = std::find(entry.data.i32,
+                entry.data.i32 + entry.count, ANDROID_CONTROL_AVAILABLE_SETTINGS_OVERRIDES)
+                        != entry.data.i32 + entry.count;
+    } else {
+        ADD_FAILURE() << "Get camera availableCharacteristicsKeys failed!";
+    }
+
+    ASSERT_EQ(supportSettingsOverride, hasSettingsOverrideRequestKey);
+    ASSERT_EQ(supportSettingsOverride, hasSettingsOverrideResultKey);
+    ASSERT_EQ(supportSettingsOverride, hasOverridingFrameNumberKey);
+    ASSERT_EQ(supportSettingsOverride, hasSettingsOverrideCharacteristicsKey);
+}
+
 Status CameraAidlTest::isMonochromeCamera(const camera_metadata_t* staticMeta) {
     Status ret = Status::OPERATION_NOT_SUPPORTED;
     if (nullptr == staticMeta) {
@@ -604,6 +669,7 @@
     verifyExtendedSceneModeCharacteristics(metadata);
     verifyZoomCharacteristics(metadata);
     verifyStreamUseCaseCharacteristics(metadata);
+    verifySettingsOverrideCharacteristics(metadata);
 }
 
 void CameraAidlTest::verifyExtendedSceneModeCharacteristics(const camera_metadata_t* metadata) {
@@ -1515,6 +1581,15 @@
         ASSERT_EQ(zoomRatioEntry.count, 1);
         ASSERT_EQ(zoomRatioEntry.data.f[0], 1.0f);
     }
+
+    // Check settings override
+    camera_metadata_ro_entry settingsOverrideEntry;
+    int foundSettingsOverride = find_camera_metadata_ro_entry(metadata,
+           ANDROID_CONTROL_SETTINGS_OVERRIDE, &settingsOverrideEntry);
+    if (foundSettingsOverride == 0) {
+        ASSERT_EQ(settingsOverrideEntry.count, 1);
+        ASSERT_EQ(settingsOverrideEntry.data.u8[0], ANDROID_CONTROL_SETTINGS_OVERRIDE_OFF);
+    }
 }
 
 void CameraAidlTest::openEmptyDeviceSession(const std::string& name,
@@ -2788,6 +2863,192 @@
     }
 }
 
+bool CameraAidlTest::reportsColorSpaces(const camera_metadata_t* staticMeta) {
+    camera_metadata_ro_entry capabilityEntry;
+    int rc = find_camera_metadata_ro_entry(staticMeta, ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
+                                           &capabilityEntry);
+    if (rc == 0) {
+        for (uint32_t i = 0; i < capabilityEntry.count; i++) {
+            if (capabilityEntry.data.u8[i] ==
+                ANDROID_REQUEST_AVAILABLE_CAPABILITIES_COLOR_SPACE_PROFILES) {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+void CameraAidlTest::getColorSpaceProfiles(
+        const camera_metadata_t* staticMeta,
+        std::vector<RequestAvailableColorSpaceProfilesMap>* profiles) {
+    ASSERT_NE(nullptr, staticMeta);
+    ASSERT_NE(nullptr, profiles);
+    camera_metadata_ro_entry entry;
+    int rc = find_camera_metadata_ro_entry(
+            staticMeta, ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP, &entry);
+    ASSERT_EQ(rc, 0);
+    ASSERT_TRUE(entry.count > 0);
+    ASSERT_EQ(entry.count % 3, 0);
+
+    for (uint32_t i = 0; i < entry.count; i += 3) {
+        ASSERT_NE(entry.data.i64[i],
+                ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED);
+        if (std::find(profiles->begin(), profiles->end(),
+                static_cast<RequestAvailableColorSpaceProfilesMap>(entry.data.i64[i]))
+                == profiles->end()) {
+            profiles->emplace_back(
+                    static_cast<RequestAvailableColorSpaceProfilesMap>(entry.data.i64[i]));
+        }
+    }
+}
+
+bool CameraAidlTest::isColorSpaceCompatibleWithDynamicRangeAndPixelFormat(
+        const camera_metadata_t* staticMeta,
+        RequestAvailableColorSpaceProfilesMap colorSpace,
+        RequestAvailableDynamicRangeProfilesMap dynamicRangeProfile,
+        aidl::android::hardware::graphics::common::PixelFormat pixelFormat) {
+    camera_metadata_ro_entry entry;
+    int rc = find_camera_metadata_ro_entry(
+            staticMeta, ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP, &entry);
+
+    if (rc == 0) {
+        for (uint32_t i = 0; i < entry.count; i += 3) {
+            RequestAvailableColorSpaceProfilesMap entryColorSpace =
+                    static_cast<RequestAvailableColorSpaceProfilesMap>(entry.data.i64[i]);
+            int64_t dynamicRangeProfileI64 = static_cast<int64_t>(dynamicRangeProfile);
+            int32_t entryImageFormat = static_cast<int32_t>(entry.data.i64[i + 1]);
+            int32_t expectedImageFormat = halFormatToPublicFormat(pixelFormat);
+            if (entryColorSpace == colorSpace
+                    && (entry.data.i64[i + 2] & dynamicRangeProfileI64) != 0
+                    && entryImageFormat == expectedImageFormat) {
+                return true;
+            }
+        }
+    }
+
+    return false;
+}
+
+const char* CameraAidlTest::getColorSpaceProfileString(
+        RequestAvailableColorSpaceProfilesMap colorSpace) {
+    auto colorSpaceCast = static_cast<int>(colorSpace);
+    switch (colorSpaceCast) {
+        case ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED:
+            return "UNSPECIFIED";
+        case ColorSpaceNamed::SRGB:
+            return "SRGB";
+        case ColorSpaceNamed::LINEAR_SRGB:
+            return "LINEAR_SRGB";
+        case ColorSpaceNamed::EXTENDED_SRGB:
+            return "EXTENDED_SRGB";
+        case ColorSpaceNamed::LINEAR_EXTENDED_SRGB:
+            return "LINEAR_EXTENDED_SRGB";
+        case ColorSpaceNamed::BT709:
+            return "BT709";
+        case ColorSpaceNamed::BT2020:
+            return "BT2020";
+        case ColorSpaceNamed::DCI_P3:
+            return "DCI_P3";
+        case ColorSpaceNamed::DISPLAY_P3:
+            return "DISPLAY_P3";
+        case ColorSpaceNamed::NTSC_1953:
+            return "NTSC_1953";
+        case ColorSpaceNamed::SMPTE_C:
+            return "SMPTE_C";
+        case ColorSpaceNamed::ADOBE_RGB:
+            return "ADOBE_RGB";
+        case ColorSpaceNamed::PRO_PHOTO_RGB:
+            return "PRO_PHOTO_RGB";
+        case ColorSpaceNamed::ACES:
+            return "ACES";
+        case ColorSpaceNamed::ACESCG:
+            return "ACESCG";
+        case ColorSpaceNamed::CIE_XYZ:
+            return "CIE_XYZ";
+        case ColorSpaceNamed::CIE_LAB:
+            return "CIE_LAB";
+        default:
+            return "INVALID";
+    }
+
+    return "INVALID";
+}
+
+const char* CameraAidlTest::getDynamicRangeProfileString(
+        RequestAvailableDynamicRangeProfilesMap dynamicRangeProfile) {
+    auto dynamicRangeProfileCast =
+            static_cast<camera_metadata_enum_android_request_available_dynamic_range_profiles_map>
+            (dynamicRangeProfile);
+    switch (dynamicRangeProfileCast) {
+        case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD:
+            return "STANDARD";
+        case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HLG10:
+            return "HLG10";
+        case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10:
+            return "HDR10";
+        case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10_PLUS:
+            return "HDR10_PLUS";
+        case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF:
+            return "DOLBY_VISION_10B_HDR_REF";
+        case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF_PO:
+            return "DOLBY_VISION_10B_HDR_REF_P0";
+        case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM:
+            return "DOLBY_VISION_10B_HDR_OEM";
+        case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM_PO:
+            return "DOLBY_VISION_10B_HDR_OEM_P0";
+        case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF:
+            return "DOLBY_VISION_8B_HDR_REF";
+        case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF_PO:
+            return "DOLBY_VISION_8B_HDR_REF_P0";
+        case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM:
+            return "DOLBY_VISION_8B_HDR_OEM";
+        case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM_PO:
+            return "DOLBY_VISION_8B_HDR_OEM_P0";
+        default:
+            return "INVALID";
+    }
+
+    return "INVALID";
+}
+
+int32_t CameraAidlTest::halFormatToPublicFormat(
+        aidl::android::hardware::graphics::common::PixelFormat pixelFormat) {
+    // This is an incomplete mapping of pixel format to image format and assumes dataspaces
+    // (see getDataspace)
+    switch (pixelFormat) {
+    case PixelFormat::BLOB:
+        return 0x100; // ImageFormat.JPEG
+    case PixelFormat::Y16:
+        return 0x44363159; // ImageFormat.DEPTH16
+    default:
+        return static_cast<int32_t>(pixelFormat);
+    }
+}
+
+bool CameraAidlTest::supportZoomSettingsOverride(const camera_metadata_t* staticMeta) {
+    camera_metadata_ro_entry availableOverridesEntry;
+    int rc = find_camera_metadata_ro_entry(staticMeta, ANDROID_CONTROL_AVAILABLE_SETTINGS_OVERRIDES,
+                                           &availableOverridesEntry);
+    if (rc == 0) {
+        for (size_t i = 0; i < availableOverridesEntry.count; i++) {
+            if (availableOverridesEntry.data.i32[i] == ANDROID_CONTROL_SETTINGS_OVERRIDE_ZOOM) {
+                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,
+                                           &syncLatencyEntry);
+    if (rc == 0 && syncLatencyEntry.data.i32[0] == ANDROID_SYNC_MAX_LATENCY_PER_FRAME_CONTROL) {
+        return true;
+    }
+    return false;
+}
+
 void CameraAidlTest::configurePreviewStream(
         const std::string& name, const std::shared_ptr<ICameraProvider>& provider,
         const AvailableStream* previewThreshold, std::shared_ptr<ICameraDeviceSession>* session,
@@ -2933,4 +3194,379 @@
     for (auto& it : mInflightMap) {
         it.second->resultQueue = resultQueue;
     }
-}
\ No newline at end of file
+}
+
+void CameraAidlTest::processColorSpaceRequest(
+        RequestAvailableColorSpaceProfilesMap colorSpace,
+        RequestAvailableDynamicRangeProfilesMap dynamicRangeProfile) {
+    std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+    int64_t bufferId = 1;
+    CameraMetadata settings;
+
+    for (const auto& name : cameraDeviceNames) {
+        std::string version, deviceId;
+        ASSERT_TRUE(matchDeviceName(name, mProviderType, &version, &deviceId));
+        CameraMetadata meta;
+        std::shared_ptr<ICameraDevice> device;
+        openEmptyDeviceSession(name, mProvider, &mSession, &meta, &device);
+        camera_metadata_t* staticMeta = reinterpret_cast<camera_metadata_t*>(meta.metadata.data());
+
+        // Device does not report color spaces, skip.
+        if (!reportsColorSpaces(staticMeta)) {
+            ndk::ScopedAStatus ret = mSession->close();
+            mSession = nullptr;
+            ASSERT_TRUE(ret.isOk());
+            ALOGV("Camera %s does not report color spaces", name.c_str());
+            continue;
+        }
+        std::vector<RequestAvailableColorSpaceProfilesMap> profileList;
+        getColorSpaceProfiles(staticMeta, &profileList);
+        ASSERT_FALSE(profileList.empty());
+
+        // Device does not support color space / dynamic range profile, skip
+        if (std::find(profileList.begin(), profileList.end(), colorSpace)
+                == profileList.end() || !isColorSpaceCompatibleWithDynamicRangeAndPixelFormat(
+                        staticMeta, colorSpace, dynamicRangeProfile,
+                        PixelFormat::IMPLEMENTATION_DEFINED)) {
+            ndk::ScopedAStatus ret = mSession->close();
+            mSession = nullptr;
+            ASSERT_TRUE(ret.isOk());
+            ALOGV("Camera %s does not support color space %s with dynamic range profile %s and "
+                  "pixel format %d", name.c_str(), getColorSpaceProfileString(colorSpace),
+                  getDynamicRangeProfileString(dynamicRangeProfile),
+                  PixelFormat::IMPLEMENTATION_DEFINED);
+            continue;
+        }
+
+        ALOGV("Camera %s supports color space %s with dynamic range profile %s and pixel format %d",
+                name.c_str(), getColorSpaceProfileString(colorSpace),
+                getDynamicRangeProfileString(dynamicRangeProfile),
+                PixelFormat::IMPLEMENTATION_DEFINED);
+
+        // If an HDR dynamic range profile is reported in the color space profile list,
+        // the device must also have the dynamic range profiles map capability and contain
+        // the dynamic range profile in the map.
+        if (dynamicRangeProfile != static_cast<RequestAvailableDynamicRangeProfilesMap>(
+                ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD)) {
+            ASSERT_TRUE(is10BitDynamicRangeCapable(staticMeta));
+
+            std::vector<RequestAvailableDynamicRangeProfilesMap> dynamicRangeProfiles;
+            get10BitDynamicRangeProfiles(staticMeta, &dynamicRangeProfiles);
+            ASSERT_FALSE(dynamicRangeProfiles.empty());
+            ASSERT_FALSE(std::find(dynamicRangeProfiles.begin(), dynamicRangeProfiles.end(),
+                    dynamicRangeProfile) == dynamicRangeProfiles.end());
+        }
+
+        CameraMetadata req;
+        android::hardware::camera::common::V1_0::helper::CameraMetadata defaultSettings;
+        ndk::ScopedAStatus ret =
+                mSession->constructDefaultRequestSettings(RequestTemplate::PREVIEW, &req);
+        ASSERT_TRUE(ret.isOk());
+
+        const camera_metadata_t* metadata =
+                reinterpret_cast<const camera_metadata_t*>(req.metadata.data());
+        size_t expectedSize = req.metadata.size();
+        int result = validate_camera_metadata_structure(metadata, &expectedSize);
+        ASSERT_TRUE((result == 0) || (result == CAMERA_METADATA_VALIDATION_SHIFTED));
+
+        size_t entryCount = get_camera_metadata_entry_count(metadata);
+        ASSERT_GT(entryCount, 0u);
+        defaultSettings = metadata;
+
+        const camera_metadata_t* settingsBuffer = defaultSettings.getAndLock();
+        uint8_t* rawSettingsBuffer = (uint8_t*)settingsBuffer;
+        settings.metadata = std::vector(
+                rawSettingsBuffer, rawSettingsBuffer + get_camera_metadata_size(settingsBuffer));
+        overrideRotateAndCrop(&settings);
+
+        ret = mSession->close();
+        mSession = nullptr;
+        ASSERT_TRUE(ret.isOk());
+
+        std::vector<HalStream> halStreams;
+        bool supportsPartialResults = false;
+        bool useHalBufManager = false;
+        int32_t partialResultCount = 0;
+        Stream previewStream;
+        std::shared_ptr<DeviceCb> cb;
+
+        previewStream.usage =
+            static_cast<aidl::android::hardware::graphics::common::BufferUsage>(
+                    GRALLOC1_CONSUMER_USAGE_HWCOMPOSER);
+        previewStream.dataSpace = getDataspace(PixelFormat::IMPLEMENTATION_DEFINED);
+        previewStream.colorSpace = static_cast<int32_t>(colorSpace);
+        configureStreams(name, mProvider, PixelFormat::IMPLEMENTATION_DEFINED, &mSession,
+                            &previewStream, &halStreams, &supportsPartialResults,
+                            &partialResultCount, &useHalBufManager, &cb, 0,
+                            /*maxResolution*/ false, dynamicRangeProfile);
+        ASSERT_NE(mSession, nullptr);
+
+        ::aidl::android::hardware::common::fmq::MQDescriptor<
+                int8_t, aidl::android::hardware::common::fmq::SynchronizedReadWrite>
+                descriptor;
+        auto resultQueueRet = mSession->getCaptureResultMetadataQueue(&descriptor);
+        ASSERT_TRUE(resultQueueRet.isOk());
+
+        std::shared_ptr<ResultMetadataQueue> resultQueue =
+                std::make_shared<ResultMetadataQueue>(descriptor);
+        if (!resultQueue->isValid() || resultQueue->availableToWrite() <= 0) {
+            ALOGE("%s: HAL returns empty result metadata fmq, not use it", __func__);
+            resultQueue = nullptr;
+            // Don't use the queue onwards.
+        }
+
+        mInflightMap.clear();
+        // Stream as long as needed to fill the Hal inflight queue
+        std::vector<CaptureRequest> requests(halStreams[0].maxBuffers);
+
+        for (int32_t frameNumber = 0; frameNumber < requests.size(); frameNumber++) {
+            std::shared_ptr<InFlightRequest> inflightReq = std::make_shared<InFlightRequest>(
+                    static_cast<ssize_t>(halStreams.size()), false, supportsPartialResults,
+                    partialResultCount, std::unordered_set<std::string>(), resultQueue);
+
+            CaptureRequest& request = requests[frameNumber];
+            std::vector<StreamBuffer>& outputBuffers = request.outputBuffers;
+            outputBuffers.resize(halStreams.size());
+
+            size_t k = 0;
+            inflightReq->mOutstandingBufferIds.resize(halStreams.size());
+            std::vector<buffer_handle_t> graphicBuffers;
+            graphicBuffers.reserve(halStreams.size());
+
+            for (const auto& halStream : halStreams) {
+                buffer_handle_t buffer_handle;
+                if (useHalBufManager) {
+                    outputBuffers[k] = {halStream.id,   0,
+                                        NativeHandle(), BufferStatus::OK,
+                                        NativeHandle(), NativeHandle()};
+                } else {
+                    auto usage = android_convertGralloc1To0Usage(
+                            static_cast<uint64_t>(halStream.producerUsage),
+                            static_cast<uint64_t>(halStream.consumerUsage));
+                    allocateGraphicBuffer(previewStream.width, previewStream.height, usage,
+                                            halStream.overrideFormat, &buffer_handle);
+
+                    inflightReq->mOutstandingBufferIds[halStream.id][bufferId] = buffer_handle;
+                    graphicBuffers.push_back(buffer_handle);
+                    outputBuffers[k] = {halStream.id, bufferId,
+                        android::makeToAidl(buffer_handle), BufferStatus::OK, NativeHandle(),
+                        NativeHandle()};
+                    bufferId++;
+                }
+                k++;
+            }
+
+            request.inputBuffer = {
+                    -1, 0, NativeHandle(), BufferStatus::ERROR, NativeHandle(), NativeHandle()};
+            request.frameNumber = frameNumber;
+            request.fmqSettingsSize = 0;
+            request.settings = settings;
+            request.inputWidth = 0;
+            request.inputHeight = 0;
+
+            {
+                std::unique_lock<std::mutex> l(mLock);
+                mInflightMap[frameNumber] = inflightReq;
+            }
+
+        }
+
+        int32_t numRequestProcessed = 0;
+        std::vector<BufferCache> cachesToRemove;
+        ndk::ScopedAStatus returnStatus =
+            mSession->processCaptureRequest(requests, cachesToRemove, &numRequestProcessed);
+        ASSERT_TRUE(returnStatus.isOk());
+        ASSERT_EQ(numRequestProcessed, requests.size());
+
+        returnStatus = mSession->repeatingRequestEnd(requests.size() - 1,
+                std::vector<int32_t> {halStreams[0].id});
+        ASSERT_TRUE(returnStatus.isOk());
+
+        for (int32_t frameNumber = 0; frameNumber < requests.size(); frameNumber++) {
+            const auto& inflightReq = mInflightMap[frameNumber];
+            std::unique_lock<std::mutex> l(mLock);
+            while (!inflightReq->errorCodeValid &&
+                    ((0 < inflightReq->numBuffersLeft) || (!inflightReq->haveResultMetadata))) {
+                auto timeout = std::chrono::system_clock::now() +
+                                std::chrono::seconds(kStreamBufferTimeoutSec);
+                ASSERT_NE(std::cv_status::timeout, mResultCondition.wait_until(l, timeout));
+            }
+
+            ASSERT_FALSE(inflightReq->errorCodeValid);
+            ASSERT_NE(inflightReq->resultOutputBuffers.size(), 0u);
+
+            if (dynamicRangeProfile != static_cast<RequestAvailableDynamicRangeProfilesMap>(
+                    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD)) {
+                verify10BitMetadata(mHandleImporter, *inflightReq, dynamicRangeProfile);
+            }
+        }
+
+        if (useHalBufManager) {
+            std::vector<int32_t> streamIds(halStreams.size());
+            for (size_t i = 0; i < streamIds.size(); i++) {
+                streamIds[i] = halStreams[i].id;
+            }
+            mSession->signalStreamFlush(streamIds, /*streamConfigCounter*/ 0);
+            cb->waitForBuffersReturned();
+        }
+
+        ret = mSession->close();
+        mSession = nullptr;
+        ASSERT_TRUE(ret.isOk());
+    }
+}
+
+void CameraAidlTest::processZoomSettingsOverrideRequests(
+        int32_t frameCount, const bool *overrideSequence, const bool *expectedResults) {
+    std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+    AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
+                                        static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
+    int64_t bufferId = 1;
+    int32_t frameNumber = 1;
+    CameraMetadata settings;
+    ndk::ScopedAStatus ret;
+    for (const auto& name : cameraDeviceNames) {
+        CameraMetadata meta;
+        std::shared_ptr<ICameraDevice> device;
+        openEmptyDeviceSession(name, mProvider, &mSession /*out*/, &meta /*out*/,
+                               &device /*out*/);
+        camera_metadata_t* staticMeta =
+                clone_camera_metadata(reinterpret_cast<camera_metadata_t*>(meta.metadata.data()));
+
+        ret = mSession->close();
+        mSession = nullptr;
+        ASSERT_TRUE(ret.isOk());
+
+        // Device does not support zoom settnigs override
+        if (!supportZoomSettingsOverride(staticMeta)) {
+            continue;
+        }
+
+        if (!isPerFrameControl(staticMeta)) {
+            continue;
+        }
+
+        bool supportsPartialResults = false;
+        bool useHalBufManager = false;
+        int32_t partialResultCount = 0;
+        Stream previewStream;
+        std::vector<HalStream> halStreams;
+        std::shared_ptr<DeviceCb> cb;
+        configurePreviewStream(name, mProvider, &previewThreshold, &mSession /*out*/,
+                               &previewStream /*out*/, &halStreams /*out*/,
+                               &supportsPartialResults /*out*/, &partialResultCount /*out*/,
+                               &useHalBufManager /*out*/, &cb /*out*/);
+        ASSERT_NE(mSession, nullptr);
+
+        ::aidl::android::hardware::common::fmq::MQDescriptor<
+                int8_t, aidl::android::hardware::common::fmq::SynchronizedReadWrite>
+                descriptor;
+        auto resultQueueRet = mSession->getCaptureResultMetadataQueue(&descriptor);
+        ASSERT_TRUE(resultQueueRet.isOk());
+
+        std::shared_ptr<ResultMetadataQueue> resultQueue =
+                std::make_shared<ResultMetadataQueue>(descriptor);
+        if (!resultQueue->isValid() || resultQueue->availableToWrite() <= 0) {
+            ALOGE("%s: HAL returns empty result metadata fmq, not use it", __func__);
+            resultQueue = nullptr;
+            // Don't use the queue onwards.
+        }
+
+        ret = mSession->constructDefaultRequestSettings(RequestTemplate::PREVIEW, &settings);
+        ASSERT_TRUE(ret.isOk());
+
+        mInflightMap.clear();
+        ::android::hardware::camera::common::V1_0::helper::CameraMetadata requestMeta;
+        std::vector<CaptureRequest> requests(frameCount);
+        std::vector<buffer_handle_t> buffers(frameCount);
+        std::vector<std::shared_ptr<InFlightRequest>> inflightReqs(frameCount);
+        std::vector<CameraMetadata> requestSettings(frameCount);
+
+        for (int32_t i = 0; i < frameCount; i++) {
+            std::unique_lock<std::mutex> l(mLock);
+            CaptureRequest& request = requests[i];
+            std::vector<StreamBuffer>& outputBuffers = request.outputBuffers;
+            outputBuffers.resize(1);
+            StreamBuffer& outputBuffer = outputBuffers[0];
+
+            if (useHalBufManager) {
+                outputBuffer = {halStreams[0].id, 0,
+                                NativeHandle(),   BufferStatus::OK,
+                                NativeHandle(),   NativeHandle()};
+            } else {
+                allocateGraphicBuffer(previewStream.width, previewStream.height,
+                                      android_convertGralloc1To0Usage(
+                                              static_cast<uint64_t>(halStreams[0].producerUsage),
+                                              static_cast<uint64_t>(halStreams[0].consumerUsage)),
+                                      halStreams[0].overrideFormat, &buffers[i]);
+                outputBuffer = {halStreams[0].id, bufferId + i,   ::android::makeToAidl(buffers[i]),
+                                BufferStatus::OK, NativeHandle(), NativeHandle()};
+            }
+
+            // Set appropriate settings override tag
+            requestMeta.append(reinterpret_cast<camera_metadata_t*>(settings.metadata.data()));
+            int32_t settingsOverride = overrideSequence[i] ?
+                    ANDROID_CONTROL_SETTINGS_OVERRIDE_ZOOM : ANDROID_CONTROL_SETTINGS_OVERRIDE_OFF;
+            ASSERT_EQ(::android::OK, requestMeta.update(ANDROID_CONTROL_SETTINGS_OVERRIDE,
+                    &settingsOverride, 1));
+            camera_metadata_t* metaBuffer = requestMeta.release();
+            uint8_t* rawMetaBuffer = reinterpret_cast<uint8_t*>(metaBuffer);
+            requestSettings[i].metadata = std::vector(
+                    rawMetaBuffer, rawMetaBuffer + get_camera_metadata_size(metaBuffer));
+            overrideRotateAndCrop(&(requestSettings[i]));
+            request.frameNumber = frameNumber + i;
+            request.fmqSettingsSize = 0;
+            request.settings = requestSettings[i];
+            request.inputBuffer = {
+                    -1, 0, NativeHandle(), BufferStatus::ERROR, NativeHandle(), NativeHandle()};
+
+            inflightReqs[i] = std::make_shared<InFlightRequest>(1, false, supportsPartialResults,
+                                                                partialResultCount, resultQueue);
+            mInflightMap[frameNumber + i] = inflightReqs[i];
+        }
+
+        int32_t numRequestProcessed = 0;
+        std::vector<BufferCache> cachesToRemove;
+
+        ndk::ScopedAStatus returnStatus =
+                mSession->processCaptureRequest(requests, cachesToRemove, &numRequestProcessed);
+        ASSERT_TRUE(returnStatus.isOk());
+        ASSERT_EQ(numRequestProcessed, frameCount);
+
+        for (size_t i = 0; i < frameCount; i++) {
+            std::unique_lock<std::mutex> l(mLock);
+            while (!inflightReqs[i]->errorCodeValid && ((0 < inflightReqs[i]->numBuffersLeft) ||
+                                                        (!inflightReqs[i]->haveResultMetadata))) {
+                auto timeout = std::chrono::system_clock::now() +
+                               std::chrono::seconds(kStreamBufferTimeoutSec);
+                ASSERT_NE(std::cv_status::timeout, mResultCondition.wait_until(l, timeout));
+            }
+
+            ASSERT_FALSE(inflightReqs[i]->errorCodeValid);
+            ASSERT_NE(inflightReqs[i]->resultOutputBuffers.size(), 0u);
+            ASSERT_EQ(previewStream.id, inflightReqs[i]->resultOutputBuffers[0].buffer.streamId);
+            ASSERT_FALSE(inflightReqs[i]->collectedResult.isEmpty());
+            ASSERT_TRUE(inflightReqs[i]->collectedResult.exists(ANDROID_CONTROL_SETTINGS_OVERRIDE));
+            camera_metadata_entry_t overrideResult =
+                    inflightReqs[i]->collectedResult.find(ANDROID_CONTROL_SETTINGS_OVERRIDE);
+            ASSERT_EQ(overrideResult.data.i32[0] == ANDROID_CONTROL_SETTINGS_OVERRIDE_ZOOM,
+                    expectedResults[i]);
+            ASSERT_TRUE(inflightReqs[i]->collectedResult.exists(
+                    ANDROID_CONTROL_SETTINGS_OVERRIDING_FRAME_NUMBER));
+            camera_metadata_entry_t frameNumberEntry = inflightReqs[i]->collectedResult.find(
+                    ANDROID_CONTROL_SETTINGS_OVERRIDING_FRAME_NUMBER);
+            ALOGV("%s: i %zu, expcetedResults[i] %d, overrideResult is %d, frameNumber %d",
+                  __FUNCTION__, i, expectedResults[i], overrideResult.data.i32[0],
+                  frameNumberEntry.data.i32[0]);
+            if (expectedResults[i]) {
+                ASSERT_GT(frameNumberEntry.data.i32[0], inflightReqs[i]->frameNumber);
+            } else {
+                ASSERT_EQ(frameNumberEntry.data.i32[0], frameNumber + i);
+            }
+        }
+
+        ret = mSession->close();
+        mSession = nullptr;
+        ASSERT_TRUE(ret.isOk());
+    }
+}
diff --git a/camera/provider/aidl/vts/camera_aidl_test.h b/camera/provider/aidl/vts/camera_aidl_test.h
index d828cee..b6e398b 100644
--- a/camera/provider/aidl/vts/camera_aidl_test.h
+++ b/camera/provider/aidl/vts/camera_aidl_test.h
@@ -44,6 +44,8 @@
 
 #include <aidl/android/hardware/camera/provider/ICameraProvider.h>
 
+#include <aidl/android/hardware/camera/metadata/RequestAvailableColorSpaceProfilesMap.h>
+
 #include <aidl/android/hardware/graphics/common/PixelFormat.h>
 
 #include <gtest/gtest.h>
@@ -123,6 +125,26 @@
         YUV_REPROCESS,
     };
 
+    // Copied from ColorSpace.java (see Named)
+    enum ColorSpaceNamed {
+        SRGB,
+        LINEAR_SRGB,
+        EXTENDED_SRGB,
+        LINEAR_EXTENDED_SRGB,
+        BT709,
+        BT2020,
+        DCI_P3,
+        DISPLAY_P3,
+        NTSC_1953,
+        SMPTE_C,
+        ADOBE_RGB,
+        PRO_PHOTO_RGB,
+        ACES,
+        ACESCG,
+        CIE_XYZ,
+        CIE_LAB
+    };
+
     struct AvailableZSLInputOutput {
         int32_t inputFormat;
         int32_t outputFormat;
@@ -230,6 +252,8 @@
 
     static void verifyStreamUseCaseCharacteristics(const camera_metadata_t* metadata);
 
+    static void verifySettingsOverrideCharacteristics(const camera_metadata_t* metadata);
+
     static void verifyStreamCombination(const std::shared_ptr<ICameraDevice>& device,
                                         const StreamConfiguration& config, bool expectedStatus,
                                         bool expectStreamCombQuery);
@@ -348,11 +372,46 @@
             std::vector<aidl::android::hardware::camera::metadata::
                                 RequestAvailableDynamicRangeProfilesMap>* profiles);
 
+    static bool reportsColorSpaces(const camera_metadata_t* staticMeta);
+
+    static void getColorSpaceProfiles(
+            const camera_metadata_t* staticMeta,
+            std::vector<aidl::android::hardware::camera::metadata::
+                                RequestAvailableColorSpaceProfilesMap>* profiles);
+
+    static bool isColorSpaceCompatibleWithDynamicRangeAndPixelFormat(
+            const camera_metadata_t* staticMeta,
+            aidl::android::hardware::camera::metadata::
+            RequestAvailableColorSpaceProfilesMap colorSpace,
+            aidl::android::hardware::camera::metadata::
+            RequestAvailableDynamicRangeProfilesMap dynamicRangeProfile,
+            aidl::android::hardware::graphics::common::PixelFormat pixelFormat);
+
+    static const char* getColorSpaceProfileString(aidl::android::hardware::camera::metadata::
+            RequestAvailableColorSpaceProfilesMap colorSpace);
+
+    static const char* getDynamicRangeProfileString(aidl::android::hardware::camera::metadata::
+            RequestAvailableDynamicRangeProfilesMap dynamicRangeProfile);
+
+    static int32_t halFormatToPublicFormat(
+            aidl::android::hardware::graphics::common::PixelFormat pixelFormat);
+
     // Used by switchToOffline where a new result queue is created for offline reqs
     void updateInflightResultQueue(const std::shared_ptr<ResultMetadataQueue>& resultQueue);
 
     static Size getMinSize(Size a, Size b);
 
+    void processColorSpaceRequest(aidl::android::hardware::camera::metadata::
+            RequestAvailableColorSpaceProfilesMap colorSpace,
+            aidl::android::hardware::camera::metadata::
+            RequestAvailableDynamicRangeProfilesMap dynamicRangeProfile);
+
+    void processZoomSettingsOverrideRequests(
+            int32_t frameCount, const bool *overrideSequence, const bool *expectedResults);
+
+    bool supportZoomSettingsOverride(const camera_metadata_t* staticMeta);
+    bool isPerFrameControl(const camera_metadata_t* staticMeta);
+
   protected:
     // In-flight queue for tracking completion of capture requests.
     struct InFlightRequest {
diff --git a/cas/aidl/Android.bp b/cas/aidl/Android.bp
new file mode 100644
index 0000000..32f12b1
--- /dev/null
+++ b/cas/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.cas",
+    vendor_available: true,
+    srcs: ["android/hardware/cas/*.aidl"],
+    stability: "vintf",
+    imports: ["android.hardware.common-V2"],
+    backend: {
+        cpp: {
+            enabled: false,
+        },
+        java: {
+            sdk_version: "module_current",
+        },
+    },
+}
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
new file mode 100644
index 0000000..7b8099f
--- /dev/null
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/AidlCasPluginDescriptor.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.cas;
+@VintfStability
+parcelable AidlCasPluginDescriptor {
+  int caSystemId;
+  String name;
+}
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
new file mode 100644
index 0000000..dd355af
--- /dev/null
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/DestinationBuffer.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.cas;
+@VintfStability
+union DestinationBuffer {
+  android.hardware.cas.SharedBuffer nonsecureMemory;
+  android.hardware.common.NativeHandle secureMemory;
+}
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
new file mode 100644
index 0000000..e169beb
--- /dev/null
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ICas.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.cas;
+@VintfStability
+interface ICas {
+  void closeSession(in byte[] sessionId);
+  byte[] openSession(in android.hardware.cas.SessionIntent intent, in android.hardware.cas.ScramblingMode mode);
+  void processEcm(in byte[] sessionId, in byte[] ecm);
+  void processEmm(in byte[] emm);
+  void provision(in String provisionString);
+  void refreshEntitlements(in int refreshType, in byte[] refreshData);
+  void release();
+  void sendEvent(in int event, in int arg, in byte[] eventData);
+  void sendSessionEvent(in byte[] sessionId, in int event, in int arg, in byte[] eventData);
+  void setPrivateData(in byte[] pvtData);
+  void setSessionPrivateData(in byte[] sessionId, in byte[] pvtData);
+}
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
new file mode 100644
index 0000000..ebc13ce
--- /dev/null
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ICasListener.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.cas;
+@VintfStability
+interface ICasListener {
+  void onEvent(in int event, in int arg, in byte[] data);
+  void onSessionEvent(in byte[] sessionId, in int event, in int arg, in byte[] data);
+  void onStatusUpdate(in android.hardware.cas.StatusEvent event, in int number);
+}
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
new file mode 100644
index 0000000..9bf7903
--- /dev/null
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/IDescrambler.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.cas;
+@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);
+  void release();
+  boolean requiresSecureDecoderComponent(in String mime);
+  void setMediaCasSession(in byte[] sessionId);
+}
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
new file mode 100644
index 0000000..f5c8018
--- /dev/null
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/IMediaCasService.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.cas;
+@VintfStability
+interface IMediaCasService {
+  android.hardware.cas.IDescrambler createDescrambler(in int CA_system_id);
+  android.hardware.cas.ICas createPlugin(in int CA_system_id, in android.hardware.cas.ICasListener listener);
+  android.hardware.cas.AidlCasPluginDescriptor[] enumeratePlugins();
+  boolean isDescramblerSupported(in int CA_system_id);
+  boolean isSystemIdSupported(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
new file mode 100644
index 0000000..d71d4be
--- /dev/null
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ScramblingControl.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.cas;
+@Backing(type="int") @VintfStability
+enum ScramblingControl {
+  UNSCRAMBLED = 0,
+  RESERVED = 1,
+  EVENKEY = 2,
+  ODDKEY = 3,
+}
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
new file mode 100644
index 0000000..e3923c7
--- /dev/null
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ScramblingMode.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.cas;
+@Backing(type="int") @VintfStability
+enum ScramblingMode {
+  RESERVED = 0,
+  DVB_CSA1 = 1,
+  DVB_CSA2 = 2,
+  DVB_CSA3_STANDARD = 3,
+  DVB_CSA3_MINIMAL = 4,
+  DVB_CSA3_ENHANCE = 5,
+  DVB_CISSA_V1 = 6,
+  DVB_IDSA = 7,
+  MULTI2 = 8,
+  AES128 = 9,
+  AES_CBC = 10,
+  AES_ECB = 11,
+  AES_SCTE52 = 12,
+  TDES_ECB = 13,
+  TDES_SCTE52 = 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
new file mode 100644
index 0000000..af95f80
--- /dev/null
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SessionIntent.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.cas;
+@Backing(type="int") @VintfStability
+enum SessionIntent {
+  LIVE = 0,
+  PLAYBACK = 1,
+  RECORD = 2,
+  TIMESHIFT = 3,
+}
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
new file mode 100644
index 0000000..a18aa57
--- /dev/null
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SharedBuffer.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.cas;
+@VintfStability
+parcelable SharedBuffer {
+  android.hardware.common.Ashmem heapBase;
+  long offset;
+  long size;
+}
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
new file mode 100644
index 0000000..3d3a8a0
--- /dev/null
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/Status.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.cas;
+@VintfStability
+parcelable Status {
+  const int OK = 0;
+  const int ERROR_CAS_NO_LICENSE = -1;
+  const int ERROR_CAS_LICENSE_EXPIRED = -2;
+  const int ERROR_CAS_SESSION_NOT_OPENED = -3;
+  const int ERROR_CAS_CANNOT_HANDLE = -4;
+  const int ERROR_CAS_INVALID_STATE = -5;
+  const int BAD_VALUE = -6;
+  const int ERROR_CAS_NOT_PROVISIONED = -7;
+  const int ERROR_CAS_RESOURCE_BUSY = -8;
+  const int ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION = -9;
+  const int ERROR_CAS_TAMPER_DETECTED = -10;
+  const int ERROR_CAS_DEVICE_REVOKED = -11;
+  const int ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED = -12;
+  const int ERROR_CAS_DECRYPT = -13;
+  const int ERROR_CAS_UNKNOWN = -14;
+  const int ERROR_CAS_NEED_ACTIVATION = -15;
+  const int ERROR_CAS_NEED_PAIRING = -16;
+  const int ERROR_CAS_NO_CARD = -17;
+  const int ERROR_CAS_CARD_MUTE = -18;
+  const int ERROR_CAS_CARD_INVALID = -19;
+  const int ERROR_CAS_BLACKOUT = -20;
+  const int ERROR_CAS_REBOOTING = -21;
+}
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
new file mode 100644
index 0000000..178cabc
--- /dev/null
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/StatusEvent.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.cas;
+@Backing(type="byte") @VintfStability
+enum StatusEvent {
+  PLUGIN_PHYSICAL_MODULE_CHANGED = 0,
+  PLUGIN_SESSION_NUMBER_CHANGED = 1,
+}
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
new file mode 100644
index 0000000..d9ee3b4
--- /dev/null
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SubSample.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.cas;
+@VintfStability
+parcelable SubSample {
+  int numBytesOfClearData;
+  int numBytesOfEncryptedData;
+}
diff --git a/cas/aidl/android/hardware/cas/AidlCasPluginDescriptor.aidl b/cas/aidl/android/hardware/cas/AidlCasPluginDescriptor.aidl
new file mode 100644
index 0000000..55b328a
--- /dev/null
+++ b/cas/aidl/android/hardware/cas/AidlCasPluginDescriptor.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.cas;
+
+/**
+ * Describes a CAS plugin with its system ID and name.
+ */
+@VintfStability
+parcelable AidlCasPluginDescriptor {
+    int caSystemId;
+    String name;
+}
diff --git a/cas/aidl/android/hardware/cas/DestinationBuffer.aidl b/cas/aidl/android/hardware/cas/DestinationBuffer.aidl
new file mode 100644
index 0000000..068f29d
--- /dev/null
+++ b/cas/aidl/android/hardware/cas/DestinationBuffer.aidl
@@ -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.
+ */
+
+package android.hardware.cas;
+
+import android.hardware.cas.SharedBuffer;
+import android.hardware.common.NativeHandle;
+
+@VintfStability
+union DestinationBuffer {
+    /**
+     * If type == SHARED_MEMORY, the descrambled data must be written
+     * to user-space non-secure shared memory.
+     */
+    SharedBuffer nonsecureMemory;
+
+    /**
+     * If type == NATIVE_HANDLE, the descrambled data must be written
+     * to secure memory referenced by the vendor's buffer allocator.
+     */
+    NativeHandle secureMemory;
+}
diff --git a/cas/aidl/android/hardware/cas/ICas.aidl b/cas/aidl/android/hardware/cas/ICas.aidl
new file mode 100644
index 0000000..4c938c7
--- /dev/null
+++ b/cas/aidl/android/hardware/cas/ICas.aidl
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.cas;
+
+import android.hardware.cas.ScramblingMode;
+import android.hardware.cas.SessionIntent;
+
+/**
+ * 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.
+ */
+@VintfStability
+interface ICas {
+    /**
+     * Close a session.
+     *
+     * @param sessionId The id of the session to be closed.
+     */
+    void closeSession(in byte[] sessionId);
+
+    /**
+     * Open a session to descramble one or more streams by specifying intention
+     * and scrambling mode.
+     *
+     * @param intent the intention of the session to be opened.
+     * @param mode the scrambling mode the session will use.
+     *
+     * @return sessionId The id of the newly opened session.
+     */
+    byte[] openSession(in SessionIntent intent, in ScramblingMode mode);
+
+    /**
+     * Process an ECM from the ECM stream for this session’s elementary stream.
+     *
+     * @param sessionId the id of the session which the ecm data applies to.
+     * @param ecm a byte array containing the ecm data.
+     */
+    void processEcm(in byte[] sessionId, in byte[] ecm);
+
+    /**
+     * Process an in-band EMM from the EMM stream.
+     *
+     * @param emm a byte array containing the emm data.
+     */
+    void processEmm(in byte[] emm);
+
+    /**
+     * Initiate a provisioning operation for a CA system.
+     *
+     * @param provisionString string containing information needed for the
+     * provisioning operation, the format of which is scheme and implementation
+     * specific.
+     */
+    void provision(in String provisionString);
+
+    /**
+     * Notify the CA system to refresh entitlement keys.
+     *
+     * @param refreshType the type of the refreshment.
+     * @param refreshData private data associated with the refreshment.
+     */
+    void refreshEntitlements(in int refreshType, in byte[] refreshData);
+
+    /**
+     * Release the descrambler instance.
+     */
+    void release();
+
+    /**
+     * Send an scheme-specific event to the CasPlugin.
+     *
+     * @param event an integer denoting a scheme-specific event to be sent.
+     * @param arg a scheme-specific integer argument for the event.
+     * @param data a byte array containing scheme-specific data for the event.
+     */
+    void sendEvent(in int event, in int arg, in byte[] eventData);
+
+    /**
+     * Send an scheme-specific session event to the CasPlugin.
+     *
+     * @param sessionId the id of an opened session.
+     * @param event an integer denoting a scheme-specific event to be sent.
+     * @param arg a scheme-specific integer argument for the event.
+     * @param data a byte array containing scheme-specific data for the event.
+     */
+    void sendSessionEvent(in byte[] sessionId, in int event, in int arg, in byte[] eventData);
+
+    /**
+     * Provide the CA private data from a CA_descriptor in the conditional
+     * access table to a CasPlugin.
+     *
+     * @param pvtData a byte array containing the private data, the format of
+     * which is scheme-specific and opaque to the framework.
+     */
+    void setPrivateData(in byte[] pvtData);
+
+    /**
+     * Provide the CA private data from a CA_descriptor in the program map
+     * table to a session.
+     *
+     * @param sessionId the id of the session which the private data applies to.
+     * @param pvtData a byte array containing the private data, the format of
+     * which is scheme-specific and opaque to the framework.
+     */
+    void setSessionPrivateData(in byte[] sessionId, in byte[] pvtData);
+}
diff --git a/cas/aidl/android/hardware/cas/ICasListener.aidl b/cas/aidl/android/hardware/cas/ICasListener.aidl
new file mode 100644
index 0000000..32d843f
--- /dev/null
+++ b/cas/aidl/android/hardware/cas/ICasListener.aidl
@@ -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 android.hardware.cas;
+
+import android.hardware.cas.StatusEvent;
+
+@VintfStability
+interface ICasListener {
+    /**
+     * Notify the listener of a scheme-specific event from the CA system.
+     *
+     * @param event an integer whose meaning is scheme-specific.
+     * @param arg an integer whose meaning is scheme-specific.
+     * @param data a byte array of data whose format and meaning are
+     * scheme-specific.
+     */
+    void onEvent(in int event, in int arg, in byte[] data);
+
+    /**
+     * Notify the listener of a scheme-specific session event from CA system.
+     *
+     * @param sessionId the id of an opened session.
+     * @param event an integer whose meaning is scheme-specific.
+     * @param arg an integer whose meaning is scheme-specific.
+     * @param data a byte array of data whose format and meaning are
+     * scheme-specific.
+     */
+    void onSessionEvent(in byte[] sessionId, in int event, in int arg, in byte[] data);
+
+    /**
+     * Notify the listener that the status of CAS system has changed.
+     *
+     * @param event the event type of status change.
+     * @param number value for status event.
+     *               For PLUGIN_PHYSICAL_MODULE_CHANGED event:
+     *               the positive number presents how many plugins are inserted;
+     *               the negative number presents how many plugins are removed.
+     *               Client must enumerate plugins after receive the event.
+     *               For PLUGIN_SESSION_NUMBER_CHANGED event:
+     *               the number presents how many sessions are supported
+     *               in the plugin.
+     */
+    void onStatusUpdate(in StatusEvent event, in int number);
+}
diff --git a/cas/aidl/android/hardware/cas/IDescrambler.aidl b/cas/aidl/android/hardware/cas/IDescrambler.aidl
new file mode 100644
index 0000000..33fbe75
--- /dev/null
+++ b/cas/aidl/android/hardware/cas/IDescrambler.aidl
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.cas;
+
+import android.hardware.cas.DestinationBuffer;
+import android.hardware.cas.ScramblingControl;
+import android.hardware.cas.SharedBuffer;
+import android.hardware.cas.SubSample;
+
+/**
+ * IDescrambler is the API to control the descrambling operations.
+ */
+@VintfStability
+interface IDescrambler {
+    /**
+     * Descramble the data in a source SharedBuffer, described by an array of
+     * SubSample structures.
+     *
+     * @param scramblingControl an enumeration indicating the key that the subsamples
+     * were scrambled with.
+     * @param subSamples an array of SubSample structures describing the number of
+     * clear and scrambled bytes within each subsample.
+     * @param srcBuffer the SharedBuffer containing the source scrambled data.
+     * @param srcOffset the position where the source scrambled data starts at.
+     * @param dstBuffer the DestinationBuffer to hold the descrambled data.
+     * @param dstOffset the position where the descrambled data should start at.
+     *
+     * @return bytesWritten Number of bytes that have been successfully written.
+     */
+    int descramble(in ScramblingControl scramblingControl, in SubSample[] subSamples,
+            in SharedBuffer srcBuffer, in long srcOffset, in DestinationBuffer dstBuffer,
+            in long dstOffset);
+
+    /**
+     * Release the descrambler instance.
+     */
+    void release();
+
+    /**
+     * Query if the scrambling scheme requires the use of a secure decoder
+     * to decode data of the given mime type.
+     *
+     * @param mime the mime type of the media data.
+     * @return whether the descrambler requires a secure decoder.
+     */
+    boolean requiresSecureDecoderComponent(in String mime);
+
+    /**
+     * Associate a MediaCas session with this MediaDescrambler instance.
+     *
+     * @param sessionId the id of the session to associate with this descrambler instance.
+     */
+    void setMediaCasSession(in byte[] sessionId);
+}
diff --git a/cas/aidl/android/hardware/cas/IMediaCasService.aidl b/cas/aidl/android/hardware/cas/IMediaCasService.aidl
new file mode 100644
index 0000000..8bc31f6
--- /dev/null
+++ b/cas/aidl/android/hardware/cas/IMediaCasService.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.cas;
+
+import android.hardware.cas.AidlCasPluginDescriptor;
+import android.hardware.cas.ICas;
+import android.hardware.cas.ICasListener;
+import android.hardware.cas.IDescrambler;
+
+/**
+ * IMediaCasService is the main entry point for interacting with a vendor's
+ * cas HAL to create cas and descrambler plugin instances. A cas plugin instance
+ * opens cas sessions which are used to obtain keys for a descrambler session,
+ * which can in turn be used to descramble protected video content.
+ */
+@VintfStability
+interface IMediaCasService {
+    /**
+     * Construct a new instance of a DescramblerPlugin given a CA_system_id.
+     *
+     * @param CA_system_id the id of the CA system.
+     * @return the newly created plugin interface.
+     */
+    IDescrambler createDescrambler(in int CA_system_id);
+
+    /**
+     * Construct a new instance of a CasPlugin given a CA_system_id.
+     *
+     * @param CA_system_id the id of the CA system.
+     * @param listener the event listener to receive events coming from the CasPlugin.
+     * @return the newly created CasPlugin interface.
+     */
+    ICas createPlugin(in int CA_system_id, in ICasListener listener);
+
+    /**
+     * List all available CA systems on the device.
+     *
+     * @return an array of descriptors for the available CA systems.
+     */
+    AidlCasPluginDescriptor[] enumeratePlugins();
+
+    /**
+     * Query if the descrambling scheme for a CA system is supported on this device.
+     *
+     * @param CA_system_id the id of the CA system.
+     * @return whether the specified descrambling scheme is supported on this device.
+     */
+    boolean isDescramblerSupported(in int CA_system_id);
+
+    /**
+     * Query if a certain CA system is supported on this device.
+     *
+     * @param CA_system_id the id of the CA system.
+     * @return whether the specified CA system is supported on this device.
+     */
+    boolean isSystemIdSupported(in int CA_system_id);
+}
diff --git a/cas/aidl/android/hardware/cas/ScramblingControl.aidl b/cas/aidl/android/hardware/cas/ScramblingControl.aidl
new file mode 100644
index 0000000..b36787c
--- /dev/null
+++ b/cas/aidl/android/hardware/cas/ScramblingControl.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.cas;
+
+/**
+ * Enumerates the keys used to scramble the content.
+ */
+@VintfStability
+@Backing(type="int")
+enum ScramblingControl {
+    UNSCRAMBLED = 0,
+    RESERVED = 1,
+    EVENKEY = 2,
+    ODDKEY = 3,
+}
diff --git a/cas/aidl/android/hardware/cas/ScramblingMode.aidl b/cas/aidl/android/hardware/cas/ScramblingMode.aidl
new file mode 100644
index 0000000..9d73eba
--- /dev/null
+++ b/cas/aidl/android/hardware/cas/ScramblingMode.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.cas;
+
+/**
+ * The Scrambling Mode.
+ */
+@VintfStability
+@Backing(type="int")
+enum ScramblingMode {
+    RESERVED = 0,
+
+    /**
+     * DVB (Digital Video Broadcasting) CSA1 (Common Scrambling Algorithm 1) is
+     * the default mode and shall be used when the scrambling descriptor
+     * is not present in the program map section. DVB scrambling mode is
+     * specified in ETSI EN 300 468 specification.
+     */
+    DVB_CSA1,
+
+    DVB_CSA2,
+
+    /**
+     * DVB-CSA3 in standard mode.
+     */
+    DVB_CSA3_STANDARD,
+
+    /**
+     * DVB-CSA3 in minimally enhanced mode.
+     */
+    DVB_CSA3_MINIMAL,
+
+    /**
+     * DVB-CSA3 in fully enhanced mode.
+     */
+    DVB_CSA3_ENHANCE,
+
+    /**
+     * DVB-CISSA version 1.
+     */
+    DVB_CISSA_V1,
+
+    /**
+     * ATIS-0800006 IIF Default Scrambling Algorithm (IDSA).
+     */
+    DVB_IDSA,
+
+    /**
+     * a symmetric key algorithm.
+     */
+    MULTI2,
+
+    /**
+     * Advanced Encryption System (AES) 128-bit Encryption mode.
+     */
+    AES128,
+
+    /**
+     * Advanced Encryption System (AES) Cipher Block Chaining (CBC) mode.
+     */
+    AES_CBC,
+
+    /**
+     * Advanced Encryption System (AES) Electronic Code Book (ECB) mode.
+     */
+    AES_ECB,
+
+    /**
+     * Advanced Encryption System (AES) Society of Cable Telecommunications
+     * Engineers (SCTE) 52 mode.
+     */
+    AES_SCTE52,
+
+    /**
+     * Triple Data Encryption Algorithm (TDES) Electronic Code Book (ECB) mode.
+     */
+    TDES_ECB,
+
+    /**
+     * Triple Data Encryption Algorithm (TDES) Society of Cable Telecommunications
+     * Engineers (SCTE) 52 mode.
+     */
+    TDES_SCTE52,
+}
diff --git a/cas/aidl/android/hardware/cas/SessionIntent.aidl b/cas/aidl/android/hardware/cas/SessionIntent.aidl
new file mode 100644
index 0000000..844deab
--- /dev/null
+++ b/cas/aidl/android/hardware/cas/SessionIntent.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.cas;
+
+/**
+ * The intented usage for the session.
+ */
+@VintfStability
+@Backing(type="int")
+enum SessionIntent {
+    /**
+     * Live Stream.
+     */
+    LIVE,
+
+    /**
+     * Playback Recorded Stream.
+     */
+    PLAYBACK,
+
+    /**
+     * Record Live Stream.
+     */
+    RECORD,
+
+    /**
+     * View the content with Time Shift capability
+     */
+    TIMESHIFT,
+}
diff --git a/cas/aidl/android/hardware/cas/SharedBuffer.aidl b/cas/aidl/android/hardware/cas/SharedBuffer.aidl
new file mode 100644
index 0000000..8a94ff7
--- /dev/null
+++ b/cas/aidl/android/hardware/cas/SharedBuffer.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.cas;
+
+import android.hardware.common.Ashmem;
+
+/**
+ * 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.
+ */
+@VintfStability
+parcelable SharedBuffer {
+    /**
+     * Ashmem shared memory
+     */
+    Ashmem heapBase;
+
+    /**
+     * The offset from the shared memory base
+     */
+    long offset;
+
+    /**
+     * The size of the shared buffer in bytes
+     */
+    long size;
+}
diff --git a/cas/aidl/android/hardware/cas/Status.aidl b/cas/aidl/android/hardware/cas/Status.aidl
new file mode 100644
index 0000000..b2be34b
--- /dev/null
+++ b/cas/aidl/android/hardware/cas/Status.aidl
@@ -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.
+ */
+
+package android.hardware.cas;
+
+@VintfStability
+parcelable Status {
+    /**
+     * The CAS plugin must return OK when an operation completes without any
+     * errors.
+     */
+    const int OK = 0;
+
+    /**
+     * The CAS plugin must return ERROR_CAS_NO_LICENSE, when descrambling is
+     * attempted and no license keys have been provided.
+     */
+    const int ERROR_CAS_NO_LICENSE = -1;
+
+    /**
+     * ERROR_CAS_LICENSE_EXPIRED must be returned when an attempt is made
+     * to use a license and the keys in that license have expired.
+     */
+    const int ERROR_CAS_LICENSE_EXPIRED = -2;
+
+    /**
+     * The CAS plugin must return ERROR_CAS_SESSION_NOT_OPENED when an
+     * attempt is made to use a session that has not been opened.
+     */
+    const int ERROR_CAS_SESSION_NOT_OPENED = -3;
+
+    /**
+     * The CAS plugin must return ERROR_CAS_CANNOT_HANDLE when an unsupported
+     * data format or operation is attempted.
+     */
+    const int ERROR_CAS_CANNOT_HANDLE = -4;
+
+    /**
+     * ERROR_CAS_INVALID_STATE must be returned when the device is in a state
+     * where it is not able to perform descrambling.
+     */
+    const int ERROR_CAS_INVALID_STATE = -5;
+
+    /**
+     * The CAS plugin must return BAD_VALUE whenever an illegal parameter is
+     * passed to one of the interface functions.
+     */
+    const int BAD_VALUE = -6;
+
+    /**
+     * The CAS plugin must return ERROR_CAS_NOT_PROVISIONED when the device
+     * has not yet been provisioned.
+     */
+    const int ERROR_CAS_NOT_PROVISIONED = -7;
+
+    /**
+     * ERROR_CAS_RESOURCE_BUSY must be returned when resources, such as CAS
+     * sessions or secure buffers are not available to perform a requested
+     * operation because they are already in use.
+     */
+    const int ERROR_CAS_RESOURCE_BUSY = -8;
+
+    /**
+     * The CAS Plugin must return ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION
+     * when the output protection level enabled on the device is not
+     * sufficient to meet the requirements in the license policy. HDCP is an
+     * example of a form of output protection.
+     */
+    const int ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION = -9;
+
+    /**
+     * The CAS Plugin must return ERROR_CAS_TAMPER_DETECTED if an attempt to
+     * tamper with the CAS system is detected.
+     */
+    const int ERROR_CAS_TAMPER_DETECTED = -10;
+
+    /**
+     * The CAS Plugin must return ERROR_CAS_DEVICE_REVOKED if the response
+     * indicates that the device has been revoked. Device revocation means
+     * that the device is no longer permitted to play content.
+     */
+    const int ERROR_CAS_DEVICE_REVOKED = -11;
+
+    /**
+     * The CAS plugin must return ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED when
+     * descrambling is failing because the session is not initialized properly.
+     */
+    const int ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED = -12;
+
+    /**
+     * The CAS Plugin must return ERROR_CAS_DECRYPT if the DescramblerPlugin's
+     * descramble operation fails.
+     */
+    const int ERROR_CAS_DECRYPT = -13;
+
+    /**
+     * ERROR_CAS_UNKNOWN must be returned when a fatal failure occurs and no
+     * other defined error is appropriate.
+     */
+    const int ERROR_CAS_UNKNOWN = -14;
+
+    /**
+     * ERROR_CAS_NEED_ACTIVATION is used to trigger device activation process.
+     */
+    const int ERROR_CAS_NEED_ACTIVATION = -15;
+
+    /**
+     * ERROR_CAS_NEED_PAIRING is used to trigger pairing process.
+     */
+    const int ERROR_CAS_NEED_PAIRING = -16;
+
+    /**
+     * ERROR_CAS_NO_CARD is used to report no smart card for descrambling.
+     */
+    const int ERROR_CAS_NO_CARD = -17;
+
+    /**
+     * ERROR_CAS_CARD_MUTE is used to report smart card is muted for
+     * descrambling.
+     */
+    const int ERROR_CAS_CARD_MUTE = -18;
+
+    /**
+     *  ERROR_CAS_CARD_INVALID is used to report smart card isn't valid.
+     */
+    const int ERROR_CAS_CARD_INVALID = -19;
+
+    /**
+     *  ERROR_CAS_BLACKOUT is used to report geographical blackout.
+     */
+    const int ERROR_CAS_BLACKOUT = -20;
+
+    /**
+     * ERROR_CAS_REBOOTING is used to report CAS is during rebooting.
+     */
+    const int ERROR_CAS_REBOOTING = -21;
+}
diff --git a/cas/aidl/android/hardware/cas/StatusEvent.aidl b/cas/aidl/android/hardware/cas/StatusEvent.aidl
new file mode 100644
index 0000000..0f62634
--- /dev/null
+++ b/cas/aidl/android/hardware/cas/StatusEvent.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.
+ */
+
+package android.hardware.cas;
+
+/**
+ * The Event Type for status change.
+ */
+@VintfStability
+@Backing(type="byte")
+enum StatusEvent {
+    /**
+     * The status of CAS plugin was changed due to physical module insertion or
+     * removal. Client must call enumeratePlugins to update plugins' status.
+     */
+    PLUGIN_PHYSICAL_MODULE_CHANGED,
+
+    /**
+     * The status of supported session number was changed due to physical module
+     * insertion or removal. Client must update session resource according to
+     * latest StatusMessage from the StatusEvent. The plugin supports unlimited
+     * session by default.
+     */
+    PLUGIN_SESSION_NUMBER_CHANGED,
+}
diff --git a/cas/aidl/android/hardware/cas/SubSample.aidl b/cas/aidl/android/hardware/cas/SubSample.aidl
new file mode 100644
index 0000000..c1353cb
--- /dev/null
+++ b/cas/aidl/android/hardware/cas/SubSample.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.cas;
+
+/**
+ * A subsample consists of some number of bytes of clear (unscrambled)
+ * data followed by a number of bytes of scrambled data.
+ */
+@VintfStability
+parcelable SubSample {
+    int numBytesOfClearData;
+    int numBytesOfEncryptedData;
+}
diff --git a/cas/aidl/default/Android.bp b/cas/aidl/default/Android.bp
new file mode 100755
index 0000000..3c16d57
--- /dev/null
+++ b/cas/aidl/default/Android.bp
@@ -0,0 +1,93 @@
+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: "libcasexampleimpl",
+    vendor_available: true,
+
+    srcs: [
+        "CasImpl.cpp",
+        "DescramblerImpl.cpp",
+        "MediaCasService.cpp",
+        "SharedLibrary.cpp",
+        "TypeConvert.cpp",
+    ],
+
+    shared_libs: [
+        "android.hardware.cas-V1-ndk",
+        "libbinder_ndk",
+        "liblog",
+        "libutils",
+        "libcutils",
+    ],
+    static_libs: [
+        "libaidlcommonsupport",
+    ],
+    header_libs: [
+        "libstagefright_foundation_headers",
+        "media_plugin_headers",
+    ],
+}
+
+cc_defaults {
+    name: "cas_service_example_defaults",
+    vendor: true,
+    relative_install_path: "hw",
+
+    srcs: ["service.cpp"],
+
+    static_libs: [
+        "libaidlcommonsupport",
+        "libcasexampleimpl",
+    ],
+    shared_libs: [
+        "android.hardware.cas-V1-ndk",
+        "libbinder_ndk",
+        "liblog",
+        "libutils",
+        "libcutils",
+    ],
+    header_libs: ["media_plugin_headers"],
+    vintf_fragments: ["android.hardware.cas-service.xml"],
+}
+
+cc_binary {
+    name: "android.hardware.cas-service.example",
+    defaults: ["cas_service_example_defaults"],
+    init_rc: ["cas-default.rc"],
+}
+
+cc_binary {
+    name: "android.hardware.cas-service.example-lazy",
+    defaults: ["cas_service_example_defaults"],
+    init_rc: ["cas-default-lazy.rc"],
+    cflags: ["-DLAZY_SERVICE"],
+}
+
+cc_fuzz {
+    name: "android.hardware.cas-service_fuzzer",
+    vendor: true,
+
+    defaults: ["service_fuzzer_defaults"],
+    srcs: ["fuzzer.cpp"],
+
+    shared_libs: [
+        "android.hardware.cas-V1-ndk",
+        "libcutils",
+        "liblog",
+    ],
+    static_libs: [
+        "libaidlcommonsupport",
+        "libcasexampleimpl",
+    ],
+    header_libs: ["media_plugin_headers"],
+    fuzz_config: {
+        componentid: 1344,
+    },
+}
diff --git a/cas/aidl/default/CasImpl.cpp b/cas/aidl/default/CasImpl.cpp
new file mode 100755
index 0000000..2d31b35
--- /dev/null
+++ b/cas/aidl/default/CasImpl.cpp
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ icensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.cas-CasImpl"
+
+#include <media/cas/CasAPI.h>
+#include <utils/Log.h>
+
+#include "CasImpl.h"
+#include "TypeConvert.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace cas {
+
+CasImpl::CasImpl(const shared_ptr<ICasListener>& listener) : mListener(listener) {
+    ALOGV("CTOR");
+}
+
+CasImpl::~CasImpl() {
+    ALOGV("DTOR");
+    release();
+}
+
+// static
+void CasImpl::OnEvent(void* appData, int32_t event, int32_t arg, uint8_t* data, size_t size) {
+    if (appData == NULL) {
+        ALOGE("Invalid appData!");
+        return;
+    }
+    CasImpl* casImpl = static_cast<CasImpl*>(appData);
+    casImpl->onEvent(event, arg, data, size);
+}
+
+// static
+void CasImpl::CallBackExt(void* appData, int32_t event, int32_t arg, uint8_t* data, size_t size,
+                          const CasSessionId* sessionId) {
+    if (appData == NULL) {
+        ALOGE("Invalid appData!");
+        return;
+    }
+    CasImpl* casImpl = static_cast<CasImpl*>(appData);
+    casImpl->onEvent(sessionId, event, arg, data, size);
+}
+
+// static
+void CasImpl::StatusUpdate(void* appData, int32_t event, int32_t arg) {
+    if (appData == NULL) {
+        ALOGE("Invalid appData!");
+        return;
+    }
+    CasImpl* casImpl = static_cast<CasImpl*>(appData);
+    casImpl->onStatusUpdate(event, arg);
+}
+
+void CasImpl::init(CasPlugin* plugin) {
+    shared_ptr<CasPlugin> holder(plugin);
+    atomic_store(&mPluginHolder, holder);
+}
+
+void CasImpl::onEvent(int32_t event, int32_t arg, uint8_t* data, size_t size) {
+    if (mListener == NULL) {
+        return;
+    }
+
+    vector<uint8_t> eventData;
+    if (data != NULL) {
+        eventData.assign(data, data + size);
+    }
+
+    mListener->onEvent(event, arg, eventData);
+}
+
+void CasImpl::onEvent(const CasSessionId* sessionId, int32_t event, int32_t arg, uint8_t* data,
+                      size_t size) {
+    if (mListener == NULL) {
+        return;
+    }
+
+    vector<uint8_t> eventData;
+    if (data != NULL) {
+        eventData.assign(data, data + size);
+    }
+
+    if (sessionId != NULL) {
+        mListener->onSessionEvent(*sessionId, event, arg, eventData);
+    } else {
+        mListener->onEvent(event, arg, eventData);
+    }
+}
+
+void CasImpl::onStatusUpdate(int32_t event, int32_t arg) {
+    if (mListener == NULL) {
+        return;
+    }
+    mListener->onStatusUpdate(static_cast<StatusEvent>(event), arg);
+}
+
+ScopedAStatus CasImpl::setPluginStatusUpdateCallback() {
+    ALOGV("%s", __FUNCTION__);
+    shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+    return toStatus(holder->setStatusCallback(&CasImpl::StatusUpdate));
+}
+
+ScopedAStatus CasImpl::setPrivateData(const vector<uint8_t>& pvtData) {
+    ALOGV("%s", __FUNCTION__);
+    shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+    return toStatus(holder->setPrivateData(pvtData));
+}
+
+ScopedAStatus CasImpl::openSession(SessionIntent intent, ScramblingMode mode,
+                                   vector<uint8_t>* sessionId) {
+    ALOGV("%s", __FUNCTION__);
+
+    shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
+    status_t err = INVALID_OPERATION;
+    if (holder.get() != nullptr) {
+        err = holder->openSession(static_cast<uint32_t>(intent), static_cast<uint32_t>(mode),
+                                  sessionId);
+        holder.reset();
+    }
+
+    return toStatus(err);
+}
+
+ScopedAStatus CasImpl::setSessionPrivateData(const vector<uint8_t>& sessionId,
+                                             const vector<uint8_t>& pvtData) {
+    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string());
+    shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+    return toStatus(holder->setSessionPrivateData(sessionId, pvtData));
+}
+
+ScopedAStatus CasImpl::closeSession(const vector<uint8_t>& sessionId) {
+    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string());
+    shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+    return toStatus(holder->closeSession(sessionId));
+}
+
+ScopedAStatus CasImpl::processEcm(const vector<uint8_t>& sessionId, const vector<uint8_t>& ecm) {
+    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string());
+    shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+
+    return toStatus(holder->processEcm(sessionId, ecm));
+}
+
+ScopedAStatus CasImpl::processEmm(const vector<uint8_t>& emm) {
+    ALOGV("%s", __FUNCTION__);
+    shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+
+    return toStatus(holder->processEmm(emm));
+}
+
+ScopedAStatus CasImpl::sendEvent(int32_t event, int32_t arg, const vector<uint8_t>& eventData) {
+    ALOGV("%s", __FUNCTION__);
+    shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+
+    status_t err = holder->sendEvent(event, arg, eventData);
+    return toStatus(err);
+}
+
+ScopedAStatus CasImpl::sendSessionEvent(const vector<uint8_t>& sessionId, int32_t event,
+                                        int32_t arg, const vector<uint8_t>& eventData) {
+    ALOGV("%s", __FUNCTION__);
+    shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+
+    status_t err = holder->sendSessionEvent(sessionId, event, arg, eventData);
+    return toStatus(err);
+}
+
+ScopedAStatus CasImpl::provision(const string& provisionString) {
+    ALOGV("%s: provisionString=%s", __FUNCTION__, provisionString.c_str());
+    shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+
+    return toStatus(holder->provision(String8(provisionString.c_str())));
+}
+
+ScopedAStatus CasImpl::refreshEntitlements(int32_t refreshType,
+                                           const vector<uint8_t>& refreshData) {
+    ALOGV("%s", __FUNCTION__);
+    shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+
+    status_t err = holder->refreshEntitlements(refreshType, refreshData);
+    return toStatus(err);
+}
+
+ScopedAStatus CasImpl::release() {
+    ALOGV("%s: plugin=%p", __FUNCTION__, mPluginHolder.get());
+
+    shared_ptr<CasPlugin> holder(nullptr);
+    atomic_store(&mPluginHolder, holder);
+
+    return ScopedAStatus::ok();
+}
+
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/cas/aidl/default/CasImpl.h b/cas/aidl/default/CasImpl.h
new file mode 100755
index 0000000..84a8115
--- /dev/null
+++ b/cas/aidl/default/CasImpl.h
@@ -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.
+ */
+
+#include <aidl/android/hardware/cas/BnCas.h>
+#include <aidl/android/hardware/cas/ICasListener.h>
+#include <media/stagefright/foundation/ABase.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace cas {
+
+using namespace ::android;
+using namespace std;
+using ndk::ScopedAStatus;
+
+class CasImpl : public BnCas {
+  public:
+    CasImpl(const shared_ptr<ICasListener>& listener);
+    virtual ~CasImpl();
+
+    static void OnEvent(void* appData, int32_t event, int32_t arg, uint8_t* data, size_t size);
+
+    static void CallBackExt(void* appData, int32_t event, int32_t arg, uint8_t* data, size_t size,
+                            const CasSessionId* sessionId);
+
+    static void StatusUpdate(void* appData, int32_t event, int32_t arg);
+
+    void init(CasPlugin* plugin);
+    void onEvent(int32_t event, int32_t arg, uint8_t* data, size_t size);
+
+    void onEvent(const CasSessionId* sessionId, int32_t event, int32_t arg, uint8_t* data,
+                 size_t size);
+
+    void onStatusUpdate(int32_t event, int32_t arg);
+
+    // ICas inherits
+
+    ScopedAStatus setPluginStatusUpdateCallback();
+
+    virtual ScopedAStatus setPrivateData(const vector<uint8_t>& pvtData) override;
+
+    virtual ScopedAStatus openSession(SessionIntent intent, ScramblingMode mode,
+                                      vector<uint8_t>* sessionId) override;
+
+    virtual ScopedAStatus closeSession(const vector<uint8_t>& sessionId) override;
+
+    virtual ScopedAStatus setSessionPrivateData(const vector<uint8_t>& sessionId,
+                                                const vector<uint8_t>& pvtData) override;
+
+    virtual ScopedAStatus processEcm(const vector<uint8_t>& sessionId,
+                                     const vector<uint8_t>& ecm) override;
+
+    virtual ScopedAStatus processEmm(const vector<uint8_t>& emm) override;
+
+    virtual ScopedAStatus sendEvent(int32_t event, int32_t arg,
+                                    const vector<uint8_t>& eventData) override;
+
+    virtual ScopedAStatus sendSessionEvent(const vector<uint8_t>& sessionId, int32_t event,
+                                           int32_t arg, const vector<uint8_t>& eventData) override;
+
+    virtual ScopedAStatus provision(const string& provisionString) override;
+
+    virtual ScopedAStatus refreshEntitlements(int32_t refreshType,
+                                              const vector<uint8_t>& refreshData) override;
+
+    virtual ScopedAStatus release() override;
+
+  private:
+    struct PluginHolder;
+    shared_ptr<CasPlugin> mPluginHolder;
+    shared_ptr<ICasListener> mListener;
+
+    DISALLOW_EVIL_CONSTRUCTORS(CasImpl);
+};
+
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/cas/aidl/default/DescramblerImpl.cpp b/cas/aidl/default/DescramblerImpl.cpp
new file mode 100755
index 0000000..a96fd46
--- /dev/null
+++ b/cas/aidl/default/DescramblerImpl.cpp
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.cas-DescramblerImpl"
+
+#include <aidlcommonsupport/NativeHandle.h>
+#include <inttypes.h>
+#include <media/cas/DescramblerAPI.h>
+#include <media/hardware/CryptoAPI.h>
+#include <media/stagefright/foundation/AUtils.h>
+#include <sys/mman.h>
+#include <utils/Log.h>
+
+#include "DescramblerImpl.h"
+#include "TypeConvert.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace cas {
+
+#define CHECK_SUBSAMPLE_DEF(type)                                                                 \
+    static_assert(sizeof(SubSample) == sizeof(type::SubSample), "SubSample: size doesn't match"); \
+    static_assert(offsetof(SubSample, numBytesOfClearData) ==                                     \
+                          offsetof(type::SubSample, mNumBytesOfClearData),                        \
+                  "SubSample: numBytesOfClearData offset doesn't match");                         \
+    static_assert(offsetof(SubSample, numBytesOfEncryptedData) ==                                 \
+                          offsetof(type::SubSample, mNumBytesOfEncryptedData),                    \
+                  "SubSample: numBytesOfEncryptedData offset doesn't match")
+
+CHECK_SUBSAMPLE_DEF(DescramblerPlugin);
+CHECK_SUBSAMPLE_DEF(CryptoPlugin);
+
+DescramblerImpl::DescramblerImpl(DescramblerPlugin* plugin) : mPluginHolder(plugin) {
+    ALOGV("CTOR: plugin=%p", mPluginHolder.get());
+}
+
+DescramblerImpl::~DescramblerImpl() {
+    ALOGV("DTOR: plugin=%p", mPluginHolder.get());
+    release();
+}
+
+ScopedAStatus DescramblerImpl::setMediaCasSession(const vector<uint8_t>& in_sessionId) {
+    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(in_sessionId).string());
+
+    shared_ptr<DescramblerPlugin> holder = atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+
+    return toStatus(holder->setMediaCasSession(in_sessionId));
+}
+
+ScopedAStatus DescramblerImpl::requiresSecureDecoderComponent(const string& in_mime,
+                                                              bool* _aidl_return) {
+    shared_ptr<DescramblerPlugin> holder = atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        *_aidl_return = false;
+    }
+
+    *_aidl_return = holder->requiresSecureDecoderComponent(String8(in_mime.c_str()));
+    return ScopedAStatus::ok();
+}
+
+static inline bool validateRangeForSize(int64_t offset, int64_t length, int64_t size) {
+    return isInRange<int64_t, uint64_t>(0, (uint64_t)size, offset, (uint64_t)length);
+}
+
+ScopedAStatus DescramblerImpl::descramble(ScramblingControl scramblingControl,
+                                          const vector<SubSample>& subSamples,
+                                          const SharedBuffer& srcBuffer, int64_t srcOffset,
+                                          const DestinationBuffer& dstBuffer, int64_t dstOffset,
+                                          int32_t* _aidl_return) {
+    ALOGV("%s", __FUNCTION__);
+
+    // heapbase's size is stored in int64_t, but mapMemory's mmap will map size in
+    // size_t. If size is over SIZE_MAX, mapMemory mapMemory could succeed but the
+    // mapped memory's actual size will be smaller than the reported size.
+    if (srcBuffer.heapBase.size > SIZE_MAX) {
+        ALOGE("Invalid memory size: %" PRIu64 "", srcBuffer.heapBase.size);
+        android_errorWriteLog(0x534e4554, "79376389");
+        return toStatus(BAD_VALUE);
+    }
+
+    void* srcPtr = mmap(NULL, srcBuffer.heapBase.size, PROT_READ | PROT_WRITE, MAP_SHARED,
+                        srcBuffer.heapBase.fd.get(), 0);
+
+    // Validate if the offset and size in the SharedBuffer is consistent with the
+    // mapped heapbase, since the offset and size is controlled by client.
+    if (srcPtr == NULL) {
+        ALOGE("Failed to map src buffer.");
+        return toStatus(BAD_VALUE);
+    }
+    if (!validateRangeForSize(srcBuffer.offset, srcBuffer.size, srcBuffer.heapBase.size)) {
+        ALOGE("Invalid src buffer range: offset %" PRIu64 ", size %" PRIu64
+              ", srcMem"
+              "size %" PRIu64 "",
+              srcBuffer.offset, srcBuffer.size, srcBuffer.heapBase.size);
+        android_errorWriteLog(0x534e4554, "67962232");
+        return toStatus(BAD_VALUE);
+    }
+
+    // use 64-bit here to catch bad subsample size that might be overflowing.
+    uint64_t totalBytesInSubSamples = 0;
+    for (size_t i = 0; i < subSamples.size(); i++) {
+        uint32_t numBytesOfClearData = subSamples[i].numBytesOfClearData;
+        uint32_t numBytesOfEncryptedData = subSamples[i].numBytesOfEncryptedData;
+        totalBytesInSubSamples += (uint64_t)numBytesOfClearData + numBytesOfEncryptedData;
+    }
+    // Further validate if the specified srcOffset and requested total subsample size
+    // is consistent with the source shared buffer size.
+    if (!validateRangeForSize(srcOffset, totalBytesInSubSamples, srcBuffer.size)) {
+        ALOGE("Invalid srcOffset and subsample size: "
+              "srcOffset %" PRIu64 ", totalBytesInSubSamples %" PRIu64
+              ", srcBuffer"
+              "size %" PRIu64 "",
+              srcOffset, totalBytesInSubSamples, srcBuffer.size);
+        android_errorWriteLog(0x534e4554, "67962232");
+        return toStatus(BAD_VALUE);
+    }
+    srcPtr = (uint8_t*)srcPtr + srcBuffer.offset;
+
+    void* dstPtr = NULL;
+    if (dstBuffer.getTag() == DestinationBuffer::Tag::nonsecureMemory) {
+        // When using shared memory, src buffer is also used as dst,
+        // we don't map it again here.
+        dstPtr = srcPtr;
+
+        // In this case the dst and src would be the same buffer, need to validate
+        // dstOffset against the buffer size too.
+        if (!validateRangeForSize(dstOffset, totalBytesInSubSamples, srcBuffer.size)) {
+            ALOGE("Invalid dstOffset and subsample size: "
+                  "dstOffset %" PRIu64 ", totalBytesInSubSamples %" PRIu64
+                  ", srcBuffer"
+                  "size %" PRIu64 "",
+                  dstOffset, totalBytesInSubSamples, srcBuffer.size);
+            android_errorWriteLog(0x534e4554, "67962232");
+            return toStatus(BAD_VALUE);
+        }
+    } else {
+        native_handle_t* handle = makeFromAidl(dstBuffer.get<DestinationBuffer::secureMemory>());
+        dstPtr = static_cast<void*>(handle);
+    }
+
+    // Get a local copy of the shared_ptr for the plugin. Note that before
+    // calling the callback, this shared_ptr must be manually reset, since
+    // the client side could proceed as soon as the callback is called
+    // without waiting for this method to go out of scope.
+    shared_ptr<DescramblerPlugin> holder = atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+
+    // Casting SubSample to DescramblerPlugin::SubSample, but need to ensure
+    // structs are actually identical
+
+    auto returnStatus =
+            holder->descramble(dstBuffer.getTag() != DestinationBuffer::Tag::nonsecureMemory,
+                               (DescramblerPlugin::ScramblingControl)scramblingControl,
+                               subSamples.size(), (DescramblerPlugin::SubSample*)subSamples.data(),
+                               srcPtr, srcOffset, dstPtr, dstOffset, NULL);
+
+    holder.reset();
+    *_aidl_return = returnStatus;
+    return toStatus(returnStatus >= 0 ? OK : returnStatus);
+}
+
+ScopedAStatus DescramblerImpl::release() {
+    ALOGV("%s: plugin=%p", __FUNCTION__, mPluginHolder.get());
+
+    shared_ptr<DescramblerPlugin> holder(nullptr);
+    atomic_store(&mPluginHolder, holder);
+
+    return ScopedAStatus::ok();
+}
+
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/cas/aidl/default/DescramblerImpl.h b/cas/aidl/default/DescramblerImpl.h
new file mode 100755
index 0000000..2efc1a0
--- /dev/null
+++ b/cas/aidl/default/DescramblerImpl.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.
+ */
+
+#include <aidl/android/hardware/cas/BnDescrambler.h>
+#include <media/stagefright/foundation/ABase.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace cas {
+
+using namespace ::android;
+using namespace std;
+using ndk::ScopedAStatus;
+
+class DescramblerImpl : public BnDescrambler {
+  public:
+    DescramblerImpl(DescramblerPlugin* plugin);
+    virtual ~DescramblerImpl();
+
+    virtual ScopedAStatus setMediaCasSession(const vector<uint8_t>& in_sessionId) override;
+
+    virtual ScopedAStatus requiresSecureDecoderComponent(const string& in_mime,
+                                                         bool* _aidl_return) override;
+
+    virtual ScopedAStatus descramble(ScramblingControl in_scramblingControl,
+                                     const vector<SubSample>& in_subSamples,
+                                     const SharedBuffer& in_srcBuffer, int64_t in_srcOffset,
+                                     const DestinationBuffer& in_dstBuffer, int64_t in_dstOffset,
+                                     int32_t* _aidl_return) override;
+
+    virtual ScopedAStatus release() override;
+
+  private:
+    shared_ptr<DescramblerPlugin> mPluginHolder;
+
+    DISALLOW_EVIL_CONSTRUCTORS(DescramblerImpl);
+};
+
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/cas/aidl/default/FactoryLoader.h b/cas/aidl/default/FactoryLoader.h
new file mode 100755
index 0000000..f90b109
--- /dev/null
+++ b/cas/aidl/default/FactoryLoader.h
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dirent.h>
+#include <dlfcn.h>
+#include <media/cas/CasAPI.h>
+#include <utils/KeyedVector.h>
+#include <utils/Mutex.h>
+#include "SharedLibrary.h"
+
+using namespace std;
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace cas {
+
+using namespace ::android;
+
+template <class T>
+class FactoryLoader {
+  public:
+    FactoryLoader(const char* name) : mFactory(NULL), mCreateFactoryFuncName(name) {}
+
+    virtual ~FactoryLoader() { closeFactory(); }
+
+    bool findFactoryForScheme(int32_t CA_system_id, shared_ptr<SharedLibrary>* library = NULL,
+                              T** factory = NULL);
+
+    bool enumeratePlugins(vector<AidlCasPluginDescriptor>* results);
+
+  private:
+    typedef T* (*CreateFactoryFunc)();
+
+    Mutex mMapLock;
+    T* mFactory;
+    const char* mCreateFactoryFuncName;
+    shared_ptr<SharedLibrary> mLibrary;
+    KeyedVector<int32_t, String8> mCASystemIdToLibraryPathMap;
+    KeyedVector<String8, shared_ptr<SharedLibrary>> mLibraryPathToOpenLibraryMap;
+
+    bool loadFactoryForSchemeFromPath(const String8& path, int32_t CA_system_id,
+                                      shared_ptr<SharedLibrary>* library, T** factory);
+
+    bool queryPluginsFromPath(const String8& path, vector<AidlCasPluginDescriptor>* results);
+
+    bool openFactory(const String8& path);
+    void closeFactory();
+};
+
+template <class T>
+bool FactoryLoader<T>::findFactoryForScheme(int32_t CA_system_id,
+                                            shared_ptr<SharedLibrary>* library, T** factory) {
+    if (library != NULL) {
+        library->reset();
+    }
+    if (factory != NULL) {
+        *factory = NULL;
+    }
+
+    Mutex::Autolock autoLock(mMapLock);
+
+    // first check cache
+    ssize_t index = mCASystemIdToLibraryPathMap.indexOfKey(CA_system_id);
+    if (index >= 0) {
+        return loadFactoryForSchemeFromPath(mCASystemIdToLibraryPathMap[index], CA_system_id,
+                                            library, factory);
+    }
+
+    // no luck, have to search
+#ifdef __LP64__
+    String8 dirPath("/vendor/lib64/mediacas");
+#else
+    String8 dirPath("/vendor/lib/mediacas");
+#endif
+    DIR* pDir = opendir(dirPath.string());
+
+    if (pDir == NULL) {
+        ALOGE("Failed to open plugin directory %s", dirPath.string());
+        return false;
+    }
+
+    struct dirent* pEntry;
+    while ((pEntry = readdir(pDir))) {
+        String8 pluginPath = dirPath + "/" + pEntry->d_name;
+        if (pluginPath.getPathExtension() == ".so") {
+            if (loadFactoryForSchemeFromPath(pluginPath, CA_system_id, library, factory)) {
+                mCASystemIdToLibraryPathMap.add(CA_system_id, pluginPath);
+                closedir(pDir);
+
+                return true;
+            }
+        }
+    }
+
+    closedir(pDir);
+
+    ALOGE("Failed to find plugin");
+    return false;
+}
+
+template <class T>
+bool FactoryLoader<T>::enumeratePlugins(vector<AidlCasPluginDescriptor>* results) {
+    ALOGI("enumeratePlugins");
+
+    results->clear();
+
+#ifdef __LP64__
+    String8 dirPath("/vendor/lib64/mediacas");
+#else
+    String8 dirPath("/vendor/lib/mediacas");
+#endif
+    DIR* pDir = opendir(dirPath.string());
+
+    if (pDir == NULL) {
+        ALOGE("Failed to open plugin directory %s", dirPath.string());
+        return false;
+    }
+
+    Mutex::Autolock autoLock(mMapLock);
+
+    struct dirent* pEntry;
+    while ((pEntry = readdir(pDir))) {
+        String8 pluginPath = dirPath + "/" + pEntry->d_name;
+        if (pluginPath.getPathExtension() == ".so") {
+            queryPluginsFromPath(pluginPath, results);
+        }
+    }
+    return true;
+}
+
+template <class T>
+bool FactoryLoader<T>::loadFactoryForSchemeFromPath(const String8& path, int32_t CA_system_id,
+                                                    shared_ptr<SharedLibrary>* library,
+                                                    T** factory) {
+    closeFactory();
+
+    if (!openFactory(path) || !mFactory->isSystemIdSupported(CA_system_id)) {
+        closeFactory();
+        return false;
+    }
+
+    if (library != NULL) {
+        *library = mLibrary;
+    }
+    if (factory != NULL) {
+        *factory = mFactory;
+    }
+    return true;
+}
+
+template <class T>
+bool FactoryLoader<T>::queryPluginsFromPath(const String8& path,
+                                            vector<AidlCasPluginDescriptor>* results) {
+    closeFactory();
+
+    vector<CasPluginDescriptor> descriptors;
+    if (!openFactory(path) || mFactory->queryPlugins(&descriptors) != OK) {
+        closeFactory();
+        return false;
+    }
+
+    for (auto it = descriptors.begin(); it != descriptors.end(); it++) {
+        results->push_back(
+                AidlCasPluginDescriptor{.caSystemId = it->CA_system_id, .name = it->name.c_str()});
+    }
+    return true;
+}
+
+template <class T>
+bool FactoryLoader<T>::openFactory(const String8& path) {
+    // get strong pointer to open shared library
+    ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path);
+    if (index >= 0) {
+        mLibrary = mLibraryPathToOpenLibraryMap[index];
+    } else {
+        index = mLibraryPathToOpenLibraryMap.add(path, NULL);
+    }
+
+    if (!mLibrary.get()) {
+        mLibrary = ::ndk::SharedRefBase::make<SharedLibrary>(path);
+        if (!*mLibrary) {
+            return false;
+        }
+
+        mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary);
+    }
+
+    CreateFactoryFunc createFactory = (CreateFactoryFunc)mLibrary->lookup(mCreateFactoryFuncName);
+    if (createFactory == NULL || (mFactory = createFactory()) == NULL) {
+        return false;
+    }
+    return true;
+}
+
+template <class T>
+void FactoryLoader<T>::closeFactory() {
+    delete mFactory;
+    mFactory = NULL;
+    mLibrary.reset();
+}
+
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/cas/aidl/default/MediaCasService.cpp b/cas/aidl/default/MediaCasService.cpp
new file mode 100755
index 0000000..8285613
--- /dev/null
+++ b/cas/aidl/default/MediaCasService.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.cas-MediaCasService"
+
+#include <media/cas/CasAPI.h>
+#include <media/cas/DescramblerAPI.h>
+#include <utils/Log.h>
+
+#include "CasImpl.h"
+#include "DescramblerImpl.h"
+#include "MediaCasService.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace cas {
+
+MediaCasService::MediaCasService()
+    : mCasLoader("createCasFactory"), mDescramblerLoader("createDescramblerFactory") {}
+
+MediaCasService::~MediaCasService() {}
+
+ScopedAStatus MediaCasService::enumeratePlugins(
+        vector<AidlCasPluginDescriptor>* aidlCasPluginDescriptors) {
+    ALOGV("%s", __FUNCTION__);
+
+    mCasLoader.enumeratePlugins(aidlCasPluginDescriptors);
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus MediaCasService::isSystemIdSupported(int32_t CA_system_id, bool* _aidl_return) {
+    ALOGV("isSystemIdSupported: CA_system_id=%d", CA_system_id);
+
+    *_aidl_return = mCasLoader.findFactoryForScheme(CA_system_id);
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus MediaCasService::createPlugin(int32_t CA_system_id,
+                                            const shared_ptr<ICasListener>& listener,
+                                            shared_ptr<ICas>* _aidl_return) {
+    ALOGV("%s: CA_system_id=%d", __FUNCTION__, CA_system_id);
+    if (listener == NULL) ALOGV("%s: Listener is NULL", __FUNCTION__);
+
+    CasFactory* factory;
+    shared_ptr<SharedLibrary> library;
+    if (mCasLoader.findFactoryForScheme(CA_system_id, &library, &factory)) {
+        CasPlugin* plugin = NULL;
+        shared_ptr<CasImpl> casImpl = ::ndk::SharedRefBase::make<CasImpl>(listener);
+        if (factory->createPlugin(CA_system_id, casImpl.get(), &CasImpl::CallBackExt, &plugin) ==
+                    OK &&
+            plugin != NULL) {
+            casImpl->init(plugin);
+            *_aidl_return = casImpl;
+            casImpl->setPluginStatusUpdateCallback();
+        }
+    }
+
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus MediaCasService::isDescramblerSupported(int32_t CA_system_id, bool* _aidl_return) {
+    ALOGV("%s: CA_system_id=%d", __FUNCTION__, CA_system_id);
+
+    *_aidl_return = mDescramblerLoader.findFactoryForScheme(CA_system_id);
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus MediaCasService::createDescrambler(int32_t CA_system_id,
+                                                 shared_ptr<IDescrambler>* _aidl_return) {
+    ALOGV("%s: CA_system_id=%d", __FUNCTION__, CA_system_id);
+
+    DescramblerFactory* factory;
+    shared_ptr<SharedLibrary> library;
+    if (mDescramblerLoader.findFactoryForScheme(CA_system_id, &library, &factory)) {
+        DescramblerPlugin* plugin = NULL;
+        if (factory->createPlugin(CA_system_id, &plugin) == OK && plugin != NULL) {
+            *_aidl_return = ::ndk::SharedRefBase::make<DescramblerImpl>(plugin);
+        }
+    }
+
+    return ScopedAStatus::ok();
+}
+
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/cas/aidl/default/MediaCasService.h b/cas/aidl/default/MediaCasService.h
new file mode 100755
index 0000000..9662313
--- /dev/null
+++ b/cas/aidl/default/MediaCasService.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.
+ */
+#include <aidl/android/hardware/cas/BnMediaCasService.h>
+#include <media/cas/DescramblerAPI.h>
+
+#include "FactoryLoader.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace cas {
+
+using namespace ::android;
+using namespace std;
+using ndk::ScopedAStatus;
+
+class MediaCasService : public BnMediaCasService {
+  public:
+    MediaCasService();
+
+    virtual ScopedAStatus enumeratePlugins(
+            vector<AidlCasPluginDescriptor>* aidlCasPluginDescriptors) override;
+
+    virtual ScopedAStatus isSystemIdSupported(int32_t in_CA_system_id, bool* _aidl_return) override;
+
+    virtual ScopedAStatus createPlugin(int32_t in_CA_system_id,
+                                       const shared_ptr<ICasListener>& in_listener,
+                                       shared_ptr<ICas>* _aidl_return) override;
+
+    virtual ScopedAStatus isDescramblerSupported(int32_t in_CA_system_id,
+                                                 bool* _aidl_return) override;
+
+    virtual ScopedAStatus createDescrambler(int32_t in_CA_system_id,
+                                            shared_ptr<IDescrambler>* _aidl_return) override;
+
+  private:
+    FactoryLoader<CasFactory> mCasLoader;
+    FactoryLoader<DescramblerFactory> mDescramblerLoader;
+
+    virtual ~MediaCasService();
+};
+
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/cas/aidl/default/OWNERS b/cas/aidl/default/OWNERS
new file mode 100755
index 0000000..4c55752
--- /dev/null
+++ b/cas/aidl/default/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 1344
+quxiangfang@google.com
+hgchen@google.com
diff --git a/cas/aidl/default/SharedLibrary.cpp b/cas/aidl/default/SharedLibrary.cpp
new file mode 100755
index 0000000..e79f383
--- /dev/null
+++ b/cas/aidl/default/SharedLibrary.cpp
@@ -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.
+ */
+
+#define LOG_TAG "android.hardware.cas-SharedLibrary"
+
+#include "SharedLibrary.h"
+#include <dlfcn.h>
+#include <utils/Log.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace cas {
+
+SharedLibrary::SharedLibrary(const String8& path) {
+    mLibHandle = dlopen(path.string(), RTLD_NOW);
+}
+
+SharedLibrary::~SharedLibrary() {
+    if (mLibHandle != NULL) {
+        dlclose(mLibHandle);
+        mLibHandle = NULL;
+    }
+}
+
+bool SharedLibrary::operator!() const {
+    return mLibHandle == NULL;
+}
+
+void* SharedLibrary::lookup(const char* symbol) const {
+    if (!mLibHandle) {
+        return NULL;
+    }
+    // Clear last error before we load the symbol again,
+    // in case the caller didn't retrieve it.
+    (void)dlerror();
+    return dlsym(mLibHandle, symbol);
+}
+
+const char* SharedLibrary::lastError() const {
+    const char* error = dlerror();
+    return error ? error : "No errors or unknown error";
+}
+
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/cas/aidl/default/SharedLibrary.h b/cas/aidl/default/SharedLibrary.h
new file mode 100755
index 0000000..d367866
--- /dev/null
+++ b/cas/aidl/default/SharedLibrary.h
@@ -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.
+ */
+
+#include <android/binder_interface_utils.h>
+#include <media/stagefright/foundation/ABase.h>
+#include <utils/String8.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace cas {
+
+using namespace ::android;
+
+class SharedLibrary : public ndk::SharedRefBase {
+  public:
+    explicit SharedLibrary(const String8& path);
+    ~SharedLibrary();
+
+    bool operator!() const;
+    void* lookup(const char* symbol) const;
+    const char* lastError() const;
+
+  private:
+    void* mLibHandle;
+    DISALLOW_EVIL_CONSTRUCTORS(SharedLibrary);
+};
+
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/cas/aidl/default/TypeConvert.cpp b/cas/aidl/default/TypeConvert.cpp
new file mode 100755
index 0000000..4f7005f
--- /dev/null
+++ b/cas/aidl/default/TypeConvert.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.cas-TypeConvert"
+
+#include <aidl/android/hardware/cas/Status.h>
+#include <utils/Log.h>
+
+#include "TypeConvert.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace cas {
+
+ScopedAStatus toStatus(status_t legacyStatus) {
+    int status;
+    switch (legacyStatus) {
+        case OK:
+            return ndk::ScopedAStatus::ok();
+        case ERROR_CAS_NO_LICENSE:
+            status = Status::ERROR_CAS_NO_LICENSE;
+            break;
+        case ERROR_CAS_LICENSE_EXPIRED:
+            status = Status::ERROR_CAS_LICENSE_EXPIRED;
+            break;
+        case ERROR_CAS_SESSION_NOT_OPENED:
+            status = Status::ERROR_CAS_SESSION_NOT_OPENED;
+            break;
+        case ERROR_CAS_CANNOT_HANDLE:
+            status = Status::ERROR_CAS_CANNOT_HANDLE;
+            break;
+        case ERROR_CAS_TAMPER_DETECTED:
+            status = Status::ERROR_CAS_INVALID_STATE;
+            break;
+        case BAD_VALUE:
+            status = Status::BAD_VALUE;
+            break;
+        case ERROR_CAS_NOT_PROVISIONED:
+            status = Status::ERROR_CAS_NOT_PROVISIONED;
+            break;
+        case ERROR_CAS_RESOURCE_BUSY:
+            status = Status::ERROR_CAS_RESOURCE_BUSY;
+            break;
+        case ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION:
+            status = Status::ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION;
+            break;
+        case ERROR_CAS_DEVICE_REVOKED:
+            status = Status::ERROR_CAS_DEVICE_REVOKED;
+            break;
+        case ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED:
+            status = Status::ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED;
+            break;
+        case ERROR_CAS_DECRYPT:
+            status = Status::ERROR_CAS_DECRYPT;
+            break;
+        case ERROR_CAS_NEED_ACTIVATION:
+            status = Status::ERROR_CAS_NEED_ACTIVATION;
+            break;
+        case ERROR_CAS_NEED_PAIRING:
+            status = Status::ERROR_CAS_NEED_PAIRING;
+            break;
+        case ERROR_CAS_NO_CARD:
+            status = Status::ERROR_CAS_NO_CARD;
+            break;
+        case ERROR_CAS_CARD_MUTE:
+            status = Status::ERROR_CAS_CARD_MUTE;
+            break;
+        case ERROR_CAS_CARD_INVALID:
+            status = Status::ERROR_CAS_CARD_INVALID;
+            break;
+        case ERROR_CAS_BLACKOUT:
+            status = Status::ERROR_CAS_BLACKOUT;
+            break;
+        default:
+            ALOGW("Unable to convert legacy status: %d, defaulting to UNKNOWN", legacyStatus);
+            status = Status::ERROR_CAS_UNKNOWN;
+            break;
+    }
+    return ScopedAStatus::fromServiceSpecificError(status);
+}
+
+String8 sessionIdToString(const std::vector<uint8_t>& sessionId) {
+    String8 result;
+    for (auto it = sessionId.begin(); it != sessionId.end(); it++) {
+        result.appendFormat("%02x ", *it);
+    }
+    if (result.isEmpty()) {
+        result.append("(null)");
+    }
+    return result;
+}
+
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/cas/aidl/default/TypeConvert.h b/cas/aidl/default/TypeConvert.h
new file mode 100755
index 0000000..ebfa286
--- /dev/null
+++ b/cas/aidl/default/TypeConvert.h
@@ -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/binder_interface_utils.h>
+#include <media/stagefright/MediaErrors.h>
+#include <utils/String8.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace cas {
+
+using namespace ::android;
+using ndk::ScopedAStatus;
+
+ScopedAStatus toStatus(status_t legacyStatus);
+
+String8 sessionIdToString(const std::vector<uint8_t>& sessionId);
+
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/cas/aidl/default/android.hardware.cas-service.xml b/cas/aidl/default/android.hardware.cas-service.xml
new file mode 100755
index 0000000..6389fe2
--- /dev/null
+++ b/cas/aidl/default/android.hardware.cas-service.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.cas</name>
+        <fqname>IMediaCasService/default</fqname>
+    </hal>
+</manifest>
diff --git a/cas/aidl/default/cas-default-lazy.rc b/cas/aidl/default/cas-default-lazy.rc
new file mode 100755
index 0000000..60b59ca
--- /dev/null
+++ b/cas/aidl/default/cas-default-lazy.rc
@@ -0,0 +1,9 @@
+service vendor.cas-default-lazy /vendor/bin/hw/android.hardware.cas-service.example-lazy
+    interface aidl android.hardware.cas.IMediaCasService/default
+    class hal
+    user media
+    group mediadrm drmrpc
+    ioprio rt 4
+    task_profiles ProcessCapacityHigh
+    oneshot
+    disabled
diff --git a/cas/aidl/default/cas-default.rc b/cas/aidl/default/cas-default.rc
new file mode 100755
index 0000000..e00b9c5
--- /dev/null
+++ b/cas/aidl/default/cas-default.rc
@@ -0,0 +1,7 @@
+service vendor.cas-default /vendor/bin/hw/android.hardware.cas-service.example
+    interface aidl android.hardware.cas.IMediaCasService/default
+    class hal
+    user media
+    group mediadrm drmrpc
+    ioprio rt 4
+    task_profiles ProcessCapacityHigh
diff --git a/cas/aidl/default/fuzzer.cpp b/cas/aidl/default/fuzzer.cpp
new file mode 100755
index 0000000..db1369e
--- /dev/null
+++ b/cas/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 <MediaCasService.h>

+#include <fuzzbinder/libbinder_ndk_driver.h>

+#include <fuzzer/FuzzedDataProvider.h>

+

+using aidl::android::hardware::cas::MediaCasService;

+using android::fuzzService;

+using ndk::SharedRefBase;

+

+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {

+    auto mediaCasServiceAidl = SharedRefBase::make<MediaCasService>();

+

+    fuzzService(mediaCasServiceAidl->asBinder().get(), FuzzedDataProvider(data, size));

+

+    return 0;

+}
\ No newline at end of file
diff --git a/cas/aidl/default/service.cpp b/cas/aidl/default/service.cpp
new file mode 100755
index 0000000..bed2f01
--- /dev/null
+++ b/cas/aidl/default/service.cpp
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+#ifdef LAZY_SERVICE
+const bool kLazyService = true;
+#define LOG_TAG "android.hardware.cas-service.example-lazy"
+#else
+const bool kLazyService = false;
+#define LOG_TAG "android.hardware.cas-service.example"
+#endif
+
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+#include "MediaCasService.h"
+
+using aidl::android::hardware::cas::MediaCasService;
+
+int main() {
+    ABinderProcess_setThreadPoolMaxThreadCount(8);
+
+    // Setup hwbinder service
+    std::shared_ptr<MediaCasService> service = ::ndk::SharedRefBase::make<MediaCasService>();
+
+    const std::string instance = std::string() + MediaCasService::descriptor + "/default";
+    binder_status_t status;
+
+    if (kLazyService) {
+        status = AServiceManager_registerLazyService(service->asBinder().get(), instance.c_str());
+    } else {
+        status = AServiceManager_addService(service->asBinder().get(), instance.c_str());
+    }
+    LOG_ALWAYS_FATAL_IF(status != STATUS_OK, "Error while registering cas service: %d", status);
+
+    ABinderProcess_joinThreadPool();
+    return 0;
+}
diff --git a/cas/aidl/vts/functional/Android.bp b/cas/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..295ae7c
--- /dev/null
+++ b/cas/aidl/vts/functional/Android.bp
@@ -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 {
+    // 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: "VtsHalCasAidlTargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: ["VtsHalCasAidlTargetTest.cpp"],
+    static_libs: [
+        "android.hardware.cas-V1-ndk",
+        "android.hardware.common-V2-ndk",
+    ],
+    shared_libs: [
+        "libbinder_ndk",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+    disable_framework: true,
+}
diff --git a/cas/aidl/vts/functional/OWNERS b/cas/aidl/vts/functional/OWNERS
new file mode 100644
index 0000000..4c55752
--- /dev/null
+++ b/cas/aidl/vts/functional/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 1344
+quxiangfang@google.com
+hgchen@google.com
diff --git a/cas/aidl/vts/functional/VtsHalCasAidlTargetTest.cpp b/cas/aidl/vts/functional/VtsHalCasAidlTargetTest.cpp
new file mode 100644
index 0000000..266b55d
--- /dev/null
+++ b/cas/aidl/vts/functional/VtsHalCasAidlTargetTest.cpp
@@ -0,0 +1,809 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "mediacas_aidl_hal_test"
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/cas/BnCasListener.h>
+#include <aidl/android/hardware/cas/IMediaCasService.h>
+#include <aidl/android/hardware/cas/Status.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <binder/ParcelFileDescriptor.h>
+#include <cutils/ashmem.h>
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
+
+#define CLEAR_KEY_SYSTEM_ID 0xF6D8
+#define INVALID_SYSTEM_ID 0
+#define WAIT_TIMEOUT 3000000000
+
+#define PROVISION_STR                                      \
+    "{                                                   " \
+    "  \"id\": 21140844,                                 " \
+    "  \"name\": \"Test Title\",                         " \
+    "  \"lowercase_organization_name\": \"Android\",     " \
+    "  \"asset_key\": {                                  " \
+    "  \"encryption_key\": \"nezAr3CHFrmBR9R8Tedotw==\"  " \
+    "  },                                                " \
+    "  \"cas_type\": 1,                                  " \
+    "  \"track_types\": [ ]                              " \
+    "}                                                   "
+
+using aidl::android::hardware::common::Ashmem;
+using android::Mutex;
+using namespace aidl::android::hardware::cas;
+using namespace ndk;
+using namespace std;
+using namespace testing;
+
+const uint8_t kEcmBinaryBuffer[] = {
+        0x00, 0x00, 0x01, 0xf0, 0x00, 0x50, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x46, 0x00,
+        0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x27, 0x10, 0x02, 0x00,
+        0x01, 0x77, 0x01, 0x42, 0x95, 0x6c, 0x0e, 0xe3, 0x91, 0xbc, 0xfd, 0x05, 0xb1, 0x60, 0x4f,
+        0x17, 0x82, 0xa4, 0x86, 0x9b, 0x23, 0x56, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+        0x27, 0x10, 0x02, 0x00, 0x01, 0x77, 0x01, 0x42, 0x95, 0x6c, 0xd7, 0x43, 0x62, 0xf8, 0x1c,
+        0x62, 0x19, 0x05, 0xc7, 0x3a, 0x42, 0xcd, 0xfd, 0xd9, 0x13, 0x48,
+};
+
+const SubSample kSubSamples[] = {{162, 0}, {0, 184}, {0, 184}};
+
+const uint8_t kInBinaryBuffer[] = {
+        0x00, 0x00, 0x00, 0x01, 0x09, 0xf0, 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0xc0, 0x1e, 0xdb,
+        0x01, 0x40, 0x16, 0xec, 0x04, 0x40, 0x00, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x0f, 0x03,
+        0xc5, 0x8b, 0xb8, 0x00, 0x00, 0x00, 0x01, 0x68, 0xca, 0x8c, 0xb2, 0x00, 0x00, 0x01, 0x06,
+        0x05, 0xff, 0xff, 0x70, 0xdc, 0x45, 0xe9, 0xbd, 0xe6, 0xd9, 0x48, 0xb7, 0x96, 0x2c, 0xd8,
+        0x20, 0xd9, 0x23, 0xee, 0xef, 0x78, 0x32, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x63, 0x6f, 0x72,
+        0x65, 0x20, 0x31, 0x34, 0x32, 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32, 0x36, 0x34, 0x2f, 0x4d,
+        0x50, 0x45, 0x47, 0x2d, 0x34, 0x20, 0x41, 0x56, 0x43, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x63,
+        0x20, 0x2d, 0x20, 0x43, 0x6f, 0x70, 0x79, 0x6c, 0x65, 0x66, 0x74, 0x20, 0x32, 0x30, 0x30,
+        0x33, 0x2d, 0x32, 0x30, 0x31, 0x34, 0x20, 0x2d, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
+        0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e, 0x2e, 0x6f,
+        0x72, 0x67, 0x2f, 0x78, 0x32, 0x36, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x6e, 0x45, 0x21,
+        0x82, 0x38, 0xf0, 0x9d, 0x7d, 0x96, 0xe6, 0x94, 0xae, 0xe2, 0x87, 0x8f, 0x04, 0x49, 0xe5,
+        0xf6, 0x8c, 0x8b, 0x9a, 0x10, 0x18, 0xba, 0x94, 0xe9, 0x22, 0x31, 0x04, 0x7e, 0x60, 0x5b,
+        0xc4, 0x24, 0x00, 0x90, 0x62, 0x0d, 0xdc, 0x85, 0x74, 0x75, 0x78, 0xd0, 0x14, 0x08, 0xcb,
+        0x02, 0x1d, 0x7d, 0x9d, 0x34, 0xe8, 0x81, 0xb9, 0xf7, 0x09, 0x28, 0x79, 0x29, 0x8d, 0xe3,
+        0x14, 0xed, 0x5f, 0xca, 0xaf, 0xf4, 0x1c, 0x49, 0x15, 0xe1, 0x80, 0x29, 0x61, 0x76, 0x80,
+        0x43, 0xf8, 0x58, 0x53, 0x40, 0xd7, 0x31, 0x6d, 0x61, 0x81, 0x41, 0xe9, 0x77, 0x9f, 0x9c,
+        0xe1, 0x6d, 0xf2, 0xee, 0xd9, 0xc8, 0x67, 0xd2, 0x5f, 0x48, 0x73, 0xe3, 0x5c, 0xcd, 0xa7,
+        0x45, 0x58, 0xbb, 0xdd, 0x28, 0x1d, 0x68, 0xfc, 0xb4, 0xc6, 0xf6, 0x92, 0xf6, 0x30, 0x03,
+        0xaa, 0xe4, 0x32, 0xf6, 0x34, 0x51, 0x4b, 0x0f, 0x8c, 0xf9, 0xac, 0x98, 0x22, 0xfb, 0x49,
+        0xc8, 0xbf, 0xca, 0x8c, 0x80, 0x86, 0x5d, 0xd7, 0xa4, 0x52, 0xb1, 0xd9, 0xa6, 0x04, 0x4e,
+        0xb3, 0x2d, 0x1f, 0xb8, 0x35, 0xcc, 0x45, 0x6d, 0x9c, 0x20, 0xa7, 0xa4, 0x34, 0x59, 0x72,
+        0xe3, 0xae, 0xba, 0x49, 0xde, 0xd1, 0xaa, 0xee, 0x3d, 0x77, 0xfc, 0x5d, 0xc6, 0x1f, 0x9d,
+        0xac, 0xc2, 0x15, 0x66, 0xb8, 0xe1, 0x54, 0x4e, 0x74, 0x93, 0xdb, 0x9a, 0x24, 0x15, 0x6e,
+        0x20, 0xa3, 0x67, 0x3e, 0x5a, 0x24, 0x41, 0x5e, 0xb0, 0xe6, 0x35, 0x87, 0x1b, 0xc8, 0x7a,
+        0xf9, 0x77, 0x65, 0xe0, 0x01, 0xf2, 0x4c, 0xe4, 0x2b, 0xa9, 0x64, 0x96, 0x96, 0x0b, 0x46,
+        0xca, 0xea, 0x79, 0x0e, 0x78, 0xa3, 0x5f, 0x43, 0xfc, 0x47, 0x6a, 0x12, 0xfa, 0xc4, 0x33,
+        0x0e, 0x88, 0x1c, 0x19, 0x3a, 0x00, 0xc3, 0x4e, 0xb5, 0xd8, 0xfa, 0x8e, 0xf1, 0xbc, 0x3d,
+        0xb2, 0x7e, 0x50, 0x8d, 0x67, 0xc3, 0x6b, 0xed, 0xe2, 0xea, 0xa6, 0x1f, 0x25, 0x24, 0x7c,
+        0x94, 0x74, 0x50, 0x49, 0xe3, 0xc6, 0x58, 0x2e, 0xfd, 0x28, 0xb4, 0xc6, 0x73, 0xb1, 0x53,
+        0x74, 0x27, 0x94, 0x5c, 0xdf, 0x69, 0xb7, 0xa1, 0xd7, 0xf5, 0xd3, 0x8a, 0x2c, 0x2d, 0xb4,
+        0x5e, 0x8a, 0x16, 0x14, 0x54, 0x64, 0x6e, 0x00, 0x6b, 0x11, 0x59, 0x8a, 0x63, 0x38, 0x80,
+        0x76, 0xc3, 0xd5, 0x59, 0xf7, 0x3f, 0xd2, 0xfa, 0xa5, 0xca, 0x82, 0xff, 0x4a, 0x62, 0xf0,
+        0xe3, 0x42, 0xf9, 0x3b, 0x38, 0x27, 0x8a, 0x89, 0xaa, 0x50, 0x55, 0x4b, 0x29, 0xf1, 0x46,
+        0x7c, 0x75, 0xef, 0x65, 0xaf, 0x9b, 0x0d, 0x6d, 0xda, 0x25, 0x94, 0x14, 0xc1, 0x1b, 0xf0,
+        0xc5, 0x4c, 0x24, 0x0e, 0x65,
+};
+
+const uint8_t kOutRefBinaryBuffer[] = {
+        0x00, 0x00, 0x00, 0x01, 0x09, 0xf0, 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0xc0, 0x1e, 0xdb,
+        0x01, 0x40, 0x16, 0xec, 0x04, 0x40, 0x00, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x0f, 0x03,
+        0xc5, 0x8b, 0xb8, 0x00, 0x00, 0x00, 0x01, 0x68, 0xca, 0x8c, 0xb2, 0x00, 0x00, 0x01, 0x06,
+        0x05, 0xff, 0xff, 0x70, 0xdc, 0x45, 0xe9, 0xbd, 0xe6, 0xd9, 0x48, 0xb7, 0x96, 0x2c, 0xd8,
+        0x20, 0xd9, 0x23, 0xee, 0xef, 0x78, 0x32, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x63, 0x6f, 0x72,
+        0x65, 0x20, 0x31, 0x34, 0x32, 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32, 0x36, 0x34, 0x2f, 0x4d,
+        0x50, 0x45, 0x47, 0x2d, 0x34, 0x20, 0x41, 0x56, 0x43, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x63,
+        0x20, 0x2d, 0x20, 0x43, 0x6f, 0x70, 0x79, 0x6c, 0x65, 0x66, 0x74, 0x20, 0x32, 0x30, 0x30,
+        0x33, 0x2d, 0x32, 0x30, 0x31, 0x34, 0x20, 0x2d, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
+        0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e, 0x2e, 0x6f,
+        0x72, 0x67, 0x2f, 0x78, 0x32, 0x36, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, 0x2d, 0x20,
+        0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x20, 0x63, 0x61, 0x62, 0x61, 0x63, 0x3d,
+        0x30, 0x20, 0x72, 0x65, 0x66, 0x3d, 0x32, 0x20, 0x64, 0x65, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
+        0x3d, 0x31, 0x3a, 0x30, 0x3a, 0x30, 0x20, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x65, 0x3d,
+        0x30, 0x78, 0x31, 0x3a, 0x30, 0x78, 0x31, 0x31, 0x31, 0x20, 0x6d, 0x65, 0x3d, 0x68, 0x65,
+        0x78, 0x20, 0x73, 0x75, 0x62, 0x6d, 0x65, 0x3d, 0x37, 0x20, 0x70, 0x73, 0x79, 0x3d, 0x31,
+        0x20, 0x70, 0x73, 0x79, 0x5f, 0x72, 0x64, 0x3d, 0x31, 0x2e, 0x30, 0x30, 0x3a, 0x30, 0x2e,
+        0x30, 0x30, 0x20, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x66, 0x3d, 0x31, 0x20,
+        0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x3d, 0x31, 0x36, 0x20, 0x63, 0x68, 0x72,
+        0x6f, 0x6d, 0x61, 0x5f, 0x6d, 0x65, 0x3d, 0x31, 0x20, 0x74, 0x72, 0x65, 0x6c, 0x6c, 0x69,
+        0x73, 0x3d, 0x31, 0x20, 0x38, 0x78, 0x38, 0x64, 0x63, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x71,
+        0x6d, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x61, 0x64, 0x7a, 0x6f, 0x6e, 0x65, 0x3d, 0x32, 0x31,
+        0x2c, 0x31, 0x31, 0x20, 0x66, 0x61, 0x73, 0x74, 0x5f, 0x70, 0x73, 0x6b, 0x69, 0x70, 0x3d,
+        0x31, 0x20, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x61, 0x5f, 0x71, 0x70, 0x5f, 0x6f, 0x66, 0x66,
+        0x73, 0x65, 0x74, 0x3d, 0x2d, 0x32, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d,
+        0x36, 0x30, 0x20, 0x6c, 0x6f, 0x6f, 0x6b, 0x61, 0x68, 0x65, 0x61, 0x64, 0x5f, 0x74, 0x68,
+        0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x35, 0x20, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x64, 0x5f,
+        0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x30, 0x20, 0x6e, 0x72, 0x3d, 0x30, 0x20,
+        0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x20, 0x69, 0x6e, 0x74, 0x65,
+        0x72, 0x6c, 0x61, 0x63, 0x65, 0x64, 0x3d, 0x30, 0x20, 0x62, 0x6c, 0x75, 0x72, 0x61, 0x79,
+        0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74,
+        0x72, 0x61, 0x69, 0x6e, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x74, 0x72, 0x61, 0x3d, 0x30, 0x20,
+        0x62, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x3d, 0x30, 0x20, 0x77, 0x65, 0x69, 0x67, 0x68,
+        0x74, 0x70, 0x3d, 0x30, 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x3d, 0x32, 0x35, 0x30,
+        0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x3d, 0x32, 0x35, 0x20,
+        0x73, 0x63, 0x65, 0x6e, 0x65,
+};
+
+class MediaCasListener : public BnCasListener {
+  public:
+    virtual ScopedAStatus onEvent(int32_t event, int32_t arg,
+                                  const vector<uint8_t>& data) override {
+        Mutex::Autolock autoLock(mMsgLock);
+        mEvent = event;
+        mEventArg = arg;
+        mEventData = data;
+
+        mEventReceived = true;
+        mMsgCondition.signal();
+        return ScopedAStatus::ok();
+    }
+
+    virtual ScopedAStatus onSessionEvent(const vector<uint8_t>& sessionId, int32_t event,
+                                         int32_t arg, const vector<uint8_t>& data) override {
+        Mutex::Autolock autoLock(mMsgLock);
+        mSessionId = sessionId;
+        mEvent = event;
+        mEventArg = arg;
+        mEventData = data;
+
+        mEventReceived = true;
+        mMsgCondition.signal();
+        return ScopedAStatus::ok();
+    }
+
+    virtual ScopedAStatus onStatusUpdate(StatusEvent event, int32_t arg) override {
+        Mutex::Autolock autoLock(mMsgLock);
+        mStatusEvent = event;
+        mEventArg = arg;
+
+        mEventReceived = true;
+        mMsgCondition.signal();
+        return ScopedAStatus::ok();
+    }
+
+    void testEventEcho(shared_ptr<ICas>& mediaCas, int32_t& event, int32_t& eventArg,
+                       vector<uint8_t>& eventData);
+
+    void testSessionEventEcho(shared_ptr<ICas>& mediaCas, const vector<uint8_t>& sessionId,
+                              int32_t& event, int32_t& eventArg, vector<uint8_t>& eventData);
+
+    void testStatusUpdate(shared_ptr<ICas>& mediaCas, vector<uint8_t>* sessionId,
+                          SessionIntent intent, ScramblingMode mode);
+
+  private:
+    int32_t mEvent = -1;
+    int32_t mEventArg = -1;
+    StatusEvent mStatusEvent;
+    bool mEventReceived = false;
+    vector<uint8_t> mEventData;
+    vector<uint8_t> mSessionId;
+    Mutex mMsgLock;
+    android::Condition mMsgCondition;
+};
+
+void MediaCasListener::testEventEcho(shared_ptr<ICas>& mediaCas, int32_t& event, int32_t& eventArg,
+                                     vector<uint8_t>& eventData) {
+    mEventReceived = false;
+    auto returnStatus = mediaCas->sendEvent(event, eventArg, eventData);
+    EXPECT_TRUE(returnStatus.isOk());
+
+    Mutex::Autolock autoLock(mMsgLock);
+    while (!mEventReceived) {
+        if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+            ADD_FAILURE() << "event not received within timeout";
+            return;
+        }
+    }
+
+    EXPECT_EQ(mEvent, event);
+    EXPECT_EQ(mEventArg, eventArg);
+    EXPECT_TRUE(mEventData == eventData);
+}
+
+void MediaCasListener::testSessionEventEcho(shared_ptr<ICas>& mediaCas,
+                                            const vector<uint8_t>& sessionId, int32_t& event,
+                                            int32_t& eventArg, vector<uint8_t>& eventData) {
+    mEventReceived = false;
+    EXPECT_TRUE(mediaCas->sendSessionEvent(sessionId, event, eventArg, eventData).isOk());
+
+    Mutex::Autolock autoLock(mMsgLock);
+    while (!mEventReceived) {
+        if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+            ADD_FAILURE() << "event not received within timeout";
+            return;
+        }
+    }
+
+    EXPECT_TRUE(mSessionId == sessionId);
+    EXPECT_EQ(mEvent, event);
+    EXPECT_EQ(mEventArg, eventArg);
+    EXPECT_TRUE(mEventData == eventData);
+}
+
+void MediaCasListener::testStatusUpdate(shared_ptr<ICas>& mediaCas, vector<uint8_t>* sessionId,
+                                        SessionIntent intent, ScramblingMode mode) {
+    mEventReceived = false;
+    EXPECT_TRUE(mediaCas->openSession(intent, mode, sessionId).isOk());
+
+    Mutex::Autolock autoLock(mMsgLock);
+    while (!mEventReceived) {
+        if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+            ADD_FAILURE() << "event not received within timeout";
+            return;
+        }
+    }
+    EXPECT_EQ(mStatusEvent, static_cast<StatusEvent>(intent));
+    EXPECT_EQ(mEventArg, static_cast<int32_t>(mode));
+}
+
+class MediaCasAidlTest : public testing::TestWithParam<string> {
+  public:
+    virtual void SetUp() override {
+        if (AServiceManager_isDeclared(GetParam().c_str())) {
+            SpAIBinder binder(AServiceManager_waitForService(GetParam().c_str()));
+            mService = IMediaCasService::fromBinder(binder);
+        } else {
+            mService = nullptr;
+        }
+        ASSERT_NE(mService, nullptr);
+    }
+
+    shared_ptr<IMediaCasService> mService = nullptr;
+
+  protected:
+    static void description(const string& description) {
+        RecordProperty("description", description);
+    }
+
+    shared_ptr<ICas> mMediaCas;
+    shared_ptr<IDescrambler> mDescrambler;
+    shared_ptr<MediaCasListener> mCasListener;
+    typedef struct _OobInputTestParams {
+        const SubSample* subSamples;
+        int32_t numSubSamples;
+        int64_t imemSizeActual;
+        int64_t imemOffset;
+        int64_t imemSize;
+        int64_t srcOffset;
+        int64_t dstOffset;
+    } OobInputTestParams;
+
+    AssertionResult createCasPlugin(int32_t caSystemId);
+    AssertionResult openCasSession(vector<uint8_t>* sessionId, SessionIntent intent,
+                                   ScramblingMode mode);
+    AssertionResult descrambleTestInputBuffer(const shared_ptr<IDescrambler>& descrambler,
+                                              ScopedAStatus& descrambleStatus, uint8_t*& inMemory);
+    AssertionResult descrambleTestOobInput(const shared_ptr<IDescrambler>& descrambler,
+                                           ScopedAStatus& descrambleStatus,
+                                           const OobInputTestParams& params);
+};
+
+AssertionResult MediaCasAidlTest::createCasPlugin(int32_t caSystemId) {
+    bool isSystemIdSupported;
+    auto status = mService->isSystemIdSupported(caSystemId, &isSystemIdSupported);
+    bool skipDescrambler = false;
+    if (!status.isOk() || !isSystemIdSupported) {
+        return AssertionFailure();
+    }
+    bool isDescramblerSupported;
+    status = mService->isDescramblerSupported(caSystemId, &isDescramblerSupported);
+    if (!status.isOk() || !isDescramblerSupported) {
+        ALOGI("Skip Descrambler test since it's not required in cas.");
+        mDescrambler = nullptr;
+        skipDescrambler = true;
+    }
+
+    mCasListener = SharedRefBase::make<MediaCasListener>();
+    status = mService->createPlugin(caSystemId, mCasListener, &mMediaCas);
+    if (!status.isOk()) {
+        return AssertionFailure();
+    }
+    if (mMediaCas == nullptr) {
+        return AssertionFailure();
+    }
+
+    if (skipDescrambler) {
+        return AssertionSuccess();
+    }
+
+    status = mService->createDescrambler(caSystemId, &mDescrambler);
+    if (!status.isOk()) {
+        return AssertionFailure();
+    }
+
+    return AssertionResult(mDescrambler != nullptr);
+}
+
+AssertionResult MediaCasAidlTest::openCasSession(vector<uint8_t>* sessionId, SessionIntent intent,
+                                                 ScramblingMode mode) {
+    return AssertionResult(mMediaCas->openSession(intent, mode, sessionId).isOk());
+}
+
+AssertionResult MediaCasAidlTest::descrambleTestInputBuffer(
+        const shared_ptr<IDescrambler>& descrambler, ScopedAStatus& descrambleStatus,
+        uint8_t*& sharedMemory) {
+    vector<SubSample> subSample(kSubSamples,
+                                kSubSamples + (sizeof(kSubSamples) / sizeof(SubSample)));
+
+    int size = sizeof(kInBinaryBuffer);
+    auto fd = ashmem_create_region("vts-cas", size);
+    if (fd < 0) {
+        ALOGE("ashmem_create_region failed");
+        return AssertionFailure();
+    }
+
+    sharedMemory =
+            static_cast<uint8_t*>(mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
+    if (sharedMemory == reinterpret_cast<uint8_t*>(MAP_FAILED)) {
+        ALOGE("mmap failed");
+        return AssertionFailure();
+    }
+
+    memcpy(sharedMemory, kInBinaryBuffer, size);
+
+    auto dupFd = dup(fd);
+
+    SharedBuffer srcBuffer = {.heapBase.fd = ScopedFileDescriptor(std::move(fd)),
+                              .heapBase.size = size,
+                              .offset = 0,
+                              .size = size};
+
+    SharedBuffer dupBuffer = {.heapBase.fd = ScopedFileDescriptor(dupFd),
+                              .heapBase.size = size,
+                              .offset = 0,
+                              .size = size};
+
+    DestinationBuffer dstBuffer;
+    dstBuffer.set<DestinationBuffer::nonsecureMemory>(std::move(dupBuffer));
+
+    int32_t outBytes;
+    descrambleStatus = descrambler->descramble(ScramblingControl::EVENKEY /*2*/, subSample,
+                                               srcBuffer, 0, dstBuffer, 0, &outBytes);
+    if (!descrambleStatus.isOk()) {
+        ALOGI("descramble failed, status=%d, outBytes=%u, error=%s", descrambleStatus.getStatus(),
+              outBytes, descrambleStatus.getDescription().c_str());
+    }
+    return AssertionResult(descrambleStatus.isOk());
+}
+
+AssertionResult MediaCasAidlTest::descrambleTestOobInput(
+        const shared_ptr<IDescrambler>& descrambler, ScopedAStatus& descrambleStatus,
+        const OobInputTestParams& params) {
+    vector<SubSample> subSample(params.subSamples, params.subSamples + params.numSubSamples);
+
+    auto fd = ashmem_create_region("vts-cas", params.imemSizeActual);
+    if (fd < 0) {
+        ALOGE("ashmem_create_region failed");
+        return AssertionFailure();
+    }
+
+    auto dupFd = dup(fd);
+
+    SharedBuffer srcBuffer = {.heapBase.fd = ScopedFileDescriptor(std::move(fd)),
+                              .heapBase.size = params.imemSizeActual,
+                              .offset = params.imemOffset,
+                              .size = params.imemSize};
+
+    SharedBuffer dupBuffer = {.heapBase.fd = ScopedFileDescriptor(dupFd),
+                              .heapBase.size = params.imemSizeActual,
+                              .offset = params.imemOffset,
+                              .size = params.imemSize};
+
+    DestinationBuffer dstBuffer;
+    dstBuffer.set<DestinationBuffer::nonsecureMemory>(std::move(dupBuffer));
+
+    int32_t outBytes;
+    descrambleStatus =
+            descrambler->descramble(ScramblingControl::EVENKEY /*2*/, subSample, srcBuffer,
+                                    params.srcOffset, dstBuffer, params.dstOffset, &outBytes);
+    if (!descrambleStatus.isOk()) {
+        ALOGI("descramble failed, status=%d, outBytes=%u, error=%s", descrambleStatus.getStatus(),
+              outBytes, descrambleStatus.getDescription().c_str());
+    }
+    return AssertionResult(descrambleStatus.isOk());
+}
+
+TEST_P(MediaCasAidlTest, EnumeratePlugins) {
+    description("Test enumerate plugins");
+
+    vector<AidlCasPluginDescriptor> descriptors;
+    EXPECT_TRUE(mService->enumeratePlugins(&descriptors).isOk());
+
+    if (descriptors.size() == 0) {
+        ALOGW("[   WARN   ] enumeratePlugins list empty");
+        return;
+    }
+
+    for (size_t i = 0; i < descriptors.size(); i++) {
+        int32_t caSystemId = descriptors[i].caSystemId;
+
+        ASSERT_TRUE(createCasPlugin(caSystemId));
+    }
+}
+
+TEST_P(MediaCasAidlTest, TestInvalidSystemIdFails) {
+    description("Test failure for invalid system ID");
+
+    bool isSystemIdSupported;
+    auto status = mService->isSystemIdSupported(INVALID_SYSTEM_ID, &isSystemIdSupported);
+
+    EXPECT_TRUE(status.isOk());
+    ASSERT_FALSE(isSystemIdSupported);
+
+    bool isDescramblerSupported;
+    status = mService->isDescramblerSupported(INVALID_SYSTEM_ID, &isDescramblerSupported);
+
+    EXPECT_TRUE(status.isOk());
+    ASSERT_FALSE(isDescramblerSupported);
+
+    shared_ptr<ICas> mediaCas;
+    shared_ptr<MediaCasListener> casListener = SharedRefBase::make<MediaCasListener>();
+    status = mService->createPlugin(INVALID_SYSTEM_ID, casListener, &mediaCas);
+    ASSERT_TRUE(status.isOk());
+    EXPECT_EQ(mediaCas, nullptr);
+
+    shared_ptr<IDescrambler> descrambler;
+    status = mService->createDescrambler(INVALID_SYSTEM_ID, &descrambler);
+    ASSERT_TRUE(status.isOk());
+    EXPECT_EQ(descrambler, nullptr);
+}
+
+TEST_P(MediaCasAidlTest, TestClearKeyPluginInstalled) {
+    description("Test if ClearKey plugin is installed");
+
+    vector<AidlCasPluginDescriptor> descriptors;
+    EXPECT_TRUE(mService->enumeratePlugins(&descriptors).isOk());
+
+    if (descriptors.size() == 0) {
+        ALOGW("[   WARN   ] enumeratePlugins list empty");
+    }
+
+    for (size_t i = 0; i < descriptors.size(); i++) {
+        int32_t caSystemId = descriptors[i].caSystemId;
+        if (CLEAR_KEY_SYSTEM_ID == caSystemId) {
+            return;
+        }
+    }
+
+    ADD_FAILURE() << "ClearKey plugin not installed";
+}
+
+TEST_P(MediaCasAidlTest, TestClearKeySessionClosedAfterRelease) {
+    description("Test that all sessions are closed after a MediaCas object is released");
+
+    ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
+
+    EXPECT_TRUE(mMediaCas->provision(PROVISION_STR).isOk());
+
+    SessionIntent intent = SessionIntent::LIVE;
+    ScramblingMode mode = ScramblingMode::DVB_CSA1;
+
+    vector<uint8_t> sessionId;
+    ASSERT_TRUE(openCasSession(&sessionId, intent, mode));
+
+    vector<uint8_t> streamSessionId;
+    ASSERT_TRUE(openCasSession(&streamSessionId, intent, mode));
+
+    EXPECT_TRUE(mMediaCas->release().isOk());
+
+    if (mDescrambler != nullptr) {
+        auto status = mDescrambler->setMediaCasSession(sessionId);
+        EXPECT_FALSE(status.isOk());
+        EXPECT_EQ(Status::ERROR_CAS_SESSION_NOT_OPENED, status.getServiceSpecificError());
+
+        status = mDescrambler->setMediaCasSession(streamSessionId);
+        EXPECT_FALSE(status.isOk());
+        EXPECT_EQ(Status::ERROR_CAS_SESSION_NOT_OPENED, status.getServiceSpecificError());
+    }
+}
+
+TEST_P(MediaCasAidlTest, TestClearKeyErrors) {
+    description("Test that invalid call sequences fail with expected error codes");
+
+    ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
+
+    /*
+     * Test MediaCas error codes
+     */
+    // Provision should fail with an invalid asset string
+    auto returnStatus = mMediaCas->provision("invalid asset string");
+    EXPECT_FALSE(returnStatus.isOk());
+    EXPECT_EQ(Status::ERROR_CAS_NO_LICENSE, returnStatus.getServiceSpecificError());
+
+    SessionIntent intent = SessionIntent::LIVE;
+    ScramblingMode mode = ScramblingMode::DVB_CSA1;
+
+    // Open a session, then close it so that it should become invalid
+    vector<uint8_t> invalidSessionId;
+    ASSERT_TRUE(openCasSession(&invalidSessionId, intent, mode));
+    EXPECT_TRUE(mMediaCas->closeSession(invalidSessionId).isOk());
+
+    // processEcm should fail with an invalid session id
+    vector<uint8_t> ecm(kEcmBinaryBuffer, kEcmBinaryBuffer + sizeof(kEcmBinaryBuffer));
+    returnStatus = mMediaCas->processEcm(invalidSessionId, ecm);
+    EXPECT_FALSE(returnStatus.isOk());
+    EXPECT_EQ(Status::ERROR_CAS_SESSION_NOT_OPENED, returnStatus.getServiceSpecificError());
+
+    vector<uint8_t> sessionId;
+    ASSERT_TRUE(openCasSession(&sessionId, intent, mode));
+
+    // processEcm should fail without provisioning
+    returnStatus = mMediaCas->processEcm(sessionId, ecm);
+    EXPECT_FALSE(returnStatus.isOk());
+    EXPECT_EQ(Status::ERROR_CAS_NOT_PROVISIONED, returnStatus.getServiceSpecificError());
+
+    EXPECT_TRUE(mMediaCas->provision(PROVISION_STR).isOk());
+
+    // processEcm should fail with ecm with bad descriptor count
+    ecm[17] = 0x03;  // change the descriptor count field to 3 (invalid)
+    returnStatus = mMediaCas->processEcm(sessionId, ecm);
+    EXPECT_FALSE(returnStatus.isOk());
+    EXPECT_EQ(Status::ERROR_CAS_UNKNOWN, returnStatus.getServiceSpecificError());
+
+    // processEcm should fail with ecm buffer that's too short
+    ecm.resize(8);
+    returnStatus = mMediaCas->processEcm(sessionId, ecm);
+    EXPECT_FALSE(returnStatus.isOk());
+    EXPECT_EQ(Status::BAD_VALUE, returnStatus.getServiceSpecificError());
+
+    if (mDescrambler != nullptr) {
+        /*
+         * Test MediaDescrambler error codes
+         */
+        // setMediaCasSession should fail with an invalid session id
+        returnStatus = mDescrambler->setMediaCasSession(invalidSessionId);
+        EXPECT_FALSE(returnStatus.isOk());
+        EXPECT_EQ(Status::ERROR_CAS_SESSION_NOT_OPENED, returnStatus.getServiceSpecificError());
+
+        // descramble should fail without a valid session
+        ScopedAStatus descrambleStatus = ScopedAStatus::ok();
+        uint8_t* sharedBuffer = nullptr;
+
+        ASSERT_FALSE(descrambleTestInputBuffer(mDescrambler, descrambleStatus, sharedBuffer));
+        EXPECT_EQ(Status::ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED,
+                  descrambleStatus.getServiceSpecificError());
+
+        // Now set a valid session, should still fail because no valid ecm is processed
+        EXPECT_TRUE(mDescrambler->setMediaCasSession(sessionId).isOk());
+        ASSERT_FALSE(descrambleTestInputBuffer(mDescrambler, descrambleStatus, sharedBuffer));
+        EXPECT_EQ(Status::ERROR_CAS_DECRYPT, descrambleStatus.getServiceSpecificError());
+
+        // Verify that requiresSecureDecoderComponent handles empty mime
+        bool requiresSecureDecoderComponent = true;
+        EXPECT_TRUE(
+                mDescrambler->requiresSecureDecoderComponent("", &requiresSecureDecoderComponent)
+                        .isOk());
+        EXPECT_FALSE(requiresSecureDecoderComponent);
+
+        // Verify that requiresSecureDecoderComponent handles invalid mime
+        requiresSecureDecoderComponent = true;
+        EXPECT_TRUE(
+                mDescrambler->requiresSecureDecoderComponent("bad", &requiresSecureDecoderComponent)
+                        .isOk());
+        EXPECT_FALSE(requiresSecureDecoderComponent);
+    }
+}
+
+TEST_P(MediaCasAidlTest, TestClearKeyApisWithSession) {
+    description("Test that valid call sequences with SessionEvent send and receive");
+
+    ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
+
+    EXPECT_TRUE(mMediaCas->provision(PROVISION_STR).isOk());
+
+    vector<uint8_t> pvtData;
+    pvtData.resize(256);
+    EXPECT_TRUE(mMediaCas->setPrivateData(pvtData).isOk());
+
+    SessionIntent intent = SessionIntent::LIVE;
+    ScramblingMode mode = ScramblingMode::DVB_CSA1;
+
+    vector<uint8_t> sessionId;
+    ASSERT_TRUE(openCasSession(&sessionId, intent, mode));
+    EXPECT_TRUE(mMediaCas->setSessionPrivateData(sessionId, pvtData).isOk());
+
+    vector<uint8_t> streamSessionId;
+    ASSERT_TRUE(openCasSession(&streamSessionId, intent, mode));
+    EXPECT_TRUE(mMediaCas->setSessionPrivateData(streamSessionId, pvtData).isOk());
+
+    if (mDescrambler != nullptr) {
+        EXPECT_TRUE(mDescrambler->setMediaCasSession(sessionId).isOk());
+        EXPECT_TRUE(mDescrambler->setMediaCasSession(streamSessionId).isOk());
+    }
+
+    vector<uint8_t> nullPtrVector(0);
+    EXPECT_TRUE(mMediaCas->refreshEntitlements(3, nullPtrVector).isOk());
+
+    vector<uint8_t> refreshData{0, 1, 2, 3};
+    EXPECT_TRUE(mMediaCas->refreshEntitlements(10, refreshData).isOk());
+
+    int32_t eventID = 1;
+    int32_t eventArg = 2;
+    mCasListener->testEventEcho(mMediaCas, eventID, eventArg, nullPtrVector);
+    mCasListener->testSessionEventEcho(mMediaCas, sessionId, eventID, eventArg, nullPtrVector);
+
+    eventID = 3;
+    eventArg = 4;
+    vector<uint8_t> eventData{'e', 'v', 'e', 'n', 't', 'd', 'a', 't', 'a'};
+    mCasListener->testEventEcho(mMediaCas, eventID, eventArg, eventData);
+    mCasListener->testSessionEventEcho(mMediaCas, sessionId, eventID, eventArg, eventData);
+
+    mCasListener->testStatusUpdate(mMediaCas, &sessionId, intent, mode);
+
+    vector<uint8_t> clearKeyEmmData{'c', 'l', 'e', 'a', 'r', 'k', 'e', 'y', 'e', 'm', 'm'};
+    EXPECT_TRUE(mMediaCas->processEmm(clearKeyEmmData).isOk());
+
+    vector<uint8_t> ecm(kEcmBinaryBuffer, kEcmBinaryBuffer + sizeof(kEcmBinaryBuffer));
+    EXPECT_TRUE(mMediaCas->processEcm(sessionId, ecm).isOk());
+    EXPECT_TRUE(mMediaCas->processEcm(streamSessionId, ecm).isOk());
+
+    if (mDescrambler != nullptr) {
+        bool requiresSecureDecoderComponent = true;
+        EXPECT_TRUE(mDescrambler
+                            ->requiresSecureDecoderComponent("video/avc",
+                                                             &requiresSecureDecoderComponent)
+                            .isOk());
+        EXPECT_FALSE(requiresSecureDecoderComponent);
+
+        ScopedAStatus descrambleStatus = ScopedAStatus::ok();
+        uint8_t* sharedBuffer = nullptr;
+
+        ASSERT_TRUE(descrambleTestInputBuffer(mDescrambler, descrambleStatus, sharedBuffer));
+
+        int compareResult =
+                memcmp(static_cast<const void*>(sharedBuffer),
+                       static_cast<const void*>(kOutRefBinaryBuffer), sizeof(kOutRefBinaryBuffer));
+        EXPECT_EQ(0, compareResult);
+
+        EXPECT_TRUE(mDescrambler->release().isOk());
+    }
+
+    EXPECT_TRUE(mMediaCas->release().isOk());
+}
+
+TEST_P(MediaCasAidlTest, TestClearKeyOobFails) {
+    description("Test that oob descramble request fails with expected error");
+
+    ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
+    EXPECT_TRUE(mMediaCas->provision(PROVISION_STR).isOk());
+
+    SessionIntent intent = SessionIntent::LIVE;
+    ScramblingMode mode = ScramblingMode::DVB_CSA1;
+
+    vector<uint8_t> sessionId;
+    ASSERT_TRUE(openCasSession(&sessionId, intent, mode));
+
+    if (mDescrambler != nullptr) {
+        EXPECT_TRUE(mDescrambler->setMediaCasSession(sessionId).isOk());
+    }
+
+    vector<uint8_t> ecm(kEcmBinaryBuffer, kEcmBinaryBuffer + sizeof(kEcmBinaryBuffer));
+    EXPECT_TRUE(mMediaCas->processEcm(sessionId, ecm).isOk());
+
+    if (mDescrambler != nullptr) {
+        ScopedAStatus descrambleStatus = ScopedAStatus::ok();
+
+        // test invalid src buffer offset
+        ASSERT_FALSE(
+                descrambleTestOobInput(mDescrambler, descrambleStatus,
+                                       {.subSamples = kSubSamples,
+                                        .numSubSamples = sizeof(kSubSamples) / sizeof(SubSample),
+                                        .imemSizeActual = sizeof(kInBinaryBuffer),
+                                        .imemOffset = 0xcccccc,
+                                        .imemSize = sizeof(kInBinaryBuffer),
+                                        .srcOffset = 0,
+                                        .dstOffset = 0}));
+        EXPECT_EQ(Status::BAD_VALUE, descrambleStatus.getServiceSpecificError());
+
+        // test invalid src buffer size
+        ASSERT_FALSE(
+                descrambleTestOobInput(mDescrambler, descrambleStatus,
+                                       {.subSamples = kSubSamples,
+                                        .numSubSamples = sizeof(kSubSamples) / sizeof(SubSample),
+                                        .imemSizeActual = sizeof(kInBinaryBuffer),
+                                        .imemOffset = 0,
+                                        .imemSize = 0xcccccc,
+                                        .srcOffset = 0,
+                                        .dstOffset = 0}));
+        EXPECT_EQ(Status::BAD_VALUE, descrambleStatus.getServiceSpecificError());
+
+        // test invalid src buffer size
+        ASSERT_FALSE(
+                descrambleTestOobInput(mDescrambler, descrambleStatus,
+                                       {.subSamples = kSubSamples,
+                                        .numSubSamples = sizeof(kSubSamples) / sizeof(SubSample),
+                                        .imemSizeActual = sizeof(kInBinaryBuffer),
+                                        .imemOffset = 1,
+                                        .imemSize = -1,
+                                        .srcOffset = 0,
+                                        .dstOffset = 0}));
+        EXPECT_EQ(Status::BAD_VALUE, descrambleStatus.getServiceSpecificError());
+
+        // test invalid srcOffset
+        ASSERT_FALSE(
+                descrambleTestOobInput(mDescrambler, descrambleStatus,
+                                       {.subSamples = kSubSamples,
+                                        .numSubSamples = sizeof(kSubSamples) / sizeof(SubSample),
+                                        .imemSizeActual = sizeof(kInBinaryBuffer),
+                                        .imemOffset = 0,
+                                        .imemSize = sizeof(kInBinaryBuffer),
+                                        .srcOffset = 0xcccccc,
+                                        .dstOffset = 0}));
+        EXPECT_EQ(Status::BAD_VALUE, descrambleStatus.getServiceSpecificError());
+
+        // test invalid dstOffset
+        ASSERT_FALSE(
+                descrambleTestOobInput(mDescrambler, descrambleStatus,
+                                       {.subSamples = kSubSamples,
+                                        .numSubSamples = sizeof(kSubSamples) / sizeof(SubSample),
+                                        .imemSizeActual = sizeof(kInBinaryBuffer),
+                                        .imemOffset = 0,
+                                        .imemSize = sizeof(kInBinaryBuffer),
+                                        .srcOffset = 0,
+                                        .dstOffset = 0xcccccc}));
+        EXPECT_EQ(Status::BAD_VALUE, descrambleStatus.getServiceSpecificError());
+
+        // test detection of oob subsample sizes
+        const SubSample invalidSubSamples1[] = {{162, 0}, {0, 184}, {0, 0xdddddd}};
+
+        ASSERT_FALSE(descrambleTestOobInput(
+                mDescrambler, descrambleStatus,
+                {.subSamples = invalidSubSamples1,
+                 .numSubSamples = sizeof(invalidSubSamples1) / sizeof(SubSample),
+                 .imemSizeActual = sizeof(kInBinaryBuffer),
+                 .imemOffset = 0,
+                 .imemSize = sizeof(kInBinaryBuffer),
+                 .srcOffset = 0,
+                 .dstOffset = 0}));
+        EXPECT_EQ(Status::BAD_VALUE, descrambleStatus.getServiceSpecificError());
+
+        // test detection of overflowing subsample sizes
+        const SubSample invalidSubSamples2[] = {{162, 0}, {0, 184}, {2, -1}};
+
+        ASSERT_FALSE(descrambleTestOobInput(
+                mDescrambler, descrambleStatus,
+                {.subSamples = invalidSubSamples2,
+                 .numSubSamples = sizeof(invalidSubSamples2) / sizeof(SubSample),
+                 .imemSizeActual = sizeof(kInBinaryBuffer),
+                 .imemOffset = 0,
+                 .imemSize = sizeof(kInBinaryBuffer),
+                 .srcOffset = 0,
+                 .dstOffset = 0}));
+        EXPECT_EQ(Status::BAD_VALUE, descrambleStatus.getServiceSpecificError());
+
+        EXPECT_TRUE(mDescrambler->release().isOk());
+    }
+    EXPECT_TRUE(mMediaCas->release().isOk());
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MediaCasAidlTest);
+
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, MediaCasAidlTest,
+        testing::ValuesIn(android::getAidlHalInstanceNames(IMediaCasService::descriptor)),
+        android::PrintInstanceNameToString);
+
+// Start thread pool to receive callbacks from AIDL service.
+int main(int argc, char** argv) {
+    InitGoogleTest(&argc, argv);
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/common/aidl/Android.bp b/common/aidl/Android.bp
index 43f8c4d..7f6890c 100644
--- a/common/aidl/Android.bp
+++ b/common/aidl/Android.bp
@@ -37,6 +37,7 @@
             min_sdk_version: "29",
         },
     },
+    frozen: true,
     versions: [
         "1",
         "2",
diff --git a/common/fmq/aidl/Android.bp b/common/fmq/aidl/Android.bp
index a85597c..95fcc41 100644
--- a/common/fmq/aidl/Android.bp
+++ b/common/fmq/aidl/Android.bp
@@ -37,5 +37,6 @@
             min_sdk_version: "29",
         },
     },
+    frozen: true,
     versions: ["1"],
 }
diff --git a/common/support/NativeHandle.cpp b/common/support/NativeHandle.cpp
index 321d7a8..126ef2e 100644
--- a/common/support/NativeHandle.cpp
+++ b/common/support/NativeHandle.cpp
@@ -22,6 +22,13 @@
 
 using aidl::android::hardware::common::NativeHandle;
 
+/**
+ * Checks if a NativeHandle is null
+ */
+bool isAidlNativeHandleEmpty(const NativeHandle& handle) {
+    return handle.fds.empty() && handle.ints.empty();
+}
+
 static native_handle_t* fromAidl(const NativeHandle& handle, bool doDup) {
     native_handle_t* to = native_handle_create(handle.fds.size(), handle.ints.size());
     if (!to) return nullptr;
diff --git a/common/support/include/aidlcommonsupport/NativeHandle.h b/common/support/include/aidlcommonsupport/NativeHandle.h
index 10eecba..b5ea1dd 100644
--- a/common/support/include/aidlcommonsupport/NativeHandle.h
+++ b/common/support/include/aidlcommonsupport/NativeHandle.h
@@ -22,6 +22,11 @@
 namespace android {
 
 /**
+ * Checks if a NativeHandle is empty.
+ */
+bool isAidlNativeHandleEmpty(const aidl::android::hardware::common::NativeHandle& handle);
+
+/**
  * Creates a libcutils native handle from an AIDL native handle, but it does not
  * dup internally, so it will contain the same FDs as the handle itself. The
  * result should be deleted with native_handle_delete.
diff --git a/common/support/test.cpp b/common/support/test.cpp
index 2359277..9b79581 100644
--- a/common/support/test.cpp
+++ b/common/support/test.cpp
@@ -62,6 +62,7 @@
 
 TEST(ConvertNativeHandle, MakeFromAidlEmpty) {
     NativeHandle handle;
+    EXPECT_TRUE(isAidlNativeHandleEmpty(handle));
     native_handle_t* to = makeFromAidl(handle);
     checkEq(handle, to, false /*exceptFds*/);
     // no native_handle_close b/c fds are owned by NativeHandle
@@ -70,6 +71,7 @@
 
 TEST(ConvertNativeHandle, MakeFromAidl) {
     NativeHandle handle = makeTestAidlHandle();
+    EXPECT_FALSE(isAidlNativeHandleEmpty(handle));
     native_handle_t* to = makeFromAidl(handle);
     checkEq(handle, to, false /*exceptFds*/);
     // no native_handle_close b/c fds are owned by NativeHandle
@@ -106,6 +108,7 @@
 TEST(ConvertNativeHandle, MakeToAidlEmpty) {
     native_handle_t* handle = native_handle_create(0, 0);
     NativeHandle to = makeToAidl(handle);
+    EXPECT_TRUE(isAidlNativeHandleEmpty(to));
     checkEq(to, handle, false /*exceptFds*/);
     // no native_handle_close b/c fds are owned by NativeHandle now
     EXPECT_EQ(0, native_handle_delete(handle));
@@ -114,6 +117,7 @@
 TEST(ConvertNativeHandle, MakeToAidl) {
     native_handle_t* handle = makeTestLibcutilsHandle();
     NativeHandle to = makeToAidl(handle);
+    EXPECT_FALSE(isAidlNativeHandleEmpty(to));
     checkEq(to, handle, false /*exceptFds*/);
     // no native_handle_close b/c fds are owned by NativeHandle now
     EXPECT_EQ(0, native_handle_delete(handle));
@@ -122,6 +126,7 @@
 TEST(ConvertNativeHandle, DupToAidlEmpty) {
     native_handle_t* handle = native_handle_create(0, 0);
     NativeHandle to = dupToAidl(handle);
+    EXPECT_TRUE(isAidlNativeHandleEmpty(to));
     checkEq(to, handle, true /*exceptFds*/);
     EXPECT_EQ(0, native_handle_close(handle));
     EXPECT_EQ(0, native_handle_delete(handle));
@@ -130,6 +135,7 @@
 TEST(ConvertNativeHandle, DupToAidl) {
     native_handle_t* handle = makeTestLibcutilsHandle();
     NativeHandle to = dupToAidl(handle);
+    EXPECT_FALSE(isAidlNativeHandleEmpty(to));
     checkEq(to, handle, true /*exceptFds*/);
     EXPECT_EQ(0, native_handle_close(handle));
     EXPECT_EQ(0, native_handle_delete(handle));
diff --git a/compatibility_matrices/Android.bp b/compatibility_matrices/Android.bp
index 524242f..37c2820 100644
--- a/compatibility_matrices/Android.bp
+++ b/compatibility_matrices/Android.bp
@@ -28,8 +28,6 @@
         "compatibility_matrix.3.xml",
     ],
     kernel_configs: [
-        "kernel_config_p_4.4",
-        "kernel_config_p_4.9",
         "kernel_config_p_4.14",
     ],
 }
@@ -41,7 +39,6 @@
         "compatibility_matrix.4.xml",
     ],
     kernel_configs: [
-        "kernel_config_q_4.9",
         "kernel_config_q_4.14",
         "kernel_config_q_4.19",
     ],
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index 6f0bd61..f8954a3 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -109,19 +109,19 @@
         <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">
         <name>android.hardware.biometrics.face</name>
-        <version>2</version>
+        <version>3</version>
         <interface>
             <name>IFace</name>
             <instance>default</instance>
@@ -129,7 +129,7 @@
     </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.biometrics.fingerprint</name>
-        <version>2</version>
+        <version>3</version>
         <interface>
             <name>IFingerprint</name>
             <instance>default</instance>
@@ -145,6 +145,13 @@
         </interface>
     </hal>
     <hal format="aidl" optional="true">
+        <name>android.hardware.bluetooth</name>
+        <interface>
+            <name>IBluetoothHci</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl" optional="true">
         <name>android.hardware.bluetooth.audio</name>
         <version>2</version>
         <interface>
@@ -166,17 +173,9 @@
             <regex-instance>.*</regex-instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="aidl" optional="true" updatable-via-apex="true">
         <name>android.hardware.camera.provider</name>
-        <version>2.4-7</version>
-        <interface>
-            <name>ICameraProvider</name>
-            <regex-instance>[^/]+/[0-9]+</regex-instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.camera.provider</name>
-        <version>1</version>
+        <version>1-2</version>
         <interface>
             <name>ICameraProvider</name>
             <regex-instance>[^/]+/[0-9]+</regex-instance>
@@ -190,9 +189,16 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="aidl" optional="true">
+        <name>android.hardware.cas</name>
+        <interface>
+            <name>IMediaCasService</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl" optional="true">
         <name>android.hardware.confirmationui</name>
-        <version>1.0</version>
+        <version>1</version>
         <interface>
             <name>IConfirmationUI</name>
             <instance>default</instance>
@@ -205,7 +211,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl" optional="true" updatable-via-apex="true">
         <name>android.hardware.drm</name>
         <version>1</version>
         <interface>
@@ -238,7 +244,7 @@
     </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.gnss</name>
-        <version>2</version>
+        <version>3</version>
         <interface>
             <name>IGnss</name>
             <instance>default</instance>
@@ -262,7 +268,7 @@
     </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.graphics.allocator</name>
-        <version>1</version>
+        <version>1-2</version>
         <interface>
             <name>IAllocator</name>
             <instance>default</instance>
@@ -276,7 +282,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="false">
+    <hal format="hidl" optional="true">
         <name>android.hardware.graphics.mapper</name>
         <!-- New, non-Go devices should use 4.0, tested in vts_treble_vintf_vendor_test -->
         <version>2.1</version>
@@ -305,7 +311,7 @@
     </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.identity</name>
-        <version>1-4</version>
+        <version>1-5</version>
         <interface>
             <name>IIdentityCredentialStore</name>
             <instance>default</instance>
@@ -352,7 +358,7 @@
     </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.security.keymint</name>
-        <version>1-2</version>
+        <version>1-3</version>
         <interface>
             <name>IKeyMintDevice</name>
             <instance>default</instance>
@@ -361,7 +367,7 @@
     </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.security.keymint</name>
-        <version>1-2</version>
+        <version>1-3</version>
         <interface>
             <name>IRemotelyProvisionedComponent</name>
             <instance>default</instance>
@@ -385,16 +391,13 @@
             <regex-instance>vendor[0-9]*_software</regex-instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.media.omx</name>
-        <version>1.0</version>
+    <hal format="aidl" optional="true">
+        <name>android.hardware.media.c2</name>
+        <version>1</version>
         <interface>
-            <name>IOmx</name>
-            <instance>default</instance>
-        </interface>
-        <interface>
-            <name>IOmxStore</name>
-            <instance>default</instance>
+            <name>IComponentStore</name>
+            <regex-instance>default[0-9]*</regex-instance>
+            <regex-instance>vendor[0-9]*_software</regex-instance>
         </interface>
     </hal>
     <hal format="aidl" optional="true">
@@ -405,14 +408,6 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.neuralnetworks</name>
-        <version>1.0-3</version>
-        <interface>
-            <name>IDevice</name>
-            <regex-instance>.*</regex-instance>
-        </interface>
-    </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.neuralnetworks</name>
         <version>1-4</version>
@@ -453,7 +448,7 @@
     </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.radio.config</name>
-        <version>1</version>
+        <version>2</version>
         <interface>
             <name>IRadioConfig</name>
             <instance>default</instance>
@@ -461,7 +456,7 @@
     </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.radio.data</name>
-        <version>1</version>
+        <version>2</version>
         <interface>
             <name>IRadioData</name>
             <instance>slot1</instance>
@@ -471,7 +466,7 @@
     </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.radio.messaging</name>
-        <version>1</version>
+        <version>2</version>
         <interface>
             <name>IRadioMessaging</name>
             <instance>slot1</instance>
@@ -481,7 +476,7 @@
     </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.radio.modem</name>
-        <version>1</version>
+        <version>2</version>
         <interface>
             <name>IRadioModem</name>
             <instance>slot1</instance>
@@ -501,7 +496,7 @@
     </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.radio.sim</name>
-        <version>1</version>
+        <version>2</version>
         <interface>
             <name>IRadioSim</name>
             <instance>slot1</instance>
@@ -511,7 +506,7 @@
     </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.radio.voice</name>
-        <version>1</version>
+        <version>2</version>
         <interface>
             <name>IRadioVoice</name>
             <instance>slot1</instance>
@@ -519,6 +514,16 @@
             <instance>slot3</instance>
         </interface>
     </hal>
+    <hal format="aidl" optional="true">
+        <name>android.hardware.radio.ims</name>
+        <version>1</version>
+        <interface>
+            <name>IRadioIms</name>
+            <instance>slot1</instance>
+            <instance>slot2</instance>
+            <instance>slot3</instance>
+        </interface>
+    </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.radio</name>
         <version>1.2</version>
@@ -527,6 +532,14 @@
             <instance>slot1</instance>
         </interface>
     </hal>
+    <hal format="aidl" optional="true">
+        <name>android.hardware.radio.ims.media</name>
+        <version>1</version>
+        <interface>
+            <name>IImsMedia</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.renderscript</name>
         <version>1.0</version>
@@ -553,6 +566,15 @@
         </interface>
     </hal>
     <hal format="aidl" optional="true">
+        <name>android.hardware.secure_element</name>
+        <version>1</version>
+        <interface>
+            <name>ISecureElement</name>
+            <regex-instance>eSE[1-9][0-9]*</regex-instance>
+            <regex-instance>SIM[1-9][0-9]*</regex-instance>
+        </interface>
+    </hal>
+    <hal format="aidl" optional="true">
         <name>android.hardware.security.secureclock</name>
         <version>1</version>
         <interface>
@@ -600,27 +622,25 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="false">
+    <hal format="aidl" optional="false">
         <name>android.hardware.thermal</name>
-        <version>2.0</version>
+        <version>1</version>
         <interface>
             <name>IThermal</name>
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="aidl" optional="true">
         <name>android.hardware.tv.cec</name>
-        <version>1.0-1</version>
         <interface>
             <name>IHdmiCec</name>
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.tv.input</name>
-        <version>1.0</version>
+    <hal format="aidl" optional="true">
+        <name>android.hardware.tv.hdmi</name>
         <interface>
-            <name>ITvInput</name>
+            <name>IHdmi</name>
             <instance>default</instance>
         </interface>
     </hal>
@@ -642,6 +662,7 @@
     </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.usb</name>
+        <version>1-2</version>
         <interface>
             <name>IUsb</name>
             <instance>default</instance>
@@ -728,6 +749,7 @@
     </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.wifi.supplicant</name>
+        <version>2</version>
         <interface>
             <name>ISupplicant</name>
             <instance>default</instance>
diff --git a/compatibility_matrices/exclude/fcm_exclude.cpp b/compatibility_matrices/exclude/fcm_exclude.cpp
index 6de9d03..cf1e138 100644
--- a/compatibility_matrices/exclude/fcm_exclude.cpp
+++ b/compatibility_matrices/exclude/fcm_exclude.cpp
@@ -61,6 +61,7 @@
             "android.hardware.graphics.common",
             "android.hardware.input.common",
             "android.hardware.keymaster",
+            "android.hardware.media.bufferpool2",
             "android.hardware.radio",
             "android.hardware.uwb.fira_android",
 
@@ -68,6 +69,8 @@
             // does not depend on this HAL, hence it is not declared in any manifests or matrices.
             "android.hardware.fastboot@1.0",
             "android.hardware.fastboot@1.1",
+            // Fastboot AIDL
+            "android.hardware.fastboot",
 
             // Deprecated HALs.
             // HIDL
diff --git a/confirmationui/OWNERS b/confirmationui/OWNERS
new file mode 100644
index 0000000..2bcdb0e
--- /dev/null
+++ b/confirmationui/OWNERS
@@ -0,0 +1,2 @@
+swillden@google.com
+subrahmanyaman@google.com
diff --git a/confirmationui/aidl/Android.bp b/confirmationui/aidl/Android.bp
new file mode 100644
index 0000000..5395101
--- /dev/null
+++ b/confirmationui/aidl/Android.bp
@@ -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.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+aidl_interface {
+    name: "android.hardware.confirmationui",
+    vendor_available: true,
+    imports: [
+        "android.hardware.security.keymint-V3",
+    ],
+    srcs: ["android/hardware/confirmationui/*.aidl"],
+    stability: "vintf",
+    backend: {
+        java: {
+            platform_apis: true,
+        },
+        ndk: {
+            apps_enabled: false,
+        },
+        cpp: {
+            enabled: false,
+        },
+    },
+}
diff --git a/confirmationui/aidl/aidl_api/android.hardware.confirmationui/current/android/hardware/confirmationui/IConfirmationResultCallback.aidl b/confirmationui/aidl/aidl_api/android.hardware.confirmationui/current/android/hardware/confirmationui/IConfirmationResultCallback.aidl
new file mode 100644
index 0000000..6d6ec97
--- /dev/null
+++ b/confirmationui/aidl/aidl_api/android.hardware.confirmationui/current/android/hardware/confirmationui/IConfirmationResultCallback.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.confirmationui;
+@VintfStability
+interface IConfirmationResultCallback {
+  void result(in int error, in byte[] formattedMessage, in byte[] confirmationToken);
+}
diff --git a/confirmationui/aidl/aidl_api/android.hardware.confirmationui/current/android/hardware/confirmationui/IConfirmationUI.aidl b/confirmationui/aidl/aidl_api/android.hardware.confirmationui/current/android/hardware/confirmationui/IConfirmationUI.aidl
new file mode 100644
index 0000000..c5c7aa7
--- /dev/null
+++ b/confirmationui/aidl/aidl_api/android.hardware.confirmationui/current/android/hardware/confirmationui/IConfirmationUI.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.confirmationui;
+@VintfStability
+interface IConfirmationUI {
+  void abort();
+  void deliverSecureInputEvent(in android.hardware.security.keymint.HardwareAuthToken secureInputToken);
+  void promptUserConfirmation(in android.hardware.confirmationui.IConfirmationResultCallback resultCB, in byte[] promptText, in byte[] extraData, in @utf8InCpp String locale, in android.hardware.confirmationui.UIOption[] uiOptions);
+  const int OK = 0;
+  const int CANCELED = 1;
+  const int ABORTED = 2;
+  const int OPERATION_PENDING = 3;
+  const int IGNORED = 4;
+  const int SYSTEM_ERROR = 5;
+  const int UNIMPLEMENTED = 6;
+  const int UNEXPECTED = 7;
+  const int UI_ERROR = 65536;
+  const int UI_ERROR_MISSING_GLYPH = 65537;
+  const int UI_ERROR_MESSAGE_TOO_LONG = 65538;
+  const int UI_ERROR_MALFORMED_UTF8ENCODING = 65539;
+  const int TEST_KEY_BYTE = 165;
+  const int MAX_MESSAGE_SIZE = 6144;
+}
diff --git a/confirmationui/aidl/aidl_api/android.hardware.confirmationui/current/android/hardware/confirmationui/TestModeCommands.aidl b/confirmationui/aidl/aidl_api/android.hardware.confirmationui/current/android/hardware/confirmationui/TestModeCommands.aidl
new file mode 100644
index 0000000..b8629d1
--- /dev/null
+++ b/confirmationui/aidl/aidl_api/android.hardware.confirmationui/current/android/hardware/confirmationui/TestModeCommands.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.confirmationui;
+@Backing(type="int") @VintfStability
+enum TestModeCommands {
+  OK_EVENT = 0,
+  CANCEL_EVENT = 1,
+}
diff --git a/confirmationui/aidl/aidl_api/android.hardware.confirmationui/current/android/hardware/confirmationui/UIOption.aidl b/confirmationui/aidl/aidl_api/android.hardware.confirmationui/current/android/hardware/confirmationui/UIOption.aidl
new file mode 100644
index 0000000..ebecf9e
--- /dev/null
+++ b/confirmationui/aidl/aidl_api/android.hardware.confirmationui/current/android/hardware/confirmationui/UIOption.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.confirmationui;
+@Backing(type="int") @VintfStability
+enum UIOption {
+  ACCESSIBILITY_INVERTED = 0,
+  ACCESSIBILITY_MAGNIFIED = 1,
+}
diff --git a/confirmationui/aidl/android/hardware/confirmationui/IConfirmationResultCallback.aidl b/confirmationui/aidl/android/hardware/confirmationui/IConfirmationResultCallback.aidl
new file mode 100644
index 0000000..2165fdd
--- /dev/null
+++ b/confirmationui/aidl/android/hardware/confirmationui/IConfirmationResultCallback.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.confirmationui;
+
+import android.hardware.confirmationui.IConfirmationUI;
+
+/**
+ * Callback interface passed to IConfirmationUI::promptUserConfirmation().
+ * Informs the caller about the result of the prompt operation.
+ */
+@VintfStability
+interface IConfirmationResultCallback {
+    /**
+     * This callback is called by the confirmation provider when it stops prompting the user.
+     * Iff the user has confirmed the prompted text, error is ErrorCode::OK and the
+     * parameters formattedMessage and confirmationToken hold the values needed to request
+     * a signature from keymaster.
+     * In all other cases formattedMessage and confirmationToken must be of length 0.
+     *
+     * @param error - OK: IFF the user has confirmed the prompt.
+     *              - CANCELED: If the user has pressed the cancel button.
+     *              - ABORTED: If IConfirmationUI::abort() was called.
+     *              - SYSTEM_ERROR: If an unexpected System error occurred that prevented the TUI
+     *                             from being shut down gracefully.
+     *
+     * @param formattedMessage holds the prompt text and extra data.
+     *                         The message is CBOR (RFC 7049) encoded and has the following format:
+     *                         CBOR_MAP{ "prompt", <promptText>, "extra", <extraData> }
+     *                         The message is a CBOR encoded map (type 5) with the keys
+     *                         "prompt" and "extra". The keys are encoded as CBOR text string
+     *                         (type 3). The value <promptText> is encoded as CBOR text string
+     *                         (type 3), and the value <extraData> is encoded as CBOR byte string
+     *                         (type 2). The map must have exactly one key value pair for each of
+     *                         the keys "prompt" and "extra". Other keys are not allowed.
+     *                         The value of "prompt" is given by the proptText argument to
+     *                         IConfirmationUI::promptUserConfirmation and must not be modified
+     *                         by the implementation.
+     *                         The value of "extra" is given by the extraData argument to
+     *                         IConfirmationUI::promptUserConfirmation and must not be modified
+     *                         or interpreted by the implementation.
+     *
+     * @param confirmationToken a 32-byte HMAC-SHA256 value, computed over
+     *                          "confirmation token" || <formattedMessage>
+     *                          i.e. the literal UTF-8 encoded string "confirmation token", without
+     *                          the "", concatenated with the formatted message as returned in the
+     *                          formattedMessage argument. The HMAC is keyed with a 256-bit secret
+     *                          which is shared with Keymaster. In test mode the test key MUST be
+     *                          used (see types.hal TestModeCommands and
+     * IConfirmationUI::TEST_KEY_BYTE).
+     */
+    void result(in int error, in byte[] formattedMessage, in byte[] confirmationToken);
+}
diff --git a/confirmationui/aidl/android/hardware/confirmationui/IConfirmationUI.aidl b/confirmationui/aidl/android/hardware/confirmationui/IConfirmationUI.aidl
new file mode 100644
index 0000000..f071126
--- /dev/null
+++ b/confirmationui/aidl/android/hardware/confirmationui/IConfirmationUI.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.confirmationui;
+
+import android.hardware.confirmationui.IConfirmationResultCallback;
+import android.hardware.confirmationui.UIOption;
+import android.hardware.security.keymint.HardwareAuthToken;
+
+@VintfStability
+interface IConfirmationUI {
+    // Possible Errors.
+    /**
+     * API call succeeded or the user gave approval (result callback).
+     */
+    const int OK = 0;
+    /**
+     * The user canceled the TUI (result callback).
+     */
+    const int CANCELED = 1;
+    /**
+     * IConfirmationUI::abort() was called. (result callback).
+     */
+    const int ABORTED = 2;
+    /**
+     * Cannot start another prompt.
+     */
+    const int OPERATION_PENDING = 3;
+    /**
+     * IConfirmationUI::deliverSecureInputEvent call was ignored.
+     */
+    const int IGNORED = 4;
+    /**
+     * An unexpected system error occurred.
+     */
+    const int SYSTEM_ERROR = 5;
+    /**
+     * Returned by an unimplemented API call.
+     */
+    const int UNIMPLEMENTED = 6;
+    /**
+     * This is returned when an error is diagnosed that should have been
+     * caught by earlier input sanitization. Should never be seen in production.
+     */
+    const int UNEXPECTED = 7;
+    /**
+     * General UI error.
+     */
+    const int UI_ERROR = 0x10000;
+    /**
+     * This is returned if there is no corresponding glyph for a character.
+     */
+    const int UI_ERROR_MISSING_GLYPH = 0x10001;
+    /**
+     * The implementation must return this error code on promptUserConfirmation if the
+     * resulting formatted message does not fit into MAX_MESSAGE_SIZE bytes. It is
+     * advised that the implementation formats the message upon receiving this API call to
+     * be able to diagnose this syndrome.
+     */
+    const int UI_ERROR_MESSAGE_TOO_LONG = 0x10002;
+    /**
+     * This is returned if the UTF8 encoding is malformed.
+     */
+    const int UI_ERROR_MALFORMED_UTF8ENCODING = 0x10003;
+
+    // Constants
+    /**
+     * The test key is 32byte word with all bytes set to TEST_KEY_BYTE.
+     */
+    const int TEST_KEY_BYTE = 0xA5;
+    /**
+     * This defines the maximum message size. This indirectly limits the size of the prompt text
+     * and the extra data that can be passed to the confirmation UI. The prompt text and extra data
+     * must fit in to this size including CBOR header information.
+     */
+    const int MAX_MESSAGE_SIZE = 0x1800;
+
+    /**
+     * Aborts a pending user prompt. This allows the framework to gracefully end a TUI dialog.
+     * If a TUI operation was pending the corresponding call back is informed with
+     * ErrorCode::Aborted.
+     */
+    void abort();
+
+    /**
+     * DeliverSecureInput is used by the framework to deliver a secure input event to the
+     * confirmation provider.
+     *
+     * VTS test mode:
+     * This function can be used to test certain code paths non-interactively.
+     * See TestModeCommands.aidl for details.
+     *
+     * @param secureInputToken An authentication token as generated by Android authentication
+     *                         providers.
+     */
+    void deliverSecureInputEvent(in HardwareAuthToken secureInputToken);
+
+    /**
+     * Asynchronously initiates a confirmation UI dialog prompting the user to confirm a given text.
+     * The TUI prompt must be implemented in such a way that a positive response indicates with
+     * high confidence that a user has seen the given prompt text even if the Android framework
+     * including the kernel was compromised.
+     *
+     * Service status return:
+     *
+     * OK IFF the dialog was successfully started. In this case, and only in this
+     *                      case, the implementation must, eventually, call the callback to
+     *                      indicate completion.
+     * OPERATION_PENDING is returned when the confirmation provider is currently
+     *                      in use.
+     * SYSTEM_ERROR an error occurred trying to communicate with the confirmation
+     *                      provider (e.g. trusted app).
+     * UI_ERROR the confirmation provider encountered an issue with displaying
+     *                      the prompt text to the user.
+     *
+     * @param resultCB Implementation of IResultCallback. Used by the implementation to report
+     *                 the result of the current pending user prompt.
+     *
+     * @param promptText UTF-8 encoded bytes which is to be presented to the user.
+     *
+     * @param extraData A binary blob that must be included in the formatted output message as is.
+     *                  It is opaque to the implementation. Implementations must neither interpret
+     *                  nor modify the content.
+     *
+     * @param locale String specifying the locale that must be used by the TUI dialog. The string
+     *                      is an IETF BCP 47 tag.
+     *
+     * @param uiOptions A set of uiOptions manipulating how the confirmation prompt is displayed.
+     *                  Refer to UIOption in types.hal for possible options.
+     */
+    void promptUserConfirmation(in IConfirmationResultCallback resultCB, in byte[] promptText,
+            in byte[] extraData, in @utf8InCpp String locale, in UIOption[] uiOptions);
+}
diff --git a/confirmationui/aidl/android/hardware/confirmationui/TestModeCommands.aidl b/confirmationui/aidl/android/hardware/confirmationui/TestModeCommands.aidl
new file mode 100644
index 0000000..5b1d8fb
--- /dev/null
+++ b/confirmationui/aidl/android/hardware/confirmationui/TestModeCommands.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.confirmationui;
+
+/**
+ * Test mode commands.
+ *
+ * IConfirmationUI::deliverSecureInputEvent can be used to test certain code paths.
+ * To that end, the caller passes an auth token that has an HMAC keyed with the test key
+ * (see IConfirmationUI::TEST_KEY_BYTE). Implementations first check the HMAC against test key.
+ * If the test key produces a matching HMAC, the implementation evaluates the challenge field
+ * of the auth token against the values defined in TestModeCommand.
+ * If the command indicates that a confirmation token is to be generated the test key MUST be used
+ * to generate this confirmation token.
+ *
+ * See command code for individual test command descriptions.
+ */
+@VintfStability
+@Backing(type="int")
+enum TestModeCommands {
+    /**
+     * Simulates the user pressing the OK button on the UI. If no operation is pending
+     * ResponseCode::Ignored must be returned. A pending operation is finalized successfully
+     * see IConfirmationResultCallback::result, however, the test key
+     * (see IConfirmationUI::TEST_KEY_BYTE) MUST be used to generate the confirmation token.
+     */
+    OK_EVENT = 0,
+    /**
+     * Simulates the user pressing the CANCEL button on the UI. If no operation is pending
+     * Result::Ignored must be returned. A pending operation is finalized as specified in
+     * IConfirmationResultCallback.hal.
+     */
+    CANCEL_EVENT = 1,
+}
diff --git a/confirmationui/aidl/android/hardware/confirmationui/UIOption.aidl b/confirmationui/aidl/android/hardware/confirmationui/UIOption.aidl
new file mode 100644
index 0000000..b242c53
--- /dev/null
+++ b/confirmationui/aidl/android/hardware/confirmationui/UIOption.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.confirmationui;
+
+/**
+ * UI modification options.
+ */
+@VintfStability
+@Backing(type="int")
+enum UIOption {
+    /**
+     * Accessibility: Requests color inverted style.
+     */
+    ACCESSIBILITY_INVERTED = 0,
+    /**
+     * Accessibility: Requests magnified style.
+     */
+    ACCESSIBILITY_MAGNIFIED = 1,
+}
diff --git a/confirmationui/aidl/vts/functional/Android.bp b/confirmationui/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..3649c87
--- /dev/null
+++ b/confirmationui/aidl/vts/functional/Android.bp
@@ -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 {
+    // See: http://go/android-license-faq
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_test {
+    name: "VtsHalConfirmationUITargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "keymint_use_latest_hal_aidl_ndk_shared",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: [
+        "VtsHalConfirmationUITargetTest.cpp",
+    ],
+    static_libs: [
+        "android.hardware.confirmationui-V1-ndk",
+        "libcn-cbor",
+        "android.hardware.confirmationui-support-lib",
+    ],
+    shared_libs: [
+        "libbinder_ndk",
+        "libcrypto",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
diff --git a/confirmationui/aidl/vts/functional/VtsHalConfirmationUITargetTest.cpp b/confirmationui/aidl/vts/functional/VtsHalConfirmationUITargetTest.cpp
new file mode 100644
index 0000000..61dae8b
--- /dev/null
+++ b/confirmationui/aidl/vts/functional/VtsHalConfirmationUITargetTest.cpp
@@ -0,0 +1,535 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "ConfirmationIOAidlHalTest"
+
+#include <algorithm>
+#include <condition_variable>
+#include <future>
+#include <iostream>
+#include <memory>
+#include <mutex>
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/confirmationui/BnConfirmationResultCallback.h>
+#include <aidl/android/hardware/confirmationui/IConfirmationUI.h>
+#include <aidl/android/hardware/confirmationui/TestModeCommands.h>
+#include <aidl/android/hardware/confirmationui/UIOption.h>
+#include <android-base/thread_annotations.h>
+#include <android/hardware/confirmationui/support/confirmationui_utils.h>
+#include <cutils/log.h>
+
+#include <openssl/hmac.h>
+#include <openssl/sha.h>
+
+#include <cn-cbor/cn-cbor.h>
+
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <android/binder_status.h>
+
+static constexpr int TIMEOUT_PERIOD = 10;
+
+namespace aidl::android::hardware::confirmationui::test {
+using ::aidl::android::hardware::security::keymint::HardwareAuthenticatorType;
+using ::aidl::android::hardware::security::keymint::HardwareAuthToken;
+using ::android::hardware::confirmationui::support::auth_token_key_t;
+using ::android::hardware::confirmationui::support::ByteBufferProxy;
+using ::android::hardware::confirmationui::support::HMac;
+using ::android::hardware::confirmationui::support::hmac_t;
+using ::android::hardware::confirmationui::support::hton;
+using ::android::hardware::confirmationui::support::NullOr;
+using std::shared_ptr;
+using std::string;
+using std::vector;
+
+namespace {
+const auth_token_key_t testKey(static_cast<uint8_t>(IConfirmationUI::TEST_KEY_BYTE));
+
+class HMacImplementation {
+  public:
+    static NullOr<hmac_t> hmac256(const auth_token_key_t& key,
+                                  std::initializer_list<ByteBufferProxy> buffers) {
+        HMAC_CTX hmacCtx;
+        HMAC_CTX_init(&hmacCtx);
+        if (!HMAC_Init_ex(&hmacCtx, key.data(), key.size(), EVP_sha256(), nullptr)) {
+            return {};
+        }
+        for (auto& buffer : buffers) {
+            if (!HMAC_Update(&hmacCtx, buffer.data(), buffer.size())) {
+                return {};
+            }
+        }
+        hmac_t result;
+        if (!HMAC_Final(&hmacCtx, result.data(), nullptr)) {
+            return {};
+        }
+        return result;
+    }
+};
+
+using HMacer = HMac<HMacImplementation>;
+
+template <typename... Data>
+vector<uint8_t> testHMAC(const Data&... data) {
+    auto hmac = HMacer::hmac256(testKey, data...);
+    if (!hmac.isOk()) {
+        ADD_FAILURE() << "Failed to compute test hmac.  This is a self-test error.";
+        return {};
+    }
+    vector<uint8_t> result(hmac.value().size());
+    std::copy(hmac.value().data(), hmac.value().data() + hmac.value().size(), result.data());
+    return result;
+}
+
+template <typename T>
+auto toBytes(const T& v) -> const uint8_t (&)[sizeof(T)] {
+    return *reinterpret_cast<const uint8_t(*)[sizeof(T)]>(&v);
+}
+
+HardwareAuthToken makeTestToken(const TestModeCommands command, uint64_t timestamp = 0) {
+    HardwareAuthToken auth_token;
+    auth_token.challenge = static_cast<uint64_t>(command);
+    auth_token.userId = 0;
+    auth_token.authenticatorId = 0;
+    auth_token.authenticatorType = HardwareAuthenticatorType::NONE;
+    auth_token.timestamp = {static_cast<int64_t>(timestamp)};
+
+    // Canonical form  of auth-token v0
+    // version (1 byte)
+    // challenge (8 bytes)
+    // user_id (8 bytes)
+    // authenticator_id (8 bytes)
+    // authenticator_type (4 bytes)
+    // timestamp (8 bytes)
+    // total 37 bytes
+    auth_token.mac = testHMAC("\0",
+                              toBytes(auth_token.challenge),                //
+                              toBytes(auth_token.userId),                   //
+                              toBytes(auth_token.authenticatorId),          //
+                              toBytes(hton(auth_token.authenticatorType)),  //
+                              toBytes(hton(auth_token.timestamp)));         //
+
+    return auth_token;
+}
+
+#define DEBUG_CONFRIMATIONUI_UTILS_TEST
+
+#ifdef DEBUG_CONFRIMATIONUI_UTILS_TEST
+std::ostream& hexdump(std::ostream& out, const uint8_t* data, size_t size) {
+    for (size_t i = 0; i < size; ++i) {
+        uint8_t byte = data[i];
+        out << std::hex << std::setw(2) << std::setfill('0') << (unsigned)byte;
+        switch (i & 0xf) {
+            case 0xf:
+                out << "\n";
+                break;
+            case 7:
+                out << "  ";
+                break;
+            default:
+                out << " ";
+                break;
+        }
+    }
+    return out;
+}
+#endif
+
+constexpr char hex_value[256] = {0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 1,  2,  3,  4,  5,  6,  7, 8, 9, 0, 0, 0, 0, 0, 0,  // '0'..'9'
+                                 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 'A'..'F'
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 'a'..'f'
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+std::string hex2str(std::string a) {
+    std::string b;
+    size_t num = a.size() / 2;
+    b.resize(num);
+    for (size_t i = 0; i < num; i++) {
+        b[i] = (hex_value[a[i * 2] & 0xFF] << 4) + (hex_value[a[i * 2 + 1] & 0xFF]);
+    }
+    return b;
+}
+
+int getReturnCode(const ::ndk::ScopedAStatus& result) {
+    if (result.isOk()) return IConfirmationUI::OK;
+
+    if (result.getExceptionCode() == EX_SERVICE_SPECIFIC) {
+        return static_cast<int>(result.getServiceSpecificError());
+    }
+    return result.getStatus();
+}
+
+}  // namespace
+
+class ConfirmationUIAidlTest : public ::testing::TestWithParam<std::string> {
+  public:
+    void TearDown() override { confirmator_->abort(); }
+    void SetUp() override {
+        std::string name = GetParam();
+        ASSERT_TRUE(AServiceManager_isDeclared(name.c_str())) << name;
+        ndk::SpAIBinder binder(AServiceManager_waitForService(name.c_str()));
+        ASSERT_NE(binder, nullptr);
+        confirmator_ = IConfirmationUI::fromBinder(binder);
+        ASSERT_NE(confirmator_, nullptr);
+    }
+
+    // Used as a mechanism to inform the test about data/event callback
+    inline void notify() {
+        std::unique_lock<std::mutex> lock(mtx_);
+        cv_.notify_one();
+    }
+
+    // Test code calls this function to wait for data/event callback
+    inline std::cv_status wait() {
+        std::unique_lock<std::mutex> lock(mtx_);
+        auto now = std::chrono::system_clock::now();
+        std::cv_status status = cv_.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD));
+        return status;
+    }
+
+  protected:
+    shared_ptr<IConfirmationUI> confirmator_;
+
+  private:
+    // synchronization objects
+    std::mutex mtx_;
+    std::condition_variable cv_;
+};
+
+class ConfirmationTestCallback
+    : public ::aidl::android::hardware::confirmationui::BnConfirmationResultCallback {
+  public:
+    ConfirmationTestCallback(ConfirmationUIAidlTest& parent) : parent_(parent){};
+    virtual ~ConfirmationTestCallback() = default;
+
+    ::ndk::ScopedAStatus result(int32_t err, const vector<uint8_t>& msg,
+                                const vector<uint8_t>& confToken) override {
+        error_ = err;
+        formattedMessage_ = msg;
+        confirmationToken_ = confToken;
+        parent_.notify();
+        return ndk::ScopedAStatus::ok();
+    }
+
+    bool verifyConfirmationToken() {
+        static constexpr char confirmationPrefix[] = "confirmation token";
+        EXPECT_EQ(32U, confirmationToken_.size());
+        return 32U == confirmationToken_.size() &&
+               !memcmp(confirmationToken_.data(),
+                       testHMAC(confirmationPrefix, formattedMessage_).data(), 32);
+    }
+
+    int error_;
+    vector<uint8_t> formattedMessage_;
+    vector<uint8_t> confirmationToken_;
+
+  private:
+    ConfirmationUIAidlTest& parent_;
+};
+
+struct CnCborDeleter {
+    void operator()(cn_cbor* ptr) { cn_cbor_free(ptr); }
+};
+
+typedef std::unique_ptr<cn_cbor, CnCborDeleter> CnCborPtr;
+
+// Simulates the User taping Ok
+TEST_P(ConfirmationUIAidlTest, UserOkTest) {
+    static constexpr char test_prompt[] = "Me first, gimme gimme!";
+    static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+    shared_ptr<ConfirmationTestCallback> conf_cb =
+            ::ndk::SharedRefBase::make<ConfirmationTestCallback>(*this);
+    vector<uint8_t> prompt_text(test_prompt, test_prompt + strlen(test_prompt));
+    vector<uint8_t> extra(test_extra, test_extra + 3);
+    ASSERT_TRUE(confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {}).isOk());
+    // Simulate the user taping ok.
+    ASSERT_TRUE(confirmator_->deliverSecureInputEvent(makeTestToken(TestModeCommands::OK_EVENT))
+                        .isOk());
+    // Wait for the callback.
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    ASSERT_EQ(IConfirmationUI::OK, conf_cb->error_);
+
+    ASSERT_TRUE(conf_cb->verifyConfirmationToken());
+
+    cn_cbor_errback cn_cbor_error;
+    auto parsed_message = CnCborPtr(cn_cbor_decode(
+            conf_cb->formattedMessage_.data(), conf_cb->formattedMessage_.size(), &cn_cbor_error));
+    // is parsable CBOR
+    ASSERT_TRUE(parsed_message.get());
+    // is a map
+    ASSERT_EQ(CN_CBOR_MAP, parsed_message->type);
+
+    // the message must have exactly 2 key value pairs.
+    // cn_cbor holds 2*<no_of_pairs> in the length field
+    ASSERT_EQ(4, parsed_message->length);
+    // map has key "prompt"
+    auto prompt = cn_cbor_mapget_string(parsed_message.get(), "prompt");
+    ASSERT_TRUE(prompt);
+    ASSERT_EQ(CN_CBOR_TEXT, prompt->type);
+    ASSERT_EQ(22, prompt->length);
+    ASSERT_EQ(0, memcmp(test_prompt, prompt->v.str, 22));
+    // map has key "extra"
+    auto extra_out = cn_cbor_mapget_string(parsed_message.get(), "extra");
+    ASSERT_TRUE(extra_out);
+    ASSERT_EQ(CN_CBOR_BYTES, extra_out->type);
+    ASSERT_EQ(3, extra_out->length);
+    ASSERT_EQ(0, memcmp(test_extra, extra_out->v.bytes, 3));
+}
+
+// Initiates a confirmation prompt with a message that is too long
+TEST_P(ConfirmationUIAidlTest, MessageTooLongTest) {
+    static constexpr uint8_t test_extra[IConfirmationUI::MAX_MESSAGE_SIZE] = {};
+    static constexpr char test_prompt[] = "D\'oh!";
+    shared_ptr<ConfirmationTestCallback> conf_cb =
+            ::ndk::SharedRefBase::make<ConfirmationTestCallback>(*this);
+    vector<uint8_t> prompt_text(test_prompt, test_prompt + strlen(test_prompt));
+    vector<uint8_t> extra(test_extra, test_extra + sizeof(test_extra));
+    auto result = confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {});
+    ASSERT_EQ(IConfirmationUI::UI_ERROR_MESSAGE_TOO_LONG, getReturnCode(result));
+}
+
+// If the message gets very long some HAL implementations might fail even before the message
+// reaches the trusted app implementation. But the HAL must still diagnose the correct error.
+TEST_P(ConfirmationUIAidlTest, MessageWayTooLongTest) {
+    static constexpr uint8_t test_extra[(IConfirmationUI::MAX_MESSAGE_SIZE)*10] = {};
+    static constexpr char test_prompt[] = "D\'oh!";
+    shared_ptr<ConfirmationTestCallback> conf_cb =
+            ::ndk::SharedRefBase::make<ConfirmationTestCallback>(*this);
+    vector<uint8_t> prompt_text(test_prompt, test_prompt + strlen(test_prompt));
+    vector<uint8_t> extra(test_extra, test_extra + sizeof(test_extra));
+    auto result = confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {});
+    ASSERT_EQ(IConfirmationUI::UI_ERROR_MESSAGE_TOO_LONG, getReturnCode(result));
+}
+
+// Simulates the User tapping the Cancel
+TEST_P(ConfirmationUIAidlTest, UserCancelTest) {
+    static constexpr char test_prompt[] = "Me first, gimme gimme!";
+    static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+    shared_ptr<ConfirmationTestCallback> conf_cb =
+            ::ndk::SharedRefBase::make<ConfirmationTestCallback>(*this);
+    vector<uint8_t> prompt_text(test_prompt, test_prompt + strlen(test_prompt));
+    vector<uint8_t> extra(test_extra, test_extra + 3);
+    ASSERT_TRUE(confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {}).isOk());
+
+    // Simulate the user taping ok.
+    ASSERT_TRUE(confirmator_->deliverSecureInputEvent(makeTestToken(TestModeCommands::CANCEL_EVENT))
+                        .isOk());
+    // Wait for the callback.
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    ASSERT_EQ(IConfirmationUI::CANCELED, conf_cb->error_);
+
+    ASSERT_EQ(0U, conf_cb->confirmationToken_.size());
+    ASSERT_EQ(0U, conf_cb->formattedMessage_.size());
+}
+
+// Simulates the framework cancelling an ongoing prompt
+TEST_P(ConfirmationUIAidlTest, AbortTest) {
+    static constexpr char test_prompt[] = "Me first, gimme gimme!";
+    static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+    shared_ptr<ConfirmationTestCallback> conf_cb =
+            ::ndk::SharedRefBase::make<ConfirmationTestCallback>(*this);
+    vector<uint8_t> prompt_text(test_prompt, test_prompt + strlen(test_prompt));
+    vector<uint8_t> extra(test_extra, test_extra + 3);
+    ASSERT_TRUE(confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {}).isOk());
+
+    confirmator_->abort();
+
+    // Wait for the callback.
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    ASSERT_EQ(IConfirmationUI::ABORTED, conf_cb->error_);
+    ASSERT_EQ(0U, conf_cb->confirmationToken_.size());
+    ASSERT_EQ(0U, conf_cb->formattedMessage_.size());
+}
+
+// Tests if the confirmation dialog can successfully render 100 'W' characters as required by
+// the design guidelines.
+TEST_P(ConfirmationUIAidlTest, PortableMessageTest1) {
+    static constexpr char test_prompt[] =
+            "WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW"
+            "WWWWWWWWWWWWWW";
+    static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+    shared_ptr<ConfirmationTestCallback> conf_cb =
+            ::ndk::SharedRefBase::make<ConfirmationTestCallback>(*this);
+    vector<uint8_t> prompt_text(test_prompt, test_prompt + strlen(test_prompt));
+    vector<uint8_t> extra(test_extra, test_extra + 3);
+    ASSERT_TRUE(confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {}).isOk());
+
+    confirmator_->abort();
+
+    // Wait for the callback.
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    ASSERT_EQ(IConfirmationUI::ABORTED, conf_cb->error_);
+    ASSERT_EQ(0U, conf_cb->confirmationToken_.size());
+    ASSERT_EQ(0U, conf_cb->formattedMessage_.size());
+}
+
+// Tests if the confirmation dialog can successfully render 100 'W' characters as required by
+// the design guidelines in magnified mode.
+TEST_P(ConfirmationUIAidlTest, PortableMessageTest1Magnified) {
+    static constexpr char test_prompt[] =
+            "WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW"
+            "WWWWWWWWWWWWWW";
+    static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+    shared_ptr<ConfirmationTestCallback> conf_cb =
+            ::ndk::SharedRefBase::make<ConfirmationTestCallback>(*this);
+    vector<uint8_t> prompt_text(test_prompt, test_prompt + strlen(test_prompt));
+    vector<uint8_t> extra(test_extra, test_extra + 3);
+    ASSERT_TRUE(confirmator_
+                        ->promptUserConfirmation(conf_cb, prompt_text, extra, "en",
+                                                 {UIOption::ACCESSIBILITY_MAGNIFIED})
+                        .isOk());
+
+    confirmator_->abort();
+
+    // Wait for the callback.
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    ASSERT_EQ(IConfirmationUI::ABORTED, conf_cb->error_);
+    ASSERT_EQ(0U, conf_cb->confirmationToken_.size());
+    ASSERT_EQ(0U, conf_cb->formattedMessage_.size());
+}
+
+// Tests if the confirmation dialog can successfully render 8 groups of 12 'W' characters as
+// required by the design guidelines.
+TEST_P(ConfirmationUIAidlTest, PortableMessageTest2) {
+    static constexpr char test_prompt[] =
+            "WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW "
+            "WWWWWWWWWWWW WWWWWWWWWWWW";
+    static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+    shared_ptr<ConfirmationTestCallback> conf_cb =
+            ::ndk::SharedRefBase::make<ConfirmationTestCallback>(*this);
+    vector<uint8_t> prompt_text(test_prompt, test_prompt + strlen(test_prompt));
+    vector<uint8_t> extra(test_extra, test_extra + 3);
+    ASSERT_TRUE(confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {}).isOk());
+
+    confirmator_->abort();
+
+    // Wait for the callback.
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    ASSERT_EQ(IConfirmationUI::ABORTED, conf_cb->error_);
+    ASSERT_EQ(0U, conf_cb->confirmationToken_.size());
+    ASSERT_EQ(0U, conf_cb->formattedMessage_.size());
+}
+
+// Tests if the confirmation dialog can successfully render 8 groups of 12 'W' characters as
+// required by the design guidelines in magnified mode.
+TEST_P(ConfirmationUIAidlTest, PortableMessageTest2Magnified) {
+    static constexpr char test_prompt[] =
+            "WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW "
+            "WWWWWWWWWWWW WWWWWWWWWWWW";
+    static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+    shared_ptr<ConfirmationTestCallback> conf_cb =
+            ::ndk::SharedRefBase::make<ConfirmationTestCallback>(*this);
+    vector<uint8_t> prompt_text(test_prompt, test_prompt + strlen(test_prompt));
+    vector<uint8_t> extra(test_extra, test_extra + 3);
+    ASSERT_TRUE(confirmator_
+                        ->promptUserConfirmation(conf_cb, prompt_text, extra, "en",
+                                                 {UIOption::ACCESSIBILITY_MAGNIFIED})
+                        .isOk());
+
+    confirmator_->abort();
+
+    // Wait for the callback.
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    ASSERT_EQ(IConfirmationUI::ABORTED, conf_cb->error_);
+    ASSERT_EQ(0U, conf_cb->confirmationToken_.size());
+    ASSERT_EQ(0U, conf_cb->formattedMessage_.size());
+}
+
+// Passing malformed UTF-8 to the confirmation UI
+// This test passes a string that ends in the middle of a multibyte character
+TEST_P(ConfirmationUIAidlTest, MalformedUTF8Test1) {
+    static constexpr char test_prompt[] = {char(0xc0), 0};
+    static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+    shared_ptr<ConfirmationTestCallback> conf_cb =
+            ::ndk::SharedRefBase::make<ConfirmationTestCallback>(*this);
+    vector<uint8_t> prompt_text(test_prompt, test_prompt + strlen(test_prompt));
+    vector<uint8_t> extra(test_extra, test_extra + 3);
+    auto result = confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {});
+    ASSERT_EQ(IConfirmationUI::UI_ERROR_MALFORMED_UTF8ENCODING, getReturnCode(result));
+}
+
+// Passing malformed UTF-8 to the confirmation UI
+// This test passes a string with a 5-byte character.
+TEST_P(ConfirmationUIAidlTest, MalformedUTF8Test2) {
+    static constexpr char test_prompt[] = {char(0xf8), char(0x82), char(0x82),
+                                           char(0x82), char(0x82), 0};
+    static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+    shared_ptr<ConfirmationTestCallback> conf_cb =
+            ::ndk::SharedRefBase::make<ConfirmationTestCallback>(*this);
+    vector<uint8_t> prompt_text(test_prompt, test_prompt + strlen(test_prompt));
+    vector<uint8_t> extra(test_extra, test_extra + 3);
+    auto result = confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {});
+    ASSERT_EQ(IConfirmationUI::UI_ERROR_MALFORMED_UTF8ENCODING, getReturnCode(result));
+}
+
+// Passing malformed UTF-8 to the confirmation UI
+// This test passes a string with a 2-byte character followed by a stray non UTF-8 character.
+TEST_P(ConfirmationUIAidlTest, MalformedUTF8Test3) {
+    static constexpr char test_prompt[] = {char(0xc0), char(0x82), char(0x83), 0};
+    static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+    shared_ptr<ConfirmationTestCallback> conf_cb =
+            ::ndk::SharedRefBase::make<ConfirmationTestCallback>(*this);
+    vector<uint8_t> prompt_text(test_prompt, test_prompt + strlen(test_prompt));
+    vector<uint8_t> extra(test_extra, test_extra + 3);
+    auto result = confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {});
+    ASSERT_EQ(IConfirmationUI::UI_ERROR_MALFORMED_UTF8ENCODING, getReturnCode(result));
+}
+
+// Test the implementation of HMAC SHA 256 against a golden blob.
+TEST(ConfirmationUITestSelfTest, HMAC256SelfTest) {
+    const char key_str[32] = "keykeykeykeykeykeykeykeykeykeyk";
+    const uint8_t(&key)[32] = *reinterpret_cast<const uint8_t(*)[32]>(key_str);
+    auto expected = hex2str("2377fbcaa7fb3f6c20cfa1d9ebc60e9922cf58c909e25e300f3cb57f7805c886");
+    auto result = HMacer::hmac256(key, "value1", "value2", "value3");
+
+#ifdef DEBUG_CONFRIMATIONUI_UTILS_TEST
+    hexdump(std::cout, reinterpret_cast<const uint8_t*>(expected.data()), 32) << std::endl;
+    hexdump(std::cout, result.value().data(), 32) << std::endl;
+#endif
+
+    ByteBufferProxy expected_bytes(expected);
+    ASSERT_TRUE(result.isOk());
+    ASSERT_EQ(expected, result.value());
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ConfirmationUIAidlTest);
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, ConfirmationUIAidlTest,
+        testing::ValuesIn(::android::getAidlHalInstanceNames(IConfirmationUI::descriptor)),
+        ::android::PrintInstanceNameToString);
+
+}  // namespace aidl::android::hardware::confirmationui::test
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/current.txt b/current.txt
index afde7b1..146ded6 100644
--- a/current.txt
+++ b/current.txt
@@ -929,4 +929,7 @@
 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
+
 # There will be no more HIDL HALs. Use AIDL instead.
diff --git a/fastboot/OWNERS b/fastboot/OWNERS
new file mode 100644
index 0000000..286b65f
--- /dev/null
+++ b/fastboot/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 1228891
+dvander@google.com
+elsk@google.com
+dhavale@google.com
diff --git a/fastboot/aidl/Android.bp b/fastboot/aidl/Android.bp
new file mode 100644
index 0000000..a5735ab
--- /dev/null
+++ b/fastboot/aidl/Android.bp
@@ -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.
+
+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.fastboot",
+    vendor_available: true,
+    recovery_available: true,
+    srcs: ["android/hardware/fastboot/*.aidl"],
+    stability: "vintf",
+    backend: {
+        cpp: {
+            enabled: false,
+        },
+        java: {
+            enabled: false,
+        },
+    },
+}
diff --git a/fastboot/aidl/aidl_api/android.hardware.fastboot/current/android/hardware/fastboot/FileSystemType.aidl b/fastboot/aidl/aidl_api/android.hardware.fastboot/current/android/hardware/fastboot/FileSystemType.aidl
new file mode 100644
index 0000000..b15d037
--- /dev/null
+++ b/fastboot/aidl/aidl_api/android.hardware.fastboot/current/android/hardware/fastboot/FileSystemType.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.fastboot;
+@Backing(type="byte") @VintfStability
+enum FileSystemType {
+  EXT4 = 0,
+  F2FS = 1,
+  RAW = 2,
+}
diff --git a/fastboot/aidl/aidl_api/android.hardware.fastboot/current/android/hardware/fastboot/IFastboot.aidl b/fastboot/aidl/aidl_api/android.hardware.fastboot/current/android/hardware/fastboot/IFastboot.aidl
new file mode 100644
index 0000000..445fcde
--- /dev/null
+++ b/fastboot/aidl/aidl_api/android.hardware.fastboot/current/android/hardware/fastboot/IFastboot.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.fastboot;
+@VintfStability
+interface IFastboot {
+  String doOemCommand(in String oemCmd);
+  void doOemSpecificErase();
+  int getBatteryVoltageFlashingThreshold();
+  boolean getOffModeChargeState();
+  android.hardware.fastboot.FileSystemType getPartitionType(in String partitionName);
+  String getVariant();
+  const int FAILURE_UNKNOWN = 1;
+}
diff --git a/fastboot/aidl/android/hardware/fastboot/FileSystemType.aidl b/fastboot/aidl/android/hardware/fastboot/FileSystemType.aidl
new file mode 100644
index 0000000..b4027ec
--- /dev/null
+++ b/fastboot/aidl/android/hardware/fastboot/FileSystemType.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.
+ */
+
+package android.hardware.fastboot;
+
+@VintfStability
+@Backing(type="byte")
+enum FileSystemType {
+    /**
+     * Fourth extended file system.
+     */
+    EXT4,
+    /**
+     * Flash Friendly File System.
+     */
+    F2FS,
+    /**
+     * Raw file system.
+     */
+    RAW,
+}
diff --git a/fastboot/aidl/android/hardware/fastboot/IFastboot.aidl b/fastboot/aidl/android/hardware/fastboot/IFastboot.aidl
new file mode 100644
index 0000000..abdc215
--- /dev/null
+++ b/fastboot/aidl/android/hardware/fastboot/IFastboot.aidl
@@ -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.
+ */
+
+package android.hardware.fastboot;
+
+import android.hardware.fastboot.FileSystemType;
+
+/**
+ * IFastboot interface implements vendor specific fastboot commands.
+ */
+@VintfStability
+interface IFastboot {
+    /**
+     * Status code for function.
+     * Operation failed due to unknown reason.
+     */
+    const int FAILURE_UNKNOWN = 1;
+    /**
+     * Executes a fastboot OEM command.
+     *
+     * @param oemCmd The oem command that is passed to the fastboot HAL.
+     * @return optional String if the operation is successful and output is expected
+     *         for the command.
+     * @throws :
+     *         - EX_ILLEGAL_ARGUMENT for bad arguments.
+     *         - EX_UNSUPPORTED_OPERATION for unsupported commands.
+     *         - EX_SERVICE_SPECIFIC with status FAILURE_UNKNOWN for other errors.
+     */
+    String doOemCommand(in String oemCmd);
+
+    /**
+     * Executes an OEM specific erase after fastboot erase userdata.
+     *
+     * @throws :
+     *         - EX_UNSUPPORTED_OPERATION if it is not supported.
+     *         - EX_SERVICE_SPECIFIC with status FAILURE_UNKNOWN for
+     *           unknown error in oem specific command or other errors.
+     */
+    void doOemSpecificErase();
+
+    /**
+     * Returns the minimum battery voltage required for flashing in mV.
+     *
+     * @return Minimum batterery voltage (in mV) required for flashing to
+     *         be successful.
+     * @throws :
+     *         - EX_SERVICE_SPECIFIC with status FAILURE_UNKNOWN if error.
+     */
+    int getBatteryVoltageFlashingThreshold();
+
+    /**
+     * Returns whether off-mode-charging is enabled. If enabled, the device
+     *      autoboots into a special mode when power is applied.
+     *
+     * @return Returns whether off-mode-charging is enabled.
+     * @throws :
+     *         - EX_SERVICE_SPECIFIC with status FAILURE_UNKNOWN if error.
+     */
+    boolean getOffModeChargeState();
+
+    /**
+     * Returns the file system type of the partition. Implementation is only
+     *       required for physical partitions that need to be wiped and reformatted.
+     * @param in partitionName Name of the partition.
+     * @return Returns the file system type of the partition. Type can be ext4,
+     *         f2fs or raw.
+     * @throws :
+     *         - EX_SERVICE_SPECIFIC with status FAILURE_UNKNOWN if the partition
+     *           is invalid or does not require reformatting.
+     */
+    FileSystemType getPartitionType(in String partitionName);
+
+    /**
+     * Returns an OEM-defined string indicating the variant of the device, for
+     * example, US and ROW.
+     * @return Indicates the device variant.
+     * @throws :
+     *         - EX_SERVICE_SPECIFIC with status FAILURE_UNKNOWN if error.
+     */
+    String getVariant();
+}
diff --git a/fastboot/aidl/default/Android.bp b/fastboot/aidl/default/Android.bp
new file mode 100644
index 0000000..0c96b33
--- /dev/null
+++ b/fastboot/aidl/default/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: "android.hardware.fastboot-service.example_recovery",
+    init_rc: ["android.hardware.fastboot-service.example_recovery.rc"],
+    vintf_fragments: ["android.hardware.fastboot-service.example.xml"],
+    recovery_available: true,
+    srcs: [
+        "Fastboot.cpp",
+        "main.cpp",
+    ],
+    relative_install_path: "hw",
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "liblog",
+        "libutils",
+        "libcutils",
+        "android.hardware.fastboot-V1-ndk",
+    ],
+}
diff --git a/fastboot/aidl/default/Fastboot.cpp b/fastboot/aidl/default/Fastboot.cpp
new file mode 100644
index 0000000..1ba73d3
--- /dev/null
+++ b/fastboot/aidl/default/Fastboot.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Fastboot.h"
+
+using ndk::ScopedAStatus;
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace fastboot {
+
+ScopedAStatus Fastboot::getPartitionType(const std::string& in_partitionName,
+                                         FileSystemType* _aidl_return) {
+    if (in_partitionName.empty()) {
+        return ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                           "Invalid partition name");
+    }
+    *_aidl_return = FileSystemType::RAW;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus Fastboot::doOemCommand(const std::string& in_oemCmd, std::string* _aidl_return) {
+    *_aidl_return = "";
+    if (in_oemCmd.empty()) {
+        return ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT, "Invalid command");
+    }
+    return ScopedAStatus::fromExceptionCodeWithMessage(
+            EX_UNSUPPORTED_OPERATION, "Command not supported in default implementation");
+}
+
+ScopedAStatus Fastboot::getVariant(std::string* _aidl_return) {
+    *_aidl_return = "NA";
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus Fastboot::getOffModeChargeState(bool* _aidl_return) {
+    *_aidl_return = false;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus Fastboot::getBatteryVoltageFlashingThreshold(int32_t* _aidl_return) {
+    *_aidl_return = 0;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus Fastboot::doOemSpecificErase() {
+    return ScopedAStatus::fromExceptionCodeWithMessage(
+            EX_UNSUPPORTED_OPERATION, "Command not supported in default implementation");
+}
+
+}  // namespace fastboot
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/fastboot/aidl/default/Fastboot.h b/fastboot/aidl/default/Fastboot.h
new file mode 100644
index 0000000..48e2c38
--- /dev/null
+++ b/fastboot/aidl/default/Fastboot.h
@@ -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.
+ */
+
+#pragma once
+
+#include "aidl/android/hardware/fastboot/BnFastboot.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace fastboot {
+class Fastboot : public BnFastboot {
+    ::ndk::ScopedAStatus doOemCommand(const std::string& in_oemCmd,
+                                      std::string* _aidl_return) override;
+    ::ndk::ScopedAStatus doOemSpecificErase() override;
+    ::ndk::ScopedAStatus getBatteryVoltageFlashingThreshold(int32_t* _aidl_return) override;
+    ::ndk::ScopedAStatus getOffModeChargeState(bool* _aidl_return) override;
+    ::ndk::ScopedAStatus getPartitionType(
+            const std::string& in_partitionName,
+            ::aidl::android::hardware::fastboot::FileSystemType* _aidl_return) override;
+    ::ndk::ScopedAStatus getVariant(std::string* _aidl_return) override;
+};
+
+}  // namespace fastboot
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/fastboot/aidl/default/android.hardware.fastboot-service.example.xml b/fastboot/aidl/default/android.hardware.fastboot-service.example.xml
new file mode 100644
index 0000000..9490f98
--- /dev/null
+++ b/fastboot/aidl/default/android.hardware.fastboot-service.example.xml
@@ -0,0 +1,8 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.fastboot</name>
+        <version>1</version>
+        <fqname>IFastboot/default</fqname>
+    </hal>
+</manifest>
+
diff --git a/fastboot/aidl/default/android.hardware.fastboot-service.example_recovery.rc b/fastboot/aidl/default/android.hardware.fastboot-service.example_recovery.rc
new file mode 100644
index 0000000..5d4ee13
--- /dev/null
+++ b/fastboot/aidl/default/android.hardware.fastboot-service.example_recovery.rc
@@ -0,0 +1,6 @@
+service vendor.fastboot-default /system/bin/hw/android.hardware.fastboot-service.example_recovery
+    class hal
+    seclabel u:r:hal_fastboot_default:s0
+    user system
+    group system
+    interface aidl android.hardware.fastboot.IFastboot/default
diff --git a/fastboot/aidl/default/main.cpp b/fastboot/aidl/default/main.cpp
new file mode 100644
index 0000000..1b1b41d
--- /dev/null
+++ b/fastboot/aidl/default/main.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/binder_manager.h>
+#include <android/binder_process.h>
+#include "Fastboot.h"
+
+using aidl::android::hardware::fastboot::Fastboot;
+using aidl::android::hardware::fastboot::IFastboot;
+
+int main(int, char* argv[]) {
+    android::base::InitLogging(argv, android::base::KernelLogger);
+    ABinderProcess_setThreadPoolMaxThreadCount(0);
+    std::shared_ptr<IFastboot> service = ndk::SharedRefBase::make<Fastboot>();
+
+    const std::string instance = std::string(IFastboot::descriptor) + "/default";
+    auto status = AServiceManager_addService(service->asBinder().get(), instance.c_str());
+    CHECK_EQ(status, STATUS_OK) << "Failed to add service " << instance << " " << status;
+    LOG(INFO) << "IFastboot AIDL service running...";
+
+    ABinderProcess_joinThreadPool();
+    return EXIT_FAILURE;  // should not reach
+}
diff --git a/fastboot/aidl/fastbootshim/Android.bp b/fastboot/aidl/fastbootshim/Android.bp
new file mode 100644
index 0000000..c843c12
--- /dev/null
+++ b/fastboot/aidl/fastbootshim/Android.bp
@@ -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 {
+    // 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: "libfastbootshim_defaults",
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    static_libs: [
+        "android.hardware.fastboot-V1-ndk",
+        "android.hardware.fastboot@1.0",
+        "android.hardware.fastboot@1.1",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "libcutils",
+        "libhidlbase",
+        "liblog",
+        "libutils",
+    ],
+}
+
+// Shim library that wraps a HIDL Fastboot object into an AIDL Fastboot object.
+cc_library_static {
+    name: "libfastbootshim",
+    defaults: ["libfastbootshim_defaults"],
+    recovery_available: true,
+    srcs: [
+        "fastbootshim.cpp",
+    ],
+    export_include_dirs: [
+        "include",
+    ],
+}
diff --git a/fastboot/aidl/fastbootshim/fastbootshim.cpp b/fastboot/aidl/fastbootshim/fastbootshim.cpp
new file mode 100644
index 0000000..4ab67f3
--- /dev/null
+++ b/fastboot/aidl/fastbootshim/fastbootshim.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <fastbootshim.h>
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::Void;
+using ::android::hardware::fastboot::V1_0::FileSystemType;
+using ::android::hardware::fastboot::V1_0::Result;
+using ::android::hardware::fastboot::V1_0::Status;
+
+using ndk::ScopedAStatus;
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace fastboot {
+ScopedAStatus ResultToAStatus(Result result) {
+    switch (result.status) {
+        case Status::SUCCESS:
+            return ScopedAStatus::ok();
+        case Status::NOT_SUPPORTED:
+            return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+        case Status::INVALID_ARGUMENT:
+            return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+        case Status::FAILURE_UNKNOWN:
+            return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                    BnFastboot::FAILURE_UNKNOWN, ("Error " + std::string(result.message)).c_str());
+    }
+    return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+            BnFastboot::FAILURE_UNKNOWN,
+            ("Unrecognized status value " + toString(result.status)).c_str());
+}
+FastbootShim::FastbootShim(const sp<HidlFastboot>& service) : service_(service) {}
+
+ScopedAStatus FastbootShim::getPartitionType(const std::string& in_partitionName,
+                                             FileSystemType* _aidl_return) {
+    Result out_result = {Status::FAILURE_UNKNOWN, ""};
+    if (in_partitionName.empty()) {
+        return ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                           "Invalid partition name");
+    }
+    const hidl_string partition = in_partitionName;
+    auto ret = service_->getPartitionType(partition, [&](auto type, auto& result) {
+        out_result = result;
+        if (out_result.status != Status::SUCCESS) return;
+        *_aidl_return = static_cast<aidl::android::hardware::fastboot::FileSystemType>(type);
+    });
+    return ResultToAStatus(out_result);
+}
+
+ScopedAStatus FastbootShim::doOemCommand(const std::string& in_oemCmd, std::string* _aidl_return) {
+    Result out_result = {Status::FAILURE_UNKNOWN, ""};
+    *_aidl_return = "";
+    if (in_oemCmd.empty()) {
+        return ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT, "Invalid command");
+    }
+    const hidl_string oemCmdArgs = in_oemCmd;
+    auto ret = service_->doOemCommand(oemCmdArgs, [&](auto& result) {
+        out_result = result;
+        if (out_result.status != Status::SUCCESS) return;
+        *_aidl_return = std::string(result.message.c_str());
+    });
+    return ResultToAStatus(out_result);
+}
+
+ScopedAStatus FastbootShim::getVariant(std::string* _aidl_return) {
+    Result out_result = {Status::FAILURE_UNKNOWN, ""};
+    *_aidl_return = "";
+    auto ret = service_->getVariant([&](auto& variant, auto& result) {
+        out_result = result;
+        if (out_result.status != Status::SUCCESS) return;
+        *_aidl_return = std::string(variant.c_str());
+    });
+    return ResultToAStatus(out_result);
+}
+
+ScopedAStatus FastbootShim::getOffModeChargeState(bool* _aidl_return) {
+    Result out_result = {Status::FAILURE_UNKNOWN, ""};
+    *_aidl_return = false;
+    auto ret = service_->getOffModeChargeState([&](auto state, auto& result) {
+        out_result = result;
+        if (out_result.status != Status::SUCCESS) return;
+        *_aidl_return = state;
+    });
+    return ResultToAStatus(out_result);
+}
+
+ScopedAStatus FastbootShim::getBatteryVoltageFlashingThreshold(int32_t* _aidl_return) {
+    Result out_result = {Status::FAILURE_UNKNOWN, ""};
+    *_aidl_return = 0;
+    auto ret = service_->getBatteryVoltageFlashingThreshold([&](auto batteryVoltage, auto& result) {
+        out_result = result;
+        if (out_result.status != Status::SUCCESS) return;
+        *_aidl_return = batteryVoltage;
+    });
+    return ResultToAStatus(out_result);
+}
+
+ScopedAStatus FastbootShim::doOemSpecificErase() {
+    Result out_result = {Status::FAILURE_UNKNOWN, ""};
+    auto ret = service_->doOemSpecificErase([&](auto& result) { out_result = result; });
+    return ResultToAStatus(out_result);
+}
+
+}  // namespace fastboot
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/fastboot/aidl/fastbootshim/include/fastbootshim.h b/fastboot/aidl/fastbootshim/include/fastbootshim.h
new file mode 100644
index 0000000..410a03e
--- /dev/null
+++ b/fastboot/aidl/fastbootshim/include/fastbootshim.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 <aidl/android/hardware/fastboot/BnFastboot.h>
+#include <android/hardware/fastboot/1.1/IFastboot.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace fastboot {
+// Shim that wraps HIDL IFastboot with AIDL BnFastboot
+class FastbootShim : public BnFastboot {
+    using HidlFastboot = ::android::hardware::fastboot::V1_1::IFastboot;
+
+  public:
+    explicit FastbootShim(const ::android::sp<HidlFastboot>& service);
+    ::ndk::ScopedAStatus doOemCommand(const std::string& in_oemCmd,
+                                      std::string* _aidl_return) override;
+    ::ndk::ScopedAStatus doOemSpecificErase() override;
+    ::ndk::ScopedAStatus getBatteryVoltageFlashingThreshold(int32_t* _aidl_return) override;
+    ::ndk::ScopedAStatus getOffModeChargeState(bool* _aidl_return) override;
+    ::ndk::ScopedAStatus getPartitionType(
+            const std::string& in_partitionName,
+            ::aidl::android::hardware::fastboot::FileSystemType* _aidl_return) override;
+    ::ndk::ScopedAStatus getVariant(std::string* _aidl_return) override;
+
+  private:
+    ::android::sp<HidlFastboot> service_;
+};
+
+}  // namespace fastboot
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/gatekeeper/1.0/vts/OWNERS b/gatekeeper/1.0/vts/OWNERS
index 738c710..ee2af97 100644
--- a/gatekeeper/1.0/vts/OWNERS
+++ b/gatekeeper/1.0/vts/OWNERS
@@ -1,3 +1,3 @@
-jdanis@google.com
+# Bug component: 1124862
 swillden@google.com
 guangzhu@google.com
diff --git a/gatekeeper/OWNERS b/gatekeeper/OWNERS
index d95b856..fddc2ff 100644
--- a/gatekeeper/OWNERS
+++ b/gatekeeper/OWNERS
@@ -1,2 +1,4 @@
+# Bug component: 1124862
 swillden@google.com
 guangzhu@google.com
+subrahmanyaman@google.com
diff --git a/gatekeeper/aidl/Android.bp b/gatekeeper/aidl/Android.bp
index 6b1bc7e..770e8ab 100644
--- a/gatekeeper/aidl/Android.bp
+++ b/gatekeeper/aidl/Android.bp
@@ -11,7 +11,7 @@
     name: "android.hardware.gatekeeper",
     vendor_available: true,
     imports: [
-        "android.hardware.security.keymint-V2",
+        "android.hardware.security.keymint-V3",
     ],
     srcs: ["android/hardware/gatekeeper/*.aidl"],
     stability: "vintf",
diff --git a/gnss/1.1/default/Android.bp b/gnss/1.1/default/Android.bp
index a73182e..300e8de 100644
--- a/gnss/1.1/default/Android.bp
+++ b/gnss/1.1/default/Android.bp
@@ -27,7 +27,7 @@
         "android.hardware.gnss@2.0",
         "android.hardware.gnss@1.1",
         "android.hardware.gnss@1.0",
-        "android.hardware.gnss-V2-ndk",
+        "android.hardware.gnss-V3-ndk",
     ],
     static_libs: [
         "android.hardware.gnss@common-default-lib",
diff --git a/gnss/1.1/vts/functional/Android.bp b/gnss/1.1/vts/functional/Android.bp
index f8fad94..2414cbc 100644
--- a/gnss/1.1/vts/functional/Android.bp
+++ b/gnss/1.1/vts/functional/Android.bp
@@ -36,7 +36,7 @@
         "android.hardware.gnss@1.1",
         "android.hardware.gnss@2.0",
         "android.hardware.gnss@common-vts-lib",
-        "android.hardware.gnss-V2-cpp",
+        "android.hardware.gnss-V3-cpp",
     ],
     shared_libs: [
         "android.hardware.gnss.measurement_corrections@1.0",
diff --git a/gnss/2.0/default/Android.bp b/gnss/2.0/default/Android.bp
index 769e8ae..83bc2cc 100644
--- a/gnss/2.0/default/Android.bp
+++ b/gnss/2.0/default/Android.bp
@@ -50,7 +50,7 @@
         "android.hardware.gnss@2.0",
         "android.hardware.gnss@1.1",
         "android.hardware.gnss@1.0",
-        "android.hardware.gnss-V2-ndk",
+        "android.hardware.gnss-V3-ndk",
     ],
     static_libs: [
         "android.hardware.gnss@common-default-lib",
diff --git a/gnss/2.0/vts/functional/Android.bp b/gnss/2.0/vts/functional/Android.bp
index 2042dd9..e8db886 100644
--- a/gnss/2.0/vts/functional/Android.bp
+++ b/gnss/2.0/vts/functional/Android.bp
@@ -39,7 +39,7 @@
         "android.hardware.gnss@2.0",
         "android.hardware.gnss@2.1",
         "android.hardware.gnss@common-vts-lib",
-        "android.hardware.gnss-V2-cpp",
+        "android.hardware.gnss-V3-cpp",
     ],
     test_suites: [
         "general-tests",
diff --git a/gnss/2.1/default/Android.bp b/gnss/2.1/default/Android.bp
index 2979f5c..4a4ce54 100644
--- a/gnss/2.1/default/Android.bp
+++ b/gnss/2.1/default/Android.bp
@@ -44,7 +44,7 @@
         "android.hardware.gnss@1.0",
         "android.hardware.gnss@1.1",
         "android.hardware.gnss@2.0",
-        "android.hardware.gnss-V2-ndk",
+        "android.hardware.gnss-V3-ndk",
     ],
     static_libs: [
         "android.hardware.gnss@common-default-lib",
diff --git a/gnss/2.1/vts/functional/Android.bp b/gnss/2.1/vts/functional/Android.bp
index d7b6eeb..76f9d07 100644
--- a/gnss/2.1/vts/functional/Android.bp
+++ b/gnss/2.1/vts/functional/Android.bp
@@ -40,7 +40,7 @@
         "android.hardware.gnss@2.0",
         "android.hardware.gnss@2.1",
         "android.hardware.gnss@common-vts-lib",
-        "android.hardware.gnss-V2-cpp",
+        "android.hardware.gnss-V3-cpp",
     ],
     shared_libs: [
         "libvintf",
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssData.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssData.aidl
index 31426f0..54e3b21 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssData.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssData.aidl
@@ -39,6 +39,7 @@
   android.hardware.gnss.GnssClock clock;
   android.hardware.gnss.ElapsedRealtime elapsedRealtime;
   android.hardware.gnss.GnssData.GnssAgc[] gnssAgcs = {};
+  boolean isFullTracking;
   @VintfStability
   parcelable GnssAgc {
     double agcLevelDb;
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IAGnssRil.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IAGnssRil.aidl
index 8930752..c782b6f 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IAGnssRil.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IAGnssRil.aidl
@@ -39,6 +39,7 @@
   void setRefLocation(in android.hardware.gnss.IAGnssRil.AGnssRefLocation agnssReflocation);
   void setSetId(in android.hardware.gnss.IAGnssRil.SetIdType type, in @utf8InCpp String setid);
   void updateNetworkState(in android.hardware.gnss.IAGnssRil.NetworkAttributes attributes);
+  void injectNiSuplMessageData(in byte[] msgData, in int slotIndex);
   const int NETWORK_CAPABILITY_NOT_METERED = 1;
   const int NETWORK_CAPABILITY_NOT_ROAMING = 2;
   @Backing(type="int") @VintfStability
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 48c88f5..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
@@ -45,6 +45,7 @@
   void gnssSetSystemInfoCb(in android.hardware.gnss.IGnssCallback.GnssSystemInfo info);
   void gnssRequestTimeCb();
   void gnssRequestLocationCb(in boolean independentFromGnss, in boolean isUserEmergency);
+  void gnssSetSignalTypeCapabilitiesCb(in android.hardware.gnss.GnssSignalType[] gnssSignalTypes);
   const int CAPABILITY_SCHEDULING = 1;
   const int CAPABILITY_MSB = 2;
   const int CAPABILITY_MSA = 4;
@@ -60,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/GnssData.aidl b/gnss/aidl/android/hardware/gnss/GnssData.aidl
index 075a039..492ba31 100644
--- a/gnss/aidl/android/hardware/gnss/GnssData.aidl
+++ b/gnss/aidl/android/hardware/gnss/GnssData.aidl
@@ -99,4 +99,15 @@
      * weak to be acquired, the AGC value must still be reported.
      */
     GnssAgc[] gnssAgcs = {};
+
+    /**
+     * True indicates that the GNSS chipset switches off duty cycling. In such mode, no clock
+     * discontinuities are expected and, when supported, carrier phase should be continuous in good
+     * signal conditions. All non-blocklisted, healthy constellations, satellites and frequency
+     * bands must be tracked and reported in this mode.
+     *
+     * False indicates that the GNSS chipset optimizes power via duty cycling, constellations and
+     * frequency limits, etc.
+     */
+    boolean isFullTracking;
 }
diff --git a/gnss/aidl/android/hardware/gnss/IAGnssRil.aidl b/gnss/aidl/android/hardware/gnss/IAGnssRil.aidl
index 44847f0..5f2e261 100644
--- a/gnss/aidl/android/hardware/gnss/IAGnssRil.aidl
+++ b/gnss/aidl/android/hardware/gnss/IAGnssRil.aidl
@@ -164,4 +164,14 @@
      *
      */
     void updateNetworkState(in NetworkAttributes attributes);
+
+    /**
+     * Injects an SMS/WAP initiated SUPL message.
+     *
+     * @param msgData ASN.1 encoded SUPL INIT message. This is defined in
+     * UserPlane Location Protocol (Version 2.0.4).
+     * @param slotIndex Specifies the slot index (See
+     *         android.telephony.SubscriptionManager#getSlotIndex()) of the SUPL connection.
+     */
+    void injectNiSuplMessageData(in byte[] msgData, in int slotIndex);
 }
diff --git a/gnss/aidl/android/hardware/gnss/IGnss.aidl b/gnss/aidl/android/hardware/gnss/IGnss.aidl
index f0b583d..aaafe7f 100644
--- a/gnss/aidl/android/hardware/gnss/IGnss.aidl
+++ b/gnss/aidl/android/hardware/gnss/IGnss.aidl
@@ -104,7 +104,7 @@
      *
      * The framework calls this method to instruct the GPS engine to prepare for serving requests
      * from the framework. The GNSS HAL implementation must respond to all GNSS requests from the
-     * framework upon successful return from this method until cleanup() method is called to
+     * framework upon successful return from this method until close() method is called to
      * close this interface.
      *
      * @param callback Callback interface for IGnss.
diff --git a/gnss/aidl/android/hardware/gnss/IGnssCallback.aidl b/gnss/aidl/android/hardware/gnss/IGnssCallback.aidl
index 8633bea..ff9feea 100644
--- a/gnss/aidl/android/hardware/gnss/IGnssCallback.aidl
+++ b/gnss/aidl/android/hardware/gnss/IGnssCallback.aidl
@@ -18,6 +18,7 @@
 
 import android.hardware.gnss.GnssConstellationType;
 import android.hardware.gnss.GnssLocation;
+import android.hardware.gnss.GnssSignalType;
 import android.hardware.gnss.IGnssConfiguration;
 import android.hardware.gnss.IGnssPsds;
 
@@ -81,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.
      *
@@ -308,4 +312,18 @@
      *        during-call to E911, or up to 5 minutes after end-of-call or text to E911).
      */
     void gnssRequestLocationCb(in boolean independentFromGnss, in boolean isUserEmergency);
+
+    /**
+     * Callback to inform the framework of the list of GnssSignalTypes the GNSS HAL implementation
+     * supports.
+     *
+     * These capabilities are static at runtime, i.e., they represent the signal types the
+     * GNSS implementation supports without considering the temporary disabled signal types such as
+     * the blocklisted satellites/constellations or the constellations disabled by regional
+     * restrictions.
+     *
+     * @param gnssSignalTypes a list of GnssSignalTypes specifying the constellations, carrier
+     *     frequencies, and the code types the GNSS HAL implementation supports.
+     */
+    void gnssSetSignalTypeCapabilitiesCb(in GnssSignalType[] gnssSignalTypes);
 }
diff --git a/gnss/aidl/android/hardware/gnss/IGnssMeasurementInterface.aidl b/gnss/aidl/android/hardware/gnss/IGnssMeasurementInterface.aidl
index 8733754..4316407 100644
--- a/gnss/aidl/android/hardware/gnss/IGnssMeasurementInterface.aidl
+++ b/gnss/aidl/android/hardware/gnss/IGnssMeasurementInterface.aidl
@@ -78,6 +78,9 @@
      * output rate of 1Hz (occasional intra-measurement time offsets in the range from 0-2000msec
      * can be tolerated.)
      *
+     * If setCallback() is invoked without a previous close(), the HAL must use the new callback
+     * and parameters to provide updates.
+     *
      * @param callback Handle to GnssMeasurement callback interface.
      * @param enableFullTracking If true, GNSS chipset must switch off duty cycling. In such mode
      *     no clock discontinuities are expected and, when supported, carrier phase should be
@@ -104,6 +107,9 @@
     /**
      * Initializes the interface and registers the callback routines with the HAL.
      *
+     * If setCallbackWithOptions() is invoked without a previous close(), the HAL must use the new
+     * callback and options to provide updates.
+     *
      * @param options See Options definition.
      */
     void setCallbackWithOptions(in IGnssMeasurementCallback callback, in Options options);
diff --git a/gnss/aidl/default/AGnssRil.cpp b/gnss/aidl/default/AGnssRil.cpp
index 2aa1abc..81b4f2a 100644
--- a/gnss/aidl/default/AGnssRil.cpp
+++ b/gnss/aidl/default/AGnssRil.cpp
@@ -17,6 +17,7 @@
 #define LOG_TAG "AGnssRilAidl"
 
 #include "AGnssRil.h"
+#include <aidl/android/hardware/gnss/BnGnss.h>
 #include <inttypes.h>
 #include <log/log.h>
 
@@ -55,4 +56,15 @@
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus AGnssRil::injectNiSuplMessageData(const std::vector<uint8_t>& msgData,
+                                                     int slotIndex) {
+    ALOGD("AGnssRil::injectNiSuplMessageData: msgData:%d bytes slotIndex:%d",
+          static_cast<int>(msgData.size()), slotIndex);
+    if (msgData.size() > 0) {
+        return ndk::ScopedAStatus::ok();
+    } else {
+        return ndk::ScopedAStatus::fromServiceSpecificError(IGnss::ERROR_INVALID_ARGUMENT);
+    }
+}
+
 }  // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/AGnssRil.h b/gnss/aidl/default/AGnssRil.h
index e205b69..76583ac 100644
--- a/gnss/aidl/default/AGnssRil.h
+++ b/gnss/aidl/default/AGnssRil.h
@@ -26,6 +26,8 @@
     ndk::ScopedAStatus setRefLocation(const AGnssRefLocation& agnssReflocation) override;
     ndk::ScopedAStatus setSetId(SetIdType type, const std::string& setid) override;
     ndk::ScopedAStatus updateNetworkState(const NetworkAttributes& attributes) override;
+    ndk::ScopedAStatus injectNiSuplMessageData(const std::vector<uint8_t>& msgData,
+                                               int slotIndex) override;
 
   private:
     // Synchronization lock for sCallback
diff --git a/gnss/aidl/default/Android.bp b/gnss/aidl/default/Android.bp
index c8ae6b2..ca5a41f 100644
--- a/gnss/aidl/default/Android.bp
+++ b/gnss/aidl/default/Android.bp
@@ -50,7 +50,7 @@
         "android.hardware.gnss.measurement_corrections@1.1",
         "android.hardware.gnss.measurement_corrections@1.0",
         "android.hardware.gnss.visibility_control@1.0",
-        "android.hardware.gnss-V2-ndk",
+        "android.hardware.gnss-V3-ndk",
     ],
     srcs: [
         "AGnssRil.cpp",
diff --git a/gnss/aidl/default/Gnss.cpp b/gnss/aidl/default/Gnss.cpp
index cf2c90d..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__);
@@ -68,13 +69,27 @@
 
     IGnssCallback::GnssSystemInfo systemInfo = {
             .yearOfHw = 2022,
-            .name = "Google Mock GNSS Implementation AIDL v2",
+            .name = "Google, Cuttlefish, AIDL v3",
     };
     status = sGnssCallback->gnssSetSystemInfoCb(systemInfo);
     if (!status.isOk()) {
         ALOGE("%s: Unable to invoke callback.gnssSetSystemInfoCb", __func__);
     }
-
+    GnssSignalType signalType1 = {
+            .constellation = GnssConstellationType::GPS,
+            .carrierFrequencyHz = 1.57542e+09,
+            .codeType = GnssSignalType::CODE_TYPE_C,
+    };
+    GnssSignalType signalType2 = {
+            .constellation = GnssConstellationType::GLONASS,
+            .carrierFrequencyHz = 1.5980625e+09,
+            .codeType = GnssSignalType::CODE_TYPE_C,
+    };
+    status = sGnssCallback->gnssSetSignalTypeCapabilitiesCb(
+            std::vector<GnssSignalType>({signalType1, signalType2}));
+    if (!status.isOk()) {
+        ALOGE("%s: Unable to invoke callback.gnssSetSignalTypeCapabilitiesCb", __func__);
+    }
     return ScopedAStatus::ok();
 }
 
diff --git a/gnss/aidl/default/GnssMeasurementInterface.cpp b/gnss/aidl/default/GnssMeasurementInterface.cpp
index 606de07..90056ce 100644
--- a/gnss/aidl/default/GnssMeasurementInterface.cpp
+++ b/gnss/aidl/default/GnssMeasurementInterface.cpp
@@ -54,7 +54,7 @@
         ALOGW("GnssMeasurement callback already set. Resetting the callback...");
         stop();
     }
-    start(enableCorrVecOutputs);
+    start(enableCorrVecOutputs, enableFullTracking);
 
     return ndk::ScopedAStatus::ok();
 }
@@ -73,7 +73,7 @@
         stop();
     }
     mIntervalMs = std::max(options.intervalMs, 1000);
-    start(options.enableCorrVecOutputs);
+    start(options.enableCorrVecOutputs, options.enableFullTracking);
 
     return ndk::ScopedAStatus::ok();
 }
@@ -91,7 +91,8 @@
     return ndk::ScopedAStatus::ok();
 }
 
-void GnssMeasurementInterface::start(const bool enableCorrVecOutputs) {
+void GnssMeasurementInterface::start(const bool enableCorrVecOutputs,
+                                     const bool enableFullTracking) {
     ALOGD("start");
 
     if (mIsActive) {
@@ -103,7 +104,7 @@
 
     mIsActive = true;
     mThreadBlocker.reset();
-    mThread = std::thread([this, enableCorrVecOutputs]() {
+    mThread = std::thread([this, enableCorrVecOutputs, enableFullTracking]() {
         int intervalMs;
         do {
             if (!mIsActive) {
@@ -122,7 +123,8 @@
                     this->reportMeasurement(*measurement);
                 }
             } else {
-                auto measurement = Utils::getMockMeasurement(enableCorrVecOutputs);
+                auto measurement =
+                        Utils::getMockMeasurement(enableCorrVecOutputs, enableFullTracking);
                 this->reportMeasurement(measurement);
             }
             intervalMs =
diff --git a/gnss/aidl/default/GnssMeasurementInterface.h b/gnss/aidl/default/GnssMeasurementInterface.h
index bb08027..d2737e5 100644
--- a/gnss/aidl/default/GnssMeasurementInterface.h
+++ b/gnss/aidl/default/GnssMeasurementInterface.h
@@ -41,7 +41,7 @@
     void setLocationEnabled(const bool enabled);
 
   private:
-    void start(const bool enableCorrVecOutputs);
+    void start(const bool enableCorrVecOutputs, const bool enableFullTracking);
     void stop();
     void reportMeasurement(const GnssData&);
     void waitForStoppingThreads();
diff --git a/gnss/aidl/default/gnss-default.xml b/gnss/aidl/default/gnss-default.xml
index 7449310..73b841e 100644
--- a/gnss/aidl/default/gnss-default.xml
+++ b/gnss/aidl/default/gnss-default.xml
@@ -1,7 +1,7 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.gnss</name>
-        <version>2</version>
+        <version>3</version>
         <interface>
             <name>IGnss</name>
             <instance>default</instance>
diff --git a/gnss/aidl/vts/Android.bp b/gnss/aidl/vts/Android.bp
index f02a41e..2a09a56 100644
--- a/gnss/aidl/vts/Android.bp
+++ b/gnss/aidl/vts/Android.bp
@@ -51,7 +51,7 @@
         "libbinder",
     ],
     static_libs: [
-        "android.hardware.gnss-V2-cpp",
+        "android.hardware.gnss-V3-cpp",
         "android.hardware.gnss@common-vts-lib",
     ],
     test_suites: [
diff --git a/gnss/aidl/vts/GnssCallbackAidl.cpp b/gnss/aidl/vts/GnssCallbackAidl.cpp
index 2f6128b..d3be414 100644
--- a/gnss/aidl/vts/GnssCallbackAidl.cpp
+++ b/gnss/aidl/vts/GnssCallbackAidl.cpp
@@ -23,6 +23,7 @@
 using android::hardware::gnss::GnssLocation;
 using GnssSvInfo = android::hardware::gnss::IGnssCallback::GnssSvInfo;
 using GnssSystemInfo = android::hardware::gnss::IGnssCallback::GnssSystemInfo;
+using GnssSignalType = android::hardware::gnss::GnssSignalType;
 
 Status GnssCallbackAidl::gnssSetCapabilitiesCb(const int capabilities) {
     ALOGI("Capabilities received %#08x", capabilities);
@@ -30,6 +31,20 @@
     return Status::ok();
 }
 
+Status GnssCallbackAidl::gnssSetSignalTypeCapabilitiesCb(
+        const std::vector<GnssSignalType>& signalTypes) {
+    ALOGI("SignalTypeCapabilities received");
+    std::ostringstream ss;
+    for (auto& signalType : signalTypes) {
+        ss << "[constellation=" << (int)signalType.constellation
+           << ", carrierFrequencyHz=" << signalType.carrierFrequencyHz
+           << ", codeType=" << signalType.codeType << "], ";
+    }
+    ALOGI("%s", ss.str().c_str());
+    signal_type_capabilities_cbq_.store(signalTypes);
+    return Status::ok();
+}
+
 Status GnssCallbackAidl::gnssStatusCb(const GnssStatusValue /* status */) {
     ALOGI("gnssStatusCb");
     return Status::ok();
diff --git a/gnss/aidl/vts/GnssCallbackAidl.h b/gnss/aidl/vts/GnssCallbackAidl.h
index a9495ba..06526d3 100644
--- a/gnss/aidl/vts/GnssCallbackAidl.h
+++ b/gnss/aidl/vts/GnssCallbackAidl.h
@@ -25,6 +25,7 @@
   public:
     GnssCallbackAidl()
         : capabilities_cbq_("capabilities"),
+          signal_type_capabilities_cbq_("signal_type_capabilities"),
           info_cbq_("system_info"),
           location_cbq_("location"),
           sv_info_list_cbq_("sv_info"),
@@ -32,6 +33,8 @@
     ~GnssCallbackAidl(){};
 
     android::binder::Status gnssSetCapabilitiesCb(const int capabilities) override;
+    android::binder::Status gnssSetSignalTypeCapabilitiesCb(
+            const std::vector<android::hardware::gnss::GnssSignalType>& signalTypes) override;
     android::binder::Status gnssStatusCb(const GnssStatusValue status) override;
     android::binder::Status gnssSvStatusCb(const std::vector<GnssSvInfo>& svInfoList) override;
     android::binder::Status gnssLocationCb(
@@ -45,11 +48,15 @@
                                                   const bool isUserEmergency) override;
 
     int last_capabilities_;
+    std::vector<android::hardware::gnss::GnssSignalType> last_signal_type_capabilities;
     android::hardware::gnss::IGnssCallback::GnssSystemInfo last_info_;
     android::hardware::gnss::GnssLocation last_location_;
 
     android::hardware::gnss::common::GnssCallbackEventQueue<int> capabilities_cbq_;
     android::hardware::gnss::common::GnssCallbackEventQueue<
+            std::vector<android::hardware::gnss::GnssSignalType>>
+            signal_type_capabilities_cbq_;
+    android::hardware::gnss::common::GnssCallbackEventQueue<
             android::hardware::gnss::IGnssCallback::GnssSystemInfo>
             info_cbq_;
     android::hardware::gnss::common::GnssCallbackEventQueue<android::hardware::gnss::GnssLocation>
diff --git a/gnss/aidl/vts/GnssMeasurementCallbackAidl.cpp b/gnss/aidl/vts/GnssMeasurementCallbackAidl.cpp
index a553954..0d15b2a 100644
--- a/gnss/aidl/vts/GnssMeasurementCallbackAidl.cpp
+++ b/gnss/aidl/vts/GnssMeasurementCallbackAidl.cpp
@@ -24,9 +24,11 @@
 
 android::binder::Status GnssMeasurementCallbackAidl::gnssMeasurementCb(const GnssData& gnssData) {
     ALOGI("gnssMeasurementCb");
-    ALOGV("elapsedRealtime: flags = 0x%X, timestampNs: %" PRId64 ", timeUncertaintyNs=%lf",
+    ALOGV("elapsedRealtime: flags = 0x%X, timestampNs: %" PRId64
+          ", timeUncertaintyNs=%lf"
+          " isFullTracking=%s",
           gnssData.elapsedRealtime.flags, gnssData.elapsedRealtime.timestampNs,
-          gnssData.elapsedRealtime.timeUncertaintyNs);
+          gnssData.elapsedRealtime.timeUncertaintyNs, gnssData.isFullTracking ? "true" : "false");
 
     gnss_data_cbq_.store(gnssData);
     return android::binder::Status::ok();
diff --git a/gnss/aidl/vts/gnss_hal_test.cpp b/gnss/aidl/vts/gnss_hal_test.cpp
index 0e1218e..7578585 100644
--- a/gnss/aidl/vts/gnss_hal_test.cpp
+++ b/gnss/aidl/vts/gnss_hal_test.cpp
@@ -105,6 +105,26 @@
         EXPECT_TRUE(aidl_gnss_cb_->info_cbq_.retrieve(aidl_gnss_cb_->last_info_, TIMEOUT_SEC));
         EXPECT_EQ(aidl_gnss_cb_->info_cbq_.calledCount(), 1);
     }
+
+    /*
+     * SignalTypeCapabilities callback should trigger.
+     */
+    if (aidl_gnss_hal_->getInterfaceVersion() >= 3) {
+        EXPECT_TRUE(aidl_gnss_cb_->signal_type_capabilities_cbq_.retrieve(
+                aidl_gnss_cb_->last_signal_type_capabilities, TIMEOUT_SEC));
+        EXPECT_EQ(aidl_gnss_cb_->signal_type_capabilities_cbq_.calledCount(), 1);
+    }
+}
+
+void GnssHalTest::TearDown() {
+    GnssHalTestTemplate<IGnss_V2_1>::TearDown();
+    if (aidl_gnss_hal_ != nullptr) {
+        aidl_gnss_hal_->close();
+        aidl_gnss_hal_ = nullptr;
+    }
+
+    // Set to nullptr to destruct the callback event queues and warn of any unprocessed events.
+    aidl_gnss_cb_ = nullptr;
 }
 
 void GnssHalTest::CheckLocation(const GnssLocation& location, bool check_speed) {
@@ -457,6 +477,28 @@
     }
 }
 
+void GnssHalTest::checkGnssDataFields(const sp<GnssMeasurementCallbackAidl>& callback,
+                                      const int numMeasurementEvents, const int timeoutSeconds,
+                                      const bool isFullTracking) {
+    for (int i = 0; i < numMeasurementEvents; i++) {
+        GnssData lastGnssData;
+        ASSERT_TRUE(callback->gnss_data_cbq_.retrieve(lastGnssData, timeoutSeconds));
+        EXPECT_EQ(callback->gnss_data_cbq_.calledCount(), i + 1);
+        ASSERT_TRUE(lastGnssData.measurements.size() > 0);
+
+        // Validity check GnssData fields
+        checkGnssMeasurementClockFields(lastGnssData);
+        if (aidl_gnss_hal_->getInterfaceVersion() >= 3) {
+            if (isFullTracking) {
+                EXPECT_EQ(lastGnssData.isFullTracking, isFullTracking);
+            }
+        }
+        for (const auto& measurement : lastGnssData.measurements) {
+            checkGnssMeasurementFields(measurement, lastGnssData);
+        }
+    }
+}
+
 void GnssHalTest::assertMeanAndStdev(int intervalMs, std::vector<int>& deltasMs) {
     double mean = computeMean(deltasMs);
     double stdev = computeStdev(mean, deltasMs);
diff --git a/gnss/aidl/vts/gnss_hal_test.h b/gnss/aidl/vts/gnss_hal_test.h
index 645fc82..470294c 100644
--- a/gnss/aidl/vts/gnss_hal_test.h
+++ b/gnss/aidl/vts/gnss_hal_test.h
@@ -64,6 +64,7 @@
 
     virtual void SetUp() override;
     virtual void SetUpGnssCallback() override;
+    virtual void TearDown() override;
 
     void CheckLocation(const android::hardware::gnss::GnssLocation& location,
                        const bool check_speed);
@@ -100,6 +101,9 @@
     void collectMeasurementIntervals(const sp<GnssMeasurementCallbackAidl>& callback,
                                      const int numMeasurementEvents, const int timeoutSeconds,
                                      std::vector<int>& deltaMs);
+    void checkGnssDataFields(const sp<GnssMeasurementCallbackAidl>& callback,
+                             const int numMeasurementEvents, const int timeoutSeconds,
+                             const bool isFullTracking);
     void assertMeanAndStdev(int intervalMillis, std::vector<int>& deltasMillis);
 
     sp<IGnssAidl> aidl_gnss_hal_;
diff --git a/gnss/aidl/vts/gnss_hal_test_cases.cpp b/gnss/aidl/vts/gnss_hal_test_cases.cpp
index 3696233..48027b6 100644
--- a/gnss/aidl/vts/gnss_hal_test_cases.cpp
+++ b/gnss/aidl/vts/gnss_hal_test_cases.cpp
@@ -173,6 +173,7 @@
  * GnssCapabilities:
  * 1. Verifies that GNSS hardware supports measurement capabilities.
  * 2. Verifies that GNSS hardware supports Scheduling capabilities.
+ * 3. Verifies that GNSS hardware supports non-empty signal type capabilities.
  */
 TEST_P(GnssHalTest, GnssCapabilites) {
     if (aidl_gnss_hal_->getInterfaceVersion() <= 1) {
@@ -182,6 +183,10 @@
         EXPECT_TRUE(aidl_gnss_cb_->last_capabilities_ & IGnssCallback::CAPABILITY_MEASUREMENTS);
     }
     EXPECT_TRUE(aidl_gnss_cb_->last_capabilities_ & IGnssCallback::CAPABILITY_SCHEDULING);
+    if (aidl_gnss_hal_->getInterfaceVersion() <= 2) {
+        return;
+    }
+    EXPECT_FALSE(aidl_gnss_cb_->last_signal_type_capabilities.empty());
 }
 
 /*
@@ -1077,6 +1082,7 @@
  * 2. Sets AGnssRilCallback.
  * 3. Update network state to connected and then disconnected.
  * 4. Sets reference location.
+ * 5. Injects empty NI message data and verifies that it returns an error.
  */
 TEST_P(GnssHalTest, TestAGnssRilExtension) {
     if (aidl_gnss_hal_->getInterfaceVersion() <= 1) {
@@ -1120,6 +1126,9 @@
 
     status = iAGnssRil->setRefLocation(agnssReflocation);
     ASSERT_TRUE(status.isOk());
+
+    status = iAGnssRil->injectNiSuplMessageData(std::vector<uint8_t>(), 0);
+    ASSERT_FALSE(status.isOk());
 }
 
 /*
@@ -1462,7 +1471,7 @@
 /*
  * TestGnssMeasurementIntervals:
  * 1. start measurement with interval
- * 2. verify that the received measurement intervals have expected mean and stdev
+ * 2. verify that the received measurement intervals have expected mean and stddev
  */
 TEST_P(GnssHalTest, TestGnssMeasurementIntervals_LocationOnAfterMeasurement) {
     if (aidl_gnss_hal_->getInterfaceVersion() <= 1) {
@@ -1494,3 +1503,136 @@
         assertMeanAndStdev(locationIntervalMs, deltas);
     }
 }
+
+/*
+ * 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.
+ *    Verify the measurements were received at 1Hz.
+ */
+TEST_P(GnssHalTest, TestGnssMeasurementSetCallback) {
+    if (aidl_gnss_hal_->getInterfaceVersion() <= 2) {
+        return;
+    }
+    const int kFirstGnssMeasurementTimeoutSeconds = 10;
+    sp<IGnssMeasurementInterface> iGnssMeasurement;
+    auto status = aidl_gnss_hal_->getExtensionGnssMeasurement(&iGnssMeasurement);
+    ASSERT_TRUE(status.isOk());
+    ASSERT_TRUE(iGnssMeasurement != nullptr);
+
+    ALOGD("TestGnssMeasurementSetCallback");
+    auto callback = sp<GnssMeasurementCallbackAidl>::make();
+    std::vector<int> deltas;
+
+    // setCallback at 20s interval and wait for 1 measurement
+    startMeasurementWithInterval(20000, iGnssMeasurement, callback);
+    collectMeasurementIntervals(callback, /* numEvents= */ 1, kFirstGnssMeasurementTimeoutSeconds,
+                                deltas);
+
+    // setCallback at 1s interval and wait for 5 measurements
+    callback->gnss_data_cbq_.reset();
+    startMeasurementWithInterval(1000, iGnssMeasurement, callback);
+    collectMeasurementIntervals(callback, /* numEvents= */ 5, kFirstGnssMeasurementTimeoutSeconds,
+                                deltas);
+
+    // verify the measurements were received at 1Hz
+    assertMeanAndStdev(1000, deltas);
+
+    status = iGnssMeasurement->close();
+    ASSERT_TRUE(status.isOk());
+}
+
+/*
+ * TestGnssMeasurementIsFullTracking
+ * 1. Start measurement with enableFullTracking=true. Verify the received measurements have
+ *    isFullTracking=true.
+ * 2. Start measurement with enableFullTracking = false. Verify the received measurements have
+ *    isFullTracking=false.
+ * 3. Do step 1 again.
+ */
+TEST_P(GnssHalTest, TestGnssMeasurementIsFullTracking) {
+    // GnssData.isFullTracking is added in the interface version 3
+    if (aidl_gnss_hal_->getInterfaceVersion() <= 2) {
+        return;
+    }
+    const int kFirstGnssMeasurementTimeoutSeconds = 10;
+    const int kNumMeasurementEvents = 5;
+    std::vector<bool> isFullTrackingList({true, false, true});
+
+    sp<IGnssMeasurementInterface> iGnssMeasurement;
+    auto status = aidl_gnss_hal_->getExtensionGnssMeasurement(&iGnssMeasurement);
+    ASSERT_TRUE(status.isOk());
+    ASSERT_TRUE(iGnssMeasurement != nullptr);
+
+    ALOGD("TestGnssMeasurementIsFullTracking");
+    auto callback = sp<GnssMeasurementCallbackAidl>::make();
+    IGnssMeasurementInterface::Options options;
+    options.intervalMs = 1000;
+
+    for (auto isFullTracking : isFullTrackingList) {
+        options.enableFullTracking = isFullTracking;
+
+        callback->gnss_data_cbq_.reset();
+        auto status = iGnssMeasurement->setCallbackWithOptions(callback, options);
+        checkGnssDataFields(callback, kNumMeasurementEvents, kFirstGnssMeasurementTimeoutSeconds,
+                            isFullTracking);
+    }
+
+    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/Android.bp b/gnss/common/utils/default/Android.bp
index b896f04..4cf17a6 100644
--- a/gnss/common/utils/default/Android.bp
+++ b/gnss/common/utils/default/Android.bp
@@ -57,6 +57,6 @@
         "android.hardware.gnss@2.1",
         "android.hardware.gnss.measurement_corrections@1.1",
         "android.hardware.gnss.measurement_corrections@1.0",
-        "android.hardware.gnss-V2-ndk",
+        "android.hardware.gnss-V3-ndk",
     ],
 }
diff --git a/gnss/common/utils/default/Utils.cpp b/gnss/common/utils/default/Utils.cpp
index 4de49f3..2aed29b 100644
--- a/gnss/common/utils/default/Utils.cpp
+++ b/gnss/common/utils/default/Utils.cpp
@@ -147,7 +147,7 @@
     return gnssData;
 }
 
-GnssData Utils::getMockMeasurement(const bool enableCorrVecOutputs) {
+GnssData Utils::getMockMeasurement(const bool enableCorrVecOutputs, const bool enableFullTracking) {
     aidl::android::hardware::gnss::GnssSignalType signalType = {
             .constellation = GnssConstellationType::GLONASS,
             .carrierFrequencyHz = 1.59975e+09,
@@ -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,
@@ -258,7 +258,8 @@
     GnssData gnssData = {.measurements = {measurement},
                          .clock = clock,
                          .elapsedRealtime = timestamp,
-                         .gnssAgcs = std::vector({gnssAgc1, gnssAgc2})};
+                         .gnssAgcs = std::vector({gnssAgc1, gnssAgc2}),
+                         .isFullTracking = enableFullTracking};
     return gnssData;
 }
 
diff --git a/gnss/common/utils/default/include/Utils.h b/gnss/common/utils/default/include/Utils.h
index ad8f539..9be4a19 100644
--- a/gnss/common/utils/default/include/Utils.h
+++ b/gnss/common/utils/default/include/Utils.h
@@ -32,7 +32,7 @@
 
 struct Utils {
     static aidl::android::hardware::gnss::GnssData getMockMeasurement(
-            const bool enableCorrVecOutputs);
+            const bool enableCorrVecOutputs, const bool enableFullTracking);
     static V2_0::IGnssMeasurementCallback::GnssData getMockMeasurementV2_0();
     static V2_1::IGnssMeasurementCallback::GnssData getMockMeasurementV2_1();
 
diff --git a/gnss/common/utils/vts/Android.bp b/gnss/common/utils/vts/Android.bp
index f92e609..b5325b2 100644
--- a/gnss/common/utils/vts/Android.bp
+++ b/gnss/common/utils/vts/Android.bp
@@ -44,7 +44,7 @@
         "android.hardware.gnss@2.1",
         "android.hardware.gnss.measurement_corrections@1.0",
         "android.hardware.gnss.measurement_corrections@1.1",
-        "android.hardware.gnss-V2-cpp",
+        "android.hardware.gnss-V3-cpp",
     ],
     static_libs: [
         "libgtest",
diff --git a/graphics/Android.bp b/graphics/Android.bp
index b48844d..4898dbe 100644
--- a/graphics/Android.bp
+++ b/graphics/Android.bp
@@ -19,41 +19,41 @@
 cc_defaults {
     name: "android.hardware.graphics.allocator-ndk_static",
     static_libs: [
-        "android.hardware.graphics.allocator-V1-ndk",
+        "android.hardware.graphics.allocator-V2-ndk",
     ],
 }
 
 cc_defaults {
     name: "android.hardware.graphics.allocator-ndk_shared",
     shared_libs: [
-        "android.hardware.graphics.allocator-V1-ndk",
+        "android.hardware.graphics.allocator-V2-ndk",
     ],
 }
 
 cc_defaults {
     name: "android.hardware.graphics.common-ndk_static",
     static_libs: [
-        "android.hardware.graphics.common-V3-ndk",
+        "android.hardware.graphics.common-V4-ndk",
     ],
 }
 
 cc_defaults {
     name: "android.hardware.graphics.common-ndk_shared",
     shared_libs: [
-        "android.hardware.graphics.common-V3-ndk",
+        "android.hardware.graphics.common-V4-ndk",
     ],
 }
 
 cc_defaults {
     name: "android.hardware.graphics.composer3-ndk_static",
     static_libs: [
-        "android.hardware.graphics.composer3-V1-ndk",
+        "android.hardware.graphics.composer3-V2-ndk",
     ],
 }
 
 cc_defaults {
     name: "android.hardware.graphics.composer3-ndk_shared",
     shared_libs: [
-        "android.hardware.graphics.composer3-V1-ndk",
+        "android.hardware.graphics.composer3-V2-ndk",
     ],
 }
diff --git a/graphics/OWNERS b/graphics/OWNERS
index 75ceb23..1cb6015 100644
--- a/graphics/OWNERS
+++ b/graphics/OWNERS
@@ -6,4 +6,5 @@
 chrisforbes@google.com
 jreck@google.com
 lpy@google.com
+scroggo@google.com
 sumir@google.com
\ No newline at end of file
diff --git a/graphics/allocator/2.0/default/OWNERS b/graphics/allocator/2.0/default/OWNERS
deleted file mode 100644
index c9f24d0..0000000
--- a/graphics/allocator/2.0/default/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Graphics team
-chrisforbes@google.com
-jreck@google.com
-lpy@google.com
diff --git a/graphics/allocator/2.0/utils/OWNERS b/graphics/allocator/2.0/utils/OWNERS
deleted file mode 100644
index c9f24d0..0000000
--- a/graphics/allocator/2.0/utils/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Graphics team
-chrisforbes@google.com
-jreck@google.com
-lpy@google.com
diff --git a/graphics/allocator/aidl/Android.bp b/graphics/allocator/aidl/Android.bp
index 272ab48..67c7fb5 100644
--- a/graphics/allocator/aidl/Android.bp
+++ b/graphics/allocator/aidl/Android.bp
@@ -14,9 +14,11 @@
         enabled: true,
         support_system_process: true,
     },
+    vndk_use_version: "2",
     srcs: ["android/hardware/graphics/allocator/*.aidl"],
     imports: [
         "android.hardware.common-V2",
+        "android.hardware.graphics.common-V4",
     ],
     stability: "vintf",
     backend: {
@@ -37,6 +39,7 @@
             min_sdk_version: "29",
         },
     },
+    frozen: false,
     versions_with_info: [
         {
             version: "1",
diff --git a/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl b/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl
new file mode 100644
index 0000000..980e246
--- /dev/null
+++ b/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl
@@ -0,0 +1,44 @@
+/*
+ * 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.graphics.allocator;
+@VintfStability
+parcelable BufferDescriptorInfo {
+  byte[128] name;
+  int width;
+  int height;
+  int layerCount;
+  android.hardware.graphics.common.PixelFormat format = android.hardware.graphics.common.PixelFormat.UNSPECIFIED;
+  android.hardware.graphics.common.BufferUsage usage = android.hardware.graphics.common.BufferUsage.CPU_READ_NEVER;
+  long reservedSize;
+}
diff --git a/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/IAllocator.aidl b/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/IAllocator.aidl
index fe0b0a2..48bef16 100644
--- a/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/IAllocator.aidl
+++ b/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/IAllocator.aidl
@@ -34,5 +34,11 @@
 package android.hardware.graphics.allocator;
 @VintfStability
 interface IAllocator {
+  /**
+   * @deprecated As of android.hardware.graphics.allocator-V2, this is deprecated & replaced with allocate2
+   */
   android.hardware.graphics.allocator.AllocationResult allocate(in byte[] descriptor, in int count);
+  android.hardware.graphics.allocator.AllocationResult allocate2(in android.hardware.graphics.allocator.BufferDescriptorInfo descriptor, in int count);
+  boolean isSupported(in android.hardware.graphics.allocator.BufferDescriptorInfo descriptor);
+  String getIMapperLibrarySuffix();
 }
diff --git a/graphics/allocator/aidl/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl b/graphics/allocator/aidl/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl
new file mode 100644
index 0000000..ffc50b8
--- /dev/null
+++ b/graphics/allocator/aidl/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl
@@ -0,0 +1,65 @@
+/*
+ * 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.graphics.allocator;
+
+import android.hardware.graphics.common.BufferUsage;
+import android.hardware.graphics.common.PixelFormat;
+
+@VintfStability
+parcelable BufferDescriptorInfo {
+    /**
+     * The name of the buffer in ASCII. Useful for debugging/tracing.
+     */
+    byte[128] name;
+
+    /**
+     * The width specifies how many columns of pixels must be in the
+     * allocated buffer, but does not necessarily represent the offset in
+     * columns between the same column in adjacent rows. The rows may be
+     * padded.
+     */
+    int width;
+
+    /**
+     * The height specifies how many rows of pixels must be in the
+     * allocated buffer.
+     */
+    int height;
+
+    /**
+     * The number of image layers that must be in the allocated buffer.
+     */
+    int layerCount;
+
+    /**
+     * Buffer pixel format. See PixelFormat.aidl in graphics/common for
+     * valid values
+     */
+    PixelFormat format = PixelFormat.UNSPECIFIED;
+
+    /**
+     * Buffer usage mask; valid flags can be found in the definition of
+     * BufferUsage.aidl in graphics/common
+     */
+    BufferUsage usage = BufferUsage.CPU_READ_NEVER;
+
+    /**
+     * The size in bytes of the reserved region associated with the buffer.
+     * See getReservedRegion for more information.
+     */
+    long reservedSize;
+}
diff --git a/graphics/allocator/aidl/android/hardware/graphics/allocator/IAllocator.aidl b/graphics/allocator/aidl/android/hardware/graphics/allocator/IAllocator.aidl
index 92dfd4f..71cebd6 100644
--- a/graphics/allocator/aidl/android/hardware/graphics/allocator/IAllocator.aidl
+++ b/graphics/allocator/aidl/android/hardware/graphics/allocator/IAllocator.aidl
@@ -17,6 +17,7 @@
 package android.hardware.graphics.allocator;
 
 import android.hardware.graphics.allocator.AllocationResult;
+import android.hardware.graphics.allocator.BufferDescriptorInfo;
 
 @VintfStability
 interface IAllocator {
@@ -31,6 +32,43 @@
      * @param count The number of buffers to allocate.
      * @return An AllocationResult containing the result of the allocation
      * @throws AllocationError on failure
+     * @deprecated As of android.hardware.graphics.allocator-V2, this is deprecated & replaced with
+     *         allocate2
      */
     AllocationResult allocate(in byte[] descriptor, in int count);
+
+    /**
+     * Allocates buffers with the properties specified by the descriptor.
+     *
+     * Allocations should be optimized for usage bits provided in the
+     * descriptor.
+     *
+     * @param descriptor Properties of the buffers to allocate. This must be
+     *     obtained from IMapper::createDescriptor().
+     * @param count The number of buffers to allocate.
+     * @return An AllocationResult containing the result of the allocation
+     * @throws AllocationError on failure
+     */
+    AllocationResult allocate2(in BufferDescriptorInfo descriptor, in int count);
+
+    /**
+     * Test whether the given BufferDescriptorInfo is allocatable.
+     *
+     * If this function returns true, it means that a buffer with the given
+     * description can be allocated on this implementation, unless resource
+     * exhaustion occurs. If this function returns false, it means that the
+     * allocation of the given description will never succeed.
+     *
+     * @param description the description of the buffer
+     * @return supported whether the description is supported
+     */
+    boolean isSupported(in BufferDescriptorInfo descriptor);
+
+    /**
+     * Retrieve the library suffix to load for the IMapper SP-HAL. This library must implement the
+     * IMapper stable-C interface (android/hardware/graphics/mapper/IMapper.h).
+     *
+     * The library that will attempt to be loaded is "/vendor/lib[64]/hw/mapper.<imapper_suffix>.so"
+     */
+    String getIMapperLibrarySuffix();
 }
diff --git a/graphics/allocator/aidl/vts/Android.bp b/graphics/allocator/aidl/vts/Android.bp
index a38af14..630ab2a 100644
--- a/graphics/allocator/aidl/vts/Android.bp
+++ b/graphics/allocator/aidl/vts/Android.bp
@@ -55,6 +55,7 @@
     ],
     header_libs: [
         "libhwui_internal_headers",
+        "libimapper_stablec",
     ],
     cflags: [
         "-Wall",
diff --git a/graphics/allocator/aidl/vts/VtsHalGraphicsAllocatorAidl_TargetTest.cpp b/graphics/allocator/aidl/vts/VtsHalGraphicsAllocatorAidl_TargetTest.cpp
index 59af5cf..09f1c15 100644
--- a/graphics/allocator/aidl/vts/VtsHalGraphicsAllocatorAidl_TargetTest.cpp
+++ b/graphics/allocator/aidl/vts/VtsHalGraphicsAllocatorAidl_TargetTest.cpp
@@ -25,7 +25,10 @@
 #include <aidl/android/hardware/graphics/common/PixelFormat.h>
 #include <aidlcommonsupport/NativeHandle.h>
 #include <android/binder_manager.h>
+#include <android/dlext.h>
 #include <android/hardware/graphics/mapper/4.0/IMapper.h>
+#include <android/hardware/graphics/mapper/IMapper.h>
+#include <dlfcn.h>
 #include <gtest/gtest.h>
 #include <hidl/GtestPrinter.h>
 #include <hidl/ServiceManagement.h>
@@ -33,6 +36,7 @@
 #include <renderthread/EglManager.h>
 #include <utils/GLUtils.h>
 #include <vndk/hardware_buffer.h>
+#include <vndksupport/linker.h>
 #include <initializer_list>
 #include <optional>
 #include <string>
@@ -42,60 +46,70 @@
 using namespace aidl::android::hardware::graphics::common;
 using namespace android;
 using namespace android::hardware;
-using namespace android::hardware::graphics::mapper::V4_0;
+using IMapper4 = android::hardware::graphics::mapper::V4_0::IMapper;
+using Error = android::hardware::graphics::mapper::V4_0::Error;
+using android::hardware::graphics::mapper::V4_0::BufferDescriptor;
 using android::uirenderer::AutoEglImage;
 using android::uirenderer::AutoGLFramebuffer;
 using android::uirenderer::AutoSkiaGlTexture;
 using android::uirenderer::renderthread::EglManager;
 
-static constexpr uint64_t pack(const std::initializer_list<BufferUsage>& usages) {
-    uint64_t ret = 0;
-    for (const auto u : usages) {
-        ret |= static_cast<uint64_t>(u);
-    }
-    return ret;
+typedef AIMapper_Error (*AIMapper_loadIMapperFn)(AIMapper* _Nullable* _Nonnull outImplementation);
+
+inline BufferUsage operator|(BufferUsage lhs, BufferUsage rhs) {
+    using T = std::underlying_type_t<BufferUsage>;
+    return static_cast<BufferUsage>(static_cast<T>(lhs) | static_cast<T>(rhs));
 }
 
-static constexpr hardware::graphics::common::V1_2::PixelFormat cast(PixelFormat format) {
-    return static_cast<hardware::graphics::common::V1_2::PixelFormat>(format);
+inline BufferUsage& operator|=(BufferUsage& lhs, BufferUsage rhs) {
+    lhs = lhs | rhs;
+    return lhs;
 }
 
+static IMapper4::BufferDescriptorInfo convert(const BufferDescriptorInfo& info) {
+    return IMapper4::BufferDescriptorInfo{
+            .name{reinterpret_cast<const char*>(info.name.data())},
+            .width = static_cast<uint32_t>(info.width),
+            .height = static_cast<uint32_t>(info.height),
+            .layerCount = static_cast<uint32_t>(info.layerCount),
+            .format = static_cast<hardware::graphics::common::V1_2::PixelFormat>(info.format),
+            .usage = static_cast<uint64_t>(info.usage),
+            .reservedSize = 0,
+    };
+}
+
+class GraphicsTestsBase;
+
 class BufferHandle {
-    sp<IMapper> mMapper;
+    GraphicsTestsBase& mTestBase;
     native_handle_t* mRawHandle;
     bool mImported = false;
     uint32_t mStride;
-    const IMapper::BufferDescriptorInfo mInfo;
+    const BufferDescriptorInfo mInfo;
 
     BufferHandle(const BufferHandle&) = delete;
     void operator=(const BufferHandle&) = delete;
 
   public:
-    BufferHandle(const sp<IMapper> mapper, native_handle_t* handle, bool imported, uint32_t stride,
-                 const IMapper::BufferDescriptorInfo& info)
-        : mMapper(mapper), mRawHandle(handle), mImported(imported), mStride(stride), mInfo(info) {}
+    BufferHandle(GraphicsTestsBase& testBase, native_handle_t* handle, bool imported,
+                 uint32_t stride, const BufferDescriptorInfo& info)
+        : mTestBase(testBase),
+          mRawHandle(handle),
+          mImported(imported),
+          mStride(stride),
+          mInfo(info) {}
 
-    ~BufferHandle() {
-        if (mRawHandle == nullptr) return;
-
-        if (mImported) {
-            Error error = mMapper->freeBuffer(mRawHandle);
-            EXPECT_EQ(Error::NONE, error) << "failed to free buffer " << mRawHandle;
-        } else {
-            native_handle_close(mRawHandle);
-            native_handle_delete(mRawHandle);
-        }
-    }
+    ~BufferHandle();
 
     uint32_t stride() const { return mStride; }
 
     AHardwareBuffer_Desc describe() const {
         return {
-                .width = mInfo.width,
-                .height = mInfo.height,
-                .layers = mInfo.layerCount,
+                .width = static_cast<uint32_t>(mInfo.width),
+                .height = static_cast<uint32_t>(mInfo.height),
+                .layers = static_cast<uint32_t>(mInfo.layerCount),
                 .format = static_cast<uint32_t>(mInfo.format),
-                .usage = mInfo.usage,
+                .usage = static_cast<uint64_t>(mInfo.usage),
                 .stride = stride(),
                 .rfu0 = 0,
                 .rfu1 = 0,
@@ -114,25 +128,43 @@
 
 class GraphicsTestsBase {
   private:
+    friend class BufferHandle;
+    int32_t mIAllocatorVersion = 1;
     std::shared_ptr<IAllocator> mAllocator;
-    sp<IMapper> mMapper;
+    sp<IMapper4> mMapper4;
+    AIMapper* mAIMapper = nullptr;
 
   protected:
-    void Initialize(std::string allocatorService, std::string mapperService) {
+    void Initialize(std::string allocatorService) {
         mAllocator = IAllocator::fromBinder(
                 ndk::SpAIBinder(AServiceManager_checkService(allocatorService.c_str())));
-        mMapper = IMapper::getService(mapperService);
+        ASSERT_TRUE(mAllocator->getInterfaceVersion(&mIAllocatorVersion).isOk());
+        if (mIAllocatorVersion >= 2) {
+            std::string mapperSuffix;
+            auto status = mAllocator->getIMapperLibrarySuffix(&mapperSuffix);
+            ASSERT_TRUE(status.isOk());
+            std::string lib_name = "mapper." + mapperSuffix + ".so";
+            void* so = android_load_sphal_library(lib_name.c_str(), RTLD_LOCAL | RTLD_NOW);
+            ASSERT_NE(nullptr, so) << "Failed to load " << lib_name;
+            auto loadIMapper = (AIMapper_loadIMapperFn)dlsym(so, "AIMapper_loadIMapper");
+            ASSERT_NE(nullptr, loadIMapper) << "AIMapper_locaIMapper missing from " << lib_name;
+            ASSERT_EQ(AIMAPPER_ERROR_NONE, loadIMapper(&mAIMapper));
+            ASSERT_NE(mAIMapper, nullptr);
+        } else {
+            // Don't have IMapper 5, fall back to IMapper 4
+            mMapper4 = IMapper4::getService();
+            ASSERT_NE(nullptr, mMapper4.get()) << "failed to get mapper service";
+            ASSERT_FALSE(mMapper4->isRemote()) << "mapper is not in passthrough mode";
+        }
 
         ASSERT_NE(nullptr, mAllocator.get()) << "failed to get allocator service";
-        ASSERT_NE(nullptr, mMapper.get()) << "failed to get mapper service";
-        ASSERT_FALSE(mMapper->isRemote()) << "mapper is not in passthrough mode";
     }
 
-  public:
-    BufferDescriptor createDescriptor(const IMapper::BufferDescriptorInfo& descriptorInfo) {
+  private:
+    BufferDescriptor createDescriptor(const BufferDescriptorInfo& descriptorInfo) {
         BufferDescriptor descriptor;
-        mMapper->createDescriptor(
-                descriptorInfo, [&](const auto& tmpError, const auto& tmpDescriptor) {
+        mMapper4->createDescriptor(
+                convert(descriptorInfo), [&](const auto& tmpError, const auto& tmpDescriptor) {
                     ASSERT_EQ(Error::NONE, tmpError) << "failed to create descriptor";
                     descriptor = tmpDescriptor;
                 });
@@ -140,14 +172,22 @@
         return descriptor;
     }
 
-    std::unique_ptr<BufferHandle> allocate(const IMapper::BufferDescriptorInfo& descriptorInfo) {
-        auto descriptor = createDescriptor(descriptorInfo);
-        if (::testing::Test::HasFatalFailure()) {
-            return nullptr;
-        }
-
+  public:
+    std::unique_ptr<BufferHandle> allocate(const BufferDescriptorInfo& descriptorInfo) {
         AllocationResult result;
-        auto status = mAllocator->allocate(descriptor, 1, &result);
+        ::ndk::ScopedAStatus status;
+        if (mIAllocatorVersion >= 2) {
+            status = mAllocator->allocate2(descriptorInfo, 1, &result);
+        } else {
+            auto descriptor = createDescriptor(descriptorInfo);
+            if (::testing::Test::HasFatalFailure()) {
+                return nullptr;
+            }
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+            status = mAllocator->allocate(descriptor, 1, &result);
+#pragma clang diagnostic pop  // deprecation
+        }
         if (!status.isOk()) {
             status_t error = status.getExceptionCode();
             if (error == EX_SERVICE_SPECIFIC) {
@@ -158,28 +198,48 @@
             }
             return nullptr;
         } else {
-            return std::make_unique<BufferHandle>(mMapper, dupFromAidl(result.buffers[0]), false,
+            return std::make_unique<BufferHandle>(*this, dupFromAidl(result.buffers[0]), false,
                                                   result.stride, descriptorInfo);
         }
     }
 
-    bool isSupported(const IMapper::BufferDescriptorInfo& descriptorInfo) {
+    bool isSupported(const BufferDescriptorInfo& descriptorInfo) {
         bool ret = false;
-        EXPECT_TRUE(mMapper->isSupported(descriptorInfo,
-                                         [&](auto error, bool supported) {
-                                             ASSERT_EQ(Error::NONE, error);
-                                             ret = supported;
-                                         })
-                            .isOk());
+        if (mIAllocatorVersion >= 2) {
+            EXPECT_TRUE(mAllocator->isSupported(descriptorInfo, &ret).isOk());
+        } else {
+            EXPECT_TRUE(mMapper4->isSupported(convert(descriptorInfo),
+                                              [&](auto error, bool supported) {
+                                                  ASSERT_EQ(Error::NONE, error);
+                                                  ret = supported;
+                                              })
+                                .isOk());
+        }
         return ret;
     }
 };
 
-class GraphicsAllocatorAidlTests
-    : public GraphicsTestsBase,
-      public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
+BufferHandle::~BufferHandle() {
+    if (mRawHandle == nullptr) return;
+
+    if (mImported) {
+        if (mTestBase.mAIMapper) {
+            AIMapper_Error error = mTestBase.mAIMapper->v5.freeBuffer(mRawHandle);
+            EXPECT_EQ(AIMAPPER_ERROR_NONE, error);
+        } else {
+            Error error = mTestBase.mMapper4->freeBuffer(mRawHandle);
+            EXPECT_EQ(Error::NONE, error) << "failed to free buffer " << mRawHandle;
+        }
+    } else {
+        native_handle_close(mRawHandle);
+        native_handle_delete(mRawHandle);
+    }
+}
+
+class GraphicsAllocatorAidlTests : public GraphicsTestsBase,
+                                   public ::testing::TestWithParam<std::string> {
   public:
-    void SetUp() override { Initialize(std::get<0>(GetParam()), std::get<1>(GetParam())); }
+    void SetUp() override { Initialize(GetParam()); }
 
     void TearDown() override {}
 };
@@ -191,22 +251,22 @@
 
 class GraphicsFrontBufferTests
     : public GraphicsTestsBase,
-      public ::testing::TestWithParam<std::tuple<std::string, std::string, FlushMethod>> {
+      public ::testing::TestWithParam<std::tuple<std::string, FlushMethod>> {
   private:
     EglManager eglManager;
     std::function<void(EglManager&)> flush;
 
   public:
     void SetUp() override {
-        Initialize(std::get<0>(GetParam()), std::get<1>(GetParam()));
-        flush = std::get<2>(GetParam()).func;
+        Initialize(std::get<0>(GetParam()));
+        flush = std::get<1>(GetParam()).func;
         eglManager.initialize();
     }
 
     void TearDown() override { eglManager.destroy(); }
 
     void fillWithGpu(AHardwareBuffer* buffer, float red, float green, float blue, float alpha) {
-        const EGLClientBuffer clientBuffer = eglGetNativeClientBufferANDROID(buffer);
+        EGLClientBuffer clientBuffer = eglGetNativeClientBufferANDROID(buffer);
         AutoEglImage eglImage(eglManager.eglDisplay(), clientBuffer);
         AutoSkiaGlTexture glTexture;
         AutoGLFramebuffer glFbo;
@@ -235,26 +295,14 @@
     }
 };
 
-TEST_P(GraphicsAllocatorAidlTests, CreateDescriptorBasic) {
-    ASSERT_NO_FATAL_FAILURE(createDescriptor({
-            .name = "CPU_8888",
-            .width = 64,
-            .height = 64,
-            .layerCount = 1,
-            .format = cast(PixelFormat::RGBA_8888),
-            .usage = pack({BufferUsage::CPU_WRITE_OFTEN, BufferUsage::CPU_READ_OFTEN}),
-            .reservedSize = 0,
-    }));
-}
-
 TEST_P(GraphicsAllocatorAidlTests, CanAllocate) {
     auto buffer = allocate({
-            .name = "CPU_8888",
+            .name = {"CPU_8888"},
             .width = 64,
             .height = 64,
             .layerCount = 1,
-            .format = cast(PixelFormat::RGBA_8888),
-            .usage = pack({BufferUsage::CPU_WRITE_OFTEN, BufferUsage::CPU_READ_OFTEN}),
+            .format = PixelFormat::RGBA_8888,
+            .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
             .reservedSize = 0,
     });
     ASSERT_NE(nullptr, buffer.get());
@@ -262,14 +310,14 @@
 }
 
 TEST_P(GraphicsFrontBufferTests, FrontBufferGpuToCpu) {
-    IMapper::BufferDescriptorInfo info{
-            .name = "CPU_8888",
+    BufferDescriptorInfo info{
+            .name = {"CPU_8888"},
             .width = 64,
             .height = 64,
             .layerCount = 1,
-            .format = cast(PixelFormat::RGBA_8888),
-            .usage = pack({BufferUsage::GPU_RENDER_TARGET, BufferUsage::CPU_READ_OFTEN,
-                           BufferUsage::FRONT_BUFFER}),
+            .format = PixelFormat::RGBA_8888,
+            .usage = BufferUsage::GPU_RENDER_TARGET | BufferUsage::CPU_READ_OFTEN |
+                     BufferUsage::FRONT_BUFFER,
             .reservedSize = 0,
     };
     const bool supported = isSupported(info);
@@ -304,14 +352,14 @@
 }
 
 TEST_P(GraphicsFrontBufferTests, FrontBufferGpuToGpu) {
-    IMapper::BufferDescriptorInfo info{
-            .name = "CPU_8888",
+    BufferDescriptorInfo info{
+            .name = {"CPU_8888"},
             .width = 64,
             .height = 64,
             .layerCount = 1,
-            .format = cast(PixelFormat::RGBA_8888),
-            .usage = pack({BufferUsage::GPU_RENDER_TARGET, BufferUsage::GPU_TEXTURE,
-                           BufferUsage::FRONT_BUFFER}),
+            .format = PixelFormat::RGBA_8888,
+            .usage = BufferUsage::GPU_RENDER_TARGET | BufferUsage::GPU_TEXTURE |
+                     BufferUsage::FRONT_BUFFER,
             .reservedSize = 0,
     };
     const bool supported = isSupported(info);
@@ -344,11 +392,9 @@
 }
 
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsAllocatorAidlTests);
-INSTANTIATE_TEST_CASE_P(
-        PerInstance, GraphicsAllocatorAidlTests,
-        testing::Combine(testing::ValuesIn(getAidlHalInstanceNames(IAllocator::descriptor)),
-                         testing::ValuesIn(getAllHalInstanceNames(IMapper::descriptor))),
-        PrintInstanceTupleNameToString<>);
+INSTANTIATE_TEST_CASE_P(PerInstance, GraphicsAllocatorAidlTests,
+                        testing::ValuesIn(getAidlHalInstanceNames(IAllocator::descriptor)),
+                        PrintInstanceNameToString);
 
 const auto FlushMethodsValues = testing::Values(
         FlushMethod{"glFinish", [](EglManager&) { glFinish(); }},
@@ -362,7 +408,7 @@
                     }},
         FlushMethod{"eglClientWaitSync", [](EglManager& eglManager) {
                         EGLDisplay display = eglManager.eglDisplay();
-                        EGLSyncKHR fence = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, NULL);
+                        EGLSyncKHR fence = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr);
                         eglClientWaitSyncKHR(display, fence, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
                                              EGL_FOREVER_KHR);
                         eglDestroySyncKHR(display, fence);
@@ -371,9 +417,8 @@
 INSTANTIATE_TEST_CASE_P(
         PerInstance, GraphicsFrontBufferTests,
         testing::Combine(testing::ValuesIn(getAidlHalInstanceNames(IAllocator::descriptor)),
-                         testing::ValuesIn(getAllHalInstanceNames(IMapper::descriptor)),
                          FlushMethodsValues),
         [](auto info) -> std::string {
-            std::string name = std::to_string(info.index) + "/" + std::get<2>(info.param).name;
+            std::string name = std::to_string(info.index) + "/" + std::get<1>(info.param).name;
             return Sanitize(name);
-        });
+        });
\ No newline at end of file
diff --git a/graphics/common/OWNERS b/graphics/common/OWNERS
deleted file mode 100644
index 94999ea..0000000
--- a/graphics/common/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-# Bug component: 1075130
-adyabr@google.com
-alecmouri@google.com
-jreck@google.com
-scroggo@google.com
diff --git a/graphics/common/aidl/Android.bp b/graphics/common/aidl/Android.bp
index 40a575d..84bc1af 100644
--- a/graphics/common/aidl/Android.bp
+++ b/graphics/common/aidl/Android.bp
@@ -15,7 +15,7 @@
         enabled: true,
         support_system_process: true,
     },
-    vndk_use_version: "3",
+    vndk_use_version: "4",
     srcs: [
         "android/hardware/graphics/common/*.aidl",
     ],
@@ -40,6 +40,7 @@
             min_sdk_version: "29",
         },
     },
+    frozen: false,
     versions_with_info: [
         {
             version: "1",
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Hdr.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Hdr.aidl
index 7bae45e..128ef49 100644
--- a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Hdr.aidl
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Hdr.aidl
@@ -39,4 +39,5 @@
   HDR10 = 2,
   HLG = 3,
   HDR10_PLUS = 4,
+  DOLBY_VISION_4K30 = 5,
 }
diff --git a/graphics/common/aidl/android/hardware/graphics/common/Hdr.aidl b/graphics/common/aidl/android/hardware/graphics/common/Hdr.aidl
index f543780..407b54f 100644
--- a/graphics/common/aidl/android/hardware/graphics/common/Hdr.aidl
+++ b/graphics/common/aidl/android/hardware/graphics/common/Hdr.aidl
@@ -39,4 +39,8 @@
      * Device supports HDR10+
      */
     HDR10_PLUS = 4,
+    /**
+     * If present, indicates that device supports Dolby Vision only up to 4k30hz graphics mode
+     */
+    DOLBY_VISION_4K30 = 5,
 }
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/default/OWNERS b/graphics/composer/2.1/default/OWNERS
deleted file mode 100644
index 331c80d..0000000
--- a/graphics/composer/2.1/default/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Graphics team
-adyabr@google.com
-alecmouri@google.com
-lpy@google.com
diff --git a/graphics/composer/2.1/utils/OWNERS b/graphics/composer/2.1/utils/OWNERS
deleted file mode 100644
index 83c4f5f..0000000
--- a/graphics/composer/2.1/utils/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-adyabr@google.com
-alecmouri@google.com
-lpy@google.com
diff --git a/graphics/composer/2.1/vts/OWNERS b/graphics/composer/2.1/vts/OWNERS
deleted file mode 100644
index a643bbd..0000000
--- a/graphics/composer/2.1/vts/OWNERS
+++ /dev/null
@@ -1,8 +0,0 @@
-# Graphics team
-adyabr@google.com
-alecmouri@google.com
-lpy@google.com
-
-# VTS team
-yim@google.com
-zhuoyao@google.com
diff --git a/graphics/composer/2.1/vts/functional/OWNERS b/graphics/composer/2.1/vts/functional/OWNERS
deleted file mode 100644
index 3d970d1..0000000
--- a/graphics/composer/2.1/vts/functional/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Bug component: 25423
-adyabr@google.com
-alecmouri@google.com
-sumir@google.com
diff --git a/graphics/composer/2.2/default/OWNERS b/graphics/composer/2.2/default/OWNERS
deleted file mode 100644
index e8f584d..0000000
--- a/graphics/composer/2.2/default/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-# Graphics team
-adyabr@google.com
-alecmouri@google.com
-lpy@google.com
-
diff --git a/graphics/composer/2.2/utils/OWNERS b/graphics/composer/2.2/utils/OWNERS
deleted file mode 100644
index 331c80d..0000000
--- a/graphics/composer/2.2/utils/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Graphics team
-adyabr@google.com
-alecmouri@google.com
-lpy@google.com
diff --git a/graphics/composer/2.2/vts/functional/OWNERS b/graphics/composer/2.2/vts/functional/OWNERS
deleted file mode 100644
index a4eb0ca..0000000
--- a/graphics/composer/2.2/vts/functional/OWNERS
+++ /dev/null
@@ -1,6 +0,0 @@
-# Bug component: 25423
-# Graphics team
-adyabr@google.com
-alecmouri@google.com
-lpy@google.com
-sumir@google.com
diff --git a/graphics/composer/2.3/default/OWNERS b/graphics/composer/2.3/default/OWNERS
deleted file mode 100644
index 331c80d..0000000
--- a/graphics/composer/2.3/default/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Graphics team
-adyabr@google.com
-alecmouri@google.com
-lpy@google.com
diff --git a/graphics/composer/2.3/utils/OWNERS b/graphics/composer/2.3/utils/OWNERS
deleted file mode 100644
index 331c80d..0000000
--- a/graphics/composer/2.3/utils/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Graphics team
-adyabr@google.com
-alecmouri@google.com
-lpy@google.com
diff --git a/graphics/composer/2.3/vts/functional/OWNERS b/graphics/composer/2.3/vts/functional/OWNERS
deleted file mode 100644
index a4eb0ca..0000000
--- a/graphics/composer/2.3/vts/functional/OWNERS
+++ /dev/null
@@ -1,6 +0,0 @@
-# Bug component: 25423
-# Graphics team
-adyabr@google.com
-alecmouri@google.com
-lpy@google.com
-sumir@google.com
diff --git a/graphics/composer/2.4/default/OWNERS b/graphics/composer/2.4/default/OWNERS
deleted file mode 100644
index 331c80d..0000000
--- a/graphics/composer/2.4/default/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Graphics team
-adyabr@google.com
-alecmouri@google.com
-lpy@google.com
diff --git a/graphics/composer/2.4/utils/OWNERS b/graphics/composer/2.4/utils/OWNERS
deleted file mode 100644
index 331c80d..0000000
--- a/graphics/composer/2.4/utils/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Graphics team
-adyabr@google.com
-alecmouri@google.com
-lpy@google.com
diff --git a/graphics/composer/2.4/vts/functional/OWNERS b/graphics/composer/2.4/vts/functional/OWNERS
deleted file mode 100644
index a4eb0ca..0000000
--- a/graphics/composer/2.4/vts/functional/OWNERS
+++ /dev/null
@@ -1,6 +0,0 @@
-# Bug component: 25423
-# Graphics team
-adyabr@google.com
-alecmouri@google.com
-lpy@google.com
-sumir@google.com
diff --git a/graphics/composer/aidl/Android.bp b/graphics/composer/aidl/Android.bp
index a5ca0a0..1e08221 100644
--- a/graphics/composer/aidl/Android.bp
+++ b/graphics/composer/aidl/Android.bp
@@ -31,12 +31,14 @@
         enabled: true,
         support_system_process: true,
     },
+    frozen: false,
+    vndk_use_version: "1",
     srcs: [
         "android/hardware/graphics/composer3/*.aidl",
     ],
     stability: "vintf",
     imports: [
-        "android.hardware.graphics.common-V3",
+        "android.hardware.graphics.common-V4",
         "android.hardware.common-V2",
     ],
     backend: {
@@ -57,7 +59,7 @@
         {
             version: "1",
             imports: [
-                "android.hardware.graphics.common-V3",
+                "android.hardware.graphics.common-V4",
                 "android.hardware.common-V2",
             ],
         },
diff --git a/graphics/composer/aidl/OWNERS b/graphics/composer/aidl/OWNERS
deleted file mode 100644
index 9028d9d..0000000
--- a/graphics/composer/aidl/OWNERS
+++ /dev/null
@@ -1,6 +0,0 @@
-# Bug component: 1075131
-
-# Graphics team
-adyabr@google.com
-alecmouri@google.com
-sumir@google.com
\ No newline at end of file
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayCapability.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayCapability.aidl
index 6eba887..0e2d72b 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayCapability.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayCapability.aidl
@@ -42,4 +42,5 @@
   AUTO_LOW_LATENCY_MODE = 5,
   SUSPEND = 6,
   DISPLAY_IDLE_TIMER = 7,
+  MULTI_THREADED_PRESENT = 8,
 }
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerClient.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerClient.aidl
index b49f239..a7e6535 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerClient.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerClient.aidl
@@ -75,6 +75,7 @@
   void setReadbackBuffer(long display, in android.hardware.common.NativeHandle buffer, in @nullable ParcelFileDescriptor releaseFence);
   void setVsyncEnabled(long display, boolean enabled);
   void setIdleTimerEnabled(long display, int timeoutMs);
+  android.hardware.graphics.composer3.OverlayProperties getOverlaySupport();
   const int EX_BAD_CONFIG = 1;
   const int EX_BAD_DISPLAY = 2;
   const int EX_BAD_LAYER = 3;
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/OverlayProperties.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/OverlayProperties.aidl
new file mode 100644
index 0000000..4d8fcac
--- /dev/null
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/OverlayProperties.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.graphics.composer3;
+@VintfStability
+parcelable OverlayProperties {
+  android.hardware.graphics.composer3.SupportedBufferCombinations[] combinations;
+}
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/SupportedBufferCombinations.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/SupportedBufferCombinations.aidl
new file mode 100644
index 0000000..1828be1
--- /dev/null
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/SupportedBufferCombinations.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.graphics.composer3;
+@VintfStability
+parcelable SupportedBufferCombinations {
+  android.hardware.graphics.common.PixelFormat[] pixelFormats;
+  android.hardware.graphics.common.Dataspace[] dataspaces;
+}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayCapability.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayCapability.aidl
index f4b2984..7154d74 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayCapability.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayCapability.aidl
@@ -80,4 +80,20 @@
      * IComposerCallback.onVsyncIdle.
      */
     DISPLAY_IDLE_TIMER = 7,
+    /**
+     * Indicates that both the composer HAL implementation and the given display
+     * support calling executeCommands concurrently from separate threads.
+     * executeCommands for a particular display will never run concurrently to
+     * any other executeCommands for the same display. In addition, the
+     * CommandResultPayload must only reference displays included in the
+     * DisplayCommands passed to executeCommands. Displays referenced from
+     * separate threads must have minimal interference with one another. If a
+     * HWC-managed display has this capability, SurfaceFlinger can run
+     * executeCommands for this display concurrently with other displays with the
+     * same capability.
+     * @see IComposerClient.executeCommands
+     * @see DisplayCommand.presentDisplay
+     * @see DisplayCommand.validateDisplay
+     */
+    MULTI_THREADED_PRESENT = 8,
 }
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerClient.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerClient.aidl
index a4ea64f..88bb3a4 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerClient.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerClient.aidl
@@ -32,6 +32,7 @@
 import android.hardware.graphics.composer3.FormatColorComponent;
 import android.hardware.graphics.composer3.HdrCapabilities;
 import android.hardware.graphics.composer3.IComposerCallback;
+import android.hardware.graphics.composer3.OverlayProperties;
 import android.hardware.graphics.composer3.PerFrameMetadataKey;
 import android.hardware.graphics.composer3.PowerMode;
 import android.hardware.graphics.composer3.ReadbackBufferAttributes;
@@ -814,4 +815,14 @@
      *
      */
     void setIdleTimerEnabled(long display, int timeoutMs);
+
+    /**
+     * Hardware overlays is a technique to composite different buffers directly to the screen
+     * while bypassing GPU composition.
+     *
+     * This function returns what the device's overlays support.
+     *
+     * @return the overlay properties of the device.
+     */
+    OverlayProperties getOverlaySupport();
 }
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/OverlayProperties.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/OverlayProperties.aidl
new file mode 100644
index 0000000..d3bd7d3
--- /dev/null
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/OverlayProperties.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.graphics.composer3;
+
+import android.hardware.graphics.composer3.SupportedBufferCombinations;
+
+@VintfStability
+parcelable OverlayProperties {
+    // Array of all valid pixelformat and dataspace combinations.
+    // If all supported formats work with all supported dataspaces,
+    // then this list may only have 1 entry.
+    // If some dataspaces, e.g. scRGB, only work with specific formats,
+    // then this list may contain more than 1 entry.
+    SupportedBufferCombinations[] combinations;
+}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/SupportedBufferCombinations.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/SupportedBufferCombinations.aidl
new file mode 100644
index 0000000..41f8817
--- /dev/null
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/SupportedBufferCombinations.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.graphics.composer3;
+
+@VintfStability
+parcelable SupportedBufferCombinations {
+    // List of pixelformats and dataspaces that can be used together.
+    // All pixelformats and dataspaces stored inside are valid combinations.
+    android.hardware.graphics.common.PixelFormat[] pixelFormats;
+    android.hardware.graphics.common.Dataspace[] dataspaces;
+}
diff --git a/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientReader.h b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientReader.h
index 27dce76..76ba24b 100644
--- a/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientReader.h
+++ b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientReader.h
@@ -19,8 +19,8 @@
 #include <algorithm>
 #include <limits>
 #include <memory>
+#include <optional>
 #include <unordered_map>
-#include <unordered_set>
 #include <vector>
 
 #include <inttypes.h>
@@ -41,8 +41,15 @@
 
 class ComposerClientReader {
   public:
+    explicit ComposerClientReader(std::optional<int64_t> display = {}) : mDisplay(display) {}
+
     ~ComposerClientReader() { resetData(); }
 
+    ComposerClientReader(ComposerClientReader&&) = default;
+
+    ComposerClientReader(const ComposerClientReader&) = delete;
+    ComposerClientReader& operator=(const ComposerClientReader&) = delete;
+
     // Parse and execute commands from the command queue.  The commands are
     // actually return values from the server and will be saved in ReturnData.
     void parse(std::vector<CommandResultPayload>&& results) {
@@ -85,6 +92,7 @@
 
     void hasChanges(int64_t display, uint32_t* outNumChangedCompositionTypes,
                     uint32_t* outNumLayerRequestMasks) const {
+        LOG_ALWAYS_FATAL_IF(mDisplay && display != *mDisplay);
         auto found = mReturnData.find(display);
         if (found == mReturnData.end()) {
             *outNumChangedCompositionTypes = 0;
@@ -100,6 +108,7 @@
 
     // Get and clear saved changed composition types.
     std::vector<ChangedCompositionLayer> takeChangedCompositionTypes(int64_t display) {
+        LOG_ALWAYS_FATAL_IF(mDisplay && display != *mDisplay);
         auto found = mReturnData.find(display);
         if (found == mReturnData.end()) {
             return {};
@@ -111,6 +120,7 @@
 
     // Get and clear saved display requests.
     DisplayRequest takeDisplayRequests(int64_t display) {
+        LOG_ALWAYS_FATAL_IF(mDisplay && display != *mDisplay);
         auto found = mReturnData.find(display);
         if (found == mReturnData.end()) {
             return {};
@@ -122,6 +132,7 @@
 
     // Get and clear saved release fences.
     std::vector<ReleaseFences::Layer> takeReleaseFences(int64_t display) {
+        LOG_ALWAYS_FATAL_IF(mDisplay && display != *mDisplay);
         auto found = mReturnData.find(display);
         if (found == mReturnData.end()) {
             return {};
@@ -133,6 +144,7 @@
 
     // Get and clear saved present fence.
     ndk::ScopedFileDescriptor takePresentFence(int64_t display) {
+        LOG_ALWAYS_FATAL_IF(mDisplay && display != *mDisplay);
         auto found = mReturnData.find(display);
         if (found == mReturnData.end()) {
             return {};
@@ -144,6 +156,7 @@
 
     // Get what stage succeeded during PresentOrValidate: Present or Validate
     std::optional<PresentOrValidate::Result> takePresentOrValidateStage(int64_t display) {
+        LOG_ALWAYS_FATAL_IF(mDisplay && display != *mDisplay);
         auto found = mReturnData.find(display);
         if (found == mReturnData.end()) {
             return std::nullopt;
@@ -154,6 +167,7 @@
 
     // Get the client target properties requested by hardware composer.
     ClientTargetPropertyWithBrightness takeClientTargetProperty(int64_t display) {
+        LOG_ALWAYS_FATAL_IF(mDisplay && display != *mDisplay);
         auto found = mReturnData.find(display);
 
         // If not found, return the default values.
@@ -177,32 +191,38 @@
     void parseSetError(CommandError&& error) { mErrors.emplace_back(error); }
 
     void parseSetChangedCompositionTypes(ChangedCompositionTypes&& changedCompositionTypes) {
+        LOG_ALWAYS_FATAL_IF(mDisplay && changedCompositionTypes.display != *mDisplay);
         auto& data = mReturnData[changedCompositionTypes.display];
         data.changedLayers = std::move(changedCompositionTypes.layers);
     }
 
     void parseSetDisplayRequests(DisplayRequest&& displayRequest) {
+        LOG_ALWAYS_FATAL_IF(mDisplay && displayRequest.display != *mDisplay);
         auto& data = mReturnData[displayRequest.display];
         data.displayRequests = std::move(displayRequest);
     }
 
     void parseSetPresentFence(PresentFence&& presentFence) {
+        LOG_ALWAYS_FATAL_IF(mDisplay && presentFence.display != *mDisplay);
         auto& data = mReturnData[presentFence.display];
         data.presentFence = std::move(presentFence.fence);
     }
 
     void parseSetReleaseFences(ReleaseFences&& releaseFences) {
+        LOG_ALWAYS_FATAL_IF(mDisplay && releaseFences.display != *mDisplay);
         auto& data = mReturnData[releaseFences.display];
         data.releasedLayers = std::move(releaseFences.layers);
     }
 
     void parseSetPresentOrValidateDisplayResult(const PresentOrValidate&& presentOrValidate) {
+        LOG_ALWAYS_FATAL_IF(mDisplay && presentOrValidate.display != *mDisplay);
         auto& data = mReturnData[presentOrValidate.display];
         data.presentOrValidateState = std::move(presentOrValidate.result);
     }
 
     void parseSetClientTargetProperty(
             const ClientTargetPropertyWithBrightness&& clientTargetProperty) {
+        LOG_ALWAYS_FATAL_IF(mDisplay && clientTargetProperty.display != *mDisplay);
         auto& data = mReturnData[clientTargetProperty.display];
         data.clientTargetProperty = std::move(clientTargetProperty);
     }
@@ -222,6 +242,7 @@
 
     std::vector<CommandError> mErrors;
     std::unordered_map<int64_t, ReturnData> mReturnData;
+    const std::optional<int64_t> mDisplay;
 };
 
 }  // namespace aidl::android::hardware::graphics::composer3
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 775ae9f..0c8742f 100644
--- a/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h
+++ b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h
@@ -19,8 +19,6 @@
 #include <algorithm>
 #include <limits>
 #include <memory>
-#include <unordered_map>
-#include <unordered_set>
 #include <vector>
 
 #include <inttypes.h>
@@ -63,10 +61,15 @@
   public:
     static constexpr std::optional<ClockMonotonicTimestamp> kNoTimestamp = std::nullopt;
 
-    ComposerClientWriter() { reset(); }
+    explicit ComposerClientWriter(int64_t display) : mDisplay(display) { reset(); }
 
     ~ComposerClientWriter() { reset(); }
 
+    ComposerClientWriter(ComposerClientWriter&&) = default;
+
+    ComposerClientWriter(const ComposerClientWriter&) = delete;
+    ComposerClientWriter& operator=(const ComposerClientWriter&) = delete;
+
     void reset() {
         mDisplayCommand.reset();
         mLayerCommand.reset();
@@ -229,6 +232,7 @@
     std::optional<DisplayCommand> mDisplayCommand;
     std::optional<LayerCommand> mLayerCommand;
     std::vector<DisplayCommand> mCommands;
+    const int64_t mDisplay;
 
     Buffer getBuffer(uint32_t slot, const native_handle_t* bufferHandle, int fence) {
         Buffer bufferCommand;
@@ -254,6 +258,7 @@
 
     DisplayCommand& getDisplayCommand(int64_t display) {
         if (!mDisplayCommand.has_value() || mDisplayCommand->display != display) {
+            LOG_ALWAYS_FATAL_IF(display != mDisplay);
             flushLayerCommand();
             flushDisplayCommand();
             mDisplayCommand.emplace();
diff --git a/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerServiceWriter.h b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerServiceWriter.h
index 34cda6a..b50b84b 100644
--- a/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerServiceWriter.h
+++ b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerServiceWriter.h
@@ -18,6 +18,7 @@
 
 #include <aidl/android/hardware/graphics/composer3/CommandResultPayload.h>
 #include <aidl/android/hardware/graphics/composer3/IComposerClient.h>
+#include <android-base/logging.h>
 #include <inttypes.h>
 #include <string.h>
 
@@ -26,8 +27,6 @@
 #include <memory>
 #include <vector>
 
-#include "Util.h"
-
 namespace aidl::android::hardware::graphics::composer3::impl {
 
 class ComposerServiceWriter {
diff --git a/graphics/composer/aidl/vts/OWNERS b/graphics/composer/aidl/vts/OWNERS
deleted file mode 100644
index d95d98d..0000000
--- a/graphics/composer/aidl/vts/OWNERS
+++ /dev/null
@@ -1,6 +0,0 @@
-# Bug component: 199413815
-
-# Graphics team
-adyabr@google.com
-alecmouri@google.com
-ramindani@google.com
diff --git a/graphics/composer/aidl/vts/VtsComposerClient.cpp b/graphics/composer/aidl/vts/VtsComposerClient.cpp
index 5bc7296..34cc802 100644
--- a/graphics/composer/aidl/vts/VtsComposerClient.cpp
+++ b/graphics/composer/aidl/vts/VtsComposerClient.cpp
@@ -338,6 +338,11 @@
             outDisplayOrientation};
 }
 
+std::pair<ScopedAStatus, composer3::OverlayProperties> VtsComposerClient::getOverlaySupport() {
+    OverlayProperties properties;
+    return {mComposerClient->getOverlaySupport(&properties), properties};
+}
+
 ScopedAStatus VtsComposerClient::setIdleTimerEnabled(int64_t display, int32_t timeoutMs) {
     return mComposerClient->setIdleTimerEnabled(display, timeoutMs);
 }
diff --git a/graphics/composer/aidl/vts/VtsComposerClient.h b/graphics/composer/aidl/vts/VtsComposerClient.h
index 3625c8c..1883336 100644
--- a/graphics/composer/aidl/vts/VtsComposerClient.h
+++ b/graphics/composer/aidl/vts/VtsComposerClient.h
@@ -35,6 +35,7 @@
 #include <string>
 #include <thread>
 #include <unordered_map>
+#include <unordered_set>
 #include "GraphicsComposerCallback.h"
 
 using aidl::android::hardware::graphics::common::Dataspace;
@@ -172,6 +173,8 @@
 
     std::pair<ScopedAStatus, std::vector<VtsDisplay>> getDisplays();
 
+    std::pair<ScopedAStatus, OverlayProperties> getOverlaySupport();
+
   private:
     ScopedAStatus updateDisplayProperties(VtsDisplay* vtsDisplay, int32_t config);
 
diff --git a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
index 46dde09..6fa3392 100644
--- a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
+++ b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
@@ -53,6 +53,7 @@
         const auto& [status, displays] = mComposerClient->getDisplays();
         ASSERT_TRUE(status.isOk());
         mDisplays = displays;
+        mWriter.reset(new ComposerClientWriter(getPrimaryDisplayId()));
 
         setTestColorModes();
 
@@ -200,15 +201,15 @@
 
     void writeLayers(const std::vector<std::shared_ptr<TestLayer>>& layers) {
         for (const auto& layer : layers) {
-            layer->write(mWriter);
+            layer->write(*mWriter);
         }
         execute();
     }
 
     void execute() {
-        const auto& commands = mWriter.getPendingCommands();
+        const auto& commands = mWriter->getPendingCommands();
         if (commands.empty()) {
-            mWriter.reset();
+            mWriter->reset();
             return;
         }
 
@@ -216,7 +217,7 @@
         ASSERT_TRUE(status.isOk()) << "executeCommands failed " << status.getDescription();
 
         mReader.parse(std::move(results));
-        mWriter.reset();
+        mWriter->reset();
     }
 
     bool getHasReadbackBuffer() {
@@ -236,7 +237,7 @@
     std::vector<VtsDisplay> mDisplays;
     // use the slot count usually set by SF
     std::vector<ColorMode> mTestColorModes;
-    ComposerClientWriter mWriter;
+    std::unique_ptr<ComposerClientWriter> mWriter;
     ComposerClientReader mReader;
     std::unique_ptr<TestRenderEngine> mTestRenderEngine;
     common::PixelFormat mPixelFormat;
@@ -297,7 +298,7 @@
 
         writeLayers(layers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
         execute();
         // if hwc cannot handle and asks for composition change,
         // just succeed the test
@@ -306,7 +307,7 @@
             return;
         }
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter.presentDisplay(getPrimaryDisplayId());
+        mWriter->presentDisplay(getPrimaryDisplayId());
         execute();
         ASSERT_TRUE(mReader.takeErrors().empty());
 
@@ -349,14 +350,14 @@
                 getDisplayHeight(), common::PixelFormat::RGBA_8888);
         layer->setDisplayFrame({0, 0, getDisplayWidth(), getDisplayHeight()});
         layer->setZOrder(10);
-        layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+        layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), *mWriter);
         ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors));
 
         std::vector<std::shared_ptr<TestLayer>> layers = {layer};
 
         writeLayers(layers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
         execute();
 
         if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
@@ -365,7 +366,7 @@
         }
         ASSERT_TRUE(mReader.takeErrors().empty());
 
-        mWriter.presentDisplay(getPrimaryDisplayId());
+        mWriter->presentDisplay(getPrimaryDisplayId());
         execute();
 
         ASSERT_TRUE(mReader.takeErrors().empty());
@@ -395,7 +396,7 @@
         layer->setColor(BLUE);
         layer->setDisplayFrame(coloredSquare);
         layer->setZOrder(10);
-        layer->write(mWriter);
+        layer->write(*mWriter);
 
         // This following buffer call should have no effect
         const auto usage = static_cast<uint32_t>(common::BufferUsage::CPU_WRITE_OFTEN) |
@@ -403,8 +404,8 @@
         const auto& [graphicBufferStatus, graphicBuffer] = allocateBuffer(usage);
         ASSERT_TRUE(graphicBufferStatus);
         const auto& buffer = graphicBuffer->handle;
-        mWriter.setLayerBuffer(getPrimaryDisplayId(), layer->getLayer(), /*slot*/ 0, buffer,
-                               /*acquireFence*/ -1);
+        mWriter->setLayerBuffer(getPrimaryDisplayId(), layer->getLayer(), /*slot*/ 0, buffer,
+                                /*acquireFence*/ -1);
 
         // expected color for each pixel
         std::vector<Color> expectedColors(
@@ -415,7 +416,7 @@
                                       getDisplayHeight(), mPixelFormat, mDataspace);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
-        mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
         execute();
 
         if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
@@ -423,7 +424,7 @@
             return;
         }
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter.presentDisplay(getPrimaryDisplayId());
+        mWriter->presentDisplay(getPrimaryDisplayId());
         execute();
         ASSERT_TRUE(mReader.takeErrors().empty());
 
@@ -533,7 +534,7 @@
                                                        getDisplayHeight(), PixelFormat::RGBA_FP16);
         layer->setDisplayFrame({0, 0, getDisplayWidth(), getDisplayHeight()});
         layer->setZOrder(10);
-        layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+        layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), *mWriter);
 
         std::vector<std::shared_ptr<TestLayer>> layers = {layer};
 
@@ -542,7 +543,7 @@
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
         writeLayers(layers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
         execute();
 
         auto changedCompositionTypes = mReader.takeChangedCompositionTypes(getPrimaryDisplayId());
@@ -572,17 +573,17 @@
             int32_t clientFence;
             const auto unlockStatus = graphicBuffer->unlockAsync(&clientFence);
             ASSERT_EQ(::android::OK, unlockStatus);
-            mWriter.setClientTarget(getPrimaryDisplayId(), /*slot*/ 0, buffer, clientFence,
-                                    clientDataspace, std::vector<common::Rect>(1, damage));
-            layer->setToClientComposition(mWriter);
-            mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+            mWriter->setClientTarget(getPrimaryDisplayId(), /*slot*/ 0, buffer, clientFence,
+                                     clientDataspace, std::vector<common::Rect>(1, damage));
+            layer->setToClientComposition(*mWriter);
+            mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
             execute();
             changedCompositionTypes = mReader.takeChangedCompositionTypes(getPrimaryDisplayId());
             ASSERT_TRUE(changedCompositionTypes.empty());
         }
         ASSERT_TRUE(mReader.takeErrors().empty());
 
-        mWriter.presentDisplay(getPrimaryDisplayId());
+        mWriter->presentDisplay(getPrimaryDisplayId());
         execute();
 
         ASSERT_TRUE(mReader.takeErrors().empty());
@@ -631,9 +632,9 @@
         deviceLayer->setDisplayFrame({0, 0, static_cast<int32_t>(deviceLayer->getWidth()),
                                       static_cast<int32_t>(deviceLayer->getHeight())});
         deviceLayer->setZOrder(10);
-        deviceLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+        deviceLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), *mWriter);
         ASSERT_NO_FATAL_FAILURE(deviceLayer->setBuffer(deviceColors));
-        deviceLayer->write(mWriter);
+        deviceLayer->write(*mWriter);
 
         PixelFormat clientFormat = PixelFormat::RGBA_8888;
         auto clientUsage = static_cast<uint32_t>(
@@ -651,8 +652,8 @@
                                     getDisplayHeight()};
         clientLayer->setDisplayFrame(clientFrame);
         clientLayer->setZOrder(0);
-        clientLayer->write(mWriter);
-        mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+        clientLayer->write(*mWriter);
+        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
         execute();
 
         auto changedCompositionTypes = mReader.takeChangedCompositionTypes(getPrimaryDisplayId());
@@ -678,16 +679,16 @@
         int32_t clientFence;
         const auto unlockStatus = graphicBuffer->unlockAsync(&clientFence);
         ASSERT_EQ(::android::OK, unlockStatus);
-        mWriter.setClientTarget(getPrimaryDisplayId(), /*slot*/ 0, buffer, clientFence,
-                                clientDataspace, std::vector<common::Rect>(1, clientFrame));
-        clientLayer->setToClientComposition(mWriter);
-        mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+        mWriter->setClientTarget(getPrimaryDisplayId(), /*slot*/ 0, buffer, clientFence,
+                                 clientDataspace, std::vector<common::Rect>(1, clientFrame));
+        clientLayer->setToClientComposition(*mWriter);
+        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
         execute();
         changedCompositionTypes = mReader.takeChangedCompositionTypes(getPrimaryDisplayId());
         ASSERT_TRUE(changedCompositionTypes.empty());
         ASSERT_TRUE(mReader.takeErrors().empty());
 
-        mWriter.presentDisplay(getPrimaryDisplayId());
+        mWriter->presentDisplay(getPrimaryDisplayId());
         execute();
         ASSERT_TRUE(mReader.takeErrors().empty());
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
@@ -718,7 +719,7 @@
                                                        getDisplayHeight(), PixelFormat::RGBA_8888);
         layer->setDisplayFrame({0, 0, getDisplayWidth(), getDisplayHeight()});
         layer->setZOrder(10);
-        layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+        layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), *mWriter);
         ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors));
 
         std::vector<std::shared_ptr<TestLayer>> layers = {layer};
@@ -729,14 +730,14 @@
 
         writeLayers(layers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
         execute();
         if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
             GTEST_SUCCEED();
             return;
         }
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter.presentDisplay(getPrimaryDisplayId());
+        mWriter->presentDisplay(getPrimaryDisplayId());
         execute();
         ASSERT_TRUE(mReader.takeErrors().empty());
 
@@ -757,11 +758,11 @@
 
         writeLayers(layers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
         execute();
         ASSERT_TRUE(mReader.takeErrors().empty());
         ASSERT_TRUE(mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty());
-        mWriter.presentDisplay(getPrimaryDisplayId());
+        mWriter->presentDisplay(getPrimaryDisplayId());
         execute();
         ASSERT_TRUE(mReader.takeErrors().empty());
 
@@ -798,7 +799,7 @@
 
         writeLayers(layers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
         execute();
         if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
             GTEST_SUCCEED();
@@ -806,7 +807,7 @@
         }
         ASSERT_TRUE(mReader.takeErrors().empty());
 
-        mWriter.presentDisplay(getPrimaryDisplayId());
+        mWriter->presentDisplay(getPrimaryDisplayId());
         execute();
         ASSERT_TRUE(mReader.takeErrors().empty());
 
@@ -846,7 +847,7 @@
                                                        getDisplayHeight(), PixelFormat::RGBA_8888);
         layer->setDisplayFrame({0, 0, getDisplayWidth(), getDisplayHeight()});
         layer->setZOrder(10);
-        layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+        layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), *mWriter);
         layer->setSourceCrop({0, static_cast<float>(getDisplayHeight() / 2),
                               static_cast<float>(getDisplayWidth()),
                               static_cast<float>(getDisplayHeight())});
@@ -862,14 +863,14 @@
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
         writeLayers(layers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
         execute();
         if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
             GTEST_SUCCEED();
             return;
         }
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter.presentDisplay(getPrimaryDisplayId());
+        mWriter->presentDisplay(getPrimaryDisplayId());
         execute();
         ASSERT_TRUE(mReader.takeErrors().empty());
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
@@ -920,13 +921,13 @@
 
         writeLayers(layers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
         execute();
         if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
             GTEST_SUCCEED();
             return;
         }
-        mWriter.presentDisplay(getPrimaryDisplayId());
+        mWriter->presentDisplay(getPrimaryDisplayId());
         execute();
         ASSERT_TRUE(mReader.takeErrors().empty());
 
@@ -942,11 +943,11 @@
 
         writeLayers(layers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
         execute();
         ASSERT_TRUE(mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty());
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter.presentDisplay(getPrimaryDisplayId());
+        mWriter->presentDisplay(getPrimaryDisplayId());
         execute();
         ASSERT_TRUE(mReader.takeErrors().empty());
 
@@ -980,7 +981,7 @@
     // Preconditions to successfully run are knowing the max brightness and successfully applying
     // the max brightness
     ASSERT_GT(maxBrightnessNits, 0.f);
-    mWriter.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 1.f, maxBrightnessNits);
+    mWriter->setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 1.f, maxBrightnessNits);
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
 
@@ -1030,7 +1031,7 @@
 
         writeLayers(layers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
         execute();
         if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
             GTEST_SUCCEED()
@@ -1038,7 +1039,7 @@
                     << toString(mode);
             continue;
         }
-        mWriter.presentDisplay(getPrimaryDisplayId());
+        mWriter->presentDisplay(getPrimaryDisplayId());
         execute();
         ASSERT_TRUE(mReader.takeErrors().empty());
 
@@ -1088,7 +1089,7 @@
                                                        getDisplayHeight(), PixelFormat::RGBA_8888);
         layer->setDisplayFrame({0, 0, getDisplayWidth(), getDisplayHeight()});
         layer->setZOrder(10);
-        layer->setDataspace(Dataspace::UNKNOWN, mWriter);
+        layer->setDataspace(Dataspace::UNKNOWN, *mWriter);
         ASSERT_NO_FATAL_FAILURE(layer->setBuffer(topLayerPixelColors));
 
         layer->setBlendMode(blendMode);
@@ -1165,14 +1166,14 @@
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
         writeLayers(mLayers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
         execute();
         if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
             GTEST_SUCCEED();
             return;
         }
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter.presentDisplay(getPrimaryDisplayId());
+        mWriter->presentDisplay(getPrimaryDisplayId());
         execute();
         ASSERT_TRUE(mReader.takeErrors().empty());
 
@@ -1210,14 +1211,14 @@
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
         writeLayers(mLayers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
         execute();
         if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
             GTEST_SUCCEED();
             return;
         }
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter.presentDisplay(getPrimaryDisplayId());
+        mWriter->presentDisplay(getPrimaryDisplayId());
         execute();
         ASSERT_TRUE(mReader.takeErrors().empty());
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
@@ -1250,14 +1251,14 @@
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
         writeLayers(mLayers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
         execute();
         if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
             GTEST_SUCCEED();
             return;
         }
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter.presentDisplay(getPrimaryDisplayId());
+        mWriter->presentDisplay(getPrimaryDisplayId());
         execute();
         ASSERT_TRUE(mReader.takeErrors().empty());
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
@@ -1323,7 +1324,7 @@
                                       getDisplayHeight(), mPixelFormat, mDataspace);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
         mLayer->setTransform(Transform::FLIP_H);
-        mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+        mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), *mWriter);
 
         std::vector<Color> expectedColors(
                 static_cast<size_t>(getDisplayWidth() * getDisplayHeight()));
@@ -1334,14 +1335,14 @@
 
         writeLayers(mLayers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
         execute();
         if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
             GTEST_SUCCEED();
             return;
         }
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter.presentDisplay(getPrimaryDisplayId());
+        mWriter->presentDisplay(getPrimaryDisplayId());
         execute();
         ASSERT_TRUE(mReader.takeErrors().empty());
 
@@ -1369,7 +1370,7 @@
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
         mLayer->setTransform(Transform::FLIP_V);
-        mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+        mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), *mWriter);
 
         std::vector<Color> expectedColors(
                 static_cast<size_t>(getDisplayWidth() * getDisplayHeight()));
@@ -1380,14 +1381,14 @@
 
         writeLayers(mLayers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
         execute();
         if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
             GTEST_SUCCEED();
             return;
         }
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter.presentDisplay(getPrimaryDisplayId());
+        mWriter->presentDisplay(getPrimaryDisplayId());
         execute();
         ASSERT_TRUE(mReader.takeErrors().empty());
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
@@ -1414,7 +1415,7 @@
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
         mLayer->setTransform(Transform::ROT_180);
-        mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+        mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), *mWriter);
 
         std::vector<Color> expectedColors(
                 static_cast<size_t>(getDisplayWidth() * getDisplayHeight()));
@@ -1426,14 +1427,14 @@
 
         writeLayers(mLayers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
         execute();
         if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
             GTEST_SUCCEED();
             return;
         }
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter.presentDisplay(getPrimaryDisplayId());
+        mWriter->presentDisplay(getPrimaryDisplayId());
         execute();
         ASSERT_TRUE(mReader.takeErrors().empty());
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
diff --git a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
index 93b646f..fa66812 100644
--- a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
+++ b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
@@ -13,6 +13,7 @@
  * 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/graphics/common/BlendMode.h>
@@ -32,9 +33,11 @@
 #include <ui/GraphicBuffer.h>
 #include <ui/PixelFormat.h>
 #include <algorithm>
+#include <iterator>
 #include <numeric>
 #include <string>
 #include <thread>
+#include <unordered_map>
 #include "GraphicsComposerCallback.h"
 #include "VtsComposerClient.h"
 
@@ -808,6 +811,18 @@
     EXPECT_TRUE(status.isOk());
 }
 
+// TODO(b/250036572): disable this due to no implementation and revup on cuttlefish
+TEST_P(GraphicsComposerAidlTest, DISABLED_GetOverlaySupport) {
+    const auto& [status, _] = mComposerClient->getOverlaySupport();
+    if (!status.isOk() && status.getExceptionCode() == EX_SERVICE_SPECIFIC &&
+        status.getServiceSpecificError() == IComposerClient::EX_UNSUPPORTED) {
+        GTEST_SUCCEED() << "getOverlaySupport is not supported";
+        return;
+    }
+
+    ASSERT_TRUE(status.isOk());
+}
+
 TEST_P(GraphicsComposerAidlTest, GetDisplayPhysicalOrientation_BadDisplay) {
     const auto& [status, _] = mComposerClient->getDisplayPhysicalOrientation(getInvalidDisplayId());
 
@@ -1065,17 +1080,23 @@
     }
 
     void execute() {
-        const auto& commands = mWriter.getPendingCommands();
-        if (commands.empty()) {
-            mWriter.reset();
-            return;
+        std::vector<CommandResultPayload> payloads;
+        for (auto& [_, writer] : mWriters) {
+            const auto& commands = writer.getPendingCommands();
+            if (commands.empty()) {
+                writer.reset();
+                continue;
+            }
+
+            auto [status, results] = mComposerClient->executeCommands(commands);
+            ASSERT_TRUE(status.isOk()) << "executeCommands failed " << status.getDescription();
+            writer.reset();
+
+            payloads.reserve(payloads.size() + results.size());
+            payloads.insert(payloads.end(), std::make_move_iterator(results.begin()),
+                            std::make_move_iterator(results.end()));
         }
-
-        auto [status, results] = mComposerClient->executeCommands(commands);
-        ASSERT_TRUE(status.isOk()) << "executeCommands failed " << status.getDescription();
-
-        mReader.parse(std::move(results));
-        mWriter.reset();
+        mReader.parse(std::move(payloads));
     }
 
     static inline auto toTimePoint(nsecs_t time) {
@@ -1139,6 +1160,7 @@
         const auto& [status, layer] =
                 mComposerClient->createLayer(display.getDisplayId(), kBufferSlotCount);
         EXPECT_TRUE(status.isOk());
+        auto& writer = getWriter(display.getDisplayId());
         {
             const auto buffer = allocate(::android::PIXEL_FORMAT_RGBA_8888);
             ASSERT_NE(nullptr, buffer);
@@ -1147,15 +1169,15 @@
 
             configureLayer(display, layer, Composition::DEVICE, display.getFrameRect(),
                            display.getCrop());
-            mWriter.setLayerBuffer(display.getDisplayId(), layer, /*slot*/ 0, buffer->handle,
-                                   /*acquireFence*/ -1);
-            mWriter.setLayerDataspace(display.getDisplayId(), layer, common::Dataspace::UNKNOWN);
+            writer.setLayerBuffer(display.getDisplayId(), layer, /*slot*/ 0, buffer->handle,
+                                  /*acquireFence*/ -1);
+            writer.setLayerDataspace(display.getDisplayId(), layer, common::Dataspace::UNKNOWN);
 
-            mWriter.validateDisplay(display.getDisplayId(), ComposerClientWriter::kNoTimestamp);
+            writer.validateDisplay(display.getDisplayId(), ComposerClientWriter::kNoTimestamp);
             execute();
             ASSERT_TRUE(mReader.takeErrors().empty());
 
-            mWriter.presentDisplay(display.getDisplayId());
+            writer.presentDisplay(display.getDisplayId());
             execute();
             ASSERT_TRUE(mReader.takeErrors().empty());
         }
@@ -1164,15 +1186,15 @@
             const auto buffer = allocate(::android::PIXEL_FORMAT_RGBA_8888);
             ASSERT_NE(nullptr, buffer->handle);
 
-            mWriter.setLayerBuffer(display.getDisplayId(), layer, /*slot*/ 0, buffer->handle,
-                                   /*acquireFence*/ -1);
-            mWriter.setLayerSurfaceDamage(display.getDisplayId(), layer,
-                                          std::vector<Rect>(1, {0, 0, 10, 10}));
-            mWriter.validateDisplay(display.getDisplayId(), ComposerClientWriter::kNoTimestamp);
+            writer.setLayerBuffer(display.getDisplayId(), layer, /*slot*/ 0, buffer->handle,
+                                  /*acquireFence*/ -1);
+            writer.setLayerSurfaceDamage(display.getDisplayId(), layer,
+                                         std::vector<Rect>(1, {0, 0, 10, 10}));
+            writer.validateDisplay(display.getDisplayId(), ComposerClientWriter::kNoTimestamp);
             execute();
             ASSERT_TRUE(mReader.takeErrors().empty());
 
-            mWriter.presentDisplay(display.getDisplayId());
+            writer.presentDisplay(display.getDisplayId());
             execute();
         }
 
@@ -1181,11 +1203,12 @@
 
     sp<::android::Fence> presentAndGetFence(
             std::optional<ClockMonotonicTimestamp> expectedPresentTime) {
-        mWriter.validateDisplay(getPrimaryDisplayId(), expectedPresentTime);
+        auto& writer = getWriter(getPrimaryDisplayId());
+        writer.validateDisplay(getPrimaryDisplayId(), expectedPresentTime);
         execute();
         EXPECT_TRUE(mReader.takeErrors().empty());
 
-        mWriter.presentDisplay(getPrimaryDisplayId());
+        writer.presentDisplay(getPrimaryDisplayId());
         execute();
         EXPECT_TRUE(mReader.takeErrors().empty());
 
@@ -1217,7 +1240,8 @@
         FRect cropRect{0, 0, (float)getPrimaryDisplay().getDisplayWidth(),
                        (float)getPrimaryDisplay().getDisplayHeight()};
         configureLayer(getPrimaryDisplay(), layer, Composition::DEVICE, displayFrame, cropRect);
-        mWriter.setLayerDataspace(getPrimaryDisplayId(), layer, common::Dataspace::UNKNOWN);
+        auto& writer = getWriter(getPrimaryDisplayId());
+        writer.setLayerDataspace(getPrimaryDisplayId(), layer, common::Dataspace::UNKNOWN);
         return layer;
     }
 
@@ -1317,8 +1341,9 @@
         ASSERT_NE(nullptr, buffer2);
 
         const auto layer = createOnScreenLayer();
-        mWriter.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, buffer1->handle,
-                               /*acquireFence*/ -1);
+        auto& writer = getWriter(getPrimaryDisplayId());
+        writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, buffer1->handle,
+                              /*acquireFence*/ -1);
         const sp<::android::Fence> presentFence1 =
                 presentAndGetFence(ComposerClientWriter::kNoTimestamp);
         presentFence1->waitForever(LOG_TAG);
@@ -1328,8 +1353,8 @@
             expectedPresentTime += *framesDelay * vsyncPeriod;
         }
 
-        mWriter.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, buffer2->handle,
-                               /*acquireFence*/ -1);
+        writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, buffer2->handle,
+                              /*acquireFence*/ -1);
         const auto setExpectedPresentTime = [&]() -> std::optional<ClockMonotonicTimestamp> {
             if (!framesDelay.has_value()) {
                 return ComposerClientWriter::kNoTimestamp;
@@ -1350,17 +1375,18 @@
 
     void configureLayer(const VtsDisplay& display, int64_t layer, Composition composition,
                         const Rect& displayFrame, const FRect& cropRect) {
-        mWriter.setLayerCompositionType(display.getDisplayId(), layer, composition);
-        mWriter.setLayerDisplayFrame(display.getDisplayId(), layer, displayFrame);
-        mWriter.setLayerPlaneAlpha(display.getDisplayId(), layer, /*alpha*/ 1);
-        mWriter.setLayerSourceCrop(display.getDisplayId(), layer, cropRect);
-        mWriter.setLayerTransform(display.getDisplayId(), layer, static_cast<Transform>(0));
-        mWriter.setLayerVisibleRegion(display.getDisplayId(), layer,
-                                      std::vector<Rect>(1, displayFrame));
-        mWriter.setLayerZOrder(display.getDisplayId(), layer, /*z*/ 10);
-        mWriter.setLayerBlendMode(display.getDisplayId(), layer, BlendMode::NONE);
-        mWriter.setLayerSurfaceDamage(display.getDisplayId(), layer,
-                                      std::vector<Rect>(1, displayFrame));
+        auto& writer = getWriter(display.getDisplayId());
+        writer.setLayerCompositionType(display.getDisplayId(), layer, composition);
+        writer.setLayerDisplayFrame(display.getDisplayId(), layer, displayFrame);
+        writer.setLayerPlaneAlpha(display.getDisplayId(), layer, /*alpha*/ 1);
+        writer.setLayerSourceCrop(display.getDisplayId(), layer, cropRect);
+        writer.setLayerTransform(display.getDisplayId(), layer, static_cast<Transform>(0));
+        writer.setLayerVisibleRegion(display.getDisplayId(), layer,
+                                     std::vector<Rect>(1, displayFrame));
+        writer.setLayerZOrder(display.getDisplayId(), layer, /*z*/ 10);
+        writer.setLayerBlendMode(display.getDisplayId(), layer, BlendMode::NONE);
+        writer.setLayerSurfaceDamage(display.getDisplayId(), layer,
+                                     std::vector<Rect>(1, displayFrame));
     }
     // clang-format off
     const std::array<float, 16> kIdentity = {{
@@ -1371,12 +1397,20 @@
     }};
     // clang-format on
 
-    ComposerClientWriter mWriter;
+    ComposerClientWriter& getWriter(int64_t display) {
+        auto [it, _] = mWriters.try_emplace(display, display);
+        return it->second;
+    }
+
     ComposerClientReader mReader;
+
+  private:
+    std::unordered_map<int64_t, ComposerClientWriter> mWriters;
 };
 
 TEST_P(GraphicsComposerAidlCommandTest, SetColorTransform) {
-    mWriter.setColorTransform(getPrimaryDisplayId(), kIdentity.data());
+    auto& writer = getWriter(getPrimaryDisplayId());
+    writer.setColorTransform(getPrimaryDisplayId(), kIdentity.data());
     execute();
 }
 
@@ -1384,7 +1418,8 @@
     const auto& [status, layer] =
             mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
     EXPECT_TRUE(status.isOk());
-    mWriter.setLayerColorTransform(getPrimaryDisplayId(), layer, kIdentity.data());
+    auto& writer = getWriter(getPrimaryDisplayId());
+    writer.setLayerColorTransform(getPrimaryDisplayId(), layer, kIdentity.data());
     execute();
 
     const auto errors = mReader.takeErrors();
@@ -1400,8 +1435,9 @@
     ASSERT_TRUE(status.isOk());
     bool brightnessSupport = std::find(capabilities.begin(), capabilities.end(),
                                        DisplayCapability::BRIGHTNESS) != capabilities.end();
+    auto& writer = getWriter(getPrimaryDisplayId());
     if (!brightnessSupport) {
-        mWriter.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 0.5f, -1.f);
+        writer.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 0.5f, -1.f);
         execute();
         const auto errors = mReader.takeErrors();
         EXPECT_EQ(1, errors.size());
@@ -1410,23 +1446,23 @@
         return;
     }
 
-    mWriter.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 0.0f, -1.f);
+    writer.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 0.0f, -1.f);
     execute();
     EXPECT_TRUE(mReader.takeErrors().empty());
 
-    mWriter.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 0.5f, -1.f);
+    writer.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 0.5f, -1.f);
     execute();
     EXPECT_TRUE(mReader.takeErrors().empty());
 
-    mWriter.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 1.0f, -1.f);
+    writer.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 1.0f, -1.f);
     execute();
     EXPECT_TRUE(mReader.takeErrors().empty());
 
-    mWriter.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ -1.0f, -1.f);
+    writer.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ -1.0f, -1.f);
     execute();
     EXPECT_TRUE(mReader.takeErrors().empty());
 
-    mWriter.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 2.0f, -1.f);
+    writer.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 2.0f, -1.f);
     execute();
     {
         const auto errors = mReader.takeErrors();
@@ -1434,7 +1470,7 @@
         EXPECT_EQ(IComposerClient::EX_BAD_PARAMETER, errors[0].errorCode);
     }
 
-    mWriter.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ -2.0f, -1.f);
+    writer.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ -2.0f, -1.f);
     execute();
     {
         const auto errors = mReader.takeErrors();
@@ -1447,8 +1483,9 @@
     EXPECT_TRUE(mComposerClient->setClientTargetSlotCount(getPrimaryDisplayId(), kBufferSlotCount)
                         .isOk());
 
-    mWriter.setClientTarget(getPrimaryDisplayId(), /*slot*/ 0, nullptr, /*acquireFence*/ -1,
-                            Dataspace::UNKNOWN, std::vector<Rect>());
+    auto& writer = getWriter(getPrimaryDisplayId());
+    writer.setClientTarget(getPrimaryDisplayId(), /*slot*/ 0, nullptr, /*acquireFence*/ -1,
+                           Dataspace::UNKNOWN, std::vector<Rect>());
 
     execute();
 }
@@ -1468,24 +1505,28 @@
 
     const auto buffer = allocate(::android::PIXEL_FORMAT_RGBA_8888);
     const auto handle = buffer->handle;
-    mWriter.setOutputBuffer(display.display, /*slot*/ 0, handle, /*releaseFence*/ -1);
+    auto& writer = getWriter(display.display);
+    writer.setOutputBuffer(display.display, /*slot*/ 0, handle, /*releaseFence*/ -1);
     execute();
 }
 
 TEST_P(GraphicsComposerAidlCommandTest, ValidDisplay) {
-    mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+    auto& writer = getWriter(getPrimaryDisplayId());
+    writer.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
     execute();
 }
 
 TEST_P(GraphicsComposerAidlCommandTest, AcceptDisplayChanges) {
-    mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
-    mWriter.acceptDisplayChanges(getPrimaryDisplayId());
+    auto& writer = getWriter(getPrimaryDisplayId());
+    writer.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+    writer.acceptDisplayChanges(getPrimaryDisplayId());
     execute();
 }
 
 TEST_P(GraphicsComposerAidlCommandTest, PresentDisplay) {
-    mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
-    mWriter.presentDisplay(getPrimaryDisplayId());
+    auto& writer = getWriter(getPrimaryDisplayId());
+    writer.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+    writer.presentDisplay(getPrimaryDisplayId());
     execute();
 }
 
@@ -1506,6 +1547,7 @@
     const auto& [renderIntentsStatus, renderIntents] =
             mComposerClient->getRenderIntents(getPrimaryDisplayId(), ColorMode::NATIVE);
     EXPECT_TRUE(renderIntentsStatus.isOk());
+    auto& writer = getWriter(getPrimaryDisplayId());
     for (auto intent : renderIntents) {
         EXPECT_TRUE(mComposerClient->setColorMode(getPrimaryDisplayId(), ColorMode::NATIVE, intent)
                             .isOk());
@@ -1523,10 +1565,10 @@
         FRect cropRect{0, 0, (float)getPrimaryDisplay().getDisplayWidth(),
                        (float)getPrimaryDisplay().getDisplayHeight()};
         configureLayer(getPrimaryDisplay(), layer, Composition::CURSOR, displayFrame, cropRect);
-        mWriter.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, handle,
-                               /*acquireFence*/ -1);
-        mWriter.setLayerDataspace(getPrimaryDisplayId(), layer, Dataspace::UNKNOWN);
-        mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+        writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, handle,
+                              /*acquireFence*/ -1);
+        writer.setLayerDataspace(getPrimaryDisplayId(), layer, Dataspace::UNKNOWN);
+        writer.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
         execute();
         if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
             GTEST_SUCCEED() << "Composition change requested, skipping test";
@@ -1534,18 +1576,18 @@
         }
 
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter.presentDisplay(getPrimaryDisplayId());
+        writer.presentDisplay(getPrimaryDisplayId());
         execute();
         ASSERT_TRUE(mReader.takeErrors().empty());
 
         const auto buffer2 = allocate(::android::PIXEL_FORMAT_RGBA_8888);
         const auto handle2 = buffer2->handle;
         ASSERT_NE(nullptr, handle2);
-        mWriter.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, handle2,
-                               /*acquireFence*/ -1);
-        mWriter.setLayerSurfaceDamage(getPrimaryDisplayId(), layer,
-                                      std::vector<Rect>(1, {0, 0, 10, 10}));
-        mWriter.presentDisplay(getPrimaryDisplayId());
+        writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, handle2,
+                              /*acquireFence*/ -1);
+        writer.setLayerSurfaceDamage(getPrimaryDisplayId(), layer,
+                                     std::vector<Rect>(1, {0, 0, 10, 10}));
+        writer.presentDisplay(getPrimaryDisplayId());
         execute();
     }
 }
@@ -1559,15 +1601,16 @@
     const auto handle = buffer->handle;
     ASSERT_NE(nullptr, handle);
 
-    mWriter.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, handle, /*acquireFence*/ -1);
+    auto& writer = getWriter(getPrimaryDisplayId());
+    writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, handle, /*acquireFence*/ -1);
 
     Rect displayFrame{0, 0, getPrimaryDisplay().getDisplayWidth(),
                       getPrimaryDisplay().getDisplayHeight()};
     FRect cropRect{0, 0, (float)getPrimaryDisplay().getDisplayWidth(),
                    (float)getPrimaryDisplay().getDisplayHeight()};
     configureLayer(getPrimaryDisplay(), layer, Composition::CURSOR, displayFrame, cropRect);
-    mWriter.setLayerDataspace(getPrimaryDisplayId(), layer, Dataspace::UNKNOWN);
-    mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+    writer.setLayerDataspace(getPrimaryDisplayId(), layer, Dataspace::UNKNOWN);
+    writer.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
 
     execute();
 
@@ -1575,15 +1618,15 @@
         GTEST_SUCCEED() << "Composition change requested, skipping test";
         return;
     }
-    mWriter.presentDisplay(getPrimaryDisplayId());
+    writer.presentDisplay(getPrimaryDisplayId());
     ASSERT_TRUE(mReader.takeErrors().empty());
 
-    mWriter.setLayerCursorPosition(getPrimaryDisplayId(), layer, /*x*/ 1, /*y*/ 1);
+    writer.setLayerCursorPosition(getPrimaryDisplayId(), layer, /*x*/ 1, /*y*/ 1);
     execute();
 
-    mWriter.setLayerCursorPosition(getPrimaryDisplayId(), layer, /*x*/ 0, /*y*/ 0);
-    mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
-    mWriter.presentDisplay(getPrimaryDisplayId());
+    writer.setLayerCursorPosition(getPrimaryDisplayId(), layer, /*x*/ 0, /*y*/ 0);
+    writer.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+    writer.presentDisplay(getPrimaryDisplayId());
     execute();
 }
 
@@ -1595,7 +1638,8 @@
     const auto& [layerStatus, layer] =
             mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
     EXPECT_TRUE(layerStatus.isOk());
-    mWriter.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, handle, /*acquireFence*/ -1);
+    auto& writer = getWriter(getPrimaryDisplayId());
+    writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, handle, /*acquireFence*/ -1);
     execute();
 }
 
@@ -1607,15 +1651,16 @@
     Rect empty{0, 0, 0, 0};
     Rect unit{0, 0, 1, 1};
 
-    mWriter.setLayerSurfaceDamage(getPrimaryDisplayId(), layer, std::vector<Rect>(1, empty));
+    auto& writer = getWriter(getPrimaryDisplayId());
+    writer.setLayerSurfaceDamage(getPrimaryDisplayId(), layer, std::vector<Rect>(1, empty));
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
 
-    mWriter.setLayerSurfaceDamage(getPrimaryDisplayId(), layer, std::vector<Rect>(1, unit));
+    writer.setLayerSurfaceDamage(getPrimaryDisplayId(), layer, std::vector<Rect>(1, unit));
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
 
-    mWriter.setLayerSurfaceDamage(getPrimaryDisplayId(), layer, std::vector<Rect>());
+    writer.setLayerSurfaceDamage(getPrimaryDisplayId(), layer, std::vector<Rect>());
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
 }
@@ -1628,15 +1673,16 @@
     Rect empty{0, 0, 0, 0};
     Rect unit{0, 0, 1, 1};
 
-    mWriter.setLayerBlockingRegion(getPrimaryDisplayId(), layer, std::vector<Rect>(1, empty));
+    auto& writer = getWriter(getPrimaryDisplayId());
+    writer.setLayerBlockingRegion(getPrimaryDisplayId(), layer, std::vector<Rect>(1, empty));
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
 
-    mWriter.setLayerBlockingRegion(getPrimaryDisplayId(), layer, std::vector<Rect>(1, unit));
+    writer.setLayerBlockingRegion(getPrimaryDisplayId(), layer, std::vector<Rect>(1, unit));
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
 
-    mWriter.setLayerBlockingRegion(getPrimaryDisplayId(), layer, std::vector<Rect>());
+    writer.setLayerBlockingRegion(getPrimaryDisplayId(), layer, std::vector<Rect>());
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
 }
@@ -1646,15 +1692,16 @@
             mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
     EXPECT_TRUE(layerStatus.isOk());
 
-    mWriter.setLayerBlendMode(getPrimaryDisplayId(), layer, BlendMode::NONE);
+    auto& writer = getWriter(getPrimaryDisplayId());
+    writer.setLayerBlendMode(getPrimaryDisplayId(), layer, BlendMode::NONE);
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
 
-    mWriter.setLayerBlendMode(getPrimaryDisplayId(), layer, BlendMode::PREMULTIPLIED);
+    writer.setLayerBlendMode(getPrimaryDisplayId(), layer, BlendMode::PREMULTIPLIED);
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
 
-    mWriter.setLayerBlendMode(getPrimaryDisplayId(), layer, BlendMode::COVERAGE);
+    writer.setLayerBlendMode(getPrimaryDisplayId(), layer, BlendMode::COVERAGE);
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
 }
@@ -1664,11 +1711,12 @@
             mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
     EXPECT_TRUE(layerStatus.isOk());
 
-    mWriter.setLayerColor(getPrimaryDisplayId(), layer, Color{1.0f, 1.0f, 1.0f, 1.0f});
+    auto& writer = getWriter(getPrimaryDisplayId());
+    writer.setLayerColor(getPrimaryDisplayId(), layer, Color{1.0f, 1.0f, 1.0f, 1.0f});
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
 
-    mWriter.setLayerColor(getPrimaryDisplayId(), layer, Color{0.0f, 0.0f, 0.0f, 0.0f});
+    writer.setLayerColor(getPrimaryDisplayId(), layer, Color{0.0f, 0.0f, 0.0f, 0.0f});
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
 }
@@ -1678,19 +1726,20 @@
             mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
     EXPECT_TRUE(layerStatus.isOk());
 
-    mWriter.setLayerCompositionType(getPrimaryDisplayId(), layer, Composition::CLIENT);
+    auto& writer = getWriter(getPrimaryDisplayId());
+    writer.setLayerCompositionType(getPrimaryDisplayId(), layer, Composition::CLIENT);
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
 
-    mWriter.setLayerCompositionType(getPrimaryDisplayId(), layer, Composition::DEVICE);
+    writer.setLayerCompositionType(getPrimaryDisplayId(), layer, Composition::DEVICE);
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
 
-    mWriter.setLayerCompositionType(getPrimaryDisplayId(), layer, Composition::SOLID_COLOR);
+    writer.setLayerCompositionType(getPrimaryDisplayId(), layer, Composition::SOLID_COLOR);
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
 
-    mWriter.setLayerCompositionType(getPrimaryDisplayId(), layer, Composition::CURSOR);
+    writer.setLayerCompositionType(getPrimaryDisplayId(), layer, Composition::CURSOR);
     execute();
 }
 
@@ -1721,9 +1770,10 @@
 
         configureLayer(display, layer, Composition::DISPLAY_DECORATION, display.getFrameRect(),
                           display.getCrop());
-        mWriter.setLayerBuffer(display.getDisplayId(), layer, /*slot*/ 0, decorBuffer->handle,
-                               /*acquireFence*/ -1);
-        mWriter.validateDisplay(display.getDisplayId(), ComposerClientWriter::kNoTimestamp);
+        auto& writer = getWriter(display.getDisplayId());
+        writer.setLayerBuffer(display.getDisplayId(), layer, /*slot*/ 0, decorBuffer->handle,
+                              /*acquireFence*/ -1);
+        writer.validateDisplay(display.getDisplayId(), ComposerClientWriter::kNoTimestamp);
         execute();
         if (support) {
             ASSERT_TRUE(mReader.takeErrors().empty());
@@ -1740,7 +1790,8 @@
             mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
     EXPECT_TRUE(layerStatus.isOk());
 
-    mWriter.setLayerDataspace(getPrimaryDisplayId(), layer, Dataspace::UNKNOWN);
+    auto& writer = getWriter(getPrimaryDisplayId());
+    writer.setLayerDataspace(getPrimaryDisplayId(), layer, Dataspace::UNKNOWN);
     execute();
 }
 
@@ -1749,7 +1800,8 @@
             mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
     EXPECT_TRUE(layerStatus.isOk());
 
-    mWriter.setLayerDisplayFrame(getPrimaryDisplayId(), layer, Rect{0, 0, 1, 1});
+    auto& writer = getWriter(getPrimaryDisplayId());
+    writer.setLayerDisplayFrame(getPrimaryDisplayId(), layer, Rect{0, 0, 1, 1});
     execute();
 }
 
@@ -1758,11 +1810,12 @@
             mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
     EXPECT_TRUE(layerStatus.isOk());
 
-    mWriter.setLayerPlaneAlpha(getPrimaryDisplayId(), layer, /*alpha*/ 0.0f);
+    auto& writer = getWriter(getPrimaryDisplayId());
+    writer.setLayerPlaneAlpha(getPrimaryDisplayId(), layer, /*alpha*/ 0.0f);
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
 
-    mWriter.setLayerPlaneAlpha(getPrimaryDisplayId(), layer, /*alpha*/ 1.0f);
+    writer.setLayerPlaneAlpha(getPrimaryDisplayId(), layer, /*alpha*/ 1.0f);
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
 }
@@ -1781,7 +1834,8 @@
             mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
     EXPECT_TRUE(layerStatus.isOk());
 
-    mWriter.setLayerSidebandStream(getPrimaryDisplayId(), layer, handle);
+    auto& writer = getWriter(getPrimaryDisplayId());
+    writer.setLayerSidebandStream(getPrimaryDisplayId(), layer, handle);
     execute();
 }
 
@@ -1790,7 +1844,8 @@
             mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
     EXPECT_TRUE(layerStatus.isOk());
 
-    mWriter.setLayerSourceCrop(getPrimaryDisplayId(), layer, FRect{0.0f, 0.0f, 1.0f, 1.0f});
+    auto& writer = getWriter(getPrimaryDisplayId());
+    writer.setLayerSourceCrop(getPrimaryDisplayId(), layer, FRect{0.0f, 0.0f, 1.0f, 1.0f});
     execute();
 }
 
@@ -1799,39 +1854,40 @@
             mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
     EXPECT_TRUE(layerStatus.isOk());
 
-    mWriter.setLayerTransform(getPrimaryDisplayId(), layer, static_cast<Transform>(0));
+    auto& writer = getWriter(getPrimaryDisplayId());
+    writer.setLayerTransform(getPrimaryDisplayId(), layer, static_cast<Transform>(0));
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
 
-    mWriter.setLayerTransform(getPrimaryDisplayId(), layer, Transform::FLIP_H);
+    writer.setLayerTransform(getPrimaryDisplayId(), layer, Transform::FLIP_H);
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
 
-    mWriter.setLayerTransform(getPrimaryDisplayId(), layer, Transform::FLIP_V);
+    writer.setLayerTransform(getPrimaryDisplayId(), layer, Transform::FLIP_V);
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
 
-    mWriter.setLayerTransform(getPrimaryDisplayId(), layer, Transform::ROT_90);
+    writer.setLayerTransform(getPrimaryDisplayId(), layer, Transform::ROT_90);
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
 
-    mWriter.setLayerTransform(getPrimaryDisplayId(), layer, Transform::ROT_180);
+    writer.setLayerTransform(getPrimaryDisplayId(), layer, Transform::ROT_180);
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
 
-    mWriter.setLayerTransform(getPrimaryDisplayId(), layer, Transform::ROT_270);
+    writer.setLayerTransform(getPrimaryDisplayId(), layer, Transform::ROT_270);
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
 
-    mWriter.setLayerTransform(getPrimaryDisplayId(), layer,
-                              static_cast<Transform>(static_cast<int>(Transform::FLIP_H) |
-                                                     static_cast<int>(Transform::ROT_90)));
+    writer.setLayerTransform(getPrimaryDisplayId(), layer,
+                             static_cast<Transform>(static_cast<int>(Transform::FLIP_H) |
+                                                    static_cast<int>(Transform::ROT_90)));
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
 
-    mWriter.setLayerTransform(getPrimaryDisplayId(), layer,
-                              static_cast<Transform>(static_cast<int>(Transform::FLIP_V) |
-                                                     static_cast<int>(Transform::ROT_90)));
+    writer.setLayerTransform(getPrimaryDisplayId(), layer,
+                             static_cast<Transform>(static_cast<int>(Transform::FLIP_V) |
+                                                    static_cast<int>(Transform::ROT_90)));
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
 }
@@ -1844,15 +1900,16 @@
     Rect empty{0, 0, 0, 0};
     Rect unit{0, 0, 1, 1};
 
-    mWriter.setLayerVisibleRegion(getPrimaryDisplayId(), layer, std::vector<Rect>(1, empty));
+    auto& writer = getWriter(getPrimaryDisplayId());
+    writer.setLayerVisibleRegion(getPrimaryDisplayId(), layer, std::vector<Rect>(1, empty));
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
 
-    mWriter.setLayerVisibleRegion(getPrimaryDisplayId(), layer, std::vector<Rect>(1, unit));
+    writer.setLayerVisibleRegion(getPrimaryDisplayId(), layer, std::vector<Rect>(1, unit));
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
 
-    mWriter.setLayerVisibleRegion(getPrimaryDisplayId(), layer, std::vector<Rect>());
+    writer.setLayerVisibleRegion(getPrimaryDisplayId(), layer, std::vector<Rect>());
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
 }
@@ -1862,11 +1919,12 @@
             mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
     EXPECT_TRUE(layerStatus.isOk());
 
-    mWriter.setLayerZOrder(getPrimaryDisplayId(), layer, /*z*/ 10);
+    auto& writer = getWriter(getPrimaryDisplayId());
+    writer.setLayerZOrder(getPrimaryDisplayId(), layer, /*z*/ 10);
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
 
-    mWriter.setLayerZOrder(getPrimaryDisplayId(), layer, /*z*/ 0);
+    writer.setLayerZOrder(getPrimaryDisplayId(), layer, /*z*/ 0);
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
 }
@@ -1888,6 +1946,7 @@
      *  white (D65)     0.3127  0.3290
      */
 
+    auto& writer = getWriter(getPrimaryDisplayId());
     std::vector<PerFrameMetadata> aidlMetadata;
     aidlMetadata.push_back({PerFrameMetadataKey::DISPLAY_RED_PRIMARY_X, 0.680f});
     aidlMetadata.push_back({PerFrameMetadataKey::DISPLAY_RED_PRIMARY_Y, 0.320f});
@@ -1901,7 +1960,7 @@
     aidlMetadata.push_back({PerFrameMetadataKey::MIN_LUMINANCE, 0.1f});
     aidlMetadata.push_back({PerFrameMetadataKey::MAX_CONTENT_LIGHT_LEVEL, 78.0});
     aidlMetadata.push_back({PerFrameMetadataKey::MAX_FRAME_AVERAGE_LIGHT_LEVEL, 62.0});
-    mWriter.setLayerPerFrameMetadata(getPrimaryDisplayId(), layer, aidlMetadata);
+    writer.setLayerPerFrameMetadata(getPrimaryDisplayId(), layer, aidlMetadata);
     execute();
 
     const auto errors = mReader.takeErrors();
@@ -1918,19 +1977,20 @@
     const auto& [layerStatus, layer] =
             mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
 
-    mWriter.setLayerBrightness(getPrimaryDisplayId(), layer, 0.2f);
+    auto& writer = getWriter(getPrimaryDisplayId());
+    writer.setLayerBrightness(getPrimaryDisplayId(), layer, 0.2f);
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
 
-    mWriter.setLayerBrightness(getPrimaryDisplayId(), layer, 1.f);
+    writer.setLayerBrightness(getPrimaryDisplayId(), layer, 1.f);
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
 
-    mWriter.setLayerBrightness(getPrimaryDisplayId(), layer, 0.f);
+    writer.setLayerBrightness(getPrimaryDisplayId(), layer, 0.f);
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
 
-    mWriter.setLayerBrightness(getPrimaryDisplayId(), layer, -1.f);
+    writer.setLayerBrightness(getPrimaryDisplayId(), layer, -1.f);
     execute();
     {
         const auto errors = mReader.takeErrors();
@@ -1938,7 +1998,7 @@
         EXPECT_EQ(IComposerClient::EX_BAD_PARAMETER, errors[0].errorCode);
     }
 
-    mWriter.setLayerBrightness(getPrimaryDisplayId(), layer, std::nanf(""));
+    writer.setLayerBrightness(getPrimaryDisplayId(), layer, std::nanf(""));
     execute();
     {
         const auto errors = mReader.takeErrors();
@@ -2103,8 +2163,9 @@
     ASSERT_NE(nullptr, buffer->handle);
 
     const auto layer = createOnScreenLayer();
-    mWriter.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, buffer->handle,
-                           /*acquireFence*/ -1);
+    auto& writer = getWriter(getPrimaryDisplayId());
+    writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, buffer->handle,
+                          /*acquireFence*/ -1);
     int32_t vsyncIdleCount = mComposerClient->getVsyncIdleCount();
     auto earlyVsyncIdleTime = systemTime() + std::chrono::nanoseconds(2s).count();
     EXPECT_TRUE(
@@ -2157,6 +2218,20 @@
     }
 }
 
+TEST_P(GraphicsComposerAidlCommandTest, MultiThreadedPresent) {
+    std::vector<VtsDisplay*> displays;
+    for (auto& display : mDisplays) {
+        if (hasDisplayCapability(display.getDisplayId(),
+                                 DisplayCapability::MULTI_THREADED_PRESENT)) {
+            displays.push_back(&display);
+        }
+    }
+    if (displays.size() <= 1u) {
+        return;
+    }
+    // TODO(b/251842321): Try to present on multiple threads.
+}
+
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsComposerAidlCommandTest);
 INSTANTIATE_TEST_SUITE_P(
         PerInstance, GraphicsComposerAidlCommandTest,
diff --git a/graphics/mapper/2.0/default/OWNERS b/graphics/mapper/2.0/default/OWNERS
deleted file mode 100644
index c9f24d0..0000000
--- a/graphics/mapper/2.0/default/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Graphics team
-chrisforbes@google.com
-jreck@google.com
-lpy@google.com
diff --git a/graphics/mapper/2.0/utils/OWNERS b/graphics/mapper/2.0/utils/OWNERS
deleted file mode 100644
index c9f24d0..0000000
--- a/graphics/mapper/2.0/utils/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Graphics team
-chrisforbes@google.com
-jreck@google.com
-lpy@google.com
diff --git a/graphics/mapper/2.0/vts/OWNERS b/graphics/mapper/2.0/vts/OWNERS
deleted file mode 100644
index 62e3f2a..0000000
--- a/graphics/mapper/2.0/vts/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-# Bug component: 25423
-chrisforbes@google.com
-jreck@google.com
-lpy@google.com
-sumir@google.com
diff --git a/graphics/mapper/2.1/default/OWNERS b/graphics/mapper/2.1/default/OWNERS
deleted file mode 100644
index c9f24d0..0000000
--- a/graphics/mapper/2.1/default/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Graphics team
-chrisforbes@google.com
-jreck@google.com
-lpy@google.com
diff --git a/graphics/mapper/2.1/utils/OWNERS b/graphics/mapper/2.1/utils/OWNERS
deleted file mode 100644
index c9f24d0..0000000
--- a/graphics/mapper/2.1/utils/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Graphics team
-chrisforbes@google.com
-jreck@google.com
-lpy@google.com
diff --git a/graphics/mapper/2.1/vts/OWNERS b/graphics/mapper/2.1/vts/OWNERS
deleted file mode 100644
index 43c018a..0000000
--- a/graphics/mapper/2.1/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 25423
-include ../../2.0/vts/OWNERS
diff --git a/graphics/mapper/3.0/utils/OWNERS b/graphics/mapper/3.0/utils/OWNERS
deleted file mode 100644
index c9f24d0..0000000
--- a/graphics/mapper/3.0/utils/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Graphics team
-chrisforbes@google.com
-jreck@google.com
-lpy@google.com
diff --git a/graphics/mapper/3.0/vts/OWNERS b/graphics/mapper/3.0/vts/OWNERS
deleted file mode 100644
index 43c018a..0000000
--- a/graphics/mapper/3.0/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 25423
-include ../../2.0/vts/OWNERS
diff --git a/graphics/mapper/4.0/utils/OWNERS b/graphics/mapper/4.0/utils/OWNERS
deleted file mode 100644
index c9f24d0..0000000
--- a/graphics/mapper/4.0/utils/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Graphics team
-chrisforbes@google.com
-jreck@google.com
-lpy@google.com
diff --git a/graphics/mapper/4.0/utils/vts/Android.bp b/graphics/mapper/4.0/utils/vts/Android.bp
index 55e721e..51e871b 100644
--- a/graphics/mapper/4.0/utils/vts/Android.bp
+++ b/graphics/mapper/4.0/utils/vts/Android.bp
@@ -47,7 +47,7 @@
     ],
     export_static_lib_headers: [
         "android.hardware.graphics.allocator@4.0",
-        "android.hardware.graphics.common-V3-ndk",
+        "android.hardware.graphics.common-V4-ndk",
         "android.hardware.graphics.mapper@4.0",
     ],
     export_include_dirs: ["include"],
diff --git a/graphics/mapper/4.0/vts/OWNERS b/graphics/mapper/4.0/vts/OWNERS
deleted file mode 100644
index 43c018a..0000000
--- a/graphics/mapper/4.0/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 25423
-include ../../2.0/vts/OWNERS
diff --git a/graphics/mapper/stable-c/Android.bp b/graphics/mapper/stable-c/Android.bp
new file mode 100644
index 0000000..c03f67e
--- /dev/null
+++ b/graphics/mapper/stable-c/Android.bp
@@ -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 {
+    // 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_headers {
+    name: "libimapper_stablec",
+    export_include_dirs: ["include"],
+    vendor_available: true,
+    header_libs: [
+        "libarect_headers",
+    ],
+    export_header_lib_headers: [
+        "libarect_headers",
+    ],
+}
+
+cc_library_headers {
+    name: "libimapper_providerutils",
+    vendor_available: true,
+    export_include_dirs: ["implutils/include"],
+    header_libs: [
+        "libbase_headers",
+        "libimapper_stablec",
+    ],
+    export_header_lib_headers: [
+        "libbase_headers",
+        "libimapper_stablec",
+    ],
+}
+
+cc_test {
+    name: "libimapper_providerutils_tests",
+    defaults: [
+        "android.hardware.graphics.allocator-ndk_shared",
+        "android.hardware.graphics.common-ndk_shared",
+    ],
+    header_libs: [
+        "libimapper_providerutils",
+    ],
+    srcs: [
+        "implutils/impltests.cpp",
+    ],
+    visibility: [":__subpackages__"],
+    cpp_std: "experimental",
+}
+
+cc_test {
+    name: "VtsHalGraphicsMapperStableC_TargetTest",
+    cpp_std: "experimental",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+        "android.hardware.graphics.allocator-ndk_shared",
+        "android.hardware.graphics.common-ndk_shared",
+    ],
+    srcs: [
+        "vts/VtsHalGraphicsMapperStableC_TargetTest.cpp",
+    ],
+
+    shared_libs: [
+        "libbinder_ndk",
+        "libbase",
+        "libsync",
+        "libvndksupport",
+    ],
+    static_libs: [
+        "libaidlcommonsupport",
+        "libgralloctypes",
+        "libgtest",
+    ],
+    header_libs: [
+        "libimapper_stablec",
+        "libimapper_providerutils",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
diff --git a/graphics/mapper/stable-c/implutils/impltests.cpp b/graphics/mapper/stable-c/implutils/impltests.cpp
new file mode 100644
index 0000000..9c5d70b
--- /dev/null
+++ b/graphics/mapper/stable-c/implutils/impltests.cpp
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h>
+#include <android/hardware/graphics/mapper/utils/IMapperProvider.h>
+#include <vector>
+
+using namespace ::android::hardware::graphics::mapper;
+using namespace ::aidl::android::hardware::graphics::common;
+
+// 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;
+
+    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));
+}
+
+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;
+    PlaneLayout myPlaneLayout;
+    myPlaneLayout.offsetInBytes = 10;
+    myPlaneLayout.sampleIncrementInBits = 11;
+    myPlaneLayout.strideInBytes = 12;
+    myPlaneLayout.widthInSamples = 13;
+    myPlaneLayout.heightInSamples = 14;
+    myPlaneLayout.totalSizeInBytes = 15;
+    myPlaneLayout.horizontalSubsampling = 16;
+    myPlaneLayout.verticalSubsampling = 17;
+
+    myPlaneLayout.components.resize(3);
+    for (int i = 0; i < myPlaneLayout.components.size(); i++) {
+        auto& it = myPlaneLayout.components[i];
+        it.type = ExtendableType{"Plane ID", 40 + i};
+        it.offsetInBits = 20 + i;
+        it.sizeInBits = 30 + i;
+    }
+
+    std::vector<PlaneLayout> layouts{myPlaneLayout, PlaneLayout{}};
+
+    std::vector<char> buffer(5000, '\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);
+    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]);
+    EXPECT_FALSE(PlaneLayoutValue::decode(buffer.data(), 0).has_value());
+    auto read = PlaneLayoutValue::decode(buffer.data(), buffer.size());
+    ASSERT_TRUE(read.has_value());
+    EXPECT_EQ(layouts, *read);
+}
+
+TEST(Metadata, setGetRects) {
+    using RectsValue = StandardMetadata<StandardMetadataType::CROP>::value;
+    std::vector<uint8_t> buffer(500, 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));
+    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]);
+    auto read = RectsValue::decode(buffer.data(), buffer.size());
+    ASSERT_TRUE(read.has_value());
+    EXPECT_EQ(cropRects.size(), read->size());
+    EXPECT_EQ(cropRects, *read);
+}
+
+TEST(Metadata, setGetSmpte2086) {
+    using Smpte2086Value = StandardMetadata<StandardMetadataType::SMPTE2086>::value;
+    Smpte2086 source;
+    source.minLuminance = 12.335f;
+    source.maxLuminance = 452.889f;
+    source.whitePoint = XyColor{-6.f, -9.f};
+    source.primaryRed = XyColor{.1f, .2f};
+    source.primaryGreen = XyColor{.3f, .4f};
+    source.primaryBlue = XyColor{.5f, .6f};
+
+    constexpr int expectedSize = 10 * sizeof(float);
+    std::vector<uint8_t> buffer(500, 0);
+    EXPECT_EQ(expectedSize, Smpte2086Value::encode(source, buffer.data(), buffer.size()));
+    auto read = Smpte2086Value::decode(buffer.data(), buffer.size());
+    ASSERT_TRUE(read.has_value());
+    ASSERT_TRUE(read->has_value());
+    EXPECT_EQ(source, read->value());
+
+    // A valid encoding of a nullopt
+    read = Smpte2086Value::decode(nullptr, 0);
+    ASSERT_TRUE(read.has_value());
+    EXPECT_FALSE(read->has_value());
+}
+
+TEST(Metadata, setGetCta861_3) {
+    using Cta861_3Value = StandardMetadata<StandardMetadataType::CTA861_3>::value;
+    Cta861_3 source;
+    source.maxFrameAverageLightLevel = 244.55f;
+    source.maxContentLightLevel = 202.202f;
+
+    constexpr int expectedSize = 2 * sizeof(float);
+    std::vector<uint8_t> buffer(500, 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());
+    ASSERT_TRUE(read->has_value());
+    EXPECT_EQ(source, read->value());
+
+    // A valid encoding of a nullopt
+    read = Cta861_3Value::decode(nullptr, 0);
+    ASSERT_TRUE(read.has_value());
+    EXPECT_FALSE(read->has_value());
+}
+
+TEST(Metadata, setGetSmpte2094_10) {
+    using SMPTE2094_10Value = StandardMetadata<StandardMetadataType::SMPTE2094_10>::value;
+
+    std::vector<uint8_t> buffer(500, 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),
+              SMPTE2094_10Value::encode(emptyBuffer, buffer.data(), buffer.size()));
+    read = SMPTE2094_10Value::decode(buffer.data(), buffer.size());
+    ASSERT_TRUE(read.has_value());
+    ASSERT_TRUE(read->has_value());
+    EXPECT_EQ(0, read->value().size());
+
+    const std::vector<uint8_t> simpleBuffer{0, 1, 2, 3, 4, 5};
+    EXPECT_EQ(sizeof(int64_t) + 6,
+              SMPTE2094_10Value::encode(simpleBuffer, buffer.data(), buffer.size()));
+    read = SMPTE2094_10Value::decode(buffer.data(), buffer.size());
+    ASSERT_TRUE(read.has_value());
+    ASSERT_TRUE(read->has_value());
+    EXPECT_EQ(6, read->value().size());
+    EXPECT_EQ(simpleBuffer, read->value());
+}
+
+TEST(MetadataProvider, bufferId) {
+    using BufferId = StandardMetadata<StandardMetadataType::BUFFER_ID>::value;
+    std::vector<uint8_t> buffer(500, 0);
+    int result = provideStandardMetadata(StandardMetadataType::BUFFER_ID, buffer.data(),
+                                         buffer.size(), []<StandardMetadataType T>(auto&& provide) {
+                                             if constexpr (T == StandardMetadataType::BUFFER_ID) {
+                                                 return provide(42);
+                                             }
+                                             return 0;
+                                         });
+
+    EXPECT_EQ(8, result);
+    auto read = BufferId::decode(buffer.data(), buffer.size());
+    EXPECT_EQ(42, read.value_or(0));
+}
+
+TEST(MetadataProvider, allJumpsWork) {
+    const auto& values = ndk::internal::enum_values<StandardMetadataType>;
+    auto get = [](StandardMetadataType type) -> int {
+        return provideStandardMetadata(type, nullptr, 0, []<StandardMetadataType T>(auto&&) {
+            return static_cast<int>(T) + 100;
+        });
+    };
+
+    for (auto& type : values) {
+        const int expected = type == StandardMetadataType::INVALID ? -AIMAPPER_ERROR_UNSUPPORTED
+                                                                   : static_cast<int>(type) + 100;
+        EXPECT_EQ(expected, get(type));
+    }
+}
+
+TEST(MetadataProvider, invalid) {
+    int result = provideStandardMetadata(StandardMetadataType::INVALID, nullptr, 0,
+                                         []<StandardMetadataType T>(auto&&) { return 10; });
+
+    EXPECT_EQ(-AIMAPPER_ERROR_UNSUPPORTED, result);
+}
+
+TEST(MetadataProvider, outOfBounds) {
+    int result = provideStandardMetadata(static_cast<StandardMetadataType>(-1), nullptr, 0,
+                                         []<StandardMetadataType T>(auto&&) { return 10; });
+    EXPECT_EQ(-AIMAPPER_ERROR_UNSUPPORTED, result) << "-1 should have resulted in UNSUPPORTED";
+
+    result = provideStandardMetadata(static_cast<StandardMetadataType>(100), nullptr, 0,
+                                     []<StandardMetadataType T>(auto&&) { return 10; });
+    EXPECT_EQ(-AIMAPPER_ERROR_UNSUPPORTED, result)
+            << "100 (out of range) should have resulted in UNSUPPORTED";
+}
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
new file mode 100644
index 0000000..7861af8
--- /dev/null
+++ b/graphics/mapper/stable-c/implutils/include/android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h
@@ -0,0 +1,576 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/graphics/common/BlendMode.h>
+#include <aidl/android/hardware/graphics/common/BufferUsage.h>
+#include <aidl/android/hardware/graphics/common/Cta861_3.h>
+#include <aidl/android/hardware/graphics/common/Dataspace.h>
+#include <aidl/android/hardware/graphics/common/ExtendableType.h>
+#include <aidl/android/hardware/graphics/common/PixelFormat.h>
+#include <aidl/android/hardware/graphics/common/PlaneLayout.h>
+#include <aidl/android/hardware/graphics/common/PlaneLayoutComponent.h>
+#include <aidl/android/hardware/graphics/common/Rect.h>
+#include <aidl/android/hardware/graphics/common/Smpte2086.h>
+#include <aidl/android/hardware/graphics/common/StandardMetadataType.h>
+#include <aidl/android/hardware/graphics/common/XyColor.h>
+#include <android/hardware/graphics/mapper/IMapper.h>
+
+#include <cinttypes>
+#include <string_view>
+#include <type_traits>
+#include <vector>
+
+namespace android::hardware::graphics::mapper {
+
+using ::aidl::android::hardware::graphics::common::BlendMode;
+using ::aidl::android::hardware::graphics::common::BufferUsage;
+using ::aidl::android::hardware::graphics::common::Cta861_3;
+using ::aidl::android::hardware::graphics::common::Dataspace;
+using ::aidl::android::hardware::graphics::common::ExtendableType;
+using ::aidl::android::hardware::graphics::common::PixelFormat;
+using ::aidl::android::hardware::graphics::common::PlaneLayout;
+using ::aidl::android::hardware::graphics::common::PlaneLayoutComponent;
+using ::aidl::android::hardware::graphics::common::Rect;
+using ::aidl::android::hardware::graphics::common::Smpte2086;
+using ::aidl::android::hardware::graphics::common::StandardMetadataType;
+using ::aidl::android::hardware::graphics::common::XyColor;
+
+class MetadataWriter {
+  private:
+    uint8_t* _Nonnull mDest;
+    size_t mSizeRemaining = 0;
+    int32_t mDesiredSize = 0;
+
+    void* _Nullable reserve(size_t sizeToWrite) {
+        if (mDesiredSize < 0) {
+            // Error state
+            return nullptr;
+        }
+        if (__builtin_add_overflow(mDesiredSize, sizeToWrite, &mDesiredSize)) {
+            // Overflowed, abort writing any further data
+            mDesiredSize = -AIMAPPER_ERROR_BAD_VALUE;
+            mSizeRemaining = 0;
+            return nullptr;
+        }
+        if (sizeToWrite > mSizeRemaining) {
+            mSizeRemaining = 0;
+            return nullptr;
+        } else {
+            mSizeRemaining -= sizeToWrite;
+            uint8_t* whereToWrite = mDest;
+            mDest += sizeToWrite;
+            return whereToWrite;
+        }
+    }
+
+  public:
+    explicit MetadataWriter(void* _Nullable destBuffer, size_t destBufferSize)
+        : mDest(reinterpret_cast<uint8_t*>(destBuffer)), mSizeRemaining(destBufferSize) {}
+
+    int32_t desiredSize() const { return mDesiredSize; }
+
+    template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
+    MetadataWriter& write(T value) {
+        auto sizeToWrite = sizeof(T);
+        if (void* dest = reserve(sizeToWrite)) {
+            memcpy(dest, &value, sizeToWrite);
+        }
+        return *this;
+    }
+
+    MetadataWriter& write(float value) {
+        auto sizeToWrite = sizeof(float);
+        if (void* dest = reserve(sizeToWrite)) {
+            memcpy(dest, &value, sizeToWrite);
+        }
+        return *this;
+    }
+
+    MetadataWriter& write(const std::string_view& value) {
+        auto sizeToWrite = value.length();
+        write<int64_t>(sizeToWrite);
+        if (void* dest = reserve(sizeToWrite)) {
+            memcpy(dest, value.data(), sizeToWrite);
+        }
+        return *this;
+    }
+
+    MetadataWriter& write(const std::vector<uint8_t>& value) {
+        auto sizeToWrite = value.size();
+        write<int64_t>(sizeToWrite);
+        if (void* dest = reserve(sizeToWrite)) {
+            memcpy(dest, value.data(), sizeToWrite);
+        }
+        return *this;
+    }
+
+    MetadataWriter& write(const ExtendableType& value) {
+        return write(value.name).write(value.value);
+    }
+
+    MetadataWriter& write(const XyColor& value) { return write(value.x).write(value.y); }
+};
+
+class MetadataReader {
+  private:
+    const uint8_t* _Nonnull mSrc;
+    size_t mSizeRemaining = 0;
+    bool mOk = true;
+
+    const void* _Nullable advance(size_t size) {
+        if (mOk && mSizeRemaining >= size) {
+            const void* buf = mSrc;
+            mSrc += size;
+            mSizeRemaining -= size;
+            return buf;
+        }
+        mOk = false;
+        return nullptr;
+    }
+
+  public:
+    explicit MetadataReader(const void* _Nonnull metadata, size_t metadataSize)
+        : mSrc(reinterpret_cast<const uint8_t*>(metadata)), mSizeRemaining(metadataSize) {}
+
+    [[nodiscard]] size_t remaining() const { return mSizeRemaining; }
+    [[nodiscard]] bool ok() const { return mOk; }
+
+    template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
+    MetadataReader& read(T& dest) {
+        if (const void* src = advance(sizeof(T))) {
+            memcpy(&dest, src, sizeof(T));
+        }
+        return *this;
+    }
+
+    MetadataReader& read(float& dest) {
+        if (const void* src = advance(sizeof(float))) {
+            memcpy(&dest, src, sizeof(float));
+        }
+        return *this;
+    }
+
+    MetadataReader& read(std::string& dest) {
+        dest = readString();
+        return *this;
+    }
+
+    MetadataReader& read(ExtendableType& dest) {
+        dest.name = readString();
+        read(dest.value);
+        return *this;
+    }
+
+    MetadataReader& read(XyColor& dest) {
+        read(dest.x);
+        read(dest.y);
+        return *this;
+    }
+
+    template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
+    [[nodiscard]] std::optional<T> readInt() {
+        auto sizeToRead = sizeof(T);
+        if (const void* src = advance(sizeof(T))) {
+            T ret;
+            memcpy(&ret, src, sizeToRead);
+            return ret;
+        }
+        return std::nullopt;
+    }
+
+    [[nodiscard]] std::string_view readString() {
+        auto lengthOpt = readInt<int64_t>();
+        if (!lengthOpt) {
+            return std::string_view{};
+        }
+        size_t length = lengthOpt.value();
+        if (const void* src = advance(length)) {
+            return std::string_view{reinterpret_cast<const char*>(src), length};
+        }
+        return std::string_view{};
+    }
+
+    [[nodiscard]] std::optional<ExtendableType> readExtendable() {
+        ExtendableType ret;
+        ret.name = readString();
+        auto value = readInt<int64_t>();
+        if (value) {
+            ret.value = value.value();
+            return ret;
+        } else {
+            return std::nullopt;
+        }
+    }
+
+    [[nodiscard]] std::vector<uint8_t> readBuffer() {
+        std::vector<uint8_t> ret;
+        size_t length = readInt<int64_t>().value_or(0);
+        if (const void* src = advance(length)) {
+            ret.resize(length);
+            memcpy(ret.data(), src, length);
+        }
+        return ret;
+    }
+};
+
+template <typename T, class Enable = void>
+struct MetadataValue {};
+
+template <typename T>
+struct MetadataValue<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();
+    }
+
+    [[nodiscard]] static std::optional<T> decode(const void* _Nonnull metadata,
+                                                 size_t metadataSize) {
+        return MetadataReader{metadata, metadataSize}.readInt<T>();
+    }
+};
+
+template <typename T>
+struct MetadataValue<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}
+                .write(static_cast<std::underlying_type_t<T>>(value))
+                .desiredSize();
+    }
+
+    [[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()
+                       ? std::optional<T>(static_cast<T>(temp))
+                       : std::nullopt;
+    }
+};
+
+template <>
+struct MetadataValue<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();
+    }
+
+    [[nodiscard]] static std::optional<std::string> decode(const void* _Nonnull metadata,
+                                                           size_t metadataSize) {
+        auto reader = MetadataReader{metadata, metadataSize};
+        auto result = reader.readString();
+        return reader.ok() ? std::optional<std::string>{result} : std::nullopt;
+    }
+};
+
+template <>
+struct MetadataValue<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();
+    }
+
+    [[nodiscard]] static std::optional<ExtendableType> decode(const void* _Nonnull metadata,
+                                                              size_t metadataSize) {
+        return MetadataReader{metadata, metadataSize}.readExtendable();
+    }
+};
+
+template <>
+struct MetadataValue<std::vector<PlaneLayout>> {
+    [[nodiscard]] static int32_t encode(const std::vector<PlaneLayout>& values,
+                                        void* _Nullable destBuffer, size_t destBufferSize) {
+        MetadataWriter writer{destBuffer, destBufferSize};
+        writer.write<int64_t>(values.size());
+        for (const auto& value : values) {
+            writer.write<int64_t>(value.components.size());
+            for (const auto& component : value.components) {
+                writer.write(component.type)
+                        .write<int64_t>(component.offsetInBits)
+                        .write<int64_t>(component.sizeInBits);
+            }
+            writer.write<int64_t>(value.offsetInBytes)
+                    .write<int64_t>(value.sampleIncrementInBits)
+                    .write<int64_t>(value.strideInBytes)
+                    .write<int64_t>(value.widthInSamples)
+                    .write<int64_t>(value.heightInSamples)
+                    .write<int64_t>(value.totalSizeInBytes)
+                    .write<int64_t>(value.horizontalSubsampling)
+                    .write<int64_t>(value.verticalSubsampling);
+        }
+        return writer.desiredSize();
+    }
+
+    using DecodeResult = std::optional<std::vector<PlaneLayout>>;
+    [[nodiscard]] static DecodeResult decode(const void* _Nonnull metadata, size_t metadataSize) {
+        std::vector<PlaneLayout> values;
+        MetadataReader reader{metadata, metadataSize};
+        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++) {
+                PlaneLayoutComponent& component = value.components.emplace_back();
+                reader.read(component.type)
+                        .read<int64_t>(component.offsetInBits)
+                        .read<int64_t>(component.sizeInBits);
+            }
+            reader.read<int64_t>(value.offsetInBytes)
+                    .read<int64_t>(value.sampleIncrementInBits)
+                    .read<int64_t>(value.strideInBytes)
+                    .read<int64_t>(value.widthInSamples)
+                    .read<int64_t>(value.heightInSamples)
+                    .read<int64_t>(value.totalSizeInBytes)
+                    .read<int64_t>(value.horizontalSubsampling)
+                    .read<int64_t>(value.verticalSubsampling);
+        }
+        return reader.ok() ? DecodeResult{std::move(values)} : std::nullopt;
+    }
+};
+
+template <>
+struct MetadataValue<std::vector<Rect>> {
+    [[nodiscard]] static int32_t encode(const std::vector<Rect>& value, void* _Nullable destBuffer,
+                                        size_t destBufferSize) {
+        MetadataWriter writer{destBuffer, destBufferSize};
+        writer.write<int64_t>(value.size());
+        for (auto& rect : value) {
+            writer.write<int32_t>(rect.left)
+                    .write<int32_t>(rect.top)
+                    .write<int32_t>(rect.right)
+                    .write<int32_t>(rect.bottom);
+        }
+        return writer.desiredSize();
+    }
+
+    using DecodeResult = std::optional<std::vector<Rect>>;
+    [[nodiscard]] static DecodeResult decode(const void* _Nonnull metadata, size_t metadataSize) {
+        MetadataReader reader{metadata, metadataSize};
+        std::vector<Rect> value;
+        auto numRects = reader.readInt<int64_t>().value_or(0);
+        value.reserve(numRects);
+        for (int i = 0; i < numRects && reader.ok(); i++) {
+            Rect& rect = value.emplace_back();
+            reader.read<int32_t>(rect.left)
+                    .read<int32_t>(rect.top)
+                    .read<int32_t>(rect.right)
+                    .read<int32_t>(rect.bottom);
+        }
+        return reader.ok() ? DecodeResult{std::move(value)} : std::nullopt;
+    }
+};
+
+template <>
+struct MetadataValue<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}
+                    .write(value.primaryRed)
+                    .write(value.primaryGreen)
+                    .write(value.primaryBlue)
+                    .write(value.whitePoint)
+                    .write(value.maxLuminance)
+                    .write(value.minLuminance)
+                    .desiredSize();
+        } else {
+            return 0;
+        }
+    }
+
+    // Double optional because the value type itself is an optional<>
+    using DecodeResult = std::optional<std::optional<Smpte2086>>;
+    [[nodiscard]] static DecodeResult decode(const void* _Nullable metadata, size_t metadataSize) {
+        std::optional<Smpte2086> optValue{std::nullopt};
+        if (metadataSize > 0) {
+            Smpte2086 value;
+            MetadataReader reader{metadata, metadataSize};
+            reader.read(value.primaryRed)
+                    .read(value.primaryGreen)
+                    .read(value.primaryBlue)
+                    .read(value.whitePoint)
+                    .read(value.maxLuminance)
+                    .read(value.minLuminance);
+            if (reader.ok()) {
+                optValue = std::move(value);
+            } else {
+                return std::nullopt;
+            }
+        }
+        return DecodeResult{std::move(optValue)};
+    }
+};
+
+template <>
+struct MetadataValue<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}
+                    .write(value.maxContentLightLevel)
+                    .write(value.maxFrameAverageLightLevel)
+                    .desiredSize();
+        } else {
+            return 0;
+        }
+    }
+
+    // Double optional because the value type itself is an optional<>
+    using DecodeResult = std::optional<std::optional<Cta861_3>>;
+    [[nodiscard]] static DecodeResult decode(const void* _Nullable metadata, size_t metadataSize) {
+        std::optional<Cta861_3> optValue{std::nullopt};
+        if (metadataSize > 0) {
+            MetadataReader reader{metadata, metadataSize};
+            Cta861_3 value;
+            reader.read(value.maxContentLightLevel).read(value.maxFrameAverageLightLevel);
+            if (reader.ok()) {
+                optValue = std::move(value);
+            } else {
+                return std::nullopt;
+            }
+        }
+        return DecodeResult{std::move(optValue)};
+    }
+};
+
+template <>
+struct MetadataValue<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();
+    }
+
+    using DecodeResult = std::optional<std::optional<std::vector<uint8_t>>>;
+    [[nodiscard]] static DecodeResult decode(const void* _Nonnull metadata, size_t metadataSize) {
+        std::optional<std::vector<uint8_t>> optValue;
+        if (metadataSize > 0) {
+            MetadataReader reader{metadata, metadataSize};
+            auto value = reader.readBuffer();
+            if (reader.ok()) {
+                optValue = std::move(value);
+            } else {
+                return std::nullopt;
+            }
+        }
+        return DecodeResult{std::move(optValue)};
+    }
+};
+
+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_TYPE(BUFFER_ID, uint64_t);
+DEFINE_TYPE(NAME, std::string);
+DEFINE_TYPE(WIDTH, uint64_t);
+DEFINE_TYPE(HEIGHT, uint64_t);
+DEFINE_TYPE(LAYER_COUNT, uint64_t);
+DEFINE_TYPE(PIXEL_FORMAT_REQUESTED, PixelFormat);
+DEFINE_TYPE(PIXEL_FORMAT_FOURCC, uint32_t);
+DEFINE_TYPE(PIXEL_FORMAT_MODIFIER, uint64_t);
+DEFINE_TYPE(USAGE, BufferUsage);
+DEFINE_TYPE(ALLOCATION_SIZE, uint64_t);
+DEFINE_TYPE(PROTECTED_CONTENT, uint64_t);
+DEFINE_TYPE(COMPRESSION, ExtendableType);
+DEFINE_TYPE(INTERLACED, ExtendableType);
+DEFINE_TYPE(CHROMA_SITING, ExtendableType);
+DEFINE_TYPE(PLANE_LAYOUTS, std::vector<PlaneLayout>);
+DEFINE_TYPE(CROP, std::vector<Rect>);
+DEFINE_TYPE(DATASPACE, Dataspace);
+DEFINE_TYPE(BLEND_MODE, BlendMode);
+DEFINE_TYPE(SMPTE2086, std::optional<Smpte2086>);
+DEFINE_TYPE(CTA861_3, std::optional<Cta861_3>);
+DEFINE_TYPE(SMPTE2094_10, std::optional<std::vector<uint8_t>>);
+DEFINE_TYPE(SMPTE2094_40, std::optional<std::vector<uint8_t>>);
+
+#undef DEFINE_TYPE
+
+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
+    // function with the appropriate concrete type
+    using F_PTR = decltype(&f);
+    using THUNK = void (*)(F_PTR);
+    static constexpr auto jump = std::array<THUNK, sizeof...(I)>{[](F_PTR fp) {
+        constexpr StandardMetadataType type = ndk::internal::enum_values<StandardMetadataType>[I];
+        if constexpr (type != StandardMetadataType::INVALID) {
+            (*fp)(StandardMetadata<type>{});
+        }
+    }...};
+
+    auto index = static_cast<size_t>(type);
+    if (index >= 0 && index < jump.size()) {
+        jump[index](&f);
+    }
+}
+
+template <typename F, typename StandardMetadataSequence = std::make_index_sequence<
+                              ndk::internal::enum_values<StandardMetadataType>.size()>>
+int32_t provideStandardMetadata(StandardMetadataType type, void* _Nullable destBuffer,
+                                size_t destBufferSize, F&& f) {
+    int32_t retVal = -AIMAPPER_ERROR_UNSUPPORTED;
+    invokeWithStandardMetadata(
+            [&]<StandardMetadataType T>(StandardMetadata<T>) {
+                retVal = f.template operator()<T>(
+                        [&](const typename StandardMetadata<T>::value_type& value) -> int32_t {
+                            return StandardMetadata<T>::value::encode(value, destBuffer,
+                                                                      destBufferSize);
+                        });
+            },
+            type, StandardMetadataSequence{});
+    return retVal;
+}
+
+template <typename F, typename StandardMetadataSequence = std::make_index_sequence<
+                              ndk::internal::enum_values<StandardMetadataType>.size()>>
+AIMapper_Error applyStandardMetadata(StandardMetadataType type, const void* _Nonnull metadata,
+                                     size_t metadataSize, F&& f) {
+    AIMapper_Error retVal = AIMAPPER_ERROR_UNSUPPORTED;
+    invokeWithStandardMetadata(
+            [&]<StandardMetadataType T>(StandardMetadata<T>) {
+                auto value = StandardMetadata<T>::value::decode(metadata, metadataSize);
+                if (value.has_value()) {
+                    retVal = f.template operator()<T>(std::move(*value));
+                } else {
+                    retVal = AIMAPPER_ERROR_BAD_VALUE;
+                }
+            },
+            type, StandardMetadataSequence{});
+    return retVal;
+}
+
+}  // namespace android::hardware::graphics::mapper
\ No newline at end of file
diff --git a/graphics/mapper/stable-c/implutils/include/android/hardware/graphics/mapper/utils/IMapperProvider.h b/graphics/mapper/stable-c/implutils/include/android/hardware/graphics/mapper/utils/IMapperProvider.h
new file mode 100644
index 0000000..957fdc9
--- /dev/null
+++ b/graphics/mapper/stable-c/implutils/include/android/hardware/graphics/mapper/utils/IMapperProvider.h
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/unique_fd.h>
+#include <android/hardware/graphics/mapper/IMapper.h>
+#include <log/log.h>
+
+#include <mutex>
+#include <optional>
+#include <type_traits>
+
+/**
+ * Helper utilities for providing an IMapper-StableC implementation.
+ */
+
+namespace vendor::mapper {
+
+/**
+ * Extend from this interface to provide Version 5 of the IMapper interface
+ */
+struct IMapperV5Impl {
+    static const auto version = AIMAPPER_VERSION_5;
+    virtual ~IMapperV5Impl() = default;
+
+    virtual AIMapper_Error importBuffer(const native_handle_t* _Nonnull handle,
+                                        buffer_handle_t _Nullable* _Nonnull outBufferHandle) = 0;
+
+    virtual AIMapper_Error freeBuffer(buffer_handle_t _Nonnull buffer) = 0;
+
+    virtual AIMapper_Error getTransportSize(buffer_handle_t _Nonnull buffer,
+                                            uint32_t* _Nonnull outNumFds,
+                                            uint32_t* _Nonnull outNumInts) = 0;
+
+    virtual AIMapper_Error lock(buffer_handle_t _Nonnull buffer, uint64_t cpuUsage,
+                                ARect accessRegion, int acquireFence,
+                                void* _Nullable* _Nonnull outData) = 0;
+
+    virtual AIMapper_Error unlock(buffer_handle_t _Nonnull buffer, int* _Nonnull releaseFence) = 0;
+
+    virtual AIMapper_Error flushLockedBuffer(buffer_handle_t _Nonnull buffer) = 0;
+
+    virtual AIMapper_Error rereadLockedBuffer(buffer_handle_t _Nonnull buffer) = 0;
+
+    virtual int32_t getMetadata(buffer_handle_t _Nonnull buffer, AIMapper_MetadataType metadataType,
+                                void* _Nullable destBuffer, size_t destBufferSize) = 0;
+
+    virtual int32_t getStandardMetadata(buffer_handle_t _Nonnull buffer,
+                                        int64_t standardMetadataType, void* _Nullable destBuffer,
+                                        size_t destBufferSize) = 0;
+
+    virtual AIMapper_Error setMetadata(buffer_handle_t _Nonnull buffer,
+                                       AIMapper_MetadataType metadataType,
+                                       const void* _Nonnull metadata, size_t metadataSize) = 0;
+
+    virtual AIMapper_Error setStandardMetadata(buffer_handle_t _Nonnull buffer,
+                                               int64_t standardMetadataType,
+                                               const void* _Nonnull metadata,
+                                               size_t metadataSize) = 0;
+
+    virtual AIMapper_Error listSupportedMetadataTypes(
+            const AIMapper_MetadataTypeDescription* _Nullable* _Nonnull outDescriptionList,
+            size_t* _Nonnull outNumberOfDescriptions) = 0;
+
+    virtual AIMapper_Error dumpBuffer(buffer_handle_t _Nonnull bufferHandle,
+                                      AIMapper_DumpBufferCallback _Nonnull dumpBufferCallback,
+                                      void* _Null_unspecified context) = 0;
+
+    virtual AIMapper_Error dumpAllBuffers(
+            AIMapper_BeginDumpBufferCallback _Nonnull beginDumpBufferCallback,
+            AIMapper_DumpBufferCallback _Nonnull dumpBufferCallback,
+            void* _Null_unspecified context) = 0;
+
+    virtual AIMapper_Error getReservedRegion(buffer_handle_t _Nonnull buffer,
+                                             void* _Nullable* _Nonnull outReservedRegion,
+                                             uint64_t* _Nonnull outReservedSize) = 0;
+};
+
+namespace provider {
+#ifndef __cpp_inline_variables
+#error "Only C++17 & newer is supported; inline variables is missing"
+#endif
+
+inline void* _Nullable sIMapperInstance = nullptr;
+}  // namespace provider
+
+template <typename IMPL>
+class IMapperProvider {
+  private:
+    static_assert(IMPL::version >= AIMAPPER_VERSION_5, "Must be at least AIMAPPER_VERSION_5");
+    static_assert(std::is_final_v<IMPL>, "Implementation must be final");
+    static_assert(std::is_constructible_v<IMPL>, "Implementation must have a no-args constructor");
+
+    std::once_flag mLoadOnceFlag;
+    std::optional<IMPL> mImpl;
+    AIMapper mMapper = {};
+
+    static IMPL& impl() {
+        return *reinterpret_cast<IMapperProvider<IMPL>*>(provider::sIMapperInstance)->mImpl;
+    }
+
+    void bindV5() {
+        mMapper.v5 = {
+                .importBuffer = [](const native_handle_t* _Nonnull handle,
+                                   buffer_handle_t _Nullable* _Nonnull outBufferHandle)
+                        -> AIMapper_Error { return impl().importBuffer(handle, outBufferHandle); },
+
+                .freeBuffer = [](buffer_handle_t _Nonnull buffer) -> AIMapper_Error {
+                    return impl().freeBuffer(buffer);
+                },
+
+                .getTransportSize = [](buffer_handle_t _Nonnull buffer,
+                                       uint32_t* _Nonnull outNumFds,
+                                       uint32_t* _Nonnull outNumInts) -> AIMapper_Error {
+                    return impl().getTransportSize(buffer, outNumFds, outNumInts);
+                },
+
+                .lock = [](buffer_handle_t _Nonnull buffer, uint64_t cpuUsage, ARect accessRegion,
+                           int acquireFence, void* _Nullable* _Nonnull outData) -> AIMapper_Error {
+                    return impl().lock(buffer, cpuUsage, accessRegion, acquireFence, outData);
+                },
+
+                .unlock = [](buffer_handle_t _Nonnull buffer, int* _Nonnull releaseFence)
+                        -> AIMapper_Error { return impl().unlock(buffer, releaseFence); },
+
+                .flushLockedBuffer = [](buffer_handle_t _Nonnull buffer) -> AIMapper_Error {
+                    return impl().flushLockedBuffer(buffer);
+                },
+
+                .rereadLockedBuffer = [](buffer_handle_t _Nonnull buffer) -> AIMapper_Error {
+                    return impl().rereadLockedBuffer(buffer);
+                },
+
+                .getMetadata = [](buffer_handle_t _Nonnull buffer,
+                                  AIMapper_MetadataType metadataType, void* _Nullable destBuffer,
+                                  size_t destBufferSize) -> int32_t {
+                    return impl().getMetadata(buffer, metadataType, destBuffer, destBufferSize);
+                },
+
+                .getStandardMetadata = [](buffer_handle_t _Nonnull buffer,
+                                          int64_t standardMetadataType, void* _Nullable destBuffer,
+                                          size_t destBufferSize) -> int32_t {
+                    return impl().getStandardMetadata(buffer, standardMetadataType, destBuffer,
+                                                      destBufferSize);
+                },
+
+                .setMetadata = [](buffer_handle_t _Nonnull buffer,
+                                  AIMapper_MetadataType metadataType, const void* _Nonnull metadata,
+                                  size_t metadataSize) -> AIMapper_Error {
+                    return impl().setMetadata(buffer, metadataType, metadata, metadataSize);
+                },
+
+                .setStandardMetadata =
+                        [](buffer_handle_t _Nonnull buffer, int64_t standardMetadataType,
+                           const void* _Nonnull metadata, size_t metadataSize) -> AIMapper_Error {
+                    return impl().setStandardMetadata(buffer, standardMetadataType, metadata,
+                                                      metadataSize);
+                },
+
+                .listSupportedMetadataTypes =
+                        [](const AIMapper_MetadataTypeDescription* _Nullable* _Nonnull outDescriptionList,
+                           size_t* _Nonnull outNumberOfDescriptions) -> AIMapper_Error {
+                    return impl().listSupportedMetadataTypes(outDescriptionList,
+                                                             outNumberOfDescriptions);
+                },
+
+                .dumpBuffer = [](buffer_handle_t _Nonnull bufferHandle,
+                                 AIMapper_DumpBufferCallback _Nonnull dumpBufferCallback,
+                                 void* _Null_unspecified context) -> AIMapper_Error {
+                    return impl().dumpBuffer(bufferHandle, dumpBufferCallback, context);
+                },
+
+                .dumpAllBuffers =
+                        [](AIMapper_BeginDumpBufferCallback _Nonnull beginDumpBufferCallback,
+                           AIMapper_DumpBufferCallback _Nonnull dumpBufferCallback,
+                           void* _Null_unspecified context) {
+                            return impl().dumpAllBuffers(beginDumpBufferCallback,
+                                                         dumpBufferCallback, context);
+                        },
+
+                .getReservedRegion = [](buffer_handle_t _Nonnull buffer,
+                                        void* _Nullable* _Nonnull outReservedRegion,
+                                        uint64_t* _Nonnull outReservedSize) -> AIMapper_Error {
+                    return impl().getReservedRegion(buffer, outReservedRegion, outReservedSize);
+                },
+        };
+    }
+
+  public:
+    explicit IMapperProvider() = default;
+
+    AIMapper_Error load(AIMapper* _Nullable* _Nonnull outImplementation) {
+        std::call_once(mLoadOnceFlag, [this] {
+            LOG_ALWAYS_FATAL_IF(provider::sIMapperInstance != nullptr,
+                                "AIMapper implementation already loaded!");
+            provider::sIMapperInstance = this;
+            mImpl.emplace();
+            mMapper.version = IMPL::version;
+            if (IMPL::version >= AIMAPPER_VERSION_5) {
+                bindV5();
+            }
+        });
+        *outImplementation = &mMapper;
+        return AIMAPPER_ERROR_NONE;
+    }
+};
+
+}  // namespace vendor::mapper
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
new file mode 100644
index 0000000..0f6d146
--- /dev/null
+++ b/graphics/mapper/stable-c/include/android/hardware/graphics/mapper/IMapper.h
@@ -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.
+ */
+
+/**
+ *  IMapper Stable-C HAL interface
+ *
+ *  This file represents the sphal interface between libui & the IMapper HAL implementation.
+ *  A vendor implementation of this interface is retrieved by looking up the vendor imapper
+ *  implementation library via the IAllocator AIDL interface.
+ *
+ *  This interface is not intended for general use.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+#include <cinttypes>
+#include <cstddef>
+#include <type_traits>
+
+#include <android/rect.h>
+#include <cutils/native_handle.h>
+
+__BEGIN_DECLS
+
+/**
+ * AIMapper versioning
+ *
+ * IMapper versions 0-1 are pre-treble
+ * IMapper versions 2-4 are HIDL
+ * C-style AIMapper API starts at 5
+ */
+enum AIMapper_Version : uint32_t {
+    AIMAPPER_VERSION_5 = 5,
+};
+
+/**
+ * Possible AIMapper errors
+ * Values are the same as IMapper 4.0's Error type for simplicity
+ */
+enum AIMapper_Error : int32_t {
+    /**
+     * No error.
+     */
+    AIMAPPER_ERROR_NONE = 0,
+    /**
+     * Invalid BufferDescriptor.
+     */
+    AIMAPPER_ERROR_BAD_DESCRIPTOR = 1,
+    /**
+     * Invalid buffer handle.
+     */
+    AIMAPPER_ERROR_BAD_BUFFER = 2,
+    /**
+     * Invalid HardwareBufferDescription.
+     */
+    AIMAPPER_ERROR_BAD_VALUE = 3,
+    /**
+     * Resource unavailable.
+     */
+    AIMAPPER_ERROR_NO_RESOURCES = 5,
+    /**
+     * Permanent failure.
+     */
+    AIMAPPER_ERROR_UNSUPPORTED = 7,
+};
+
+/**
+ * MetadataType represents the different types of buffer metadata that could be
+ * associated with a buffer. It is used by IMapper to help get and set buffer metadata
+ * on the buffer's native handle.
+ *
+ * Standard buffer metadata will have the name field set to
+ * "android.hardware.graphics.common.StandardMetadataType" and will contain values
+ * from StandardMetadataType.aidl.
+ *
+ * Vendor-provided metadata should be prefixed with a "vendor.mycompanyname.*" namespace. It is
+ * recommended that the metadata follows the pattern of StandardMetadaType.aidl. That is, an
+ * aidl-defined enum with @VendorStability on it and the naming then matching that type such
+ * as "vendor.mycompanyname.graphics.common.MetadataType" with the value field then set to the
+ * aidl's enum value.
+ *
+ * Each company should create their own enum & namespace. The name
+ * field prevents values from different companies from colliding.
+ */
+typedef struct AIMapper_MetadataType {
+    const char* _Nonnull name;
+    int64_t value;
+} AIMapper_MetadataType;
+
+typedef struct AIMapper_MetadataTypeDescription {
+    /**
+     * The `name` of the metadataType must be valid for the lifetime of the process
+     */
+    AIMapper_MetadataType metadataType;
+    /**
+     * description should contain a string representation of the MetadataType.
+     *
+     * For example: "MyExampleMetadataType is a 64-bit timestamp in nanoseconds
+     * that indicates when a buffer is decoded. It is set by the media HAL after
+     * a buffer is decoded. It is used by the display HAL for hardware
+     * synchronization".
+     *
+     * This field is required for any non-StandardMetadataTypes. For StandardMetadataTypes this
+     * field may be null. The lifetime of this pointer must be valid for the duration of the
+     * process (that is, a static const char*).
+     */
+    const char* _Nullable description;
+    /**
+     * isGettable represents if the MetadataType can be get.
+     */
+    bool isGettable;
+    /**
+     * isSettable represents if the MetadataType can be set.
+     */
+    bool isSettable;
+
+    /** Reserved for future use; must be zero-initialized currently */
+    uint8_t reserved[32];
+} AIMapper_MetadataTypeDescription;
+
+/**
+ * Callback that is passed to dumpBuffer.
+ *
+ * @param context The caller-provided void* that was passed to dumpBuffer.
+ * @param metadataType The type of the metadata passed to the callback
+ * @param value A pointer to the value of the metadata. The lifetime of this pointer is only
+ *              valid for the duration of the call
+ * @param valueSize The size of the value buffer.
+ */
+typedef void (*AIMapper_DumpBufferCallback)(void* _Null_unspecified context,
+                                            AIMapper_MetadataType metadataType,
+                                            const void* _Nonnull value, size_t valueSize);
+
+/**
+ * Callback that is passed to dumpAllBuffers.
+ *
+ * Indicates that a buffer is about to be dumped. Will be followed by N calls to
+ * AIMapper_DumpBufferCallback for all the metadata for this buffer.
+ *
+ * @param context The caller-provided void* that was passed to dumpAllBuffers.
+ */
+typedef void (*AIMapper_BeginDumpBufferCallback)(void* _Null_unspecified context);
+
+/**
+ * Implementation of AIMAPPER_VERSION_5
+ * All functions must not be null & must provide a valid implementation.
+ */
+typedef struct AIMapperV5 {
+    /**
+     * Imports a raw buffer handle to create an imported buffer handle for use
+     * with the rest of the mapper or with other in-process libraries.
+     *
+     * A buffer handle is considered raw when it is cloned (e.g., with
+     * `native_handle_clone()`) from another buffer handle locally, or when it
+     * is received from another HAL server/client or another process. A raw
+     * buffer handle must not be used to access the underlying graphic
+     * buffer. It must be imported to create an imported handle first.
+     *
+     * This function must at least validate the raw handle before creating the
+     * imported handle. It must also support importing the same raw handle
+     * multiple times to create multiple imported handles. The imported handle
+     * must be considered valid everywhere in the process, including in
+     * another instance of the mapper.
+     *
+     * Because of passthrough HALs, a raw buffer handle received from a HAL
+     * may actually have been imported in the process. importBuffer() must treat
+     * such a handle as if it is raw and must not return `BAD_BUFFER`. The
+     * returned handle is independent from the input handle as usual, and
+     * freeBuffer() must be called on it when it is no longer needed.
+     *
+     * @param handle Raw buffer handle to import.
+     * @param outBufferHandle The resulting imported buffer handle.
+     * @return Error status of the call, which may be
+     *     - `NONE` upon success.
+     *     - `BAD_BUFFER` if the raw handle is invalid.
+     *     - `NO_RESOURCES` if the raw handle cannot be imported due to
+     *       unavailability of resources.
+     */
+    AIMapper_Error (*_Nonnull importBuffer)(const native_handle_t* _Nonnull handle,
+                                            buffer_handle_t _Nullable* _Nonnull outBufferHandle);
+
+    /**
+     * Frees a buffer handle. Buffer handles returned by importBuffer() must be
+     * freed with this function when no longer needed.
+     *
+     * This function must free up all resources allocated by importBuffer() for
+     * the imported handle. For example, if the imported handle was created
+     * with `native_handle_create()`, this function must call
+     * `native_handle_close()` and `native_handle_delete()`.
+     *
+     * @param buffer Imported buffer handle.
+     * @return error Error status of the call, which may be
+     *     - `NONE` upon success.
+     *     - `BAD_BUFFER` if the buffer is invalid.
+     */
+    AIMapper_Error (*_Nonnull freeBuffer)(buffer_handle_t _Nonnull buffer);
+
+    /**
+     * Calculates the transport size of a buffer. An imported buffer handle is a
+     * raw buffer handle with the process-local runtime data appended. This
+     * function, for example, allows a caller to omit the process-local runtime
+     * data at the tail when serializing the imported buffer handle.
+     *
+     * Note that a client might or might not omit the process-local runtime data
+     * when sending an imported buffer handle. The mapper must support both
+     * cases on the receiving end.
+     *
+     * @param buffer Buffer to get the transport size from.
+     * @param outNumFds The number of file descriptors needed for transport.
+     * @param outNumInts The number of integers needed for transport.
+     * @return error Error status of the call, which may be
+     *     - `NONE` upon success.
+     *     - `BAD_BUFFER` if the buffer is invalid.
+     */
+    AIMapper_Error (*_Nonnull getTransportSize)(buffer_handle_t _Nonnull buffer,
+                                                uint32_t* _Nonnull outNumFds,
+                                                uint32_t* _Nonnull outNumInts);
+
+    /**
+     * Locks the given buffer for the specified CPU usage.
+     *
+     * Locking the same buffer simultaneously from multiple threads is
+     * permitted, but if any of the threads attempt to lock the buffer for
+     * writing, the behavior is undefined, except that it must not cause
+     * process termination or block the client indefinitely. Leaving the
+     * buffer content in an indeterminate state or returning an error are both
+     * acceptable.
+     *
+     * 1D buffers (width = size in bytes, height = 1, pixel_format = BLOB) must
+     * "lock in place". The buffers must be directly accessible via mapping.
+     *
+     * The client must not modify the content of the buffer outside of
+     * @p accessRegion, and the device need not guarantee that content outside
+     * of @p accessRegion is valid for reading. The result of reading or writing
+     * outside of @p accessRegion is undefined, except that it must not cause
+     * process termination.
+     *
+     * An accessRegion of all-zeros means the entire buffer. That is, it is
+     * equivalent to '(0,0)-(buffer width, buffer height)'.
+     *
+     * This function can lock both single-planar and multi-planar formats. The caller
+     * should use get() to get information about the buffer they are locking.
+     * get() can be used to get information about the planes, offsets, stride,
+     * etc.
+     *
+     * This function must also work on buffers with
+     * `AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_*` if supported by the device, as well
+     * as with any other formats requested by multimedia codecs when they are
+     * configured with a flexible-YUV-compatible color format.
+     *
+     * On success, @p data must be filled with a pointer to the locked buffer
+     * memory. This address will represent the top-left corner of the entire
+     * buffer, even if @p accessRegion does not begin at the top-left corner.
+     *
+     * The locked buffer must adhere to the format requested at allocation time
+     * in the BufferDescriptorInfo.
+     *
+     * @param buffer Buffer to lock.
+     * @param cpuUsage CPU usage flags to request. See BufferUsage.aidl for possible values.
+     * @param accessRegion Portion of the buffer that the client intends to
+     *     access.
+     * @param acquireFence Handle containing a file descriptor referring to a
+     *     sync fence object, which will be signaled when it is safe for the
+     *     mapper to lock the buffer. @p acquireFence may be an empty fence (-1) if
+     *     it is already safe to lock. Ownership is passed to the callee and it is the
+     *     implementations responsibility to ensure it is closed even when an error
+     *     occurs.
+     * @param outData CPU-accessible pointer to the buffer data.
+     * @return error Error status of the call, which may be
+     *     - `NONE` upon success.
+     *     - `BAD_BUFFER` if the buffer is invalid or is incompatible with this
+     *       function.
+     *     - `BAD_VALUE` if @p cpuUsage is 0, contains non-CPU usage flags, or
+     *       is incompatible with the buffer. Also if the @p accessRegion is
+     *       outside the bounds of the buffer or the accessRegion is invalid.
+     *     - `NO_RESOURCES` if the buffer cannot be locked at this time. Note
+     *       that locking may succeed at a later time.
+     * @return data CPU-accessible pointer to the buffer data.
+     */
+    AIMapper_Error (*_Nonnull lock)(buffer_handle_t _Nonnull buffer, uint64_t cpuUsage,
+                                    ARect accessRegion, int acquireFence,
+                                    void* _Nullable* _Nonnull outData);
+
+    /**
+     * Unlocks a buffer to indicate all CPU accesses to the buffer have
+     * completed.
+     *
+     * @param buffer Buffer to unlock.
+     * @param releaseFence Handle containing a file descriptor referring to a
+     *     sync fence object. The sync fence object will be signaled when the
+     *     mapper has completed any pending work. @p releaseFence may be an
+     *     empty fence (-1).
+     * @return error Error status of the call, which may be
+     *     - `NONE` upon success.
+     *     - `BAD_BUFFER` if the buffer is invalid or not locked.
+     */
+    AIMapper_Error (*_Nonnull unlock)(buffer_handle_t _Nonnull buffer, int* _Nonnull releaseFence);
+
+    /**
+     * Flushes the contents of a locked buffer.
+     *
+     * This function flushes the CPUs caches for the range of all the buffer's
+     * planes and metadata. This should behave similarly to unlock() except the
+     * buffer should remain mapped to the CPU.
+     *
+     * The client is still responsible for calling unlock() when it is done
+     * with all CPU accesses to the buffer.
+     *
+     * If non-CPU blocks are simultaneously writing the buffer, the locked
+     * copy should still be flushed but what happens is undefined except that
+     * it should not cause any crashes.
+     *
+     * @param buffer Buffer to flush.
+     * @return error Error status of the call, which may be
+     *     - `NONE` upon success.
+     *     - `BAD_BUFFER` if the buffer is invalid or not locked.
+     */
+    AIMapper_Error (*_Nonnull flushLockedBuffer)(buffer_handle_t _Nonnull buffer);
+
+    /**
+     * Rereads the contents of a locked buffer.
+     *
+     * This should fetch the most recent copy of the locked buffer.
+     *
+     * It may reread locked copies of the buffer in other processes.
+     *
+     * The client is still responsible for calling unlock() when it is done
+     * with all CPU accesses to the buffer.
+     *
+     * @param buffer Buffer to reread.
+     * @return error Error status of the call, which may be
+     *     - `NONE` upon success.
+     *     - `BAD_BUFFER` if the buffer is invalid or not locked.
+     *     - `NO_RESOURCES` if the buffer cannot be reread at this time. Note
+     *       that rereading may succeed at a later time.
+     */
+    AIMapper_Error (*_Nonnull rereadLockedBuffer)(buffer_handle_t _Nonnull buffer);
+
+    /**
+     * Description for get(...), set(...) and getFromBufferDescriptorInfo(...)
+     *
+     * ------------ Overview -----------------------------------
+     * Gralloc 4 adds support for getting and setting buffer metadata on a buffer.
+     *
+     * To get buffer metadata, the client passes in a buffer handle and a token that
+     * represents the type of buffer metadata they would like to get. IMapper returns
+     * a byte stream that contains the buffer metadata. To set the buffer metadata, the
+     * client passes in a buffer handle and a token that represents the type of buffer
+     * metadata they would like to set and a byte stream that contains the buffer metadata
+     * they are setting.
+     *
+     * Buffer metadata is global for a buffer. When the metadata is set on the buffer
+     * in a process, the updated metadata should be available to all other processes.
+     * Please see "Storing and Propagating Metadata" below for more details.
+     *
+     * The getter and setter functions have been optimized for easy vendor extension.
+     * They do not require a formal extension to add support for getting and setting
+     * vendor defined buffer metadata. See "Buffer Metadata Token" and
+     * "Buffer Metadata Stream" below for more details.
+     *
+     * ------------ Storing and Propagating Metadata -----------
+     * Buffer metadata must be global. Any changes to the metadata must be propagated
+     * to all other processes immediately. Vendors may chose how they would like support
+     * this functionality.
+     *
+     * We recommend supporting this functionality by allocating an extra page of shared
+     * memory and storing it in the buffer's native_handle_t. The buffer metadata can
+     * be stored in the extra page of shared memory. Set operations are automatically
+     * propagated to all other processes.
+     *
+     * ------------ Buffer Metadata Synchronization ------------
+     * There are no explicit buffer metadata synchronization primitives. Many devices
+     * before gralloc 4 already support getting and setting of global buffer metadata
+     * with no explicit synchronization primitives. Adding synchronization primitives
+     * would just add unnecessary complexity.
+     *
+     * The general rule is if a process has permission to write to a buffer, they
+     * have permission to write to the buffer's writable metadata. If a process has permission
+     * to read from a buffer, they have permission to read the buffer's metadata.
+     *
+     * There is one exception to this rule. Fences CANNOT be used to protect a buffer's
+     * metadata. A process should finish writing to a buffer's metadata before
+     * sending the buffer to another process that will read or write to the buffer.
+     * This exception is needed because sometimes userspace needs to read the
+     * buffer's metadata before the buffer's contents are ready.
+     *
+     * As a simple example: an app renders to a buffer and then displays the buffer.
+     * In this example when the app renders to the buffer, both the buffer and its
+     * metadata need to be updated. The app's process queues up its work on the GPU
+     * and gets back an acquire fence. The app's process must update the buffer's
+     * metadata before enqueuing the buffer to SurfaceFlinger. The app process CANNOT
+     * update the buffer's metadata after enqueuing the buffer. When HardwareComposer
+     * receives the buffer, it is immediately safe to read the buffer's metadata
+     * and use it to program the display driver. To read the buffer's contents,
+     * display driver must still wait on the acquire fence.
+     *
+     * ------------ Buffer Metadata Token ----------------------
+     * In order to allow arbitrary vendor defined metadata, the token used to access
+     * metadata is defined defined as a struct that has a string representing
+     * the enum type and an int that represents the enum value. The string protects
+     * different enum values from colliding.
+     *
+     * The token struct (MetadataType) is defined as a C struct since it
+     * is passed into a C function. The standard buffer metadata types are NOT
+     * defined as a C enum but instead as an AIDL enum to allow for broader usage across
+     * other HALs and libraries. By putting the enum in the
+     * stable AIDL (hardware/interfaces/graphics/common/aidl/android/hardware/
+     * graphics/common/StandardMetadataType.aidl), vendors will be able to optionally
+     * choose to support future standard buffer metadata types without upgrading
+     * IMapper versions. For more information see the description of "struct MetadataType".
+     *
+     * ------------ Buffer Metadata Stream ---------------------
+     * The buffer metadata is get and set as a void* buffer. By getting
+     * and setting buffer metadata as a generic buffer, vendors can use the standard
+     * getters and setter functions defined here. Vendors do NOT need to add their own
+     * getters and setter functions for each new type of buffer metadata.
+     *
+     * Converting buffer metadata into a byte stream can be non-trivial. For the standard
+     * buffer metadata types defined in StandardMetadataType.aidl, there are also
+     * support functions that will encode the buffer metadata into a byte stream
+     * and decode the buffer metadata from a byte stream. We STRONGLY recommend using
+     * these support functions. The framework will use them when getting and setting
+     * metadata. The support functions are defined in
+     * frameworks/native/libs/gralloc/types/include/gralloctypes/Gralloc4.h.
+     */
+
+    /**
+     * Gets the buffer metadata for a given MetadataType.
+     *
+     * Buffer metadata can be changed after allocation so clients should avoid "caching"
+     * the buffer metadata. For example, if the video resolution changes and the buffers
+     * are not reallocated, several buffer metadata values may change without warning.
+     * Clients should not expect the values to be constant. They should requery them every
+     * frame. The only exception is buffer metadata that is determined at allocation
+     * time. For StandardMetadataType values, only BUFFER_ID, NAME, WIDTH,
+     * HEIGHT, LAYER_COUNT, PIXEL_FORMAT_REQUESTED and USAGE are safe to cache because
+     * they are determined at allocation time.
+     *
+     * @param buffer Buffer containing desired metadata
+     * @param metadataType MetadataType for the metadata value being queried
+     * @param destBuffer Pointer to a buffer in which to store the result of the get() call; if
+     * null, the computed output size or error must still be returned.
+     * @param destBufferSize How large the destBuffer buffer is. If destBuffer is null this must be
+     * 0.
+     * @return The number of bytes written to `destBuffer` or which would have been written
+     *         if `destBufferSize` was large enough.
+     *         A negative value indicates an error, which may be
+     *         - `BAD_BUFFER` if the raw handle is invalid.
+     *         - `UNSUPPORTED` when metadataType is unknown/unsupported.
+     *            IMapper must support getting all StandardMetadataType.aidl values defined
+     *            at the time the device first launches.
+     */
+    int32_t (*_Nonnull getMetadata)(buffer_handle_t _Nonnull buffer,
+                                    AIMapper_MetadataType metadataType, void* _Nullable destBuffer,
+                                    size_t destBufferSize);
+
+    /**
+     * Gets the buffer metadata for a StandardMetadataType.
+     *
+     * This is equivalent to `getMetadata` when passed an AIMapper_MetadataType with name
+     * set to "android.hardware.graphics.common.StandardMetadataType"
+     *
+     * Buffer metadata can be changed after allocation so clients should avoid "caching"
+     * the buffer metadata. For example, if the video resolution changes and the buffers
+     * are not reallocated, several buffer metadata values may change without warning.
+     * Clients should not expect the values to be constant. They should requery them every
+     * frame. The only exception is buffer metadata that is determined at allocation
+     * time. For StandardMetadataType values, only BUFFER_ID, NAME, WIDTH,
+     * HEIGHT, LAYER_COUNT, PIXEL_FORMAT_REQUESTED and USAGE are safe to cache because
+     * they are determined at allocation time.
+     *
+     * @param buffer Buffer containing desired metadata
+     * @param standardMetadataType StandardMetadataType for the metadata value being queried
+     * @param destBuffer Pointer to a buffer in which to store the result of the get() call; if
+     * null, the computed output size or error must still be returned.
+     * @param destBufferSize How large the destBuffer buffer is. If destBuffer is null this must be
+     * 0.
+     * @return The number of bytes written to `destBuffer` or which would have been written
+     *         if `destBufferSize` was large enough.
+     *         A negative value indicates an error, which may be
+     *         - `BAD_BUFFER` if the raw handle is invalid.
+     *         - `UNSUPPORTED` when metadataType is unknown/unsupported.
+     *            IMapper must support getting all StandardMetadataType.aidl values defined
+     *            at the time the device first launches.
+     */
+    int32_t (*_Nonnull getStandardMetadata)(buffer_handle_t _Nonnull buffer,
+                                            int64_t standardMetadataType,
+                                            void* _Nullable destBuffer, size_t destBufferSize);
+
+    /**
+     * Sets the global value for a given MetadataType.
+     *
+     * Metadata fields are not required to be settable. This function can
+     * return Error::UNSUPPORTED whenever it doesn't support setting a
+     * particular Metadata field.
+     *
+     * The framework will attempt to set the following StandardMetadataType
+     * 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
+     * @param metadata Pointer to a buffer of bytes representing the value associated with
+     * @param metadataSize The size of the metadata buffer
+     * @return error Error status of the call, which may be
+     *     - `NONE` upon success.
+     *     - `BAD_BUFFER` if the raw handle is invalid.
+     *     - `BAD_VALUE` when the field is constant and can never be set (such as
+     *       BUFFER_ID, NAME, WIDTH, HEIGHT, LAYER_COUNT, PIXEL_FORMAT_REQUESTED and
+     *       USAGE)
+     *     - `NO_RESOURCES` if the set cannot be fulfilled due to unavailability of
+     *        resources.
+     *     - `UNSUPPORTED` when metadataType is unknown/unsupported or setting
+     *       it is unsupported. Unsupported should also be returned if the metadata
+     *       is malformed.
+     */
+    AIMapper_Error (*_Nonnull setMetadata)(buffer_handle_t _Nonnull buffer,
+                                           AIMapper_MetadataType metadataType,
+                                           const void* _Nonnull metadata, size_t metadataSize);
+
+    /**
+     * Sets the global value for a given MetadataType.
+     *
+     * This is equivalent to `setMetadata` when passed an AIMapper_MetadataType with name
+     * set to "android.hardware.graphics.common.StandardMetadataType"
+     *
+     * Metadata fields are not required to be settable. This function can
+     * return Error::UNSUPPORTED whenever it doesn't support setting a
+     * particular Metadata field.
+     *
+     * The framework will attempt to set the following StandardMetadataType
+     * 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
+     * @param metadata Pointer to a buffer of bytes representing the value associated with
+     * @param metadataSize The size of the metadata buffer
+     * @return error Error status of the call, which may be
+     *     - `NONE` upon success.
+     *     - `BAD_BUFFER` if the raw handle is invalid.
+     *     - `BAD_VALUE` when the field is constant and can never be set (such as
+     *       BUFFER_ID, NAME, WIDTH, HEIGHT, LAYER_COUNT, PIXEL_FORMAT_REQUESTED and
+     *       USAGE)
+     *     - `NO_RESOURCES` if the set cannot be fulfilled due to unavailability of
+     *        resources.
+     *     - `UNSUPPORTED` when metadataType is unknown/unsupported or setting
+     *       it is unsupported. Unsupported should also be returned if the metadata
+     *       is malformed.
+     */
+    AIMapper_Error (*_Nonnull setStandardMetadata)(buffer_handle_t _Nonnull buffer,
+                                                   int64_t standardMetadataType,
+                                                   const void* _Nonnull metadata,
+                                                   size_t metadataSize);
+
+    /**
+     * Lists all the MetadataTypes supported by IMapper as well as a description
+     * of each supported MetadataType. For StandardMetadataTypes, the description
+     * string can be left empty.
+     *
+     * This list is expected to be static & thus the returned array must be valid for the
+     * lifetime of the process.
+     *
+     * @param outDescriptionList The list of descriptions
+     * @param outNumberOfDescriptions How many descriptions are in `outDescriptionList`
+     * @return error Error status of the call, which may be
+     *     - `NONE` upon success.
+     *     - `UNSUPPORTED` if there's any error
+     */
+    AIMapper_Error (*_Nonnull listSupportedMetadataTypes)(
+            const AIMapper_MetadataTypeDescription* _Nullable* _Nonnull outDescriptionList,
+            size_t* _Nonnull outNumberOfDescriptions);
+
+    /**
+     * Dumps a buffer's metadata.
+     *
+     * @param buffer The buffer to dump the metadata for
+     * @param dumpBufferCallback Callback that will be invoked for each of the metadata fields
+     * @param context A caller-provided context to be passed to the dumpBufferCallback
+     * @return error Error status of the call, which may be
+     *     - `NONE` upon success.
+     *     - `BAD_BUFFER` if the raw handle is invalid.
+     *     - `NO_RESOURCES` if the get cannot be fulfilled due to unavailability of
+     *       resources.
+     */
+    AIMapper_Error (*_Nonnull dumpBuffer)(buffer_handle_t _Nonnull buffer,
+                                          AIMapper_DumpBufferCallback _Nonnull dumpBufferCallback,
+                                          void* _Null_unspecified context);
+
+    /**
+     * Dump the metadata for all imported buffers in the current process
+     *
+     * The HAL implementation should invoke beginDumpCallback before dumping a buffer's metadata,
+     * followed by N calls to dumpBufferCallback for that buffer's metadata fields. The call
+     * sequence should follow this pseudocode:
+     *
+     * for (auto buffer : gListOfImportedBuffers) {
+     *    beginDumpCallback(context);
+     *    for (auto metadata : buffer->allMetadata()) {
+     *        dumpBufferCallback(context, metadata...);
+     *    }
+     * }
+     *
+     * @param beginDumpCallback Signals that a buffer is about to be dumped
+     * @param dumpBufferCallback Callback that will be invoked for each of the metadata fields
+     * @param context A caller-provided context to be passed to beginDumpCallback and
+     *                dumpBufferCallback
+     * @return error Error status of the call, which may be
+     *     - `NONE` upon success.
+     *     - `BAD_BUFFER` if the raw handle is invalid.
+     *     - `NO_RESOURCES` if the get cannot be fulfilled due to unavailability of
+     *       resources.
+     */
+    AIMapper_Error (*_Nonnull dumpAllBuffers)(
+            AIMapper_BeginDumpBufferCallback _Nonnull beginDumpCallback,
+            AIMapper_DumpBufferCallback _Nonnull dumpBufferCallback,
+            void* _Null_unspecified context);
+
+    /**
+     * Returns the region of shared memory associated with the buffer that is
+     * reserved for client use.
+     *
+     * The shared memory may be allocated from any shared memory allocator.
+     * The shared memory must be CPU-accessible and virtually contiguous. The
+     * starting address must be word-aligned.
+     *
+     * This function may only be called after importBuffer() has been called by the
+     * client. The reserved region must remain accessible until freeBuffer() has
+     * been called. After freeBuffer() has been called, the client must not access
+     * the reserved region.
+     *
+     * This reserved memory may be used in future versions of Android to
+     * help clients implement backwards compatible features without requiring
+     * IAllocator/IMapper updates.
+     *
+     * @param buffer Imported buffer handle.
+     * @param outReservedRegion CPU-accessible pointer to the reserved region
+     * @param outReservedSize the size of the reservedRegion that was requested
+     *    in the BufferDescriptorInfo.
+     * @return error Error status of the call, which may be
+     *     - `NONE` upon success.
+     *     - `BAD_BUFFER` if the buffer is invalid.
+     */
+    AIMapper_Error (*_Nonnull getReservedRegion)(buffer_handle_t _Nonnull buffer,
+                                                 void* _Nullable* _Nonnull outReservedRegion,
+                                                 uint64_t* _Nonnull outReservedSize);
+
+} AIMapperV5;
+
+/**
+ * Return value for AIMapper_loadIMapper
+ *
+ * Note: This struct's size is not fixed and callers must never store it by-value as a result.
+ *       Only fields up to those covered by `version` are allowed to be accessed.
+ */
+typedef struct AIMapper {
+    alignas(alignof(max_align_t)) AIMapper_Version version;
+    AIMapperV5 v5;
+} AIMapper;
+
+/**
+ * Loads the vendor-provided implementation of AIMapper
+ * @return Error status of the call.
+ *          - `NONE` upon success
+ *          - `UNSUPPORTED` if no implementation is available
+ */
+AIMapper_Error AIMapper_loadIMapper(AIMapper* _Nullable* _Nonnull outImplementation);
+
+__END_DECLS
\ No newline at end of file
diff --git a/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp b/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp
new file mode 100644
index 0000000..326346c
--- /dev/null
+++ b/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp
@@ -0,0 +1,1763 @@
+/*
+ * 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "VtsHalGraphicsMapperStableC_TargetTest"
+
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/graphics/allocator/AllocationError.h>
+#include <aidl/android/hardware/graphics/allocator/AllocationResult.h>
+#include <aidl/android/hardware/graphics/allocator/IAllocator.h>
+#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>
+#include <android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h>
+#include <gralloctypes/Gralloc4.h>
+#include <hidl/GtestPrinter.h>
+#include <system/graphics.h>
+
+#include <dlfcn.h>
+#include <drm/drm_fourcc.h>
+#include <gtest/gtest.h>
+#include <vndksupport/linker.h>
+#include <initializer_list>
+#include <optional>
+#include <string>
+#include <tuple>
+#include <vector>
+
+using namespace aidl::android::hardware::graphics::allocator;
+using namespace aidl::android::hardware::graphics::common;
+using namespace android;
+using namespace android::hardware;
+using namespace ::android::hardware::graphics::mapper;
+
+typedef AIMapper_Error (*AIMapper_loadIMapperFn)(AIMapper* _Nullable* _Nonnull outImplementation);
+
+inline constexpr BufferUsage operator|(BufferUsage lhs, BufferUsage rhs) {
+    using T = std::underlying_type_t<BufferUsage>;
+    return static_cast<BufferUsage>(static_cast<T>(lhs) | static_cast<T>(rhs));
+}
+
+inline BufferUsage& operator|=(BufferUsage& lhs, BufferUsage rhs) {
+    lhs = lhs | rhs;
+    return lhs;
+}
+
+struct YCbCr {
+    android_ycbcr yCbCr;
+    int64_t horizontalSubSampling;
+    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;
+
+  public:
+    explicit BufferHandle(AIMapper* mapper, native_handle_t* rawHandle) : mIMapper(mapper) {
+        EXPECT_EQ(AIMAPPER_ERROR_NONE, mIMapper->v5.importBuffer(rawHandle, &mHandle));
+    }
+
+    explicit BufferHandle(BufferHandle&& other) { *this = std::move(other); }
+
+    BufferHandle& operator=(BufferHandle&& other) noexcept {
+        reset();
+        mIMapper = other.mIMapper;
+        mHandle = other.mHandle;
+        other.mHandle = nullptr;
+        return *this;
+    }
+
+    ~BufferHandle() { reset(); }
+
+    constexpr explicit operator bool() const noexcept { return mHandle != nullptr; }
+
+    buffer_handle_t operator*() const noexcept { return mHandle; }
+
+    void reset() {
+        if (mHandle != nullptr) {
+            EXPECT_EQ(AIMAPPER_ERROR_NONE, mIMapper->v5.freeBuffer(mHandle));
+            mHandle = nullptr;
+        }
+    }
+};
+
+class BufferAllocation {
+    AIMapper* mIMapper;
+    native_handle_t* mRawHandle;
+    uint32_t mStride;
+    const BufferDescriptorInfo mInfo;
+
+  public:
+    BufferAllocation(const BufferAllocation&) = delete;
+    void operator=(const BufferAllocation&) = delete;
+
+    BufferAllocation(AIMapper* mapper, native_handle_t* handle, uint32_t stride,
+                     const BufferDescriptorInfo& info)
+        : mIMapper(mapper), mRawHandle(handle), mStride(stride), mInfo(info) {}
+
+    ~BufferAllocation() {
+        if (mRawHandle == nullptr) return;
+
+        native_handle_close(mRawHandle);
+        native_handle_delete(mRawHandle);
+    }
+
+    uint32_t stride() const { return mStride; }
+    const BufferDescriptorInfo& info() const { return mInfo; }
+
+    BufferHandle import() { return BufferHandle{mIMapper, mRawHandle}; }
+
+    const native_handle_t* rawHandle() const { return mRawHandle; }
+};
+
+class GraphicsTestsBase {
+  private:
+    friend class BufferAllocation;
+    int32_t mIAllocatorVersion = 1;
+    std::shared_ptr<IAllocator> mAllocator;
+    AIMapper* mIMapper = nullptr;
+    AIMapper_loadIMapperFn mIMapperLoader;
+
+  protected:
+    void Initialize(std::shared_ptr<IAllocator> allocator) {
+        mAllocator = allocator;
+        ASSERT_NE(nullptr, mAllocator.get()) << "failed to get allocator service";
+        ASSERT_TRUE(mAllocator->getInterfaceVersion(&mIAllocatorVersion).isOk());
+        ASSERT_GE(mIAllocatorVersion, 2);
+        std::string mapperSuffix;
+        auto status = mAllocator->getIMapperLibrarySuffix(&mapperSuffix);
+        ASSERT_TRUE(status.isOk()) << "Failed to get IMapper library suffix";
+        std::string lib_name = "mapper." + mapperSuffix + ".so";
+        void* so = android_load_sphal_library(lib_name.c_str(), RTLD_LOCAL | RTLD_NOW);
+        ASSERT_NE(nullptr, so) << "Failed to load " << lib_name;
+        mIMapperLoader = (AIMapper_loadIMapperFn)dlsym(so, "AIMapper_loadIMapper");
+        ASSERT_NE(nullptr, mIMapperLoader) << "AIMapper_locaIMapper missing from " << lib_name;
+        ASSERT_EQ(AIMAPPER_ERROR_NONE, mIMapperLoader(&mIMapper));
+        ASSERT_NE(mIMapper, nullptr);
+    }
+
+  public:
+    AIMapper_loadIMapperFn getIMapperLoader() const { return mIMapperLoader; }
+
+    std::unique_ptr<BufferAllocation> allocate(const BufferDescriptorInfo& descriptorInfo) {
+        AllocationResult result;
+        ::ndk::ScopedAStatus status = mAllocator->allocate2(descriptorInfo, 1, &result);
+        if (!status.isOk()) {
+            status_t error = status.getExceptionCode();
+            if (error == EX_SERVICE_SPECIFIC) {
+                error = status.getServiceSpecificError();
+                EXPECT_NE(OK, error) << "Failed to set error properly";
+            } else {
+                EXPECT_EQ(OK, error) << "Allocation transport failure";
+            }
+            return nullptr;
+        } else {
+            return std::make_unique<BufferAllocation>(mIMapper, dupFromAidl(result.buffers[0]),
+                                                      result.stride, descriptorInfo);
+        }
+    }
+
+    std::unique_ptr<BufferAllocation> allocateGeneric() {
+        return allocate({
+                .name = {"VTS_TEMP"},
+                .width = 64,
+                .height = 64,
+                .layerCount = 1,
+                .format = PixelFormat::RGBA_8888,
+                .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+                .reservedSize = 0,
+        });
+    }
+
+    bool isSupported(const BufferDescriptorInfo& descriptorInfo) {
+        bool ret = false;
+        EXPECT_TRUE(mAllocator->isSupported(descriptorInfo, &ret).isOk());
+        return ret;
+    }
+
+    AIMapper* mapper() const { return mIMapper; }
+
+    template <StandardMetadataType T>
+    auto getStandardMetadata(buffer_handle_t bufferHandle)
+            -> decltype(StandardMetadata<T>::value::decode(nullptr, 0)) {
+        using Value = typename StandardMetadata<T>::value;
+        std::vector<uint8_t> buffer;
+        // Initial guess
+        buffer.resize(512);
+        int32_t sizeRequired = mapper()->v5.getStandardMetadata(
+                bufferHandle, static_cast<int64_t>(T), buffer.data(), buffer.size());
+        if (sizeRequired < 0) {
+            EXPECT_EQ(-AIMAPPER_ERROR_UNSUPPORTED, sizeRequired)
+                    << "Received something other than UNSUPPORTED from valid getStandardMetadata "
+                       "call";
+            return std::nullopt;
+        }
+        if (sizeRequired > buffer.size()) {
+            buffer.resize(sizeRequired);
+            sizeRequired = mapper()->v5.getStandardMetadata(bufferHandle, static_cast<int64_t>(T),
+                                                            buffer.data(), buffer.size());
+        }
+        if (sizeRequired < 0 || sizeRequired >= buffer.size()) {
+            ADD_FAILURE() << "getStandardMetadata failed, received " << sizeRequired
+                          << " with buffer size " << buffer.size();
+            // Generate a fail type
+            return std::nullopt;
+        }
+        return Value::decode(buffer.data(), sizeRequired);
+    }
+
+    template <StandardMetadataType T>
+    AIMapper_Error setStandardMetadata(buffer_handle_t bufferHandle,
+                                       const typename StandardMetadata<T>::value_type& value) {
+        using Value = typename StandardMetadata<T>::value;
+        int32_t sizeRequired = Value::encode(value, nullptr, 0);
+        if (sizeRequired < 0) {
+            EXPECT_GE(sizeRequired, 0) << "Failed to calculate required size";
+            return static_cast<AIMapper_Error>(-sizeRequired);
+        }
+        std::vector<uint8_t> buffer;
+        buffer.resize(sizeRequired);
+        sizeRequired = Value::encode(value, buffer.data(), buffer.size());
+        if (sizeRequired < 0 || sizeRequired > buffer.size()) {
+            ADD_FAILURE() << "Failed to encode with calculated size " << sizeRequired
+                          << "; buffer size" << buffer.size();
+            return static_cast<AIMapper_Error>(-sizeRequired);
+        }
+        return mapper()->v5.setStandardMetadata(bufferHandle, static_cast<int64_t>(T),
+                                                buffer.data(), sizeRequired);
+    }
+
+    void verifyRGBA8888PlaneLayouts(const std::vector<PlaneLayout>& planeLayouts) {
+        ASSERT_EQ(1, planeLayouts.size());
+
+        const auto& planeLayout = planeLayouts.front();
+
+        ASSERT_EQ(4, planeLayout.components.size());
+
+        int64_t offsetInBitsR = -1;
+        int64_t offsetInBitsG = -1;
+        int64_t offsetInBitsB = -1;
+        int64_t offsetInBitsA = -1;
+
+        for (const auto& component : planeLayout.components) {
+            if (!gralloc4::isStandardPlaneLayoutComponentType(component.type)) {
+                continue;
+            }
+            EXPECT_EQ(8, component.sizeInBits);
+            if (component.type.value == gralloc4::PlaneLayoutComponentType_R.value) {
+                offsetInBitsR = component.offsetInBits;
+            }
+            if (component.type.value == gralloc4::PlaneLayoutComponentType_G.value) {
+                offsetInBitsG = component.offsetInBits;
+            }
+            if (component.type.value == gralloc4::PlaneLayoutComponentType_B.value) {
+                offsetInBitsB = component.offsetInBits;
+            }
+            if (component.type.value == gralloc4::PlaneLayoutComponentType_A.value) {
+                offsetInBitsA = component.offsetInBits;
+            }
+        }
+
+        EXPECT_EQ(0, offsetInBitsR);
+        EXPECT_EQ(8, offsetInBitsG);
+        EXPECT_EQ(16, offsetInBitsB);
+        EXPECT_EQ(24, offsetInBitsA);
+
+        EXPECT_EQ(0, planeLayout.offsetInBytes);
+        EXPECT_EQ(32, planeLayout.sampleIncrementInBits);
+        // Skip testing stride because any stride is valid
+        EXPECT_LE(planeLayout.widthInSamples * planeLayout.heightInSamples * 4,
+                  planeLayout.totalSizeInBytes);
+        EXPECT_EQ(1, planeLayout.horizontalSubsampling);
+        EXPECT_EQ(1, planeLayout.verticalSubsampling);
+    }
+
+    void fillRGBA8888(uint8_t* data, uint32_t height, size_t strideInBytes, size_t widthInBytes) {
+        for (uint32_t y = 0; y < height; y++) {
+            memset(data, y, widthInBytes);
+            data += strideInBytes;
+        }
+    }
+
+    void verifyRGBA8888(const buffer_handle_t bufferHandle, const uint8_t* data, uint32_t height,
+                        size_t strideInBytes, size_t widthInBytes) {
+        auto decodeResult = getStandardMetadata<StandardMetadataType::PLANE_LAYOUTS>(bufferHandle);
+        ASSERT_TRUE(decodeResult.has_value());
+        const auto& planeLayouts = *decodeResult;
+        ASSERT_TRUE(planeLayouts.size() > 0);
+
+        verifyRGBA8888PlaneLayouts(planeLayouts);
+
+        for (uint32_t y = 0; y < height; y++) {
+            for (size_t i = 0; i < widthInBytes; i++) {
+                EXPECT_EQ(static_cast<uint8_t>(y), data[i]);
+            }
+            data += strideInBytes;
+        }
+    }
+
+    void traverseYCbCrData(const android_ycbcr& yCbCr, int32_t width, int32_t height,
+                           int64_t hSubsampling, int64_t vSubsampling,
+                           std::function<void(uint8_t*, uint8_t)> traverseFuncion) {
+        auto yData = static_cast<uint8_t*>(yCbCr.y);
+        auto cbData = static_cast<uint8_t*>(yCbCr.cb);
+        auto crData = static_cast<uint8_t*>(yCbCr.cr);
+        auto yStride = yCbCr.ystride;
+        auto cStride = yCbCr.cstride;
+        auto chromaStep = yCbCr.chroma_step;
+
+        for (uint32_t y = 0; y < height; y++) {
+            for (uint32_t x = 0; x < width; x++) {
+                auto val = static_cast<uint8_t>(height * y + x);
+
+                traverseFuncion(yData + yStride * y + x, val);
+
+                if (y % vSubsampling == 0 && x % hSubsampling == 0) {
+                    uint32_t subSampleX = x / hSubsampling;
+                    uint32_t subSampleY = y / vSubsampling;
+                    const auto subSampleOffset = cStride * subSampleY + chromaStep * subSampleX;
+                    const auto subSampleVal =
+                            static_cast<uint8_t>(height * subSampleY + subSampleX);
+
+                    traverseFuncion(cbData + subSampleOffset, subSampleVal);
+                    traverseFuncion(crData + subSampleOffset, subSampleVal + 1);
+                }
+            }
+        }
+    }
+
+    void fillYCbCrData(const android_ycbcr& yCbCr, int32_t width, int32_t height,
+                       int64_t hSubsampling, int64_t vSubsampling) {
+        traverseYCbCrData(yCbCr, width, height, hSubsampling, vSubsampling,
+                          [](auto address, auto fillingData) { *address = fillingData; });
+    }
+
+    void verifyYCbCrData(const android_ycbcr& yCbCr, int32_t width, int32_t height,
+                         int64_t hSubsampling, int64_t vSubsampling) {
+        traverseYCbCrData(
+                yCbCr, width, height, hSubsampling, vSubsampling,
+                [](auto address, auto expectedData) { EXPECT_EQ(*address, expectedData); });
+    }
+
+    constexpr uint64_t bitsToBytes(int64_t bits) { return bits / 8; }
+    constexpr uint64_t bytesToBits(int64_t bytes) { return bytes * 8; }
+
+    void getAndroidYCbCr(buffer_handle_t bufferHandle, uint8_t* data, android_ycbcr* outYCbCr,
+                         int64_t* hSubsampling, int64_t* vSubsampling) {
+        auto decodeResult = getStandardMetadata<StandardMetadataType::PLANE_LAYOUTS>(bufferHandle);
+        ASSERT_TRUE(decodeResult.has_value());
+        const auto& planeLayouts = *decodeResult;
+        ASSERT_TRUE(planeLayouts.size() > 0);
+
+        outYCbCr->y = nullptr;
+        outYCbCr->cb = nullptr;
+        outYCbCr->cr = nullptr;
+        outYCbCr->ystride = 0;
+        outYCbCr->cstride = 0;
+        outYCbCr->chroma_step = 0;
+
+        for (const auto& planeLayout : planeLayouts) {
+            for (const auto& planeLayoutComponent : planeLayout.components) {
+                if (!gralloc4::isStandardPlaneLayoutComponentType(planeLayoutComponent.type)) {
+                    continue;
+                }
+                ASSERT_EQ(0, planeLayoutComponent.offsetInBits % 8);
+
+                uint8_t* tmpData = data + planeLayout.offsetInBytes +
+                                   bitsToBytes(planeLayoutComponent.offsetInBits);
+                uint64_t sampleIncrementInBytes;
+
+                auto type = static_cast<PlaneLayoutComponentType>(planeLayoutComponent.type.value);
+                switch (type) {
+                    case PlaneLayoutComponentType::Y:
+                        ASSERT_EQ(nullptr, outYCbCr->y);
+                        ASSERT_EQ(8, planeLayoutComponent.sizeInBits);
+                        ASSERT_EQ(8, planeLayout.sampleIncrementInBits);
+                        outYCbCr->y = tmpData;
+                        outYCbCr->ystride = planeLayout.strideInBytes;
+                        break;
+
+                    case PlaneLayoutComponentType::CB:
+                    case PlaneLayoutComponentType::CR:
+                        ASSERT_EQ(0, planeLayout.sampleIncrementInBits % 8);
+
+                        sampleIncrementInBytes = planeLayout.sampleIncrementInBits / 8;
+                        ASSERT_TRUE(sampleIncrementInBytes == 1 || sampleIncrementInBytes == 2);
+
+                        if (outYCbCr->cstride == 0 && outYCbCr->chroma_step == 0) {
+                            outYCbCr->cstride = planeLayout.strideInBytes;
+                            outYCbCr->chroma_step = sampleIncrementInBytes;
+                        } else {
+                            ASSERT_EQ(outYCbCr->cstride, planeLayout.strideInBytes);
+                            ASSERT_EQ(outYCbCr->chroma_step, sampleIncrementInBytes);
+                        }
+
+                        if (*hSubsampling == 0 && *vSubsampling == 0) {
+                            *hSubsampling = planeLayout.horizontalSubsampling;
+                            *vSubsampling = planeLayout.verticalSubsampling;
+                        } else {
+                            ASSERT_EQ(*hSubsampling, planeLayout.horizontalSubsampling);
+                            ASSERT_EQ(*vSubsampling, planeLayout.verticalSubsampling);
+                        }
+
+                        if (type == PlaneLayoutComponentType::CB) {
+                            ASSERT_EQ(nullptr, outYCbCr->cb);
+                            outYCbCr->cb = tmpData;
+                        } else {
+                            ASSERT_EQ(nullptr, outYCbCr->cr);
+                            outYCbCr->cr = tmpData;
+                        }
+                        break;
+                    default:
+                        break;
+                };
+            }
+        }
+
+        ASSERT_NE(nullptr, outYCbCr->y);
+        ASSERT_NE(nullptr, outYCbCr->cb);
+        ASSERT_NE(nullptr, outYCbCr->cr);
+    }
+
+    YCbCr getAndroidYCbCr_P010(const native_handle_t* bufferHandle, uint8_t* data) {
+        YCbCr yCbCr_P010;
+        auto decodeResult = getStandardMetadata<StandardMetadataType::PLANE_LAYOUTS>(bufferHandle);
+        if (!decodeResult.has_value()) {
+            ADD_FAILURE() << "failed to get plane layout";
+            return YCbCr{};
+        }
+        const auto& planeLayouts = *decodeResult;
+        EXPECT_EQ(2, planeLayouts.size());
+        EXPECT_EQ(1, planeLayouts[0].components.size());
+        EXPECT_EQ(2, planeLayouts[1].components.size());
+
+        yCbCr_P010.yCbCr.y = nullptr;
+        yCbCr_P010.yCbCr.cb = nullptr;
+        yCbCr_P010.yCbCr.cr = nullptr;
+        yCbCr_P010.yCbCr.ystride = 0;
+        yCbCr_P010.yCbCr.cstride = 0;
+        yCbCr_P010.yCbCr.chroma_step = 0;
+        int64_t cb_offset = 0;
+        int64_t cr_offset = 0;
+
+        for (const auto& planeLayout : planeLayouts) {
+            for (const auto& planeLayoutComponent : planeLayout.components) {
+                if (!gralloc4::isStandardPlaneLayoutComponentType(planeLayoutComponent.type)) {
+                    continue;
+                }
+
+                uint8_t* tmpData = data + planeLayout.offsetInBytes +
+                                   bitsToBytes(planeLayoutComponent.offsetInBits);
+                uint64_t sampleIncrementInBytes = 0;
+                auto type = static_cast<PlaneLayoutComponentType>(planeLayoutComponent.type.value);
+                switch (type) {
+                    case PlaneLayoutComponentType::Y:
+                        // For specs refer:
+                        // https://docs.microsoft.com/en-us/windows/win32/medfound/10-bit-and-16-bit-yuv-video-formats
+                        EXPECT_EQ(6, planeLayoutComponent.offsetInBits);
+                        EXPECT_EQ(nullptr, yCbCr_P010.yCbCr.y);
+                        EXPECT_EQ(10, planeLayoutComponent.sizeInBits);
+                        EXPECT_EQ(16, planeLayout.sampleIncrementInBits);
+
+                        yCbCr_P010.yCbCr.y = tmpData;
+                        yCbCr_P010.yCbCr.ystride = planeLayout.strideInBytes;
+                        break;
+
+                    case PlaneLayoutComponentType::CB:
+                    case PlaneLayoutComponentType::CR:
+                        sampleIncrementInBytes = bitsToBytes(planeLayout.sampleIncrementInBits);
+                        EXPECT_EQ(4, sampleIncrementInBytes);
+
+                        if (yCbCr_P010.yCbCr.cstride == 0 && yCbCr_P010.yCbCr.chroma_step == 0) {
+                            yCbCr_P010.yCbCr.cstride = planeLayout.strideInBytes;
+                            yCbCr_P010.yCbCr.chroma_step = sampleIncrementInBytes;
+                        } else {
+                            EXPECT_EQ(yCbCr_P010.yCbCr.cstride, planeLayout.strideInBytes);
+                            EXPECT_EQ(yCbCr_P010.yCbCr.chroma_step, sampleIncrementInBytes);
+                        }
+
+                        if (yCbCr_P010.horizontalSubSampling == 0 &&
+                            yCbCr_P010.verticalSubSampling == 0) {
+                            yCbCr_P010.horizontalSubSampling = planeLayout.horizontalSubsampling;
+                            yCbCr_P010.verticalSubSampling = planeLayout.verticalSubsampling;
+                        } else {
+                            EXPECT_EQ(yCbCr_P010.horizontalSubSampling,
+                                      planeLayout.horizontalSubsampling);
+                            EXPECT_EQ(yCbCr_P010.verticalSubSampling,
+                                      planeLayout.verticalSubsampling);
+                        }
+
+                        if (type == PlaneLayoutComponentType::CB) {
+                            EXPECT_EQ(nullptr, yCbCr_P010.yCbCr.cb);
+                            yCbCr_P010.yCbCr.cb = tmpData;
+                            cb_offset = planeLayoutComponent.offsetInBits;
+                        } else {
+                            EXPECT_EQ(nullptr, yCbCr_P010.yCbCr.cr);
+                            yCbCr_P010.yCbCr.cr = tmpData;
+                            cr_offset = planeLayoutComponent.offsetInBits;
+                        }
+                        break;
+                    default:
+                        break;
+                };
+            }
+        }
+
+        EXPECT_EQ(cb_offset + bytesToBits(2), cr_offset);
+        EXPECT_NE(nullptr, yCbCr_P010.yCbCr.y);
+        EXPECT_NE(nullptr, yCbCr_P010.yCbCr.cb);
+        EXPECT_NE(nullptr, yCbCr_P010.yCbCr.cr);
+        return yCbCr_P010;
+    }
+};
+
+class GraphicsMapperStableCTests
+    : public GraphicsTestsBase,
+      public ::testing::TestWithParam<std::tuple<std::string, std::shared_ptr<IAllocator>>> {
+  public:
+    void SetUp() override { Initialize(std::get<1>(GetParam())); }
+
+    void TearDown() override {}
+};
+
+TEST_P(GraphicsMapperStableCTests, AllV5CallbacksDefined) {
+    ASSERT_GE(mapper()->version, AIMAPPER_VERSION_5);
+
+    EXPECT_TRUE(mapper()->v5.importBuffer);
+    EXPECT_TRUE(mapper()->v5.freeBuffer);
+    EXPECT_TRUE(mapper()->v5.getTransportSize);
+    EXPECT_TRUE(mapper()->v5.lock);
+    EXPECT_TRUE(mapper()->v5.unlock);
+    EXPECT_TRUE(mapper()->v5.flushLockedBuffer);
+    EXPECT_TRUE(mapper()->v5.rereadLockedBuffer);
+    EXPECT_TRUE(mapper()->v5.getMetadata);
+    EXPECT_TRUE(mapper()->v5.getStandardMetadata);
+    EXPECT_TRUE(mapper()->v5.setMetadata);
+    EXPECT_TRUE(mapper()->v5.setStandardMetadata);
+    EXPECT_TRUE(mapper()->v5.listSupportedMetadataTypes);
+    EXPECT_TRUE(mapper()->v5.dumpBuffer);
+    EXPECT_TRUE(mapper()->v5.getReservedRegion);
+}
+
+TEST_P(GraphicsMapperStableCTests, DualLoadIsIdentical) {
+    ASSERT_GE(mapper()->version, AIMAPPER_VERSION_5);
+    AIMapper* secondMapper;
+    ASSERT_EQ(AIMAPPER_ERROR_NONE, getIMapperLoader()(&secondMapper));
+
+    EXPECT_EQ(secondMapper->v5.importBuffer, mapper()->v5.importBuffer);
+    EXPECT_EQ(secondMapper->v5.freeBuffer, mapper()->v5.freeBuffer);
+    EXPECT_EQ(secondMapper->v5.getTransportSize, mapper()->v5.getTransportSize);
+    EXPECT_EQ(secondMapper->v5.lock, mapper()->v5.lock);
+    EXPECT_EQ(secondMapper->v5.unlock, mapper()->v5.unlock);
+    EXPECT_EQ(secondMapper->v5.flushLockedBuffer, mapper()->v5.flushLockedBuffer);
+    EXPECT_EQ(secondMapper->v5.rereadLockedBuffer, mapper()->v5.rereadLockedBuffer);
+    EXPECT_EQ(secondMapper->v5.getMetadata, mapper()->v5.getMetadata);
+    EXPECT_EQ(secondMapper->v5.getStandardMetadata, mapper()->v5.getStandardMetadata);
+    EXPECT_EQ(secondMapper->v5.setMetadata, mapper()->v5.setMetadata);
+    EXPECT_EQ(secondMapper->v5.setStandardMetadata, mapper()->v5.setStandardMetadata);
+    EXPECT_EQ(secondMapper->v5.listSupportedMetadataTypes, mapper()->v5.listSupportedMetadataTypes);
+    EXPECT_EQ(secondMapper->v5.dumpBuffer, mapper()->v5.dumpBuffer);
+    EXPECT_EQ(secondMapper->v5.getReservedRegion, mapper()->v5.getReservedRegion);
+}
+
+TEST_P(GraphicsMapperStableCTests, CanAllocate) {
+    auto buffer = allocate({
+            .name = {"VTS_TEMP"},
+            .width = 64,
+            .height = 64,
+            .layerCount = 1,
+            .format = PixelFormat::RGBA_8888,
+            .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+            .reservedSize = 0,
+    });
+    ASSERT_NE(nullptr, buffer.get());
+    EXPECT_GE(buffer->stride(), 64);
+}
+
+TEST_P(GraphicsMapperStableCTests, ImportFreeBuffer) {
+    auto buffer = allocate({
+            .name = {"VTS_TEMP"},
+            .width = 64,
+            .height = 64,
+            .layerCount = 1,
+            .format = PixelFormat::RGBA_8888,
+            .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+            .reservedSize = 0,
+    });
+    ASSERT_NE(nullptr, buffer.get());
+    EXPECT_GE(buffer->stride(), 64);
+
+    {
+        auto import1 = buffer->import();
+        auto import2 = buffer->import();
+        EXPECT_TRUE(import1);
+        EXPECT_TRUE(import2);
+        EXPECT_NE(*import1, *import2);
+    }
+}
+
+/**
+ * Test IMapper::importBuffer and IMapper::freeBuffer cross mapper instances.
+ */
+TEST_P(GraphicsMapperStableCTests, ImportFreeBufferSingleton) {
+    auto buffer = allocate({
+            .name = {"VTS_TEMP"},
+            .width = 64,
+            .height = 64,
+            .layerCount = 1,
+            .format = PixelFormat::RGBA_8888,
+            .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+            .reservedSize = 0,
+    });
+    ASSERT_NE(nullptr, buffer.get());
+    EXPECT_GE(buffer->stride(), 64);
+
+    buffer_handle_t bufferHandle = nullptr;
+    ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.importBuffer(buffer->rawHandle(), &bufferHandle));
+    ASSERT_NE(nullptr, bufferHandle);
+
+    AIMapper* secondMapper;
+    ASSERT_EQ(AIMAPPER_ERROR_NONE, getIMapperLoader()(&secondMapper));
+    ASSERT_EQ(AIMAPPER_ERROR_NONE, secondMapper->v5.freeBuffer(bufferHandle));
+}
+
+/**
+ * Test IMapper::importBuffer with invalid buffers.
+ */
+TEST_P(GraphicsMapperStableCTests, ImportBufferNegative) {
+    native_handle_t* invalidHandle = nullptr;
+    buffer_handle_t bufferHandle = nullptr;
+    EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER, mapper()->v5.importBuffer(invalidHandle, &bufferHandle))
+            << "importBuffer with nullptr did not fail with BAD_BUFFER";
+
+    invalidHandle = native_handle_create(0, 0);
+    EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER, mapper()->v5.importBuffer(invalidHandle, &bufferHandle))
+            << "importBuffer with invalid handle did not fail with BAD_BUFFER";
+    native_handle_delete(invalidHandle);
+}
+
+/**
+ * Test IMapper::freeBuffer with invalid buffers.
+ */
+TEST_P(GraphicsMapperStableCTests, FreeBufferNegative) {
+    native_handle_t* bufferHandle = nullptr;
+    EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER, mapper()->v5.freeBuffer(bufferHandle))
+            << "freeBuffer with nullptr did not fail with BAD_BUFFER";
+
+    bufferHandle = native_handle_create(0, 0);
+    EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER, mapper()->v5.freeBuffer(bufferHandle))
+            << "freeBuffer with invalid handle did not fail with BAD_BUFFER";
+    native_handle_delete(bufferHandle);
+
+    auto buffer = allocateGeneric();
+    EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER, mapper()->v5.freeBuffer(buffer->rawHandle()))
+            << "freeBuffer with un-imported handle did not fail with BAD_BUFFER";
+}
+
+/**
+ * Test IMapper::lock and IMapper::unlock.
+ */
+TEST_P(GraphicsMapperStableCTests, LockUnlockBasic) {
+    constexpr auto usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN;
+    auto buffer = allocate({
+            .name = {"VTS_TEMP"},
+            .width = 64,
+            .height = 64,
+            .layerCount = 1,
+            .format = PixelFormat::RGBA_8888,
+            .usage = usage,
+            .reservedSize = 0,
+    });
+    ASSERT_NE(nullptr, buffer.get());
+
+    // lock buffer for writing
+    const auto& info = buffer->info();
+    const auto stride = buffer->stride();
+    const ARect region{0, 0, info.width, info.height};
+    auto handle = buffer->import();
+    uint8_t* data = nullptr;
+    ASSERT_EQ(AIMAPPER_ERROR_NONE,
+              mapper()->v5.lock(*handle, static_cast<int64_t>(usage), region, -1, (void**)&data));
+
+    // RGBA_8888
+    fillRGBA8888(data, info.height, stride * 4, info.width * 4);
+
+    int releaseFence = -1;
+    ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*handle, &releaseFence));
+
+    // lock again for reading
+    ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.lock(*handle, static_cast<int64_t>(usage), region,
+                                                     releaseFence, (void**)&data));
+    releaseFence = -1;
+
+    ASSERT_NO_FATAL_FAILURE(verifyRGBA8888(*handle, data, info.height, stride * 4, info.width * 4));
+
+    releaseFence = -1;
+    ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*handle, &releaseFence));
+    if (releaseFence != -1) {
+        close(releaseFence);
+    }
+}
+
+/**
+ *  Test multiple operations associated with different color formats
+ */
+TEST_P(GraphicsMapperStableCTests, Lock_YCRCB_420_SP) {
+    BufferDescriptorInfo info{
+            .name = {"VTS_TEMP"},
+            .width = 64,
+            .height = 64,
+            .layerCount = 1,
+            .format = PixelFormat::YCRCB_420_SP,
+            .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+            .reservedSize = 0,
+    };
+    auto buffer = allocate(info);
+    if (!buffer) {
+        ASSERT_FALSE(isSupported(info));
+        GTEST_SUCCEED() << "YCRCB_420_SP format is unsupported";
+        return;
+    }
+
+    // lock buffer for writing
+    const ARect region{0, 0, info.width, info.height};
+    auto handle = buffer->import();
+    uint8_t* data = nullptr;
+    ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.lock(*handle, static_cast<int64_t>(info.usage),
+                                                     region, -1, (void**)&data));
+
+    android_ycbcr yCbCr;
+    int64_t hSubsampling = 0;
+    int64_t vSubsampling = 0;
+    ASSERT_NO_FATAL_FAILURE(getAndroidYCbCr(*handle, data, &yCbCr, &hSubsampling, &vSubsampling));
+
+    constexpr uint32_t kCbCrSubSampleFactor = 2;
+    ASSERT_EQ(kCbCrSubSampleFactor, hSubsampling);
+    ASSERT_EQ(kCbCrSubSampleFactor, vSubsampling);
+
+    auto cbData = static_cast<uint8_t*>(yCbCr.cb);
+    auto crData = static_cast<uint8_t*>(yCbCr.cr);
+    ASSERT_EQ(crData + 1, cbData);
+    ASSERT_EQ(2, yCbCr.chroma_step);
+
+    fillYCbCrData(yCbCr, info.width, info.height, hSubsampling, vSubsampling);
+
+    int releaseFence = -1;
+    ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*handle, &releaseFence));
+
+    // lock again for reading
+    ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.lock(*handle, static_cast<int64_t>(info.usage),
+                                                     region, releaseFence, (void**)&data));
+    releaseFence = -1;
+
+    ASSERT_NO_FATAL_FAILURE(getAndroidYCbCr(*handle, data, &yCbCr, &hSubsampling, &vSubsampling));
+
+    verifyYCbCrData(yCbCr, info.width, info.height, hSubsampling, vSubsampling);
+
+    releaseFence = -1;
+    ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*handle, &releaseFence));
+    if (releaseFence != -1) {
+        close(releaseFence);
+    }
+}
+
+TEST_P(GraphicsMapperStableCTests, YV12SubsampleMetadata) {
+    BufferDescriptorInfo info{
+            .name = {"VTS_TEMP"},
+            .width = 64,
+            .height = 64,
+            .layerCount = 1,
+            .format = PixelFormat::YV12,
+            .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+            .reservedSize = 0,
+    };
+    auto buffer = allocate(info);
+    ASSERT_NE(nullptr, buffer.get());
+
+    // lock buffer for writing
+    const ARect region{0, 0, info.width, info.height};
+    auto handle = buffer->import();
+    uint8_t* data = nullptr;
+    ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.lock(*handle, static_cast<int64_t>(info.usage),
+                                                     region, -1, (void**)&data));
+
+    auto decodeResult = getStandardMetadata<StandardMetadataType::PLANE_LAYOUTS>(*handle);
+    ASSERT_TRUE(decodeResult.has_value());
+    const auto& planeLayouts = *decodeResult;
+
+    ASSERT_EQ(3, planeLayouts.size());
+
+    auto yPlane = planeLayouts[0];
+    auto crPlane = planeLayouts[1];
+    auto cbPlane = planeLayouts[2];
+
+    constexpr uint32_t kCbCrSubSampleFactor = 2;
+    EXPECT_EQ(kCbCrSubSampleFactor, crPlane.horizontalSubsampling);
+    EXPECT_EQ(kCbCrSubSampleFactor, crPlane.verticalSubsampling);
+
+    EXPECT_EQ(kCbCrSubSampleFactor, cbPlane.horizontalSubsampling);
+    EXPECT_EQ(kCbCrSubSampleFactor, cbPlane.verticalSubsampling);
+
+    const long chromaSampleWidth = info.width / kCbCrSubSampleFactor;
+    const long chromaSampleHeight = info.height / kCbCrSubSampleFactor;
+
+    EXPECT_EQ(info.width, yPlane.widthInSamples);
+    EXPECT_EQ(info.height, yPlane.heightInSamples);
+
+    EXPECT_EQ(chromaSampleWidth, crPlane.widthInSamples);
+    EXPECT_EQ(chromaSampleHeight, crPlane.heightInSamples);
+
+    EXPECT_EQ(chromaSampleWidth, cbPlane.widthInSamples);
+    EXPECT_EQ(chromaSampleHeight, cbPlane.heightInSamples);
+
+    EXPECT_LE(crPlane.widthInSamples, crPlane.strideInBytes);
+    EXPECT_LE(cbPlane.widthInSamples, cbPlane.strideInBytes);
+
+    int releaseFence = -1;
+    ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*handle, &releaseFence));
+    if (releaseFence != -1) {
+        close(releaseFence);
+    }
+}
+
+TEST_P(GraphicsMapperStableCTests, Lock_YV12) {
+    BufferDescriptorInfo info{
+            .name = {"VTS_TEMP"},
+            .width = 64,
+            .height = 64,
+            .layerCount = 1,
+            .format = PixelFormat::YV12,
+            .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+            .reservedSize = 0,
+    };
+    auto buffer = allocate(info);
+    ASSERT_NE(nullptr, buffer.get());
+
+    // lock buffer for writing
+    const ARect region{0, 0, info.width, info.height};
+    auto handle = buffer->import();
+    uint8_t* data = nullptr;
+    ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.lock(*handle, static_cast<int64_t>(info.usage),
+                                                     region, -1, (void**)&data));
+
+    android_ycbcr yCbCr;
+    int64_t hSubsampling = 0;
+    int64_t vSubsampling = 0;
+    ASSERT_NO_FATAL_FAILURE(getAndroidYCbCr(*handle, data, &yCbCr, &hSubsampling, &vSubsampling));
+
+    constexpr uint32_t kCbCrSubSampleFactor = 2;
+    ASSERT_EQ(kCbCrSubSampleFactor, hSubsampling);
+    ASSERT_EQ(kCbCrSubSampleFactor, vSubsampling);
+
+    auto cbData = static_cast<uint8_t*>(yCbCr.cb);
+    auto crData = static_cast<uint8_t*>(yCbCr.cr);
+    ASSERT_EQ(crData + yCbCr.cstride * info.height / vSubsampling, cbData);
+    ASSERT_EQ(1, yCbCr.chroma_step);
+
+    fillYCbCrData(yCbCr, info.width, info.height, hSubsampling, vSubsampling);
+
+    int releaseFence = -1;
+    ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*handle, &releaseFence));
+
+    // lock again for reading
+    ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.lock(*handle, static_cast<int64_t>(info.usage),
+                                                     region, releaseFence, (void**)&data));
+    releaseFence = -1;
+
+    ASSERT_NO_FATAL_FAILURE(getAndroidYCbCr(*handle, data, &yCbCr, &hSubsampling, &vSubsampling));
+
+    verifyYCbCrData(yCbCr, info.width, info.height, hSubsampling, vSubsampling);
+
+    ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*handle, &releaseFence));
+    if (releaseFence != -1) {
+        close(releaseFence);
+    }
+}
+
+TEST_P(GraphicsMapperStableCTests, Lock_YCBCR_420_888) {
+    BufferDescriptorInfo info{
+            .name = {"VTS_TEMP"},
+            .width = 64,
+            .height = 64,
+            .layerCount = 1,
+            .format = PixelFormat::YCBCR_420_888,
+            .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+            .reservedSize = 0,
+    };
+    auto buffer = allocate(info);
+    ASSERT_NE(nullptr, buffer.get());
+
+    // lock buffer for writing
+    const ARect region{0, 0, info.width, info.height};
+    auto handle = buffer->import();
+    uint8_t* data = nullptr;
+    ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.lock(*handle, static_cast<int64_t>(info.usage),
+                                                     region, -1, (void**)&data));
+
+    android_ycbcr yCbCr;
+    int64_t hSubsampling = 0;
+    int64_t vSubsampling = 0;
+    ASSERT_NO_FATAL_FAILURE(getAndroidYCbCr(*handle, data, &yCbCr, &hSubsampling, &vSubsampling));
+
+    constexpr uint32_t kCbCrSubSampleFactor = 2;
+    ASSERT_EQ(kCbCrSubSampleFactor, hSubsampling);
+    ASSERT_EQ(kCbCrSubSampleFactor, vSubsampling);
+
+    fillYCbCrData(yCbCr, info.width, info.height, hSubsampling, vSubsampling);
+
+    int releaseFence = -1;
+    ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*handle, &releaseFence));
+
+    // lock again for reading
+    ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.lock(*handle, static_cast<int64_t>(info.usage),
+                                                     region, releaseFence, (void**)&data));
+    releaseFence = -1;
+
+    ASSERT_NO_FATAL_FAILURE(getAndroidYCbCr(*handle, data, &yCbCr, &hSubsampling, &vSubsampling));
+
+    verifyYCbCrData(yCbCr, info.width, info.height, hSubsampling, vSubsampling);
+
+    ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*handle, &releaseFence));
+    if (releaseFence != -1) {
+        close(releaseFence);
+    }
+}
+
+TEST_P(GraphicsMapperStableCTests, Lock_RAW10) {
+    BufferDescriptorInfo info{
+            .name = {"VTS_TEMP"},
+            .width = 64,
+            .height = 64,
+            .layerCount = 1,
+            .format = PixelFormat::RAW10,
+            .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+            .reservedSize = 0,
+    };
+    auto buffer = allocate(info);
+    if (!buffer) {
+        ASSERT_FALSE(isSupported(info));
+        GTEST_SUCCEED() << "RAW10 format is unsupported";
+        return;
+    }
+
+    // lock buffer for writing
+    const ARect region{0, 0, info.width, info.height};
+    auto handle = buffer->import();
+    uint8_t* data = nullptr;
+    ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.lock(*handle, static_cast<int64_t>(info.usage),
+                                                     region, -1, (void**)&data));
+
+    auto decodeResult = getStandardMetadata<StandardMetadataType::PLANE_LAYOUTS>(*handle);
+    ASSERT_TRUE(decodeResult.has_value());
+    const auto& planeLayouts = *decodeResult;
+
+    ASSERT_EQ(1, planeLayouts.size());
+    auto planeLayout = planeLayouts[0];
+
+    EXPECT_EQ(0, planeLayout.sampleIncrementInBits);
+    EXPECT_EQ(1, planeLayout.horizontalSubsampling);
+    EXPECT_EQ(1, planeLayout.verticalSubsampling);
+
+    ASSERT_EQ(1, planeLayout.components.size());
+    auto planeLayoutComponent = planeLayout.components[0];
+
+    EXPECT_EQ(PlaneLayoutComponentType::RAW,
+              static_cast<PlaneLayoutComponentType>(planeLayoutComponent.type.value));
+    EXPECT_EQ(0, planeLayoutComponent.offsetInBits % 8);
+    EXPECT_EQ(-1, planeLayoutComponent.sizeInBits);
+
+    int releaseFence = -1;
+    ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*handle, &releaseFence));
+    if (releaseFence != -1) {
+        close(releaseFence);
+    }
+}
+
+TEST_P(GraphicsMapperStableCTests, Lock_RAW12) {
+    BufferDescriptorInfo info{
+            .name = {"VTS_TEMP"},
+            .width = 64,
+            .height = 64,
+            .layerCount = 1,
+            .format = PixelFormat::RAW12,
+            .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+            .reservedSize = 0,
+    };
+    auto buffer = allocate(info);
+    if (!buffer) {
+        ASSERT_FALSE(isSupported(info));
+        GTEST_SUCCEED() << "RAW12 format is unsupported";
+        return;
+    }
+
+    // lock buffer for writing
+    const ARect region{0, 0, info.width, info.height};
+    auto handle = buffer->import();
+    uint8_t* data = nullptr;
+    ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.lock(*handle, static_cast<int64_t>(info.usage),
+                                                     region, -1, (void**)&data));
+
+    auto decodeResult = getStandardMetadata<StandardMetadataType::PLANE_LAYOUTS>(*handle);
+    ASSERT_TRUE(decodeResult.has_value());
+    const auto& planeLayouts = *decodeResult;
+
+    ASSERT_EQ(1, planeLayouts.size());
+    auto planeLayout = planeLayouts[0];
+
+    EXPECT_EQ(0, planeLayout.sampleIncrementInBits);
+    EXPECT_EQ(1, planeLayout.horizontalSubsampling);
+    EXPECT_EQ(1, planeLayout.verticalSubsampling);
+
+    ASSERT_EQ(1, planeLayout.components.size());
+    auto planeLayoutComponent = planeLayout.components[0];
+
+    EXPECT_EQ(PlaneLayoutComponentType::RAW,
+              static_cast<PlaneLayoutComponentType>(planeLayoutComponent.type.value));
+    EXPECT_EQ(0, planeLayoutComponent.offsetInBits % 8);
+    EXPECT_EQ(-1, planeLayoutComponent.sizeInBits);
+
+    int releaseFence = -1;
+    ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*handle, &releaseFence));
+    if (releaseFence != -1) {
+        close(releaseFence);
+    }
+}
+
+TEST_P(GraphicsMapperStableCTests, Lock_YCBCR_P010) {
+    BufferDescriptorInfo info{
+            .name = {"VTS_TEMP"},
+            .width = 64,
+            .height = 64,
+            .layerCount = 1,
+            .format = PixelFormat::YCBCR_P010,
+            .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+            .reservedSize = 0,
+    };
+    auto buffer = allocate(info);
+    if (!buffer) {
+        ASSERT_FALSE(isSupported(info));
+        GTEST_SUCCEED() << "YCBCR_P010 format is unsupported";
+        return;
+    }
+
+    // lock buffer for writing
+    const ARect region{0, 0, info.width, info.height};
+    auto handle = buffer->import();
+    uint8_t* data = nullptr;
+    ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.lock(*handle, static_cast<int64_t>(info.usage),
+                                                     region, -1, (void**)&data));
+
+    YCbCr yCbCr;
+    ASSERT_NO_FATAL_FAILURE(yCbCr = getAndroidYCbCr_P010(*handle, data));
+
+    constexpr uint32_t kCbCrSubSampleFactor = 2;
+    ASSERT_EQ(kCbCrSubSampleFactor, yCbCr.horizontalSubSampling);
+    ASSERT_EQ(kCbCrSubSampleFactor, yCbCr.verticalSubSampling);
+
+    ASSERT_EQ(0, info.height % 2);
+
+    // fill the data
+    fillYCbCrData(yCbCr.yCbCr, info.width, info.height, yCbCr.horizontalSubSampling,
+                  yCbCr.verticalSubSampling);
+    // verify the YCbCr data
+    verifyYCbCrData(yCbCr.yCbCr, info.width, info.height, yCbCr.horizontalSubSampling,
+                    yCbCr.verticalSubSampling);
+
+    int releaseFence = -1;
+    ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*handle, &releaseFence));
+    if (releaseFence != -1) {
+        close(releaseFence);
+    }
+}
+
+TEST_P(GraphicsMapperStableCTests, LockBadAccessRegion) {
+    auto buffer = allocateGeneric();
+    ASSERT_NE(nullptr, buffer);
+    const auto& info = buffer->info();
+
+    // lock buffer for writing
+    const ARect region{0, 0, info.width * 2, info.height * 2};
+    auto handle = buffer->import();
+    uint8_t* data = nullptr;
+    EXPECT_EQ(AIMAPPER_ERROR_BAD_VALUE, mapper()->v5.lock(*handle, static_cast<int64_t>(info.usage),
+                                                          region, -1, (void**)&data));
+}
+
+TEST_P(GraphicsMapperStableCTests, UnlockNegative) {
+    native_handle_t* invalidHandle = nullptr;
+    int releaseFence = -1;
+    EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER, mapper()->v5.unlock(invalidHandle, &releaseFence))
+            << "unlock with nullptr did not fail with BAD_BUFFER";
+
+    invalidHandle = native_handle_create(0, 0);
+    EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER, mapper()->v5.unlock(invalidHandle, &releaseFence))
+            << "unlock with invalid handle did not fail with BAD_BUFFER";
+    native_handle_delete(invalidHandle);
+
+    auto buffer = allocateGeneric();
+    EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER, mapper()->v5.unlock(buffer->rawHandle(), &releaseFence))
+            << "unlock with un-imported handle did not fail with BAD_BUFFER";
+}
+
+TEST_P(GraphicsMapperStableCTests, UnlockNotImported) {
+    int releaseFence = -1;
+    auto buffer = allocateGeneric();
+    ASSERT_TRUE(buffer);
+    EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER, mapper()->v5.unlock(buffer->rawHandle(), &releaseFence))
+            << "unlock with un-imported handle did not fail with BAD_BUFFER";
+}
+
+TEST_P(GraphicsMapperStableCTests, UnlockNotLocked) {
+    int releaseFence = -1;
+    auto buffer = allocateGeneric();
+    ASSERT_TRUE(buffer);
+    auto bufferHandle = buffer->import();
+    ASSERT_TRUE(bufferHandle);
+    EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER, mapper()->v5.unlock(*bufferHandle, &releaseFence))
+            << "unlock with unlocked handle did not fail with BAD_BUFFER";
+}
+
+TEST_P(GraphicsMapperStableCTests, LockUnlockNested) {
+    auto buffer = allocateGeneric();
+    ASSERT_TRUE(buffer);
+    auto bufferHandle = buffer->import();
+    ASSERT_TRUE(bufferHandle);
+    const ARect region{0, 0, buffer->info().width, buffer->info().height};
+    auto usage = static_cast<int64_t>(buffer->info().usage);
+    auto handle = buffer->import();
+    uint8_t* data = nullptr;
+    EXPECT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.lock(*handle, usage, region, -1, (void**)&data));
+    EXPECT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.lock(*handle, usage, region, -1, (void**)&data))
+            << "Second lock failed";
+    int releaseFence = -1;
+    EXPECT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*handle, &releaseFence));
+    if (releaseFence != -1) {
+        close(releaseFence);
+        releaseFence = -1;
+    }
+    EXPECT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*handle, &releaseFence))
+            << "Second unlock failed";
+    if (releaseFence != -1) {
+        close(releaseFence);
+        releaseFence = -1;
+    }
+    EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER, mapper()->v5.unlock(*handle, &releaseFence))
+            << "Third, unmatched, unlock should have failed with BAD_BUFFER";
+}
+
+TEST_P(GraphicsMapperStableCTests, FlushRereadBasic) {
+    auto buffer = allocateGeneric();
+    ASSERT_TRUE(buffer);
+    auto bufferHandle = buffer->import();
+    ASSERT_TRUE(bufferHandle);
+    const auto& info = buffer->info();
+    const auto stride = buffer->stride();
+    const ARect region{0, 0, buffer->info().width, buffer->info().height};
+
+    auto writeHandle = buffer->import();
+    auto readHandle = buffer->import();
+    ASSERT_TRUE(writeHandle && readHandle);
+
+    // lock buffer for writing
+
+    uint8_t* writeData;
+    EXPECT_EQ(AIMAPPER_ERROR_NONE,
+              mapper()->v5.lock(*writeHandle, static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN),
+                                region, -1, (void**)&writeData));
+
+    uint8_t* readData;
+    EXPECT_EQ(AIMAPPER_ERROR_NONE,
+              mapper()->v5.lock(*readHandle, static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN),
+                                region, -1, (void**)&readData));
+
+    fillRGBA8888(writeData, info.height, stride * 4, info.width * 4);
+
+    EXPECT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.flushLockedBuffer(*writeHandle));
+    EXPECT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.rereadLockedBuffer(*readHandle));
+
+    ASSERT_NO_FATAL_FAILURE(
+            verifyRGBA8888(*readHandle, readData, info.height, stride * 4, info.width * 4));
+
+    int releaseFence = -1;
+
+    EXPECT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*readHandle, &releaseFence));
+    if (releaseFence != -1) {
+        close(releaseFence);
+        releaseFence = -1;
+    }
+
+    EXPECT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*writeHandle, &releaseFence));
+    if (releaseFence != -1) {
+        close(releaseFence);
+        releaseFence = -1;
+    }
+}
+
+TEST_P(GraphicsMapperStableCTests, FlushLockedBufferBadBuffer) {
+    // Amazingly this is enough to make the compiler happy even though flushLockedBuffer
+    // is _Nonnull :shrug:
+    buffer_handle_t badBuffer = nullptr;
+    EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER, mapper()->v5.flushLockedBuffer(badBuffer));
+}
+
+TEST_P(GraphicsMapperStableCTests, RereadLockedBufferBadBuffer) {
+    buffer_handle_t badBuffer = nullptr;
+    EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER, mapper()->v5.rereadLockedBuffer(badBuffer));
+}
+
+TEST_P(GraphicsMapperStableCTests, GetBufferId) {
+    auto buffer = allocateGeneric();
+    auto bufferHandle = buffer->import();
+    auto bufferId = getStandardMetadata<StandardMetadataType::BUFFER_ID>(*bufferHandle);
+    ASSERT_TRUE(bufferId.has_value());
+
+    auto buffer2 = allocateGeneric();
+    auto bufferHandle2 = buffer2->import();
+    auto bufferId2 = getStandardMetadata<StandardMetadataType::BUFFER_ID>(*bufferHandle2);
+    ASSERT_TRUE(bufferId2.has_value());
+
+    EXPECT_NE(*bufferId, *bufferId2);
+}
+
+TEST_P(GraphicsMapperStableCTests, GetName) {
+    auto buffer = allocate({
+            .name = {"Hello, World!"},
+            .width = 64,
+            .height = 64,
+            .layerCount = 1,
+            .format = PixelFormat::RGBA_8888,
+            .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+            .reservedSize = 0,
+    });
+    auto bufferHandle = buffer->import();
+    auto name = getStandardMetadata<StandardMetadataType::NAME>(*bufferHandle);
+    ASSERT_TRUE(name.has_value());
+    EXPECT_EQ(*name, "Hello, World!");
+}
+
+TEST_P(GraphicsMapperStableCTests, GetWidthHeight) {
+    auto buffer = allocate({
+            .name = {"Hello, World!"},
+            .width = 64,
+            .height = 128,
+            .layerCount = 1,
+            .format = PixelFormat::RGBA_8888,
+            .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+            .reservedSize = 0,
+    });
+    auto bufferHandle = buffer->import();
+    auto value = getStandardMetadata<StandardMetadataType::WIDTH>(*bufferHandle);
+    ASSERT_TRUE(value.has_value());
+    EXPECT_EQ(*value, 64);
+    value = getStandardMetadata<StandardMetadataType::HEIGHT>(*bufferHandle);
+    ASSERT_TRUE(value.has_value());
+    EXPECT_EQ(*value, 128);
+}
+
+TEST_P(GraphicsMapperStableCTests, GetLayerCount) {
+    auto buffer = allocateGeneric();
+    auto bufferHandle = buffer->import();
+    auto value = getStandardMetadata<StandardMetadataType::LAYER_COUNT>(*bufferHandle);
+    ASSERT_TRUE(value.has_value());
+    EXPECT_EQ(*value, buffer->info().layerCount);
+}
+
+TEST_P(GraphicsMapperStableCTests, GetPixelFormatRequested) {
+    auto buffer = allocateGeneric();
+    auto bufferHandle = buffer->import();
+    auto value = getStandardMetadata<StandardMetadataType::PIXEL_FORMAT_REQUESTED>(*bufferHandle);
+    ASSERT_TRUE(value.has_value());
+    EXPECT_EQ(*value, buffer->info().format);
+}
+
+TEST_P(GraphicsMapperStableCTests, GetPixelFormatFourCC) {
+    auto buffer = allocate({
+            .name = {"Hello, World!"},
+            .width = 64,
+            .height = 128,
+            .layerCount = 1,
+            .format = PixelFormat::RGBA_8888,
+            .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+            .reservedSize = 0,
+    });
+    {
+        auto bufferHandle = buffer->import();
+        auto value = getStandardMetadata<StandardMetadataType::PIXEL_FORMAT_FOURCC>(*bufferHandle);
+        ASSERT_TRUE(value.has_value());
+        EXPECT_EQ(*value, DRM_FORMAT_ABGR8888);
+    }
+
+    buffer = allocate({
+            .name = {"yv12"},
+            .width = 64,
+            .height = 128,
+            .layerCount = 1,
+            .format = PixelFormat::YV12,
+            .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+            .reservedSize = 0,
+    });
+    {
+        auto bufferHandle = buffer->import();
+        auto value = getStandardMetadata<StandardMetadataType::PIXEL_FORMAT_FOURCC>(*bufferHandle);
+        ASSERT_TRUE(value.has_value());
+        EXPECT_EQ(*value, DRM_FORMAT_YVU420);
+    }
+}
+
+TEST_P(GraphicsMapperStableCTests, GetPixelFormatModifier) {
+    auto buffer = allocateGeneric();
+    auto bufferHandle = buffer->import();
+    auto value = getStandardMetadata<StandardMetadataType::PIXEL_FORMAT_MODIFIER>(*bufferHandle);
+    ASSERT_TRUE(value.has_value());
+    // Only the upper 8-bits are defined and is just the vendor ID, the lower 56 bits are
+    // then vendor specific. So there's not anything useful to assert here beyond just that
+    // we successfully queried a value
+}
+
+TEST_P(GraphicsMapperStableCTests, GetUsage) {
+    auto buffer = allocateGeneric();
+    auto bufferHandle = buffer->import();
+    auto value = getStandardMetadata<StandardMetadataType::USAGE>(*bufferHandle);
+    ASSERT_TRUE(value.has_value());
+    EXPECT_EQ(buffer->info().usage, *value);
+}
+
+TEST_P(GraphicsMapperStableCTests, GetAllocationSize) {
+    auto buffer = allocateGeneric();
+    auto bufferHandle = buffer->import();
+    auto value = getStandardMetadata<StandardMetadataType::ALLOCATION_SIZE>(*bufferHandle);
+    ASSERT_TRUE(value.has_value());
+    const auto estimatedSize = buffer->stride() * buffer->info().height * 4;
+    // This buffer has CPU usage, so we expect at least stride * height * 4 since it should be
+    // generally linear uncompressed.
+    EXPECT_GE(*value, estimatedSize)
+            << "Expected allocation size to be at least stride * height * 4bpp";
+    // Might need refining, but hopefully this a generous-enough upper-bound?
+    EXPECT_LT(*value, estimatedSize * 2)
+            << "Expected allocation size to less than double stride * height * 4bpp";
+}
+
+TEST_P(GraphicsMapperStableCTests, GetProtectedContent) {
+    const BufferDescriptorInfo info{
+            .name = {"prot8888"},
+            .width = 64,
+            .height = 64,
+            .layerCount = 1,
+            .format = PixelFormat::RGBA_8888,
+            .usage = BufferUsage::PROTECTED | BufferUsage::COMPOSER_OVERLAY,
+            .reservedSize = 0,
+    };
+    auto buffer = allocate(info);
+    if (!buffer) {
+        ASSERT_FALSE(isSupported(info))
+                << "Allocation of trivial sized buffer failed, so isSupported() must be false";
+        GTEST_SUCCEED() << "PROTECTED RGBA_8888 is unsupported";
+        return;
+    }
+    auto bufferHandle = buffer->import();
+    auto value = getStandardMetadata<StandardMetadataType::PROTECTED_CONTENT>(*bufferHandle);
+    ASSERT_TRUE(value.has_value());
+    EXPECT_EQ(*value, 1);
+}
+
+TEST_P(GraphicsMapperStableCTests, GetCompression) {
+    auto buffer = allocateGeneric();
+    ASSERT_TRUE(buffer);
+    auto bufferHandle = buffer->import();
+    ASSERT_TRUE(bufferHandle);
+    auto value = getStandardMetadata<StandardMetadataType::COMPRESSION>(*bufferHandle);
+    ASSERT_TRUE(value.has_value());
+    EXPECT_EQ(gralloc4::Compression_None.name, value->name);
+    EXPECT_EQ(gralloc4::Compression_None.value, value->value);
+}
+
+TEST_P(GraphicsMapperStableCTests, GetInterlaced) {
+    auto buffer = allocateGeneric();
+    ASSERT_TRUE(buffer);
+    auto bufferHandle = buffer->import();
+    ASSERT_TRUE(bufferHandle);
+    auto value = getStandardMetadata<StandardMetadataType::INTERLACED>(*bufferHandle);
+    ASSERT_TRUE(value.has_value());
+    EXPECT_EQ(gralloc4::Interlaced_None.name, value->name);
+    EXPECT_EQ(gralloc4::Interlaced_None.value, value->value);
+}
+
+TEST_P(GraphicsMapperStableCTests, GetChromaSiting) {
+    auto buffer = allocateGeneric();
+    ASSERT_TRUE(buffer);
+    auto bufferHandle = buffer->import();
+    ASSERT_TRUE(bufferHandle);
+    auto value = getStandardMetadata<StandardMetadataType::CHROMA_SITING>(*bufferHandle);
+    ASSERT_TRUE(value.has_value());
+    EXPECT_EQ(gralloc4::ChromaSiting_None.name, value->name);
+    EXPECT_EQ(gralloc4::ChromaSiting_None.value, value->value);
+}
+
+TEST_P(GraphicsMapperStableCTests, GetPlaneLayouts) {
+    auto buffer = allocateGeneric();
+    ASSERT_TRUE(buffer);
+    auto bufferHandle = buffer->import();
+    ASSERT_TRUE(bufferHandle);
+    auto value = getStandardMetadata<StandardMetadataType::PLANE_LAYOUTS>(*bufferHandle);
+    ASSERT_TRUE(value.has_value());
+    ASSERT_NO_FATAL_FAILURE(verifyRGBA8888PlaneLayouts(*value));
+}
+
+TEST_P(GraphicsMapperStableCTests, GetCrop) {
+    auto buffer = allocateGeneric();
+    ASSERT_TRUE(buffer);
+    auto bufferHandle = buffer->import();
+    ASSERT_TRUE(bufferHandle);
+    auto value = getStandardMetadata<StandardMetadataType::CROP>(*bufferHandle);
+    ASSERT_TRUE(value.has_value());
+    EXPECT_EQ(1, value->size());
+    const Rect expected{0, 0, buffer->info().width, buffer->info().height};
+    EXPECT_EQ(expected, value->at(0));
+}
+
+TEST_P(GraphicsMapperStableCTests, GetSetDataspace) {
+    auto buffer = allocateGeneric();
+    ASSERT_TRUE(buffer);
+    auto bufferHandle = buffer->import();
+    ASSERT_TRUE(bufferHandle);
+    auto value = getStandardMetadata<StandardMetadataType::DATASPACE>(*bufferHandle);
+    ASSERT_TRUE(value.has_value());
+    EXPECT_EQ(Dataspace::UNKNOWN, *value);
+    EXPECT_EQ(AIMAPPER_ERROR_NONE, setStandardMetadata<StandardMetadataType::DATASPACE>(
+                                           *bufferHandle, Dataspace::DISPLAY_P3));
+    value = getStandardMetadata<StandardMetadataType::DATASPACE>(*bufferHandle);
+    ASSERT_TRUE(value.has_value());
+    EXPECT_EQ(Dataspace::DISPLAY_P3, *value);
+}
+
+TEST_P(GraphicsMapperStableCTests, GetSetBlendMode) {
+    auto buffer = allocateGeneric();
+    ASSERT_TRUE(buffer);
+    auto bufferHandle = buffer->import();
+    ASSERT_TRUE(bufferHandle);
+    auto value = getStandardMetadata<StandardMetadataType::BLEND_MODE>(*bufferHandle);
+    ASSERT_TRUE(value.has_value());
+    EXPECT_EQ(BlendMode::INVALID, *value);
+    EXPECT_EQ(AIMAPPER_ERROR_NONE, setStandardMetadata<StandardMetadataType::BLEND_MODE>(
+                                           *bufferHandle, BlendMode::COVERAGE));
+    value = getStandardMetadata<StandardMetadataType::BLEND_MODE>(*bufferHandle);
+    ASSERT_TRUE(value.has_value());
+    EXPECT_EQ(BlendMode::COVERAGE, *value);
+}
+
+TEST_P(GraphicsMapperStableCTests, GetSetSmpte2086) {
+    auto buffer = allocateGeneric();
+    ASSERT_TRUE(buffer);
+    auto bufferHandle = buffer->import();
+    ASSERT_TRUE(bufferHandle);
+    auto value = getStandardMetadata<StandardMetadataType::SMPTE2086>(*bufferHandle);
+    ASSERT_TRUE(value.has_value());
+    EXPECT_FALSE(value->has_value());
+
+    // TODO: Maybe use something resembling real values, but validation isn't supposed to happen
+    // here anyway so :shrug:
+    const Smpte2086 awesomeHdr{
+            XyColor{1.f, 1.f},      XyColor{2.f, 2.f}, XyColor{3.f, 3.f},
+            XyColor{400.f, 1000.f}, 100000.0f,         0.0001f,
+    };
+    EXPECT_EQ(AIMAPPER_ERROR_NONE,
+              setStandardMetadata<StandardMetadataType::SMPTE2086>(*bufferHandle, awesomeHdr));
+    value = getStandardMetadata<StandardMetadataType::SMPTE2086>(*bufferHandle);
+    ASSERT_TRUE(value.has_value());
+    ASSERT_TRUE(value->has_value());
+    EXPECT_EQ(awesomeHdr, *value);
+
+    EXPECT_EQ(AIMAPPER_ERROR_NONE,
+              setStandardMetadata<StandardMetadataType::SMPTE2086>(*bufferHandle, std::nullopt));
+    value = getStandardMetadata<StandardMetadataType::SMPTE2086>(*bufferHandle);
+    ASSERT_TRUE(value.has_value());
+    EXPECT_FALSE(value->has_value());
+}
+
+TEST_P(GraphicsMapperStableCTests, GetCta861_3) {
+    auto buffer = allocateGeneric();
+    ASSERT_TRUE(buffer);
+    auto bufferHandle = buffer->import();
+    ASSERT_TRUE(bufferHandle);
+    auto value = getStandardMetadata<StandardMetadataType::CTA861_3>(*bufferHandle);
+    ASSERT_TRUE(value.has_value());
+    EXPECT_FALSE(value->has_value());
+
+    const Cta861_3 genericHlgish{1000.f, 140.f};
+    EXPECT_EQ(AIMAPPER_ERROR_NONE,
+              setStandardMetadata<StandardMetadataType::CTA861_3>(*bufferHandle, genericHlgish));
+    value = getStandardMetadata<StandardMetadataType::CTA861_3>(*bufferHandle);
+    ASSERT_TRUE(value.has_value());
+    ASSERT_TRUE(value->has_value());
+    EXPECT_EQ(genericHlgish, *value);
+
+    EXPECT_EQ(AIMAPPER_ERROR_NONE,
+              setStandardMetadata<StandardMetadataType::CTA861_3>(*bufferHandle, std::nullopt));
+    value = getStandardMetadata<StandardMetadataType::CTA861_3>(*bufferHandle);
+    ASSERT_TRUE(value.has_value());
+    EXPECT_FALSE(value->has_value());
+}
+
+TEST_P(GraphicsMapperStableCTests, GetSmpte2094_10) {
+    auto buffer = allocateGeneric();
+    ASSERT_TRUE(buffer);
+    auto bufferHandle = buffer->import();
+    ASSERT_TRUE(bufferHandle);
+    auto value = getStandardMetadata<StandardMetadataType::SMPTE2094_10>(*bufferHandle);
+    if (value.has_value()) {
+        EXPECT_FALSE(value->has_value());
+    }
+}
+
+TEST_P(GraphicsMapperStableCTests, GetSmpte2094_40) {
+    auto buffer = allocateGeneric();
+    ASSERT_TRUE(buffer);
+    auto bufferHandle = buffer->import();
+    ASSERT_TRUE(bufferHandle);
+    auto value = getStandardMetadata<StandardMetadataType::SMPTE2094_40>(*bufferHandle);
+    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(
+        int32_t minVersion) {
+    auto instanceNames = getAidlHalInstanceNames(IAllocator::descriptor);
+    std::vector<std::tuple<std::string, std::shared_ptr<IAllocator>>> filteredInstances;
+    filteredInstances.reserve(instanceNames.size());
+    for (const auto& name : instanceNames) {
+        auto allocator =
+                IAllocator::fromBinder(ndk::SpAIBinder(AServiceManager_checkService(name.c_str())));
+        int32_t version = 0;
+        if (allocator->getInterfaceVersion(&version).isOk()) {
+            if (version >= minVersion) {
+                filteredInstances.emplace_back(name, std::move(allocator));
+            }
+        }
+    }
+    return filteredInstances;
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsMapperStableCTests);
+INSTANTIATE_TEST_CASE_P(PerInstance, GraphicsMapperStableCTests,
+                        testing::ValuesIn(getIAllocatorsAtLeastVersion(2)),
+                        [](auto info) -> std::string {
+                            std::string name =
+                                    std::to_string(info.index) + "/" + std::get<0>(info.param);
+                            return Sanitize(name);
+                        });
\ No newline at end of file
diff --git a/identity/aidl/Android.bp b/identity/aidl/Android.bp
index 57451ed..2090473 100644
--- a/identity/aidl/Android.bp
+++ b/identity/aidl/Android.bp
@@ -14,10 +14,11 @@
         "android/hardware/identity/*.aidl",
     ],
     imports: [
-        "android.hardware.keymaster",
-        "android.hardware.security.keymint",
+        "android.hardware.keymaster-V3",
+        "android.hardware.security.rkp-V3",
     ],
     stability: "vintf",
+    frozen: true,
     backend: {
         java: {
             platform_apis: true,
@@ -31,28 +32,28 @@
             version: "1",
             imports: [
                 "android.hardware.keymaster-V3",
-                "android.hardware.security.keymint-V1",
+                "android.hardware.security.rkp-V1",
             ],
         },
         {
             version: "2",
             imports: [
                 "android.hardware.keymaster-V3",
-                "android.hardware.security.keymint-V1",
+                "android.hardware.security.rkp-V1",
             ],
         },
         {
             version: "3",
             imports: [
                 "android.hardware.keymaster-V3",
-                "android.hardware.security.keymint-V1",
+                "android.hardware.security.rkp-V1",
             ],
         },
         {
             version: "4",
             imports: [
                 "android.hardware.keymaster-V3",
-                "android.hardware.security.keymint-V2",
+                "android.hardware.security.rkp-V3",
             ],
         },
 
diff --git a/identity/aidl/default/Android.bp b/identity/aidl/default/Android.bp
index a57875a..7bc3c8d 100644
--- a/identity/aidl/default/Android.bp
+++ b/identity/aidl/default/Android.bp
@@ -45,6 +45,7 @@
         "libpuresoftkeymasterdevice",
         "android.hardware.identity-support-lib",
         "android.hardware.keymaster-V3-ndk",
+        "android.hardware.security.rkp-V3-ndk",
     ],
 }
 
@@ -112,6 +113,7 @@
         "android.hardware.keymaster-V3-ndk",
         "android.hardware.identity-libeic-hal-common",
         "android.hardware.identity-libeic-library",
+        "android.hardware.security.rkp-V3-ndk",
     ],
     srcs: [
         "service.cpp",
diff --git a/identity/aidl/default/EicOpsImpl.cc b/identity/aidl/default/EicOpsImpl.cc
index b6d324f..803df64 100644
--- a/identity/aidl/default/EicOpsImpl.cc
+++ b/identity/aidl/default/EicOpsImpl.cc
@@ -489,7 +489,7 @@
 }
 
 bool eicOpsEcdh(const uint8_t publicKey[EIC_P256_PUB_KEY_SIZE],
-                const uint8_t privateKey[EIC_P256_PUB_KEY_SIZE],
+                const uint8_t privateKey[EIC_P256_PRIV_KEY_SIZE],
                 uint8_t sharedSecret[EIC_P256_COORDINATE_SIZE]) {
     vector<uint8_t> pubKeyVec(EIC_P256_PUB_KEY_SIZE + 1);
     pubKeyVec[0] = 0x04;
diff --git a/identity/aidl/default/android.hardware.identity_credential.xml b/identity/aidl/default/android.hardware.identity_credential.xml
index 20b2710..a49ddca 100644
--- a/identity/aidl/default/android.hardware.identity_credential.xml
+++ b/identity/aidl/default/android.hardware.identity_credential.xml
@@ -14,5 +14,5 @@
      limitations under the License.
 -->
 <permissions>
-  <feature name="android.hardware.identity_credential" version="202201" />
+  <feature name="android.hardware.identity_credential" version="202301" />
 </permissions>
diff --git a/identity/aidl/vts/Android.bp b/identity/aidl/vts/Android.bp
index dd29819..5e303bb 100644
--- a/identity/aidl/vts/Android.bp
+++ b/identity/aidl/vts/Android.bp
@@ -39,6 +39,8 @@
         "libcrypto",
     ],
     static_libs: [
+        "android.hardware.security.rkp-V3-cpp",
+        "android.hardware.security.rkp-V3-ndk",
         "android.hardware.security.secureclock-V1-ndk",
         "libcppbor_external",
         "libcppcose_rkp",
@@ -59,3 +61,16 @@
     ],
     require_root: true,
 }
+
+java_test_host {
+    name: "IdentityCredentialImplementedTest",
+    libs: [
+        "tradefed",
+        "vts-core-tradefed-harness",
+    ],
+    srcs: ["src/**/*.java"],
+    test_suites: [
+        "vts",
+    ],
+    test_config: "IdentityCredentialImplementedTest.xml",
+}
diff --git a/identity/aidl/vts/IdentityCredentialImplementedTest.xml b/identity/aidl/vts/IdentityCredentialImplementedTest.xml
new file mode 100644
index 0000000..4276ae6
--- /dev/null
+++ b/identity/aidl/vts/IdentityCredentialImplementedTest.xml
@@ -0,0 +1,22 @@
+<?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.
+-->
+<configuration description="Runs IdentityCredentialImplementedTest">
+  <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
+
+  <test class="com.android.tradefed.testtype.HostTest" >
+    <option name="jar" value="IdentityCredentialImplementedTest.jar" />
+  </test>
+</configuration>
diff --git a/identity/aidl/vts/src/com/android/tests/security/identity/IdentityCredentialImplementedTest.java b/identity/aidl/vts/src/com/android/tests/security/identity/IdentityCredentialImplementedTest.java
new file mode 100644
index 0000000..4936f8c
--- /dev/null
+++ b/identity/aidl/vts/src/com/android/tests/security/identity/IdentityCredentialImplementedTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tests.security.identity;
+
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
+
+import android.platform.test.annotations.RequiresDevice;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+// This is a host-test which executes shell commands on the device. It would be
+// nicer to have this be a Device test (like CTS) but this is currently not
+// possible, see https://source.android.com/docs/core/tests/vts
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class IdentityCredentialImplementedTest extends BaseHostJUnit4Test {
+    // Returns the ro.vendor.api_level or 0 if not set.
+    //
+    // Throws NumberFormatException if ill-formatted.
+    //
+    // Throws DeviceNotAvailableException if device is not available.
+    //
+    private int getVendorApiLevel() throws NumberFormatException, DeviceNotAvailableException {
+        String vendorApiLevelString =
+                getDevice().executeShellCommand("getprop ro.vendor.api_level").trim();
+        if (vendorApiLevelString.isEmpty()) {
+            return 0;
+        }
+        return Integer.parseInt(vendorApiLevelString);
+    }
+
+    // As of Android 14 VSR (vendor API level 34), Identity Credential is required at feature
+    // version 202301 or later.
+    @RequiresDevice
+    @Test
+    public void testIdentityCredentialIsImplemented() throws Exception {
+        int vendorApiLevel = getVendorApiLevel();
+        assumeTrue(vendorApiLevel >= 34);
+
+        final String minimumFeatureVersionNeeded = "202301";
+
+        String result = getDevice().executeShellCommand(
+                "pm has-feature android.hardware.identity_credential "
+                + minimumFeatureVersionNeeded);
+        if (!result.trim().equals("true")) {
+            fail("Identity Credential feature version " + minimumFeatureVersionNeeded
+                    + " required but not found");
+        }
+    }
+}
diff --git a/input/common/aidl/Android.bp b/input/common/aidl/Android.bp
index 390d8b5..95a14b2 100644
--- a/input/common/aidl/Android.bp
+++ b/input/common/aidl/Android.bp
@@ -9,6 +9,7 @@
 
 aidl_interface {
     name: "android.hardware.input.common",
+    host_supported: true,
     vendor_available: true,
     srcs: ["android/hardware/input/common/*.aidl"],
     stability: "vintf",
diff --git a/input/processor/aidl/Android.bp b/input/processor/aidl/Android.bp
index 354816e..773bb49 100644
--- a/input/processor/aidl/Android.bp
+++ b/input/processor/aidl/Android.bp
@@ -9,6 +9,7 @@
 
 aidl_interface {
     name: "android.hardware.input.processor",
+    host_supported: true,
     vendor_available: true,
     srcs: ["android/hardware/input/processor/*.aidl"],
     imports: [
diff --git a/ir/aidl/default/Android.bp b/ir/aidl/default/Android.bp
index a4fb439..a8096c2 100644
--- a/ir/aidl/default/Android.bp
+++ b/ir/aidl/default/Android.bp
@@ -36,6 +36,7 @@
         "liblog",
         "libutils",
         "android.hardware.ir-V1-ndk",
+        "libhardware"
     ],
 
     srcs: ["main.cpp"],
diff --git a/ir/aidl/default/android.hardware.ir-service.example.rc b/ir/aidl/default/android.hardware.ir-service.example.rc
index 56def64..d27f282 100644
--- a/ir/aidl/default/android.hardware.ir-service.example.rc
+++ b/ir/aidl/default/android.hardware.ir-service.example.rc
@@ -1,4 +1,4 @@
 service vendor.ir-default /vendor/bin/hw/android.hardware.ir-service.example
     class hal
-    user nobody
-    group nobody
+    user system
+    group system
diff --git a/ir/aidl/default/main.cpp b/ir/aidl/default/main.cpp
index 7c4a816..92376fc 100644
--- a/ir/aidl/default/main.cpp
+++ b/ir/aidl/default/main.cpp
@@ -15,49 +15,77 @@
  */
 
 #include <aidl/android/hardware/ir/BnConsumerIr.h>
+#include <aidl/android/hardware/ir/ConsumerIrFreqRange.h>
 #include <android-base/logging.h>
 #include <android/binder_interface_utils.h>
 #include <android/binder_manager.h>
 #include <android/binder_process.h>
+#include <hardware/consumerir.h>
 #include <numeric>
 
+#include <log/log.h>
+
+using ::aidl::android::hardware::ir::ConsumerIrFreqRange;
+
 namespace aidl::android::hardware::ir {
 
-const std::vector<ConsumerIrFreqRange> kSupportedFreqs = {
-        {2000, 4000},
-        {10000, 30000},
-};
-
 class ConsumerIr : public BnConsumerIr {
+  public:
+    ConsumerIr();
+  private:
     ::ndk::ScopedAStatus getCarrierFreqs(std::vector<ConsumerIrFreqRange>* _aidl_return) override;
     ::ndk::ScopedAStatus transmit(int32_t in_carrierFreqHz,
                                   const std::vector<int32_t>& in_pattern) override;
+    consumerir_device_t *mDevice = nullptr;
 };
 
-::ndk::ScopedAStatus ConsumerIr::getCarrierFreqs(std::vector<ConsumerIrFreqRange>* _aidl_return) {
-    *_aidl_return = kSupportedFreqs;
-    return ::ndk::ScopedAStatus::ok();
+ConsumerIr::ConsumerIr() {
+    const hw_module_t *hw_module = NULL;
+
+    int ret = hw_get_module(CONSUMERIR_HARDWARE_MODULE_ID, &hw_module);
+    if (ret != 0) {
+        ALOGE("hw_get_module %s failed: %d", CONSUMERIR_HARDWARE_MODULE_ID, ret);
+        return;
+    }
+    ret = hw_module->methods->open(hw_module, CONSUMERIR_TRANSMITTER, (hw_device_t **) &mDevice);
+    if (ret < 0) {
+        // note - may want to make this a fatal error - otherwise the service will crash when it's used
+        ALOGE("Can't open consumer IR transmitter, error: %d", ret);
+        // in case it's modified
+        mDevice = nullptr;
+    }
 }
 
-bool isSupportedFreq(int32_t freq) {
-    for (const auto& range : kSupportedFreqs) {
-        if (freq >= range.minHz && freq <= range.maxHz) return true;
+::ndk::ScopedAStatus ConsumerIr::getCarrierFreqs(std::vector<ConsumerIrFreqRange>* _aidl_return) {
+    int32_t len = mDevice->get_num_carrier_freqs(mDevice);
+    if (len < 0) {
+        (*_aidl_return).clear();
+        return ::ndk::ScopedAStatus::ok();
     }
-    return false;
+
+    consumerir_freq_range_t *rangeAr = new consumerir_freq_range_t[len];
+    bool success = (mDevice->get_carrier_freqs(mDevice, len, rangeAr) >= 0);
+    if (!success) {
+        (*_aidl_return).clear();
+        return ::ndk::ScopedAStatus::ok();
+    }
+
+    (*_aidl_return).resize(len);
+    for (int32_t i = 0; i < len; i++) {
+        (*_aidl_return)[i].minHz = static_cast<uint32_t>(rangeAr[i].min);
+        (*_aidl_return)[i].maxHz = static_cast<uint32_t>(rangeAr[i].max);
+    }
+    return ::ndk::ScopedAStatus::ok();
 }
 
 ::ndk::ScopedAStatus ConsumerIr::transmit(int32_t in_carrierFreqHz,
                                           const std::vector<int32_t>& in_pattern) {
-    if (isSupportedFreq(in_carrierFreqHz)) {
-        // trasmit the pattern, each integer is number of microseconds in an
-        // alternating on/off state.
-        usleep(std::accumulate(in_pattern.begin(), in_pattern.end(), 0));
+    if (in_carrierFreqHz > 0) {
+        mDevice->transmit(mDevice, in_carrierFreqHz, in_pattern.data(), in_pattern.size());
         return ::ndk::ScopedAStatus::ok();
     } else {
-        // unsupported operation
         return ::ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
     }
-    return ::ndk::ScopedAStatus::ok();
 }
 
 }  // namespace aidl::android::hardware::ir
diff --git a/keymaster/3.0/default/OWNERS b/keymaster/3.0/default/OWNERS
deleted file mode 100644
index 335660d..0000000
--- a/keymaster/3.0/default/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-jdanis@google.com
-swillden@google.com
diff --git a/keymaster/3.0/vts/OWNERS b/keymaster/3.0/vts/OWNERS
deleted file mode 100644
index 846bb84..0000000
--- a/keymaster/3.0/vts/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-drysdale@google.com
-jdanis@google.com
-swillden@google.com
-yim@google.com
-yuexima@google.com
diff --git a/keymaster/3.0/vts/functional/OWNERS b/keymaster/3.0/vts/functional/OWNERS
deleted file mode 100644
index 2ef9086..0000000
--- a/keymaster/3.0/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 189335
-swillden@google.com
diff --git a/keymaster/4.0/default/OWNERS b/keymaster/4.0/default/OWNERS
deleted file mode 100644
index 335660d..0000000
--- a/keymaster/4.0/default/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-jdanis@google.com
-swillden@google.com
diff --git a/keymaster/4.0/support/OWNERS b/keymaster/4.0/support/OWNERS
deleted file mode 100644
index a9efe66..0000000
--- a/keymaster/4.0/support/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-jdanis@google.com
-swillden@google.com
-jbires@google.com
diff --git a/keymaster/4.0/vts/OWNERS b/keymaster/4.0/vts/OWNERS
deleted file mode 100644
index 0d6fa6c..0000000
--- a/keymaster/4.0/vts/OWNERS
+++ /dev/null
@@ -1,6 +0,0 @@
-drysdale@google.com
-jbires@google.com
-jdanis@google.com
-swillden@google.com
-yim@google.com
-yuexima@google.com
diff --git a/keymaster/4.0/vts/functional/OWNERS b/keymaster/4.0/vts/functional/OWNERS
deleted file mode 100644
index 2ef9086..0000000
--- a/keymaster/4.0/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 189335
-swillden@google.com
diff --git a/keymaster/4.1/default/OWNERS b/keymaster/4.1/default/OWNERS
deleted file mode 100644
index 2b2ad2a..0000000
--- a/keymaster/4.1/default/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-jbires@google.com
-jdanis@google.com
-swillden@google.com
-zeuthen@google.com
\ No newline at end of file
diff --git a/keymaster/4.1/support/OWNERS b/keymaster/4.1/support/OWNERS
deleted file mode 100644
index 2b2ad2a..0000000
--- a/keymaster/4.1/support/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-jbires@google.com
-jdanis@google.com
-swillden@google.com
-zeuthen@google.com
\ No newline at end of file
diff --git a/keymaster/4.1/vts/OWNERS b/keymaster/4.1/vts/OWNERS
deleted file mode 100644
index 24ed042..0000000
--- a/keymaster/4.1/vts/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-drysdale@google.com
-jbires@google.com
-jdanis@google.com
-swillden@google.com
-zeuthen@google.com
\ No newline at end of file
diff --git a/keymaster/4.1/vts/functional/OWNERS b/keymaster/4.1/vts/functional/OWNERS
deleted file mode 100644
index 2ef9086..0000000
--- a/keymaster/4.1/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 189335
-swillden@google.com
diff --git a/keymaster/OWNERS b/keymaster/OWNERS
new file mode 100644
index 0000000..ac8bd83
--- /dev/null
+++ b/keymaster/OWNERS
@@ -0,0 +1,14 @@
+# Bug component: 1084733
+
+# Please assign all bugs related to /hardware/interfaces/keymaster to the team alias:
+#
+#    android-hardware-security@google.com
+#
+# This will get them auto-assigned to the on-call triage engineer, ensuring quickest response.
+
+drysdale@google.com
+eranm@google.com
+hasinitg@google.com
+jbires@google.com
+swillden@google.com
+zeuthen@google.com
diff --git a/keymaster/aidl/Android.bp b/keymaster/aidl/Android.bp
index 0fb6e4c..a3800c1 100644
--- a/keymaster/aidl/Android.bp
+++ b/keymaster/aidl/Android.bp
@@ -19,9 +19,18 @@
             platform_apis: true,
         },
     },
-    versions: [
-        "1",
-        "2",
-        "3",
+    versions_with_info: [
+        {
+            version: "1",
+            imports: [],
+        },
+        {
+            version: "2",
+            imports: [],
+        },
+        {
+            version: "3",
+            imports: [],
+        },
     ],
 }
diff --git a/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/HardwareAuthToken.aidl b/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/HardwareAuthToken.aidl
index 4f21cba..6e84e98 100644
--- a/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/HardwareAuthToken.aidl
+++ b/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/HardwareAuthToken.aidl
@@ -1,14 +1,30 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
+// 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 changes to the AIDL files built
+// 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
@@ -16,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.keymaster;
+/* @hide */
 @VintfStability
 parcelable HardwareAuthToken {
   long challenge;
diff --git a/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/HardwareAuthenticatorType.aidl b/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/HardwareAuthenticatorType.aidl
index 924567f..0a40549 100644
--- a/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/HardwareAuthenticatorType.aidl
+++ b/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/HardwareAuthenticatorType.aidl
@@ -1,14 +1,30 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
+// 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 changes to the AIDL files built
+// 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
@@ -16,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.keymaster;
+/* @hide */
 @Backing(type="int") @VintfStability
 enum HardwareAuthenticatorType {
   NONE = 0,
diff --git a/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/SecurityLevel.aidl b/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/SecurityLevel.aidl
index 127c1bf..d32ef68 100644
--- a/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/SecurityLevel.aidl
+++ b/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/SecurityLevel.aidl
@@ -1,14 +1,30 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
+// 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 changes to the AIDL files built
+// 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
@@ -16,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.keymaster;
+/* @hide */
 @Backing(type="int") @VintfStability
 enum SecurityLevel {
   SOFTWARE = 0,
diff --git a/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/Timestamp.aidl b/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/Timestamp.aidl
index 45fa1ae..5b7b37a 100644
--- a/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/Timestamp.aidl
+++ b/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/Timestamp.aidl
@@ -1,14 +1,30 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
+// 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 changes to the AIDL files built
+// 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
@@ -16,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.keymaster;
+/* @hide */
 @VintfStability
 parcelable Timestamp {
   long milliSeconds;
diff --git a/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/VerificationToken.aidl b/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/VerificationToken.aidl
index b116dac..10fa5e1 100644
--- a/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/VerificationToken.aidl
+++ b/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/VerificationToken.aidl
@@ -1,14 +1,30 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
+// 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 changes to the AIDL files built
+// 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
@@ -16,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.keymaster;
+/* @hide */
 @VintfStability
 parcelable VerificationToken {
   long challenge;
diff --git a/keymaster/aidl/android/hardware/keymaster/HardwareAuthToken.aidl b/keymaster/aidl/android/hardware/keymaster/HardwareAuthToken.aidl
index 99b036a..427c192 100644
--- a/keymaster/aidl/android/hardware/keymaster/HardwareAuthToken.aidl
+++ b/keymaster/aidl/android/hardware/keymaster/HardwareAuthToken.aidl
@@ -16,8 +16,8 @@
 
 package android.hardware.keymaster;
 
-import android.hardware.keymaster.Timestamp;
 import android.hardware.keymaster.HardwareAuthenticatorType;
+import android.hardware.keymaster.Timestamp;
 
 /**
  * HardwareAuthToken is used to prove successful user authentication, to unlock the use of a key.
@@ -27,10 +27,10 @@
  * begin(), update(), and finish() to prove that authentication occurred.  See those methods for
  * more details.  It is up to the caller to determine which of the generated auth tokens is
  * appropriate for a given key operation.
+ * @hide
  */
 @VintfStability
 parcelable HardwareAuthToken {
-
     /**
      * challenge is a value that's used to enable authentication tokens to authorize specific
      * events.  The primary use case for challenge is to authorize an IKeymasterDevice cryptographic
@@ -49,7 +49,7 @@
      *  but is created in an authentication application in the secure environment, such as the
      *  Fingerprint application.
      */
-    long authenticatorId;  // Secure authenticator ID.
+    long authenticatorId; // Secure authenticator ID.
 
     /**
      * authenticatorType describes the type of authentication that took place, e.g. password or
diff --git a/keymaster/aidl/android/hardware/keymaster/HardwareAuthenticatorType.aidl b/keymaster/aidl/android/hardware/keymaster/HardwareAuthenticatorType.aidl
index 3141858..7a303a7 100644
--- a/keymaster/aidl/android/hardware/keymaster/HardwareAuthenticatorType.aidl
+++ b/keymaster/aidl/android/hardware/keymaster/HardwareAuthenticatorType.aidl
@@ -20,6 +20,7 @@
  * Hardware authentication type, used by HardwareAuthTokens to specify the mechanism used to
  * authentiate the user, and in KeyCharacteristics to specify the allowable mechanisms for
  * authenticating to activate a key.
+ * @hide
  */
 @VintfStability
 @Backing(type="int")
diff --git a/keymaster/aidl/android/hardware/keymaster/SecurityLevel.aidl b/keymaster/aidl/android/hardware/keymaster/SecurityLevel.aidl
index 00578a4..0b84392 100644
--- a/keymaster/aidl/android/hardware/keymaster/SecurityLevel.aidl
+++ b/keymaster/aidl/android/hardware/keymaster/SecurityLevel.aidl
@@ -18,6 +18,7 @@
 
 /**
  * Device security levels.
+ * @hide
  */
 @VintfStability
 @Backing(type="int")
diff --git a/keymaster/aidl/android/hardware/keymaster/Timestamp.aidl b/keymaster/aidl/android/hardware/keymaster/Timestamp.aidl
index 19ea944..0b0c36f 100644
--- a/keymaster/aidl/android/hardware/keymaster/Timestamp.aidl
+++ b/keymaster/aidl/android/hardware/keymaster/Timestamp.aidl
@@ -16,14 +16,13 @@
 
 package android.hardware.keymaster;
 
-
 /**
  * Time in milliseconds since some arbitrary point in time.  Time must be monotonically increasing,
  * and a secure environment's notion of "current time" must not repeat until the Android device
  * reboots, or until at least 50 million years have elapsed (note that this requirement is satisfied
  * by setting the clock to zero during each boot, and then counting time accurately).
+ * @hide
  */
-
 @VintfStability
 parcelable Timestamp {
     long milliSeconds;
diff --git a/keymaster/aidl/android/hardware/keymaster/VerificationToken.aidl b/keymaster/aidl/android/hardware/keymaster/VerificationToken.aidl
index 5efd937..ceee941 100644
--- a/keymaster/aidl/android/hardware/keymaster/VerificationToken.aidl
+++ b/keymaster/aidl/android/hardware/keymaster/VerificationToken.aidl
@@ -24,6 +24,7 @@
  *
  * This version of the parcelable currently don't use the parametersVerified field since it's not
  * needed for time-based verification. This can be added in a later version, if needed.
+ * @hide
  */
 @VintfStability
 parcelable VerificationToken {
@@ -39,7 +40,6 @@
      */
     Timestamp timestamp;
 
-
     /**
      * SecurityLevel of the secure environment that generated the token.
      */
diff --git a/media/bufferpool/aidl/Android.bp b/media/bufferpool/aidl/Android.bp
new file mode 100644
index 0000000..68ac489
--- /dev/null
+++ b/media/bufferpool/aidl/Android.bp
@@ -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 {
+    // 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.bufferpool2",
+    vendor_available: true,
+    srcs: ["android/hardware/media/bufferpool2/*.aidl"],
+    imports: [
+        "android.hardware.common-V2",
+        "android.hardware.common.fmq-V1",
+    ],
+    stability: "vintf",
+    backend: {
+        cpp: {
+            enabled: false,
+        },
+        java: {
+            enabled: false,
+        },
+        ndk: {
+            enabled: true,
+        },
+    },
+}
diff --git a/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/Buffer.aidl b/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/Buffer.aidl
new file mode 100644
index 0000000..4ea0bba
--- /dev/null
+++ b/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/Buffer.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.media.bufferpool2;
+@VintfStability
+parcelable Buffer {
+  int id;
+  android.hardware.common.NativeHandle buffer;
+}
diff --git a/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/BufferInvalidationMessage.aidl b/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/BufferInvalidationMessage.aidl
new file mode 100644
index 0000000..181286c
--- /dev/null
+++ b/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/BufferInvalidationMessage.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.media.bufferpool2;
+@FixedSize @VintfStability
+parcelable BufferInvalidationMessage {
+  int messageId;
+  int fromBufferId;
+  int toBufferId;
+}
diff --git a/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/BufferStatus.aidl b/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/BufferStatus.aidl
new file mode 100644
index 0000000..13174ff
--- /dev/null
+++ b/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/BufferStatus.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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.media.bufferpool2;
+@Backing(type="int") @VintfStability
+enum BufferStatus {
+  NOT_USED = 0,
+  USED = 1,
+  TRANSFER_TO = 2,
+  TRANSFER_FROM = 3,
+  TRANSFER_TIMEOUT = 4,
+  TRANSFER_LOST = 5,
+  TRANSFER_FETCH = 6,
+  TRANSFER_OK = 7,
+  TRANSFER_ERROR = 8,
+  INVALIDATION_ACK = 9,
+}
diff --git a/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/BufferStatusMessage.aidl b/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/BufferStatusMessage.aidl
new file mode 100644
index 0000000..7e79a36
--- /dev/null
+++ b/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/BufferStatusMessage.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.media.bufferpool2;
+@FixedSize @VintfStability
+parcelable BufferStatusMessage {
+  long transactionId;
+  int bufferId;
+  android.hardware.media.bufferpool2.BufferStatus status;
+  long connectionId;
+  long targetConnectionId;
+  long timestampUs;
+}
diff --git a/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/IAccessor.aidl b/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/IAccessor.aidl
new file mode 100644
index 0000000..4053797
--- /dev/null
+++ b/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/IAccessor.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.media.bufferpool2;
+@VintfStability
+interface IAccessor {
+  android.hardware.media.bufferpool2.IAccessor.ConnectionInfo connect(in android.hardware.media.bufferpool2.IObserver observer);
+  @VintfStability
+  parcelable ConnectionInfo {
+    android.hardware.media.bufferpool2.IConnection connection;
+    long connectionId;
+    int msgId;
+    android.hardware.common.fmq.MQDescriptor<android.hardware.media.bufferpool2.BufferStatusMessage,android.hardware.common.fmq.SynchronizedReadWrite> toFmqDesc;
+    android.hardware.common.fmq.MQDescriptor<android.hardware.media.bufferpool2.BufferInvalidationMessage,android.hardware.common.fmq.UnsynchronizedWrite> fromFmqDesc;
+  }
+}
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
new file mode 100644
index 0000000..54896d4
--- /dev/null
+++ b/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/IClientManager.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.media.bufferpool2;
+@VintfStability
+interface IClientManager {
+  long registerSender(in android.hardware.media.bufferpool2.IAccessor bufferPool);
+}
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
new file mode 100644
index 0000000..300fcba
--- /dev/null
+++ b/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/IConnection.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.media.bufferpool2;
+@VintfStability
+interface IConnection {
+  android.hardware.media.bufferpool2.IConnection.FetchResult[] fetch(in android.hardware.media.bufferpool2.IConnection.FetchInfo[] fetchInfos);
+  parcelable FetchInfo {
+    long transactionId;
+    int bufferId;
+  }
+  union FetchResult {
+    android.hardware.media.bufferpool2.Buffer buffer;
+    android.hardware.media.bufferpool2.ResultStatus failure;
+  }
+}
diff --git a/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/IObserver.aidl b/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/IObserver.aidl
new file mode 100644
index 0000000..2d8cffe
--- /dev/null
+++ b/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/IObserver.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.media.bufferpool2;
+@VintfStability
+interface IObserver {
+  oneway void onMessage(in long connectionId, in int msgId);
+}
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
new file mode 100644
index 0000000..7370998
--- /dev/null
+++ b/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/ResultStatus.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.media.bufferpool2;
+@VintfStability
+parcelable ResultStatus {
+  int resultStatus;
+  const int OK = 0;
+  const int NO_MEMORY = 1;
+  const int ALREADY_EXISTS = 2;
+  const int NOT_FOUND = 3;
+  const int CRITICAL_ERROR = 4;
+}
diff --git a/media/bufferpool/aidl/android/hardware/media/bufferpool2/Buffer.aidl b/media/bufferpool/aidl/android/hardware/media/bufferpool2/Buffer.aidl
new file mode 100644
index 0000000..976f674
--- /dev/null
+++ b/media/bufferpool/aidl/android/hardware/media/bufferpool2/Buffer.aidl
@@ -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.
+ */
+
+package android.hardware.media.bufferpool2;
+
+import android.hardware.common.NativeHandle;
+
+/**
+ * Generic buffer for fast recycling for media/stagefright.
+ *
+ * During media pipeline buffer references are created, shared and
+ * destroyed frequently. The underlying buffers are allocated on demand
+ * by a buffer pool, and are recycled to the buffer pool when they are
+ * no longer referenced by the clients.
+ *
+ * E.g. ion or gralloc buffer
+ */
+@VintfStability
+parcelable Buffer {
+    int id;
+    NativeHandle buffer;
+}
diff --git a/media/bufferpool/aidl/android/hardware/media/bufferpool2/BufferInvalidationMessage.aidl b/media/bufferpool/aidl/android/hardware/media/bufferpool2/BufferInvalidationMessage.aidl
new file mode 100644
index 0000000..ad03cd5
--- /dev/null
+++ b/media/bufferpool/aidl/android/hardware/media/bufferpool2/BufferInvalidationMessage.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.media.bufferpool2;
+
+/*
+ * Buffer pool sends a buffer invalidation message to clients in order to
+ * ensure fast reclamation of the buffers. Buffer pool implementation on
+ * clients must release the invalidated buffers right away after finishing
+ * the use of buffers upon receiving a buffer invalidation message.
+ * Users cannot delay or control timing of the handling/reception of
+ * invalidation messages. Buffer pool implementation must guarantee timely
+ * handling of invalidation messages.
+ */
+@VintfStability
+@FixedSize
+parcelable BufferInvalidationMessage {
+    int messageId;
+    /**
+     * Buffers from fromBufferId to toBufferId must be invalidated.
+     * fromBufferId is inclusive, but toBufferId is not inclusive.
+     * If fromBufferId > toBufferID, wrap happens. In that case
+     * the wrap is based on UINT32_MAX.
+     */
+    int fromBufferId;
+    int toBufferId;
+}
diff --git a/media/bufferpool/aidl/android/hardware/media/bufferpool2/BufferStatus.aidl b/media/bufferpool/aidl/android/hardware/media/bufferpool2/BufferStatus.aidl
new file mode 100644
index 0000000..b63aee2
--- /dev/null
+++ b/media/bufferpool/aidl/android/hardware/media/bufferpool2/BufferStatus.aidl
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.bufferpool2;
+
+/**
+ * Buffer ownership status for the specified client.
+ * Buffer transfer status for the specified buffer transafer transaction.
+ * BufferStatus is posted along with BufferStatusMessage from a client to
+ * the buffer pool for synchronization after status change.
+ */
+@VintfStability
+@Backing(type="int")
+enum BufferStatus {
+    /**
+     * No longer used by the specified client.
+     */
+    NOT_USED = 0,
+    /**
+     * Buffer is acquired by the specified client.
+     */
+    USED = 1,
+    /**
+     * Buffer is sent by the specified client.
+     */
+    TRANSFER_TO = 2,
+    /**
+     * Buffer transfer is acked by the receiver client.
+     */
+    TRANSFER_FROM = 3,
+    /**
+     * Buffer transfer is timed out by receiver client.
+     */
+    TRANSFER_TIMEOUT = 4,
+    /**
+     * Buffer transfer is not acked by the receiver.
+     */
+    TRANSFER_LOST = 5,
+    /**
+     * Buffer fetch request from the client.
+     */
+    TRANSFER_FETCH = 6,
+    /**
+     * Buffer transaction succeeded.
+     */
+    TRANSFER_OK = 7,
+    /**
+     * Buffer transaction failure.
+     */
+    TRANSFER_ERROR = 8,
+    /**
+     * Buffer invalidation ack.
+     */
+    INVALIDATION_ACK = 9,
+}
diff --git a/media/bufferpool/aidl/android/hardware/media/bufferpool2/BufferStatusMessage.aidl b/media/bufferpool/aidl/android/hardware/media/bufferpool2/BufferStatusMessage.aidl
new file mode 100644
index 0000000..e3fd8f0
--- /dev/null
+++ b/media/bufferpool/aidl/android/hardware/media/bufferpool2/BufferStatusMessage.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.media.bufferpool2;
+
+import android.hardware.media.bufferpool2.BufferStatus;
+
+/**
+ * Buffer ownership status change message. This message is
+ * sent via fmq to the buffer pool from client processes.
+ */
+@VintfStability
+@FixedSize
+parcelable BufferStatusMessage {
+    /**
+     * Transaction Id = (SenderId : sender local transaction Id)
+     * Transaction Id is created from sender and posted via fmq within
+     * TRANSFER_TO message.
+     */
+    long transactionId;
+    int bufferId;
+    BufferStatus status;
+    /**
+     * Used by the buffer pool, not by client.
+     */
+    long connectionId;
+    /**
+     * Valid only when TRANSFER_TO is posted.
+     */
+    long targetConnectionId;
+    /**
+     * Used by the buffer pool, not by client.
+     * Monotonic timestamp in Us since fixed point in time as decided
+     * by the sender of the message
+     */
+    long timestampUs;
+}
diff --git a/media/bufferpool/aidl/android/hardware/media/bufferpool2/IAccessor.aidl b/media/bufferpool/aidl/android/hardware/media/bufferpool2/IAccessor.aidl
new file mode 100644
index 0000000..0fa5961
--- /dev/null
+++ b/media/bufferpool/aidl/android/hardware/media/bufferpool2/IAccessor.aidl
@@ -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.
+ */
+
+package android.hardware.media.bufferpool2;
+
+import android.hardware.common.fmq.MQDescriptor;
+import android.hardware.common.fmq.SynchronizedReadWrite;
+import android.hardware.common.fmq.UnsynchronizedWrite;
+
+
+import android.hardware.media.bufferpool2.BufferInvalidationMessage;
+import android.hardware.media.bufferpool2.BufferStatusMessage;
+import android.hardware.media.bufferpool2.IConnection;
+import android.hardware.media.bufferpool2.IObserver;
+
+/**
+ * IAccessor creates IConnection which is used from IClientManager in order to
+ * use functionality of the specified buffer pool.
+ */
+@VintfStability
+interface IAccessor {
+    @VintfStability
+     /**
+     * Connection information between the bufferpool process and the receiver
+     * process. The information is used from the receiver process in order to
+     * receive buffers from the bufferpool process.
+     */
+    parcelable ConnectionInfo {
+        /**
+        * The interface to get shared buffers from the bufferpool.
+        */
+        IConnection connection;
+        /**
+         * The identifier for a (sender/receiver) pair during buffer transfer.
+         * This is system wide unique.
+         */
+        long connectionId;
+        /**
+         * Id of the most recent message from bufferpool. This is monotonic.
+         */
+        int msgId;
+        /**
+         * The FMQ descriptor for sending buffer status messages back to bufferpool
+         */
+        MQDescriptor<BufferStatusMessage, SynchronizedReadWrite> toFmqDesc;
+        /**
+         * The FMQ descriptor for receiving buffer invalidation messages from bufferpool
+         */
+        MQDescriptor<BufferInvalidationMessage, UnsynchronizedWrite> fromFmqDesc;
+    }
+
+    /**
+     * Registers a new client and creates IConnection to the buffer pool for
+     * the client. IConnection and FMQ are used by IClientManager in order to
+     * communicate with the buffer pool. Via FMQ IClientManager sends
+     * BufferStatusMessage(s) to the buffer pool.
+     *
+     * FMQ is used to send buffer ownership status changes to a buffer pool
+     * from a buffer pool client. A buffer pool synchronizes FMQ messages when
+     * there is an aidl request from the clients. Every client has its own
+     * connection and FMQ to communicate with the buffer pool. So sending an
+     * FMQ message on behalf of other clients is not possible.
+     *
+     * FMQ messages are sent when a buffer is acquired or released. Also, FMQ
+     * messages are sent when a buffer is transferred from a client to another
+     * client. FMQ has its own ID from a buffer pool. A client is specified
+     * with the ID.
+     *
+     * To transfer a buffer, a sender must send an FMQ message. The message
+     * must include a receiver's ID and a transaction ID. A receiver must send
+     * the transaction ID to fetch a buffer from a buffer pool. Since the
+     * sender already registered the receiver via an FMQ message, The buffer
+     * pool must verify the receiver with the transaction ID. In order to
+     * prevent faking a receiver, a connection to a buffer pool from client is
+     * made and kept private. Also part of transaction ID is a sender ID in
+     * order to prevent fake transactions from other clients. This must be
+     * verified with an FMQ message from a buffer pool.
+     *
+     * @param observer The buffer pool event observer from the client.
+     *     Observer is provided to ensure FMQ messages are processed even when
+     *     client processes are idle. Buffer invalidation caused by
+     *     reconfiguration does not call observer. Buffer invalidation caused
+     *     by termination of pipeline call observer in order to ensure
+     *     invalidation is done after pipeline completion.
+     * @return ConnectionInfo The information regarding the established
+     *     connection
+     * @@throws ServiceSpecificException with one of the following values:
+     *     ResultStatus::NO_MEMORY        - Memory allocation failure occurred.
+     *     ResultStatus::ALREADY_EXISTS   - A connection was already made.
+     *     ResultStatus::CRITICAL_ERROR   - Other errors.
+     */
+    ConnectionInfo connect(in IObserver observer);
+}
diff --git a/media/bufferpool/aidl/android/hardware/media/bufferpool2/IClientManager.aidl b/media/bufferpool/aidl/android/hardware/media/bufferpool2/IClientManager.aidl
new file mode 100644
index 0000000..bf36e25
--- /dev/null
+++ b/media/bufferpool/aidl/android/hardware/media/bufferpool2/IClientManager.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.
+ */
+
+package android.hardware.media.bufferpool2;
+
+import android.hardware.media.bufferpool2.IAccessor;
+
+/**
+ * IClientManager manages IConnection(s) inside a process. A locally
+ * created IConnection represents a communication node(receiver) with the
+ * specified buffer pool(IAccessor).
+ * IConnection(s) are not exposed to other processes(IClientManager).
+ * IClientManager instance must be unique within a process.
+ */
+@VintfStability
+interface IClientManager {
+    /**
+     * Sets up a buffer receiving communication node for the specified
+     * buffer pool. A manager must create a IConnection to the buffer
+     * pool if it does not already have a connection.
+     *
+     * @param bufferPool a buffer pool which is specified with the IAccessor.
+     *     The specified buffer pool is the owner of received buffers.
+     * @return the Id of the communication node to the buffer pool.
+     *     This id is used in FMQ to notify IAccessor that a buffer has been
+     *     sent to that connection during transfers.
+     * @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);
+}
diff --git a/media/bufferpool/aidl/android/hardware/media/bufferpool2/IConnection.aidl b/media/bufferpool/aidl/android/hardware/media/bufferpool2/IConnection.aidl
new file mode 100644
index 0000000..d869f47
--- /dev/null
+++ b/media/bufferpool/aidl/android/hardware/media/bufferpool2/IConnection.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.
+ */
+
+package android.hardware.media.bufferpool2;
+
+import android.hardware.media.bufferpool2.Buffer;
+import android.hardware.media.bufferpool2.ResultStatus;
+
+/**
+ * A connection to a buffer pool which handles requests from a buffer pool
+ * client. The connection must be made in order to receive buffers from
+ * other buffer pool clients.
+ */
+@VintfStability
+interface IConnection {
+
+    parcelable FetchInfo {
+        /**
+         * Unique transaction id for buffer transferring.
+         */
+        long transactionId;
+        /**
+         * Id of the buffer to be fetched.
+         */
+        int bufferId;
+    }
+
+    union FetchResult {
+        /**
+         * The fetched buffer on successful fetch.
+         */
+        Buffer buffer;
+        /**
+         * The reason of the request failure. Possible values are below.
+         *
+         * ResultStatus::NOT_FOUND        - A buffer was not found due to invalidation.
+         * ResultStatus::CRITICAL_ERROR   - Other errors.
+         */
+        ResultStatus failure;
+    }
+
+    /**
+     * Retrieves buffers using an array of FetchInfo.
+     * Each element of FetchInfo array contains a bufferId and a transactionId
+     * for each buffer to fetch. The method must be called from receiving side of buffers
+     * during transferring only when the specified buffer is neither cached nor used.
+     *
+     * The method could have partial failures, in the case other successfully fetched buffers
+     * will be in returned result along with the failures. The order of the returned result
+     * will be the same with the fetchInfos.
+     *
+     * @param fetchInfos information of buffers to fetch
+     * @return Requested buffers.
+     *         If there are failures, reasons of failures are also included.
+     * @throws ServiceSpecificException with one of the following values:
+     *     ResultStatus::NO_MEMORY        - Memory allocation failure occurred.
+     *     ResultStatus::CRITICAL_ERROR   - Other errors.
+     */
+    FetchResult[] fetch(in FetchInfo[] fetchInfos);
+}
diff --git a/media/bufferpool/aidl/android/hardware/media/bufferpool2/IObserver.aidl b/media/bufferpool/aidl/android/hardware/media/bufferpool2/IObserver.aidl
new file mode 100644
index 0000000..07d1c3e
--- /dev/null
+++ b/media/bufferpool/aidl/android/hardware/media/bufferpool2/IObserver.aidl
@@ -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.
+ */
+
+package android.hardware.media.bufferpool2;
+
+/**
+ * IObserver listens on notifications from the buffer pool. On receiving
+ * notifications, FMQ messages from the specific buffer pool which are already
+ * in the FMQ are processed.
+ */
+@VintfStability
+interface IObserver {
+    /**
+     * The specific buffer pool sent a message to the client. Calling this
+     * method from the buffer pool enforces a buffer pool client process the
+     * message.
+     *
+     * @param connectionId the connection Id of the specific buffer pool client
+     * @param msgId Id of the most recent message
+     */
+    oneway void onMessage(in long connectionId, in int msgId);
+}
diff --git a/media/bufferpool/aidl/android/hardware/media/bufferpool2/ResultStatus.aidl b/media/bufferpool/aidl/android/hardware/media/bufferpool2/ResultStatus.aidl
new file mode 100644
index 0000000..162f9a7
--- /dev/null
+++ b/media/bufferpool/aidl/android/hardware/media/bufferpool2/ResultStatus.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.media.bufferpool2;
+
+@VintfStability
+parcelable ResultStatus {
+    const int OK = 0;
+    const int NO_MEMORY = 1;
+    const int ALREADY_EXISTS = 2;
+    const int NOT_FOUND = 3;
+    const int CRITICAL_ERROR = 4;
+
+    int resultStatus;
+}
diff --git a/media/c2/aidl/Android.bp b/media/c2/aidl/Android.bp
new file mode 100644
index 0000000..10867c0
--- /dev/null
+++ b/media/c2/aidl/Android.bp
@@ -0,0 +1,29 @@
+// This is the expected build file, but it may not be right in all cases
+
+aidl_interface {
+    name: "android.hardware.media.c2",
+    vendor_available: true,
+    srcs: ["android/hardware/media/c2/*.aidl"],
+    include_dirs: [
+        "frameworks/native/aidl/gui",
+    ],
+    imports: [
+        "android.hardware.common-V2",
+        "android.hardware.media.bufferpool2-V1",
+    ],
+    stability: "vintf",
+    backend: {
+        cpp: {
+            enabled: false,
+        },
+        java: {
+            enabled: false,
+        },
+        ndk: {
+            enabled: true,
+            additional_shared_libraries: [
+                "libnativewindow",
+            ],
+        },
+    },
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/BaseBlock.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/BaseBlock.aidl
new file mode 100644
index 0000000..460ff97
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/BaseBlock.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.media.c2;
+@VintfStability
+union BaseBlock {
+  android.hardware.common.NativeHandle nativeBlock;
+  android.hardware.media.bufferpool2.BufferStatusMessage pooledBlock;
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/Block.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/Block.aidl
new file mode 100644
index 0000000..7b3005e
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/Block.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.media.c2;
+@VintfStability
+parcelable Block {
+  int index;
+  android.hardware.media.c2.Params meta;
+  android.hardware.common.NativeHandle fence;
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/Buffer.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/Buffer.aidl
new file mode 100644
index 0000000..b632932
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/Buffer.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.media.c2;
+@VintfStability
+parcelable Buffer {
+  android.hardware.media.c2.Params info;
+  android.hardware.media.c2.Block[] blocks;
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/FieldDescriptor.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/FieldDescriptor.aidl
new file mode 100644
index 0000000..d0e4cbf
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/FieldDescriptor.aidl
@@ -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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.media.c2;
+@VintfStability
+parcelable FieldDescriptor {
+  android.hardware.media.c2.FieldId fieldId;
+  android.hardware.media.c2.FieldDescriptor.Type type;
+  int structIndex;
+  int extent;
+  String name;
+  android.hardware.media.c2.FieldDescriptor.NamedValue[] namedValues;
+  @Backing(type="int") @VintfStability
+  enum Type {
+    NO_INIT = 0,
+    INT32 = 1,
+    UINT32 = 2,
+    CNTR32 = 3,
+    INT64 = 4,
+    UINT64 = 5,
+    CNTR64 = 6,
+    FLOAT = 7,
+    STRING = 256,
+    BLOB = 257,
+    STRUCT = 131072,
+  }
+  @VintfStability
+  parcelable NamedValue {
+    String name;
+    long value;
+  }
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/FieldId.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/FieldId.aidl
new file mode 100644
index 0000000..935b85d
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/FieldId.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.media.c2;
+@VintfStability
+parcelable FieldId {
+  int offset;
+  int sizeBytes;
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/FieldSupportedValues.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/FieldSupportedValues.aidl
new file mode 100644
index 0000000..69060be
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/FieldSupportedValues.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.media.c2;
+@VintfStability
+union FieldSupportedValues {
+  boolean empty;
+  android.hardware.media.c2.ValueRange range;
+  long[] values;
+  long[] flags;
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/FieldSupportedValuesQuery.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/FieldSupportedValuesQuery.aidl
new file mode 100644
index 0000000..22f7c84
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/FieldSupportedValuesQuery.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.media.c2;
+@VintfStability
+parcelable FieldSupportedValuesQuery {
+  android.hardware.media.c2.ParamField field;
+  android.hardware.media.c2.FieldSupportedValuesQuery.Type type;
+  @Backing(type="int") @VintfStability
+  enum Type {
+    POSSIBLE = 0,
+    CURRENT = 1,
+  }
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/FieldSupportedValuesQueryResult.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/FieldSupportedValuesQueryResult.aidl
new file mode 100644
index 0000000..187e3eb
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/FieldSupportedValuesQueryResult.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.media.c2;
+@VintfStability
+parcelable FieldSupportedValuesQueryResult {
+  android.hardware.media.c2.Status status;
+  android.hardware.media.c2.FieldSupportedValues values;
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/FrameData.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/FrameData.aidl
new file mode 100644
index 0000000..e73b05e
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/FrameData.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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.media.c2;
+@VintfStability
+parcelable FrameData {
+  int flags;
+  android.hardware.media.c2.WorkOrdinal ordinal;
+  android.hardware.media.c2.Buffer[] buffers;
+  android.hardware.media.c2.Params configUpdate;
+  android.hardware.media.c2.InfoBuffer[] infoBuffers;
+  const int DROP_FRAME = 1;
+  const int END_OF_STREAM = 2;
+  const int DISCARD_FRAME = 4;
+  const int FLAG_INCOMPLETE = 8;
+  const int CODEC_CONFIG = -2147483648;
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IComponent.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IComponent.aidl
new file mode 100644
index 0000000..7ed09af
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IComponent.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.media.c2;
+@VintfStability
+interface IComponent {
+  android.hardware.common.NativeHandle configureVideoTunnel(in int avSyncHwId);
+  android.hardware.media.c2.IComponent.BlockPool createBlockPool(in int allocatorId);
+  void destroyBlockPool(in long blockPoolId);
+  void drain(in boolean withEos);
+  android.hardware.media.c2.WorkBundle flush();
+  android.hardware.media.c2.IComponentInterface getInterface();
+  void queue(in android.hardware.media.c2.WorkBundle workBundle);
+  void release();
+  void reset();
+  void setOutputSurface(in long blockPoolId, in android.view.Surface surface, in android.hardware.media.c2.SurfaceSyncObj syncObject);
+  void start();
+  void stop();
+  parcelable BlockPool {
+    long blockPoolId;
+    android.hardware.media.c2.IConfigurable configurable;
+  }
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IComponentInterface.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IComponentInterface.aidl
new file mode 100644
index 0000000..2350dae
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IComponentInterface.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.media.c2;
+@VintfStability
+interface IComponentInterface {
+  android.hardware.media.c2.IConfigurable getConfigurable();
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IComponentListener.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IComponentListener.aidl
new file mode 100644
index 0000000..f6f2a63
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IComponentListener.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.media.c2;
+@VintfStability
+interface IComponentListener {
+  oneway void onError(in android.hardware.media.c2.Status status, in int errorCode);
+  oneway void onFramesRendered(in android.hardware.media.c2.IComponentListener.RenderedFrame[] renderedFrames);
+  oneway void onInputBuffersReleased(in android.hardware.media.c2.IComponentListener.InputBuffer[] inputBuffers);
+  oneway void onTripped(in android.hardware.media.c2.SettingResult[] settingResults);
+  oneway void onWorkDone(in android.hardware.media.c2.WorkBundle workBundle);
+  @VintfStability
+  parcelable InputBuffer {
+    long frameIndex;
+    int arrayIndex;
+  }
+  @VintfStability
+  parcelable RenderedFrame {
+    long bufferQueueId;
+    int slotId;
+    long timestampNs;
+  }
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IComponentStore.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IComponentStore.aidl
new file mode 100644
index 0000000..35532be
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IComponentStore.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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.media.c2;
+@VintfStability
+interface IComponentStore {
+  void copyBuffer(in android.hardware.media.c2.Buffer src, in android.hardware.media.c2.Buffer dst);
+  android.hardware.media.c2.IComponent createComponent(in String name, in android.hardware.media.c2.IComponentListener listener, in android.hardware.media.bufferpool2.IClientManager pool);
+  android.hardware.media.c2.IComponentInterface createInterface(in String name);
+  android.hardware.media.c2.IConfigurable getConfigurable();
+  android.hardware.media.bufferpool2.IClientManager getPoolClientManager();
+  android.hardware.media.c2.StructDescriptor[] getStructDescriptors(in int[] indices);
+  android.hardware.media.c2.IComponentStore.ComponentTraits[] listComponents();
+  @VintfStability
+  parcelable ComponentTraits {
+    String name;
+    android.hardware.media.c2.IComponentStore.ComponentTraits.Domain domain;
+    android.hardware.media.c2.IComponentStore.ComponentTraits.Kind kind;
+    int rank;
+    String mediaType;
+    String[] aliases;
+    @Backing(type="int") @VintfStability
+    enum Kind {
+      OTHER = 0,
+      DECODER = 1,
+      ENCODER = 2,
+    }
+    @Backing(type="int") @VintfStability
+    enum Domain {
+      OTHER = 0,
+      VIDEO = 1,
+      AUDIO = 2,
+      IMAGE = 3,
+    }
+  }
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IConfigurable.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IConfigurable.aidl
new file mode 100644
index 0000000..32f5abd
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IConfigurable.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.media.c2;
+@VintfStability
+interface IConfigurable {
+  android.hardware.media.c2.IConfigurable.ConfigResult config(in android.hardware.media.c2.Params inParams, in boolean mayBlock);
+  int getId();
+  String getName();
+  android.hardware.media.c2.Params query(in int[] indices, in boolean mayBlock);
+  android.hardware.media.c2.ParamDescriptor[] querySupportedParams(in int start, in int count);
+  android.hardware.media.c2.FieldSupportedValuesQueryResult[] querySupportedValues(in android.hardware.media.c2.FieldSupportedValuesQuery[] inFields, in boolean mayBlock);
+  @VintfStability
+  parcelable ConfigResult {
+    android.hardware.media.c2.Params params;
+    android.hardware.media.c2.SettingResult[] failures;
+  }
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/InfoBuffer.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/InfoBuffer.aidl
new file mode 100644
index 0000000..94cd77d
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/InfoBuffer.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.media.c2;
+@VintfStability
+parcelable InfoBuffer {
+  int index;
+  android.hardware.media.c2.Buffer buffer;
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/ParamDescriptor.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/ParamDescriptor.aidl
new file mode 100644
index 0000000..04c869c
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/ParamDescriptor.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.media.c2;
+@VintfStability
+parcelable ParamDescriptor {
+  int index;
+  int attrib;
+  String name;
+  int[] dependencies;
+  const int ATTRIBUTE_REQUIRED = 1;
+  const int ATTRIBUTE_PERSISTENT = 2;
+  const int ATTRIBUTE_STRICT = 4;
+  const int ATTRIBUTE_READ_ONLY = 8;
+  const int ATTRIBUTE_HIDDEN = 16;
+  const int ATTRIBUTE_INTERNAL = 32;
+  const int ATTRIBUTE_CONST = 64;
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/ParamField.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/ParamField.aidl
new file mode 100644
index 0000000..13d2522
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/ParamField.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.media.c2;
+@VintfStability
+parcelable ParamField {
+  int index;
+  android.hardware.media.c2.FieldId fieldId;
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/ParamFieldValues.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/ParamFieldValues.aidl
new file mode 100644
index 0000000..5a2821c
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/ParamFieldValues.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.media.c2;
+@VintfStability
+parcelable ParamFieldValues {
+  android.hardware.media.c2.ParamField paramOrField;
+  android.hardware.media.c2.FieldSupportedValues[] values;
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/Params.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/Params.aidl
new file mode 100644
index 0000000..7d363c0
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/Params.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.media.c2;
+@VintfStability
+parcelable Params {
+  byte[] params;
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/SettingResult.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/SettingResult.aidl
new file mode 100644
index 0000000..f9e6a93
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/SettingResult.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.media.c2;
+@VintfStability
+parcelable SettingResult {
+  android.hardware.media.c2.SettingResult.Failure failure;
+  android.hardware.media.c2.ParamFieldValues field;
+  android.hardware.media.c2.ParamFieldValues[] conflicts;
+  @Backing(type="int") @VintfStability
+  enum Failure {
+    BAD_TYPE = 0,
+    BAD_PORT = 1,
+    BAD_INDEX = 2,
+    READ_ONLY = 3,
+    MISMATCH = 4,
+    BAD_VALUE = 5,
+    CONFLICT = 6,
+    UNSUPPORTED = 7,
+    INFO_BAD_VALUE = 8,
+    INFO_CONFLICT = 9,
+  }
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/Status.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/Status.aidl
new file mode 100644
index 0000000..ad07677
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/Status.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.media.c2;
+@VintfStability
+parcelable Status {
+  int status;
+  const int OK = 0;
+  const int BAD_VALUE = -22;
+  const int BAD_INDEX = -75;
+  const int CANNOT_DO = -2147483646;
+  const int DUPLICATE = -17;
+  const int NOT_FOUND = -2;
+  const int BAD_STATE = -38;
+  const int BLOCKING = -9930;
+  const int NO_MEMORY = -12;
+  const int REFUSED = -1;
+  const int TIMED_OUT = -110;
+  const int OMITTED = -74;
+  const int CORRUPTED = -2147483648;
+  const int NO_INIT = -19;
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/StructDescriptor.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/StructDescriptor.aidl
new file mode 100644
index 0000000..58268e0
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/StructDescriptor.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.media.c2;
+@VintfStability
+parcelable StructDescriptor {
+  int type;
+  android.hardware.media.c2.FieldDescriptor[] fields;
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/SurfaceSyncObj.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/SurfaceSyncObj.aidl
new file mode 100644
index 0000000..1c9bf8d
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/SurfaceSyncObj.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.media.c2;
+@VintfStability
+parcelable SurfaceSyncObj {
+  android.hardware.common.NativeHandle syncMemory;
+  long bqId;
+  int generationId;
+  long consumerUsage;
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/ValueRange.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/ValueRange.aidl
new file mode 100644
index 0000000..db71ce0
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/ValueRange.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.media.c2;
+@VintfStability
+parcelable ValueRange {
+  long min;
+  long max;
+  long step;
+  long num;
+  long denom;
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/Work.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/Work.aidl
new file mode 100644
index 0000000..a534348
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/Work.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.media.c2;
+@VintfStability
+parcelable Work {
+  byte[] chainInfo;
+  android.hardware.media.c2.FrameData input;
+  android.hardware.media.c2.Worklet[] worklets;
+  int workletsProcessed;
+  android.hardware.media.c2.Status result;
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/WorkBundle.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/WorkBundle.aidl
new file mode 100644
index 0000000..84708a8
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/WorkBundle.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.media.c2;
+@VintfStability
+parcelable WorkBundle {
+  android.hardware.media.c2.Work[] works;
+  android.hardware.media.c2.BaseBlock[] baseBlocks;
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/WorkOrdinal.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/WorkOrdinal.aidl
new file mode 100644
index 0000000..2833df3
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/WorkOrdinal.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.media.c2;
+@VintfStability
+parcelable WorkOrdinal {
+  long timestampUs;
+  long frameIndex;
+  long customOrdinal;
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/Worklet.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/Worklet.aidl
new file mode 100644
index 0000000..a79abf2
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/Worklet.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.media.c2;
+@VintfStability
+parcelable Worklet {
+  int componentId;
+  byte[] tunings;
+  android.hardware.media.c2.SettingResult[] failures;
+  android.hardware.media.c2.FrameData output;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/BaseBlock.aidl b/media/c2/aidl/android/hardware/media/c2/BaseBlock.aidl
new file mode 100644
index 0000000..8b8b8e0
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/BaseBlock.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.
+ */
+
+package android.hardware.media.c2;
+
+import android.hardware.common.NativeHandle;
+
+/**
+ * Storage type for `BaseBlock`.
+ *
+ * A `BaseBlock` is a representation of a codec memory block. Coded data,
+ * decoded data, codec-specific data, and other codec-related data are all sent
+ * in the form of BaseBlocks.
+ */
+@VintfStability
+union BaseBlock {
+    /**
+     * #nativeBlock is the opaque representation of a buffer.
+     */
+    NativeHandle nativeBlock;
+    /**
+     * #pooledBlock is a reference to a buffer handled by a BufferPool.
+     */
+    android.hardware.media.bufferpool2.BufferStatusMessage pooledBlock;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/Block.aidl b/media/c2/aidl/android/hardware/media/c2/Block.aidl
new file mode 100644
index 0000000..34aa7b1
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/Block.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.media.c2;
+
+import android.hardware.common.NativeHandle;
+import android.hardware.media.c2.Params;
+
+/**
+ * Reference to a @ref BaseBlock within a @ref WorkBundle.
+ *
+ * `Block` contains additional attributes that `BaseBlock` does not. These
+ * attributes may differ among `Block` objects that refer to the same
+ * `BaseBlock` in the same `WorkBundle`.
+ */
+@VintfStability
+parcelable Block {
+    /**
+     * Identity of a `BaseBlock` within a `WorkBundle`. This is an index into
+     * #WorkBundle.baseBlocks.
+     */
+    int index;
+    /**
+     * Metadata associated with this `Block`.
+     */
+    Params meta;
+    /**
+     * Fence for synchronizing `Block` access.
+     */
+    NativeHandle fence;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/Buffer.aidl b/media/c2/aidl/android/hardware/media/c2/Buffer.aidl
new file mode 100644
index 0000000..d2dcf2d
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/Buffer.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.media.c2;
+
+import android.hardware.media.c2.Block;
+import android.hardware.media.c2.Params;
+
+/**
+ * A codec buffer, which is a collection of @ref Block objects and metadata.
+ *
+ * This is a part of @ref FrameData.
+ */
+@VintfStability
+parcelable Buffer {
+    /**
+     * Metadata associated with the buffer.
+     */
+    Params info;
+    /**
+     * Blocks contained in the buffer.
+     */
+    Block[] blocks;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/FieldDescriptor.aidl b/media/c2/aidl/android/hardware/media/c2/FieldDescriptor.aidl
new file mode 100644
index 0000000..a2774ec
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/FieldDescriptor.aidl
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2;
+
+import android.hardware.media.c2.FieldId;
+
+/**
+ * Description of a field inside a C2Param structure.
+ */
+@VintfStability
+parcelable FieldDescriptor {
+    /**
+     * Possible types of the field.
+     */
+    @VintfStability
+    @Backing(type="int")
+    enum Type {
+        NO_INIT = 0,
+        INT32,
+        UINT32,
+        CNTR32,
+        INT64,
+        UINT64,
+        CNTR64,
+        FLOAT,
+        /**
+         * Fixed-size string (POD).
+         */
+        STRING = 0x100,
+        /**
+         * A blob has no sub-elements and can be thought of as an array of
+         * bytes. However, bytes cannot be individually addressed by clients.
+         */
+        BLOB,
+        /**
+         * The field is a structure that may contain other fields.
+         */
+        STRUCT = 0x20000,
+    }
+    /**
+     * Named value type. This is used for defining an enum value for a numeric
+     * type.
+     */
+    @VintfStability
+    parcelable NamedValue {
+        /**
+         * Name of the enum value. This must be unique for each enum value in
+         * the same field.
+         */
+        String name;
+        /**
+         * Underlying value of the enum value. Multiple enum names may have the
+         * same underlying value.
+         */
+        long value;
+    }
+    /**
+     * Location of the field in the C2Param structure
+     */
+    FieldId fieldId;
+    /**
+     * Type of the field.
+     */
+    Type type;
+    /**
+     * If #type is #Type.STRUCT, #structIndex is the C2Param structure index;
+     * otherwise, #structIndex is not used.
+     */
+    int structIndex;
+    /**
+     * Extent of the field.
+     * - For a non-array field, #extent is 1.
+     * - For a fixed-length array field, #extent is the length. An array field
+     *   of length 1 is indistinguishable from a non-array field.
+     * - For a variable-length array field, #extent is 0. This can only occur as
+     *   the last member of a C2Param structure.
+     */
+    int extent;
+    /**
+     * Name of the field. This must be unique for each field in the same
+     * structure.
+     */
+    String name;
+    /**
+     * List of enum values. This is not used when #type is not one of the
+     * numeric types.
+     */
+    NamedValue[] namedValues;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/FieldId.aidl b/media/c2/aidl/android/hardware/media/c2/FieldId.aidl
new file mode 100644
index 0000000..68bf058
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/FieldId.aidl
@@ -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.
+ */
+
+package android.hardware.media.c2;
+
+/**
+ * Identifying information of a field relative to a known C2Param structure.
+ *
+ * Within a given C2Param structure, each field is uniquely identified by @ref
+ * FieldId.
+ */
+@VintfStability
+parcelable FieldId {
+    /**
+     * Offset of the field in bytes.
+     */
+    int offset;
+    /**
+     * Size of the field in bytes.
+     */
+    int sizeBytes;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/FieldSupportedValues.aidl b/media/c2/aidl/android/hardware/media/c2/FieldSupportedValues.aidl
new file mode 100644
index 0000000..6c2033b
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/FieldSupportedValues.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.media.c2;
+
+import android.hardware.media.c2.ValueRange;
+
+/*
+ * Description of supported values for a field of C2Param.
+ *
+ * This can be a continuous range or a discrete set of values.
+ *
+ * The intended type of values must be made clear in the context where
+ * `FieldSupportedValues` is used.
+ */
+@VintfStability
+union FieldSupportedValues {
+    /**
+     * No supported values
+     */
+    boolean empty;
+    /**
+     * Numeric range, described in a #ValueRange structure
+     */
+    ValueRange range;
+    /**
+     * List of values
+     */
+    long[] values;
+    /**
+     * List of flags that can be OR-ed.
+     *
+     * The list contains { min-mask, flag1, flag2... }. Basically, the first
+     * value is the required set of flags to be set, and the rest of the values are flags that can
+     * be set independently. FLAGS is only supported for integral types. Supported flags should
+     * not overlap, as it can make validation non-deterministic. The standard validation method
+     * is that starting from the original value, if each flag is removed when fully present (the
+     * min-mask must be fully present), we shall arrive at 0.
+     */
+    long[] flags;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/FieldSupportedValuesQuery.aidl b/media/c2/aidl/android/hardware/media/c2/FieldSupportedValuesQuery.aidl
new file mode 100644
index 0000000..bdaaef6
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/FieldSupportedValuesQuery.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.media.c2;
+
+import android.hardware.media.c2.ParamField;
+
+/**
+ * Query information for supported values of a field. This is used as input to
+ * IConfigurable::querySupportedValues().
+ */
+@VintfStability
+parcelable FieldSupportedValuesQuery {
+    @VintfStability
+    @Backing(type="int")
+    enum Type {
+        /**
+         * Query all possible values regardless of other settings.
+         */
+        POSSIBLE = 0,
+        /**
+         * Query currently possible values given dependent settings.
+         */
+        CURRENT,
+    }
+    /**
+     * Identity of the field to query.
+     */
+    ParamField field;
+    /**
+     * Type of the query. See #Type for more information.
+     */
+    Type type;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/FieldSupportedValuesQueryResult.aidl b/media/c2/aidl/android/hardware/media/c2/FieldSupportedValuesQueryResult.aidl
new file mode 100644
index 0000000..b5c28c6
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/FieldSupportedValuesQueryResult.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.media.c2;
+
+import android.hardware.media.c2.FieldSupportedValues;
+import android.hardware.media.c2.Status;
+
+/**
+ * This structure is used to hold the result from
+ * IConfigurable::querySupportedValues().
+ */
+@VintfStability
+parcelable FieldSupportedValuesQueryResult {
+    /**
+     * Result of the query. Possible values are
+     * - `Status::OK`: The query was successful.
+     * - `Status::BAD_STATE`: The query was requested when the `IConfigurable` instance
+     *   was in a bad state.
+     * - `Status::BAD_INDEX`: The requested field was not recognized.
+     * - `Status::TIMED_OUT`: The query could not be completed in a timely manner.
+     * - `Status::BLOCKING`: The query must block, but the parameter `mayBlock` in the
+     *   call to `querySupportedValues()` was `false`.
+     * - `Status::CORRUPTED`: Some unknown error occurred.
+     */
+    Status status;
+    /**
+     * Supported values. This is meaningful only when #status is `OK`.
+     */
+    FieldSupportedValues values;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/FrameData.aidl b/media/c2/aidl/android/hardware/media/c2/FrameData.aidl
new file mode 100644
index 0000000..15c1b6d
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/FrameData.aidl
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2;
+
+import android.hardware.media.c2.Buffer;
+import android.hardware.media.c2.InfoBuffer;
+import android.hardware.media.c2.Params;
+import android.hardware.media.c2.WorkOrdinal;
+
+/**
+ * Data for an input frame or an output frame.
+ *
+ * This structure represents a @e frame with its metadata. A @e frame consists
+ * of an ordered set of buffers, configuration changes, and info buffers along
+ * with some non-configuration metadata.
+ *
+ * @note `FrameData` is the HIDL counterpart of `C2FrameData` in the Codec 2.0
+ * standard.
+ */
+@VintfStability
+parcelable FrameData {
+    /** List of frame flags */
+    /**
+     * For input frames: no output frame shall be generated when processing
+     * this frame, but metadata must still be processed.
+     *
+     * For output frames: this frame must be discarded but metadata is still
+     * valid.
+     */
+    const int DROP_FRAME = (1 << 0);
+    /**
+     * This frame is the last frame of the current stream. Further frames
+     * are part of a new stream.
+     */
+    const int END_OF_STREAM = (1 << 1);
+    /**
+     * This frame must be discarded with its metadata.
+     *
+     * This flag is only set by components, e.g. as a response to the flush
+     * command.
+     */
+    const int DISCARD_FRAME = (1 << 2);
+    /**
+     * This frame is not the last frame produced for the input.
+     *
+     * This flag is normally set by the component - e.g. when an input frame
+     * results in multiple output frames, this flag is set on all but the
+     * last output frame.
+     *
+     * Also, when components are chained, this flag should be propagated
+     * down the work chain. That is, if set on an earlier frame of a
+     * work-chain, it should be propagated to all later frames in that
+     * chain. Additionally, components down the chain could set this flag
+     * even if not set earlier, e.g. if multiple output frames are generated
+     * at that component for the input frame.
+     */
+    const int FLAG_INCOMPLETE = (1 << 3);
+    /**
+     * This frame contains only codec-specific configuration data, and no
+     * actual access unit.
+     */
+    const int CODEC_CONFIG = (1 << 31);
+    /**
+     * Frame flags, as described above.
+     */
+    int flags;
+    /**
+     * @ref WorkOrdinal of the frame.
+     */
+    WorkOrdinal ordinal;
+    /**
+     * List of frame buffers.
+     */
+    Buffer[] buffers;
+    /**
+     * List of configuration updates.
+     */
+    Params configUpdate;
+    /**
+     * List of info buffers.
+     */
+    InfoBuffer[] infoBuffers;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/IComponent.aidl b/media/c2/aidl/android/hardware/media/c2/IComponent.aidl
new file mode 100644
index 0000000..b3390c3
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/IComponent.aidl
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2;
+
+import android.hardware.common.NativeHandle;
+import android.view.Surface;
+
+import android.hardware.media.c2.IComponentInterface;
+import android.hardware.media.c2.IConfigurable;
+import android.hardware.media.c2.WorkBundle;
+import android.hardware.media.c2.SurfaceSyncObj;
+
+/**
+ * Interface for an AIDL Codec2 component.
+ * Components have two states: stopped and running. The running state has three
+ * sub-states: executing, tripped and error.
+ *
+ * All methods in `IComponent` must not block. If a method call cannot be
+ * completed in a timely manner, it must throw `Status::TIMED_OUT`.
+ */
+@VintfStability
+interface IComponent {
+    /**
+     * The reference object from framwork to HAL C2BlockPool.
+     *
+     * The object will be returned when C2BlockPool is created by a framework
+     * request. The object also can be destroyed using blockPoolId.
+     * Using configurable framework can query/config the object in HAL(IComponent).
+     */
+    parcelable BlockPool {
+        long blockPoolId;
+        IConfigurable configurable;
+    }
+    /**
+     * Configures a component for a tunneled playback mode.
+     *
+     * A successful call to this method puts the component in the *tunneled*
+     * mode. In this mode, the output `Worklet`s returned in
+     * IComponentListener::onWorkDone() may not contain any buffers. The output
+     * buffers are passed directly to the consumer end of a buffer queue whose
+     * producer side is configured with the returned @p sidebandStream passed
+     * to IGraphicBufferProducer::setSidebandStream().
+     *
+     * The component is initially in the non-tunneled mode by default. The
+     * tunneled mode can be toggled on only before the component starts
+     * processing. Once the component is put into the tunneled mode, it shall
+     * stay in the tunneled mode until and only until reset() is called.
+     *
+     * @param avSyncHwId A resource ID for hardware sync. The generator of sync
+     *     IDs must ensure that this number is unique among all services at any
+     *     given time. For example, if both the audio HAL and the tuner HAL
+     *     support this feature, sync IDs from the audio HAL must not clash
+     *     with sync IDs from the tuner HAL.
+     * @return Codec-allocated sideband stream NativeHandle. This can
+     *     be passed to IGraphicBufferProducer::setSidebandStream() to
+     *     establish a direct channel to the consumer.
+     * @throws ServiceSpecificException with one of the following values:
+     *   - `Status::OMITTED`   - The component does not support video tunneling.
+     *   - `Status::BAD_STATE` - The component is already running.
+     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `Status::CORRUPTED` - Some unknown error occurred.
+     */
+    NativeHandle configureVideoTunnel(in int avSyncHwId);
+
+    /**
+     * Creates a local `C2BlockPool` backed by the given allocator and returns
+     * its id.
+     *
+     * The returned @p blockPoolId is the only way the client can refer to a
+     * `C2BlockPool` object in the component. The id can be passed to
+     * setOutputSurface() or used in some C2Param objects later.
+     *
+     * The created `C2BlockPool` object can be destroyed by calling
+     * destroyBlockPool(), reset() or release(). reset() and release() must
+     * destroy all `C2BlockPool` objects that have been created.
+     *
+     * @param allocatorId Id of a `C2Allocator`.
+     * @param out configurable Configuration interface for the created pool. This
+     *     must not be null.
+     * @return Created block pool information. This could be used to config/query and
+     * also be used in setOutputSurface() if the allocator
+     * @throws ServiceSpecificException with one of the following values:
+     *   - `Status::NO_MEMORY` - Not enough memory to create the pool.
+     *   - `Status::BAD_VALUE` - @p allocatorId is not recognized.
+     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `Status::CORRUPTED` - Some unknown error occurred.
+     */
+    BlockPool createBlockPool(in int allocatorId);
+
+    /**
+     * Destroys a local block pool previously created by createBlockPool().
+     *
+     * @param blockPoolId Id of a `C2BlockPool` that was previously returned by
+     *      createBlockPool().
+     * @throws ServiceSpecificException with one of the following values:
+     *   - `Status::NOT_FOUND` - The supplied blockPoolId is not valid.
+     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `Status::CORRUPTED` - Some unknown error occurred.
+     */
+    void destroyBlockPool(in long blockPoolId);
+
+    /**
+     * Drains the component, and optionally downstream components. This is a
+     * signalling method; as such it does not wait for any work completion.
+     *
+     * The last `Work` item is marked as "drain-till-here", so the component is
+     * notified not to wait for further `Work` before it processes what is
+     * already queued. This method can also be used to set the end-of-stream
+     * flag after `Work` has been queued. Client can continue to queue further
+     * `Work` immediately after this method returns.
+     *
+     * This method must be supported in running (including tripped) states.
+     *
+     * `Work` that is completed must be returned via
+     * IComponentListener::onWorkDone().
+     *
+     * @param withEos Whether to drain the component with marking end-of-stream.
+     * @throws ServiceSpecificException with one of the following values:
+     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `Status::CORRUPTED` - Some unknown error occurred.
+     */
+    void drain(in boolean withEos);
+
+    /**
+     * Discards and abandons any pending `Work` items for the component.
+     *
+     * This method must be supported in running (including tripped) states.
+     *
+     * `Work` that could be immediately abandoned/discarded must be returned in
+     * @p flushedWorkBundle. The order in which queued `Work` items are
+     * discarded can be arbitrary.
+     *
+     * `Work` that could not be abandoned or discarded immediately must be
+     * marked to be discarded at the earliest opportunity, and must be returned
+     * via IComponentListener::onWorkDone(). This must be completed within
+     * 500ms.
+     *
+     * @return `WorkBundle` object containing flushed `Work` items.
+     * @throws ServiceSpecificException with one of the following values:
+     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `Status::CORRUPTED` - Some unknown error occurred.
+     */
+    WorkBundle flush();
+
+    /**
+     * Returns the @ref IComponentInterface instance associated to this
+     * component.
+     *
+     * An @ref IConfigurable instance for the component can be obtained by calling
+     * IComponentInterface::getConfigurable() on the returned @p intf.
+     *
+     * @return `IComponentInterface` instance. This must not be null.
+     */
+    IComponentInterface getInterface();
+
+    /**
+     * Queues up work for the component.
+     *
+     * This method must be supported in running (including tripped) states.
+     *
+     * It is acceptable for this method to return `OK` and return an error value
+     * using the IComponentListener::onWorkDone() callback.
+     *
+     * @param workBundle `WorkBundle` object containing a list of `Work` objects
+     *     to queue to the component.
+     * @throws ServiceSpecificException with one of the following values:
+     *   - `Status::BAD_INDEX` - Some component id in some `Worklet` is not valid.
+     *   - `Status::CANNOT_DO` - The components are not tunneled but some `Work` object
+     *                   contains tunneling information.
+     *   - `Status::NO_MEMORY` - Not enough memory to queue @p workBundle.
+     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `Status::CORRUPTED` - Some unknown error occurred.
+     */
+    void queue(in WorkBundle workBundle);
+
+    /**
+     * Releases the component.
+     *
+     * This method must be supported in stopped state.
+     *
+     * This method destroys the component. Upon return, if @p status is `OK` or
+     * `DUPLICATE`, all resources must have been released.
+     *
+     * @throws ServiceSpecificException with one of the following values:
+     *   - `Status::BAD_STATE` - The component is running.
+     *   - `Status::DUPLICATE` - The component is already released.
+     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `Status::CORRUPTED` - Some unknown error occurred.
+     */
+    void release();
+
+    /**
+     * Resets the component.
+     *
+     * This method must be supported in all (including tripped) states other
+     * than released.
+     *
+     * This method must be supported during any other blocking call.
+     *
+     * This method must return within 500ms.
+     *
+     * When this call returns, if @p status is `OK`, all `Work` items must
+     * have been abandoned, and all resources (including `C2BlockPool` objects
+     * previously created by createBlockPool()) must have been released.
+     *
+     * If the return value is `BAD_STATE` or `DUPLICATE`, no state change is
+     * expected as a response to this call. For all other return values, the
+     * component must be in the stopped state.
+     *
+     * This brings settings back to their default, "guaranteeing" no tripped
+     * state.
+     *
+     * @throws ServiceSpecificException with one of the following values:
+     *   - `Status::BAD_STATE` - Component is in released state.
+     *   - `Status::DUPLICATE` - When called during another reset call from another
+     *                   thread.
+     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `Status::CORRUPTED` - Some unknown error occurred.
+     */
+    void reset();
+
+    /**
+     * Starts using a surface for output with a synchronization object
+     *
+     * This method must not block.
+     *
+     * @param blockPoolId Id of the `C2BlockPool` to be associated with the
+     *     output surface.
+     * @param surface Output surface.
+     * @param syncObject synchronization object for buffer allocation between
+     *     Framework and Component.
+     * @throws ServiceSpecificException with one of the following values:
+     *   - `Status::CANNOT_DO` - The component does not support an output surface.
+     *   - `Status::REFUSED`   - The output surface cannot be accessed.
+     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `Status::CORRUPTED` - Some unknown error occurred.
+     */
+    void setOutputSurface(in long blockPoolId, in Surface surface,
+        in SurfaceSyncObj syncObject);
+
+    /**
+     * Starts the component.
+     *
+     * This method must be supported in stopped state as well as tripped state.
+     *
+     * If the return value is `OK`, the component must be in the running state.
+     * If the return value is `BAD_STATE` or `DUPLICATE`, no state change is
+     * expected as a response to this call. Otherwise, the component must be in
+     * the stopped state.
+     *
+     * If a component is in the tripped state and start() is called while the
+     * component configuration still results in a trip, start() must succeed and
+     * a new onTripped() callback must be used to communicate the configuration
+     * conflict that results in the new trip.
+     *
+     * @throws ServiceSpecificException with one of the following values:
+     *   - `Status::BAD_STATE` - Component is not in stopped or tripped state.
+     *   - `Status::DUPLICATE` - When called during another start call from another
+     *                   thread.
+     *   - `Status::NO_MEMORY` - Not enough memory to start the component.
+     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `Status::CORRUPTED` - Some unknown error occurred.
+     */
+    void start();
+
+    /**
+     * Stops the component.
+     *
+     * This method must be supported in running (including tripped) state.
+     *
+     * This method must return within 500ms.
+     *
+     * Upon this call, all pending `Work` must be abandoned.
+     *
+     * If the return value is `BAD_STATE` or `DUPLICATE`, no state change is
+     * expected as a response to this call. For all other return values, the
+     * component must be in the stopped state.
+     *
+     * This does not alter any settings and tunings that may have resulted in a
+     * tripped state.
+     *
+     * @throws ServiceSpecificException with one of the following values:
+     *   - `Status::BAD_STATE` - Component is not in running state.
+     *   - `Status::DUPLICATE` - When called during another stop call from another
+     *                   thread.
+     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `Status::CORRUPTED` - Some unknown error occurred.
+     */
+    void stop();
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/IComponentInterface.aidl b/media/c2/aidl/android/hardware/media/c2/IComponentInterface.aidl
new file mode 100644
index 0000000..9db81e6
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/IComponentInterface.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.
+ */
+
+package android.hardware.media.c2;
+
+import android.hardware.media.c2.IConfigurable;
+
+/**
+ * Component interface object. This object contains all of the configurations of
+ * a potential or actual component. It can be created and used independently of
+ * an actual Codec2 component to query supported parameters for various
+ * component settings, and configurations for a potential component.
+ *
+ * An actual component exposes this interface via IComponent::getInterface().
+ */
+@VintfStability
+interface IComponentInterface {
+    /**
+     * Returns the @ref IConfigurable instance associated to this component
+     * interface.
+     *
+     * @return `IConfigurable` instance. This must not be null.
+     */
+    IConfigurable getConfigurable();
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/IComponentListener.aidl b/media/c2/aidl/android/hardware/media/c2/IComponentListener.aidl
new file mode 100644
index 0000000..75500b7
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/IComponentListener.aidl
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2;
+
+import android.hardware.media.c2.SettingResult;
+import android.hardware.media.c2.Status;
+import android.hardware.media.c2.WorkBundle;
+
+/**
+ * Callback interface for handling notifications from @ref IComponent.
+ */
+@VintfStability
+oneway interface IComponentListener {
+    /**
+     * Identifying information for an input buffer previously queued to the
+     * component via IComponent::queue().
+     */
+    @VintfStability
+    parcelable InputBuffer {
+        /**
+         * This value comes from `Work::input.ordinal.frameIndex` in a `Work`
+         * object that was previously queued.
+         */
+        long frameIndex;
+        /**
+         * This value is an index into `Work::input.buffers` (which is an array)
+         * in a `Work` object that was previously queued.
+         */
+        int arrayIndex;
+    }
+    /**
+     * Information about rendering of a frame to a `Surface`.
+     */
+    @VintfStability
+    parcelable RenderedFrame {
+        /**
+         * Id of the `BufferQueue` containing the rendered buffer.
+         *
+         * This value must have been obtained by an earlier call to
+         * IGraphicBufferProducer::getUniqueId().
+         */
+        long bufferQueueId;
+        /**
+         * Id of the slot of the rendered buffer.
+         *
+         * This value must have been obtained by an earlier call to
+         * IGraphicBufferProducer::dequeueBuffer() or
+         * IGraphicBufferProducer::attachBuffer().
+         */
+        int slotId;
+        /**
+         * Timestamp the rendering happened.
+         *
+         * The reference point for the timestamp is determined by the
+         * `BufferQueue` that performed the rendering.
+         */
+        long timestampNs;
+    }
+    /**
+     * Notify the listener of an error.
+     *
+     * @param status Error type. @p status may be `OK`, which means that an
+     *     error has occurred, but the error type does not fit into the type
+     *     `Status`. In this case, additional information is provided by
+     *     @p errorCode.
+     * @param errorCode Additional error information. The framework may not
+     *     recognize the meaning of this value.
+     */
+    void onError(in Status status, in int errorCode);
+
+    /**
+     * Notify the listener that frames have been rendered.
+     *
+     * @param renderedFrames List of @ref RenderedFrame objects.
+     */
+    void onFramesRendered(in RenderedFrame[] renderedFrames);
+
+    /**
+     * Notify the listener that some input buffers are no longer needed by the
+     * component, and hence can be released or reused by the client.
+     *
+     * Input buffers that are contained in a `Work` object returned by an
+     * earlier onWorkDone() call are assumed released, so they must not appear
+     * in any onInputBuffersReleased() calls. That means
+     * onInputBuffersReleased() must only report input buffers that are released
+     * before the output in the same `Work` item is produced. However, it is
+     * possible for an input buffer to be returned by onWorkDone() after it has
+     * been reported by onInputBuffersReleased().
+     *
+     * @note onWorkDone() and onInputBuffersReleased() both notify the client
+     * that input buffers are no longer needed. However, in order to minimize
+     * IPC calls, onInputBuffersReleased() should be called only when
+     * onWorkDone() cannot be called, e.g., the component needs more input
+     * before an output can be produced.
+     *
+     * @param inputBuffers List of `InputBuffer` objects, identifying input
+     * buffers that are no longer needed by the component.
+     */
+    void onInputBuffersReleased(in InputBuffer[] inputBuffers);
+
+    /**
+     * Notify the listener that the component is tripped.
+     *
+     * @param settingResults List of failures.
+     */
+    void onTripped(in SettingResult[] settingResults);
+
+    /**
+     * Notify the listener that some `Work` items have been completed.
+     *
+     * All the input buffers in the returned `Work` objects must not be used by
+     * the component after onWorkDone() is called.
+     *
+     * @param workBundle List of completed `Work` objects.
+     */
+    void onWorkDone(in WorkBundle workBundle);
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/IComponentStore.aidl b/media/c2/aidl/android/hardware/media/c2/IComponentStore.aidl
new file mode 100644
index 0000000..1435a7e
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/IComponentStore.aidl
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2;
+
+import android.hardware.media.c2.Buffer;
+import android.hardware.media.c2.IComponent;
+import android.hardware.media.c2.IComponentInterface;
+import android.hardware.media.c2.IComponentListener;
+import android.hardware.media.c2.IConfigurable;
+import android.hardware.media.c2.StructDescriptor;
+
+/**
+ * Entry point for Codec2 HAL.
+ *
+ * All methods in `IComponentStore` must not block. If a method call cannot be
+ * completed in a timely manner, it must throw `Status::TIMED_OUT`. The only
+ * exceptions are getPoolClientManager() and getConfigurable(),  which must
+ * always return immediately.
+ *
+ * @note This is an extension of version 1.1 of `IComponentStore`. The purpose
+ * of the extension is to add support for blocking output buffer allocator.
+ */
+@VintfStability
+interface IComponentStore {
+    /**
+     * Component traits.
+     */
+    @VintfStability
+    parcelable ComponentTraits {
+        @VintfStability
+        @Backing(type="int")
+        enum Kind {
+            OTHER = 0,
+            DECODER,
+            ENCODER,
+        }
+        @VintfStability
+        @Backing(type="int")
+        enum Domain {
+            OTHER = 0,
+            VIDEO,
+            AUDIO,
+            IMAGE,
+        }
+        /**
+         * Name of the component. This must be unique for each component.
+         *
+         * This name is use to identify the component to create in
+         * createComponent() and createComponentInterface().
+         */
+        String name;
+        /**
+         * Component domain.
+         */
+        Domain domain;
+        /**
+         * Component kind.
+         */
+        Kind kind;
+        /**
+         * Rank used by `MediaCodecList` to determine component ordering. Lower
+         * value means higher priority.
+         */
+        int rank;
+        /**
+         * MIME type.
+         */
+        String mediaType;
+        /**
+         * Aliases for component name for backward compatibility.
+         *
+         * Multiple components can have the same alias (but not the same
+         * component name) as long as their media types differ.
+         */
+        String[] aliases;
+    }
+
+    /**
+     * Copies the contents of @p src into @p dst without changing the format of
+     * @p dst.
+     *
+     * @param src Source buffer.
+     * @param dst Destination buffer.
+     * @throws ServiceSpecificException with one of the following values:
+     *   - `Status::CANNOT_DO` - @p src and @p dst are not compatible.
+     *   - `Status::REFUSED`   - No permission to copy.
+     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `Status::CORRUPTED` - Some unknown error occurred.
+     */
+    void copyBuffer(in Buffer src, in Buffer dst);
+
+    /**
+     * Creates a component by name.
+     *
+     * @param name Name of the component to create. This must match one of the
+     *     names returned by listComponents().
+     * @param listener Callback receiver.
+     * @param pool `IClientManager` object of the BufferPool in the client
+     *     process. This may be null if the client does not own a BufferPool.
+     * @return The created component.
+     * @throws ServiceSpecificException with one of the following values:
+     *   - `Status::NOT_FOUND` - There is no component with the given name.
+     *   - `Status::NO_MEMORY` - Not enough memory to create the component.
+     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `Status::CORRUPTED` - Some unknown error occurred.
+     *
+     * @sa IComponentListener.
+     */
+    IComponent createComponent(in String name, in IComponentListener listener,
+        in android.hardware.media.bufferpool2.IClientManager pool);
+
+    /**
+     * Creates a component interface by name.
+     *
+     * @param name Name of the component interface to create. This should match
+     *     one of the names returned by listComponents().
+     * @return The created component interface.
+     * @throws ServiceSpecificException with one of the following values:
+     *   - `Status::NOT_FOUND` - There is no component interface with the given name.
+     *   - `Status::NO_MEMORY` - Not enough memory to create the component interface.
+     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `Status::CORRUPTED` - Some unknown error occurred.
+     */
+    IComponentInterface createInterface(in String name);
+
+    /**
+     * Returns the @ref IConfigurable instance associated to this component
+     * store.
+     *
+     * @return `IConfigurable` instance. This must not be null.
+     */
+    IConfigurable getConfigurable();
+
+    /**
+     * Returns the `IClientManager` object for the component's BufferPool.
+     *
+     * @return If the component store supports receiving buffers via
+     *     BufferPool API, @p pool must be a valid `IClientManager` instance.
+     *     Otherwise, @p pool must be null.
+     */
+    android.hardware.media.bufferpool2.IClientManager getPoolClientManager();
+
+    /**
+     * Returns a list of `StructDescriptor` objects for a set of requested
+     * C2Param structure indices that this store is aware of.
+     *
+     * This operation must be performed at best effort, e.g. the component
+     * store must simply ignore all struct indices that it is not aware of.
+     *
+     * @param indices Indices of C2Param structures to describe.
+     * @return List of `StructDescriptor` objects.
+     * @throws ServiceSpecificException with one of the following values:
+     *   - `Status::NOT_FOUND` - Some indices were not known.
+     *   - `Status::NO_MEMORY` - Not enough memory to complete this method.
+     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `Status::CORRUPTED` - Some unknown error occurred.
+     */
+    StructDescriptor[] getStructDescriptors(in int[] indices);
+
+    /**
+     * Returns the list of components supported by this component store.
+     *
+     * @return traits List of component traits for all components supported by
+     *     this store (in no particular order).
+     * @throws ServiceSpecificException with one of the following values:
+     *   - `Status::NO_MEMORY` - Not enough memory to complete this method.
+     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `Status::CORRUPTED` - Some unknown error occurred.
+     */
+    ComponentTraits[] listComponents();
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/IConfigurable.aidl b/media/c2/aidl/android/hardware/media/c2/IConfigurable.aidl
new file mode 100644
index 0000000..7fdb825
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/IConfigurable.aidl
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2;
+
+import android.hardware.media.c2.FieldSupportedValuesQuery;
+import android.hardware.media.c2.FieldSupportedValuesQueryResult;
+import android.hardware.media.c2.ParamDescriptor;
+import android.hardware.media.c2.Params;
+import android.hardware.media.c2.SettingResult;
+
+/**
+ * Generic configuration interface presented by all configurable Codec2 objects.
+ *
+ * This interface must be supported in all states of the owning object, and must
+ * not change the state of the owning object.
+ */
+@VintfStability
+interface IConfigurable {
+    /**
+     * Return parcelable for config() interface.
+     *
+     * This includes the successful config settings along with the failure reasons of
+     * the specified setting.
+     */
+    @VintfStability
+    parcelable ConfigResult {
+        Params params;
+        SettingResult[] failures;
+    }
+
+    /**
+     * Sets a set of parameters for the object.
+     *
+     * Tuning is performed at best effort: the object must update all supported
+     * configurations at best effort and skip unsupported parameters. Any errors
+     * are communicated in the return value along with the failures.
+     *
+     * A non-strict parameter update with an unsupported value shall cause an
+     * update to the closest supported value. A strict parameter update with an
+     * unsupported value shall be skipped and a failure shall be returned.
+     *
+     * If @p mayBlock is false, this method must not block. An update that
+     * requires blocking shall be skipped and a failure shall be returned.
+     *
+     * If @p mayBlock is true, an update may block, but the whole method call
+     * has to complete in a timely manner, or `Status::TIMED_OUT` is thrown.
+     *
+     * The final values for all parameters set are propagated back to the caller
+     * in @p params.
+     *
+     * \par For IComponent
+     *
+     * When the object type is @ref IComponent, this method must be supported in
+     * any state except released.
+     *
+     * The blocking behavior of this method differs among states:
+     *   - In the stopped state, this must be non-blocking. @p mayBlock is
+     *     ignored. (The method operates as if @p mayBlock was false.)
+     *   - In any of the running states, this method may block momentarily if
+     *     @p mayBlock is true. However, if the call cannot be completed in a
+     *     timely manner, `Status::TIMED_OUT` is thrown.
+     *
+     * @note Parameter tuning @e does depend on the order of the tuning
+     * parameters, e.g., some parameter update may enable some subsequent
+     * parameter update.
+     *
+     * @param inParams Requested parameter updates.
+     * @param mayBlock Whether this call may block or not.
+     * @return result of config. Params in the result should be in same order
+     *     with @p inParams.
+     * @throws ServiceSpecificException with one of the following values:
+     *   - `Status::NO_MEMORY` - Some supported parameters could not be updated
+     *                   successfully because they contained unsupported values.
+     *                   These are returned in @p failures.
+     *   - `Status::BLOCKING`  - Setting some parameters requires blocking, but
+     *                   @p mayBlock is false.
+     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `Status::CORRUPTED` - Some unknown error occurred.
+     */
+    ConfigResult config(in Params inParams, in boolean mayBlock);
+
+    /**
+     * Returns the id of the object. This must be unique among all objects of
+     * the same type hosted by the same store.
+     *
+     * @return Id of the object.
+     */
+    int getId();
+
+    /**
+     * Returns the name of the object.
+     *
+     * This must match the name that was supplied during the creation of the
+     * object.
+     *
+     * @return Name of the object.
+     */
+    String getName();
+
+    /**
+     * Queries a set of parameters from the object.
+     *
+     * Querying is performed at best effort: the object must query all supported
+     * parameters and skip unsupported ones (which may include parameters that
+     * could not be allocated).
+     *
+     * If @p mayBlock is true, a query may block, but the whole method call
+     * has to complete in a timely manner, or `Status::TIMED_OUT` is thrown.
+     *
+     * If @p mayBlock is false, this method must not block(All parameter queries
+     * that require blocking must be skipped). Otherwise, this
+     * method is allowed to block for a certain period of time before completing
+     * the operation. If the operation is not completed in a timely manner,
+     * `Status::TIMED_OUT` is thrown.
+     *
+     * @note Since unsupported parameters will be skipped, the returned results
+     *     does not have every settings from @p indices, but the result will preserve
+     *     the original order from @p indices though unsupported settings are skipped.
+     *
+     * \par For IComponent
+     *
+     * When the object type is @ref IComponent, this method must be supported in
+     * any state except released. This call must not change the state nor the
+     * internal configuration of the component.
+     *
+     * The blocking behavior of this method differs among states:
+     *   - In the stopped state, this must be non-blocking. @p mayBlock is
+     *     ignored. (The method operates as if @p mayBlock was false.)
+     *   - In any of the running states, this method may block momentarily if
+     *     @p mayBlock is true. However, if the call cannot be completed in a
+     *     timely manner, `Status::status` is thrown.
+     *
+     * @param indices List of C2Param structure indices to query.
+     * @param mayBlock Whether this call may block or not.
+     * @return Flattened representation of std::vector<C2Param> object.
+     *     Unsupported settings are skipped in the results. The order in @p indices
+     *     still be preserved except skipped settings.
+     * @throws ServiceSpecificException with one of the following values:
+     *   - `Status::NO_MEMORY` - Could not allocate memory for a supported parameter.
+     *   - `Status::BLOCKING`  - Querying some parameters requires blocking, but
+     *                   @p mayBlock is false.
+     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `Status::CORRUPTED` - Some unknown error occurred.
+     */
+    Params query(in int[] indices, in boolean mayBlock);
+
+    /**
+     * Returns a list of supported parameters within a selected range of C2Param
+     * structure indices.
+     *
+     * @param start The first index of the selected range.
+     * @param count The length of the selected range.
+     * @return List of supported parameters in the selected range. This
+     *     list may have fewer than @p count elements if some indices in the
+     *     range are not supported.
+     * @throws ServiceSpecificException with one of the following values:
+     *   - `Status::NO_MEMORY` - Not enough memory to complete this method.
+     *
+     */
+    ParamDescriptor[] querySupportedParams(in int start, in int count);
+
+    /**
+     * Retrieves the supported values for the queried fields.
+     *
+     * The object must process all fields queried even if some queries fail.
+     *
+     * If @p mayBlock is false, this method must not block. Otherwise, this
+     * method is allowed to block for a certain period of time before completing
+     * the operation. If the operation cannot be completed in a timely manner,
+     * `Status::TIMED_OUT` is thrown.
+     *
+     * \par For IComponent
+     *
+     * When the object type is @ref IComponent, this method must be supported in
+     * any state except released.
+     *
+     * The blocking behavior of this method differs among states:
+     *   - In the stopped state, this must be non-blocking. @p mayBlock is
+     *     ignored. (The method operates as if @p mayBlock was false.)
+     *   - In any of the running states, this method may block momentarily if
+     *     @p mayBlock is true. However, if the call cannot be completed in a
+     *     timely manner, `Status::TIMED_OUT` is thrown.
+     *
+     * @param inFields List of field queries.
+     * @param mayBlock Whether this call may block or not.
+     * @return List of supported values and results for the
+     *     supplied queries.
+     * @throws ServiceSpecificException with one of the following values:
+     *   - `Status::BLOCKING`  - Querying some parameters requires blocking, but
+     *                   @p mayBlock is false.
+     *   - `Status::NO_MEMORY` - Not enough memory to complete this method.
+     *   - `Status::BLOCKING`  - Querying some fields requires blocking, but @p mayblock
+     *                   is false.
+     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `Status::CORRUPTED` - Some unknown error occurred.
+     */
+    FieldSupportedValuesQueryResult[] querySupportedValues(
+            in FieldSupportedValuesQuery[] inFields, in boolean mayBlock);
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/InfoBuffer.aidl b/media/c2/aidl/android/hardware/media/c2/InfoBuffer.aidl
new file mode 100644
index 0000000..207c4d0
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/InfoBuffer.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.media.c2;
+
+import android.hardware.media.c2.Buffer;
+
+/**
+ * An extension of @ref Buffer that also contains a C2Param structure index.
+ *
+ * This is a part of @ref FrameData.
+ */
+@VintfStability
+parcelable InfoBuffer {
+    /**
+     * A C2Param structure index.
+     */
+    int index;
+    /**
+     * Associated @ref Buffer object.
+     */
+    Buffer buffer;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/ParamDescriptor.aidl b/media/c2/aidl/android/hardware/media/c2/ParamDescriptor.aidl
new file mode 100644
index 0000000..84c6acc
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/ParamDescriptor.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.
+ */
+
+package android.hardware.media.c2;
+
+/**
+ * Usage description of a C2Param structure.
+ *
+ * @ref ParamDescriptor is returned by IConfigurable::querySupportedParams().
+ */
+@VintfStability
+parcelable ParamDescriptor {
+    /** The list of bit flags for attrib */
+    /**
+     * The parameter is required to be specified.
+     */
+    const int ATTRIBUTE_REQUIRED = 1 << 0;
+    /**
+     * The parameter retains its value.
+     */
+    const int ATTRIBUTE_PERSISTENT = 1 << 1;
+    /**
+     * The parameter is strict.
+     */
+    const int ATTRIBUTE_STRICT = 1 << 2;
+    /**
+     * The parameter is publicly read-only.
+     */
+    const int ATTRIBUTE_READ_ONLY = 1 << 3;
+    /**
+     * The parameter must not be visible to clients.
+     */
+    const int ATTRIBUTE_HIDDEN = 1 << 4;
+    /**
+     * The parameter must not be used by framework (other than testing).
+     */
+    const int ATTRIBUTE_INTERNAL = 1 << 5;
+    /**
+     * The parameter is publicly constant (hence read-only).
+     */
+    const int ATTRIBUTE_CONST = 1 << 6;
+
+    /**
+     * Index of the C2Param structure being described.
+     */
+    int index;
+    /**
+     * bit flag for attribute defined in the above.
+     */
+    int attrib;
+    /**
+     * Name of the structure. This must be unique for each structure.
+     */
+    String name;
+    /**
+     * Indices of other C2Param structures that this C2Param structure depends
+     * on.
+     */
+    int[] dependencies;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/ParamField.aidl b/media/c2/aidl/android/hardware/media/c2/ParamField.aidl
new file mode 100644
index 0000000..64a46bb
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/ParamField.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.
+ */
+
+package android.hardware.media.c2;
+
+import android.hardware.media.c2.FieldId;
+
+/**
+ * Reference to a field in a C2Param structure.
+ */
+@VintfStability
+parcelable ParamField {
+    /**
+     * Index of the C2Param structure.
+     */
+    int index;
+    /**
+     * Identifier of the field inside the C2Param structure.
+     */
+    FieldId fieldId;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/ParamFieldValues.aidl b/media/c2/aidl/android/hardware/media/c2/ParamFieldValues.aidl
new file mode 100644
index 0000000..7b74c0e
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/ParamFieldValues.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.media.c2;
+
+import android.hardware.media.c2.FieldSupportedValues;
+import android.hardware.media.c2.ParamField;
+
+/**
+ * Supported values for a field.
+ *
+ * This is a pair of the field specifier together with an optional supported
+ * values object. This structure is used when reporting parameter configuration
+ * failures and conflicts.
+ */
+@VintfStability
+parcelable ParamFieldValues {
+    /**
+     * Reference to a field or a C2Param structure.
+     */
+    ParamField paramOrField;
+    /**
+     * Optional supported values for the field if #paramOrField specifies an
+     * actual field that is numeric (non struct, blob or string). Supported
+     * values for arrays (including string and blobs) describe the supported
+     * values for each element (character for string, and bytes for blobs). It
+     * is optional for read-only strings and blobs.
+     */
+    FieldSupportedValues[] values;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/Params.aidl b/media/c2/aidl/android/hardware/media/c2/Params.aidl
new file mode 100644
index 0000000..53b512c
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/Params.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.media.c2;
+
+/**
+ * Flattened representation of std::vector<C2Param> object.
+ *
+ * The `Params` type is an array of bytes made up by concatenating a list of
+ * C2Param objects. The start index (offset into @ref Params) of each C2Param
+ * object in the list is divisible by 8. Up to 7 padding bytes may be added
+ * after each C2Param object to achieve this 64-bit alignment.
+ *
+ * Each C2Param object has the following layout:
+ * - 4 bytes: C2Param structure index (of type @ref ParamIndex) identifying the
+ *   type of the C2Param object.
+ * - 4 bytes: size of the C2Param object (unsigned 4-byte integer).
+ * - (size - 8) bytes: data of the C2Param object.
+ */
+@VintfStability
+parcelable Params {
+    byte[] params;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/SettingResult.aidl b/media/c2/aidl/android/hardware/media/c2/SettingResult.aidl
new file mode 100644
index 0000000..c2b9574
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/SettingResult.aidl
@@ -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.
+ */
+
+package android.hardware.media.c2;
+
+import android.hardware.media.c2.ParamFieldValues;
+
+/**
+ * Information describing the reason the parameter settings may fail, or may be
+ * overridden.
+ */
+@VintfStability
+parcelable SettingResult {
+    /**
+     * Failure code
+     */
+    @VintfStability
+    @Backing(type="int")
+    enum Failure {
+        /**
+         * Parameter is not supported.
+         */
+        BAD_TYPE,
+        /**
+         * Parameter is not supported on the specific port.
+         */
+        BAD_PORT,
+        /**
+         * Parameter is not supported on the specific stream.
+         */
+        BAD_INDEX,
+        /**
+         * Parameter is read-only and cannot be set.
+         */
+        READ_ONLY,
+        /**
+         * Parameter mismatches input data.
+         */
+        MISMATCH,
+        /**
+         * Strict parameter does not accept value for the field at all.
+         */
+        BAD_VALUE,
+        /**
+         * Strict parameter field value is in conflict with an/other
+         * setting(s).
+         */
+        CONFLICT,
+        /**
+         * Parameter field is out of range due to other settings. (This failure
+         * mode can only be used for strict calculated parameters.)
+         */
+        UNSUPPORTED,
+        /**
+         * Field does not access the requested parameter value at all. It has
+         * been corrected to the closest supported value. This failure mode is
+         * provided to give guidance as to what are the currently supported
+         * values for this field (which may be a subset of the at-all-potential
+         * values).
+         */
+        INFO_BAD_VALUE,
+        /**
+         * Requested parameter value is in conflict with an/other setting(s)
+         * and has been corrected to the closest supported value. This failure
+         * mode is given to provide guidance as to what are the currently
+         * supported values as well as to optionally provide suggestion to the
+         * client as to how to enable the requested parameter value.
+         */
+        INFO_CONFLICT,
+    }
+    Failure failure;
+    /**
+     * Failing (or corrected) field or parameter and optionally, currently
+     * supported values for the field. Values must only be set for field
+     * failures other than `BAD_VALUE`, and only if they are different from the
+     * globally supported values (e.g. due to restrictions by another parameter
+     * or input data).
+     */
+    ParamFieldValues field;
+    /**
+     * Conflicting parameters or fields with (optional) suggested values for any
+     * conflicting fields to avoid the conflict. Values must only be set for
+     * `CONFLICT`, `UNSUPPORTED` or `INFO_CONFLICT` failure code.
+     */
+    ParamFieldValues[] conflicts;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/Status.aidl b/media/c2/aidl/android/hardware/media/c2/Status.aidl
new file mode 100644
index 0000000..58a2404
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/Status.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.
+ */
+
+package android.hardware.media.c2;
+
+/**
+ * Common return values for Codec2 operations.
+ */
+@VintfStability
+parcelable Status {
+    /**
+     * Operation completed successfully.
+     */
+    const int OK = 0;
+    /**
+     * Argument has invalid value (user error).
+     */
+    const int BAD_VALUE = -22;
+    /**
+     * Argument uses invalid index (user error).
+     */
+    const int BAD_INDEX = -75;
+    /**
+     * Argument/Index is valid but not possible.
+     */
+    const int CANNOT_DO = -2147483646;
+    /**
+     * Object already exists.
+     */
+    const int DUPLICATE = -17;
+    /**
+     * Object not found.
+     */
+    const int NOT_FOUND = -2;
+    /**
+     * Operation is not permitted in the current state.
+     */
+    const int BAD_STATE = -38;
+    /**
+     * Operation would block but blocking is not permitted.
+     */
+    const int BLOCKING = -9930;
+    /**
+     * Not enough memory to complete operation.
+     */
+    const int NO_MEMORY = -12;
+    /**
+     * Missing permission to complete operation.
+     */
+    const int REFUSED = -1;
+    /**
+     * Operation did not complete within timeout.
+     */
+    const int TIMED_OUT = -110;
+    /**
+     * Operation is not implemented/supported (optional only).
+     */
+    const int OMITTED = -74;
+    /**
+     * Some unexpected error prevented the operation.
+     */
+    const int CORRUPTED = -2147483648;
+    /**
+     * Status has not been initialized.
+     */
+    const int NO_INIT = -19;
+
+    int status;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/StructDescriptor.aidl b/media/c2/aidl/android/hardware/media/c2/StructDescriptor.aidl
new file mode 100644
index 0000000..00359041
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/StructDescriptor.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.media.c2;
+
+import android.hardware.media.c2.FieldDescriptor;
+
+/**
+ * Description of a C2Param structure. It consists of an index and a list of
+ * `FieldDescriptor`s.
+ */
+@VintfStability
+parcelable StructDescriptor {
+    /**
+     * Index of the structure.
+     *
+     * Actually C2Param::CoreIndex
+     * Core index is the underlying parameter type for a parameter. It is used to describe the
+     * layout of the parameter structure regardless of the component or parameter kind/scope.
+     *
+     * It is used to identify and distinguish global parameters, and also parameters on a given
+     * port or stream. They must be unique for the set of global parameters, as well as for the
+     * set of parameters on each port or each stream, but the same core index can be used for
+     * parameters on different streams or ports, as well as for global parameters and port/stream
+     * parameters.
+     */
+    int type;
+    /**
+     * List of fields in the structure.
+     *
+     * Fields are ordered by their offsets. A field that is a structure is
+     * ordered before its members.
+     */
+    FieldDescriptor[] fields;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/SurfaceSyncObj.aidl b/media/c2/aidl/android/hardware/media/c2/SurfaceSyncObj.aidl
new file mode 100644
index 0000000..d20e102
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/SurfaceSyncObj.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.media.c2;
+
+import android.hardware.common.NativeHandle;
+/**
+ * Surface(BufferQueue/IGBP) synchronization object regarding # of dequeued
+ * output buffers. This keeps # of dequeued buffers from Surface less than
+ * configured max # of dequeued buffers all the time.
+ */
+@VintfStability
+parcelable SurfaceSyncObj {
+    /**
+     * ASharedMemory for synchronization data. Layout is below
+     *
+     * |lock(futex)                               4bytes|
+     * |conditional_variable(futex)               4bytes|
+     * |# of max dequeable buffer                 4bytes|
+     * |# of dequeued buffer                      4bytes|
+     * |Status of the surface                     4bytes|
+     *      INIT        = 0, Configuring surface is not finished.
+     *      ACTIVE      = 1, Surface is ready to allocate(dequeue).
+     *      SWITCHING   = 2, Switching to the new surface. It is blocked
+     *                       to allocate(dequeue) a buffer until switching
+     *                       completes.
+     */
+    NativeHandle syncMemory;
+    /**
+     * BufferQueue id.
+     */
+    long bqId;
+    /**
+     * Generation id.
+     */
+    int generationId;
+    /**
+     * Consumer usage flags. See +ndk
+     * libnativewindow#AHardwareBuffer_UsageFlags for possible values.
+     */
+    long consumerUsage;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/ValueRange.aidl b/media/c2/aidl/android/hardware/media/c2/ValueRange.aidl
new file mode 100644
index 0000000..9abcb7d
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/ValueRange.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.media.c2;
+
+/**
+ * Description of a set of values.
+ *
+ * If the `step` member is 0, and `num` and `denom` are both 1, the `Range`
+ * structure represents a closed interval bounded by `min` and `max`.
+ *
+ * Otherwise, the #ValueRange structure represents a finite sequence of numbers
+ * produced from the following recurrence relation:
+ *
+ * @code
+ * v[0] = min
+ * v[i] = v[i - 1] * num / denom + step ; i >= 1
+ * @endcode
+ *
+ * Both the ratio `num / denom` and the value `step` must be positive. The
+ * last number in the sequence described by this #Range structure is the
+ * largest number in the sequence that is smaller than or equal to `max`.
+ *
+ * @note
+ * The division in the formula may truncate the result if the data type of
+ * these values is an integral type.
+ */
+@VintfStability
+parcelable ValueRange {
+    /**
+     * Lower end of the range (inclusive).
+     */
+    long min;
+    /**
+     * Upper end of the range (inclusive).
+     */
+    long max;
+    /**
+     * The non-homogeneous term in the recurrence relation.
+     */
+    long step;
+    /**
+     * The numerator of the scale coefficient in the recurrence relation.
+     */
+    long num;
+    /**
+     * The denominator of the scale coefficient in the recurrence relation.
+     */
+    long denom;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/Work.aidl b/media/c2/aidl/android/hardware/media/c2/Work.aidl
new file mode 100644
index 0000000..4b8d696
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/Work.aidl
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2;
+
+import android.hardware.media.c2.FrameData;
+import android.hardware.media.c2.Status;
+import android.hardware.media.c2.Worklet;
+
+/**
+ * A collection of input data to and output data from the component.
+ *
+ * A `Work` object holds information about a single work item. It is created by
+ * the client and passed to the component via IComponent::queue(). The component
+ * has two ways of returning a `Work` object to the client:
+ *   1. If the queued `Work` object has been successfully processed,
+ *      IComponentListener::onWorkDone() shall be called to notify the listener,
+ *      and the output shall be included in the returned `Work` object.
+ *   2. If the client calls IComponent::flush(), a `Work` object that has not
+ *      been processed shall be returned.
+ *
+ * `Work` is a part of @ref WorkBundle.
+ */
+@VintfStability
+parcelable Work {
+    /**
+     * Additional work chain info not part of this work.
+     */
+    byte[] chainInfo;
+    /**
+     * @ref FrameData for the input.
+     */
+    FrameData input;
+    /**
+     * The chain of `Worklet`s.
+     *
+     * The length of #worklets is 1 when tunneling is not enabled.
+     *
+     * If #worklets has more than a single element, the tunnels between
+     * successive components of the work chain must have been successfully
+     * pre-registered at the time that the `Work` is submitted. Allocating the
+     * output buffers in the `Worklet`s is the responsibility of each component
+     * in the chain.
+     *
+     * Upon `Work` submission, #worklets must be an appropriately sized vector
+     * containing `Worklet`s with @ref Worklet.hasOutput set to `false`. After a
+     * successful processing, all but the final `Worklet` in the returned
+     * #worklets must have @ref Worklet.hasOutput set to `false`.
+     */
+    Worklet[] worklets;
+    /**
+     * The number of `Worklet`s successfully processed in this chain.
+     *
+     * This must be initialized to 0 by the client when the `Work` is submitted,
+     * and it must contain the number of `Worklet`s that were successfully
+     * processed when the `Work` is returned to the client.
+     *
+     * #workletsProcessed cannot exceed the length of #worklets. If
+     * #workletsProcessed is smaller than the length of #worklets, #result
+     * cannot be `OK`.
+     */
+    int workletsProcessed;
+    /**
+     * The final outcome of the `Work` (corresponding to #workletsProcessed).
+     *
+     * The value of @ref Status.OK implies that all `Worklet`s have been
+     * successfully processed.
+     */
+    Status result;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/WorkBundle.aidl b/media/c2/aidl/android/hardware/media/c2/WorkBundle.aidl
new file mode 100644
index 0000000..2125fda
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/WorkBundle.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.media.c2;
+
+import android.hardware.media.c2.BaseBlock;
+import android.hardware.media.c2.Work;
+
+/**
+ * List of `Work` objects.
+ *
+ * `WorkBundle` is used in IComponent::queue(), IComponent::flush() and
+ * IComponentListener::onWorkDone(). A `WorkBundle` object consists of a list of
+ * `Work` objects and a list of `BaseBlock` objects. Bundling multiple `Work`
+ * objects together provides two benefits:
+ *   1. Batching of `Work` objects can reduce the number of IPC calls.
+ *   2. If multiple `Work` objects contain `Block`s that refer to the same
+ *      `BaseBlock`, the number of `BaseBlock`s that is sent between processes
+ *      is also reduced.
+ *
+ * @note `WorkBundle` is the AIDL counterpart of the vector of `C2Work` in the
+ * Codec 2.0 standard. The presence of #baseBlocks helps with minimizing the
+ * data transferred over an IPC.
+ */
+@VintfStability
+parcelable WorkBundle {
+    /**
+     * A list of Work items.
+     */
+    Work[] works;
+    /**
+     * A list of blocks indexed by elements of #works.
+     */
+    BaseBlock[] baseBlocks;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/WorkOrdinal.aidl b/media/c2/aidl/android/hardware/media/c2/WorkOrdinal.aidl
new file mode 100644
index 0000000..5708a90
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/WorkOrdinal.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.media.c2;
+
+/**
+ * Ordering information of @ref FrameData objects. Each member is used for
+ * comparing urgency: a smaller difference from a reference value indicates that
+ * the associated Work object is more urgent. The reference value for each
+ * member is initialized the first time it is communicated between the client
+ * and the codec, and it may be updated to later values that are communicated.
+ *
+ * Each member of `WorkOrdinal` is stored as an unsigned integer, but the actual
+ * order it represents is derived by subtracting the reference value, then
+ * interpreting the result as a signed number with the same storage size (using
+ * two's complement).
+ *
+ * @note `WorkOrdinal` is the HIDL counterpart of `C2WorkOrdinalStruct` in the
+ * Codec 2.0 standard.
+ */
+@VintfStability
+parcelable WorkOrdinal {
+    /**
+     * Timestamp in microseconds.
+     */
+    long timestampUs;
+    /**
+     * Frame index.
+     */
+    long frameIndex;
+    /**
+     * Component specific frame ordinal.
+     */
+    long customOrdinal;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/Worklet.aidl b/media/c2/aidl/android/hardware/media/c2/Worklet.aidl
new file mode 100644
index 0000000..6b3ceac
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/Worklet.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.media.c2;
+
+import android.hardware.media.c2.FrameData;
+import android.hardware.media.c2.SettingResult;
+
+/**
+ * In/out structure containing some instructions for and results from output
+ * processing.
+ *
+ * This is a part of @ref Work. One `Worklet` corresponds to one output
+ * @ref FrameData. The client must construct an original `Worklet` object inside
+ * a @ref Work object for each expected output before calling
+ * IComponent::queue().
+ */
+@VintfStability
+parcelable Worklet {
+    /**
+     * Component id. (Input)
+     *
+     * This is used only when tunneling is enabled.
+     *
+     * When used, this must match the return value from IConfigurable::getId().
+     */
+    int componentId;
+    /**
+     * List of C2Param objects describing tunings to be applied before
+     * processing this `Worklet`. (Input)
+     */
+    byte[] tunings;
+    /**
+     * List of failures. (Output)
+     */
+    SettingResult[] failures;
+    /**
+     * Output frame data. (Output)
+     */
+    FrameData output;
+}
diff --git a/memtrack/aidl/Android.bp b/memtrack/aidl/Android.bp
index 79effcb..0d1c241 100644
--- a/memtrack/aidl/Android.bp
+++ b/memtrack/aidl/Android.bp
@@ -39,5 +39,6 @@
             },
         },
     },
+    frozen: true,
     versions: ["1"],
 }
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/aidl/Android.bp b/neuralnetworks/aidl/Android.bp
index db1188d..be86879 100644
--- a/neuralnetworks/aidl/Android.bp
+++ b/neuralnetworks/aidl/Android.bp
@@ -17,7 +17,7 @@
     stability: "vintf",
     imports: [
         "android.hardware.common-V2",
-        "android.hardware.graphics.common-V3",
+        "android.hardware.graphics.common-V4",
     ],
     backend: {
         java: {
@@ -40,28 +40,28 @@
             version: "1",
             imports: [
                 "android.hardware.common-V2",
-                "android.hardware.graphics.common-V3",
+                "android.hardware.graphics.common-V4",
             ],
         },
         {
             version: "2",
             imports: [
                 "android.hardware.common-V2",
-                "android.hardware.graphics.common-V3",
+                "android.hardware.graphics.common-V4",
             ],
         },
         {
             version: "3",
             imports: [
                 "android.hardware.common-V2",
-                "android.hardware.graphics.common-V3",
+                "android.hardware.graphics.common-V4",
             ],
         },
         {
             version: "4",
             imports: [
                 "android.hardware.common-V2",
-                "android.hardware.graphics.common-V3",
+                "android.hardware.graphics.common-V4",
             ],
         },
 
diff --git a/oemlock/aidl/default/OemLock.cpp b/oemlock/aidl/default/OemLock.cpp
index 646b532..234a8a9 100644
--- a/oemlock/aidl/default/OemLock.cpp
+++ b/oemlock/aidl/default/OemLock.cpp
@@ -24,29 +24,31 @@
 // Methods from ::android::hardware::oemlock::IOemLock follow.
 
 ::ndk::ScopedAStatus OemLock::getName(std::string *out_name) {
-    (void)out_name;
+    *out_name = "SomeCoolName";
     return ::ndk::ScopedAStatus::ok();
 }
 
 ::ndk::ScopedAStatus OemLock::setOemUnlockAllowedByCarrier(bool in_allowed, const std::vector<uint8_t> &in_signature, OemLockSecureStatus *_aidl_return) {
-    (void)in_allowed;
+    // Default impl doesn't care about a valid vendor signature
     (void)in_signature;
-    (void)_aidl_return;
+
+    mAllowedByCarrier = in_allowed;
+    *_aidl_return = OemLockSecureStatus::OK;
     return ::ndk::ScopedAStatus::ok();
 }
 
 ::ndk::ScopedAStatus OemLock::isOemUnlockAllowedByCarrier(bool *out_allowed) {
-    (void)out_allowed;
+    *out_allowed = mAllowedByCarrier;
     return ::ndk::ScopedAStatus::ok();
 }
 
 ::ndk::ScopedAStatus OemLock::setOemUnlockAllowedByDevice(bool in_allowed) {
-    (void)in_allowed;
+    mAllowedByDevice = in_allowed;
     return ::ndk::ScopedAStatus::ok();
 }
 
 ::ndk::ScopedAStatus OemLock::isOemUnlockAllowedByDevice(bool *out_allowed) {
-    (void)out_allowed;
+    *out_allowed = mAllowedByDevice;
     return ::ndk::ScopedAStatus::ok();
 }
 
diff --git a/oemlock/aidl/default/OemLock.h b/oemlock/aidl/default/OemLock.h
index b0df414..9dff21a 100644
--- a/oemlock/aidl/default/OemLock.h
+++ b/oemlock/aidl/default/OemLock.h
@@ -36,6 +36,10 @@
     ::ndk::ScopedAStatus isOemUnlockAllowedByDevice(bool* out_allowed) override;
     ::ndk::ScopedAStatus setOemUnlockAllowedByCarrier(bool in_allowed, const std::vector<uint8_t>& in_signature, OemLockSecureStatus* _aidl_return) override;
     ::ndk::ScopedAStatus setOemUnlockAllowedByDevice(bool in_allowed) override;
+
+  private:
+    bool mAllowedByCarrier = false;
+    bool mAllowedByDevice = false;
 };
 
 } // namespace oemlock
diff --git a/power/TEST_MAPPING b/power/TEST_MAPPING
new file mode 100644
index 0000000..c0963f9
--- /dev/null
+++ b/power/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "VtsHalPowerTargetTest"
+    }
+  ]
+}
diff --git a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPowerHintSession.aidl b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPowerHintSession.aidl
index 928668c..e6809da 100644
--- a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPowerHintSession.aidl
+++ b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPowerHintSession.aidl
@@ -40,4 +40,5 @@
   oneway void resume();
   oneway void close();
   oneway void sendHint(android.hardware.power.SessionHint hint);
+  void setThreads(in int[] threadIds);
 }
diff --git a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/SessionHint.aidl b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/SessionHint.aidl
index b19c77b..9c1f381 100644
--- a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/SessionHint.aidl
+++ b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/SessionHint.aidl
@@ -38,4 +38,5 @@
   CPU_LOAD_DOWN = 1,
   CPU_LOAD_RESET = 2,
   CPU_LOAD_RESUME = 3,
+  POWER_EFFICIENCY = 4,
 }
diff --git a/power/aidl/android/hardware/power/IPowerHintSession.aidl b/power/aidl/android/hardware/power/IPowerHintSession.aidl
index 4ca9c54..7db0ea1 100644
--- a/power/aidl/android/hardware/power/IPowerHintSession.aidl
+++ b/power/aidl/android/hardware/power/IPowerHintSession.aidl
@@ -20,7 +20,7 @@
 import android.hardware.power.WorkDuration;
 
 @VintfStability
-oneway interface IPowerHintSession {
+interface IPowerHintSession {
     /**
      * Updates the desired duration of a previously-created thread group.
      *
@@ -29,7 +29,7 @@
      *
      * @param targetDurationNanos the new desired duration in nanoseconds
      */
-    void updateTargetWorkDuration(long targetDurationNanos);
+    oneway void updateTargetWorkDuration(long targetDurationNanos);
 
     /**
      * Reports the actual duration of a thread group.
@@ -41,22 +41,22 @@
      * @param actualDurationMicros how long the thread group took to complete its
      *        last task in nanoseconds
      */
-    void reportActualWorkDuration(in WorkDuration[] durations);
+    oneway void reportActualWorkDuration(in WorkDuration[] durations);
 
     /**
      * Pause the session when the application is not allowed to send hint in framework.
      */
-    void pause();
+    oneway void pause();
 
     /**
      * Resume the session when the application is allowed to send hint in framework.
      */
-    void resume();
+    oneway void resume();
 
     /**
      * Close the session to release resources.
      */
-    void close();
+    oneway void close();
 
     /**
      * Gives information to the PowerHintSession about upcoming or unexpected
@@ -64,5 +64,21 @@
      *
      * @param hint The hint to provide to the PowerHintSession
      */
-    void sendHint(SessionHint hint);
+    oneway void sendHint(SessionHint hint);
+
+    /**
+     * Sets a list of threads to the power hint session. This operation will replace
+     * the current list of threads with the given list of threads. If there's already
+     * boost for the replaced threads, a reset must be performed for the replaced
+     * threads. Note that this is not an oneway method.
+     *
+     * @param threadIds The list of threads to be associated
+     * with this session.
+     *
+     * @throws ScopedAStatus Status of the operation. If status code is not
+     *    STATUS_OK, getMessage() must be populated with the human-readable
+     *    error message. If the list of thread ids is empty, EX_ILLEGAL_ARGUMENT
+     *    must be thrown.
+     */
+    void setThreads(in int[] threadIds);
 }
diff --git a/power/aidl/android/hardware/power/SessionHint.aidl b/power/aidl/android/hardware/power/SessionHint.aidl
index 6a95035..a172e12 100644
--- a/power/aidl/android/hardware/power/SessionHint.aidl
+++ b/power/aidl/android/hardware/power/SessionHint.aidl
@@ -25,22 +25,31 @@
      * This hint must be sent before reporting the actual duration to the session.
      */
     CPU_LOAD_UP = 0,
+
     /**
      * This hint indicates a decrease in CPU workload intensity. It means that
      * this hint session can reduce CPU resources and still meet the target duration.
      */
     CPU_LOAD_DOWN = 1,
-    /*
+
+    /**
      * This hint indicates an upcoming CPU workload that is completely changed and
      * unknown. It means that the hint session should reset CPU resources to a known
      * baseline to prepare for an arbitrary load, and must wake up if inactive.
      */
     CPU_LOAD_RESET = 2,
-    /*
+
+    /**
      * This hint indicates that the most recent CPU workload is resuming after a
      * period of inactivity. It means that the hint session should allocate similar
      * CPU resources to what was used previously, and must wake up if inactive.
      */
     CPU_LOAD_RESUME = 3,
 
+    /**
+     * This hint indicates that this power hint session should be applied with a
+     * power-efficient-first scheduling strategy. This means the work of this
+     * power hint session is noncritical despite its CPU intensity.
+     */
+    POWER_EFFICIENCY = 4,
 }
diff --git a/power/aidl/default/Android.bp b/power/aidl/default/Android.bp
index d1257f3..da91ee6 100644
--- a/power/aidl/default/Android.bp
+++ b/power/aidl/default/Android.bp
@@ -35,6 +35,7 @@
     srcs: [
         "main.cpp",
         "Power.cpp",
+        "PowerHintSession.cpp",
     ],
 }
 
diff --git a/power/aidl/default/Power.cpp b/power/aidl/default/Power.cpp
index 7f08f44..8fe370c 100644
--- a/power/aidl/default/Power.cpp
+++ b/power/aidl/default/Power.cpp
@@ -15,6 +15,7 @@
  */
 
 #include "Power.h"
+#include "PowerHintSession.h"
 
 #include <android-base/logging.h>
 
@@ -25,42 +26,53 @@
 namespace impl {
 namespace example {
 
+using namespace std::chrono_literals;
+
+using ndk::ScopedAStatus;
+
 const std::vector<Boost> BOOST_RANGE{ndk::enum_range<Boost>().begin(),
                                      ndk::enum_range<Boost>().end()};
 const std::vector<Mode> MODE_RANGE{ndk::enum_range<Mode>().begin(), ndk::enum_range<Mode>().end()};
 
-ndk::ScopedAStatus Power::setMode(Mode type, bool enabled) {
+ScopedAStatus Power::setMode(Mode type, bool enabled) {
     LOG(VERBOSE) << "Power setMode: " << static_cast<int32_t>(type) << " to: " << enabled;
-    return ndk::ScopedAStatus::ok();
+    return ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Power::isModeSupported(Mode type, bool* _aidl_return) {
+ScopedAStatus Power::isModeSupported(Mode type, bool* _aidl_return) {
     LOG(INFO) << "Power isModeSupported: " << static_cast<int32_t>(type);
     *_aidl_return = type >= MODE_RANGE.front() && type <= MODE_RANGE.back();
-    return ndk::ScopedAStatus::ok();
+    return ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Power::setBoost(Boost type, int32_t durationMs) {
+ScopedAStatus Power::setBoost(Boost type, int32_t durationMs) {
     LOG(VERBOSE) << "Power setBoost: " << static_cast<int32_t>(type)
                  << ", duration: " << durationMs;
-    return ndk::ScopedAStatus::ok();
+    return ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Power::isBoostSupported(Boost type, bool* _aidl_return) {
+ScopedAStatus Power::isBoostSupported(Boost type, bool* _aidl_return) {
     LOG(INFO) << "Power isBoostSupported: " << static_cast<int32_t>(type);
     *_aidl_return = type >= BOOST_RANGE.front() && type <= BOOST_RANGE.back();
-    return ndk::ScopedAStatus::ok();
+    return ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Power::createHintSession(int32_t, int32_t, const std::vector<int32_t>&, int64_t,
-                                            std::shared_ptr<IPowerHintSession>* _aidl_return) {
-    *_aidl_return = nullptr;
-    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ScopedAStatus Power::createHintSession(int32_t, int32_t, const std::vector<int32_t>& tids, int64_t,
+                                       std::shared_ptr<IPowerHintSession>* _aidl_return) {
+    if (tids.size() == 0) {
+        *_aidl_return = nullptr;
+        return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+    std::shared_ptr<IPowerHintSession> powerHintSession =
+            ndk::SharedRefBase::make<PowerHintSession>();
+    mPowerHintSessions.push_back(powerHintSession);
+    *_aidl_return = powerHintSession;
+    return ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Power::getHintSessionPreferredRate(int64_t* outNanoseconds) {
-    *outNanoseconds = -1;
-    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ScopedAStatus Power::getHintSessionPreferredRate(int64_t* outNanoseconds) {
+    *outNanoseconds = std::chrono::nanoseconds(1ms).count();
+    return ScopedAStatus::ok();
 }
 
 }  // namespace example
diff --git a/power/aidl/default/Power.h b/power/aidl/default/Power.h
index ef6439d..7f8405e 100644
--- a/power/aidl/default/Power.h
+++ b/power/aidl/default/Power.h
@@ -26,6 +26,7 @@
 namespace example {
 
 class Power : public BnPower {
+  public:
     ndk::ScopedAStatus setMode(Mode type, bool enabled) override;
     ndk::ScopedAStatus isModeSupported(Mode type, bool* _aidl_return) override;
     ndk::ScopedAStatus setBoost(Boost type, int32_t durationMs) override;
@@ -35,6 +36,9 @@
                                          int64_t durationNanos,
                                          std::shared_ptr<IPowerHintSession>* _aidl_return) override;
     ndk::ScopedAStatus getHintSessionPreferredRate(int64_t* outNanoseconds) override;
+
+  private:
+    std::vector<std::shared_ptr<IPowerHintSession>> mPowerHintSessions;
 };
 
 }  // namespace example
diff --git a/power/aidl/default/PowerHintSession.cpp b/power/aidl/default/PowerHintSession.cpp
new file mode 100644
index 0000000..f395800
--- /dev/null
+++ b/power/aidl/default/PowerHintSession.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 "PowerHintSession.h"
+
+#include <android-base/logging.h>
+
+namespace aidl::android::hardware::power::impl::example {
+
+using ndk::ScopedAStatus;
+
+PowerHintSession::PowerHintSession() {}
+
+ScopedAStatus PowerHintSession::updateTargetWorkDuration(int64_t targetDurationNanos) {
+    LOG(VERBOSE) << __func__ << "target duration in nanoseconds: " << targetDurationNanos;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus PowerHintSession::reportActualWorkDuration(
+        const std::vector<WorkDuration>& /* durations */) {
+    LOG(VERBOSE) << __func__;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus PowerHintSession::pause() {
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus PowerHintSession::resume() {
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus PowerHintSession::close() {
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus PowerHintSession::sendHint(SessionHint /* hint */) {
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus PowerHintSession::setThreads(const std::vector<int32_t>& threadIds) {
+    if (threadIds.size() == 0) {
+        LOG(ERROR) << "Error: threadIds.size() shouldn't be " << threadIds.size();
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+    return ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::power::impl::example
diff --git a/power/aidl/default/PowerHintSession.h b/power/aidl/default/PowerHintSession.h
new file mode 100644
index 0000000..1d74716
--- /dev/null
+++ b/power/aidl/default/PowerHintSession.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/power/BnPowerHintSession.h>
+#include <aidl/android/hardware/power/SessionHint.h>
+#include <aidl/android/hardware/power/WorkDuration.h>
+
+namespace aidl::android::hardware::power::impl::example {
+
+class PowerHintSession : public BnPowerHintSession {
+  public:
+    explicit PowerHintSession();
+    ndk::ScopedAStatus updateTargetWorkDuration(int64_t targetDurationNanos) override;
+    ndk::ScopedAStatus reportActualWorkDuration(
+            const std::vector<WorkDuration>& durations) override;
+    ndk::ScopedAStatus pause() override;
+    ndk::ScopedAStatus resume() override;
+    ndk::ScopedAStatus close() override;
+    ndk::ScopedAStatus sendHint(SessionHint hint) override;
+    ndk::ScopedAStatus setThreads(const std::vector<int32_t>& threadIds) override;
+};
+
+}  // namespace aidl::android::hardware::power::impl::example
diff --git a/power/aidl/vts/Android.bp b/power/aidl/vts/Android.bp
index d5cc2b6..56c98bd 100644
--- a/power/aidl/vts/Android.bp
+++ b/power/aidl/vts/Android.bp
@@ -35,6 +35,7 @@
         "android.hardware.power-V4-ndk",
     ],
     test_suites: [
+        "general-tests",
         "vts",
     ],
 }
diff --git a/power/aidl/vts/VtsHalPowerTargetTest.cpp b/power/aidl/vts/VtsHalPowerTargetTest.cpp
index dcf075f..5f5ce56 100644
--- a/power/aidl/vts/VtsHalPowerTargetTest.cpp
+++ b/power/aidl/vts/VtsHalPowerTargetTest.cpp
@@ -92,6 +92,18 @@
         DurationWrapper(1000000000L, 4L),
 };
 
+// DEVICEs launching with Android 11 MUST meet the requirements for the
+// target-level=5 compatibility_matrix file.
+const uint64_t kCompatibilityMatrix5ApiLevel = 30;
+
+// DEVICEs launching with Android 13 MUST meet the requirements for the
+// target-level=7 compatibility_matrix file.
+const uint64_t kCompatibilityMatrix7ApiLevel = 33;
+
+// DEVICEs launching with Android 14 MUST meet the requirements for the
+// target-level=8 compatibility_matrix file.
+const uint64_t kCompatibilityMatrix8ApiLevel = 34;
+
 inline bool isUnknownOrUnsupported(const ndk::ScopedAStatus& status) {
     return status.getStatus() == STATUS_UNKNOWN_TRANSACTION ||
            status.getExceptionCode() == EX_UNSUPPORTED_OPERATION;
@@ -103,9 +115,13 @@
         AIBinder* binder = AServiceManager_waitForService(GetParam().c_str());
         ASSERT_NE(binder, nullptr);
         power = IPower::fromBinder(ndk::SpAIBinder(binder));
+
+        mApiLevel = GetUintProperty<uint64_t>("ro.vendor.api_level", 0);
+        ASSERT_NE(mApiLevel, 0);
     }
 
     std::shared_ptr<IPower> power;
+    uint64_t mApiLevel;
 };
 
 TEST_P(PowerAidl, setMode) {
@@ -161,11 +177,11 @@
 TEST_P(PowerAidl, getHintSessionPreferredRate) {
     int64_t rate = -1;
     auto status = power->getHintSessionPreferredRate(&rate);
-    if (!status.isOk()) {
+    if (mApiLevel < kCompatibilityMatrix7ApiLevel && !status.isOk()) {
         EXPECT_TRUE(isUnknownOrUnsupported(status));
-        return;
+        GTEST_SKIP() << "DEVICE not launching with Android 13 and beyond.";
     }
-
+    ASSERT_TRUE(status.isOk());
     // At least 1ms rate limit from HAL
     ASSERT_GE(rate, 1000000);
 }
@@ -173,10 +189,11 @@
 TEST_P(PowerAidl, createAndCloseHintSession) {
     std::shared_ptr<IPowerHintSession> session;
     auto status = power->createHintSession(getpid(), getuid(), kSelfTids, 16666666L, &session);
-    if (!status.isOk()) {
+    if (mApiLevel < kCompatibilityMatrix7ApiLevel && !status.isOk()) {
         EXPECT_TRUE(isUnknownOrUnsupported(status));
-        return;
+        GTEST_SKIP() << "DEVICE not launching with Android 13 and beyond.";
     }
+    ASSERT_TRUE(status.isOk());
     ASSERT_NE(nullptr, session);
     ASSERT_TRUE(session->pause().isOk());
     ASSERT_TRUE(session->resume().isOk());
@@ -188,9 +205,14 @@
 TEST_P(PowerAidl, createHintSessionFailed) {
     std::shared_ptr<IPowerHintSession> session;
     auto status = power->createHintSession(getpid(), getuid(), kEmptyTids, 16666666L, &session);
+
+    // Regardless of whether V2 and beyond is supported, the status is always not STATUS_OK.
     ASSERT_FALSE(status.isOk());
-    if (isUnknownOrUnsupported(status)) {
-        return;
+
+    // If device not launching with Android 13 and beyond, check whether it's supported,
+    // if not, skip the test.
+    if (mApiLevel < kCompatibilityMatrix7ApiLevel && isUnknownOrUnsupported(status)) {
+        GTEST_SKIP() << "DEVICE not launching with Android 13 and beyond.";
     }
     ASSERT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
 }
@@ -198,10 +220,11 @@
 TEST_P(PowerAidl, updateAndReportDurations) {
     std::shared_ptr<IPowerHintSession> session;
     auto status = power->createHintSession(getpid(), getuid(), kSelfTids, 16666666L, &session);
-    if (!status.isOk()) {
+    if (mApiLevel < kCompatibilityMatrix7ApiLevel && !status.isOk()) {
         EXPECT_TRUE(isUnknownOrUnsupported(status));
-        return;
+        GTEST_SKIP() << "DEVICE not launching with Android 13 and beyond.";
     }
+    ASSERT_TRUE(status.isOk());
     ASSERT_NE(nullptr, session);
 
     ASSERT_TRUE(session->updateTargetWorkDuration(16666667LL).isOk());
@@ -223,17 +246,37 @@
     }
 }
 
+TEST_P(PowerAidl, setThreads) {
+    std::shared_ptr<IPowerHintSession> session;
+    auto status = power->createHintSession(getpid(), getuid(), kSelfTids, 16666666L, &session);
+    if (mApiLevel < kCompatibilityMatrix7ApiLevel && !status.isOk()) {
+        EXPECT_TRUE(isUnknownOrUnsupported(status));
+        GTEST_SKIP() << "DEVICE not launching with Android 13 and beyond.";
+    }
+    ASSERT_TRUE(status.isOk());
+
+    if (mApiLevel < kCompatibilityMatrix8ApiLevel) {
+        GTEST_SKIP() << "DEVICE not launching with Android 14 and beyond.";
+    }
+
+    status = session->setThreads(kEmptyTids);
+    ASSERT_FALSE(status.isOk());
+    ASSERT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
+
+    status = session->setThreads(kSelfTids);
+    ASSERT_TRUE(status.isOk());
+}
+
 // FIXED_PERFORMANCE mode is required for all devices which ship on Android 11
 // or later
 TEST_P(PowerAidl, hasFixedPerformance) {
-    auto apiLevel = GetUintProperty<uint64_t>("ro.vendor.api_level", 0);
-    ASSERT_NE(apiLevel, 0);
-
-    if (apiLevel >= 30) {
-        bool supported;
-        ASSERT_TRUE(power->isModeSupported(Mode::FIXED_PERFORMANCE, &supported).isOk());
-        ASSERT_TRUE(supported);
+    if (mApiLevel < kCompatibilityMatrix5ApiLevel) {
+        GTEST_SKIP() << "FIXED_PERFORMANCE mode is only required for all devices launching Android "
+                        "11 or later.";
     }
+    bool supported;
+    ASSERT_TRUE(power->isModeSupported(Mode::FIXED_PERFORMANCE, &supported).isOk());
+    ASSERT_TRUE(supported);
 }
 
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(PowerAidl);
diff --git a/power/stats/aidl/OWNERS b/power/stats/aidl/OWNERS
index b290b49..e0d66d7 100644
--- a/power/stats/aidl/OWNERS
+++ b/power/stats/aidl/OWNERS
@@ -1,3 +1,4 @@
-bsschwar@google.com
+darrenhsu@google.com
+joaodias@google.com
 krossmo@google.com
-tstrudel@google.com
+vincentwang@google.com
diff --git a/radio/aidl/Android.bp b/radio/aidl/Android.bp
index 613f31b..9dbe09a 100644
--- a/radio/aidl/Android.bp
+++ b/radio/aidl/Android.bp
@@ -36,7 +36,7 @@
     host_supported: true,
     srcs: ["android/hardware/radio/config/*.aidl"],
     stability: "vintf",
-    imports: ["android.hardware.radio-V1"],
+    imports: ["android.hardware.radio-V2"],
     backend: {
         cpp: {
             enabled: true,
@@ -60,7 +60,7 @@
     host_supported: true,
     srcs: ["android/hardware/radio/data/*.aidl"],
     stability: "vintf",
-    imports: ["android.hardware.radio-V1"],
+    imports: ["android.hardware.radio-V2"],
     backend: {
         cpp: {
             enabled: true,
@@ -84,7 +84,7 @@
     host_supported: true,
     srcs: ["android/hardware/radio/messaging/*.aidl"],
     stability: "vintf",
-    imports: ["android.hardware.radio-V1"],
+    imports: ["android.hardware.radio-V2"],
     backend: {
         cpp: {
             enabled: true,
@@ -108,7 +108,7 @@
     host_supported: true,
     srcs: ["android/hardware/radio/modem/*.aidl"],
     stability: "vintf",
-    imports: ["android.hardware.radio-V1"],
+    imports: ["android.hardware.radio-V2"],
     backend: {
         cpp: {
             enabled: true,
@@ -132,7 +132,7 @@
     host_supported: true,
     srcs: ["android/hardware/radio/network/*.aidl"],
     stability: "vintf",
-    imports: ["android.hardware.radio-V1"],
+    imports: ["android.hardware.radio-V2"],
     backend: {
         cpp: {
             enabled: true,
@@ -157,8 +157,8 @@
     srcs: ["android/hardware/radio/sim/*.aidl"],
     stability: "vintf",
     imports: [
-        "android.hardware.radio-V1",
-        "android.hardware.radio.config",
+        "android.hardware.radio-V2",
+        "android.hardware.radio.config-V2",
     ],
     backend: {
         cpp: {
@@ -186,7 +186,7 @@
     host_supported: true,
     srcs: ["android/hardware/radio/voice/*.aidl"],
     stability: "vintf",
-    imports: ["android.hardware.radio-V1"],
+    imports: ["android.hardware.radio-V2"],
     backend: {
         cpp: {
             enabled: true,
@@ -203,3 +203,38 @@
     ],
 
 }
+
+aidl_interface {
+    name: "android.hardware.radio.ims.media",
+    vendor_available: true,
+    srcs: ["android/hardware/radio/ims/media/*.aidl"],
+    stability: "vintf",
+    imports: [
+        "android.hardware.radio-V2",
+        "android.hardware.radio.data-V2",
+    ],
+    backend: {
+        cpp: {
+            enabled: false,
+        },
+        java: {
+            sdk_version: "module_current",
+        },
+    },
+}
+
+aidl_interface {
+    name: "android.hardware.radio.ims",
+    vendor_available: true,
+    srcs: ["android/hardware/radio/ims/*.aidl"],
+    stability: "vintf",
+    imports: ["android.hardware.radio-V2"],
+    backend: {
+        cpp: {
+            enabled: false,
+        },
+        java: {
+            sdk_version: "module_current",
+        },
+    },
+}
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..da894cd 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;
 }
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.ims.media/current/android/hardware/radio/ims/media/AmrMode.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/AmrMode.aidl
new file mode 100644
index 0000000..5179169
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/AmrMode.aidl
@@ -0,0 +1,46 @@
+/*
+ * 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.radio.ims.media;
+@Backing(type="int") @VintfStability
+enum AmrMode {
+  AMR_MODE_0 = 1 << 0,
+  AMR_MODE_1 = 1 << 1,
+  AMR_MODE_2 = 1 << 2,
+  AMR_MODE_3 = 1 << 3,
+  AMR_MODE_4 = 1 << 4,
+  AMR_MODE_5 = 1 << 5,
+  AMR_MODE_6 = 1 << 6,
+  AMR_MODE_7 = 1 << 7,
+  AMR_MODE_8 = 1 << 8,
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/AmrParams.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/AmrParams.aidl
new file mode 100644
index 0000000..36edb7f
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/AmrParams.aidl
@@ -0,0 +1,40 @@
+/*
+ * 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.radio.ims.media;
+@VintfStability
+parcelable AmrParams {
+  android.hardware.radio.ims.media.AmrMode amrMode;
+  boolean octetAligned;
+  int maxRedundancyMillis;
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/AnbrBitrate.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/AnbrBitrate.aidl
new file mode 100644
index 0000000..711ac19
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/AnbrBitrate.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.radio.ims.media;
+@VintfStability
+parcelable AnbrBitrate {
+  int uplinkBps;
+  int downlinkBps;
+  const int INVALID_ANBR_BITRATE = -1;
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/CallQuality.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/CallQuality.aidl
new file mode 100644
index 0000000..fff6e1c
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/CallQuality.aidl
@@ -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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.ims.media;
+@VintfStability
+parcelable CallQuality {
+  int downlinkCallQualityLevel;
+  int uplinkCallQualityLevel;
+  int callDuration;
+  int numRtpPacketsTransmitted;
+  int numRtpPacketsReceived;
+  int numRtpPacketsTransmittedLost;
+  int numRtpPacketsNotReceived;
+  int averageRelativeJitter;
+  int maxRelativeJitter;
+  int averageRoundTripTime;
+  int codecType;
+  boolean rtpInactivityDetected;
+  boolean rxSilenceDetected;
+  boolean txSilenceDetected;
+  int numVoiceFrames;
+  int numNoDataFrames;
+  int numDroppedRtpPackets;
+  long minPlayoutDelayMillis;
+  long maxPlayoutDelayMillis;
+  int numRtpSidPacketsReceived;
+  int numRtpDuplicatePackets;
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/CodecParams.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/CodecParams.aidl
new file mode 100644
index 0000000..3da2dbd
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/CodecParams.aidl
@@ -0,0 +1,43 @@
+/*
+ * 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.radio.ims.media;
+@VintfStability
+parcelable CodecParams {
+  android.hardware.radio.ims.media.CodecType codecType;
+  byte rxPayloadTypeNumber;
+  byte txPayloadTypeNumber;
+  byte samplingRateKHz;
+  boolean dtxEnabled;
+  android.hardware.radio.ims.media.CodecSpecificParams codecSpecificParams;
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/CodecSpecificParams.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/CodecSpecificParams.aidl
new file mode 100644
index 0000000..08e3f0f
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/CodecSpecificParams.aidl
@@ -0,0 +1,39 @@
+/*
+ * 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.radio.ims.media;
+@VintfStability
+union CodecSpecificParams {
+  android.hardware.radio.ims.media.AmrParams amr;
+  android.hardware.radio.ims.media.EvsParams evs;
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/CodecType.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/CodecType.aidl
new file mode 100644
index 0000000..56d2800
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/CodecType.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.radio.ims.media;
+@Backing(type="int") @VintfStability
+enum CodecType {
+  AMR = 1,
+  AMR_WB = 2,
+  EVS = 4,
+  PCMA = 8,
+  PCMU = 16,
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/DtmfParams.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/DtmfParams.aidl
new file mode 100644
index 0000000..5523fd8
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/DtmfParams.aidl
@@ -0,0 +1,40 @@
+/*
+ * 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.radio.ims.media;
+@VintfStability
+parcelable DtmfParams {
+  byte rxPayloadTypeNumber;
+  byte txPayloadTypeNumber;
+  byte samplingRateKHz;
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/EvsBandwidth.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/EvsBandwidth.aidl
new file mode 100644
index 0000000..eb31175
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/EvsBandwidth.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.radio.ims.media;
+@Backing(type="int") @VintfStability
+enum EvsBandwidth {
+  NONE = 0,
+  NARROW_BAND = 1,
+  WIDE_BAND = 2,
+  SUPER_WIDE_BAND = 4,
+  FULL_BAND = 8,
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/EvsMode.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/EvsMode.aidl
new file mode 100644
index 0000000..a067357
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/EvsMode.aidl
@@ -0,0 +1,58 @@
+/*
+ * 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.radio.ims.media;
+@Backing(type="int") @VintfStability
+enum EvsMode {
+  EVS_MODE_0 = 1 << 0,
+  EVS_MODE_1 = 1 << 1,
+  EVS_MODE_2 = 1 << 2,
+  EVS_MODE_3 = 1 << 3,
+  EVS_MODE_4 = 1 << 4,
+  EVS_MODE_5 = 1 << 5,
+  EVS_MODE_6 = 1 << 6,
+  EVS_MODE_7 = 1 << 7,
+  EVS_MODE_8 = 1 << 8,
+  EVS_MODE_9 = 1 << 9,
+  EVS_MODE_10 = 1 << 10,
+  EVS_MODE_11 = 1 << 11,
+  EVS_MODE_12 = 1 << 12,
+  EVS_MODE_13 = 1 << 13,
+  EVS_MODE_14 = 1 << 14,
+  EVS_MODE_15 = 1 << 15,
+  EVS_MODE_16 = 1 << 16,
+  EVS_MODE_17 = 1 << 17,
+  EVS_MODE_18 = 1 << 18,
+  EVS_MODE_19 = 1 << 19,
+  EVS_MODE_20 = 1 << 20,
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/EvsParams.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/EvsParams.aidl
new file mode 100644
index 0000000..735eb08
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/EvsParams.aidl
@@ -0,0 +1,43 @@
+/*
+ * 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.radio.ims.media;
+@VintfStability
+parcelable EvsParams {
+  android.hardware.radio.ims.media.EvsBandwidth bandwidth;
+  android.hardware.radio.ims.media.EvsMode evsMode;
+  byte channelAwareMode;
+  boolean useHeaderFullOnly;
+  boolean useEvsModeSwitch;
+  byte codecModeRequest;
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/IImsMedia.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/IImsMedia.aidl
new file mode 100644
index 0000000..30793e5
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/IImsMedia.aidl
@@ -0,0 +1,40 @@
+/*
+ * 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.radio.ims.media;
+@VintfStability
+interface IImsMedia {
+  oneway void setListener(in android.hardware.radio.ims.media.IImsMediaListener mediaListener);
+  oneway void openSession(int sessionId, in android.hardware.radio.ims.media.LocalEndPoint localEndPoint, in android.hardware.radio.ims.media.RtpConfig config);
+  oneway void closeSession(int sessionId);
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/IImsMediaListener.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/IImsMediaListener.aidl
new file mode 100644
index 0000000..40f7107
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/IImsMediaListener.aidl
@@ -0,0 +1,40 @@
+/*
+ * 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.radio.ims.media;
+@VintfStability
+interface IImsMediaListener {
+  oneway void onOpenSessionSuccess(int sessionId, android.hardware.radio.ims.media.IImsMediaSession session);
+  oneway void onOpenSessionFailure(int sessionId, android.hardware.radio.ims.media.RtpError error);
+  oneway void onSessionClosed(int sessionId);
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/IImsMediaSession.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/IImsMediaSession.aidl
new file mode 100644
index 0000000..ea9f3a4
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/IImsMediaSession.aidl
@@ -0,0 +1,44 @@
+/*
+ * 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.radio.ims.media;
+@VintfStability
+interface IImsMediaSession {
+  oneway void setListener(in android.hardware.radio.ims.media.IImsMediaSessionListener sessionListener);
+  oneway void modifySession(in android.hardware.radio.ims.media.RtpConfig config);
+  oneway void sendDtmf(char dtmfDigit, int duration);
+  oneway void startDtmf(char dtmfDigit);
+  oneway void stopDtmf();
+  oneway void sendHeaderExtension(in List<android.hardware.radio.ims.media.RtpHeaderExtension> extensions);
+  oneway void setMediaQualityThreshold(in android.hardware.radio.ims.media.MediaQualityThreshold threshold);
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/IImsMediaSessionListener.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/IImsMediaSessionListener.aidl
new file mode 100644
index 0000000..f03b29e
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/IImsMediaSessionListener.aidl
@@ -0,0 +1,46 @@
+/*
+ * 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.radio.ims.media;
+@VintfStability
+interface IImsMediaSessionListener {
+  oneway void onModifySessionResponse(in android.hardware.radio.ims.media.RtpConfig config, android.hardware.radio.ims.media.RtpError error);
+  oneway void onFirstMediaPacketReceived(in android.hardware.radio.ims.media.RtpConfig config);
+  oneway void onHeaderExtensionReceived(in List<android.hardware.radio.ims.media.RtpHeaderExtension> extensions);
+  oneway void notifyMediaInactivity(android.hardware.radio.ims.media.MediaProtocolType packetType);
+  oneway void notifyPacketLoss(int packetLossPercentage);
+  oneway void notifyJitter(int jitter);
+  oneway void triggerAnbrQuery(in android.hardware.radio.ims.media.RtpConfig config);
+  oneway void onDtmfReceived(char dtmfDigit);
+  oneway void onCallQualityChanged(in android.hardware.radio.ims.media.CallQuality callQuality);
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/LocalEndPoint.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/LocalEndPoint.aidl
new file mode 100644
index 0000000..6ec5156
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/LocalEndPoint.aidl
@@ -0,0 +1,40 @@
+/*
+ * 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.radio.ims.media;
+@VintfStability
+parcelable LocalEndPoint {
+  ParcelFileDescriptor rtpFd;
+  ParcelFileDescriptor rtcpFd;
+  int modemId;
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/MediaDirection.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/MediaDirection.aidl
new file mode 100644
index 0000000..d90b2a4
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/MediaDirection.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.radio.ims.media;
+@Backing(type="int") @VintfStability
+enum MediaDirection {
+  NO_FLOW = 0,
+  SEND_ONLY = 1,
+  RECEIVE_ONLY = 2,
+  SEND_RECEIVE = 3,
+  INACTIVE = 4,
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/MediaProtocolType.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/MediaProtocolType.aidl
new file mode 100644
index 0000000..1a290d4
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/MediaProtocolType.aidl
@@ -0,0 +1,39 @@
+/*
+ * 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.radio.ims.media;
+@Backing(type="int") @VintfStability
+enum MediaProtocolType {
+  RTP = 0,
+  RTCP = 1,
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/MediaQualityThreshold.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/MediaQualityThreshold.aidl
new file mode 100644
index 0000000..a448bac
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/MediaQualityThreshold.aidl
@@ -0,0 +1,43 @@
+/*
+ * 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.radio.ims.media;
+@VintfStability
+parcelable MediaQualityThreshold {
+  int rtpInactivityTimerMillis;
+  int rtcpInactivityTimerMillis;
+  int rtpPacketLossDurationMillis;
+  int rtpPacketLossRate;
+  int jitterDurationMillis;
+  int rtpJitterMillis;
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtcpConfig.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtcpConfig.aidl
new file mode 100644
index 0000000..6a76d85
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtcpConfig.aidl
@@ -0,0 +1,41 @@
+/*
+ * 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.radio.ims.media;
+@VintfStability
+parcelable RtcpConfig {
+  String canonicalName;
+  int transmitPort;
+  int transmitIntervalSec;
+  int rtcpXrBlocks;
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtcpXrReportBlockType.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtcpXrReportBlockType.aidl
new file mode 100644
index 0000000..2eefe6f
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtcpXrReportBlockType.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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.ims.media;
+@Backing(type="int") @VintfStability
+enum RtcpXrReportBlockType {
+  RTCPXR_NONE = 0,
+  RTCPXR_LOSS_RLE_REPORT_BLOCK = 1,
+  RTCPXR_DUPLICATE_RLE_REPORT_BLOCK = 2,
+  RTCPXR_PACKET_RECEIPT_TIMES_REPORT_BLOCK = 4,
+  RTCPXR_RECEIVER_REFERENCE_TIME_REPORT_BLOCK = 8,
+  RTCPXR_DLRR_REPORT_BLOCK = 16,
+  RTCPXR_STATISTICS_SUMMARY_REPORT_BLOCK = 32,
+  RTCPXR_VOIP_METRICS_REPORT_BLOCK = 64,
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtpAddress.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtpAddress.aidl
new file mode 100644
index 0000000..35357d1
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtpAddress.aidl
@@ -0,0 +1,39 @@
+/*
+ * 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.radio.ims.media;
+@VintfStability
+parcelable RtpAddress {
+  String ipAddress;
+  int portNumber;
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtpConfig.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtpConfig.aidl
new file mode 100644
index 0000000..ad8b86c
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtpConfig.aidl
@@ -0,0 +1,43 @@
+/*
+ * 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.radio.ims.media;
+@VintfStability
+parcelable RtpConfig {
+  android.hardware.radio.ims.media.MediaDirection direction;
+  android.hardware.radio.AccessNetwork accessNetwork;
+  android.hardware.radio.ims.media.RtpAddress remoteAddress;
+  android.hardware.radio.ims.media.RtpSessionParams sessionParams;
+  android.hardware.radio.ims.media.RtcpConfig rtcpConfig;
+  android.hardware.radio.ims.media.AnbrBitrate anbrBitrateParams;
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtpError.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtpError.aidl
new file mode 100644
index 0000000..41b0aeb
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtpError.aidl
@@ -0,0 +1,44 @@
+/*
+ * 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.radio.ims.media;
+@Backing(type="int") @VintfStability
+enum RtpError {
+  NONE = 0,
+  INVALID_PARAM = 1,
+  NOT_READY = 2,
+  NO_MEMORY = 3,
+  NO_RESOURCES = 4,
+  PORT_UNAVAILABLE = 5,
+  NOT_SUPPORTED = 6,
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtpHeaderExtension.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtpHeaderExtension.aidl
new file mode 100644
index 0000000..83b8a31
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtpHeaderExtension.aidl
@@ -0,0 +1,39 @@
+/*
+ * 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.radio.ims.media;
+@VintfStability
+parcelable RtpHeaderExtension {
+  int localId;
+  byte[] data;
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtpSessionParams.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtpSessionParams.aidl
new file mode 100644
index 0000000..13a7487
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtpSessionParams.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.radio.ims.media;
+@VintfStability
+parcelable RtpSessionParams {
+  byte pTimeMillis;
+  int maxPtimeMillis;
+  byte dscp;
+  android.hardware.radio.ims.media.DtmfParams dtmfParams;
+  android.hardware.radio.ims.media.CodecParams codecParams;
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ConnectionFailureInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ConnectionFailureInfo.aidl
new file mode 100644
index 0000000..030479f
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ConnectionFailureInfo.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.radio.ims;
+@JavaDerive(toString=true) @VintfStability
+parcelable ConnectionFailureInfo {
+  android.hardware.radio.ims.ConnectionFailureInfo.ConnectionFailureReason failureReason;
+  int causeCode;
+  int waitTimeMillis;
+  @Backing(type="int") @VintfStability
+  enum ConnectionFailureReason {
+    REASON_ACCESS_DENIED = 1,
+    REASON_NAS_FAILURE = 2,
+    REASON_RACH_FAILURE = 3,
+    REASON_RLC_FAILURE = 4,
+    REASON_RRC_REJECT = 5,
+    REASON_RRC_TIMEOUT = 6,
+    REASON_NO_SERVICE = 7,
+    REASON_PDN_NOT_AVAILABLE = 8,
+    REASON_RF_BUSY = 9,
+    REASON_UNSPECIFIED = 65535,
+  }
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/EpsFallbackReason.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/EpsFallbackReason.aidl
new file mode 100644
index 0000000..ebea903
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/EpsFallbackReason.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.ims;
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
+enum EpsFallbackReason {
+  NO_NETWORK_TRIGGER = 1,
+  NO_NETWORK_RESPONSE = 2,
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/IRadioIms.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/IRadioIms.aidl
new file mode 100644
index 0000000..4df8709
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/IRadioIms.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.ims;
+@VintfStability
+interface IRadioIms {
+  oneway void setSrvccCallInfo(int serial, in android.hardware.radio.ims.SrvccCall[] srvccCalls);
+  oneway void updateImsRegistrationInfo(int serial, in android.hardware.radio.ims.ImsRegistration imsRegistration);
+  oneway void startImsTraffic(int serial, int token, android.hardware.radio.ims.ImsTrafficType imsTrafficType, android.hardware.radio.AccessNetwork accessNetworkType, android.hardware.radio.ims.ImsCall.Direction trafficDirection);
+  oneway void stopImsTraffic(int serial, int token);
+  oneway void triggerEpsFallback(int serial, in android.hardware.radio.ims.EpsFallbackReason reason);
+  oneway void setResponseFunctions(in android.hardware.radio.ims.IRadioImsResponse radioImsResponse, in android.hardware.radio.ims.IRadioImsIndication radioImsIndication);
+  oneway void sendAnbrQuery(int serial, android.hardware.radio.ims.ImsStreamType mediaType, android.hardware.radio.ims.ImsStreamDirection direction, int bitsPerSecond);
+  oneway void updateImsCallStatus(int serial, in android.hardware.radio.ims.ImsCall[] imsCalls);
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/IRadioImsIndication.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/IRadioImsIndication.aidl
new file mode 100644
index 0000000..ef6b4cc
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/IRadioImsIndication.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.radio.ims;
+@VintfStability
+interface IRadioImsIndication {
+  oneway void onConnectionSetupFailure(in android.hardware.radio.RadioIndicationType type, int token, in android.hardware.radio.ims.ConnectionFailureInfo info);
+  oneway void notifyAnbr(in android.hardware.radio.RadioIndicationType type, in android.hardware.radio.ims.ImsStreamType mediaType, in android.hardware.radio.ims.ImsStreamDirection direction, int bitsPerSecond);
+  oneway void triggerImsDeregistration(in android.hardware.radio.RadioIndicationType type, in android.hardware.radio.ims.ImsDeregistrationReason reason);
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/IRadioImsResponse.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/IRadioImsResponse.aidl
new file mode 100644
index 0000000..053ba46
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/IRadioImsResponse.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.radio.ims;
+@VintfStability
+interface IRadioImsResponse {
+  oneway void setSrvccCallInfoResponse(in android.hardware.radio.RadioResponseInfo info);
+  oneway void updateImsRegistrationInfoResponse(in android.hardware.radio.RadioResponseInfo info);
+  oneway void startImsTrafficResponse(in android.hardware.radio.RadioResponseInfo info, in @nullable android.hardware.radio.ims.ConnectionFailureInfo failureInfo);
+  oneway void stopImsTrafficResponse(in android.hardware.radio.RadioResponseInfo info);
+  oneway void triggerEpsFallbackResponse(in android.hardware.radio.RadioResponseInfo info);
+  oneway void sendAnbrQueryResponse(in android.hardware.radio.RadioResponseInfo info);
+  oneway void updateImsCallStatusResponse(in android.hardware.radio.RadioResponseInfo info);
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsCall.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsCall.aidl
new file mode 100644
index 0000000..e48653b
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsCall.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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.ims;
+@JavaDerive(toString=true) @VintfStability
+parcelable ImsCall {
+  int index;
+  android.hardware.radio.ims.ImsCall.CallType callType;
+  android.hardware.radio.AccessNetwork accessNetwork;
+  android.hardware.radio.ims.ImsCall.CallState callState;
+  android.hardware.radio.ims.ImsCall.Direction direction;
+  boolean isHeldByRemote;
+  @Backing(type="int")
+  enum CallType {
+    NORMAL = 0,
+    EMERGENCY = 1,
+  }
+  @Backing(type="int")
+  enum CallState {
+    ACTIVE = 0,
+    HOLDING = 1,
+    DIALING = 2,
+    ALERTING = 3,
+    INCOMING = 4,
+    WAITING = 5,
+    DISCONNECTING = 6,
+    DISCONNECTED = 7,
+  }
+  @Backing(type="int")
+  enum Direction {
+    INCOMING = 0,
+    OUTGOING = 1,
+  }
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsDeregistrationReason.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsDeregistrationReason.aidl
new file mode 100644
index 0000000..b04e559
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsDeregistrationReason.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.radio.ims;
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
+enum ImsDeregistrationReason {
+  REASON_SIM_REMOVED = 1,
+  REASON_SIM_REFRESH = 2,
+  REASON_ALLOWED_NETWORK_TYPES_CHANGED = 3,
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsRegistration.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsRegistration.aidl
new file mode 100644
index 0000000..1c4c12a
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsRegistration.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.ims;
+@JavaDerive(toString=true) @VintfStability
+parcelable ImsRegistration {
+  android.hardware.radio.ims.ImsRegistrationState regState;
+  android.hardware.radio.AccessNetwork accessNetworkType;
+  android.hardware.radio.ims.SuggestedAction suggestedAction;
+  int capabilities;
+  const int IMS_MMTEL_CAPABILITY_NONE = 0;
+  const int IMS_MMTEL_CAPABILITY_VOICE = 1;
+  const int IMS_MMTEL_CAPABILITY_VIDEO = 2;
+  const int IMS_MMTEL_CAPABILITY_SMS = 4;
+  const int IMS_RCS_CAPABILITIES = 8;
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsRegistrationState.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsRegistrationState.aidl
new file mode 100644
index 0000000..664f561
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsRegistrationState.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.ims;
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
+enum ImsRegistrationState {
+  NOT_REGISTERED = 0,
+  REGISTERED = 1,
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsStreamDirection.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsStreamDirection.aidl
new file mode 100644
index 0000000..cf2e4f1
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsStreamDirection.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.ims;
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
+enum ImsStreamDirection {
+  UPLINK = 1,
+  DOWNLINK = 2,
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsStreamType.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsStreamType.aidl
new file mode 100644
index 0000000..10c477f
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsStreamType.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.ims;
+@Backing(type="int") @VintfStability
+enum ImsStreamType {
+  AUDIO = 1,
+  VIDEO = 2,
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsTrafficType.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsTrafficType.aidl
new file mode 100644
index 0000000..f7654b4
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsTrafficType.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.radio.ims;
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
+enum ImsTrafficType {
+  EMERGENCY = 0,
+  EMERGENCY_SMS = 1,
+  VOICE = 2,
+  VIDEO = 3,
+  SMS = 4,
+  REGISTRATION = 5,
+  UT_XCAP = 6,
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/SrvccCall.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/SrvccCall.aidl
new file mode 100644
index 0000000..a8b7cfc
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/SrvccCall.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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.ims;
+@JavaDerive(toString=true) @VintfStability
+parcelable SrvccCall {
+  int index;
+  android.hardware.radio.ims.SrvccCall.CallType callType;
+  int callState;
+  android.hardware.radio.ims.SrvccCall.CallSubState callSubstate;
+  android.hardware.radio.ims.SrvccCall.ToneType ringbackToneType;
+  boolean isMpty;
+  boolean isMT;
+  String number;
+  int numPresentation;
+  String name;
+  int namePresentation;
+  @Backing(type="int") @VintfStability
+  enum CallType {
+    NORMAL = 0,
+    EMERGENCY = 1,
+  }
+  @Backing(type="int") @VintfStability
+  enum CallSubState {
+    NONE = 0,
+    PREALERTING = 1,
+  }
+  @Backing(type="int") @VintfStability
+  enum ToneType {
+    NONE = 0,
+    LOCAL = 1,
+    NETWORK = 2,
+  }
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/SuggestedAction.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/SuggestedAction.aidl
new file mode 100644
index 0000000..da19774
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/SuggestedAction.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.radio.ims;
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
+enum SuggestedAction {
+  NONE = 0,
+  TRIGGER_PLMN_BLOCK = 1,
+  TRIGGER_PLMN_BLOCK_WITH_TIMEOUT = 2,
+}
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 41eff51..74dc39d 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
@@ -41,9 +41,18 @@
   oneway void getModemActivityInfo(in int serial);
   oneway void getModemStackStatus(in int serial);
   oneway void getRadioCapability(in int serial);
+  /**
+   * @deprecated NV APIs are deprecated starting from Android U.
+   */
   oneway void nvReadItem(in int serial, in android.hardware.radio.modem.NvItem itemId);
   oneway void nvResetConfig(in int serial, in android.hardware.radio.modem.ResetNvType resetType);
+  /**
+   * @deprecated NV APIs are deprecated starting from Android U.
+   */
   oneway void nvWriteCdmaPrl(in int serial, in byte[] prl);
+  /**
+   * @deprecated NV APIs are deprecated starting from Android U.
+   */
   oneway void nvWriteItem(in int serial, in android.hardware.radio.modem.NvWriteItem item);
   oneway void requestShutdown(in int serial);
   oneway void responseAcknowledgement();
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 dcaff45..af8bbe1 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
@@ -42,9 +42,18 @@
   oneway void getModemActivityInfoResponse(in android.hardware.radio.RadioResponseInfo info, in android.hardware.radio.modem.ActivityStatsInfo activityInfo);
   oneway void getModemStackStatusResponse(in android.hardware.radio.RadioResponseInfo info, in boolean isEnabled);
   oneway void getRadioCapabilityResponse(in android.hardware.radio.RadioResponseInfo info, in android.hardware.radio.modem.RadioCapability rc);
+  /**
+   * @deprecated NV APIs are deprecated starting from Android U.
+   */
   oneway void nvReadItemResponse(in android.hardware.radio.RadioResponseInfo info, in String result);
   oneway void nvResetConfigResponse(in android.hardware.radio.RadioResponseInfo info);
+  /**
+   * @deprecated NV APIs are deprecated starting from Android U.
+   */
   oneway void nvWriteCdmaPrlResponse(in android.hardware.radio.RadioResponseInfo info);
+  /**
+   * @deprecated NV APIs are deprecated starting from Android U.
+   */
   oneway void nvWriteItemResponse(in android.hardware.radio.RadioResponseInfo info);
   oneway void requestShutdownResponse(in android.hardware.radio.RadioResponseInfo info);
   oneway void sendDeviceStateResponse(in android.hardware.radio.RadioResponseInfo info);
diff --git a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/NvItem.aidl b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/NvItem.aidl
index 3e27643..b80d7ac 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/NvItem.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/NvItem.aidl
@@ -32,6 +32,9 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.modem;
+/**
+ * @deprecated NV APIs are deprecated starting from Android U.
+ */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum NvItem {
   CDMA_MEID = 1,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/NvWriteItem.aidl b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/NvWriteItem.aidl
index 17b7de0..6a786bc 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/NvWriteItem.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/NvWriteItem.aidl
@@ -32,6 +32,9 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.modem;
+/**
+ * @deprecated NV APIs are deprecated starting from Android U.
+ */
 @JavaDerive(toString=true) @VintfStability
 parcelable NvWriteItem {
   android.hardware.radio.modem.NvItem itemId;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EmergencyRegResult.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EmergencyRegResult.aidl
index af17b43..7d99a53 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EmergencyRegResult.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EmergencyRegResult.aidl
@@ -37,6 +37,7 @@
   android.hardware.radio.AccessNetwork accessNetwork;
   android.hardware.radio.network.RegState regState;
   android.hardware.radio.network.Domain emcDomain;
+  boolean isVopsSupported;
   boolean isEmcBearerSupported;
   byte nwProvidedEmc;
   byte nwProvidedEmf;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EutranRegistrationInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EutranRegistrationInfo.aidl
index dfbf881..93df3a4 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EutranRegistrationInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EutranRegistrationInfo.aidl
@@ -36,4 +36,13 @@
 parcelable EutranRegistrationInfo {
   android.hardware.radio.network.LteVopsInfo lteVopsInfo;
   android.hardware.radio.network.NrIndicators nrIndicators;
+  android.hardware.radio.network.EutranRegistrationInfo.AttachResultType lteAttachResultType;
+  int extraInfo;
+  const int EXTRA_CSFB_NOT_PREFERRED = 1;
+  const int EXTRA_SMS_ONLY = 2;
+  enum AttachResultType {
+    NONE = 0,
+    EPS_ONLY = 1,
+    COMBINED = 2,
+  }
 }
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 832738f..5aed024 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
@@ -41,6 +41,9 @@
   oneway void getCdmaRoamingPreference(in int serial);
   oneway void getCellInfoList(in int serial);
   oneway void getDataRegistrationState(in int serial);
+  /**
+   * @deprecated Deprecated starting from Android U.
+   */
   oneway void getImsRegistrationState(in int serial);
   oneway void getNetworkSelectionMode(in int serial);
   oneway void getOperator(in int serial);
@@ -72,6 +75,11 @@
   oneway void getUsageSetting(in int serial);
   oneway void setEmergencyMode(int serial, in android.hardware.radio.network.EmergencyMode emcModeType);
   oneway void triggerEmergencyNetworkScan(int serial, in android.hardware.radio.network.EmergencyNetworkScanTrigger request);
-  oneway void cancelEmergencyNetworkScan(in int serial);
+  oneway void cancelEmergencyNetworkScan(int serial, boolean resetScan);
   oneway void exitEmergencyMode(in int serial);
+  oneway void setNullCipherAndIntegrityEnabled(in int serial, in boolean enabled);
+  oneway void isN1ModeEnabled(in int serial);
+  oneway void setN1ModeEnabled(in int serial, boolean enable);
+  oneway void setLocationPrivacySetting(in int serial, in boolean shareLocation);
+  oneway void getLocationPrivacySetting(in int serial);
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkIndication.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkIndication.aidl
index 0f017ea..229f3e2 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkIndication.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkIndication.aidl
@@ -49,4 +49,5 @@
   oneway void suppSvcNotify(in android.hardware.radio.RadioIndicationType type, in android.hardware.radio.network.SuppSvcNotification suppSvc);
   oneway void voiceRadioTechChanged(in android.hardware.radio.RadioIndicationType type, in android.hardware.radio.RadioTechnology rat);
   oneway void emergencyNetworkScanResult(in android.hardware.radio.RadioIndicationType type, in android.hardware.radio.network.EmergencyRegResult result);
+  oneway void onNetworkInitiatedLocationResult(in android.hardware.radio.RadioIndicationType type, in android.hardware.radio.network.LocationResponseType locationResponseType);
 }
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 24d587e..ccdfde6 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
@@ -42,6 +42,9 @@
   oneway void getCdmaRoamingPreferenceResponse(in android.hardware.radio.RadioResponseInfo info, in android.hardware.radio.network.CdmaRoamingType type);
   oneway void getCellInfoListResponse(in android.hardware.radio.RadioResponseInfo info, in android.hardware.radio.network.CellInfo[] cellInfo);
   oneway void getDataRegistrationStateResponse(in android.hardware.radio.RadioResponseInfo info, in android.hardware.radio.network.RegStateResult dataRegResponse);
+  /**
+   * @deprecated Deprecated starting from Android U.
+   */
   oneway void getImsRegistrationStateResponse(in android.hardware.radio.RadioResponseInfo info, in boolean isRegistered, in android.hardware.radio.RadioTechnologyFamily ratFamily);
   oneway void getNetworkSelectionModeResponse(in android.hardware.radio.RadioResponseInfo info, in boolean manual);
   oneway void getOperatorResponse(in android.hardware.radio.RadioResponseInfo info, in String longName, in String shortName, in String numeric);
@@ -73,4 +76,9 @@
   oneway void triggerEmergencyNetworkScanResponse(in android.hardware.radio.RadioResponseInfo info);
   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 isN1ModeEnabledResponse(in android.hardware.radio.RadioResponseInfo info, boolean isEnabled);
+  oneway void setN1ModeEnabledResponse(in android.hardware.radio.RadioResponseInfo info);
+  oneway void setLocationPrivacySettingResponse(in android.hardware.radio.RadioResponseInfo info);
+  oneway void getLocationPrivacySettingResponse(in android.hardware.radio.RadioResponseInfo info, boolean shareLocation);
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl
new file mode 100644
index 0000000..e89a40f
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.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.radio.network;
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
+enum LocationResponseType {
+  REJECTED = 0,
+  ACCEPTED_NO_LOCATION_PROVIDED = 1,
+  ACCEPTED_LOCATION_PROVIDED = 2,
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/RegState.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/RegState.aidl
index e6e7999..711c9ac 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/RegState.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/RegState.aidl
@@ -44,4 +44,5 @@
   NOT_REG_MT_SEARCHING_OP_EM = 12,
   REG_DENIED_EM = 13,
   UNKNOWN_EM = 14,
+  REG_EM = 20,
 }
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..2f2e07b 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;
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioAccessFamily.aidl b/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioAccessFamily.aidl
index ecc2a9b..afc4f4e 100644
--- a/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioAccessFamily.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioAccessFamily.aidl
@@ -53,6 +53,9 @@
   GSM = 65536,
   TD_SCDMA = 131072,
   IWLAN = 262144,
+  /**
+   * @deprecated use LTE instead.
+   */
   LTE_CA = 524288,
   NR = 1048576,
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioTechnology.aidl b/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioTechnology.aidl
index 9dad0a4..7060469 100644
--- a/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioTechnology.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioTechnology.aidl
@@ -53,6 +53,9 @@
   GSM = 16,
   TD_SCDMA = 17,
   IWLAN = 18,
+  /**
+   * @deprecated use LTE instead and indicate carrier aggregation through multiple physical channel configurations in IRadioNetwork::currentPhysicalChannelConfigs.
+   */
   LTE_CA = 19,
   NR = 20,
 }
diff --git a/radio/aidl/android/hardware/radio/RadioAccessFamily.aidl b/radio/aidl/android/hardware/radio/RadioAccessFamily.aidl
index 6cd0a95..edf33ba 100644
--- a/radio/aidl/android/hardware/radio/RadioAccessFamily.aidl
+++ b/radio/aidl/android/hardware/radio/RadioAccessFamily.aidl
@@ -41,6 +41,7 @@
     GSM = 1 << RadioTechnology.GSM,
     TD_SCDMA = 1 << RadioTechnology.TD_SCDMA,
     IWLAN = 1 << RadioTechnology.IWLAN,
+    /** @deprecated use LTE instead. */
     LTE_CA = 1 << RadioTechnology.LTE_CA,
     /**
      * 5G NR. This is only use in 5G Standalone mode.
diff --git a/radio/aidl/android/hardware/radio/RadioError.aidl b/radio/aidl/android/hardware/radio/RadioError.aidl
index ae58a0e..61d5a77 100644
--- a/radio/aidl/android/hardware/radio/RadioError.aidl
+++ b/radio/aidl/android/hardware/radio/RadioError.aidl
@@ -41,6 +41,9 @@
      * Operation requires SIM PUK2 to be entered
      */
     SIM_PUK2 = 5,
+    /**
+     * Optional API
+     */
     REQUEST_NOT_SUPPORTED = 6,
     CANCELLED = 7,
     /**
diff --git a/radio/aidl/android/hardware/radio/RadioTechnology.aidl b/radio/aidl/android/hardware/radio/RadioTechnology.aidl
index 917cb16..4b51152 100644
--- a/radio/aidl/android/hardware/radio/RadioTechnology.aidl
+++ b/radio/aidl/android/hardware/radio/RadioTechnology.aidl
@@ -45,6 +45,10 @@
     GSM,
     TD_SCDMA,
     IWLAN,
+    /**
+     * @deprecated use LTE instead and indicate carrier aggregation through multiple
+     * physical channel configurations in IRadioNetwork::currentPhysicalChannelConfigs.
+     */
     LTE_CA,
     /**
      * 5G NR. This is only used in 5G Standalone mode.
diff --git a/radio/aidl/android/hardware/radio/config/IRadioConfigResponse.aidl b/radio/aidl/android/hardware/radio/config/IRadioConfigResponse.aidl
index 929f02d..0d36bbd 100644
--- a/radio/aidl/android/hardware/radio/config/IRadioConfigResponse.aidl
+++ b/radio/aidl/android/hardware/radio/config/IRadioConfigResponse.aidl
@@ -54,7 +54,6 @@
      * Valid errors returned:
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
-     *   RadioError:REQUEST_NOT_SUPPORTED
      */
     void getNumOfLiveModemsResponse(
             in android.hardware.radio.RadioResponseInfo info, in byte numOfLiveModems);
@@ -93,7 +92,6 @@
      * Valid errors returned:
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:INVALID_ARGUMENTS
      */
     void setNumOfLiveModemsResponse(in android.hardware.radio.RadioResponseInfo info);
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..73f2954 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,8 @@
      * active port in the slot mapping.
      */
     SimPortInfo[] portInfo;
+    /**
+     * Jointly supported Multiple Enabled Profiles(MEP) mode as per SGP.22 V3.0
+     */
+    MultipleEnabledProfilesMode supportedMepMode;
 }
diff --git a/radio/aidl/android/hardware/radio/data/IRadioDataResponse.aidl b/radio/aidl/android/hardware/radio/data/IRadioDataResponse.aidl
index 88b6c1b..06c83c1 100644
--- a/radio/aidl/android/hardware/radio/data/IRadioDataResponse.aidl
+++ b/radio/aidl/android/hardware/radio/data/IRadioDataResponse.aidl
@@ -44,7 +44,6 @@
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
      *   RadioError:NO_RESOURCES- Indicates that no pdu session ids are available
-     *   RadioError:REQUEST_NOT_SUPPORTED
      */
     void allocatePduSessionIdResponse(in RadioResponseInfo info, in int id);
 
@@ -57,7 +56,6 @@
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
      *   RadioError:NO_RESOURCES
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:INVALID_CALL_ID
      */
     void cancelHandoverResponse(in RadioResponseInfo info);
@@ -66,7 +64,6 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
-     *   RadioError:REQUEST_NOT_SUPPORTED may be returned when HAL 1.2 or higher is supported.
      *   RadioError:NONE indicates success. Any other error will remove the network from the list.
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_CALL_ID
@@ -112,7 +109,6 @@
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
      *   RadioError:NO_RESOURCES
-     *   RadioError:REQUEST_NOT_SUPPORTED
      */
     void releasePduSessionIdResponse(in RadioResponseInfo info);
 
@@ -131,7 +127,6 @@
      *   RadioError:INVALID_MODEM_STATE
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
-     *   RadioError:REQUEST_NOT_SUPPORTED
      */
     void setDataAllowedResponse(in RadioResponseInfo info);
 
@@ -146,7 +141,6 @@
      *   RadioError:NO_MEMORY
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:SIM_ABSENT
      */
     void setDataProfileResponse(in RadioResponseInfo info);
@@ -159,7 +153,6 @@
      *  RadioError:RADIO_NOT_AVAILABLE
      *  RadioError:MODEM_ERR
      *  RadioError:INVALID_ARGUMENTS
-     *  RadioError:REQUEST_NOT_SUPPORTED
      */
     void setDataThrottlingResponse(in RadioResponseInfo info);
 
@@ -176,7 +169,6 @@
      *   RadioError:MODEM_ERR
      *   RadioError:INVALID_ARGUMENTS
      *   RadioError:NOT_PROVISIONED
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
      */
@@ -208,7 +200,6 @@
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
      *   RadioError:NO_RESOURCES
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:INVALID_CALL_ID
      */
     void startHandoverResponse(in RadioResponseInfo info);
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/ims/ConnectionFailureInfo.aidl b/radio/aidl/android/hardware/radio/ims/ConnectionFailureInfo.aidl
new file mode 100644
index 0000000..70faa1e
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/ims/ConnectionFailureInfo.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.radio.ims;
+
+@VintfStability
+@JavaDerive(toString=true)
+parcelable ConnectionFailureInfo {
+
+    @VintfStability
+    @Backing(type="int")
+    enum ConnectionFailureReason {
+        /** Access class check failed */
+        REASON_ACCESS_DENIED = 1,
+        /** 3GPP Non-access stratum failure */
+        REASON_NAS_FAILURE = 2,
+        /** Random access failure */
+        REASON_RACH_FAILURE = 3,
+        /** Radio link failure */
+        REASON_RLC_FAILURE = 4,
+        /** Radio connection establishment rejected by network */
+        REASON_RRC_REJECT = 5,
+        /** Radio connection establishment timed out */
+        REASON_RRC_TIMEOUT = 6,
+        /** Device currently not in service */
+        REASON_NO_SERVICE = 7,
+        /** The PDN is no more active */
+        REASON_PDN_NOT_AVAILABLE = 8,
+        /** Radio resource is busy with another subscription */
+        REASON_RF_BUSY = 9,
+        REASON_UNSPECIFIED = 0xFFFF,
+    }
+
+    /**
+     * Values are REASON_* constants
+     */
+    ConnectionFailureReason failureReason;
+
+    /**
+     * Failure cause code from network or modem specific to the failure
+     */
+    int causeCode;
+
+    /**
+     * Retry wait time provided by network in milliseconds
+     */
+    int waitTimeMillis;
+}
diff --git a/radio/aidl/android/hardware/radio/ims/EpsFallbackReason.aidl b/radio/aidl/android/hardware/radio/ims/EpsFallbackReason.aidl
new file mode 100644
index 0000000..670638b
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/ims/EpsFallbackReason.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.radio.ims;
+
+@VintfStability
+@JavaDerive(toString=true)
+@Backing(type="int")
+enum EpsFallbackReason {
+    /**
+     * If VoNR is not supported and EPS fallback is not triggered by network then UE initiated EPS
+     * fallback would be triggered by IMS stack with this reason. The modem shall locally release
+     * the 5G NR SA RRC connection and acquire the LTE network and perform a tracking area update
+     * procedure. After the EPS fallback procedure is completed, the call setup for voice will
+     * be established.
+     */
+    NO_NETWORK_TRIGGER = 1,
+
+    /**
+     * If the UE doesn't receive any response for SIP INVITE within a certain time in 5G NR SA,
+     * UE initiated EPS fallback will be triggered with this reason. The modem shall reset its data
+     * buffer of IMS PDUs to prevent the ghost call. After the EPS fallback procedure is completed,
+     * the VoLTE call will be established.
+     */
+    NO_NETWORK_RESPONSE = 2,
+}
diff --git a/radio/aidl/android/hardware/radio/ims/IRadioIms.aidl b/radio/aidl/android/hardware/radio/ims/IRadioIms.aidl
new file mode 100644
index 0000000..bd661a7
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/ims/IRadioIms.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.ims;
+
+import android.hardware.radio.AccessNetwork;
+import android.hardware.radio.ims.EpsFallbackReason;
+import android.hardware.radio.ims.IRadioImsIndication;
+import android.hardware.radio.ims.IRadioImsResponse;
+import android.hardware.radio.ims.ImsCall;
+import android.hardware.radio.ims.ImsRegistration;
+import android.hardware.radio.ims.ImsStreamDirection;
+import android.hardware.radio.ims.ImsStreamType;
+import android.hardware.radio.ims.ImsTrafficType;
+import android.hardware.radio.ims.SrvccCall;
+
+/**
+ * This interface is used by IMS telephony layer to talk to cellular radio.
+ * All the functions have minimum one parameter:
+ * serial: which corresponds to serial no. of request. Serial numbers must only be memorized for the
+ * duration of a method call. If clients provide colliding serials (including passing the same
+ * serial to different methods), multiple responses (one for each method call) must still be served.
+ * setResponseFunctions must work with IRadioImsResponse and IRadioImsIndication.
+ */
+@VintfStability
+oneway interface IRadioIms {
+    /**
+     * Provides a list of SRVCC call information to radio.
+     *
+     * @param serial Serial number of request
+     * @param srvccCalls the list of calls
+     *
+     * Response function is IRadioImsResponse.setSrvccCallInfoResponse()
+     */
+    void setSrvccCallInfo(int serial, in SrvccCall[] srvccCalls);
+
+    /**
+     * Update the IMS registration information to the radio.
+     *
+     * This information shall be used by radio to implement following carrier requirements:
+     * 1) Graceful IMS PDN disconnection on cellular when NAS is about to perform detach
+     * eg. SIM removal or SIM refresh
+     * 2) Block PLMN or RAT based on the IMS registration failure reason
+     *
+     * @param serial Serial number of request
+     * @param imsRegistration IMS registration information
+     *
+     * Response function is IRadioImsResponse.updateImsRegistrationInfoResponse()
+     */
+    void updateImsRegistrationInfo(int serial, in ImsRegistration imsRegistration);
+
+    /**
+     * IMS stack notifies the NAS and RRC layers of the radio that the upcoming IMS traffic is
+     * for the service mentioned in the ImsTrafficType. If this API is not
+     * explicitly invoked and IMS module sends traffic on IMS PDN then the radio
+     * shall treat type as background data traffic type.
+     * This API shall be used by modem
+     *  1. To set the appropriate establishment cause in RRC connection request.
+     *  2. To prioritize RF resources in case of DSDS. The service priority is
+     * EMERGENCY > EMERGENCY SMS > VOICE > VIDEO > SMS > REGISTRATION > Ut/XCAP. The RF
+     * shall be prioritized to the subscription which handles higher priority service.
+     * When both subscriptions are handling the same type of service then RF shall be
+     * prioritized to the voice preferred sub.
+     *  3. To evaluate the overall access barring in the case of ACB, ACB-Skp/SCM and UAC.
+     * The response {@link IRadioImsResponse#startImsTrafficResponse()} with success shall
+     * be sent by modem upon access class is allowed and RF resource is allotted. Otherwise
+     * the same API shall be invoked with appropriate {@link ConnectionFailureInfo}. Further
+     * if RRC connection setup fails then {@link IRadioImsIndication#onConnectionSetupFailure()}
+     * shall be invoked by modem with appropriate {@link ConnectionFailureInfo}.
+     *
+     * @param serial Serial number of request
+     * @param token A nonce to identify the request
+     * @param imsTrafficType IMS traffic type like registration, voice, and video
+     * @param accessNetworkType The type of the radio access network used
+     * @param trafficDirection Indicates whether traffic is originated by mobile originated or
+     *        mobile terminated use case eg. MO/MT call/SMS etc
+     *
+     * Response function is IRadioImsResponse.startImsTrafficResponse()
+     */
+    void startImsTraffic(int serial, int token,
+            ImsTrafficType imsTrafficType, AccessNetwork accessNetworkType,
+            ImsCall.Direction trafficDirection);
+
+    /**
+     * Indicates IMS traffic has been stopped.
+     * For all IMS traffic, notified with startImsTraffic, IMS service shall notify
+     * stopImsTraffic when it completes the traffic specified by the token.
+     *
+     * @param serial Serial number of request
+     * @param token The token assigned by startImsTraffic()
+     *
+     * Response function is IRadioImsResponse.stopImsTrafficResponse()
+     */
+    void stopImsTraffic(int serial, int token);
+
+    /**
+     * Triggers the UE initiated EPS fallback when a MO voice call failed to establish on 5G NR
+     * network and network didn't initiate a fallback.
+     *
+     * @param serial Serial number of request
+     * @param reason Specifies the reason that causes EPS fallback
+     *
+     * Response function is IRadioImsResponse.triggerEpsFallbackResponse()
+     */
+    void triggerEpsFallback(int serial, in EpsFallbackReason reason);
+
+    /**
+     * Set response functions for IMS radio requests and indications.
+     *
+     * @param radioImsResponse Object containing response functions
+     * @param radioImsIndication Object containing radio indications
+     */
+    void setResponseFunctions(in IRadioImsResponse radioImsResponse,
+            in IRadioImsIndication radioImsIndication);
+
+    /**
+     * Access Network Bitrate Recommendation Query (ANBRQ), see 3GPP TS 26.114.
+     * This API triggers radio to send ANBRQ message
+     * to the access network to query the desired bitrate.
+     *
+     * @param serial Serial number of request
+     * @param mediaType Media type is used to identify media stream such as audio or video
+     * @param direction Direction of this packet stream (e.g. uplink or downlink)
+     * @param bitsPerSecond The bit rate requested by the opponent UE
+     *
+     * Response function is IRadioImsResponse.sendAnbrQueryResponse()
+     */
+    void sendAnbrQuery(int serial, ImsStreamType mediaType, ImsStreamDirection direction, int bitsPerSecond);
+
+    /**
+     * Provides a list of IMS call information to radio.
+     *
+     * @param serial Serial number of request
+     * @param imsCalls The list of IMS calls
+     *
+     * Response function is IRadioImsResponse.updateImsCallStatusResponse()
+     */
+    void updateImsCallStatus(int serial, in ImsCall[] imsCalls);
+}
diff --git a/radio/aidl/android/hardware/radio/ims/IRadioImsIndication.aidl b/radio/aidl/android/hardware/radio/ims/IRadioImsIndication.aidl
new file mode 100644
index 0000000..d123d07
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/ims/IRadioImsIndication.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.radio.ims;
+
+import android.hardware.radio.RadioIndicationType;
+import android.hardware.radio.ims.ConnectionFailureInfo;
+import android.hardware.radio.ims.ImsDeregistrationReason;
+import android.hardware.radio.ims.ImsStreamDirection;
+import android.hardware.radio.ims.ImsStreamType;
+
+/**
+ * Interface declaring unsolicited radio indications for ims APIs.
+ */
+@VintfStability
+oneway interface IRadioImsIndication {
+    /**
+     * Fired by radio when any IMS traffic is not sent to network due to any failure
+     * on cellular networks. IMS service shall call stopImsTraffic when receiving
+     * this indication.
+     *
+     * @param type Type of radio indication
+     * @param token The token of startImsTraffic() associated with this indication
+     * @param info Connection failure information
+     */
+    void onConnectionSetupFailure(
+            in RadioIndicationType type, int token, in ConnectionFailureInfo info);
+
+    /**
+     * Access Network Bitrate Recommendation (ANBR), see 3GPP TS 26.114.
+     * Notifies the bit rate received from the network via ANBR message
+     *
+     * @param type Type of radio indication
+     * @param mediaType Media type is used to identify media stream such as audio or video
+     * @param direction Direction of this packet stream (e.g. uplink or downlink)
+     * @param bitsPerSecond The recommended bit rate for the UE
+     * for a specific logical channel and a specific direction by NW
+     */
+    void notifyAnbr(in RadioIndicationType type, in ImsStreamType mediaType,
+            in ImsStreamDirection direction, int bitsPerSecond);
+
+    /**
+     * Requests IMS stack to perform graceful IMS deregistration before radio performing
+     * network detach in the events of SIM remove, refresh or and so on. The radio waits for
+     * the IMS deregistration, which will be notified by telephony via
+     * {@link IRadioIms#updateImsRegistrationInfo()}, or a certain timeout interval to start
+     * the network detach procedure.
+     *
+     * @param type Type of radio indication
+     * @param reason the reason why the deregistration is triggered
+     */
+    void triggerImsDeregistration(in RadioIndicationType type, in ImsDeregistrationReason reason);
+}
diff --git a/radio/aidl/android/hardware/radio/ims/IRadioImsResponse.aidl b/radio/aidl/android/hardware/radio/ims/IRadioImsResponse.aidl
new file mode 100644
index 0000000..241c342
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/ims/IRadioImsResponse.aidl
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.ims;
+
+import android.hardware.radio.RadioResponseInfo;
+import android.hardware.radio.ims.ConnectionFailureInfo;
+
+/**
+ * Interface declaring response functions to solicited radio requests for ims APIs.
+ */
+@VintfStability
+oneway interface IRadioImsResponse {
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:INVALID_STATE
+     *   RadioError:NO_MEMORY
+     *   RadioError:SYSTEM_ERR
+     *   RadioError:MODEM_ERR
+     *   RadioError:INTERNAL_ERR
+     *   RadioError:INVALID_ARGUMENTS
+     *   RadioError:NO_RESOURCES
+     */
+    void setSrvccCallInfoResponse(in RadioResponseInfo info);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:INVALID_STATE
+     *   RadioError:NO_MEMORY
+     *   RadioError:SYSTEM_ERR
+     *   RadioError:MODEM_ERR
+     *   RadioError:INTERNAL_ERR
+     *   RadioError:INVALID_ARGUMENTS
+     *   RadioError:NO_RESOURCES
+     */
+    void updateImsRegistrationInfoResponse(in RadioResponseInfo info);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     * @param failureInfo Information about failure in detail
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:INVALID_STATE
+     *   RadioError:NO_MEMORY
+     *   RadioError:SYSTEM_ERR
+     *   RadioError:MODEM_ERR
+     *   RadioError:INTERNAL_ERR
+     *   RadioError:INVALID_ARGUMENTS
+     *   RadioError:NO_RESOURCES
+     */
+    void startImsTrafficResponse(in RadioResponseInfo info,
+            in @nullable ConnectionFailureInfo failureInfo);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:INVALID_STATE
+     *   RadioError:NO_MEMORY
+     *   RadioError:SYSTEM_ERR
+     *   RadioError:MODEM_ERR
+     *   RadioError:INTERNAL_ERR
+     *   RadioError:INVALID_ARGUMENTS
+     *   RadioError:NO_RESOURCES
+     */
+    void stopImsTrafficResponse(in RadioResponseInfo info);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:INVALID_STATE
+     *   RadioError:NO_MEMORY
+     *   RadioError:SYSTEM_ERR
+     *   RadioError:MODEM_ERR
+     *   RadioError:INTERNAL_ERR
+     *   RadioError:INVALID_ARGUMENTS
+     *   RadioError:NO_RESOURCES
+     */
+    void triggerEpsFallbackResponse(in RadioResponseInfo info);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:INVALID_STATE
+     *   RadioError:NO_MEMORY
+     *   RadioError:SYSTEM_ERR
+     *   RadioError:MODEM_ERR
+     *   RadioError:INTERNAL_ERR
+     *   RadioError:INVALID_ARGUMENTS
+     *   RadioError:NO_RESOURCES
+     */
+    void sendAnbrQueryResponse(in RadioResponseInfo info);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:INVALID_STATE
+     *   RadioError:NO_MEMORY
+     *   RadioError:SYSTEM_ERR
+     *   RadioError:MODEM_ERR
+     *   RadioError:INTERNAL_ERR
+     *   RadioError:INVALID_ARGUMENTS
+     *   RadioError:NO_RESOURCES
+     */
+    void updateImsCallStatusResponse(in RadioResponseInfo info);
+}
diff --git a/radio/aidl/android/hardware/radio/ims/ImsCall.aidl b/radio/aidl/android/hardware/radio/ims/ImsCall.aidl
new file mode 100644
index 0000000..b71682f
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/ims/ImsCall.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.radio.ims;
+
+import android.hardware.radio.AccessNetwork;
+
+@VintfStability
+@JavaDerive(toString=true)
+parcelable ImsCall {
+
+    @Backing(type="int")
+    enum CallType {
+        NORMAL,
+        EMERGENCY,
+    }
+
+    @Backing(type="int")
+    enum CallState {
+        ACTIVE,
+        HOLDING,
+        DIALING, /* Outgoing only */
+        ALERTING, /* Outgoing only */
+        INCOMING, /* Incoming only */
+        WAITING, /* Incoming only */
+        DISCONNECTING,
+        DISCONNECTED,
+    }
+
+    @Backing(type="int")
+    enum Direction {
+        INCOMING,
+        OUTGOING,
+    }
+
+    /** Call index */
+    int index;
+
+    /** The type of the call */
+    CallType callType;
+
+    /** The access network where the call is in progress */
+    AccessNetwork accessNetwork;
+
+    /** The state of the call */
+    CallState callState;
+
+    /** The direction of the call */
+    Direction direction;
+
+    /** True if the call is put on HOLD by the other party */
+    boolean isHeldByRemote;
+}
diff --git a/radio/aidl/android/hardware/radio/ims/ImsDeregistrationReason.aidl b/radio/aidl/android/hardware/radio/ims/ImsDeregistrationReason.aidl
new file mode 100644
index 0000000..eac8db4
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/ims/ImsDeregistrationReason.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.
+ */
+
+package android.hardware.radio.ims;
+
+@VintfStability
+@JavaDerive(toString=true)
+@Backing(type="int")
+enum ImsDeregistrationReason {
+    /**
+     * Radio shall send this reason to IMS stack to perform graceful de-registration
+     * due to SIM card is removed.
+     */
+    REASON_SIM_REMOVED = 1,
+    /**
+     * Radio shall send this reason to IMS stack to perform graceful de-registration
+     * due to SIM refresh that needs a NAS detach and re-attach.
+     */
+    REASON_SIM_REFRESH = 2,
+    /**
+     * Radio shall send this reason to IMS stack to perform graceful de-registration
+     * due to allowed network types bitmask changed that results in NAS detach.
+     */
+    REASON_ALLOWED_NETWORK_TYPES_CHANGED = 3,
+}
diff --git a/radio/aidl/android/hardware/radio/ims/ImsRegistration.aidl b/radio/aidl/android/hardware/radio/ims/ImsRegistration.aidl
new file mode 100644
index 0000000..662f9e9
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/ims/ImsRegistration.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.radio.ims;
+
+import android.hardware.radio.AccessNetwork;
+import android.hardware.radio.ims.ImsRegistrationState;
+import android.hardware.radio.ims.SuggestedAction;
+
+@VintfStability
+@JavaDerive(toString=true)
+parcelable ImsRegistration {
+    /** Default value */
+    const int IMS_MMTEL_CAPABILITY_NONE = 0;
+    /** IMS voice */
+    const int IMS_MMTEL_CAPABILITY_VOICE = 1 << 0;
+    /** IMS video */
+    const int IMS_MMTEL_CAPABILITY_VIDEO = 1 << 1;
+    /** IMS SMS */
+    const int IMS_MMTEL_CAPABILITY_SMS = 1 << 2;
+    /** IMS RCS */
+    const int IMS_RCS_CAPABILITIES = 1 << 3;
+
+    /** Indicates the current IMS registration state. */
+    ImsRegistrationState regState;
+
+    /**
+     * Indicates the type of the radio access network where IMS is registered.
+     */
+    AccessNetwork accessNetworkType;
+
+    /** Indicates the expected action for the radio to do. */
+    SuggestedAction suggestedAction;
+
+    /**
+     * Values are bitwise ORs of IMS_MMTEL_CAPABILITY_* constants and IMS_RCS_CAPABILITIES.
+     * IMS capability such as VOICE, VIDEO, SMS and RCS.
+     */
+    int capabilities;
+}
diff --git a/radio/aidl/android/hardware/radio/ims/ImsRegistrationState.aidl b/radio/aidl/android/hardware/radio/ims/ImsRegistrationState.aidl
new file mode 100644
index 0000000..fd5c0fa
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/ims/ImsRegistrationState.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.ims;
+
+@VintfStability
+@JavaDerive(toString=true)
+@Backing(type="int")
+enum ImsRegistrationState {
+    /** IMS is not registered */
+    NOT_REGISTERED,
+
+    /** IMS is successfully registered */
+    REGISTERED,
+}
\ No newline at end of file
diff --git a/radio/aidl/android/hardware/radio/ims/ImsStreamDirection.aidl b/radio/aidl/android/hardware/radio/ims/ImsStreamDirection.aidl
new file mode 100644
index 0000000..c0cea32
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/ims/ImsStreamDirection.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.ims;
+
+@VintfStability
+@JavaDerive(toString=true)
+@Backing(type="int")
+enum ImsStreamDirection {
+    /** DIRECTION_UPLINK - From UE to Network **/
+    UPLINK = 1,
+    /** DIRECTION_DOWNLINK - From Network to UE **/
+    DOWNLINK = 2,
+}
diff --git a/radio/aidl/android/hardware/radio/ims/ImsStreamType.aidl b/radio/aidl/android/hardware/radio/ims/ImsStreamType.aidl
new file mode 100644
index 0000000..c12a0c1
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/ims/ImsStreamType.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.radio.ims;
+
+@VintfStability
+@Backing(type="int")
+enum ImsStreamType {
+    /** Media Stream Type - Audio **/
+    AUDIO = 1,
+    /** Media Stream Type - Video **/
+    VIDEO = 2,
+}
diff --git a/radio/aidl/android/hardware/radio/ims/ImsTrafficType.aidl b/radio/aidl/android/hardware/radio/ims/ImsTrafficType.aidl
new file mode 100644
index 0000000..5a824c0
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/ims/ImsTrafficType.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.radio.ims;
+
+@VintfStability
+@JavaDerive(toString=true)
+@Backing(type="int")
+enum ImsTrafficType {
+    /** Emergency call */
+    EMERGENCY,
+
+    /** Emergency SMS */
+    EMERGENCY_SMS,
+
+    /** Voice call */
+    VOICE,
+
+    /** Video call */
+    VIDEO,
+
+    /** SMS over IMS */
+    SMS,
+
+    /** IMS registration and subscription for reg event package (signaling) */
+    REGISTRATION,
+
+    /** Ut/XCAP (XML Configuration Access Protocol) */
+    UT_XCAP
+}
\ No newline at end of file
diff --git a/radio/aidl/android/hardware/radio/ims/SrvccCall.aidl b/radio/aidl/android/hardware/radio/ims/SrvccCall.aidl
new file mode 100644
index 0000000..38e6cdb
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/ims/SrvccCall.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.radio.ims;
+
+@VintfStability
+@JavaDerive(toString=true)
+parcelable SrvccCall {
+
+    @VintfStability
+    @Backing(type="int")
+    enum CallType {
+        NORMAL,
+        EMERGENCY,
+    }
+
+    @VintfStability
+    @Backing(type="int")
+    enum CallSubState {
+        NONE,
+        /** Pre-alerting state. Applicable for MT calls only */
+        PREALERTING,
+    }
+
+    @VintfStability
+    @Backing(type="int")
+    enum ToneType {
+        NONE,
+        LOCAL,
+        NETWORK,
+    }
+
+    /** Connection index */
+    int index;
+
+    /** The type of the call */
+    CallType callType;
+
+    /** Values are android.hardware.radio.voice.Call.STATE_* constants */
+    int callState;
+
+    /** The substate of the call */
+    CallSubState callSubstate;
+
+    /** The type of the ringback tone */
+    ToneType ringbackToneType;
+
+    /** true if is mpty call */
+    boolean isMpty;
+
+    /** true if call is mobile terminated */
+    boolean isMT;
+
+    /** Remote party nummber */
+    String number;
+
+    /** Values are android.hardware.radio.voice.Call.PRESENTATION_* constants */
+    int numPresentation;
+
+    /** Remote party name */
+    String name;
+
+    /** Values are android.hardware.radio.voice.Call.PRESENTATION_* constants */
+    int namePresentation;
+}
diff --git a/radio/aidl/android/hardware/radio/ims/SuggestedAction.aidl b/radio/aidl/android/hardware/radio/ims/SuggestedAction.aidl
new file mode 100644
index 0000000..2d12ed6
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/ims/SuggestedAction.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.radio.ims;
+
+@VintfStability
+@JavaDerive(toString=true)
+@Backing(type="int")
+enum SuggestedAction {
+    /** Default value */
+    NONE,
+    /**
+     * Indicates that the IMS registration is failed with fatal error such as 403 or 404
+     * on all P-CSCF addresses. The radio shall block the current PLMN or disable
+     * the RAT as per the carrier requirements.
+     */
+    TRIGGER_PLMN_BLOCK,
+    /**
+     * Indicates that the IMS registration on current PLMN failed multiple times.
+     * The radio shall block the current PLMN or disable the RAT during EPS or 5GS mobility
+     * management timer value as per the carrier requirements.
+     */
+    TRIGGER_PLMN_BLOCK_WITH_TIMEOUT,
+}
diff --git a/radio/aidl/android/hardware/radio/ims/media/AmrMode.aidl b/radio/aidl/android/hardware/radio/ims/media/AmrMode.aidl
new file mode 100644
index 0000000..66d8ef0
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/ims/media/AmrMode.aidl
@@ -0,0 +1,41 @@
+/*
+ * 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.radio.ims.media;
+
+/** AMR codec mode to represent the bit rate. See 3ggp Specs 26.976 & 26.071 */
+@VintfStability
+@Backing(type="int")
+enum AmrMode {
+    /** 4.75 kbps for AMR / 6.6 kbps for AMR-WB */
+    AMR_MODE_0 = 1 << 0,
+    /** 5.15 kbps for AMR / 8.855 kbps for AMR-WB */
+    AMR_MODE_1 = 1 << 1,
+    /** 5.9 kbps for AMR / 12.65 kbps for AMR-WB */
+    AMR_MODE_2 = 1 << 2,
+    /** 6.7 kbps for AMR / 14.25 kbps for AMR-WB */
+    AMR_MODE_3 = 1 << 3,
+    /** 7.4 kbps for AMR / 15.85 kbps for AMR-WB */
+    AMR_MODE_4 = 1 << 4,
+    /** 7.95 kbps for AMR / 18.25 kbps for AMR-WB */
+    AMR_MODE_5 = 1 << 5,
+    /** 10.2 kbps for AMR / 19.85 kbps for AMR-WB */
+    AMR_MODE_6 = 1 << 6,
+    /** 12.2 kbps for AMR / 23.05 kbps for AMR-WB */
+    AMR_MODE_7 = 1 << 7,
+    /** Silence frame for AMR / 23.85 kbps for AMR-WB */
+    AMR_MODE_8 = 1 << 8,
+}
diff --git a/radio/aidl/android/hardware/radio/ims/media/AmrParams.aidl b/radio/aidl/android/hardware/radio/ims/media/AmrParams.aidl
new file mode 100644
index 0000000..4ed3a24
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/ims/media/AmrParams.aidl
@@ -0,0 +1,39 @@
+/*
+ * 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.radio.ims.media;
+
+import android.hardware.radio.ims.media.AmrMode;
+
+@VintfStability
+parcelable AmrParams {
+    /** mode-set: AMR codec mode to represent the bit rate */
+    AmrMode amrMode;
+    /**
+     * octet-align: If it's set to true then all fields in the AMR/AMR-WB header
+     * shall be aligned to octet boundaries by adding padding bits.
+     */
+    boolean octetAligned;
+    /**
+     * max-red: It’s the maximum duration in milliseconds that elapses between the
+     * primary (first) transmission of a frame and any redundant transmission that
+     * the sender will use. This parameter allows a receiver to have a bounded delay
+     * when redundancy is used. Allowed values are between 0 (no redundancy will be
+     * used) and 65535. If the parameter is omitted, no limitation on the use of
+     * redundancy is present. See RFC 4867
+     */
+    int maxRedundancyMillis;
+}
diff --git a/radio/aidl/android/hardware/radio/ims/media/AnbrBitrate.aidl b/radio/aidl/android/hardware/radio/ims/media/AnbrBitrate.aidl
new file mode 100644
index 0000000..61239d0
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/ims/media/AnbrBitrate.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.ims.media;
+
+@VintfStability
+parcelable AnbrBitrate {
+    /** default value to represent NOT_SET */
+    const int INVALID_ANBR_BITRATE = -1;
+
+    /** Received bitrate in seconds for Uplink from NW or peer UE for ANBR */
+    int uplinkBps;
+    /** Received bitrate in secondsfor Downlink from NW or peer UE for ANBR */
+    int downlinkBps;
+}
diff --git a/radio/aidl/android/hardware/radio/ims/media/CallQuality.aidl b/radio/aidl/android/hardware/radio/ims/media/CallQuality.aidl
new file mode 100644
index 0000000..a8f7b16
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/ims/media/CallQuality.aidl
@@ -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.
+ */
+
+package android.hardware.radio.ims.media;
+
+@VintfStability
+parcelable CallQuality {
+    /**
+     * downlink CallQualityLevel for a given ongoing call
+     * this value corresponds to the CALL_QUALITY_* constants in {@link CallQuality}
+     */
+    int downlinkCallQualityLevel;
+    /**
+     * uplink CallQualityLevel for a given ongoing call
+     * this value corresponds to the CALL_QUALITY_* constants in {@link CallQuality}
+     */
+    int uplinkCallQualityLevel;
+    /** the call duration in milliseconds */
+    int callDuration;
+    /** RTP packets sent to network */
+    int numRtpPacketsTransmitted;
+    /** RTP packets received from network */
+    int numRtpPacketsReceived;
+    /** RTP packets which were lost in network and never transmitted */
+    int numRtpPacketsTransmittedLost;
+    /** RTP packets which were lost in network and never received */
+    int numRtpPacketsNotReceived;
+    /** average relative jitter in milliseconds */
+    int averageRelativeJitter;
+    /** maximum relative jitter in milliseconds */
+    int maxRelativeJitter;
+    /** average round trip delay in milliseconds */
+    int averageRoundTripTime;
+    /**
+     * the codec type. This value corresponds to the AUDIO_QUALITY_* constants in
+     * {@link ImsStreamMediaProfile}
+     */
+    int codecType;
+    /** True if no incoming RTP is received for a continuous duration of 4 seconds */
+    boolean rtpInactivityDetected;
+    /**
+     * True if only silence RTP packets are received for 20 seconds
+     * immediately after call is connected
+     */
+    boolean rxSilenceDetected;
+    /**
+     * True if only silence RTP packets are sent for 20 seconds
+     * immediately after call is connected
+     */
+    boolean txSilenceDetected;
+    /** the number of Voice frames sent by jitter buffer to audio */
+    int numVoiceFrames;
+    /** the number of no-data frames sent by jitter buffer to audio */
+    int numNoDataFrames;
+    /** the number of RTP voice packets dropped by jitter buffer */
+    int numDroppedRtpPackets;
+    /** the minimum playout delay in the reporting interval in milliseconds */
+    long minPlayoutDelayMillis;
+    /** the maximum playout delay in the reporting interval in milliseconds */
+    long maxPlayoutDelayMillis;
+    /**
+     * the total number of RTP SID (Silence Insertion Descriptor) packets
+     * received by this device for an ongoing call
+     */
+    int numRtpSidPacketsReceived;
+    /**
+     * the total number of RTP duplicate packets received by this device
+     * for an ongoing call
+     */
+    int numRtpDuplicatePackets;
+}
diff --git a/radio/aidl/android/hardware/radio/ims/media/CodecParams.aidl b/radio/aidl/android/hardware/radio/ims/media/CodecParams.aidl
new file mode 100644
index 0000000..0aa5505
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/ims/media/CodecParams.aidl
@@ -0,0 +1,44 @@
+/*
+ * 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.radio.ims.media;
+
+import android.hardware.radio.ims.media.CodecSpecificParams;
+import android.hardware.radio.ims.media.CodecType;
+
+@VintfStability
+parcelable CodecParams {
+    /** Negotiated codec type */
+    CodecType codecType;
+    /**
+     * Static or dynamic payload type number negotiated through the SDP for
+     * the incoming RTP packets. This value shall be matched with the PT value
+     * of the incoming RTP header. Values 0 to 127, see RFC 3551 section 6
+     */
+    byte rxPayloadTypeNumber;
+    /**
+     * Static or dynamic payload type number negotiated through the SDP for
+     * the outgoing RTP packets. This value shall be set to the PT value
+     * of the outgoing RTP header. Values 0 to 127, see RFC 3551 section 6
+     */
+    byte txPayloadTypeNumber;
+    /** Sampling rate in kHz*/
+    byte samplingRateKHz;
+    /** dtx: Whether discontinuous transmission is enabled or not */
+    boolean dtxEnabled;
+    /** Codec specific parameters */
+    CodecSpecificParams codecSpecificParams;
+}
diff --git a/radio/aidl/android/hardware/radio/ims/media/CodecSpecificParams.aidl b/radio/aidl/android/hardware/radio/ims/media/CodecSpecificParams.aidl
new file mode 100644
index 0000000..4410c81
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/ims/media/CodecSpecificParams.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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.radio.ims.media;
+
+import android.hardware.radio.ims.media.AmrParams;
+import android.hardware.radio.ims.media.EvsParams;
+
+@VintfStability
+union CodecSpecificParams {
+    AmrParams amr;
+    EvsParams evs;
+}
diff --git a/radio/aidl/android/hardware/radio/ims/media/CodecType.aidl b/radio/aidl/android/hardware/radio/ims/media/CodecType.aidl
new file mode 100644
index 0000000..31218e3
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/ims/media/CodecType.aidl
@@ -0,0 +1,32 @@
+/*
+ * 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.radio.ims.media;
+
+@VintfStability
+@Backing(type="int")
+enum CodecType {
+    /** Adaptive Multi-Rate */
+    AMR = 1 << 0,
+    /** Adaptive Multi-Rate Wide Band */
+    AMR_WB = 1 << 1,
+    /** Enhanced Voice Services */
+    EVS = 1 << 2,
+    /** G.711 A-law i.e. Pulse Code Modulation using A-law */
+    PCMA = 1 << 3,
+    /** G.711 μ-law i.e. Pulse Code Modulation using μ-law */
+    PCMU = 1 << 4,
+}
diff --git a/radio/aidl/android/hardware/radio/ims/media/DtmfParams.aidl b/radio/aidl/android/hardware/radio/ims/media/DtmfParams.aidl
new file mode 100644
index 0000000..a7dcb0d
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/ims/media/DtmfParams.aidl
@@ -0,0 +1,39 @@
+/*
+ * 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.radio.ims.media;
+
+@VintfStability
+parcelable DtmfParams {
+    /**
+     * Dynamic payload type number to be used for DTMF RTP packets received.
+     * The values is in the range from 96 to 127 chosen during the session
+     * establishment. The PT  value of the RTP header of all DTMF packets shall be
+     * set with this value.
+     */
+    byte rxPayloadTypeNumber;
+
+    /**
+     * Dynamic payload type number to be used for DTMF RTP packets sent.
+     * The values is in the range from 96 to 127 chosen during the session
+     * establishment. The PT value of the RTP header of all DTMF packets shall be set
+     * with this value.
+     */
+    byte txPayloadTypeNumber;
+
+    /** Sampling rate in kHz */
+    byte samplingRateKHz;
+}
diff --git a/radio/aidl/android/hardware/radio/ims/media/EvsBandwidth.aidl b/radio/aidl/android/hardware/radio/ims/media/EvsBandwidth.aidl
new file mode 100644
index 0000000..8278514
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/ims/media/EvsBandwidth.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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.radio.ims.media;
+/** EVS Speech codec bandwidths, See 3gpp spec 26.441 Table 1 */
+@VintfStability
+@Backing(type="int")
+enum EvsBandwidth {
+    NONE = 0,
+    NARROW_BAND = 1 << 0,
+    WIDE_BAND = 1 << 1,
+    SUPER_WIDE_BAND = 1 << 2,
+    FULL_BAND = 1 << 3,
+}
diff --git a/radio/aidl/android/hardware/radio/ims/media/EvsMode.aidl b/radio/aidl/android/hardware/radio/ims/media/EvsMode.aidl
new file mode 100644
index 0000000..95bd6c7
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/ims/media/EvsMode.aidl
@@ -0,0 +1,65 @@
+/*
+ * 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.radio.ims.media;
+
+/** EVS codec mode to represent the bit rate. See 3ggp Spec 26.952 Table 5.1 */
+@VintfStability
+@Backing(type="int")
+enum EvsMode {
+    /** 6.6 kbps for EVS AMR-WB IO */
+    EVS_MODE_0 = 1 << 0,
+    /** 8.855 kbps for AMR-WB IO */
+    EVS_MODE_1 = 1 << 1,
+    /** 12.65 kbps for AMR-WB IO */
+    EVS_MODE_2 = 1 << 2,
+    /** 14.25 kbps for AMR-WB IO */
+    EVS_MODE_3 = 1 << 3,
+    /** 15.85 kbps for AMR-WB IO */
+    EVS_MODE_4 = 1 << 4,
+    /** 18.25 kbps for AMR-WB IO */
+    EVS_MODE_5 = 1 << 5,
+    /** 19.85 kbps for AMR-WB IO */
+    EVS_MODE_6 = 1 << 6,
+    /** 23.05 kbps for AMR-WB IO */
+    EVS_MODE_7 = 1 << 7,
+    /** 23.85 kbps for AMR-WB IO */
+    EVS_MODE_8 = 1 << 8,
+    /** 5.9 kbps for EVS primary */
+    EVS_MODE_9 = 1 << 9,
+    /** 7.2 kbps for EVS primary */
+    EVS_MODE_10 = 1 << 10,
+    /** 8.0 kbps for EVS primary */
+    EVS_MODE_11 = 1 << 11,
+    /** 9.6 kbps for EVS primary */
+    EVS_MODE_12 = 1 << 12,
+    /** 13.2 kbps for EVS primary */
+    EVS_MODE_13 = 1 << 13,
+    /** 16.4 kbps for EVS primary */
+    EVS_MODE_14 = 1 << 14,
+    /** 24.4 kbps for EVS primary */
+    EVS_MODE_15 = 1 << 15,
+    /** 32.0 kbps for EVS primary */
+    EVS_MODE_16 = 1 << 16,
+    /** 48.0 kbps for EVS primary */
+    EVS_MODE_17 = 1 << 17,
+    /** 64.0 kbps for EVS primary */
+    EVS_MODE_18 = 1 << 18,
+    /** 96.0 kbps for EVS primary */
+    EVS_MODE_19 = 1 << 19,
+    /** 128.0 kbps for EVS primary */
+    EVS_MODE_20 = 1 << 20,
+}
diff --git a/radio/aidl/android/hardware/radio/ims/media/EvsParams.aidl b/radio/aidl/android/hardware/radio/ims/media/EvsParams.aidl
new file mode 100644
index 0000000..d138c83
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/ims/media/EvsParams.aidl
@@ -0,0 +1,56 @@
+/*
+ * 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.radio.ims.media;
+
+import android.hardware.radio.ims.media.EvsBandwidth;
+import android.hardware.radio.ims.media.EvsMode;
+
+@VintfStability
+parcelable EvsParams {
+    /** EVS codec bandwidth */
+    EvsBandwidth bandwidth;
+
+    /** mode-set: EVS codec mode to represent the bit rate */
+    EvsMode evsMode;
+    /**
+     * ch-aw-recv: Channel aware mode for the receive direction. Permissible values
+     * are -1, 0, 2, 3, 5, and 7. If -1, channel-aware mode is disabled in the
+     * session for the receive direction. If 0 or not present, partial redundancy
+     * (channel-aware mode) is not used at the start of the session for the receive
+     * direction. If positive (2, 3, 5, or 7), partial redundancy (channel-aware
+     * mode) is used at the start of the session for the receive direction using the
+     * value as the offset, See 3GPP TS 26.445 section 4.4.5
+     */
+    byte channelAwareMode;
+    /**
+     * hf-only: Header full only is used for the outgoing and incoming packets.
+     * If it's true then the session shall support header full format only else the
+     * session could support both header full format and compact format.
+     */
+    boolean useHeaderFullOnly;
+    /**
+     * evs-mode-switch: Used for switching between EVS Primary mode and EVS AMR-WB IO mode,
+     * If this value is true, the codec operates in AMR-WB IO mode
+     */
+    boolean useEvsModeSwitch;
+    /**
+     * cmr: Codec mode request is used to request the speech codec encoder of the
+     * other party to set the frame type index of speech mode via RTP header, See
+     * 3GPP TS 26.445 section A.3. Allowed values are -1, 0 and 1.
+     */
+    byte codecModeRequest;
+}
diff --git a/radio/aidl/android/hardware/radio/ims/media/IImsMedia.aidl b/radio/aidl/android/hardware/radio/ims/media/IImsMedia.aidl
new file mode 100644
index 0000000..ecf1370
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/ims/media/IImsMedia.aidl
@@ -0,0 +1,59 @@
+/*
+ * 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.radio.ims.media;
+
+import android.hardware.radio.ims.media.IImsMediaListener;
+import android.hardware.radio.ims.media.LocalEndPoint;
+import android.hardware.radio.ims.media.RtpConfig;
+import android.hardware.radio.ims.media.RtpError;
+
+/**
+ * This interface is used by IMS media framework to talk to RTP stack located in another processor.
+ */
+@VintfStability
+oneway interface IImsMedia {
+
+    /**
+     * Set the listener functions for receiving notifications from the RTP stack.
+     *
+     * @param mediaListener Object containing listener methods
+     */
+    void setListener(in IImsMediaListener mediaListener);
+
+    /**
+     * Opens a RTP session for the local end point with the associated initial remote configuration
+     * if there is a valid RtpConfig passed. It starts the media flow if the media direction in the
+     * RtpConfig is set to any value other than NO_MEDIA_FLOW. If the open session is successful
+     * then the implementation shall return a new IImsMediaSession binder connection for this
+     * session using IImsMediaListener#onOpenSessionSuccess() API. If the open session is failed
+     * then the implementation shall return the error using IImsMediaListener#onOpenSessionFailure()
+     *
+     * @param sessionId unique identifier of the session
+     * @param localEndPoint provides IP address, port and logical modem id for local RTP endpoint
+     * @param config provides remote end point info and codec details. This could be null initially
+     *        and the application may update this later using modifySession() API.
+     */
+    void openSession(int sessionId, in LocalEndPoint localEndPoint, in RtpConfig config);
+
+    /**
+     * Close the RTP session including cleanup of all the resources associated with the session.
+     * This shall also close the session specific binder connection opened as part of openSession().
+     *
+     * @param sessionId identifier for the rtp session that needs to be closed
+     */
+    void closeSession(int sessionId);
+}
diff --git a/radio/aidl/android/hardware/radio/ims/media/IImsMediaListener.aidl b/radio/aidl/android/hardware/radio/ims/media/IImsMediaListener.aidl
new file mode 100644
index 0000000..228acb7
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/ims/media/IImsMediaListener.aidl
@@ -0,0 +1,55 @@
+/*
+ * 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.radio.ims.media;
+
+import android.hardware.radio.ims.media.IImsMediaSession;
+import android.hardware.radio.ims.media.RtpError;
+
+/**
+ * Interface declaring listener functions for unsolicited IMS media notifications.
+ */
+@VintfStability
+oneway interface IImsMediaListener {
+    /**
+     * Fired when a IImsMedia#openSession() API is successful.
+     *
+     * @param sessionId identifier of the session
+     * @param session new IImsMediaSession binder connection to be used for the session
+     *        specific operations
+     */
+    void onOpenSessionSuccess(int sessionId, IImsMediaSession session);
+
+    /**
+     * Fired when IImsMedia#openSession() API failed to create a new session.
+     *
+     * @param sessionId identifier of the session
+     * @param error one of the following RTP error code
+     *   RtpError :INVALID_PARAM
+     *   RtpError :INTERNAL_ERR
+     *   RtpError :NO_MEMORY
+     *   RtpError :NO_RESOURCES
+     *   RtpError :PORT_UNAVAILABLE
+     */
+    void onOpenSessionFailure(int sessionId, RtpError error);
+
+    /**
+     * Fired when IImsMedia#closeSession() API handled.
+     *
+     * @param sessionId identifier of the session
+     */
+    void onSessionClosed(int sessionId);
+}
diff --git a/radio/aidl/android/hardware/radio/ims/media/IImsMediaSession.aidl b/radio/aidl/android/hardware/radio/ims/media/IImsMediaSession.aidl
new file mode 100644
index 0000000..a8d2161
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/ims/media/IImsMediaSession.aidl
@@ -0,0 +1,83 @@
+/*
+ * 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.radio.ims.media;
+
+import android.hardware.radio.ims.media.IImsMediaSessionListener;
+import android.hardware.radio.ims.media.MediaProtocolType;
+import android.hardware.radio.ims.media.MediaQualityThreshold;
+import android.hardware.radio.ims.media.RtpConfig;
+import android.hardware.radio.ims.media.RtpError;
+import android.hardware.radio.ims.media.RtpHeaderExtension;
+
+/**
+ * Session specific interface used by IMS media framework to talk to the vendor RTP stack.
+ */
+@VintfStability
+oneway interface IImsMediaSession {
+    /**
+     * Set the listener functions to receive IMS media session specific notifications.
+     *
+     * @param sessionListener Object containing notification methods
+     */
+    void setListener(in IImsMediaSessionListener sessionListener);
+
+    /**
+     * Modifies the configuration of the RTP session. It can be used to pause/resume
+     * the media stream by changing the value of the MediaDirection.
+     *
+     * @param config provides remote end point info and codec details
+     */
+    void modifySession(in RtpConfig config);
+
+    /**
+     * Send DTMF digit until the duration expires.
+     *
+     * @param dtmfDigit single char having one of 12 values: 0-9, *, #
+     * @param duration of the key press in milliseconds.
+     */
+    void sendDtmf(char dtmfDigit, int duration);
+
+    /**
+     * Start sending DTMF digit until the stopDtmf() API is received.
+     * If the implementation is currently sending a DTMF tone for which
+     * stopDtmf() is not received yet, then that digit must be stopped first
+     *
+     * @param dtmfDigit single char having one of 12 values: 0-9, *, #
+     */
+    void startDtmf(char dtmfDigit);
+
+    /**
+     * Stop sending the last DTMF digit started by startDtmf().
+     * stopDtmf() without preceding startDtmf() must be ignored.
+     */
+    void stopDtmf();
+
+    /**
+     * Send RTP header extension to the other party in the next RTP packet.
+     *
+     * @param extensions data to be transmitted via RTP header extension
+     */
+    void sendHeaderExtension(in List<RtpHeaderExtension> extensions);
+
+    /**
+     * Sets the media quality threshold parameters of the session to get
+     * media quality notifications.
+     *
+     * @param threshold media quality thresholds for various quality parameters
+     */
+    void setMediaQualityThreshold(in MediaQualityThreshold threshold);
+}
diff --git a/radio/aidl/android/hardware/radio/ims/media/IImsMediaSessionListener.aidl b/radio/aidl/android/hardware/radio/ims/media/IImsMediaSessionListener.aidl
new file mode 100644
index 0000000..d40da64
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/ims/media/IImsMediaSessionListener.aidl
@@ -0,0 +1,107 @@
+/*
+ * 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.radio.ims.media;
+
+import android.hardware.radio.ims.media.CallQuality;
+import android.hardware.radio.ims.media.MediaProtocolType;
+import android.hardware.radio.ims.media.RtpConfig;
+import android.hardware.radio.ims.media.RtpError;
+import android.hardware.radio.ims.media.RtpHeaderExtension;
+
+/**
+ * Interface declaring listener functions for unsolicited IMS media notifications per session.
+ */
+@VintfStability
+oneway interface IImsMediaSessionListener {
+    /**
+     * Notifies the result of IImsMediaSession#modifySession() API.
+     *
+     * @param config The RTP config passed in IImsMediaSession#modifySession() API
+     * @param error RtpError.NONE in case of success else one of the following
+     *   RtpError :INVALID_PARAM
+     *   RtpError :INTERNAL_ERR
+     *   RtpError :NO_MEMORY
+     *   RtpError :NO_RESOURCES
+     */
+    void onModifySessionResponse(in RtpConfig config, RtpError error);
+
+    /**
+     * Indicates when the first Rtp media packet is received by the UE during ring
+     * back, call hold or early media scenarios. This is sent only if the packet is
+     * received on the active remote configuration.
+     *
+     * In case of early media scenarios, the implementation shall play the RTP
+     * packets from the most recently added config.
+     *
+     * @param config The remote config where the media is received
+     */
+    void onFirstMediaPacketReceived(in RtpConfig config);
+
+    /**
+     * RTP header extension received from the other party
+     *
+     * @param extensions content of the received RTP header extension
+     */
+    void onHeaderExtensionReceived(in List<RtpHeaderExtension> extensions);
+
+    /**
+     * Notifies media inactivity observed as per thresholds set by
+     * setMediaQualityThreshold() API
+     *
+     * @param packetType either RTP or RTCP
+     */
+    void notifyMediaInactivity(MediaProtocolType packetType);
+
+    /**
+     * Notifies RTP packet loss observed as per thresholds set by
+     * setMediaQualityThreshold() API
+     *
+     * @param packetLossPercentage percentage of packet loss calculated over the duration
+     */
+    void notifyPacketLoss(int packetLossPercentage);
+
+    /**
+     * Notifies RTP jitter observed as per thresholds set by
+     * IImsMediaSession#setMediaQualityThreshold() API
+     *
+     * @param jitter jitter of the RTP packets in milliseconds calculated over the duration
+     */
+    void notifyJitter(int jitter);
+
+    /**
+     * The modem RTP stack fires this API to query whether the desired bitrate mentioned
+     * in the RtpConfig is currently available on the NW or not using ANBRQ message.
+     * See 3GPP TS 26.114.
+     *
+     * @param config containing desired bitrate and direction
+     */
+    void triggerAnbrQuery(in RtpConfig config);
+
+    /**
+     * Notifies the received DTMF digit from the other party
+     *
+     * @param dtmfDigit single char having one of 12 values: 0-9, *, #
+     */
+    void onDtmfReceived(char dtmfDigit);
+
+    /**
+     * Notifies when a change to call quality has occurred
+     *
+     * @param CallQuality The call quality statistics of ongoing call since last report
+     */
+    void onCallQualityChanged(in CallQuality callQuality);
+}
diff --git a/radio/aidl/android/hardware/radio/ims/media/LocalEndPoint.aidl b/radio/aidl/android/hardware/radio/ims/media/LocalEndPoint.aidl
new file mode 100644
index 0000000..2bd48c6
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/ims/media/LocalEndPoint.aidl
@@ -0,0 +1,29 @@
+/*
+ * 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.radio.ims.media;
+
+import android.os.ParcelFileDescriptor;
+
+@VintfStability
+parcelable LocalEndPoint {
+    /** Socket file descriptor for RTP traffic */
+    ParcelFileDescriptor rtpFd;
+    /** Socket file descriptor for RTCP traffic */
+    ParcelFileDescriptor rtcpFd;
+    /** The logical modem ID, returned by IRadioConfig.getPhoneCapability() */
+    int modemId;
+}
diff --git a/radio/aidl/android/hardware/radio/ims/media/MediaDirection.aidl b/radio/aidl/android/hardware/radio/ims/media/MediaDirection.aidl
new file mode 100644
index 0000000..9f04d8e
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/ims/media/MediaDirection.aidl
@@ -0,0 +1,35 @@
+/*
+ * 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.radio.ims.media;
+
+@VintfStability
+@Backing(type="int")
+enum MediaDirection {
+    /**
+     * No RTP/RTCP flow in either direction. The implementation
+     * may release the audio resource. Eg. SRVCC.
+     */
+    NO_FLOW = 0,
+    /** Device sends outgoing RTP and drops incoming RTP */
+    SEND_ONLY = 1,
+    /** Device receives the downlink RTP and does not transmit any uplink RTP */
+    RECEIVE_ONLY = 2,
+    /** Device sends and receive RTP in both directions */
+    SEND_RECEIVE = 3,
+    /** No RTP flow however RTCP continues to flow. Eg. HOLD */
+    INACTIVE = 4,
+}
diff --git a/radio/aidl/android/hardware/radio/ims/media/MediaProtocolType.aidl b/radio/aidl/android/hardware/radio/ims/media/MediaProtocolType.aidl
new file mode 100644
index 0000000..325c6fa
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/ims/media/MediaProtocolType.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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.radio.ims.media;
+
+@VintfStability
+@Backing(type="int")
+enum MediaProtocolType {
+   /** Real Time Protocol, see RFC 3550 */
+   RTP = 0,
+   /** Real Time Control Protocol, see RFC 3550 */
+   RTCP = 1,
+}
diff --git a/radio/aidl/android/hardware/radio/ims/media/MediaQualityThreshold.aidl b/radio/aidl/android/hardware/radio/ims/media/MediaQualityThreshold.aidl
new file mode 100644
index 0000000..946bd5c
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/ims/media/MediaQualityThreshold.aidl
@@ -0,0 +1,36 @@
+/*
+ * 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.radio.ims.media;
+
+@VintfStability
+parcelable MediaQualityThreshold {
+    /** Timer in milliseconds for monitoring RTP inactivity */
+    int rtpInactivityTimerMillis;
+    /** Timer in milliseconds for monitoring RTCP inactivity */
+    int rtcpInactivityTimerMillis;
+    /** Duration in milliseconds for monitoring the RTP packet loss rate */
+    int rtpPacketLossDurationMillis;
+    /**
+     * Packet loss rate in percentage of (total number of packets lost) /
+     * (total number of packets expected) during rtpPacketLossDurationMs
+     */
+    int rtpPacketLossRate;
+    /** Duration in milliseconds for monitoring the jitter for RTP traffic */
+    int jitterDurationMillis;
+    /** RTP jitter threshold in milliseconds */
+    int rtpJitterMillis;
+}
diff --git a/radio/aidl/android/hardware/radio/ims/media/RtcpConfig.aidl b/radio/aidl/android/hardware/radio/ims/media/RtcpConfig.aidl
new file mode 100644
index 0000000..98bbfc6
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/ims/media/RtcpConfig.aidl
@@ -0,0 +1,29 @@
+/*
+ * 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.radio.ims.media;
+
+@VintfStability
+parcelable RtcpConfig {
+    /** Canonical name that will be sent to all session participants */
+    String canonicalName;
+    /** Port for sending outgoing RTCP packets */
+    int transmitPort;
+    /** Transmit interval in seconds. Value 0 indicates that RTCP reports should not be reported */
+    int transmitIntervalSec;
+    /** Bitmask of RTCP-XR blocks to enable as in RtcpXrReportBlockType */
+    int rtcpXrBlocks;
+}
diff --git a/radio/aidl/android/hardware/radio/ims/media/RtcpXrReportBlockType.aidl b/radio/aidl/android/hardware/radio/ims/media/RtcpXrReportBlockType.aidl
new file mode 100644
index 0000000..7f6839a
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/ims/media/RtcpXrReportBlockType.aidl
@@ -0,0 +1,40 @@
+/*
+ * 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.radio.ims.media;
+
+/** RTP Control Protocol Extended Reports (RTCP XR) Blocks, See RFC 3611 section 4 */
+
+@VintfStability
+@Backing(type="int")
+enum RtcpXrReportBlockType {
+    /** Disable RTCP XR */
+    RTCPXR_NONE = 0,
+    /** Loss RLE Report Block */
+    RTCPXR_LOSS_RLE_REPORT_BLOCK                  = 1 << 0,
+    /** Duplicate RLE Report Block */
+    RTCPXR_DUPLICATE_RLE_REPORT_BLOCK             = 1 << 1,
+    /** Packet Receipt Times Report Block */
+    RTCPXR_PACKET_RECEIPT_TIMES_REPORT_BLOCK      = 1 << 2,
+    /** Receiver Reference Time Report Block */
+    RTCPXR_RECEIVER_REFERENCE_TIME_REPORT_BLOCK   = 1 << 3,
+    /** DLRR Report Block */
+    RTCPXR_DLRR_REPORT_BLOCK                      = 1 << 4,
+    /** Statistics Summary Report Block */
+    RTCPXR_STATISTICS_SUMMARY_REPORT_BLOCK        = 1 << 5,
+    /** VoIP Metrics Report Block */
+    RTCPXR_VOIP_METRICS_REPORT_BLOCK              = 1 << 6,
+}
diff --git a/radio/aidl/android/hardware/radio/ims/media/RtpAddress.aidl b/radio/aidl/android/hardware/radio/ims/media/RtpAddress.aidl
new file mode 100644
index 0000000..2db73a3
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/ims/media/RtpAddress.aidl
@@ -0,0 +1,25 @@
+/*
+ * 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.radio.ims.media;
+
+@VintfStability
+parcelable RtpAddress {
+    /** Point to point IP address */
+    String ipAddress;
+    /** UDP port number used for the RTP traffic */
+    int portNumber;
+}
diff --git a/radio/aidl/android/hardware/radio/ims/media/RtpConfig.aidl b/radio/aidl/android/hardware/radio/ims/media/RtpConfig.aidl
new file mode 100644
index 0000000..d0d849e
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/ims/media/RtpConfig.aidl
@@ -0,0 +1,54 @@
+/*
+ * 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.radio.ims.media;
+
+import android.hardware.radio.AccessNetwork;
+import android.hardware.radio.ims.media.AnbrBitrate;
+import android.hardware.radio.ims.media.MediaDirection;
+import android.hardware.radio.ims.media.RtcpConfig;
+import android.hardware.radio.ims.media.RtpAddress;
+import android.hardware.radio.ims.media.RtpSessionParams;
+
+@VintfStability
+parcelable RtpConfig {
+    /** Media flow direction */
+    MediaDirection direction;
+    /** Radio Access Network */
+    AccessNetwork accessNetwork;
+    /** IP address and port number of the other party for RTP media */
+    RtpAddress remoteAddress;
+    /** Negotiated session parameters */
+    RtpSessionParams sessionParams;
+    /** RTCP configuration */
+    RtcpConfig rtcpConfig;
+    /**
+     * ANBR Bitrate parameters. This is set to valid only when its triggered,
+     * otherwise it shall be set to NULL.
+     *
+     * This would be used in the following two cases
+     * - IImsMediaSession#modifySession(RtpConfig) - When RAN wants to change the bit
+     *   rate via ANBR MAC layer signaling, ImsStack would set the values and direction
+     *   and pass it in the modifySession(). The underlying RTP stack shall adapt to
+     *   the changed bitrate.
+     *
+     * - IImsMediaSessionListener#triggerAnbrQuery(RtpConfig) - When the vendor RTP
+     *   stack receives a request for bitrate increase from the peer terminal via CMR,
+     *   RTCP-APP or TMMBR, it triggers ANBRQ by setting the desired bitrate and the
+     *   direction of the stream.
+     */
+    AnbrBitrate anbrBitrateParams;
+}
diff --git a/radio/aidl/android/hardware/radio/ims/media/RtpError.aidl b/radio/aidl/android/hardware/radio/ims/media/RtpError.aidl
new file mode 100644
index 0000000..11a3468
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/ims/media/RtpError.aidl
@@ -0,0 +1,36 @@
+/*
+ * 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.radio.ims.media;
+
+@VintfStability
+@Backing(type="int")
+enum RtpError {
+    /** Success */
+    NONE = 0,
+    /** Invalid parameters passed in the request */
+    INVALID_PARAM = 1,
+    /** The RTP stack is not ready to handle the request */
+    NOT_READY = 2,
+    /** Unable to handle the request due to memory allocation failure */
+    NO_MEMORY = 3,
+    /** Unable to handle the request due to no sufficient resources such as audio, codec */
+    NO_RESOURCES = 4,
+    /** The requested port number is not available */
+    PORT_UNAVAILABLE = 5,
+    /** The request is not supported by the implementation */
+    NOT_SUPPORTED = 6,
+}
diff --git a/radio/aidl/android/hardware/radio/ims/media/RtpHeaderExtension.aidl b/radio/aidl/android/hardware/radio/ims/media/RtpHeaderExtension.aidl
new file mode 100644
index 0000000..76b13dc
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/ims/media/RtpHeaderExtension.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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.radio.ims.media;
+
+/** RTP Header Extensions, see RFC 8285 */
+@VintfStability
+parcelable RtpHeaderExtension {
+    /** Local identifier */
+    int localId;
+    /** Extension data bytes */
+    byte[] data;
+}
diff --git a/radio/aidl/android/hardware/radio/ims/media/RtpSessionParams.aidl b/radio/aidl/android/hardware/radio/ims/media/RtpSessionParams.aidl
new file mode 100644
index 0000000..f93c52c
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/ims/media/RtpSessionParams.aidl
@@ -0,0 +1,40 @@
+/*
+ * 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.radio.ims.media;
+
+import android.hardware.radio.ims.media.CodecParams;
+import android.hardware.radio.ims.media.DtmfParams;
+
+@VintfStability
+parcelable RtpSessionParams {
+    /**
+     * ptime: Recommended length of time in milliseconds represented by the media
+     * in each packet, see RFC 4566
+     */
+    byte pTimeMillis;
+    /**
+     * maxptime: Maximum amount of media that can be encapsulated in each packet
+     * represented in milliseconds, see RFC 4566
+     */
+    int maxPtimeMillis;
+    /** dscp: Differentiated Services Field Code Point value, see RFC 2474 */
+    byte dscp;
+    /** DTMF payload and clock rate */
+    DtmfParams dtmfParams;
+    /** Negotiated codec parameters */
+    CodecParams codecParams;
+}
diff --git a/radio/aidl/android/hardware/radio/messaging/IRadioMessagingResponse.aidl b/radio/aidl/android/hardware/radio/messaging/IRadioMessagingResponse.aidl
index 492755f..8cbc869 100644
--- a/radio/aidl/android/hardware/radio/messaging/IRadioMessagingResponse.aidl
+++ b/radio/aidl/android/hardware/radio/messaging/IRadioMessagingResponse.aidl
@@ -36,7 +36,6 @@
      *   RadioError:NO_MEMORY
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
-     *   RadioError:REQUEST_NOT_SUPPORTED
      */
     void acknowledgeIncomingGsmSmsWithPduResponse(in RadioResponseInfo info);
 
@@ -56,7 +55,6 @@
      *   RadioError:NETWORK_NOT_READY
      *   RadioError:INVALID_MODEM_STATE
      *   RadioError:INTERNAL_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:OPERATION_NOT_ALLOWED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
@@ -73,7 +71,6 @@
      *   RadioError:NO_MEMORY
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
-     *   RadioError:REQUEST_NOT_SUPPORTED
      */
     void acknowledgeLastIncomingGsmSmsResponse(in RadioResponseInfo info);
 
@@ -98,7 +95,6 @@
      *   RadioError:MODEM_ERR
      *   RadioError:NO_SUCH_ENTRY
      *   RadioError:INTERNAL_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:OPERATION_NOT_ALLOWED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
@@ -122,7 +118,6 @@
      *   RadioError:NO_SUCH_ENTRY
      *   RadioError:INTERNAL_ERR
      *   RadioError:RADIO_NOT_AVAILABLE
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
      *   RadioError:INVALID_MODEM_STATE
@@ -145,7 +140,6 @@
      *   RadioError:MODEM_ERR
      *   RadioError:NO_RESOURCES
      *   RadioError:INTERNAL_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
      *   RadioError:INVALID_MODEM_STATE
@@ -168,7 +162,6 @@
      *   RadioError:MODEM_ERR
      *   RadioError:NO_RESOURCES
      *   RadioError:INTERNAL_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
      *   RadioError:INVALID_MODEM_STATE
@@ -191,7 +184,6 @@
      *   RadioError:MODEM_ERR
      *   RadioError:INVALID_MODEM_STATE
      *   RadioError:NOT_PROVISIONED
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:OPERATION_NOT_ALLOWED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
@@ -212,7 +204,6 @@
      *   RadioError:MODEM_ERR
      *   RadioError:INVALID_STATE
      *   RadioError:INTERNAL_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
      *   RadioError:SIM_ABSENT
@@ -240,7 +231,6 @@
      *   RadioError:MODEM_ERR
      *   RadioError:NETWORK_ERR
      *   RadioError:INTERNAL_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:INVALID_MODEM_STATE
      *   RadioError:NETWORK_NOT_READY
      *   RadioError:OPERATION_NOT_ALLOWED
@@ -275,7 +265,6 @@
      *   RadioError:INVALID_SMSC_ADDRESS
      *   RadioError:INTERNAL_ERR
      *   RadioError:SYSTEM_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:OPERATION_NOT_ALLOWED
      *   RadioError:ENCODING_ERR
      *   RadioError:NO_RESOURCES
@@ -308,7 +297,6 @@
      *   RadioError:ENCODING_ERR
      *   RadioError:OPERATION_NOT_ALLOWED
      *   RadioError:INTERNAL_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:NETWORK_NOT_READY
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
@@ -336,7 +324,6 @@
      *   RadioError:MODEM_ERR
      *   RadioError:NETWORK_ERR
      *   RadioError:INTERNAL_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:INVALID_MODEM_STATE
      *   RadioError:NETWORK_NOT_READY
      *   RadioError:OPERATION_NOT_ALLOWED
@@ -368,7 +355,6 @@
      *   RadioError:MODEM_ERR
      *   RadioError:NETWORK_ERR
      *   RadioError:INTERNAL_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:INVALID_MODEM_STATE
      *   RadioError:NETWORK_NOT_READY
      *   RadioError:OPERATION_NOT_ALLOWED
@@ -393,7 +379,6 @@
      *   RadioError:SYSTEM_ERR
      *   RadioError:MODEM_ERR
      *   RadioError:INTERNAL_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:OPERATION_NOT_ALLOWED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
@@ -414,7 +399,6 @@
      *   RadioError:SYSTEM_ERR
      *   RadioError:MODEM_ERR
      *   RadioError:INTERNAL_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
      *   RadioError:INVALID_MODEM_STATE
@@ -434,7 +418,6 @@
      *   RadioError:SYSTEM_ERR
      *   RadioError:MODEM_ERR
      *   RadioError:INTERNAL_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:OPERATION_NOT_ALLOWED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
@@ -455,7 +438,6 @@
      *   RadioError:SYSTEM_ERR
      *   RadioError:MODEM_ERR
      *   RadioError:INTERNAL_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
      *   RadioError:INVALID_MODEM_STATE
@@ -476,7 +458,6 @@
      *   RadioError:MODEM_ERR
      *   RadioError:NO_RESOURCES
      *   RadioError:INTERNAL_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:OPERATION_NOT_ALLOWED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
@@ -502,7 +483,6 @@
      *   RadioError:INVALID_MODEM_STATE
      *   RadioError:INVALID_SMSC_ADDRESS
      *   RadioError:SYSTEM_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:OPERATION_NOT_ALLOWED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
@@ -531,7 +511,6 @@
      *   RadioError:INVALID_SMSC_ADDRESS
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:SYSTEM_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:CANCELLED
      *   RadioError:INVALID_MODEM_STATE
      *   RadioError:SIM_ABSENT
diff --git a/radio/aidl/android/hardware/radio/modem/IRadioModem.aidl b/radio/aidl/android/hardware/radio/modem/IRadioModem.aidl
index ba0ddb9..a5d98d3 100644
--- a/radio/aidl/android/hardware/radio/modem/IRadioModem.aidl
+++ b/radio/aidl/android/hardware/radio/modem/IRadioModem.aidl
@@ -117,6 +117,8 @@
      * @param itemId NvItem
      *
      * Response function is IRadioModemResponse.nvReadItemResponse()
+     *
+     * @deprecated NV APIs are deprecated starting from Android U.
      */
     void nvReadItem(in int serial, in NvItem itemId);
 
@@ -128,6 +130,8 @@
      * @param resetType ResetNvType
      *
      * Response function is IRadioModemResponse.nvResetConfigResponse()
+     *
+     * Note: This will be deprecated in favor of a rebootModem API in Android U.
      */
     void nvResetConfig(in int serial, in ResetNvType resetType);
 
@@ -139,6 +143,8 @@
      * @param prl PRL as a byte array
      *
      * Response function is IRadioModemResponse.nvWriteCdmaPrlResponse()
+     *
+     * @deprecated NV APIs are deprecated starting from Android U.
      */
     void nvWriteCdmaPrl(in int serial, in byte[] prl);
 
@@ -150,6 +156,8 @@
      * @param item NvWriteItem
      *
      * Response function is IRadioModemResponse.nvWriteItemResponse()
+     *
+     * @deprecated NV APIs are deprecated starting from Android U.
      */
     void nvWriteItem(in int serial, in NvWriteItem item);
 
diff --git a/radio/aidl/android/hardware/radio/modem/IRadioModemResponse.aidl b/radio/aidl/android/hardware/radio/modem/IRadioModemResponse.aidl
index b17cac4..eca3192 100644
--- a/radio/aidl/android/hardware/radio/modem/IRadioModemResponse.aidl
+++ b/radio/aidl/android/hardware/radio/modem/IRadioModemResponse.aidl
@@ -61,7 +61,6 @@
      *   RadioError:SYSTEM_ERR
      *   RadioError:MODEM_ERR
      *   RadioError:NOT_PROVISIONED
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
      */
@@ -88,7 +87,6 @@
      *   RadioError:NOT_PROVISIONED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
-     *   RadioError:REQUEST_NOT_SUPPORTED
      */
     void getDeviceIdentityResponse(in RadioResponseInfo info, in String imei, in String imeisv,
             in String esn, in String meid);
@@ -100,7 +98,6 @@
      * Valid errors returned:
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
-     *   RadioError:REQUEST_NOT_SUPPORTED
      */
     void getHardwareConfigResponse(in RadioResponseInfo info, in HardwareConfig[] config);
 
@@ -118,7 +115,6 @@
      *   RadioError:NOT_PROVISIONED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
-     *   RadioError:REQUEST_NOT_SUPPORTED
      */
     void getModemActivityInfoResponse(in RadioResponseInfo info, in ActivityStatsInfo activityInfo);
 
@@ -141,7 +137,6 @@
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:OPERATION_NOT_ALLOWED
      *   RadioError:INVALID_STATE
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:INTERNAL_ERR
      *   RadioError:NO_MEMORY
      *   RadioError:NO_RESOURCES
@@ -156,7 +151,8 @@
      * Valid errors returned:
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
-     *   RadioError:REQUEST_NOT_SUPPORTED
+     *
+     * @deprecated NV APIs are deprecated starting from Android U.
      */
     void nvReadItemResponse(in RadioResponseInfo info, in String result);
 
@@ -166,7 +162,8 @@
      * Valid errors returned:
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
-     *   RadioError:REQUEST_NOT_SUPPORTED
+     *
+     * Note: This will be deprecated in favor of a rebootModemResponse API in Android U.
      */
     void nvResetConfigResponse(in RadioResponseInfo info);
 
@@ -176,7 +173,8 @@
      * Valid errors returned:
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
-     *   RadioError:REQUEST_NOT_SUPPORTED
+     *
+     * @deprecated NV APIs are deprecated starting from Android U.
      */
     void nvWriteCdmaPrlResponse(in RadioResponseInfo info);
 
@@ -186,7 +184,8 @@
      * Valid errors returned:
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
-     *   RadioError:REQUEST_NOT_SUPPORTED
+     *
+     * @deprecated NV APIs are deprecated starting from Android U.
      */
     void nvWriteItemResponse(in RadioResponseInfo info);
 
@@ -200,7 +199,6 @@
      *   RadioError:NO_MEMORY
      *   RadioError:INTERNAL_ERR
      *   RadioError:SYSTEM_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
      */
@@ -216,7 +214,6 @@
      *   RadioError:INTERNAL_ERR
      *   RadioError:SYSTEM_ERR
      *   RadioError:INVALID_ARGUMENTS
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
      */
@@ -237,7 +234,6 @@
      *   RadioError:INVALID_ARGUMENTS
      *   RadioError:MODEM_ERR
      *   RadioError:INVALID_STATE
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
      */
diff --git a/radio/aidl/android/hardware/radio/modem/NvItem.aidl b/radio/aidl/android/hardware/radio/modem/NvItem.aidl
index 649b0d2..310b1ad 100644
--- a/radio/aidl/android/hardware/radio/modem/NvItem.aidl
+++ b/radio/aidl/android/hardware/radio/modem/NvItem.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.modem;
 
+/** @deprecated NV APIs are deprecated starting from Android U. */
 @VintfStability
 @Backing(type="int")
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/modem/NvWriteItem.aidl b/radio/aidl/android/hardware/radio/modem/NvWriteItem.aidl
index 47fb490..6472f23 100644
--- a/radio/aidl/android/hardware/radio/modem/NvWriteItem.aidl
+++ b/radio/aidl/android/hardware/radio/modem/NvWriteItem.aidl
@@ -18,6 +18,7 @@
 
 import android.hardware.radio.modem.NvItem;
 
+/** @deprecated NV APIs are deprecated starting from Android U. */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable NvWriteItem {
diff --git a/radio/aidl/android/hardware/radio/modem/ResetNvType.aidl b/radio/aidl/android/hardware/radio/modem/ResetNvType.aidl
index 16487f8..6476fe8 100644
--- a/radio/aidl/android/hardware/radio/modem/ResetNvType.aidl
+++ b/radio/aidl/android/hardware/radio/modem/ResetNvType.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.modem;
 
+/** Note: This will be deprecated along with nvResetConfig in Android U. */
 @VintfStability
 @Backing(type="int")
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/network/EmergencyRegResult.aidl b/radio/aidl/android/hardware/radio/network/EmergencyRegResult.aidl
index ec70e17..2215149 100644
--- a/radio/aidl/android/hardware/radio/network/EmergencyRegResult.aidl
+++ b/radio/aidl/android/hardware/radio/network/EmergencyRegResult.aidl
@@ -38,6 +38,11 @@
     Domain emcDomain;
 
     /**
+     * This indicates whether the network supports voice over PS network.
+     */
+    boolean isVopsSupported;
+
+    /**
      * This indicates if camped network support VoLTE emergency bearers.
      * This should only be set if the UE is in LTE mode.
      */
diff --git a/radio/aidl/android/hardware/radio/network/EutranRegistrationInfo.aidl b/radio/aidl/android/hardware/radio/network/EutranRegistrationInfo.aidl
index c9563ac..b986944 100644
--- a/radio/aidl/android/hardware/radio/network/EutranRegistrationInfo.aidl
+++ b/radio/aidl/android/hardware/radio/network/EutranRegistrationInfo.aidl
@@ -22,6 +22,21 @@
 @VintfStability
 @JavaDerive(toString=true)
 parcelable EutranRegistrationInfo {
+    enum AttachResultType {
+        /** Default value. */
+        NONE,
+        /** LTE is attached with eps only. */
+        EPS_ONLY,
+        /** LTE combined EPS and IMSI attach. */
+        COMBINED,
+    }
+
+    /** LTE combined attach with CSFB not preferred */
+    const int EXTRA_CSFB_NOT_PREFERRED = 1 << 0;
+
+    /** LTE combined attach for SMS only */
+    const int EXTRA_SMS_ONLY = 1 << 1;
+
     /**
      * Network capabilities for voice over PS services. This info is valid only on LTE network and
      * must be present when device is camped on LTE. VopsInfo must be empty when device is camped
@@ -33,4 +48,13 @@
      * be empty.
      */
     NrIndicators nrIndicators;
+
+    /**
+     * The type of network attachment. This info is valid only on LTE network and must be present
+     * when device has attached to the network.
+     */
+    AttachResultType lteAttachResultType;
+
+    /** Values are bitwise ORs of EXTRA_* constants */
+    int extraInfo;
 }
diff --git a/radio/aidl/android/hardware/radio/network/IRadioNetwork.aidl b/radio/aidl/android/hardware/radio/network/IRadioNetwork.aidl
index 0ac8b0e..70427f8 100644
--- a/radio/aidl/android/hardware/radio/network/IRadioNetwork.aidl
+++ b/radio/aidl/android/hardware/radio/network/IRadioNetwork.aidl
@@ -18,6 +18,8 @@
 
 import android.hardware.radio.AccessNetwork;
 import android.hardware.radio.network.CdmaRoamingType;
+import android.hardware.radio.network.EmergencyMode;
+import android.hardware.radio.network.EmergencyNetworkScanTrigger;
 import android.hardware.radio.network.IRadioNetworkIndication;
 import android.hardware.radio.network.IRadioNetworkResponse;
 import android.hardware.radio.network.IndicationFilter;
@@ -27,8 +29,6 @@
 import android.hardware.radio.network.RadioBandMode;
 import android.hardware.radio.network.SignalThresholdInfo;
 import android.hardware.radio.network.UsageSetting;
-import android.hardware.radio.network.EmergencyNetworkScanTrigger;
-import android.hardware.radio.network.EmergencyMode;
 
 /**
  * This interface is used by telephony and telecom to talk to cellular radio for network APIs.
@@ -112,6 +112,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioNetworkResponse.getImsRegistrationStateResponse()
+     *
+     * @deprecated Deprecated starting from Android U.
      */
     void getImsRegistrationState(in int serial);
 
@@ -449,27 +451,30 @@
      *
      * Response function is IRadioEmergencyResponse.setEmergencyModeResponse()
      */
-    void setEmergencyMode(int serial, in EmergencyMode emcModeType );
+    void setEmergencyMode(int serial, in EmergencyMode emcModeType);
 
     /**
      * Triggers an Emergency network scan.
      *
      * @param serial Serial number of the request.
-     * @param request Defines the radio target networks/preferred network/
-     * Max Scan Time and type of service to be scanned.
+     * @param request Contains the preferred networks and type of service to be scanned.
+     *                See {@link EmergencyNetworkScanTrigger}.
      *
      * Response function is IRadioEmergencyResponse.triggerEmergencyNetworkScanResponse()
      */
-    void triggerEmergencyNetworkScan( int serial, in EmergencyNetworkScanTrigger request);
+    void triggerEmergencyNetworkScan(int serial, in EmergencyNetworkScanTrigger request);
 
     /**
      * Cancels ongoing Emergency network scan
      *
      * @param serial Serial number of the request.
+     * @param resetScan Indicates how the next {@link #triggerEmergencyNetworkScan} should work.
+     *        If {@code true}, then the modem shall start the new scan from the beginning,
+     *        otherwise the modem shall resume from the last search.
      *
      * Response function is IRadioEmergencyResponse.cancelEmergencyNetworkScan()
      */
-    void cancelEmergencyNetworkScan(in int serial);
+    void cancelEmergencyNetworkScan(int serial, boolean resetScan);
 
     /**
      * Exits ongoing Emergency Mode
@@ -479,4 +484,80 @@
      * Response function is IRadioEmergencyResponse.exitEmergencyModeResponse()
      */
     void exitEmergencyMode(in int serial);
+
+    /**
+     * 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 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
+     * 3G: UEA0 and UIA0
+     * 4G: EEA0 and EIA0
+     * 5G: NEA0 and NIA0
+     *
+     *
+     * @param serial Serial number of the request.
+     * @param enabled To allow null encryption/integrity, set to true.
+     *                Otherwise, false.
+     *
+     * Response callback is IRadioResponse.setNullCipherAndIntegrityEnabledResponse()
+     */
+    void setNullCipherAndIntegrityEnabled(in int serial, in boolean enabled);
+
+    /**
+     * Checks whether N1 mode (access to 5G core network) is enabled or not.
+     *
+     * @param serial Serial number of request.
+     *
+     * Response function is IRadioNetworkResponse.isN1ModeEnabledResponse()
+     */
+    void isN1ModeEnabled(in int serial);
+
+    /**
+     * Enables or disables N1 mode (access to 5G core network) in accordance with
+     * 3GPP TS 24.501 4.9.
+     *
+     * Note: The default value of N1 mode shall be based on the modem's internal configuration
+     * as per device or carrier. This API may be invoked on demand first to disable N1 mode and
+     * later to re-enable for certain use case. This setting shall not be persisted by modem.
+     * This setting shall not interfere with the allowed network type bitmap set using
+     * {@link IRadioNetwork#setAllowedNetworkTypesBitmap()} API.
+     *
+     * @param serial Serial number of request.
+     * @param enable {@code true} to enable N1 mode, {@code false} to disable N1 mode.
+     *
+     * Response function is IRadioNetworkResponse.setN1ModeEnabledResponse()
+     */
+    void setN1ModeEnabled(in int serial, boolean enable);
+
+    /**
+     * This API updates the current user setting of sharing the location data. This value must be
+     * used by radio before honoring a network initiated location request for non emergency use
+     * cases. The radio shall ignore this setting during emergency call, emergency SMS or emergency
+     * call back modes and continue to provide the location information to the network initiated
+     * location requests.
+     *
+     * @param serial Serial number of request.
+     * @param shareLocation Whether to share location data to the network or not. true means the
+     *         radio is allowed to provide location data for any network initiated locations
+     *         request. false means the radio must not share location data for any network initiated
+     *         location requests for non-emergency use cases.
+     *
+     * Response function is IRadioNetworkResponse.setLocationPrivacySettingResponse()
+     */
+    void setLocationPrivacySetting(in int serial, in boolean shareLocation);
+
+    /**
+     * Request the current setting of sharing the location data.
+     *
+     * @param serial Serial number of request.
+     *
+     * Response function is IRadioNetworkResponse.getLocationPrivacySettingResponse()
+     */
+    void getLocationPrivacySetting(in int serial);
 }
diff --git a/radio/aidl/android/hardware/radio/network/IRadioNetworkIndication.aidl b/radio/aidl/android/hardware/radio/network/IRadioNetworkIndication.aidl
index 47d932d..2891496 100644
--- a/radio/aidl/android/hardware/radio/network/IRadioNetworkIndication.aidl
+++ b/radio/aidl/android/hardware/radio/network/IRadioNetworkIndication.aidl
@@ -21,13 +21,14 @@
 import android.hardware.radio.network.BarringInfo;
 import android.hardware.radio.network.CellIdentity;
 import android.hardware.radio.network.CellInfo;
+import android.hardware.radio.network.EmergencyRegResult;
 import android.hardware.radio.network.LinkCapacityEstimate;
+import android.hardware.radio.network.LocationResponseType;
 import android.hardware.radio.network.NetworkScanResult;
 import android.hardware.radio.network.PhoneRestrictedState;
 import android.hardware.radio.network.PhysicalChannelConfig;
 import android.hardware.radio.network.SignalStrength;
 import android.hardware.radio.network.SuppSvcNotification;
-import android.hardware.radio.network.EmergencyRegResult;
 
 /**
  * Interface declaring unsolicited radio indications for network APIs.
@@ -199,4 +200,13 @@
      * @param result the result of the Emergency Network Scan
      */
     void emergencyNetworkScanResult(in RadioIndicationType type, in EmergencyRegResult result);
+
+    /**
+     * Reports the result of the network initiated location request.
+     *
+     * @param type Type of radio indication
+     * @param locationResponseType result of the network initiated location request.
+     */
+    void onNetworkInitiatedLocationResult(
+            in RadioIndicationType type, in LocationResponseType locationResponseType);
 }
diff --git a/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl b/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl
index 243e949..3fa6521 100644
--- a/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl
+++ b/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl
@@ -23,13 +23,13 @@
 import android.hardware.radio.network.CdmaRoamingType;
 import android.hardware.radio.network.CellIdentity;
 import android.hardware.radio.network.CellInfo;
+import android.hardware.radio.network.EmergencyRegResult;
 import android.hardware.radio.network.OperatorInfo;
 import android.hardware.radio.network.RadioAccessSpecifier;
 import android.hardware.radio.network.RadioBandMode;
 import android.hardware.radio.network.RegStateResult;
 import android.hardware.radio.network.SignalStrength;
 import android.hardware.radio.network.UsageSetting;
-import android.hardware.radio.network.EmergencyRegResult;
 
 /**
  * Interface declaring response functions to solicited radio requests for network APIs.
@@ -57,7 +57,6 @@
      *   RadioError:INTERNAL_ERR
      *   RadioError:INVALID_ARGUMENTS
      *   RadioError:MODEM_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:NO_RESOURCES
      */
     void getAllowedNetworkTypesBitmapResponse(in RadioResponseInfo info, in int networkTypeBitmap);
@@ -74,7 +73,6 @@
      *   RadioError:INTERNAL_ERR
      *   RadioError:SYSTEM_ERR
      *   RadioError:MODEM_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
      */
@@ -93,7 +91,6 @@
      *   RadioError:INTERNAL_ERR
      *   RadioError:NO_MEMORY
      *   RadioError:MODEM_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:CANCELLED
      *   RadioError:NO_RESOURCES
      *   RadioError:INTERNAL_ERR
@@ -126,7 +123,6 @@
      *   RadioError:INTERNAL_ERR
      *   RadioError:SYSTEM_ERR
      *   RadioError:MODEM_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
      *   RadioError:SIM_ABSENT
@@ -170,7 +166,8 @@
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
      *   RadioError:INVALID_MODEM_STATE
-     *   RadioError:REQUEST_NOT_SUPPORTED
+     *
+     * @deprecated Deprecated starting from Android U.
      */
     void getImsRegistrationStateResponse(
             in RadioResponseInfo info, in boolean isRegistered, in RadioTechnologyFamily ratFamily);
@@ -187,7 +184,6 @@
      *   RadioError:SYSTEM_ERR
      *   RadioError:INVALID_ARGUMENTS
      *   RadioError:MODEM_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
      */
@@ -205,7 +201,6 @@
      *   RadioError:NO_MEMORY
      *   RadioError:INTERNAL_ERR
      *   RadioError:SYSTEM_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
      */
@@ -247,7 +242,6 @@
      *   RadioError:NO_MEMORY
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
-     *   RadioError:REQUEST_NOT_SUPPORTED
      */
     void getVoiceRadioTechnologyResponse(in RadioResponseInfo info, in RadioTechnology rat);
 
@@ -272,7 +266,6 @@
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      */
     void isNrDualConnectivityEnabledResponse(in RadioResponseInfo info, in boolean isEnabled);
 
@@ -287,7 +280,6 @@
      *   RadioError:INTERNAL_ERR
      *   RadioError:INVALID_ARGUMENTS
      *   RadioError:MODEM_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:NO_RESOURCES
      */
     void setAllowedNetworkTypesBitmapResponse(in RadioResponseInfo info);
@@ -304,7 +296,6 @@
      *   RadioError:SYSTEM_ERR
      *   RadioError:INVALID_ARGUMENTS
      *   RadioError:MODEM_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
      */
@@ -325,7 +316,6 @@
      *   RadioError:INTERNAL_ERR
      *   RadioError:SYSTEM_ERR
      *   RadioError:FDN_CHECK_FAILURE
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
      */
@@ -342,7 +332,6 @@
      *   RadioError:SYSTEM_ERR
      *   RadioError:INVALID_ARGUMENTS
      *   RadioError:MODEM_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:OPERATION_NOT_ALLOWED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
@@ -362,7 +351,6 @@
      *   RadioError:INVALID_ARGUMENTS
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
-     *   RadioError:REQUEST_NOT_SUPPORTED
      */
     void setCellInfoListRateResponse(in RadioResponseInfo info);
 
@@ -400,7 +388,6 @@
      *   RadioError:SYSTEM_ERR
      *   RadioError:INVALID_ARGUMENTS
      *   RadioError:MODEM_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
      *   RadioError:SIM_ABSENT
@@ -420,7 +407,6 @@
      *   RadioError:SYSTEM_ERR
      *   RadioError:INVALID_ARGUMENTS
      *   RadioError:MODEM_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
      *
@@ -443,7 +429,6 @@
      *   RadioError:SYSTEM_ERR
      *   RadioError:INVALID_ARGUMENTS
      *   RadioError:MODEM_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
      *
@@ -459,7 +444,6 @@
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:INVALID_STATE
      */
     void setNrDualConnectivityStateResponse(in RadioResponseInfo info);
@@ -486,7 +470,6 @@
      *   RadioError:SYSTEM_ERR
      *   RadioError:MODEM_ERR
      *   RadioError:INTERNAL_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
      *   RadioError:SIM_ABSENT
@@ -543,7 +526,6 @@
      *   RadioError:INVALID_ARGUMENTS
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:SIM_ABSENT
      */
     void supplyNetworkDepersonalizationResponse(in RadioResponseInfo info, in int remainingRetries);
@@ -575,11 +557,15 @@
     oneway void getUsageSettingResponse(in RadioResponseInfo info, in UsageSetting usageSetting);
 
     /**
+     * Response of setEmergencyMode.
+     * This is an optional API.
+     *
      * @param info Response info struct containing response type, serial no. and error.
      * @param regState the current registration state of the modem.
      *
      * Valid errors returned:
      *   RadioError:NONE
+     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:MODEM_ERR
      *   RadioError:INVALID_ARGUMENTS
@@ -587,10 +573,14 @@
     void setEmergencyModeResponse(in RadioResponseInfo info, in EmergencyRegResult regState);
 
     /**
-     * @param info Response info struct containing response type, serial no. and error
+     * Response of triggerEmergencyNetworkScan.
+     * This is an optional API.
+     *
+     * @param info Response info struct containing response type, serial no. and error.
      *
      * Valid errors returned:
      *   RadioError:NONE
+     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:MODEM_ERR
      *   RadioError:INVALID_ARGUMENTS
@@ -598,16 +588,34 @@
     void triggerEmergencyNetworkScanResponse(in RadioResponseInfo info);
 
     /**
-     * @param info Response info struct containing response type, serial no. and error
+     * Response of exitEmergencyMode.
+     * This is an optional API.
+     *
+     * @param info Response info struct containing response type, serial no. and error.
      *
      * Valid errors returned:
      *   RadioError:NONE
+     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:MODEM_ERR
      */
     void exitEmergencyModeResponse(in RadioResponseInfo info);
 
     /**
+     * Response of cancelEmergencyNetworkScan.
+     * This is an optional API.
+     *
+     * @param info Response info struct containing response type, serial no. and error.
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:REQUEST_NOT_SUPPORTED
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:MODEM_ERR
+     */
+    void cancelEmergencyNetworkScanResponse(in RadioResponseInfo info);
+
+    /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
@@ -615,5 +623,57 @@
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:MODEM_ERR
      */
-    void cancelEmergencyNetworkScanResponse(in RadioResponseInfo info);
+    void setNullCipherAndIntegrityEnabledResponse(in RadioResponseInfo info);
+
+    /**
+     * Response of isN1ModeEnabled.
+     * This is an optional API.
+     *
+     * @param info Response info struct containing response type, serial no. and error.
+     * @param isEnabled Indicates whether N1 mode is enabled or not.
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:INTERNAL_ERR
+     *   RadioError:REQUEST_NOT_SUPPORTED
+     */
+    void isN1ModeEnabledResponse(in RadioResponseInfo info, boolean isEnabled);
+
+    /**
+     * Response of setN1ModeEnabled.
+     * This is an optional API.
+     *
+     * @param info Response info struct containing response type, serial no. and error.
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:INTERNAL_ERR
+     *   RadioError:REQUEST_NOT_SUPPORTED
+     *   RadioError:INVALID_STATE
+     */
+    void setN1ModeEnabledResponse(in RadioResponseInfo info);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:INTERNAL_ERR
+     */
+    void setLocationPrivacySettingResponse(in RadioResponseInfo info);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     * @param shareLocation Indicates whether the location sharing is allowed or not, True if
+     *         allowed else false.
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:INTERNAL_ERR
+     */
+    void getLocationPrivacySettingResponse(in RadioResponseInfo info, boolean shareLocation);
 }
diff --git a/radio/aidl/android/hardware/radio/network/LocationResponseType.aidl b/radio/aidl/android/hardware/radio/network/LocationResponseType.aidl
new file mode 100644
index 0000000..0c502d0
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/network/LocationResponseType.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.
+ */
+
+package android.hardware.radio.network;
+
+@VintfStability
+@Backing(type="int")
+@JavaDerive(toString=true)
+enum LocationResponseType {
+    /**
+     * Network initiated Location request rejected by modem because the user has not given
+     * permission for this use case
+     */
+    REJECTED = 0,
+    /**
+     * Network initiated Location request is accepted by modem however no location information has
+     * been shared to network due to a failure
+     */
+    ACCEPTED_NO_LOCATION_PROVIDED = 1,
+    /**
+     * Network initiated Location request is accepted and location information is provided to the
+     * network by modem
+     */
+    ACCEPTED_LOCATION_PROVIDED = 2,
+}
diff --git a/radio/aidl/android/hardware/radio/network/RegState.aidl b/radio/aidl/android/hardware/radio/network/RegState.aidl
index 3f13783..bdba4c4 100644
--- a/radio/aidl/android/hardware/radio/network/RegState.aidl
+++ b/radio/aidl/android/hardware/radio/network/RegState.aidl
@@ -65,4 +65,10 @@
      * Same as UNKNOWN but indicates that emergency calls are enabled
      */
     UNKNOWN_EM = 14,
+    /**
+     * Emergency attached in EPS or in 5GS.
+     * Reference: 3GPP TS 24.301 9.9.3.11 EPS attach type.
+     * Reference: 3GPP TS 24.501 9.11.3.6 5GS registration result.
+     */
+    REG_EM = 20,
 }
diff --git a/radio/aidl/android/hardware/radio/network/RegStateResult.aidl b/radio/aidl/android/hardware/radio/network/RegStateResult.aidl
index 3d96b8c..f1d2972 100644
--- a/radio/aidl/android/hardware/radio/network/RegStateResult.aidl
+++ b/radio/aidl/android/hardware/radio/network/RegStateResult.aidl
@@ -33,9 +33,9 @@
      */
     RegState regState;
     /**
-     * Indicates the radio technology (except LTE_CA, which is no longer a valid value), which
-     * must not be UNKNOWN if regState is REG_HOME, REG_ROAMING, NOT_REG_MT_NOT_SEARCHING_OP_EM,
-     * NOT_REG_MT_SEARCHING_OP_EM, REG_DENIED_EM, or UNKNOWN_EM.
+     * Indicates the radio technology, which must not be UNKNOWN if regState is REG_HOME,
+     * REG_ROAMING, NOT_REG_MT_NOT_SEARCHING_OP_EM, NOT_REG_MT_SEARCHING_OP_EM, REG_DENIED_EM,
+     * or UNKNOWN_EM.
      * When the device is on carrier aggregation, vendor RIL service must properly report multiple
      * PhysicalChannelConfig elements through IRadioNetwork::currentPhysicalChannelConfigs.
      */
diff --git a/radio/aidl/android/hardware/radio/sim/IRadioSimResponse.aidl b/radio/aidl/android/hardware/radio/sim/IRadioSimResponse.aidl
index 750a29a..b3df504 100644
--- a/radio/aidl/android/hardware/radio/sim/IRadioSimResponse.aidl
+++ b/radio/aidl/android/hardware/radio/sim/IRadioSimResponse.aidl
@@ -65,7 +65,6 @@
      *   RadioError:CANCELLED
      *   RadioError:INVALID_ARGUMENTS
      *   RadioError:INVALID_SIM_STATE
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:SIM_PUK2
      */
     void changeIccPin2ForAppResponse(in RadioResponseInfo info, in int remainingRetries);
@@ -84,7 +83,6 @@
      *   RadioError:CANCELLED
      *   RadioError:INVALID_ARGUMENTS
      *   RadioError:INVALID_SIM_STATE
-     *   RadioError:REQUEST_NOT_SUPPORTED
      */
     void changeIccPinForAppResponse(in RadioResponseInfo info, in int remainingRetries);
 
@@ -108,7 +106,6 @@
      * Valid errors returned:
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
-     *   RadioError:REQUEST_NOT_SUPPORTED
      */
     void getAllowedCarriersResponse(in RadioResponseInfo info, in CarrierRestrictions carriers,
             in SimLockMultiSimPolicy multiSimPolicy);
@@ -133,7 +130,6 @@
      *   RadioError:INVALID_ARGUMENTS
      *   RadioError:MODEM_ERR
      *   RadioError:NOT_PROVISIONED
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
      *   RadioError:SIM_ABSENT
@@ -153,7 +149,6 @@
      *   RadioError:NO_MEMORY
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:SIM_ABSENT
      */
     void getCdmaSubscriptionSourceResponse(
@@ -176,7 +171,6 @@
      *   RadioError:INTERNAL_ERR
      *   RadioError:SYSTEM_ERR
      *   RadioError:FDN_CHECK_FAILURE
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
      */
@@ -191,7 +185,6 @@
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
      *   RadioError:NO_RESOURCES
-     *   RadioError:REQUEST_NOT_SUPPORTED
      */
     void getIccCardStatusResponse(in RadioResponseInfo info, in CardStatus cardStatus);
 
@@ -208,7 +201,6 @@
      *   RadioError:CANCELLED
      *   RadioError:INVALID_SIM_STATE
      *   RadioError:SIM_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      */
     void getImsiForAppResponse(in RadioResponseInfo info, in String imsi);
 
@@ -219,13 +211,10 @@
      * Valid errors returned:
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:INVALID_ARGUMENTS
      *   RadioError:INVALID_SIM_STATE
      *   RadioError:MODEM_ERR
      *   RadioError:INTERNAL_ERR
-     * REQUEST_NOT_SUPPORTED may only be returned on devices that don't support this API,
-     * indicated by the HAL capability CAPABILITY_SIM_PHONEBOOK_IN_MODEM.
      */
     void getSimPhonebookCapacityResponse(in RadioResponseInfo info, in PhonebookCapacity capacity);
 
@@ -235,13 +224,10 @@
      * Valid errors returned:
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:INVALID_ARGUMENTS
      *   RadioError:INVALID_SIM_STATE
      *   RadioError:MODEM_ERR
      *   RadioError:INTERNAL_ERR
-     * REQUEST_NOT_SUPPORTED may only be returned on devices that don't support this API,
-     * indicated by the HAL capability CAPABILITY_SIM_PHONEBOOK_IN_MODEM.
      */
     void getSimPhonebookRecordsResponse(in RadioResponseInfo info);
 
@@ -255,7 +241,6 @@
      *   RadioError:NO_MEMORY
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
-     *   RadioError:REQUEST_NOT_SUPPORTED
      */
     void iccCloseLogicalChannelResponse(in RadioResponseInfo info);
 
@@ -274,7 +259,6 @@
      *   RadioError:CANCELLED
      *   RadioError:INVALID_SIM_STATE
      *   RadioError:SIM_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      */
     void iccIoForAppResponse(in RadioResponseInfo info, in IccIoResult iccIo);
 
@@ -296,7 +280,6 @@
      *   RadioError:SIM_ERR
      *   RadioError:INVALID_SIM_STATE
      *   RadioError:MISSING_RESOURCE
-     *   RadioError:REQUEST_NOT_SUPPORTED
      */
     void iccOpenLogicalChannelResponse(
             in RadioResponseInfo info, in int channelId, in byte[] selectResponse);
@@ -312,7 +295,6 @@
      *   RadioError:NO_MEMORY
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
-     *   RadioError:REQUEST_NOT_SUPPORTED
      */
     void iccTransmitApduBasicChannelResponse(in RadioResponseInfo info, in IccIoResult result);
 
@@ -327,7 +309,6 @@
      *   RadioError:NO_MEMORY
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
-     *   RadioError:REQUEST_NOT_SUPPORTED
      */
     void iccTransmitApduLogicalChannelResponse(in RadioResponseInfo info, in IccIoResult result);
 
@@ -341,7 +322,6 @@
      *   RadioError:NO_MEMORY
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
-     *   RadioError:REQUEST_NOT_SUPPORTED
      */
     void reportStkServiceIsRunningResponse(in RadioResponseInfo info);
 
@@ -359,7 +339,6 @@
      *   RadioError:INVALID_MODEM_STATE
      *   RadioError:SIM_ERR
      *   RadioError:INVALID_ARGUMENTS
-     *   RadioError:REQUEST_NOT_SUPPORTED
      */
     void requestIccSimAuthenticationResponse(in RadioResponseInfo info, in IccIoResult result);
 
@@ -379,7 +358,6 @@
      *   RadioError:CANCELLED
      *   RadioError:INVALID_ARGUMENTS
      *   RadioError:MODEM_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:SIM_ABSENT
      */
     void sendEnvelopeResponse(in RadioResponseInfo info, in String commandResponse);
@@ -397,7 +375,6 @@
      *   RadioError:NO_MEMORY
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:SIM_ABSENT
      */
     void sendEnvelopeWithStatusResponse(in RadioResponseInfo info, in IccIoResult iccIo);
@@ -415,7 +392,6 @@
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
      *   RadioError:INVALID_MODEM_STATE
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:SIM_ABSENT
      */
     void sendTerminalResponseToSimResponse(in RadioResponseInfo info);
@@ -427,7 +403,6 @@
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_ARGUMENTS
-     *   RadioError:REQUEST_NOT_SUPPORTED
      */
     void setAllowedCarriersResponse(in RadioResponseInfo info);
 
@@ -435,12 +410,11 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
-     *   RadioError:RIL_E_SUCCESS
-     *   RadioError:RIL_E_RADIO_NOT_AVAILABLE
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:SIM_ABSENT
-     *   RadioError:RIL_E_REQUEST_NOT_SUPPORTED
      *   RadioError:INVALID_ARGUMENTS
-     *   RadioError:MODEM_INTERNAL_FAILURE
+     *   RadioError:INTERNAL_FAILURE
      */
     void setCarrierInfoForImsiEncryptionResponse(in RadioResponseInfo info);
 
@@ -456,7 +430,6 @@
      *   RadioError:NO_MEMORY
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
-     *   RadioError:REQUEST_NOT_SUPPORTED
      */
     void setCdmaSubscriptionSourceResponse(in RadioResponseInfo info);
 
@@ -477,7 +450,6 @@
      *   RadioError:SYSTEM_ERR
      *   RadioError:INVALID_STATE
      *   RadioError:FDN_CHECK_FAILURE
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:INVALID_MODEM_STATE
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
@@ -507,7 +479,6 @@
      *   RadioError:SYSTEM_ERR
      *   RadioError:MODEM_ERR
      *   RadioError:INVALID_ARGUMENTS
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
      */
@@ -527,7 +498,6 @@
      *   RadioError:CANCELLED
      *   RadioError:INVALID_ARGUMENTS
      *   RadioError:INVALID_SIM_STATE
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:SIM_PUK2
      */
     void supplyIccPin2ForAppResponse(in RadioResponseInfo info, in int remainingRetries);
@@ -546,7 +516,6 @@
      *   RadioError:CANCELLED
      *   RadioError:INVALID_ARGUMENTS
      *   RadioError:INVALID_SIM_STATE
-     *   RadioError:REQUEST_NOT_SUPPORTED
      */
     void supplyIccPinForAppResponse(in RadioResponseInfo info, in int remainingRetries);
 
@@ -564,7 +533,6 @@
      *   RadioError:CANCELLED
      *   RadioError:INVALID_ARGUMENTS
      *   RadioError:INVALID_SIM_STATE
-     *   RadioError:REQUEST_NOT_SUPPORTED
      */
     void supplyIccPuk2ForAppResponse(in RadioResponseInfo info, in int remainingRetries);
 
@@ -582,7 +550,6 @@
      *   RadioError:CANCELLED
      *   RadioError:INVALID_ARGUMENTS
      *   RadioError:INVALID_SIM_STATE
-     *   RadioError:REQUEST_NOT_SUPPORTED
      */
     void supplyIccPukForAppResponse(in RadioResponseInfo info, in int remainingRetries);
 
@@ -603,7 +570,6 @@
      *   RadioError:MODEM_ERR
      *   RadioError:INVALID_ARGUMENTS
      *   RadioError:NO_RESOURCES
-     *   RadioError:REQUEST_NOT_SUPPORTED
      */
     void supplySimDepersonalizationResponse(
             in RadioResponseInfo info, in PersoSubstate persoType, in int remainingRetries);
@@ -616,7 +582,6 @@
      * Valid errors returned:
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:INVALID_ARGUMENTS
      *   RadioError:INVALID_SIM_STATE
      *   RadioError:MODEM_ERR
@@ -624,8 +589,6 @@
      *   RadioError:SIM_ERR
      *   RadioError:NO_SUCH_ENTRY
      *   RadioError:NO_RESOURCES
-     * REQUEST_NOT_SUPPORTED may only be returned on devices that don't support this API,
-     * indicated by the HAL capability CAPABILITY_SIM_PHONEBOOK_IN_MODEM.
      */
     void updateSimPhonebookRecordsResponse(in RadioResponseInfo info, in int updatedRecordIndex);
 }
diff --git a/radio/aidl/android/hardware/radio/sim/SimApdu.aidl b/radio/aidl/android/hardware/radio/sim/SimApdu.aidl
index 43adbbc..4759e2e 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;
 }
diff --git a/radio/aidl/android/hardware/radio/voice/IRadioVoiceResponse.aidl b/radio/aidl/android/hardware/radio/voice/IRadioVoiceResponse.aidl
index cf1b953..39e3ace 100644
--- a/radio/aidl/android/hardware/radio/voice/IRadioVoiceResponse.aidl
+++ b/radio/aidl/android/hardware/radio/voice/IRadioVoiceResponse.aidl
@@ -42,7 +42,6 @@
      *   RadioError:INVALID_CALL_ID
      *   RadioError:INVALID_ARGUMENTS
      *   RadioError:SYSTEM_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
      */
@@ -71,7 +70,6 @@
      *   RadioError:INVALID_STATE
      *   RadioError:INVALID_ARGUMENTS
      *   RadioError:SYSTEM_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:INVALID_MODEM_STATE
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
@@ -92,7 +90,6 @@
      *   RadioError:OPERATION_NOT_ALLOWED
      *   RadioError:INVALID_ARGUMENTS
      *   RadioError:SYSTEM_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:INVALID_MODEM_STATE
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
@@ -122,7 +119,6 @@
      *   RadioError:OPERATION_NOT_ALLOWED
      *   RadioError:ABORTED
      *   RadioError:SYSTEM_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:INVALID_MODEM_STATE
      *   RadioError:CANCELLED
      */
@@ -163,7 +159,6 @@
      *   RadioError:SYSTEM_ERR
      *   RadioError:INVALID_ARGUMENTS
      *   RadioError:MODEM_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
      *   RadioError:SIM_ABSENT
@@ -185,7 +180,6 @@
      *   RadioError:INTERNAL_ERR
      *   RadioError:INVALID_CALL_ID
      *   RadioError:OPERATION_NOT_ALLOWED
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:INVALID_MODEM_STATE
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
@@ -212,7 +206,6 @@
      *   RadioError:MODEM_ERR
      *   RadioError:INTERNAL_ERR
      *   RadioError:FDN_CHECK_FAILURE
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:SYSTEM_ERR
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
@@ -241,7 +234,6 @@
      *   RadioError:FDN_CHECK_FAILURE
      *   RadioError:INTERNAL_ERR
      *   RadioError:SYSTEM_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
      */
@@ -260,7 +252,6 @@
      *   RadioError:MODEM_ERR
      *   RadioError:INTERNAL_ERR
      *   RadioError:FDN_CHECK_FAILURE
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
      */
@@ -282,7 +273,6 @@
      *   RadioError:INTERNAL_ERR
      *   RadioError:FDN_CHECK_FAILURE
      *   RadioError:SYSTEM_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:INVALID_ARGUMENTS
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
@@ -298,7 +288,6 @@
      *   RadioError:INTERNAL_ERR
      *   RadioError:SYSTEM_ERR
      *   RadioError:INVALID_ARGUMENTS
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
      */
@@ -344,7 +333,6 @@
      *   RadioError:INVALID_ARGUMENTS
      *   RadioError:INTERNAL_ERR
      *   RadioError:MODEM_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:NO_MEMORY
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
@@ -367,7 +355,6 @@
      *   RadioError:INVALID_ARGUMENTS
      *   RadioError:INTERNAL_ERR
      *   RadioError:SYSTEM_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
      */
@@ -386,7 +373,6 @@
      *   RadioError:INTERNAL_ERR
      *   RadioError:NO_MEMORY
      *   RadioError:SYSTEM_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
      */
@@ -404,7 +390,6 @@
      *   RadioError:INTERNAL_ERR
      *   RadioError:NO_MEMORY
      *   RadioError:SYSTEM_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
      */
@@ -423,7 +408,6 @@
      *   RadioError:INVALID_ARGUMENTS
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:SIM_ABSENT
      */
     void handleStkCallSetupRequestFromSimResponse(in RadioResponseInfo info);
@@ -442,7 +426,6 @@
      *   RadioError:INVALID_CALL_ID
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
-     *   RadioError:REQUEST_NOT_SUPPORTED
      */
     void hangupConnectionResponse(in RadioResponseInfo info);
 
@@ -461,7 +444,6 @@
      *   RadioError:OPERATION_NOT_ALLOWED
      *   RadioError:INVALID_ARGUMENTS
      *   RadioError:SYSTEM_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
      */
@@ -482,7 +464,6 @@
      *   RadioError:OPERATION_NOT_ALLOWED
      *   RadioError:INVALID_ARGUMENTS
      *   RadioError:SYSTEM_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:CANCELLED
      */
     void hangupWaitingOrBackgroundResponse(in RadioResponseInfo info);
@@ -497,7 +478,6 @@
      *   RadioError:MODEM_ERR
      *   RadioError:INTERNAL_ERR
      *   RadioError:NO_MEMORY
-     *   RadioError:REQUEST_NOT_SUPPORTED
      */
     void isVoNrEnabledResponse(in RadioResponseInfo info, in boolean enable);
 
@@ -516,7 +496,6 @@
      *   RadioError:OPERATION_NOT_ALLOWED
      *   RadioError:INVALID_ARGUMENTS
      *   RadioError:SYSTEM_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:INVALID_MODEM_STATE
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
@@ -536,7 +515,6 @@
      *   RadioError:MODEM_ERR
      *   RadioError:INVALID_CALL_ID
      *   RadioError:INVALID_STATE
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
      *   RadioError:INVALID_MODEM_STATE
@@ -557,7 +535,6 @@
      *   RadioError:MODEM_ERR
      *   RadioError:INVALID_CALL_ID
      *   RadioError:INVALID_STATE
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:INVALID_MODEM_STATE
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
@@ -578,7 +555,6 @@
      *   RadioError:INVALID_CALL_ID
      *   RadioError:INTERNAL_ERR
      *   RadioError:SYSTEM_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:CANCELLED
      *   RadioError:INVALID_MODEM_STATE
      */
@@ -603,7 +579,6 @@
      *   RadioError:ABORTED
      *   RadioError:SYSTEM_ERR
      *   RadioError:INVALID_STATE
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:INVALID_MODEM_STATE
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
@@ -625,7 +600,6 @@
      *   RadioError:INTERNAL_ERR
      *   RadioError:INVALID_CALL_ID
      *   RadioError:OPERATION_NOT_ALLOWED
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:INVALID_MODEM_STATE
      *   RadioError:CANCELLED
      */
@@ -647,7 +621,6 @@
      *   RadioError:INTERNAL_ERR
      *   RadioError:INVALID_STATE
      *   RadioError:FDN_CHECK_FAILURE
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:INVALID_MODEM_STATE
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
@@ -670,7 +643,6 @@
      *   RadioError:INVALID_STATE
      *   RadioError:FDN_CHECK_FAILURE
      *   RadioError:SYSTEM_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:INVALID_MODEM_STATE
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
@@ -690,7 +662,6 @@
      *   RadioError:NO_MEMORY
      *   RadioError:INTERNAL_ERR
      *   RadioError:SYSTEM_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
      */
@@ -707,7 +678,6 @@
      *   RadioError:REQUEST_RATE_LIMITED
      *   RadioError:INTERNAL_ERR
      *   RadioError:SYSTEM_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
      */
@@ -724,7 +694,6 @@
      *   RadioError:INTERNAL_ERR
      *   RadioError:NO_MEMORY
      *   RadioError:SYSTEM_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:INVALID_CALL_ID
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
@@ -742,7 +711,6 @@
      *   RadioError:INTERNAL_ERR
      *   RadioError:NO_MEMORY
      *   RadioError:SYSTEM_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
      */
@@ -758,7 +726,6 @@
      *   RadioError:MODEM_ERR
      *   RadioError:INTERNAL_ERR
      *   RadioError:NO_MEMORY
-     *   RadioError:REQUEST_NOT_SUPPORTED
      */
     void setVoNrEnabledResponse(in RadioResponseInfo info);
 
@@ -776,7 +743,6 @@
      *   RadioError:INTERNAL_ERR
      *   RadioError:INVALID_CALL_ID
      *   RadioError:SYSTEM_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:CANCELLED
      *   RadioError:INVALID_MODEM_STATE
      */
@@ -796,7 +762,6 @@
      *   RadioError:MODEM_ERR
      *   RadioError:INTERNAL_ERR
      *   RadioError:INVALID_CALL_ID
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:CANCELLED
      *   RadioError:INVALID_MODEM_STATE
      */
@@ -817,7 +782,6 @@
      *   RadioError:OPERATION_NOT_ALLOWED
      *   RadioError:INVALID_ARGUMENTS
      *   RadioError:SYSTEM_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:INVALID_MODEM_STATE
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
diff --git a/radio/aidl/compat/libradiocompat/Android.bp b/radio/aidl/compat/libradiocompat/Android.bp
index f79e045..c40ca30 100644
--- a/radio/aidl/compat/libradiocompat/Android.bp
+++ b/radio/aidl/compat/libradiocompat/Android.bp
@@ -31,17 +31,18 @@
         "-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION",
     ],
     shared_libs: [
-        "android.hardware.radio.config-V1-ndk",
+        "android.hardware.radio.config-V2-ndk",
         "android.hardware.radio.config@1.0",
         "android.hardware.radio.config@1.1",
         "android.hardware.radio.config@1.2",
         "android.hardware.radio.config@1.3",
-        "android.hardware.radio.data-V1-ndk",
-        "android.hardware.radio.messaging-V1-ndk",
-        "android.hardware.radio.modem-V1-ndk",
+        "android.hardware.radio.data-V2-ndk",
+        "android.hardware.radio.ims-V1-ndk",
+        "android.hardware.radio.messaging-V2-ndk",
+        "android.hardware.radio.modem-V2-ndk",
         "android.hardware.radio.network-V2-ndk",
-        "android.hardware.radio.sim-V1-ndk",
-        "android.hardware.radio.voice-V1-ndk",
+        "android.hardware.radio.sim-V2-ndk",
+        "android.hardware.radio.voice-V2-ndk",
         "android.hardware.radio@1.0",
         "android.hardware.radio@1.1",
         "android.hardware.radio@1.2",
@@ -69,6 +70,9 @@
         "data/RadioResponse-data.cpp",
         "data/RadioData.cpp",
         "data/structs.cpp",
+        "ims/RadioIndication-ims.cpp",
+        "ims/RadioResponse-ims.cpp",
+        "ims/RadioIms.cpp",
         "messaging/RadioIndication-messaging.cpp",
         "messaging/RadioMessaging.cpp",
         "messaging/RadioResponse-messaging.cpp",
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/ims/RadioIms.cpp b/radio/aidl/compat/libradiocompat/ims/RadioIms.cpp
new file mode 100644
index 0000000..d2bdfff
--- /dev/null
+++ b/radio/aidl/compat/libradiocompat/ims/RadioIms.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 <libradiocompat/RadioIms.h>
+
+#include "commonStructs.h"
+#include "debug.h"
+
+#include "collections.h"
+
+#define RADIO_MODULE "Ims"
+
+namespace android::hardware::radio::compat {
+
+using ::ndk::ScopedAStatus;
+namespace aidl = ::aidl::android::hardware::radio::ims;
+constexpr auto ok = &ScopedAStatus::ok;
+
+std::shared_ptr<aidl::IRadioImsResponse> RadioIms::respond() {
+    return mCallbackManager->response().imsCb();
+}
+
+ScopedAStatus RadioIms::setSrvccCallInfo(
+        int32_t serial, const std::vector<aidl::SrvccCall>& /*srvccCalls*/) {
+    LOG_CALL << serial;
+    LOG(ERROR) << " setSrvccCallInfo is unsupported by HIDL HALs";
+    return ok();
+}
+ScopedAStatus RadioIms::updateImsRegistrationInfo(
+        int32_t serial, const aidl::ImsRegistration& /*imsRegistration*/) {
+    LOG_CALL << serial;
+    LOG(ERROR) << " updateImsRegistrationInfo is unsupported by HIDL HALs";
+    return ok();
+}
+ScopedAStatus RadioIms::startImsTraffic(
+        int32_t serial, int32_t /*token*/, aidl::ImsTrafficType /*imsTrafficType*/,
+        ::aidl::android::hardware::radio::AccessNetwork /*accessNetworkType*/,
+        ::aidl::android::hardware::radio::ims::ImsCall::Direction /*trafficDirection*/) {
+    LOG_CALL << serial;
+    LOG(ERROR) << " startImsTraffic is unsupported by HIDL HALs";
+    return ok();
+}
+ScopedAStatus RadioIms::stopImsTraffic(int32_t serial, int32_t /*token*/) {
+    LOG_CALL << serial;
+    LOG(ERROR) << " stopImsTraffic is unsupported by HIDL HALs";
+    return ok();
+}
+ScopedAStatus RadioIms::triggerEpsFallback(int32_t serial, aidl::EpsFallbackReason /*reason*/) {
+    LOG_CALL << serial;
+    LOG(ERROR) << " triggerEpsFallback is unsupported by HIDL HALs";
+    return ok();
+}
+ScopedAStatus RadioIms::sendAnbrQuery(
+        int32_t serial, aidl::ImsStreamType /*mediaType*/, aidl::ImsStreamDirection /*direction*/,
+        int32_t /*bitsPerSecond*/) {
+    LOG_CALL << serial;
+    LOG(ERROR) << " sendAnbrQuery is unsupported by HIDL HALs";
+    return ok();
+}
+ScopedAStatus RadioIms::updateImsCallStatus(
+        int32_t serial, const std::vector<aidl::ImsCall>& /*imsCalls*/) {
+    LOG_CALL << serial;
+    LOG(ERROR) << " updateImsCallStatus is unsupported by HIDL HALs";
+    return ok();
+}
+
+ScopedAStatus RadioIms::setResponseFunctions(
+        const std::shared_ptr<aidl::IRadioImsResponse>& response,
+        const std::shared_ptr<aidl::IRadioImsIndication>& indication) {
+    LOG_CALL << response << ' ' << indication;
+    mCallbackManager->setResponseFunctions(response, indication);
+    return ok();
+}
+
+}  // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/ims/RadioIndication-ims.cpp b/radio/aidl/compat/libradiocompat/ims/RadioIndication-ims.cpp
new file mode 100644
index 0000000..10109b8
--- /dev/null
+++ b/radio/aidl/compat/libradiocompat/ims/RadioIndication-ims.cpp
@@ -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.
+ */
+
+#include <libradiocompat/RadioIndication.h>
+
+#include "commonStructs.h"
+#include "debug.h"
+
+#include "collections.h"
+
+#define RADIO_MODULE "ImsIndication"
+
+namespace android::hardware::radio::compat {
+
+using ::aidl::android::hardware::radio::RadioTechnology;
+namespace aidl = ::aidl::android::hardware::radio::ims;
+
+void RadioIndication::setResponseFunction(std::shared_ptr<aidl::IRadioImsIndication> imsCb) {
+    mImsCb = imsCb;
+}
+
+std::shared_ptr<aidl::IRadioImsIndication> RadioIndication::imsCb() {
+    return mImsCb.get();
+}
+
+}  // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/ims/RadioResponse-ims.cpp b/radio/aidl/compat/libradiocompat/ims/RadioResponse-ims.cpp
new file mode 100644
index 0000000..831a0ae
--- /dev/null
+++ b/radio/aidl/compat/libradiocompat/ims/RadioResponse-ims.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 <libradiocompat/RadioResponse.h>
+
+#include "commonStructs.h"
+#include "debug.h"
+
+#include "collections.h"
+
+#define RADIO_MODULE "ImsResponse"
+
+namespace android::hardware::radio::compat {
+
+namespace aidl = ::aidl::android::hardware::radio::ims;
+
+void RadioResponse::setResponseFunction(std::shared_ptr<aidl::IRadioImsResponse> imsCb) {
+    mImsCb = imsCb;
+}
+
+std::shared_ptr<aidl::IRadioImsResponse> RadioResponse::imsCb() {
+    return mImsCb.get();
+}
+
+}  // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioIms.h b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioIms.h
new file mode 100644
index 0000000..0dbc565
--- /dev/null
+++ b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioIms.h
@@ -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.
+ */
+#pragma once
+
+#include "RadioCompatBase.h"
+
+#include <aidl/android/hardware/radio/ims/BnRadioIms.h>
+
+namespace android::hardware::radio::compat {
+
+class RadioIms : public RadioCompatBase, public aidl::android::hardware::radio::ims::BnRadioIms {
+    ::ndk::ScopedAStatus setSrvccCallInfo(
+            int32_t serial,
+            const std::vector<::aidl::android::hardware::radio::ims::SrvccCall>& srvccCalls)
+            override;
+    ::ndk::ScopedAStatus updateImsRegistrationInfo(
+            int32_t serial,
+            const ::aidl::android::hardware::radio::ims::ImsRegistration& imsRegistration) override;
+    ::ndk::ScopedAStatus startImsTraffic(
+            int32_t serial, int32_t token,
+            ::aidl::android::hardware::radio::ims::ImsTrafficType imsTrafficType,
+            ::aidl::android::hardware::radio::AccessNetwork accessNetworkType,
+            ::aidl::android::hardware::radio::ims::ImsCall::Direction trafficDirection) override;
+    ::ndk::ScopedAStatus stopImsTraffic(int32_t serial, int32_t token) override;
+    ::ndk::ScopedAStatus triggerEpsFallback(
+            int32_t serial,
+            ::aidl::android::hardware::radio::ims::EpsFallbackReason reason) override;
+    ::ndk::ScopedAStatus sendAnbrQuery(
+            int32_t serial, ::aidl::android::hardware::radio::ims::ImsStreamType mediaType,
+            ::aidl::android::hardware::radio::ims::ImsStreamDirection direction,
+            int32_t bitsPerSecond) override;
+    ::ndk::ScopedAStatus updateImsCallStatus(
+            int32_t serial,
+            const std::vector<::aidl::android::hardware::radio::ims::ImsCall>& imsCalls) override;
+
+    ::ndk::ScopedAStatus setResponseFunctions(
+            const std::shared_ptr<::aidl::android::hardware::radio::ims::IRadioImsResponse>&
+                    radioImsResponse,
+            const std::shared_ptr<::aidl::android::hardware::radio::ims::IRadioImsIndication>&
+                    radioImsIndication) override;
+
+  protected:
+    std::shared_ptr<::aidl::android::hardware::radio::ims::IRadioImsResponse> respond();
+
+  public:
+    using RadioCompatBase::RadioCompatBase;
+};
+
+}  // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioIndication.h b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioIndication.h
index 6cfd59c..f042456 100644
--- a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioIndication.h
+++ b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioIndication.h
@@ -19,6 +19,7 @@
 #include "GuaranteedCallback.h"
 
 #include <aidl/android/hardware/radio/data/IRadioDataIndication.h>
+#include <aidl/android/hardware/radio/ims/IRadioImsIndication.h>
 #include <aidl/android/hardware/radio/messaging/IRadioMessagingIndication.h>
 #include <aidl/android/hardware/radio/modem/IRadioModemIndication.h>
 #include <aidl/android/hardware/radio/network/IRadioNetworkIndication.h>
@@ -55,6 +56,10 @@
             ::aidl::android::hardware::radio::voice::IRadioVoiceIndication,
             ::aidl::android::hardware::radio::voice::IRadioVoiceIndicationDefault, true>
             mVoiceCb;
+    GuaranteedCallback<  //
+            ::aidl::android::hardware::radio::ims::IRadioImsIndication,
+            ::aidl::android::hardware::radio::ims::IRadioImsIndicationDefault, true>
+            mImsCb;
 
     // IRadioIndication @ 1.0
     Return<void> radioStateChanged(V1_0::RadioIndicationType type,
@@ -220,6 +225,8 @@
             std::shared_ptr<::aidl::android::hardware::radio::sim::IRadioSimIndication> simCb);
     void setResponseFunction(
             std::shared_ptr<::aidl::android::hardware::radio::voice::IRadioVoiceIndication> voicCb);
+    void setResponseFunction(
+            std::shared_ptr<::aidl::android::hardware::radio::ims::IRadioImsIndication> imsCb);
 
     std::shared_ptr<::aidl::android::hardware::radio::data::IRadioDataIndication> dataCb();
     std::shared_ptr<::aidl::android::hardware::radio::messaging::IRadioMessagingIndication>
@@ -228,6 +235,7 @@
     std::shared_ptr<::aidl::android::hardware::radio::network::IRadioNetworkIndication> networkCb();
     std::shared_ptr<::aidl::android::hardware::radio::sim::IRadioSimIndication> simCb();
     std::shared_ptr<::aidl::android::hardware::radio::voice::IRadioVoiceIndication> voiceCb();
+    std::shared_ptr<::aidl::android::hardware::radio::ims::IRadioImsIndication> imsCb();
 };
 
 }  // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioNetwork.h b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioNetwork.h
index c714190..b446103 100644
--- a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioNetwork.h
+++ b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioNetwork.h
@@ -97,8 +97,15 @@
             int32_t serial,
             const ::aidl::android::hardware::radio::network::EmergencyNetworkScanTrigger&
                     scanTrigger) override;
-    ::ndk::ScopedAStatus cancelEmergencyNetworkScan(int32_t serial) override;
+    ::ndk::ScopedAStatus cancelEmergencyNetworkScan(int32_t serial, bool resetScan) override;
     ::ndk::ScopedAStatus exitEmergencyMode(int32_t serial) override;
+    ::ndk::ScopedAStatus isN1ModeEnabled(int32_t serial) override;
+    ::ndk::ScopedAStatus setN1ModeEnabled(int32_t serial, bool enable) override;
+
+    ::ndk::ScopedAStatus setNullCipherAndIntegrityEnabled(int32_t serial, bool enabled) override;
+
+    ::ndk::ScopedAStatus setLocationPrivacySetting(int32_t serial, bool shareLocation) override;
+    ::ndk::ScopedAStatus getLocationPrivacySetting(int32_t serial) override;
 
   protected:
     std::shared_ptr<::aidl::android::hardware::radio::network::IRadioNetworkResponse> respond();
diff --git a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioResponse.h b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioResponse.h
index 1f82dd1..22451ae 100644
--- a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioResponse.h
+++ b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioResponse.h
@@ -19,6 +19,7 @@
 #include "GuaranteedCallback.h"
 
 #include <aidl/android/hardware/radio/data/IRadioDataResponse.h>
+#include <aidl/android/hardware/radio/ims/IRadioImsResponse.h>
 #include <aidl/android/hardware/radio/messaging/IRadioMessagingResponse.h>
 #include <aidl/android/hardware/radio/modem/IRadioModemResponse.h>
 #include <aidl/android/hardware/radio/network/IRadioNetworkResponse.h>
@@ -49,6 +50,9 @@
     GuaranteedCallback<::aidl::android::hardware::radio::voice::IRadioVoiceResponse,
                        ::aidl::android::hardware::radio::voice::IRadioVoiceResponseDefault>
             mVoiceCb;
+    GuaranteedCallback<::aidl::android::hardware::radio::ims::IRadioImsResponse,
+                       ::aidl::android::hardware::radio::ims::IRadioImsResponseDefault>
+            mImsCb;
 
     // IRadioResponse @ 1.0
     Return<void> getIccCardStatusResponse(const V1_0::RadioResponseInfo& info,
@@ -440,6 +444,8 @@
             std::shared_ptr<::aidl::android::hardware::radio::sim::IRadioSimResponse> simCb);
     void setResponseFunction(
             std::shared_ptr<::aidl::android::hardware::radio::voice::IRadioVoiceResponse> voiceCb);
+    void setResponseFunction(
+            std::shared_ptr<::aidl::android::hardware::radio::ims::IRadioImsResponse> imsCb);
 
     std::shared_ptr<::aidl::android::hardware::radio::data::IRadioDataResponse> dataCb();
     std::shared_ptr<::aidl::android::hardware::radio::messaging::IRadioMessagingResponse>
@@ -448,6 +454,7 @@
     std::shared_ptr<::aidl::android::hardware::radio::network::IRadioNetworkResponse> networkCb();
     std::shared_ptr<::aidl::android::hardware::radio::sim::IRadioSimResponse> simCb();
     std::shared_ptr<::aidl::android::hardware::radio::voice::IRadioVoiceResponse> voiceCb();
+    std::shared_ptr<::aidl::android::hardware::radio::ims::IRadioImsResponse> imsCb();
 };
 
 }  // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp b/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp
index ff30ac3..730b5dd 100644
--- a/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp
+++ b/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp
@@ -326,7 +326,7 @@
     return ok();
 }
 
-ScopedAStatus RadioNetwork::cancelEmergencyNetworkScan(int32_t serial) {
+ScopedAStatus RadioNetwork::cancelEmergencyNetworkScan(int32_t serial, bool) {
     LOG_CALL << serial;
     LOG(ERROR) << " cancelEmergencyNetworkScan is unsupported by HIDL HALs";
     respond()->cancelEmergencyNetworkScanResponse(notSupported(serial));
@@ -340,4 +340,38 @@
     return ok();
 }
 
+ScopedAStatus RadioNetwork::setNullCipherAndIntegrityEnabled(int32_t serial, bool) {
+    LOG_CALL << serial;
+    LOG(ERROR) << " setNullCipherAndIntegrityEnabled is unsupported by HIDL HALs";
+    respond()->setNullCipherAndIntegrityEnabledResponse(notSupported(serial));
+    return ok();
+}
+
+ScopedAStatus RadioNetwork::isN1ModeEnabled(int32_t serial) {
+    LOG_CALL << serial;
+    LOG(ERROR) << " isN1ModeEnabled is unsupported by HIDL HALs";
+    respond()->isN1ModeEnabledResponse(notSupported(serial), false);
+    return ok();
+}
+
+ScopedAStatus RadioNetwork::setN1ModeEnabled(int32_t serial, bool /*enable*/) {
+    LOG_CALL << serial;
+    LOG(ERROR) << " setN1ModeEnabled is unsupported by HIDL HALs";
+    respond()->setN1ModeEnabledResponse(notSupported(serial));
+    return ok();
+}
+
+ScopedAStatus RadioNetwork::setLocationPrivacySetting(int32_t serial, bool /*shareLocation*/) {
+    LOG_CALL << serial;
+    LOG(ERROR) << " setLocationPrivacySetting is unsupported by HIDL HALs";
+    respond()->setLocationPrivacySettingResponse(notSupported(serial));
+    return ok();
+}
+
+ScopedAStatus RadioNetwork::getLocationPrivacySetting(int32_t serial) {
+    LOG_CALL << serial;
+    LOG(ERROR) << " getLocationPrivacySetting is unsupported by HIDL HALs";
+    respond()->getLocationPrivacySettingResponse(notSupported(serial), false);
+    return ok();
+}
 }  // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/service/Android.bp b/radio/aidl/compat/service/Android.bp
index 4dbaef4..7a48da2 100644
--- a/radio/aidl/compat/service/Android.bp
+++ b/radio/aidl/compat/service/Android.bp
@@ -34,17 +34,18 @@
     ],
     shared_libs: [
         "android.hardware.radio-library.compat",
-        "android.hardware.radio.config-V1-ndk",
+        "android.hardware.radio.config-V2-ndk",
         "android.hardware.radio.config@1.0",
         "android.hardware.radio.config@1.1",
         "android.hardware.radio.config@1.2",
         "android.hardware.radio.config@1.3",
-        "android.hardware.radio.data-V1-ndk",
-        "android.hardware.radio.messaging-V1-ndk",
-        "android.hardware.radio.modem-V1-ndk",
+        "android.hardware.radio.data-V2-ndk",
+        "android.hardware.radio.ims-V1-ndk",
+        "android.hardware.radio.messaging-V2-ndk",
+        "android.hardware.radio.modem-V2-ndk",
         "android.hardware.radio.network-V2-ndk",
-        "android.hardware.radio.sim-V1-ndk",
-        "android.hardware.radio.voice-V1-ndk",
+        "android.hardware.radio.sim-V2-ndk",
+        "android.hardware.radio.voice-V2-ndk",
         "android.hardware.radio@1.0",
         "android.hardware.radio@1.1",
         "android.hardware.radio@1.2",
diff --git a/radio/aidl/vts/Android.bp b/radio/aidl/vts/Android.bp
index 0d4bb3e..5a0dbd0 100644
--- a/radio/aidl/vts/Android.bp
+++ b/radio/aidl/vts/Android.bp
@@ -41,6 +41,9 @@
         "radio_data_indication.cpp",
         "radio_data_response.cpp",
         "radio_data_test.cpp",
+        "radio_ims_indication.cpp",
+        "radio_ims_response.cpp",
+        "radio_ims_test.cpp",
         "radio_messaging_indication.cpp",
         "radio_messaging_response.cpp",
         "radio_messaging_test.cpp",
@@ -63,14 +66,15 @@
         "libvintf",
     ],
     static_libs: [
-        "android.hardware.radio-V1-ndk",
-        "android.hardware.radio.config-V1-ndk",
-        "android.hardware.radio.data-V1-ndk",
-        "android.hardware.radio.messaging-V1-ndk",
-        "android.hardware.radio.modem-V1-ndk",
+        "android.hardware.radio-V2-ndk",
+        "android.hardware.radio.config-V2-ndk",
+        "android.hardware.radio.data-V2-ndk",
+        "android.hardware.radio.ims-V1-ndk",
+        "android.hardware.radio.messaging-V2-ndk",
+        "android.hardware.radio.modem-V2-ndk",
         "android.hardware.radio.network-V2-ndk",
-        "android.hardware.radio.sim-V1-ndk",
-        "android.hardware.radio.voice-V1-ndk",
+        "android.hardware.radio.sim-V2-ndk",
+        "android.hardware.radio.voice-V2-ndk",
     ],
     test_suites: [
         "general-tests",
diff --git a/radio/aidl/vts/VtsHalRadioTargetTest.cpp b/radio/aidl/vts/VtsHalRadioTargetTest.cpp
index 1ebc6af..67a2672 100644
--- a/radio/aidl/vts/VtsHalRadioTargetTest.cpp
+++ b/radio/aidl/vts/VtsHalRadioTargetTest.cpp
@@ -18,6 +18,7 @@
 
 #include "radio_config_utils.h"
 #include "radio_data_utils.h"
+#include "radio_ims_utils.h"
 #include "radio_messaging_utils.h"
 #include "radio_modem_utils.h"
 #include "radio_network_utils.h"
@@ -65,6 +66,12 @@
         testing::ValuesIn(android::getAidlHalInstanceNames(IRadioVoice::descriptor)),
         android::PrintInstanceNameToString);
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(RadioImsTest);
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, RadioImsTest,
+        testing::ValuesIn(android::getAidlHalInstanceNames(IRadioIms::descriptor)),
+        android::PrintInstanceNameToString);
+
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
     ABinderProcess_setThreadPoolMaxThreadCount(1);
diff --git a/radio/aidl/vts/radio_aidl_hal_utils.cpp b/radio/aidl/vts/radio_aidl_hal_utils.cpp
index efc4f26..6ed8e7d 100644
--- a/radio/aidl/vts/radio_aidl_hal_utils.cpp
+++ b/radio/aidl/vts/radio_aidl_hal_utils.cpp
@@ -92,6 +92,10 @@
     return testing::checkSubstringInCommandOutput("getprop persist.radio.multisim.config", "dsds");
 }
 
+bool isDsDaEnabled() {
+    return testing::checkSubstringInCommandOutput("getprop persist.radio.multisim.config", "dsda");
+}
+
 bool isTsTsEnabled() {
     return testing::checkSubstringInCommandOutput("getprop persist.radio.multisim.config", "tsts");
 }
diff --git a/radio/aidl/vts/radio_aidl_hal_utils.h b/radio/aidl/vts/radio_aidl_hal_utils.h
index 47976b9..d515e1a 100644
--- a/radio/aidl/vts/radio_aidl_hal_utils.h
+++ b/radio/aidl/vts/radio_aidl_hal_utils.h
@@ -67,6 +67,8 @@
 
 static constexpr const char* FEATURE_TELEPHONY_CDMA = "android.hardware.telephony.cdma";
 
+static constexpr const char* FEATURE_TELEPHONY_IMS = "android.hardware.telephony.ims";
+
 #define MODEM_EMERGENCY_CALL_ESTABLISH_TIME 3
 #define MODEM_EMERGENCY_CALL_DISCONNECT_TIME 3
 #define MODEM_SET_SIM_POWER_DELAY_IN_SECONDS 2
@@ -104,6 +106,11 @@
 bool isDsDsEnabled();
 
 /*
+ * Check if device is in DSDA (Dual SIM Dual Active).
+ */
+bool isDsDaEnabled();
+
+/*
  * Check if device is in TSTS (Triple SIM Triple Standby).
  */
 bool isTsTsEnabled();
diff --git a/radio/aidl/vts/radio_config_test.cpp b/radio/aidl/vts/radio_config_test.cpp
index 258b172..c979d28 100644
--- a/radio/aidl/vts/radio_config_test.cpp
+++ b/radio/aidl/vts/radio_config_test.cpp
@@ -176,7 +176,7 @@
         slotPortMapping.physicalSlotId = -1;
         slotPortMapping.portId = -1;
         std::vector<SlotPortMapping> slotPortMappingList = {slotPortMapping};
-        if (isDsDsEnabled()) {
+        if (isDsDsEnabled() || isDsDaEnabled()) {
             slotPortMappingList.push_back(slotPortMapping);
         } else if (isTsTsEnabled()) {
             slotPortMappingList.push_back(slotPortMapping);
@@ -252,7 +252,7 @@
         }
         if (isSsSsEnabled()) {
             EXPECT_EQ(1, simCount);
-        } else if (isDsDsEnabled()) {
+        } else if (isDsDsEnabled() || isDsDaEnabled()) {
             EXPECT_EQ(2, simCount);
         } else if (isTsTsEnabled()) {
             EXPECT_EQ(3, simCount);
diff --git a/radio/aidl/vts/radio_ims_indication.cpp b/radio/aidl/vts/radio_ims_indication.cpp
new file mode 100644
index 0000000..988038b
--- /dev/null
+++ b/radio/aidl/vts/radio_ims_indication.cpp
@@ -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.
+ */
+
+#include "radio_ims_utils.h"
+
+RadioImsIndication::RadioImsIndication(RadioServiceTest& parent) : parent_ims(parent) {}
+
+ndk::ScopedAStatus RadioImsIndication::onConnectionSetupFailure(RadioIndicationType /*type*/,
+        int32_t /*token*/, const ConnectionFailureInfo& /*info*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioImsIndication::notifyAnbr(RadioIndicationType /*type*/,
+        ImsStreamType /*mediaType*/, ImsStreamDirection /*direction*/, int /*bitsPerSecond*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioImsIndication::triggerImsDeregistration(RadioIndicationType /*type*/,
+        ImsDeregistrationReason /*reason*/) {
+    return ndk::ScopedAStatus::ok();
+}
diff --git a/radio/aidl/vts/radio_ims_response.cpp b/radio/aidl/vts/radio_ims_response.cpp
new file mode 100644
index 0000000..c6d62dc
--- /dev/null
+++ b/radio/aidl/vts/radio_ims_response.cpp
@@ -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.
+ */
+
+#include "radio_ims_utils.h"
+
+RadioImsResponse::RadioImsResponse(RadioServiceTest& parent) : parent_ims(parent) {}
+
+ndk::ScopedAStatus RadioImsResponse::setSrvccCallInfoResponse(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_ims.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioImsResponse::updateImsRegistrationInfoResponse(
+        const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_ims.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioImsResponse::startImsTrafficResponse(const RadioResponseInfo& info,
+        const std::optional<ConnectionFailureInfo>& response) {
+    rspInfo = info;
+    startImsTrafficResp = response;
+    parent_ims.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioImsResponse::stopImsTrafficResponse(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_ims.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioImsResponse::triggerEpsFallbackResponse(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_ims.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioImsResponse::sendAnbrQueryResponse(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_ims.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioImsResponse::updateImsCallStatusResponse(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_ims.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
diff --git a/radio/aidl/vts/radio_ims_test.cpp b/radio/aidl/vts/radio_ims_test.cpp
new file mode 100644
index 0000000..289d3ed
--- /dev/null
+++ b/radio/aidl/vts/radio_ims_test.cpp
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/radio/config/IRadioConfig.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+
+#include "radio_ims_utils.h"
+
+#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
+
+void RadioImsTest::SetUp() {
+    std::string serviceName = GetParam();
+
+    if (!isServiceValidForDeviceConfiguration(serviceName)) {
+        ALOGI("Skipped the test due to device configuration.");
+        GTEST_SKIP();
+    }
+
+    radio_ims = IRadioIms::fromBinder(
+            ndk::SpAIBinder(AServiceManager_waitForService(GetParam().c_str())));
+    ASSERT_NE(nullptr, radio_ims.get());
+
+    radioRsp_ims = ndk::SharedRefBase::make<RadioImsResponse>(*this);
+    ASSERT_NE(nullptr, radioRsp_ims.get());
+
+    count_ = 0;
+
+    radioInd_ims = ndk::SharedRefBase::make<RadioImsIndication>(*this);
+    ASSERT_NE(nullptr, radioInd_ims.get());
+
+    radio_ims->setResponseFunctions(radioRsp_ims, radioInd_ims);
+
+    // Assert IRadioConfig exists before testing
+    radio_config = config::IRadioConfig::fromBinder(ndk::SpAIBinder(
+            AServiceManager_waitForService("android.hardware.radio.config.IRadioConfig/default")));
+    ASSERT_NE(nullptr, radio_config.get());
+}
+
+/*
+ * Test IRadioIms.setSrvccCallInfo() for the response returned.
+ */
+TEST_P(RadioImsTest, setSrvccCallInfo) {
+    if (!deviceSupportsFeature(FEATURE_TELEPHONY_IMS)) {
+        ALOGI("Skipping setSrvccCallInfo because ims is not supported in device");
+        return;
+    } else {
+        ALOGI("Running setSrvccCallInfo because ims is supported in device");
+    }
+
+    serial = GetRandomSerialNumber();
+
+    SrvccCall srvccCall;
+
+    ndk::ScopedAStatus res =
+            radio_ims->setSrvccCallInfo(serial, { srvccCall });
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_ims->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_ims->rspInfo.serial);
+
+    ALOGI("setSrvccCallInfo, rspInfo.error = %s\n",
+              toString(radioRsp_ims->rspInfo.error).c_str());
+
+    verifyError(radioRsp_ims->rspInfo.error);
+}
+
+/*
+ * Test IRadioIms.updateImsRegistrationInfo() for the response returned.
+ */
+TEST_P(RadioImsTest, updateImsRegistrationInfo) {
+    if (!deviceSupportsFeature(FEATURE_TELEPHONY_IMS)) {
+        ALOGI("Skipping updateImsRegistrationInfo because ims is not supported in device");
+        return;
+    } else {
+        ALOGI("Running updateImsRegistrationInfo because ims is supported in device");
+    }
+
+    serial = GetRandomSerialNumber();
+
+    ImsRegistration regInfo;
+    regInfo.regState = ImsRegistrationState::NOT_REGISTERED;
+    regInfo.accessNetworkType = AccessNetwork::EUTRAN;
+    regInfo.suggestedAction = SuggestedAction::NONE;
+    regInfo.capabilities = ImsRegistration::IMS_MMTEL_CAPABILITY_NONE;
+
+    ndk::ScopedAStatus res =
+            radio_ims->updateImsRegistrationInfo(serial, regInfo);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_ims->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_ims->rspInfo.serial);
+
+    ALOGI("updateImsRegistrationInfo, rspInfo.error = %s\n",
+              toString(radioRsp_ims->rspInfo.error).c_str());
+
+    verifyError(radioRsp_ims->rspInfo.error);
+}
+
+/*
+ * Test IRadioIms.startImsTraffic() for the response returned.
+ */
+TEST_P(RadioImsTest, startImsTraffic) {
+    if (!deviceSupportsFeature(FEATURE_TELEPHONY_IMS)) {
+        ALOGI("Skipping startImsTraffic because ims is not supported in device");
+        return;
+    } else {
+        ALOGI("Running startImsTraffic because ims is supported in device");
+    }
+
+    serial = GetRandomSerialNumber();
+
+    ndk::ScopedAStatus res =
+            radio_ims->startImsTraffic(serial, 1,
+            ImsTrafficType::REGISTRATION, AccessNetwork::EUTRAN, ImsCall::Direction::OUTGOING);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_ims->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_ims->rspInfo.serial);
+
+    ALOGI("startImsTraffic, rspInfo.error = %s\n",
+              toString(radioRsp_ims->rspInfo.error).c_str());
+
+    verifyError(radioRsp_ims->rspInfo.error);
+}
+
+/*
+ * Test IRadioIms.stopImsTraffic() for the response returned.
+ */
+TEST_P(RadioImsTest, stopImsTraffic) {
+    if (!deviceSupportsFeature(FEATURE_TELEPHONY_IMS)) {
+        ALOGI("Skipping stopImsTraffic because ims is not supported in device");
+        return;
+    } else {
+        ALOGI("Running stopImsTraffic because ims is supported in device");
+    }
+
+    serial = GetRandomSerialNumber();
+
+    ndk::ScopedAStatus res = radio_ims->stopImsTraffic(serial, 2);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_ims->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_ims->rspInfo.serial);
+
+    ALOGI("stopImsTraffic, rspInfo.error = %s\n",
+              toString(radioRsp_ims->rspInfo.error).c_str());
+
+    verifyError(radioRsp_ims->rspInfo.error);
+}
+
+/*
+ * Test IRadioIms.triggerEpsFallback() for the response returned.
+ */
+TEST_P(RadioImsTest, triggerEpsFallback) {
+    if (!deviceSupportsFeature(FEATURE_TELEPHONY_IMS)) {
+        ALOGI("Skipping triggerEpsFallback because ims is not supported in device");
+        return;
+    } else {
+        ALOGI("Running triggerEpsFallback because ims is supported in device");
+    }
+
+    serial = GetRandomSerialNumber();
+
+    ndk::ScopedAStatus res =
+            radio_ims->triggerEpsFallback(serial, EpsFallbackReason::NO_NETWORK_TRIGGER);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_ims->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_ims->rspInfo.serial);
+
+    ALOGI("triggerEpsFallback, rspInfo.error = %s\n",
+              toString(radioRsp_ims->rspInfo.error).c_str());
+
+    verifyError(radioRsp_ims->rspInfo.error);
+}
+
+/*
+ * Test IRadioIms.sendAnbrQuery() for the response returned.
+ */
+TEST_P(RadioImsTest, sendAnbrQuery) {
+    if (!deviceSupportsFeature(FEATURE_TELEPHONY_IMS)) {
+        ALOGI("Skipping sendAnbrQuery because ims is not supported in device");
+        return;
+    } else {
+        ALOGI("Running sendAnbrQuery because ims is supported in device");
+    }
+
+    serial = GetRandomSerialNumber();
+
+    ndk::ScopedAStatus res =
+            radio_ims->sendAnbrQuery(serial, ImsStreamType::AUDIO, ImsStreamDirection::UPLINK, 13200);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_ims->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_ims->rspInfo.serial);
+
+    ALOGI("sendAnbrQuery, rspInfo.error = %s\n",
+              toString(radioRsp_ims->rspInfo.error).c_str());
+
+    verifyError(radioRsp_ims->rspInfo.error);
+}
+
+/*
+ * Test IRadioIms.updateImsCallStatus() for the response returned.
+ */
+TEST_P(RadioImsTest, updateImsCallStatus) {
+    if (!deviceSupportsFeature(FEATURE_TELEPHONY_IMS)) {
+        ALOGI("Skipping updateImsCallStatus because ims is not supported in device");
+        return;
+    } else {
+        ALOGI("Running updateImsCallStatus because ims is supported in device");
+    }
+
+    serial = GetRandomSerialNumber();
+
+    ImsCall imsCall;
+
+    ndk::ScopedAStatus res =
+            radio_ims->updateImsCallStatus(serial, { imsCall });
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_ims->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_ims->rspInfo.serial);
+
+    ALOGI("updateImsCallStatus, rspInfo.error = %s\n",
+              toString(radioRsp_ims->rspInfo.error).c_str());
+
+    verifyError(radioRsp_ims->rspInfo.error);
+}
+
+void RadioImsTest::verifyError(RadioError resp) {
+    switch (resp) {
+        case RadioError::NONE:
+        case RadioError::RADIO_NOT_AVAILABLE:
+        case RadioError::INVALID_STATE:
+        case RadioError::NO_MEMORY:
+        case RadioError::SYSTEM_ERR:
+        case RadioError::MODEM_ERR:
+        case RadioError::INTERNAL_ERR:
+        case RadioError::INVALID_ARGUMENTS:
+        case RadioError::NO_RESOURCES:
+            SUCCEED();
+            break;
+        default:
+            FAIL();
+            break;
+    }
+}
diff --git a/radio/aidl/vts/radio_ims_utils.h b/radio/aidl/vts/radio_ims_utils.h
new file mode 100644
index 0000000..2bf80dc
--- /dev/null
+++ b/radio/aidl/vts/radio_ims_utils.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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/radio/ims/BnRadioImsIndication.h>
+#include <aidl/android/hardware/radio/ims/BnRadioImsResponse.h>
+#include <aidl/android/hardware/radio/ims/IRadioIms.h>
+
+#include "radio_aidl_hal_utils.h"
+
+using namespace aidl::android::hardware::radio::ims;
+
+class RadioImsTest;
+
+/* Callback class for radio ims response */
+class RadioImsResponse : public BnRadioImsResponse {
+  protected:
+    RadioServiceTest& parent_ims;
+
+  public:
+    RadioImsResponse(RadioServiceTest& parent_ims);
+    virtual ~RadioImsResponse() = default;
+
+    RadioResponseInfo rspInfo;
+    std::optional<ConnectionFailureInfo> startImsTrafficResp;
+
+    virtual ndk::ScopedAStatus setSrvccCallInfoResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus updateImsRegistrationInfoResponse(
+            const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus startImsTrafficResponse(
+            const RadioResponseInfo& info,
+            const std::optional<ConnectionFailureInfo>& response) override;
+
+    virtual ndk::ScopedAStatus stopImsTrafficResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus triggerEpsFallbackResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus sendAnbrQueryResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus updateImsCallStatusResponse(const RadioResponseInfo& info) override;
+};
+
+/* Callback class for radio ims indication */
+class RadioImsIndication : public BnRadioImsIndication {
+  protected:
+    RadioServiceTest& parent_ims;
+
+  public:
+    RadioImsIndication(RadioServiceTest& parent_ims);
+    virtual ~RadioImsIndication() = default;
+
+    virtual ndk::ScopedAStatus onConnectionSetupFailure(RadioIndicationType type,
+            int32_t token, const ConnectionFailureInfo& info) override;
+
+    virtual ndk::ScopedAStatus notifyAnbr(RadioIndicationType type, ImsStreamType mediaType,
+            ImsStreamDirection direction, int bitsPerSecond) override;
+
+    virtual ndk::ScopedAStatus triggerImsDeregistration(RadioIndicationType type,
+            ImsDeregistrationReason reason) override;
+};
+
+// The main test class for Radio AIDL Ims.
+class RadioImsTest : public ::testing::TestWithParam<std::string>, public RadioServiceTest {
+  protected:
+    virtual void verifyError(RadioError resp);
+
+  public:
+    virtual void SetUp() override;
+
+    /* radio ims service handle */
+    std::shared_ptr<IRadioIms> radio_ims;
+    /* radio ims response handle */
+    std::shared_ptr<RadioImsResponse> radioRsp_ims;
+    /* radio ims indication handle */
+    std::shared_ptr<RadioImsIndication> radioInd_ims;
+};
diff --git a/radio/aidl/vts/radio_network_indication.cpp b/radio/aidl/vts/radio_network_indication.cpp
index ae3bd4b..7178982 100644
--- a/radio/aidl/vts/radio_network_indication.cpp
+++ b/radio/aidl/vts/radio_network_indication.cpp
@@ -97,3 +97,8 @@
         RadioIndicationType /*type*/, const EmergencyRegResult& /*result*/) {
     return ndk::ScopedAStatus::ok();
 }
+
+ndk::ScopedAStatus RadioNetworkIndication::onNetworkInitiatedLocationResult(
+        RadioIndicationType /*type*/, LocationResponseType /*locationResponseType*/) {
+    return ndk::ScopedAStatus::ok();
+}
diff --git a/radio/aidl/vts/radio_network_response.cpp b/radio/aidl/vts/radio_network_response.cpp
index 5599c03..4f0e4f3 100644
--- a/radio/aidl/vts/radio_network_response.cpp
+++ b/radio/aidl/vts/radio_network_response.cpp
@@ -293,3 +293,37 @@
     parent_network.notify(info.serial);
     return ndk::ScopedAStatus::ok();
 }
+
+ndk::ScopedAStatus RadioNetworkResponse::setNullCipherAndIntegrityEnabledResponse(
+        const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_network.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkResponse::isN1ModeEnabledResponse(
+        const RadioResponseInfo& info, bool /*isEnabled*/) {
+    rspInfo = info;
+    parent_network.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkResponse::setN1ModeEnabledResponse(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_network.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkResponse::setLocationPrivacySettingResponse(
+        const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_network.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkResponse::getLocationPrivacySettingResponse(
+        const RadioResponseInfo& info, bool /*shareLocation*/) {
+    rspInfo = info;
+    parent_network.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
diff --git a/radio/aidl/vts/radio_network_test.cpp b/radio/aidl/vts/radio_network_test.cpp
index 25c42d3..5872eb0 100644
--- a/radio/aidl/vts/radio_network_test.cpp
+++ b/radio/aidl/vts/radio_network_test.cpp
@@ -1499,11 +1499,12 @@
     // Check for access technology specific info
     AccessTechnologySpecificInfo info = radioRsp_network->dataRegResp.accessTechnologySpecificInfo;
     RadioTechnology rat = radioRsp_network->dataRegResp.rat;
+
     // TODO: add logic for cdmaInfo
-    if (rat == RadioTechnology::LTE || rat == RadioTechnology::LTE_CA) {
+    if (rat == RadioTechnology::LTE) {
         ASSERT_EQ(info.getTag(), AccessTechnologySpecificInfo::eutranInfo);
     } else if (rat == RadioTechnology::NR) {
-        ASSERT_EQ(info.getTag(), AccessTechnologySpecificInfo::ngranNrVopsInfo);
+        ASSERT_TRUE(info.getTag() == AccessTechnologySpecificInfo::ngranNrVopsInfo);
     }
 }
 
@@ -1848,7 +1849,7 @@
 
     ASSERT_TRUE(CheckAnyOfErrors(
             radioRsp_network->rspInfo.error,
-            {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
+            {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED, RadioError::RADIO_NOT_AVAILABLE,
              RadioError::MODEM_ERR, RadioError::INVALID_ARGUMENTS}));
     LOG(DEBUG) << "setEmergencyMode finished";
 }
@@ -1871,7 +1872,7 @@
 
     ASSERT_TRUE(CheckAnyOfErrors(
             radioRsp_network->rspInfo.error,
-            {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
+            {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED, RadioError::RADIO_NOT_AVAILABLE,
              RadioError::MODEM_ERR, RadioError::INVALID_ARGUMENTS}));
     LOG(DEBUG) << "triggerEmergencyNetworkScan finished";
 }
@@ -1883,14 +1884,15 @@
     LOG(DEBUG) << "cancelEmergencyNetworkScan";
     serial = GetRandomSerialNumber();
 
-    radio_network->cancelEmergencyNetworkScan(serial);
+    radio_network->cancelEmergencyNetworkScan(serial, true);
     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::NONE, RadioError::REQUEST_NOT_SUPPORTED, RadioError::RADIO_NOT_AVAILABLE,
+             RadioError::MODEM_ERR}));
     LOG(DEBUG) << "cancelEmergencyNetworkScan finished";
 }
 
@@ -1908,6 +1910,54 @@
 
     ASSERT_TRUE(CheckAnyOfErrors(
             radioRsp_network->rspInfo.error,
-            {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR}));
+            {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED, RadioError::RADIO_NOT_AVAILABLE,
+             RadioError::MODEM_ERR}));
     LOG(DEBUG) << "exitEmergencyMode finished";
 }
+
+/*
+ * Test IRadioNetwork.setN1ModeEnabled() for the response returned.
+ */
+TEST_P(RadioNetworkTest, setN1ModeEnabled) {
+    serial = GetRandomSerialNumber();
+
+    ndk::ScopedAStatus res =
+            radio_network->setN1ModeEnabled(serial, false);
+    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);
+    if (getRadioHalCapabilities()) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
+                                     {RadioError::REQUEST_NOT_SUPPORTED}));
+    } else {
+        ASSERT_TRUE(CheckAnyOfErrors(
+                radioRsp_network->rspInfo.error,
+                {RadioError::RADIO_NOT_AVAILABLE, RadioError::INTERNAL_ERR,
+                 RadioError::INVALID_STATE, RadioError::REQUEST_NOT_SUPPORTED, RadioError::NONE}));
+    }
+}
+
+/*
+ * Test IRadioNetwork.isN1ModeEnabled() for the response returned.
+ */
+TEST_P(RadioNetworkTest, isN1ModeEnabled) {
+    serial = GetRandomSerialNumber();
+
+    ndk::ScopedAStatus res = radio_network->isN1ModeEnabled(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);
+    if (getRadioHalCapabilities()) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
+                                     {RadioError::REQUEST_NOT_SUPPORTED}));
+    } else {
+        ASSERT_TRUE(CheckAnyOfErrors(
+                radioRsp_network->rspInfo.error,
+                {RadioError::RADIO_NOT_AVAILABLE, RadioError::INTERNAL_ERR,
+                 RadioError::REQUEST_NOT_SUPPORTED, RadioError::NONE}));
+    }
+}
diff --git a/radio/aidl/vts/radio_network_utils.h b/radio/aidl/vts/radio_network_utils.h
index 8480825..92dcb1f 100644
--- a/radio/aidl/vts/radio_network_utils.h
+++ b/radio/aidl/vts/radio_network_utils.h
@@ -158,6 +158,20 @@
 
     virtual ndk::ScopedAStatus cancelEmergencyNetworkScanResponse(
             const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus setNullCipherAndIntegrityEnabledResponse(
+            const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus isN1ModeEnabledResponse(
+            const RadioResponseInfo& info, bool isEnabled) override;
+
+    virtual ndk::ScopedAStatus setN1ModeEnabledResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus setLocationPrivacySettingResponse(
+            const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus getLocationPrivacySettingResponse(const RadioResponseInfo& info,
+                                                                 bool shareLocation) override;
 };
 
 /* Callback class for radio network indication */
@@ -215,6 +229,9 @@
 
     virtual ndk::ScopedAStatus emergencyNetworkScanResult(
             RadioIndicationType type, const EmergencyRegResult& result) override;
+
+    virtual ndk::ScopedAStatus onNetworkInitiatedLocationResult(
+            RadioIndicationType type, LocationResponseType locationResponseType) override;
 };
 
 // The main test class for Radio AIDL Network.
diff --git a/secure_element/aidl/Android.bp b/secure_element/aidl/Android.bp
new file mode 100644
index 0000000..5a529a4
--- /dev/null
+++ b/secure_element/aidl/Android.bp
@@ -0,0 +1,35 @@
+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..c604b68
--- /dev/null
+++ b/secure_element/aidl/default/Android.bp
@@ -0,0 +1,15 @@
+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..16b8236
--- /dev/null
+++ b/secure_element/aidl/default/main.cpp
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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>
+
+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> kAndroidTestAid = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41,
+                                                     0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64,
+                                                     0x43, 0x54, 0x53, 0x31};
+static const std::vector<uint8_t> kLongAndroidTestAid = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41,
+                                                         0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64,
+                                                         0x43, 0x54, 0x53, 0x32};
+
+class MySecureElement : public BnSecureElement {
+  public:
+    ScopedAStatus closeChannel(int8_t channelNumber) override {
+        LOG(INFO) << __func__ << " channel number: " << channelNumber;
+        return ScopedAStatus::ok();
+    }
+    ScopedAStatus getAtr(std::vector<uint8_t>* _aidl_return) override {
+        LOG(INFO) << __func__;
+        _aidl_return->clear();
+        return ScopedAStatus::ok();
+    }
+    ScopedAStatus init(const std::shared_ptr<ISecureElementCallback>& clientCallback) override {
+        LOG(INFO) << __func__ << " callback: " << clientCallback.get();
+        if (!clientCallback) {
+            return ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
+        }
+        mCb = clientCallback;
+        mCb->onStateChange(true, "");
+        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;
+
+        // 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.
+        *_aidl_return = {0x90, 0x00, 0x00};  // DO NOT COPY
+        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;
+
+        if (aid != kAndroidTestAid && aid != kLongAndroidTestAid) {
+            return ScopedAStatus::fromServiceSpecificError(NO_SUCH_ELEMENT_ERROR);
+        }
+
+        *_aidl_return = LogicalChannelResponse{.channelNumber = 1, .selectResponse = {}};
+
+        // 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.
+        if (aid == kAndroidTestAid) {                                 // DO NOT COPY
+            size_t size = 2050;                                       // DO NOT COPY
+            _aidl_return->selectResponse.resize(size);                // DO NOT COPY
+            _aidl_return->selectResponse[size - 1] = 0x00;            // DO NOT COPY
+            _aidl_return->selectResponse[size - 2] = 0x90;            // DO NOT COPY
+        } else {                                                      // DO NOT COPY
+            _aidl_return->selectResponse = {0x00, 0x00, 0x90, 0x00};  // DO NOT COPY
+        }                                                             // DO NOT COPY
+
+        LOG(INFO) << __func__ << " sending response: "
+                  << HexString(_aidl_return->selectResponse.data(),
+                               _aidl_return->selectResponse.size());
+
+        return ScopedAStatus::ok();
+    }
+    ScopedAStatus reset() override {
+        LOG(INFO) << __func__;
+        mCb->onStateChange(false, "reset");
+        mCb->onStateChange(true, "reset");
+        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() << ")";
+
+        // 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.
+
+        std::string hex = HexString(data.data(), data.size());                    // DO NOT COPY
+        if (hex == "01a4040210a000000476416e64726f696443545331") {                // DO NOT COPY
+            *_aidl_return = {0x00, 0x6A, 0x00};                                   // DO NOT COPY
+        } else if (data == std::vector<uint8_t>{0x00, 0xF4, 0x00, 0x00, 0x00}) {  // DO NOT COPY
+            // CHECK_SELECT_P2_APDU w/ channel 1 // DO NOT COPY
+            *_aidl_return = {0x00, 0x90, 0x00};                                   // DO NOT COPY
+        } else if (data == std::vector<uint8_t>{0x01, 0xF4, 0x00, 0x00, 0x00}) {  // DO NOT COPY
+            // CHECK_SELECT_P2_APDU w/ channel 1 // DO NOT COPY
+            *_aidl_return = {0x00, 0x90, 0x00};             // DO NOT COPY
+        } else if (data.size() == 5 || data.size() == 8) {  // DO NOT COPY
+            // SEGMENTED_RESP_APDU - happens to use length 5 and 8 // DO NOT COPY
+            size_t size = (data[2] << 8 | data[3]) + 2;       // DO NOT COPY
+            _aidl_return->resize(size);                       // DO NOT COPY
+            (*_aidl_return)[size - 1] = 0x00;                 // DO NOT COPY
+            (*_aidl_return)[size - 2] = 0x90;                 // DO NOT COPY
+            if (size >= 3) (*_aidl_return)[size - 3] = 0xFF;  // DO NOT COPY
+        } else {                                              // DO NOT COPY
+            *_aidl_return = {0x90, 0x00, 0x00};               // DO NOT COPY
+        }                                                     // DO NOT COPY
+
+        return ScopedAStatus::ok();
+    }
+
+  private:
+    std::shared_ptr<ISecureElementCallback> mCb;
+};
+
+int main() {
+    ABinderProcess_setThreadPoolMaxThreadCount(0);
+
+    auto se = ndk::SharedRefBase::make<MySecureElement>();
+    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/OWNERS b/security/OWNERS
index f061cd6..fbaf854 100644
--- a/security/OWNERS
+++ b/security/OWNERS
@@ -1,7 +1,14 @@
-# Please assign all bugs related to /hardware/interfaces/security to the team alias,
-# android-hardware-security@google.com.  This will get them auto-assigned to the on-call triage
-# engineer, ensuring quickest response.
+# Bug component: 1084733
+
+# Please assign all bugs related to /hardware/interfaces/security/ to the team alias:
+#
+#    android-hardware-security@google.com
+#
+# This will get them auto-assigned to the on-call triage engineer, ensuring quickest response.
+
 drysdale@google.com
+eranm@google.com
+hasinitg@google.com
 jbires@google.com
-seleneh@google.com
 swillden@google.com
+zeuthen@google.com
diff --git a/security/keymint/README.md b/security/keymint/README.md
new file mode 100644
index 0000000..54647af
--- /dev/null
+++ b/security/keymint/README.md
@@ -0,0 +1,10 @@
+# KeyMint HAL
+
+This directory contains the HAL definition for KeyMint. KeyMint provides
+cryptographic services in a hardware-isolated environment.
+
+Note that the `IRemotelyProvisionedComponent` HAL, and it's associated types,
+used to also be defined in this directory. As of Android U, this HAL has been
+moved to a different directory (../rkp). This move is ABI compatible, as the
+interfaces have been maintained. The build is split so that the generated
+code may be built with different options.
diff --git a/security/keymint/RKP_CHANGELOG.md b/security/keymint/RKP_CHANGELOG.md
deleted file mode 100644
index dfcc938..0000000
--- a/security/keymint/RKP_CHANGELOG.md
+++ /dev/null
@@ -1,33 +0,0 @@
-# Remote Provisioning Changelog
-
-This document provides an exact description of which changes have occurred in the
-`IRemotelyProvisionedComponent` HAL interface in each Android release.
-
-## Releases
-* **Android S (12):** IRemotelyProvisionedComponent v1
-* **Android T (13):** IRemotelyProvisionedComponent v2
-* **Android U (14):** IRemotelyProvisionedComponent v3
-
-## IRemotelyProvisionedComponent 1 -> 2
-* DeviceInfo
-  * Most entries are no longer optional.
-  * `att_id_state` is now `fused`. `fused` is used to indicate if SecureBoot is enabled.
-  * `version` is now `2`.
-  * `board` has been removed.
-  * `device` has been added.
-* RpcHardwareInfo
-  * `uniqueId` String added as a field in order to differentiate IRPC instances on device.
-
-## IRemotelyProvisionedComponent 2 -> 3
-* ProtectedData has been removed.
-* DeviceInfo
-  * `cert_type` has been added, with values corresponding to `widevine` or `keymint`
-  * `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.
-  * 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.
-
diff --git a/security/keymint/RKP_README.md b/security/keymint/RKP_README.md
deleted file mode 100644
index 89a2598..0000000
--- a/security/keymint/RKP_README.md
+++ /dev/null
@@ -1,374 +0,0 @@
-# Remote Provisioning HAL
-
-## Objective
-
-Design a HAL to support over-the-air provisioning of certificates for asymmetric
-keys. The HAL must interact effectively with Keystore (and other daemons) and
-protect device privacy and security.
-
-Note that this API is designed for KeyMint, but with the intention that it
-should be usable for other HALs that require certificate provisioning.
-Throughout this document we'll refer to the Keystore and KeyMint (formerly
-called Keymaster) components, but only for concreteness and convenience; those
-labels could be replaced with the names of any system and secure area
-components, respectively, that need certificates provisioned.
-
-## Key design decisions
-
-### General approach
-
-To more securely and reliably get keys and certificates to Android devices, we
-need to create a system where no party outside of the device's secure components
-is responsible for managing private keys. The strategy we've chosen is to
-deliver certificates over the air, using an asymmetric key pair created
-on-device in the factory as a root of trust to create an authenticated, secure
-channel. In this document we refer to this device-unique asymmetric key pair as
-Device Key (DK), its public half DK\_pub, its private half DK\_priv and a Device
-Key Certificate containing DK\_pub is denoted DKC.
-
-In order for the provisioning service to use DK (or a key authenticated by DK),
-it must know whether a given DK\_pub is known and trusted. To prove trust, we
-ask device OEMs to use one of two mechanisms:
-
-1.  (Preferred, recommended) The device OEM extracts DK\_pub from each device it
-    manufactures and uploads the public keys to a backend server.
-
-1.  The device OEM signs the DK\_pub to produce DKC and stores it on the device.
-    This has the advantage that they don't need to upload a DK\_pub for every
-    device immediately, but the disadvantage that they have to manage their
-    private signing keys, which means they have to have HSMs, configure and
-    secure them correctly, etc. Some backend providers may also require that the
-    OEM passes a factory security audit, and additionally promises to upload the
-    keys eventually as well.
-
-Note that in the full elaboration of this plan, DK\_pub is not the key used to
-establish a secure channel. Instead, DK\_pub is just the first public key in a
-chain of public keys which ends with the KeyMint public key, KM\_pub. All keys
-in the chain are device-unique and are joined in a certificate chain called the
-_Boot Certificate Chain_ (BCC), because in phases 2 and 3 of the remote
-provisioning project it is a chain of certificates corresponding to boot phases.
-We speak of the BCC even for phase 1, though in phase 1 it contains only a
-single self-signed DKC. This is described in more depth in the Phases section
-below.
-
-The BCC is authenticated by DK\_pub. To authenticate DK\_pub, we may have
-additional DKCs, from the SoC vendor, the device OEM, or both. Those are not
-part of the BCC but included as optional fields in the certificate request
-structure.
-
-The format of the the DK and BCC is specified within [Open Profile for DICE]
-(https://pigweed.googlesource.com/open-dice/+/HEAD/docs/specification.md).  To
-map phrases within this document to their equivalent terminology in the DICE
-specification, read the terms as follows: the DK corresponds to the UDS-derived
-key pair, DKC corresponds to the UDS certificate, and the BCC entries between
-DK\_pub and KM\_pub correspond to a chain of CDI certificates.
-
-Note: In addition to allowing 32 byte hash values for fields in the BCC payload,
-this spec additionally constrains some of the choices allowed in open-DICE.
-Specifically, these include which entries are required and which are optional in
-the BCC payload, and which algorithms are acceptable for use.
-
-### Phases
-
-RKP will be deployed in three phases, in terms of managing the root of trust
-binding between the device and the backend. To briefly describe them:
-
-* Phase 1: In phase 1 there is only one entry in the BCC; DK_pub and KM_pub are
-  the same key and the certificate is self-signed.
-* Phase 2: This is identical to phase 1, except it leverages the hardware root
-  of trust process described by DICE. Instead of trust being rooted in the TEE,
-  it is now rooted in the ROM by key material blown into fuses which are only
-  accessible to the ROM code.
-* Phase 3: This is identical to Phase 2, except the SoC vendor also does the
-  public key extraction or certification in their facilities, along with the OEM
-  doing it in the factory. This tightens up the "supply chain" and aims to make
-  key upload management more secure.
-
-### Privacy considerations
-
-Because DK and the DKCs are unique, immutable, unspoofable hardware-bound
-identifiers for the device, we must limit access to them to the absolute minimum
-possible. We do this in two ways:
-
-1.  We require KeyMint (which knows the BCC and either knows or at least has the
-ability to use KM\_priv) to refuse to ever divulge the BCC or additional
-signatures in plaintext. Instead, KeyMint requires the caller to provide an
-_Endpoint Encryption Key_ (EEK), with which it will encrypt the data before
-returning it. When provisioning production keys, the EEK must be signed by an
-approved authority whose public key is embedded in KeyMint. When certifying test
-keys, KeyMint will accept any EEK without checking the signature, but will
-encrypt and return a test BCC, rather than the real one.  The result is that
-only an entity in possession of an Trusted EEK (TEEK) private key can discover
-the plaintext of the production BCC.
-1.  Having thus limited access to the public keys to the trusted party only, we
-need to prevent the entity from abusing this unique device identifier.  The
-approach and mechanisms for doing that are beyond the scope of this document
-(they must be addressed in the server design), but generally involve taking care
-to ensure that we do not create any links between user IDs, IP addresses or
-issued certificates and the device pubkey.
-
-Although the details of the mechanisms for preventing the entity from abusing
-the BCC are, as stated, beyond the scope of this document, there is a subtle
-design decision here made specifically to enable abuse prevention. Specifically
-the `CertificateRequest` message sent to the server is (in
-[CDDL](https://tools.ietf.org/html/rfc8610)):
-
-```
-cddl
-CertificateRequest = [
-    DeviceInfo,
-    challenge : bstr,
-    ProtectedData,
-    MacedKeysToSign
-]
-```
-
-The public keys to be attested by the server are in `MacedKeysToSign`, which is
-a COSE\_Mac0 structure, MACed with a key that is found in `ProtectedData`. The
-MAC key is signed by DK\_pub.
-
-This structure allows the backend component that has access to EEK\_priv to
-decrypt `ProtectedData`, validate that the request is from an authorized device,
-check that the request is fresh and verify and extract the MAC key. That backend
-component never sees any data related to the keys to be signed, but can provide
-the MAC key to another backend component that can verify `MacedKeysToSign` and
-proceed to generate the certificates.
-
-In this way, we can partition the provisioning server into one component that
-knows the device identity, as represented by DK\_pub, but never sees the keys to
-be certified or certificates generated, and another component that sees the keys
-to be certified and certificates generated but does not know the device
-identity.
-
-### Key and cryptographic message formatting
-
-For simplicity of generation and parsing, compactness of wire representation,
-and flexibility and standardization, we've settled on using the CBOR Object
-Signing and Encryption (COSE) standard, defined in [RFC
-8152](https://tools.ietf.org/html/rfc8152). COSE provides compact and reasonably
-simple, yet easily-extensible, wire formats for:
-
-*   Keys,
-*   MACed messages,
-*   Signed messages, and
-*   Encrypted messages
-
-COSE enables easy layering of these message formats, such as using a COSE\_Sign
-structure to contain a COSE\_Key with a public key in it. We call this a
-"certificate".
-
-Due to the complexity of the standard, we'll spell out the COSE structures
-completely in this document and in the HAL and other documentation, so that
-although implementors will need to understand CBOR and the CBOR Data Definition
-Language ([CDDL, defined in RFC 8610](https://tools.ietf.org/html/rfc8610)),
-they shouldn't need to understand COSE.
-
-Note, however, that the certificate chains returned from the provisioning server
-are standard X.509 certificates.
-
-### Algorithm choices
-
-This document uses:
-
-*   ECDSA P-256 for attestation signing keys;
-*   Remote provisioning protocol signing keys:
-  *  Ed25519 / P-256
-*   ECDH keys:
-  *  X25519 / P-256
-*   AES-GCM for all encryption;
-*   SHA-256 for all message digesting;
-*   HMAC-SHA-256 for all MACing; and
-*   HKDF-SHA-256 for all key derivation.
-
-We believe that Curve25519 offers the best tradeoff in terms of security,
-efficiency and global trustworthiness, and that it is now sufficiently
-widely-used and widely-implemented to make it a practical choice.
-
-However, since Secure Elements (SE) do not currently offer support for curve
-25519, we are allowing implementations to instead make use of EC P-256 for
-signing and ECDH. To put it simply, the device unique key pair will be a P-256
-key pair for ECDSA instead of Ed25519, and the ProtectedData COSE\_Encrypt
-message will have its payload encrypted with P-256 ECDH key exchange instead of
-X25519.
-
-The CDDL in the rest of the document will use the '/' operator to show areas
-where either curve 25519 or P-256 may be used. Since there is no easy way to
-bind choices across different CDDL groups, it is important that the implementor
-stays consistent in which type is chosen. E.g. taking ES256 as the choice for
-algorithm implies the implementor should also choose the P256 public key group
-further down in the COSE structure.
-
-### Testability
-
-It's critical that the remote provisioning implementation be testable, to
-minimize the probability that broken devices are sold to end users. To support
-testing, the remote provisioning HAL methods take a `testMode` argument. Keys
-created in test mode are tagged to indicate this. The provisioning server will
-check for the test mode tag and issue test certificates that do not chain back
-to a trusted public key. In test mode, any EEK will be accepted, enabling
-testing tools to use EEKs for which they have the private key so they can
-validate the content of certificate requests. The BCC included in the
-`CertificateRequest` must contain freshly-generated keys, not the real BCC keys.
-
-Keystore (or similar) will need to be able to handle both testMode keys and
-production keys and keep them distinct, generating test certificate requests
-when asked with a test EEK and production certificate requests when asked with a
-production EEK. Likewise, the interface used to instruct Keystore to create keys
-will need to be able to specify whether test or production keys are desired.
-
-## Design
-
-### Certificate provisioning flow
-
-TODO(jbires): Replace this with a `.png` containing a sequence diagram.  The
-provisioning flow looks something like this:
-
-Provisioner -> Keystore: Prepare N keys
-Keystore -> KeyMint: generateKeyPair
-KeyMint -> KeyMint: Generate  key pair
-KeyMint --> Keystore: key\_blob,pubkey
-Keystore -> Keystore: Store key\_blob,pubkey
-Provisioner -> Server: Get TEEK
-Server --> Provisioner: TEEK
-Provisioner -> Keystore: genCertReq(N, TEEK)
-Keystore -> KeyMint: genCertReq(pubkeys, TEEK)
-KeyMint -> KeyMint: Sign pubkeys & encrypt BCC
-KeyMint --> Keystore: signature, encrypted BCC
-Keystore -> Keystore: Construct cert\_request
-Keystore --> Provisioner: cert\_request
-Provisioner --> Server: cert\_request
-Server -> Server: Validate cert\_request
-Server -> Server: Generate certificates
-Server --> Provisioner: certificates
-Provisioner -> Keystore: certificates
-Keystore -> Keystore: Store certificates
-
-The actors in the above diagram are:
-
-*   **Server** is the backend certificate provisioning server. It has access to
-    the uploaded device public keys and is responsible for providing encryption
-    keys, decrypting and validating requests, and generating certificates in
-    response to requests.
-*   **Provisioner** is an application that is responsible for communicating with
-    the server and all of the system components that require key certificates
-    from the server. It also implements the policy that defines how many key
-    pairs each client should keep in their pool.
-*   **Keystore** is the [Android keystore
-    daemon](https://developer.android.com/training/articles/keystore) (or, more
-    generally, whatever system component manages communications with a
-    particular secure aread component).
-*   **KeyMint** is the secure area component that manages cryptographic keys and
-    performs attestations (or perhaps some other secure area component).
-
-### `BCC`
-
-The _Boot Certificate Chain_ (BCC) is the chain of certificates that contains
-DK\_pub as well as other often device-unique certificates. The BCC is
-represented as a COSE\_Key containing DK\_pub followed by an array of
-COSE\_Sign1 "certificates" containing public keys and optional additional
-information, ordered from root to leaf, with each certificate signing the next.
-The first certificate in the array is signed by DK\_pub, the last certificate
-has the KeyMint (or whatever) signing key's public key, KM\_pub. In phase 1
-there is only one entry; DK\_pub and KM\_pub are the same key and the
-certificate is self-signed.
-
-Each COSE\_Sign1 certificate is a CBOR Web Token (CWT) as described in [RFC
-8392](https://tools.ietf.org/html/rfc8392) with additional fields as described
-in the Open Profile for DICE. Of these additional fields, only the
-_subjectPublicKey_ and _keyUsage_ fields are expected to be present for the
-KM\_pub entry (that is, the last entry) in a BCC, but all fields required by the
-Open Profile for DICE are expected for other entries (each of which corresponds
-to a particular firmware component or boot stage). The CWT fields _iss_ and
-_sub_ identify the issuer and subject of the certificate and are consistent
-along the BCC entries; the issuer of a given entry matches the subject of the
-previous entry.
-
-The BCC is designed to be constructed using the Open Profile for DICE. In this
-case the DK key pair is derived from the UDS as described by that profile and
-all BCC entries before the leaf are CBOR CDI certificates chained from DK\_pub.
-The KM key pair is not part of the derived DICE chain. It is generated (not
-derived) by the KeyMint module, certified by the last key in the DICE chain, and
-added as the leaf BCC entry. The key usage field in this leaf certificate must
-indicate the key is not used to sign certificates. If a UDS certificate is
-available on the device it should appear in the certificate request as the leaf
-of a DKCertChain in AdditionalDKSignatures (see
-[CertificateRequest](#certificaterequest)).
-
-The Open Profile for DICE allows for an arbitrary configuration descriptor. For
-BCC entries, this configuration descriptor is a CBOR map with the following
-optional fields. If no fields are relevant, an empty map should be encoded.
-Additional implementation-specific fields may be added using key values not in
-the range \[-70000, -70999\] (these are reserved for future additions here).
-
-```
-| Name              | Key    | Value type | Meaning                           |
-| ----------------- | ------ | ---------- | ----------------------------------|
-| Component name    | -70002 | tstr       | Name of firmware component / boot |
-:                   :        :            : stage                             :
-| Component version | -70003 | int        | Version of firmware component /   |
-:                   :        :            : boot stage                        :
-| Resettable        | -70004 | null       | If present, key changes on factory|
-:                   :        :            : reset                             :
-```
-
-Please see
-[ProtectedData.aidl](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl)
-for a full CDDL definition of the BCC.
-
-### `CertificateRequest`
-
-The full CBOR message that will be sent to the server to request certificates
-is:
-
-```cddl
-CertificateRequest = [
-    DeviceInfo,
-    challenge : bstr,       // Provided by the server
-    ProtectedData,          // See ProtectedData.aidl
-    MacedKeysToSign         // See IRemotelyProvisionedComponent.aidl
-]
-
-DeviceInfo = [
-    VerifiedDeviceInfo,     // See DeviceInfo.aidl
-    UnverifiedDeviceInfo
-]
-
-// Unverified info is anything provided by the HLOS. Subject to change out of
-// step with the HAL.
-UnverifiedDeviceInfo = {
-    ? "fingerprint" : tstr,
-}
-
-```
-
-It will be the responsibility of Keystore and the Provisioner to construct the
-`CertificateRequest`. The HAL provides a method to generate the elements that
-need to be constructed on the secure side, which are the tag field of
-`MacedKeysToSign`, `VerifiedDeviceInfo`, and the ciphertext field of
-`ProtectedData`.
-
-### HAL
-
-The remote provisioning HAL provides a simple interface that can be implemented
-by multiple secure components that require remote provisioning. It would be
-slightly simpler to extend the KeyMint API, but that approach would only serve
-the needs of KeyMint, this is more general.
-
-NOTE the data structures defined in this HAL may look a little bloated and
-complex. This is because the COSE data structures are fully spelled-out; we
-could make it much more compact by not re-specifying the standardized elements
-and instead just referencing the standard, but it seems better to fully specify
-them. If the apparent complexity seems daunting, consider what the same would
-look like if traditional ASN.1 DER-based structures from X.509 and related
-standards were used and also fully elaborated.
-
-Please see the related HAL documentation directly in the source code at the
-following links:
-
-*   [IRemotelyProvisionedComponent
-    HAL](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl)
-*   [ProtectedData](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl)
-*   [MacedPublicKey](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/MacedPublicKey.aidl)
-*   [RpcHardwareInfo](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl)
-*   [DeviceInfo](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/DeviceInfo.aidl)
-
diff --git a/security/keymint/TEST_MAPPING b/security/keymint/TEST_MAPPING
new file mode 100644
index 0000000..4ab60b6
--- /dev/null
+++ b/security/keymint/TEST_MAPPING
@@ -0,0 +1,10 @@
+{
+  "presubmit": [
+    {
+      "name": "VtsAidlKeyMintTargetTest"
+    },
+    {
+      "name": "VtsHalRemotelyProvisionedComponentTargetTest"
+    }
+  ]
+}
diff --git a/security/keymint/aidl/Android.bp b/security/keymint/aidl/Android.bp
index 96d44a7..5a76a21 100644
--- a/security/keymint/aidl/Android.bp
+++ b/security/keymint/aidl/Android.bp
@@ -17,6 +17,7 @@
         "android.hardware.security.secureclock-V1",
     ],
     stability: "vintf",
+    frozen: false,
     backend: {
         java: {
             platform_apis: true,
@@ -52,21 +53,21 @@
 cc_defaults {
     name: "keymint_use_latest_hal_aidl_ndk_static",
     static_libs: [
-        "android.hardware.security.keymint-V2-ndk",
+        "android.hardware.security.keymint-V3-ndk",
     ],
 }
 
 cc_defaults {
     name: "keymint_use_latest_hal_aidl_ndk_shared",
     shared_libs: [
-        "android.hardware.security.keymint-V2-ndk",
+        "android.hardware.security.keymint-V3-ndk",
     ],
 }
 
 cc_defaults {
     name: "keymint_use_latest_hal_aidl_cpp_static",
     static_libs: [
-        "android.hardware.security.keymint-V2-cpp",
+        "android.hardware.security.keymint-V3-cpp",
     ],
 }
 
@@ -76,6 +77,6 @@
 rust_defaults {
     name: "keymint_use_latest_hal_aidl_rust",
     rustlibs: [
-        "android.hardware.security.keymint-V2-rust",
+        "android.hardware.security.keymint-V3-rust",
     ],
 }
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/.hash b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/.hash
index b712a52..3a6d415 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/.hash
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/.hash
@@ -1 +1,2 @@
 976674616001f714f4a4df49ee45f548de828524
+cd862ae2e49b54fc965dc1b99c218eb729c93bb1
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/.hash b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/.hash
index 69ba9a6..b4c2b78 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/.hash
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/.hash
@@ -1 +1,2 @@
 207c9f218b9b9e4e74ff5232eb16511eca9d7d2e
+70c734fbd5cac5b36676d66d8d9aa941967e1e7b
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
deleted file mode 100644
index 5ff45f8..0000000
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
+++ /dev/null
@@ -1,45 +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.
- */
-///////////////////////////////////////////////////////////////////////////////
-// 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.security.keymint;
-/* @hide */
-@RustDerive(Clone=true, Eq=true, Hash=true, Ord=true, PartialEq=true, PartialOrd=true) @VintfStability
-parcelable RpcHardwareInfo {
-  int versionNumber;
-  @utf8InCpp String rpcAuthorName;
-  int supportedEekCurve = 0;
-  @nullable @utf8InCpp String uniqueId;
-  const int CURVE_NONE = 0;
-  const int CURVE_P256 = 1;
-  const int CURVE_25519 = 2;
-}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Tag.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Tag.aidl
index e310b44..6ae2369 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Tag.aidl
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Tag.aidl
@@ -90,6 +90,7 @@
   DEVICE_UNIQUE_ATTESTATION = 1879048912,
   IDENTITY_CREDENTIAL_KEY = 1879048913,
   STORAGE_KEY = 1879048914,
+  ATTESTATION_ID_SECOND_IMEI = -1879047469,
   ASSOCIATED_DATA = -1879047192,
   NONCE = -1879047191,
   MAC_LENGTH = 805307371,
diff --git a/security/keymint/aidl/android/hardware/security/keymint/DeviceInfo.aidl b/security/keymint/aidl/android/hardware/security/keymint/DeviceInfo.aidl
deleted file mode 100644
index 6954d65..0000000
--- a/security/keymint/aidl/android/hardware/security/keymint/DeviceInfo.aidl
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * 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.security.keymint;
-
-/**
- * DeviceInfo contains information about the device that's fed in as AAD in the signature of the
- * device private key over the MAC key used for the bundle of public keys. These values are intended
- * to be checked by the server to verify that the certificate signing request crafted by
- * an IRemotelyProvisionedComponent HAL instance is coming from the expected device based
- * on values initially uploaded during device manufacture in the factory.
- * @hide
- */
-@VintfStability
-parcelable DeviceInfo {
-    /**
-     * DeviceInfo is a CBOR Map structure described by the following CDDL. DeviceInfo must be
-     * canonicalized according to the specification in RFC 7049. The ordering presented here is
-     * non-canonical to group similar entries semantically.
-     *
-     *     DeviceInfo = {
-     *         "brand" : tstr,
-     *         "manufacturer" : tstr,
-     *         "product" : tstr,
-     *         "model" : tstr,
-     *         "device" : tstr,
-     *         "vb_state" : "green" / "yellow" / "orange",    ; Taken from the AVB values
-     *         "bootloader_state" : "locked" / "unlocked",    ; Taken from the AVB values
-     *         "vbmeta_digest": bstr,                         ; Taken from the AVB values
-     *         ? "os_version" : tstr,                         ; Same as
-     *                                                        ; android.os.Build.VERSION.release
-     *                                                        ; Not optional for TEE.
-     *         "system_patch_level" : uint,                   ; YYYYMMDD
-     *         "boot_patch_level" : uint,                     ; YYYYMMDD
-     *         "vendor_patch_level" : uint,                   ; YYYYMMDD
-     *         "security_level" : "tee" / "strongbox",
-     *         "fused": 1 / 0,  ; 1 if secure boot is enforced for the processor that the IRPC
-     *                          ; implementation is contained in. 0 otherwise.
-     *         "cert_type": "widevine" / "keymint"
-     *     }
-     */
-    byte[] deviceInfo;
-}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
index 926d105..2e4fc15 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
@@ -624,9 +624,15 @@
      *
      *   o The key must have a Tag::USER_AUTH_TYPE that matches the auth type in the token.
      *
-     *   o The timestamp in the auth token plus the value of the Tag::AUTH_TIMEOUT must be less than
-     *     the current secure timestamp (which is a monotonic timer counting milliseconds since
-     *     boot.)
+     *   o If the device has a source of secure time, then the timestamp in the auth token plus the
+     *     value of the Tag::AUTH_TIMEOUT must be greater than the current secure timestamp (which
+     *     is a monotonic timer counting milliseconds since boot).
+     *
+     *   o If the device does not have a source of secure time, then the timestamp check should be
+     *     performed on the first update(), updateAad() or finish() invocation for the operation,
+     *     using the timeStampToken parameter provided on the invocation to indicate the current
+     *     timestamp. It may optionally also be performed on subsequent update() / updateAad() /
+     *     finish() invocations.
      *
      *   If any of these conditions are not met, begin() must return
      *   ErrorCode::KEY_USER_NOT_AUTHENTICATED.
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintOperation.aidl b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintOperation.aidl
index c30c183..82c8a0d 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintOperation.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintOperation.aidl
@@ -40,31 +40,7 @@
      *
      * == Authorization Enforcement ==
      *
-     * Key authorization enforcement is performed primarily in begin().  The one exception is the
-     * case where the key has:
-     *
-     * o One or more Tag::USER_SECURE_IDs, and
-     *
-     * o Does not have a Tag::AUTH_TIMEOUT
-     *
-     * In this case, the key requires an authorization per operation, and the update method must
-     * receive a non-null and valid HardwareAuthToken.  For the auth token to be valid, all of the
-     * following has to be true:
-     *
-     *   o The HMAC field must validate correctly.
-     *
-     *   o At least one of the Tag::USER_SECURE_ID values from the key must match at least one of
-     *     the secure ID values in the token.
-     *
-     *   o The key must have a Tag::USER_AUTH_TYPE that matches the auth type in the token.
-     *
-     *   o The challenge field in the auth token must contain the value returned from
-     *     IKeyMintDevice::begin(), given by the challenge field of the BeginResult structure.
-     *
-     *   If any of these conditions are not met, updateAad() must return
-     *   ErrorCode::KEY_USER_NOT_AUTHENTICATED.
-     *
-     * The caller must provide the auth token on every call to updateAad(), update() and finish().
+     * See the Authorization Enforcement section for the update() method.
      *
      *
      * For GCM encryption, the AEAD tag must be appended to the ciphertext by finish().  During
@@ -104,16 +80,22 @@
      *
      * == Authorization Enforcement ==
      *
-     * Key authorization enforcement is performed primarily in IKeyMintDevice::begin().  The one
-     * exception is the case where the key has:
+     * Key authorization enforcement is performed primarily in IKeyMintDevice::begin().  There are
+     * two exceptions to this:
      *
-     * o One or more Tag::USER_SECURE_IDs, and
+     *  1) Key with USER_SECURE_IDs but no AUTH_TIMEOUT
      *
-     * o Does not have a Tag::AUTH_TIMEOUT
+     *  2) Key with USER_SECURE_IDs and AUTH_TIMEOUT, but the device does not support secure time.
      *
-     * In this case, the key requires an authorization per operation, and the update method must
-     * receive a non-empty and valid HardwareAuthToken.  For the auth token to be valid, all of the
-     * following has to be true:
+     * The first exception is the case where the key:
+     *
+     *   o Has one or more Tag::USER_SECURE_IDs, and
+     *
+     *   o Does not have a Tag::AUTH_TIMEOUT
+     *
+     * In this case, the key requires an authorization per operation, and update() / updateAad() /
+     * finish() methods must receive a non-null and valid HardwareAuthToken.  For the auth token to
+     * be valid, all of the following has to be true:
      *
      *   o The HMAC field must validate correctly.
      *
@@ -125,10 +107,47 @@
      *   o The challenge field in the auth token must contain the challenge value contained in the
      *     BeginResult returned from IKeyMintDevice::begin().
      *
-     *   If any of these conditions are not met, update() must return
+     *   If any of these conditions are not met, the method must return
      *   ErrorCode::KEY_USER_NOT_AUTHENTICATED.
      *
-     * The caller must provide the auth token on every call to update() and finish().
+     * The caller must provide the auth token on every call to update(), updateAad() and finish().
+     *
+     *
+     * The second exception is the case where the key:
+     *
+     *   o Has one or more Tag::USER_SECURE_IDs, and
+     *
+     *   o Has a Tag::AUTH_TIMEOUT value, but the device does not have a source of secure time (as
+     *     indicated by the KeyMintHardwareInfo.timestampTokenRequired field).
+     *
+     * In this case, the key requires an per-operation authorization on the first call to update(),
+     * updateAad() or finish() for the operation, using the provided timeStampToken as a source of
+     * secure time.  For this timeStampToken to be valid, all of the following has to be true:
+     *
+     *   o The HMAC field must validate correctly.
+     *
+     *   o The challenge field in the auth token must contain the challenge value contained in the
+     *     BeginResult returned from IKeyMintDevice::begin().
+     *
+     * The resulting secure time value is then used to authenticate the HardwareAuthToken. For the
+     * auth token to be valid, all of the following has to be true:
+     *
+     *   o The HMAC field must validate correctly.
+     *
+     *   o At least one of the Tag::USER_SECURE_ID values from the key must match at least one of
+     *     the secure ID values in the token.
+     *
+     *   o The key must have a Tag::USER_AUTH_TYPE that matches the auth type in the token.
+     *
+     *   o The challenge field in the auth token must contain the challenge value contained in the
+     *     BeginResult returned from IKeyMintDevice::begin().
+     *
+     *   o The timestamp in the auth token plus the value of the Tag::AUTH_TIMEOUT must be greater
+     *     than the provided secure timestamp.
+
+     *   If any of these conditions are not met, the method must return
+     *   ErrorCode::KEY_USER_NOT_AUTHENTICATED.
+     *
      *
      * -- RSA keys --
      *
@@ -187,24 +206,7 @@
      * Key authorization enforcement is performed primarily in begin().  The exceptions are
      * authorization per operation keys and confirmation-required keys.
      *
-     * Authorization per operation keys are the case where the key has one or more
-     * Tag::USER_SECURE_IDs, and does not have a Tag::AUTH_TIMEOUT.  In this case, the key requires
-     * an authorization per operation, and the finish method must receive a non-empty and valid
-     * authToken.  For the auth token to be valid, all of the following has to be true:
-     *
-     *   o The HMAC field must validate correctly.
-     *
-     *   o At least one of the Tag::USER_SECURE_ID values from the key must match at least one of
-     *     the secure ID values in the token.
-     *
-     *   o The key must have a Tag::USER_AUTH_TYPE that matches the auth type in the token.
-     *
-     *   o The challenge field in the auth token must contain the operation challenge.
-     *
-     *   If any of these conditions are not met, update() must return
-     *   ErrorCode::KEY_USER_NOT_AUTHENTICATED.
-     *
-     * The caller must provide the auth token on every call to update() and finish().
+     * Authorization per operation keys must be authorized as described for the update() method.
      *
      * Confirmation-required keys are keys that were generated with
      * Tag::TRUSTED_CONFIRMATION_REQUIRED.  For these keys, when doing a signing operation the
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl b/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
deleted file mode 100644
index c2acbed..0000000
--- a/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
+++ /dev/null
@@ -1,464 +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.
- */
-
-package android.hardware.security.keymint;
-
-import android.hardware.security.keymint.DeviceInfo;
-import android.hardware.security.keymint.MacedPublicKey;
-import android.hardware.security.keymint.ProtectedData;
-import android.hardware.security.keymint.RpcHardwareInfo;
-
-/**
- * An IRemotelyProvisionedComponent is a secure-side component for which certificates can be
- * remotely provisioned. It provides an interface for generating asymmetric key pairs and then
- * creating a CertificateRequest that contains the generated public keys, plus other information to
- * authenticate the request origin. The CertificateRequest can be sent to a server, which can
- * validate the request and create certificates.
- *
- * This interface does not provide any way to use the generated and certified key pairs. It's
- * intended to be implemented by a HAL service that does other things with keys (e.g. Keymint).
- *
- * The root of trust for secure provisioning is something called the Device Identifier Composition
- * Engine (DICE) Chain. The DICE Chain is a chain of certificates, represented as COSE_Sign1 objects
- * containing CBOR Web Tokens (CWT) which have descriptions about the stage of firmware being
- * signed, including a COSE_Key representation of that stage's public key.
- *
- * DICE Chain Design
- * =================
- *
- * For a more exhaustive and thorough look at DICE and the implementation used within this protocol,
- * please see: https://pigweed.googlesource.com/open-dice/+/HEAD/docs/specification.md
- *
- * The DICE Chain is designed to mirror the boot stages of a device, and to prove the content and
- * integrity of each firmware image. In a proper DICE Chain, each boot stage hashes its own private
- * key material with the code and any relevant configuration parameters of the next stage to produce
- * a Compound Device Identifier, or CDI, which is used as the secret key material for the next
- * stage. From the CDI, a key pair - CDI_*_Pub and CDI_*_Priv - is derived and certified for the
- * next stage by the current stages CDI_*_Priv. The next stage is then loaded and given its CDI and
- * the DICE certificate chain generated so far in a manner that does not leak the previous stage's
- * CDI_*_Priv or CDI to later boot stages. The final, "leaf" CDI certificate contains a public key,
- * denoted CDI_Leaf_Pub, whose corresponding private key, denoted CDI_Leaf_Priv, is available for
- * use by the IRemotelyProvisionedComponent.
- *
- * The root keypair is generated by immutable code (e.g. ROM), from a Unique Device Secret (UDS).
- * The keypair that is generated from it can be referred to as the UDS_Pub/UDS_Priv keys. After the
- * device-unique secret is used, it must be made unavailable to any later boot stage.
- *
- * In this way, booting the device incrementally builds a certificate chain that (a) identifies and
- * validates the integrity of every stage and (b) contains a set of public keys that correspond to
- * private keys, one known to each stage. Any stage can compute the secrets of all later stages
- * (given the necessary input), but no stage can compute the secret of any preceding stage. Updating
- * the firmware or configuration of any stage changes the key pair of that stage, and of all
- * subsequent stages, and no attacker who compromised the previous version of the updated firmware
- * can know or predict the post-update key pairs. It is recommended and expected that the DICE Chain
- * is constructed using the Open Profile for DICE.
- *
- * When the provisioning server receives a message signed by CDI_Leaf_Priv and containing a DICE
- * chain that chains from UDS_Pub to CDI_Leaf_Pub, it can be certain that (barring vulnerabilities
- * in some boot stage), the CertificateRequest came from the device associated with UDS_Pub, running
- * the specific software identified by the certificates in the chain. If the server has some
- * mechanism for knowing the hash values of compromised stages, it can determine whether signing
- * certificates is appropriate.
- *
- * Degenerate DICE Chains
- * ======================
- *
- * While a proper DICE Chain, as described above, reflects the complete boot sequence from boot ROM
- * to the secure area image of the IRemotelyProvisionedComponent, it's also possible to use a
- * "degenerate" DICE Chain which consists only of a single, self-signed certificate containing the
- * public key of a hardware-bound key pair. This is an appopriate solution for devices which haven't
- * implemented everything necessary to produce a proper DICE Chain, but can derive a unique key pair
- * in the secure area. In this degenerate case, UDS_Pub is the same as CDI_Leaf_Pub.
- *
- * DICE Chain Privacy
- * ==================
- *
- * Because the DICE Chain constitutes an unspoofable, device-unique identifier, special care is
- * taken to prevent its availability to entities who may wish to track devices. Three precautions
- * are taken:
- *
- * 1) The DICE chain is only handled by the native Remote Key Provisioning Daemon (RKPD) service on
- *    the HLOS and is not exposed to apps running on device.
- *
- * 2) The CDI_Leaf_Priv key cannot be used to sign arbitrary data.
- *
- * 3) Backend infrastructure does not correlate UDS_Pub with the certificates signed and sent back
- *    to the device.
- *
- * Versioning
- * ==========
- * Versions 1 and 2 of the schema, as previously defined in DeviceInfo.aidl, diverge in
- * functionality from Version 3. Version 3 removes the need to have testMode in function calls and
- * deprecates the Endpoint Encryption Key (EEK) as well. Vendors implementing Version 1
- * (Android S/12) or Version 2 (Android T/13) do not need to implement generateCertificateRequestV2.
- * Vendors implementing Version 3 (Android U/14) need to implement generateCertificateRequestV2.
- *
- * For better coverage of changes from version to version, please see RKP_CHANGELOG.md in the root
- * of the keymint interface directory.
- *
- * @hide
- */
-@VintfStability
-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_TEST_KEY_IN_PRODUCTION_REQUEST = 4;
-    const int STATUS_INVALID_EEK = 5;
-    // --------- END: Versions 1 and 2 Only ------------
-    const int STATUS_REMOVED = 6;
-
-    /**
-     * @return info which contains information about the underlying IRemotelyProvisionedComponent
-     *         hardware, such as version number, component name, author name, and supported curve.
-     */
-    RpcHardwareInfo getHardwareInfo();
-
-    /**
-     * 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
-     *        are marked (see the definition of PublicKey in the MacedPublicKey structure) to
-     *        prevent them from being confused with production keys.
-     *
-     * @param out MacedPublicKey macedPublicKey contains the public key of the generated key pair,
-     *        MACed so that generateCertificateRequest can easily verify, without the
-     *        privateKeyHandle, that the contained public key is for remote certification.
-     *
-     * @return data representing a handle to the private key. The format is implementation-defined,
-     *         but note that specific services may define a required format. KeyMint does.
-     */
-    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. Calling this method should return STATUS_REMOVED on v3.
-     *
-     * For v1 and v2 implementations:
-     * generateCertificateRequest creates a certificate request to be sent to the provisioning
-     * server.
-     *
-     * @param in boolean testMode indicates whether the generated certificate request is for testing
-     *        only.
-     *
-     * @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.
-     *
-     *        If testMode is true, the keysToCertify array must contain only keys flagged as test
-     *        keys. Otherwise, the method must return STATUS_PRODUCTION_KEY_IN_TEST_REQUEST.
-     *
-     *        If testMode is false, the keysToCertify array must not contain any keys flagged as
-     *        test keys. Otherwise, the method must return STATUS_TEST_KEY_IN_PRODUCTION_REQUEST.
-     *
-     * @param in endpointEncryptionKey contains an X22519 public key which will be used to encrypt
-     *        the BCC. For flexibility, this is represented as a certificate chain, represented as a
-     *        CBOR array of COSE_Sign1 objects, ordered from root to leaf. The leaf contains the
-     *        X25519 encryption key, each other element is an Ed25519 key signing the next in the
-     *        chain. The root is self-signed. An implementor may also choose to use P256 as an
-     *        alternative curve for signing and encryption instead of Curve 25519.
-     *
-     *            EekChain = [ + SignedSignatureKey, SignedEek ]
-     *
-     *            SignedSignatureKey = [              ; COSE_Sign1
-     *                protected: bstr .cbor {
-     *                    1 : AlgorithmEdDSA / AlgorithmES256,  ; Algorithm
-     *                },
-     *                unprotected: {},
-     *                payload: bstr .cbor SignatureKeyEd25519 /
-     *                         bstr .cbor SignatureKeyP256,
-     *                signature: bstr PureEd25519(.cbor SignatureKeySignatureInput) /
-     *                           bstr ECDSA(.cbor SignatureKeySignatureInput)
-     *            ]
-     *
-     *            SignatureKeyEd25519 = {             ; COSE_Key
-     *                 1 : 1,                         ; Key type : Octet Key Pair
-     *                 3 : AlgorithmEdDSA,            ; Algorithm
-     *                 -1 : 6,                        ; Curve : Ed25519
-     *                 -2 : bstr                      ; Ed25519 public key
-     *            }
-     *
-     *            SignatureKeyP256 = {
-     *                 1 : 2,                         ; Key type : EC2
-     *                 3 : AlgorithmES256,            ; Algorithm
-     *                 -1 : 1,                        ; Curve: P256
-     *                 -2 : bstr,                     ; X coordinate
-     *                 -3 : bstr                      ; Y coordinate
-     *            }
-     *
-     *            SignatureKeySignatureInput = [
-     *                context: "Signature1",
-     *                body_protected: bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 },
-     *                external_aad: bstr .size 0,
-     *                payload: bstr .cbor SignatureKeyEd25519 /
-     *                         bstr .cbor SignatureKeyP256
-     *            ]
-     *
-     *            ; COSE_Sign1
-     *            SignedEek = [
-     *                protected: bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 },
-     *                unprotected: {},
-     *                payload: bstr .cbor EekX25519 / .cbor EekP256,
-     *                signature: bstr PureEd25519(.cbor EekSignatureInput) /
-     *                           bstr ECDSA(.cbor EekSignatureInput)
-     *            ]
-     *
-     *            EekX25519 = {            ; COSE_Key
-     *                1 : 1,               ; Key type : Octet Key Pair
-     *                2 : bstr             ; KID : EEK ID
-     *                3 : -25,             ; Algorithm : ECDH-ES + HKDF-256
-     *                -1 : 4,              ; Curve : X25519
-     *                -2 : bstr            ; Ed25519 public key
-     *            }
-     *
-     *            EekP256 = {              ; COSE_Key
-     *                1 : 2,               ; Key type : EC2
-     *                2 : bstr             ; KID : EEK ID
-     *                3 : -25,             ; Algorithm : ECDH-ES + HKDF-256
-     *                -1 : 1,              ; Curve : P256
-     *                -2 : bstr            ; Sender X coordinate
-     *                -3 : bstr            ; Sender Y coordinate
-     *            }
-     *
-     *            EekSignatureInput = [
-     *                context: "Signature1",
-     *                body_protected: bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 },
-     *                external_aad: bstr .size 0,
-     *                payload: bstr .cbor EekX25519 / .cbor EekP256
-     *            ]
-     *
-     *            AlgorithmES256 = -7
-     *            AlgorithmEdDSA = -8
-     *
-     *        If the contents of endpointEncryptionKey do not match the SignedEek structure above,
-     *        the method must return STATUS_INVALID_EEK.
-     *
-     *        If testMode is true, the method must ignore the length and content of the signatures
-     *        in the chain, which implies that it must not attempt to validate the signature.
-     *
-     *        If testMode is false, the method must validate the chain signatures, and must verify
-     *        that the public key in the root certifictate is in its pre-configured set of
-     *        authorized EEK root keys. If the public key is not in the database, or if signature
-     *        verification fails, the method must return STATUS_INVALID_EEK.
-     *
-     * @param in challenge contains a byte string from the provisioning server that must be signed
-     *        by the secure area. See the description of the 'signature' output parameter for
-     *        details.
-     *
-     * @param out DeviceInfo contains the VerifiedDeviceInfo portion of the DeviceInfo array in
-     *        CertificateRequest. The structure is described within the DeviceInfo.aidl file.
-     *
-     * @param out ProtectedData contains the encrypted BCC and the ephemeral MAC key used to
-     *        authenticate the keysToSign (see keysToSignMac output argument).
-     *
-     * @return The of KeysToSign in the CertificateRequest structure. Specifically, it contains:
-     *
-     *            HMAC-256(EK_mac, .cbor KeysToMacStructure)
-     *
-     *        Where EK_mac is an ephemeral MAC key, found in ProtectedData (see below).  The MACed
-     *        data is the "tag" field of a COSE_Mac0 structure like:
-     *
-     *            MacedKeys = [                            ; COSE_Mac0
-     *                protected : bstr .cbor {
-     *                    1 : 5,                           ; Algorithm : HMAC-256
-     *                },
-     *                unprotected : {},
-     *                ; Payload is PublicKeys from keysToSign argument, in provided order.
-     *                payload: bstr .cbor [ * PublicKey ],
-     *                tag: bstr
-     *            ]
-     *
-     *            KeysToMacStructure = [
-     *                context : "MAC0",
-     *                protected : bstr .cbor { 1 : 5 },    ; Algorithm : HMAC-256
-     *                external_aad : bstr .size 0,
-     *                ; Payload is PublicKeys from keysToSign argument, in provided order.
-     *                payload : bstr .cbor [ * PublicKey ]
-     *            ]
-     */
-    byte[] generateCertificateRequest(in boolean testMode, in MacedPublicKey[] keysToSign,
-            in byte[] endpointEncryptionCertChain, in byte[] challenge, out DeviceInfo deviceInfo,
-            out ProtectedData protectedData);
-
-    /**
-     * generateCertificateRequestV2 creates a certificate signing request to be sent to the
-     * provisioning server.
-     *
-     * @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.
-     *
-     * @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
-     *        use different semantic data for this field, but the supported sizes must be between 32
-     *        and 64 bytes, inclusive.
-     *
-     * @return the following CBOR Certificate Signing Request (Csr) serialized into a byte array:
-     *
-     * Csr = [
-     *    version: 3,              ; The CDDL Schema version.
-     *    UdsCerts,
-     *    DiceCertChain,
-     *    SignedData
-     * ]
-     *
-     * ; COSE_Sign1 (untagged)
-     * SignedData = [
-     *     protected: bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 },
-     *     unprotected: {},
-     *     payload: bstr .cbor SignedDataPayload,
-     *     signature: bstr            ; PureEd25519(CDI_Leaf_Priv, bstr .cbor SignedDataSigStruct) /
-     *                                ; ECDSA(CDI_Leaf_Priv, bstr .cbor SignedDataSigStruct)
-     * ]
-     *
-     * ; Sig_structure for SignedData
-     * SignedDataSigStruct = [
-     *     context: "Signature1",
-     *     protected: bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 },
-     *     external_aad: bstr .size 0,
-     *     payload: bstr .cbor SignedDataPayload
-     * ]
-     *
-     * SignedDataPayload = [               ; CBOR Array defining the payload for SignedData
-     *     DeviceInfo,                     ; Defined in DeviceInfo.aidl
-     *     challenge: bstr .size (32..64), ; Provided by the method parameters
-     *     KeysToSign,                     ; Provided by the method parameters
-     * ]
-     *
-     * KeysToSign = [ * PublicKey ]   ; Please see MacedPublicKey.aidl for the PublicKey definition.
-     *
-     * ; UdsCerts allows the platform to provide additional certifications for the UDS_Pub. For
-     * ; example, this could be provided by the hardware vendor, who certifies all of their chips.
-     * ; The SignerName is a free-form string describing who generated the signature. The root
-     * ; certificate will need to be communicated to the verifier out of band, along with the
-     * ; SignerName that is expected for the given root certificate.
-     * UdsCerts = {
-     *     * SignerName => UdsCertChain
-     * }
-     *
-     * ; SignerName is a string identifier that indicates both the signing authority as
-     * ; well as the format of the UdsCertChain
-     * SignerName = tstr
-     *
-     * UdsCertChain = [
-     *     2* X509Certificate       ; Root -> ... -> Leaf. "Root" is the vendor self-signed
-     *                              ; cert, "Leaf" contains UDS_Public. There may also be
-     *                              ; intermediate certificates between Root and Leaf.
-     * ]
-     *
-     * ; A bstr containing a DER-encoded X.509 certificate (RSA, NIST P-curve, or edDSA)
-     * X509Certificate = bstr
-     *
-     * ; The DICE Chain contains measurements about the device firmware.
-     * ; The first entry in the DICE Chain is the UDS_Pub, encoded as a COSE_key. All entries
-     * ; after the first describe a link in the boot chain (e.g. bootloaders: BL1, BL2, ... BLN)
-     * ; Note that there is no DiceChainEntry for UDS_pub, only a "bare" COSE_key.
-     * DiceCertChain = [
-     *     PubKeyEd25519 / PubKeyECDSA256,  ; UDS_Pub
-     *     + DiceChainEntry,                ; First CDI_Certificate -> Last CDI_Certificate
-     *                                      ; Last certificate corresponds to KeyMint's DICE key.
-     * ]
-     *
-     * ; This is the signed payload for each entry in the DCC. Note that the "Configuration
-     * ; Input Values" described by the Open Profile are not used here. Instead, the Dcc
-     * ; defines its own configuration values for the Configuration Descriptor field. See
-     * ; the Open Profile for DICE for more details on the fields. SHA256 and SHA512 are acceptable
-     * ; hash algorithms. The digest bstr values in the payload are the digest values without any
-     * ; padding. Note that for SHA256, this implies the digest bstr is 32 bytes. This is an
-     * ; intentional, minor deviation from Open Profile for DICE, which specifies all digests are
-     * ; 64 bytes.
-     * DiceChainEntryPayload = {                    ; CWT [RFC8392]
-     *     1 : tstr,                                ; Issuer
-     *     2 : tstr,                                ; Subject
-     *     -4670552 : bstr .cbor PubKeyEd25519 /
-     *                bstr .cbor PubKeyECDSA256,    ; Subject Public Key
-     *     -4670553 : bstr                          ; Key Usage
-     *
-     *     ; NOTE: All of the following fields may be omitted for a "Degenerate DICE Chain", as
-     *     ;       described above.
-     *     -4670545 : bstr,                         ; Code Hash
-     *     ? -4670546 : bstr,                       ; Code Descriptor
-     *     ? -4670547 : bstr,                       ; Configuration Hash
-     *     -4670548 : bstr .cbor {                  ; Configuration Descriptor
-     *         ? -70002 : tstr,                         ; Component name
-     *         ? -70003 : int,                          ; Firmware version
-     *         ? -70004 : null,                         ; Resettable
-     *     },
-     *     -4670549 : bstr,                         ; Authority Hash
-     *     ? -4670550 : bstr,                       ; Authority Descriptor
-     *     -4670551 : bstr,                         ; Mode
-     * }
-     *
-     * ; Each entry in the Dcc is a DiceChainEntryPayload signed by the key from the previous entry
-     * ; in the Dcc array.
-     * DiceChainEntry = [                            ; COSE_Sign1 (untagged)
-     *     protected : bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 },
-     *     unprotected: {},
-     *     payload: bstr .cbor DiceChainEntryPayload,
-     *     signature: bstr ; PureEd25519(SigningKey, bstr .cbor DiceChainEntryInput) /
-     *                     ; ECDSA(SigningKey, bstr .cbor DiceChainEntryInput)
-     *                     ; See RFC 8032 for details of how to encode the signature value
-     *                     ; for Ed25519.
-     * ]
-     *
-     * DiceChainEntryInput = [
-     *     context: "Signature1",
-     *     protected: bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 },
-     *     external_aad: bstr .size 0,
-     *     payload: bstr .cbor DiceChainEntryPayload
-     * ]
-     *
-     * ; 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
-     *     -1 : 6,                      ; Curve : Ed25519
-     *     -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
-     *     -1 : 1,                      ; Curve: P256
-     *     -2 : bstr,                   ; X coordinate
-     *     -3 : bstr                    ; Y coordinate
-     * }
-     *
-     * AlgorithmES256 = -7
-     * AlgorithmEdDSA = -8
-     */
-    byte[] generateCertificateRequestV2(in MacedPublicKey[] keysToSign, in byte[] challenge);
-}
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/android/hardware/security/keymint/RpcHardwareInfo.aidl b/security/keymint/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl
deleted file mode 100644
index 0cb33ce..0000000
--- a/security/keymint/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl
+++ /dev/null
@@ -1,77 +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.
- */
-
-package android.hardware.security.keymint;
-
-/**
- * RpcHardwareInfo is the hardware information returned by calling RemotelyProvisionedComponent
- * getHardwareInfo()
- * @hide
- */
-@VintfStability
-@RustDerive(Clone=true, Eq=true, PartialEq=true, Ord=true, PartialOrd=true, Hash=true)
-parcelable RpcHardwareInfo {
-    const int CURVE_NONE = 0;
-    const int CURVE_P256 = 1;
-    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.
-     */
-    int versionNumber;
-
-    /**
-     * rpcAuthorName is the name of the author of the IRemotelyProvisionedComponent implementation
-     * (organization name, not individual). This name is implementation defined, so it can be used
-     * to distinguish between different implementations from the same author.
-     */
-    @utf8InCpp String rpcAuthorName;
-
-    /**
-     * 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
-     * if it's available. These values are defined as constants above.
-     *
-     * CURVE_NONE is made the default to help ensure that an implementor doesn't accidentally forget
-     * to provide the correct information here, as the VTS tests will check to make certain that
-     * a passing implementation does not provide CURVE_NONE.
-     */
-    int supportedEekCurve = CURVE_NONE;
-
-    /**
-     * uniqueId is an opaque identifier for this IRemotelyProvisionedComponent implementation. The
-     * client should NOT interpret the content of the identifier in any way. The client can only
-     * compare identifiers to determine if two IRemotelyProvisionedComponents share the same
-     * implementation. Each IRemotelyProvisionedComponent implementation must have a distinct
-     * identifier from all other implementations, and it must be consistent across all devices.
-     * It's critical that this identifier not be usable to uniquely identify a specific device.
-     *
-     * This identifier must be consistent across reboots, as it is used to store and track
-     * provisioned keys in a persistent, on-device database.
-     *
-     * uniqueId may not be empty, and must not be any longer than 32 characters.
-     *
-     * A recommended construction for this value is "[Vendor] [Component Name] [Major Version]",
-     * e.g. "Google Trusty KeyMint 1".
-     *
-     * This field was added in API version 2.
-     *
-     */
-    @nullable @utf8InCpp String uniqueId;
-}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
index 47361d5..837fc81 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
@@ -726,9 +726,10 @@
     ATTESTATION_ID_SERIAL = TagType.BYTES | 713,
 
     /**
-     * Tag::ATTESTATION_ID_IMEI provides the IMEIs for all radios on the device to attested key
+     * Tag::ATTESTATION_ID_IMEI provides the IMEI one of the radios on the device to attested key
      * generation/import operations.  This field must be set only when requesting attestation of the
-     * device's identifiers.
+     * device's identifiers. If the device has more than one IMEI, a second IMEI may be included
+     * by using the Tag::ATTESTATION_ID_SECOND_IMEI tag.
      *
      * If the device does not support ID attestation (or destroyAttestationIds() was previously
      * called and the device can no longer attest its IDs), any key attestation request that
@@ -883,6 +884,20 @@
     STORAGE_KEY = TagType.BOOL | 722,
 
     /**
+     * Tag::ATTESTATION_ID_SECOND_IMEI provides an additional IMEI of one of the radios on the
+     * device to attested key generation/import operations. This field MUST be accompanied by
+     * the Tag::ATTESTATION_ID_IMEI tag. It would only be used to convery a second IMEI the device
+     * has, after Tag::ATTESTATION_ID_SECOND_IMEI has been used to convery the first IMEI.
+     *
+     * If the device does not support ID attestation (or destroyAttestationIds() was previously
+     * called and the device can no longer attest its IDs), any key attestation request that
+     * includes this tag must fail with ErrorCode::CANNOT_ATTEST_IDS.
+     *
+     * Must never appear in KeyCharacteristics.
+     */
+    ATTESTATION_ID_SECOND_IMEI = TagType.BYTES | 723,
+
+    /**
      * OBSOLETE: Do not use.
      *
      * This tag value is included for historical reasons -- in Keymaster it was used to hold
diff --git a/security/keymint/aidl/default/Android.bp b/security/keymint/aidl/default/Android.bp
index 1a17fd4..17520b7 100644
--- a/security/keymint/aidl/default/Android.bp
+++ b/security/keymint/aidl/default/Android.bp
@@ -25,6 +25,7 @@
         "keymint_use_latest_hal_aidl_ndk_shared",
     ],
     shared_libs: [
+        "android.hardware.security.rkp-V3-ndk",
         "android.hardware.security.sharedsecret-V1-ndk",
         "android.hardware.security.secureclock-V1-ndk",
         "libbase",
diff --git a/security/keymint/aidl/vts/functional/Android.bp b/security/keymint/aidl/vts/functional/Android.bp
index ef5b0bd..13143bf 100644
--- a/security/keymint/aidl/vts/functional/Android.bp
+++ b/security/keymint/aidl/vts/functional/Android.bp
@@ -35,6 +35,7 @@
         "libcrypto",
     ],
     static_libs: [
+        "android.hardware.security.rkp-V3-ndk",
         "android.hardware.security.secureclock-V1-ndk",
         "libcppbor_external",
         "libcppcose_rkp",
diff --git a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
index ca517ac..ea4ba18 100644
--- a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
+++ b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
@@ -798,7 +798,7 @@
     add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_BRAND, "ro.product.brand");
     add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_DEVICE, "ro.product.device");
     add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_PRODUCT, "ro.product.name");
-    add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serial");
+    add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serialno");
     add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MANUFACTURER,
                       "ro.product.manufacturer");
     add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MODEL, "ro.product.model");
@@ -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 1dc5df3..26dc3f5 100644
--- a/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp
+++ b/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp
@@ -252,7 +252,7 @@
     add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_BRAND, "ro.product.brand");
     add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_DEVICE, "ro.product.device");
     add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_PRODUCT, "ro.product.name");
-    add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serial");
+    add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serialno");
     add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MANUFACTURER,
                       "ro.product.manufacturer");
     add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MODEL, "ro.product.model");
@@ -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/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index 5473062..43ad30a 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -1919,30 +1919,32 @@
 
     // The following check assumes that canonical CBOR encoding is used for the COSE_Key.
     if (testMode) {
-        EXPECT_THAT(cppbor::prettyPrint(parsedPayload.get()),
-                    MatchesRegex("{\n"
-                                 "  1 : 2,\n"   // kty: EC2
-                                 "  3 : -7,\n"  // alg: ES256
-                                 "  -1 : 1,\n"  // EC id: P256
-                                 // The regex {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}} matches a
-                                 // sequence of 32 hexadecimal bytes, enclosed in braces and
-                                 // separated by commas. In this case, some Ed25519 public key.
-                                 "  -2 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n"  // pub_x: data
-                                 "  -3 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n"  // pub_y: data
-                                 "  -70000 : null,\n"                              // test marker
-                                 "}"));
+        EXPECT_THAT(
+                cppbor::prettyPrint(parsedPayload.get()),
+                MatchesRegex("\\{\n"
+                             "  1 : 2,\n"   // kty: EC2
+                             "  3 : -7,\n"  // alg: ES256
+                             "  -1 : 1,\n"  // EC id: P256
+                             // The regex {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}} matches a
+                             // sequence of 32 hexadecimal bytes, enclosed in braces and
+                             // separated by commas. In this case, some Ed25519 public key.
+                             "  -2 : \\{(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}\\},\n"  // pub_x: data
+                             "  -3 : \\{(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}\\},\n"  // pub_y: data
+                             "  -70000 : null,\n"                                  // test marker
+                             "\\}"));
     } else {
-        EXPECT_THAT(cppbor::prettyPrint(parsedPayload.get()),
-                    MatchesRegex("{\n"
-                                 "  1 : 2,\n"   // kty: EC2
-                                 "  3 : -7,\n"  // alg: ES256
-                                 "  -1 : 1,\n"  // EC id: P256
-                                 // The regex {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}} matches a
-                                 // sequence of 32 hexadecimal bytes, enclosed in braces and
-                                 // separated by commas. In this case, some Ed25519 public key.
-                                 "  -2 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n"  // pub_x: data
-                                 "  -3 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n"  // pub_y: data
-                                 "}"));
+        EXPECT_THAT(
+                cppbor::prettyPrint(parsedPayload.get()),
+                MatchesRegex("\\{\n"
+                             "  1 : 2,\n"   // kty: EC2
+                             "  3 : -7,\n"  // alg: ES256
+                             "  -1 : 1,\n"  // EC id: P256
+                             // The regex {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}} matches a
+                             // sequence of 32 hexadecimal bytes, enclosed in braces and
+                             // separated by commas. In this case, some Ed25519 public key.
+                             "  -2 : \\{(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}\\},\n"  // pub_x: data
+                             "  -3 : \\{(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}\\},\n"  // pub_y: data
+                             "\\}"));
     }
 }
 
@@ -2029,6 +2031,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..5b09ca5 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
@@ -395,6 +395,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 4f5d821..b8d0c20 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -1027,6 +1027,15 @@
  * without providing NOT_BEFORE and NOT_AFTER parameters.
  */
 TEST_P(NewKeyGenerationTest, RsaWithMissingValidity) {
+    if (AidlVersion() < 2) {
+        /*
+         * The KeyMint V1 spec required that CERTIFICATE_NOT_{BEFORE,AFTER} be
+         * specified for asymmetric key generation. However, this was not
+         * checked at the time so we can only be strict about checking this for
+         * implementations of KeyMint version 2 and above.
+         */
+        GTEST_SKIP() << "Validity strict since KeyMint v2";
+    }
     // Per RFC 5280 4.1.2.5, an undefined expiration (not-after) field should be set to
     // GeneralizedTime 999912312359559, which is 253402300799000 ms from Jan 1, 1970.
     constexpr uint64_t kUndefinedExpirationDateTime = 253402300799000;
@@ -1680,6 +1689,15 @@
  * without providing NOT_BEFORE and NOT_AFTER parameters.
  */
 TEST_P(NewKeyGenerationTest, EcdsaWithMissingValidity) {
+    if (AidlVersion() < 2) {
+        /*
+         * The KeyMint V1 spec required that CERTIFICATE_NOT_{BEFORE,AFTER} be
+         * specified for asymmetric key generation. However, this was not
+         * checked at the time so we can only be strict about checking this for
+         * implementations of KeyMint version 2 and above.
+         */
+        GTEST_SKIP() << "Validity strict since KeyMint v2";
+    }
     // Per RFC 5280 4.1.2.5, an undefined expiration (not-after) field should be set to
     // GeneralizedTime 999912312359559, which is 253402300799000 ms from Jan 1, 1970.
     constexpr uint64_t kUndefinedExpirationDateTime = 253402300799000;
@@ -1990,7 +2008,7 @@
     add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_BRAND, "ro.product.brand");
     add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_DEVICE, "ro.product.device");
     add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_PRODUCT, "ro.product.name");
-    add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serial");
+    add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serialno");
     add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_MANUFACTURER, "ro.product.manufacturer");
     add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_MODEL, "ro.product.model");
 
@@ -4946,15 +4964,15 @@
 TEST_P(ImportWrappedKeyTest, WrongDigest) {
     auto wrapping_key_desc = AuthorizationSetBuilder()
                                      .RsaEncryptionKey(2048, 65537)
-                                     .Digest(Digest::SHA_2_512)
                                      .Padding(PaddingMode::RSA_OAEP)
+                                     .Digest(Digest::SHA_2_256)
                                      .Authorization(TAG_PURPOSE, KeyPurpose::WRAP_KEY)
                                      .SetDefaultValidity();
 
     ASSERT_EQ(ErrorCode::INCOMPATIBLE_DIGEST,
               ImportWrappedKey(wrapped_key, wrapping_key, wrapping_key_desc, zero_masking_key,
                                AuthorizationSetBuilder()
-                                       .Digest(Digest::SHA_2_256)
+                                       .Digest(Digest::SHA_2_512)
                                        .Padding(PaddingMode::RSA_OAEP)));
 }
 
diff --git a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
index e1f65fe..97fe08a 100644
--- a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
+++ b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
@@ -46,6 +46,7 @@
 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);                             \
@@ -180,6 +181,15 @@
         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;
@@ -200,9 +210,7 @@
         RpcHardwareInfo hwInfo;
         ASSERT_TRUE(rpc->getHardwareInfo(&hwInfo).isOk());
 
-        int32_t version;
-        ASSERT_TRUE(rpc->getInterfaceVersion(&version).isOk());
-        if (version >= VERSION_WITH_UNIQUE_ID_SUPPORT) {
+        if (hwInfo.versionNumber >= VERSION_WITH_UNIQUE_ID_SUPPORT) {
             ASSERT_TRUE(hwInfo.uniqueId);
             auto [_, wasInserted] = uniqueIds.insert(*hwInfo.uniqueId);
             EXPECT_TRUE(wasInserted);
@@ -232,10 +240,7 @@
  * Verify that the unique id is within the length limits as described in RpcHardwareInfo.aidl.
  */
 TEST_P(GetHardwareInfoTests, uniqueId) {
-    int32_t version;
-    ASSERT_TRUE(provisionable_->getInterfaceVersion(&version).isOk());
-
-    if (version < VERSION_WITH_UNIQUE_ID_SUPPORT) {
+    if (rpcHardwareInfo.versionNumber < VERSION_WITH_UNIQUE_ID_SUPPORT) {
         return;
     }
 
@@ -246,6 +251,19 @@
     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);
@@ -261,7 +279,7 @@
     auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &macedPubKey, &privateKeyBlob);
     ASSERT_TRUE(status.isOk());
     vector<uint8_t> coseKeyData;
-    check_maced_pubkey(macedPubKey, testMode, &coseKeyData);
+    checkMacedPubkeyVersioned(macedPubKey, testMode, &coseKeyData);
 }
 
 /**
@@ -284,7 +302,7 @@
     auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &macedPubKey, &privateKeyBlob);
     ASSERT_TRUE(status.isOk());
     vector<uint8_t> coseKeyData;
-    check_maced_pubkey(macedPubKey, testMode, &coseKeyData);
+    checkMacedPubkeyVersioned(macedPubKey, testMode, &coseKeyData);
 
     AttestationKey attestKey;
     attestKey.keyBlob = std::move(privateKeyBlob);
@@ -339,13 +357,13 @@
     bool testMode = true;
     auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &macedPubKey, &privateKeyBlob);
     ASSERT_TRUE(status.isOk());
-
-    check_maced_pubkey(macedPubKey, testMode, nullptr);
+    checkMacedPubkeyVersioned(macedPubKey, testMode, nullptr);
 }
 
-class CertificateRequestTest : public VtsRemotelyProvisionedComponentTests {
+class CertificateRequestTestBase : public VtsRemotelyProvisionedComponentTests {
   protected:
-    CertificateRequestTest() : eekId_(string_to_bytevec("eekid")), challenge_(randomBytes(64)) {}
+    CertificateRequestTestBase()
+        : eekId_(string_to_bytevec("eekid")), challenge_(randomBytes(64)) {}
 
     void generateTestEekChain(size_t eekLength) {
         auto chain = generateEekChain(rpcHardwareInfo.supportedEekCurve, eekLength, eekId_);
@@ -364,7 +382,7 @@
             ASSERT_TRUE(status.isOk()) << status.getMessage();
 
             vector<uint8_t> payload_value;
-            check_maced_pubkey(key, testMode, &payload_value);
+            checkMacedPubkeyVersioned(key, testMode, &payload_value);
             cborKeysToSign_.add(cppbor::EncodedItem(payload_value));
         }
     }
@@ -377,6 +395,18 @@
     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.
@@ -643,4 +673,128 @@
 
 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/keymint/aidl/vts/performance/KeyMintBenchmark.cpp b/security/keymint/aidl/vts/performance/KeyMintBenchmark.cpp
index 5bbae4c..0c61c25 100644
--- a/security/keymint/aidl/vts/performance/KeyMintBenchmark.cpp
+++ b/security/keymint/aidl/vts/performance/KeyMintBenchmark.cpp
@@ -16,16 +16,21 @@
 
 #define LOG_TAG "keymint_benchmark"
 
+#include <iostream>
+
 #include <base/command_line.h>
 #include <benchmark/benchmark.h>
-#include <iostream>
 
 #include <aidl/Vintf.h>
 #include <aidl/android/hardware/security/keymint/ErrorCode.h>
 #include <aidl/android/hardware/security/keymint/IKeyMintDevice.h>
 #include <android/binder_manager.h>
 #include <binder/IServiceManager.h>
+
 #include <keymint_support/authorization_set.h>
+#include <keymint_support/openssl_utils.h>
+#include <openssl/curve25519.h>
+#include <openssl/x509.h>
 
 #define SMALL_MESSAGE_SIZE 64
 #define MEDIUM_MESSAGE_SIZE 1024
@@ -119,6 +124,22 @@
         return {};
     }
 
+    string getAlgorithmString(string transform) {
+        if (transform.find("AES") != string::npos) {
+            return "AES";
+        } else if (transform.find("Hmac") != string::npos) {
+            return "HMAC";
+        } else if (transform.find("DESede") != string::npos) {
+            return "TRIPLE_DES";
+        } else if (transform.find("RSA") != string::npos) {
+            return "RSA";
+        } else if (transform.find("EC") != string::npos) {
+            return "EC";
+        }
+        std::cerr << "Can't find algorithm for " << transform << std::endl;
+        return "";
+    }
+
     Digest getDigest(string transform) {
         if (transform.find("MD5") != string::npos) {
             return Digest::MD5;
@@ -135,29 +156,56 @@
             return Digest::SHA_2_512;
         } else if (transform.find("RSA") != string::npos &&
                    transform.find("OAEP") != string::npos) {
-            return Digest::SHA1;
+            if (securityLevel_ == SecurityLevel::STRONGBOX) {
+                return Digest::SHA_2_256;
+            } else {
+                return Digest::SHA1;
+            }
         } else if (transform.find("Hmac") != string::npos) {
             return Digest::SHA_2_256;
         }
         return Digest::NONE;
     }
 
+    string getDigestString(string transform) {
+        if (transform.find("MD5") != string::npos) {
+            return "MD5";
+        } else if (transform.find("SHA1") != string::npos ||
+                   transform.find("SHA-1") != string::npos) {
+            return "SHA1";
+        } else if (transform.find("SHA224") != string::npos) {
+            return "SHA_2_224";
+        } else if (transform.find("SHA256") != string::npos) {
+            return "SHA_2_256";
+        } else if (transform.find("SHA384") != string::npos) {
+            return "SHA_2_384";
+        } else if (transform.find("SHA512") != string::npos) {
+            return "SHA_2_512";
+        } else if (transform.find("RSA") != string::npos &&
+                   transform.find("OAEP") != string::npos) {
+            if (securityLevel_ == SecurityLevel::STRONGBOX) {
+                return "SHA_2_256";
+            } else {
+                return "SHA1";
+            }
+        } else if (transform.find("Hmac") != string::npos) {
+            return "SHA_2_256";
+        }
+        return "";
+    }
+
     optional<EcCurve> getCurveFromLength(int keySize) {
         switch (keySize) {
             case 224:
                 return EcCurve::P_224;
-                break;
             case 256:
                 return EcCurve::P_256;
-                break;
             case 384:
                 return EcCurve::P_384;
-                break;
             case 521:
                 return EcCurve::P_521;
-                break;
             default:
-                return {};
+                return std::nullopt;
         }
     }
 
@@ -261,6 +309,109 @@
         return GetReturnErrorCode(result);
     }
 
+    /* Copied the function LocalRsaEncryptMessage from
+     * hardware/interfaces/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp in VTS.
+     * Replaced asserts with the condition check and return false in case of failure condition.
+     * Require return value to skip the benchmark test case from further execution in case
+     * LocalRsaEncryptMessage fails.
+     */
+    optional<string> LocalRsaEncryptMessage(const string& message, const AuthorizationSet& params) {
+        // Retrieve the public key from the leaf certificate.
+        if (cert_chain_.empty()) {
+            std::cerr << "Local RSA encrypt Error: invalid cert_chain_" << std::endl;
+            return "Failure";
+        }
+        X509_Ptr key_cert(parse_cert_blob(cert_chain_[0].encodedCertificate));
+        EVP_PKEY_Ptr pub_key(X509_get_pubkey(key_cert.get()));
+        RSA_Ptr rsa(EVP_PKEY_get1_RSA(const_cast<EVP_PKEY*>(pub_key.get())));
+
+        // Retrieve relevant tags.
+        Digest digest = Digest::NONE;
+        Digest mgf_digest = Digest::SHA1;
+        PaddingMode padding = PaddingMode::NONE;
+
+        auto digest_tag = params.GetTagValue(TAG_DIGEST);
+        if (digest_tag.has_value()) digest = digest_tag.value();
+        auto pad_tag = params.GetTagValue(TAG_PADDING);
+        if (pad_tag.has_value()) padding = pad_tag.value();
+        auto mgf_tag = params.GetTagValue(TAG_RSA_OAEP_MGF_DIGEST);
+        if (mgf_tag.has_value()) mgf_digest = mgf_tag.value();
+
+        const EVP_MD* md = openssl_digest(digest);
+        const EVP_MD* mgf_md = openssl_digest(mgf_digest);
+
+        // Set up encryption context.
+        EVP_PKEY_CTX_Ptr ctx(EVP_PKEY_CTX_new(pub_key.get(), /* engine= */ nullptr));
+        if (EVP_PKEY_encrypt_init(ctx.get()) <= 0) {
+            std::cerr << "Local RSA encrypt Error: Encryption init failed" << std::endl;
+            return "Failure";
+        }
+
+        int rc = -1;
+        switch (padding) {
+            case PaddingMode::NONE:
+                rc = EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_NO_PADDING);
+                break;
+            case PaddingMode::RSA_PKCS1_1_5_ENCRYPT:
+                rc = EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_PKCS1_PADDING);
+                break;
+            case PaddingMode::RSA_OAEP:
+                rc = EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_PKCS1_OAEP_PADDING);
+                break;
+            default:
+                break;
+        }
+        if (rc <= 0) {
+            std::cerr << "Local RSA encrypt Error: Set padding failed" << std::endl;
+            return "Failure";
+        }
+        if (padding == PaddingMode::RSA_OAEP) {
+            if (!EVP_PKEY_CTX_set_rsa_oaep_md(ctx.get(), md)) {
+                std::cerr << "Local RSA encrypt Error: Set digest failed: " << ERR_peek_last_error()
+                          << std::endl;
+                return "Failure";
+            }
+            if (!EVP_PKEY_CTX_set_rsa_mgf1_md(ctx.get(), mgf_md)) {
+                std::cerr << "Local RSA encrypt Error: Set digest failed: " << ERR_peek_last_error()
+                          << std::endl;
+                return "Failure";
+            }
+        }
+
+        // Determine output size.
+        size_t outlen;
+        if (EVP_PKEY_encrypt(ctx.get(), nullptr /* out */, &outlen,
+                             reinterpret_cast<const uint8_t*>(message.data()),
+                             message.size()) <= 0) {
+            std::cerr << "Local RSA encrypt Error: Determine output size failed: "
+                      << ERR_peek_last_error() << std::endl;
+            return "Failure";
+        }
+
+        // Left-zero-pad the input if necessary.
+        const uint8_t* to_encrypt = reinterpret_cast<const uint8_t*>(message.data());
+        size_t to_encrypt_len = message.size();
+
+        std::unique_ptr<string> zero_padded_message;
+        if (padding == PaddingMode::NONE && to_encrypt_len < outlen) {
+            zero_padded_message.reset(new string(outlen, '\0'));
+            memcpy(zero_padded_message->data() + (outlen - to_encrypt_len), message.data(),
+                   message.size());
+            to_encrypt = reinterpret_cast<const uint8_t*>(zero_padded_message->data());
+            to_encrypt_len = outlen;
+        }
+
+        // Do the encryption.
+        string output(outlen, '\0');
+        if (EVP_PKEY_encrypt(ctx.get(), reinterpret_cast<uint8_t*>(output.data()), &outlen,
+                             to_encrypt, to_encrypt_len) <= 0) {
+            std::cerr << "Local RSA encrypt Error: Encryption failed: " << ERR_peek_last_error()
+                      << std::endl;
+            return "Failure";
+        }
+        return output;
+    }
+
     SecurityLevel securityLevel_;
     string name_;
 
@@ -268,12 +419,13 @@
     ErrorCode GenerateKey(const AuthorizationSet& key_desc,
                           const optional<AttestationKey>& attest_key = std::nullopt) {
         key_blob_.clear();
+        cert_chain_.clear();
         KeyCreationResult creationResult;
         Status result = keymint_->generateKey(key_desc.vector_data(), attest_key, &creationResult);
         if (result.isOk()) {
             key_blob_ = std::move(creationResult.keyBlob);
+            cert_chain_ = std::move(creationResult.certificateChain);
             creationResult.keyCharacteristics.clear();
-            creationResult.certificateChain.clear();
         }
         return GetReturnErrorCode(result);
     }
@@ -338,6 +490,11 @@
         return ErrorCode::UNKNOWN_ERROR;
     }
 
+    X509_Ptr parse_cert_blob(const vector<uint8_t>& blob) {
+        const uint8_t* p = blob.data();
+        return X509_Ptr(d2i_X509(nullptr /* allocate new */, &p, blob.size()));
+    }
+
     std::shared_ptr<IKeyMintOperation> op_;
     vector<Certificate> cert_chain_;
     vector<uint8_t> key_blob_;
@@ -390,6 +547,10 @@
     BENCHMARK_KM_MSG(encrypt, transform, keySize, msgSize) \
     BENCHMARK_KM_MSG(decrypt, transform, keySize, msgSize)
 
+// Skip public key operations as they are not supported in KeyMint.
+#define BENCHMARK_KM_ASYM_CIPHER(transform, keySize, msgSize)   \
+    BENCHMARK_KM_MSG(decrypt, transform, keySize, msgSize)
+
 #define BENCHMARK_KM_CIPHER_ALL_MSGS(transform, keySize) \
     BENCHMARK_KM_ALL_MSGS(encrypt, transform, keySize)   \
     BENCHMARK_KM_ALL_MSGS(decrypt, transform, keySize)
@@ -397,12 +558,43 @@
 #define BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, keySize) \
     BENCHMARK_KM_ALL_MSGS(sign, transform, keySize)         \
     BENCHMARK_KM_ALL_MSGS(verify, transform, keySize)
-// clang-format on
+
+// Skip public key operations as they are not supported in KeyMint.
+#define BENCHMARK_KM_ASYM_SIGNATURE_ALL_MSGS(transform, keySize) \
+    BENCHMARK_KM_ALL_MSGS(sign, transform, keySize) \
+    // clang-format on
 
 /*
  * ============= KeyGen TESTS ==================
  */
+
+static bool isValidSBKeySize(string transform, int keySize) {
+    std::optional<Algorithm> algorithm = keymintTest->getAlgorithm(transform);
+    switch (algorithm.value()) {
+        case Algorithm::AES:
+            return (keySize == 128 || keySize == 256);
+        case Algorithm::HMAC:
+            return (keySize % 8 == 0 && keySize >= 64 && keySize <= 512);
+        case Algorithm::TRIPLE_DES:
+            return (keySize == 168);
+        case Algorithm::RSA:
+            return (keySize == 2048);
+        case Algorithm::EC:
+            return (keySize == 256);
+    }
+    return false;
+}
+
 static void keygen(benchmark::State& state, string transform, int keySize) {
+    // Skip the test for unsupported key size in StrongBox
+    if (keymintTest->securityLevel_ == SecurityLevel::STRONGBOX &&
+        !isValidSBKeySize(transform, keySize)) {
+        state.SkipWithError(("Skipped for STRONGBOX: Keysize: " + std::to_string(keySize) +
+                             " is not supported in StrongBox for algorithm: " +
+                             keymintTest->getAlgorithmString(transform))
+                                    .c_str());
+        return;
+    }
     addDefaultLabel(state);
     for (auto _ : state) {
         if (!keymintTest->GenerateKey(transform, keySize)) {
@@ -438,8 +630,24 @@
 /*
  * ============= SIGNATURE TESTS ==================
  */
-
 static void sign(benchmark::State& state, string transform, int keySize, int msgSize) {
+    // Skip the test for unsupported key size or unsupported digest in StrongBox
+    if (keymintTest->securityLevel_ == SecurityLevel::STRONGBOX) {
+        if (!isValidSBKeySize(transform, keySize)) {
+            state.SkipWithError(("Skipped for STRONGBOX: Keysize: " + std::to_string(keySize) +
+                                 " is not supported in StrongBox for algorithm: " +
+                                 keymintTest->getAlgorithmString(transform))
+                                        .c_str());
+            return;
+        }
+        if (keymintTest->getDigest(transform) != Digest::SHA_2_256) {
+            state.SkipWithError(
+                    ("Skipped for STRONGBOX: Digest: " + keymintTest->getDigestString(transform) +
+                     " is not supported in StrongBox")
+                            .c_str());
+            return;
+        }
+    }
     addDefaultLabel(state);
     if (!keymintTest->GenerateKey(transform, keySize, true)) {
         state.SkipWithError(
@@ -469,6 +677,23 @@
 }
 
 static void verify(benchmark::State& state, string transform, int keySize, int msgSize) {
+    // Skip the test for unsupported key size or unsupported digest in StrongBox
+    if (keymintTest->securityLevel_ == SecurityLevel::STRONGBOX) {
+        if (!isValidSBKeySize(transform, keySize)) {
+            state.SkipWithError(("Skipped for STRONGBOX: Keysize: " + std::to_string(keySize) +
+                                 " is not supported in StrongBox for algorithm: " +
+                                 keymintTest->getAlgorithmString(transform))
+                                        .c_str());
+            return;
+        }
+        if (keymintTest->getDigest(transform) != Digest::SHA_2_256) {
+            state.SkipWithError(
+                    ("Skipped for STRONGBOX: Digest: " + keymintTest->getDigestString(transform) +
+                     " is not supported in StrongBox")
+                            .c_str());
+            return;
+        }
+    }
     addDefaultLabel(state);
     if (!keymintTest->GenerateKey(transform, keySize, true)) {
         state.SkipWithError(
@@ -525,10 +750,10 @@
 BENCHMARK_KM_SIGNATURE_ALL_HMAC_KEYS(HmacSHA512)
 
 #define BENCHMARK_KM_SIGNATURE_ALL_ECDSA_KEYS(transform) \
-    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 224)      \
-    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 256)      \
-    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 384)      \
-    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 521)
+    BENCHMARK_KM_ASYM_SIGNATURE_ALL_MSGS(transform, 224)      \
+    BENCHMARK_KM_ASYM_SIGNATURE_ALL_MSGS(transform, 256)      \
+    BENCHMARK_KM_ASYM_SIGNATURE_ALL_MSGS(transform, 384)      \
+    BENCHMARK_KM_ASYM_SIGNATURE_ALL_MSGS(transform, 521)
 
 BENCHMARK_KM_SIGNATURE_ALL_ECDSA_KEYS(NONEwithECDSA);
 BENCHMARK_KM_SIGNATURE_ALL_ECDSA_KEYS(SHA1withECDSA);
@@ -538,13 +763,14 @@
 BENCHMARK_KM_SIGNATURE_ALL_ECDSA_KEYS(SHA512withECDSA);
 
 #define BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(transform) \
-    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 2048)   \
-    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 3072)   \
-    BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 4096)
+    BENCHMARK_KM_ASYM_SIGNATURE_ALL_MSGS(transform, 2048)   \
+    BENCHMARK_KM_ASYM_SIGNATURE_ALL_MSGS(transform, 3072)   \
+    BENCHMARK_KM_ASYM_SIGNATURE_ALL_MSGS(transform, 4096)
 
 BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(MD5withRSA);
 BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA1withRSA);
 BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA224withRSA);
+BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA256withRSA);
 BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA384withRSA);
 BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA512withRSA);
 
@@ -553,6 +779,7 @@
 BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA224withRSA/PSS);
 BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA384withRSA/PSS);
 BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA512withRSA/PSS);
+
 // clang-format on
 
 /*
@@ -560,6 +787,15 @@
  */
 
 static void encrypt(benchmark::State& state, string transform, int keySize, int msgSize) {
+    // Skip the test for unsupported key size in StrongBox
+    if (keymintTest->securityLevel_ == SecurityLevel::STRONGBOX &&
+        (!isValidSBKeySize(transform, keySize))) {
+        state.SkipWithError(("Skipped for STRONGBOX: Keysize: " + std::to_string(keySize) +
+                             " is not supported in StrongBox for algorithm: " +
+                             keymintTest->getAlgorithmString(transform))
+                                    .c_str());
+        return;
+    }
     addDefaultLabel(state);
     if (!keymintTest->GenerateKey(transform, keySize)) {
         state.SkipWithError(
@@ -589,6 +825,15 @@
 }
 
 static void decrypt(benchmark::State& state, string transform, int keySize, int msgSize) {
+    // Skip the test for unsupported key size in StrongBox
+    if (keymintTest->securityLevel_ == SecurityLevel::STRONGBOX &&
+        (!isValidSBKeySize(transform, keySize))) {
+        state.SkipWithError(("Skipped for STRONGBOX: Keysize: " + std::to_string(keySize) +
+                             " is not supported in StrongBox for algorithm: " +
+                             keymintTest->getAlgorithmString(transform))
+                                    .c_str());
+        return;
+    }
     addDefaultLabel(state);
     if (!keymintTest->GenerateKey(transform, keySize)) {
         state.SkipWithError(
@@ -598,23 +843,34 @@
     AuthorizationSet out_params;
     AuthorizationSet in_params = keymintTest->getOperationParams(transform);
     string message = keymintTest->GenerateMessage(msgSize);
-    auto error = keymintTest->Begin(KeyPurpose::ENCRYPT, in_params, &out_params);
-    if (error != ErrorCode::OK) {
-        state.SkipWithError(
-                ("Encryption begin error, " + std::to_string(keymintTest->getError())).c_str());
-        return;
+    optional<string> encryptedMessage;
+
+    if (keymintTest->getAlgorithm(transform).value() == Algorithm::RSA) {
+        // Public key operation not supported, doing local Encryption
+        encryptedMessage = keymintTest->LocalRsaEncryptMessage(message, in_params);
+        if ((keySize / 8) != (*encryptedMessage).size()) {
+            state.SkipWithError("Local Encryption falied");
+            return;
+        }
+    } else {
+        auto error = keymintTest->Begin(KeyPurpose::ENCRYPT, in_params, &out_params);
+        if (error != ErrorCode::OK) {
+            state.SkipWithError(
+                    ("Encryption begin error, " + std::to_string(keymintTest->getError())).c_str());
+            return;
+        }
+        encryptedMessage = keymintTest->Process(message);
+        if (!encryptedMessage) {
+            state.SkipWithError(
+                    ("Encryption error, " + std::to_string(keymintTest->getError())).c_str());
+            return;
+        }
+        in_params.push_back(out_params);
+        out_params.Clear();
     }
-    auto encryptedMessage = keymintTest->Process(message);
-    if (!encryptedMessage) {
-        state.SkipWithError(
-                ("Encryption error, " + std::to_string(keymintTest->getError())).c_str());
-        return;
-    }
-    in_params.push_back(out_params);
-    out_params.Clear();
     for (auto _ : state) {
         state.PauseTiming();
-        error = keymintTest->Begin(KeyPurpose::DECRYPT, in_params, &out_params);
+        auto error = keymintTest->Begin(KeyPurpose::DECRYPT, in_params, &out_params);
         if (error != ErrorCode::OK) {
             state.SkipWithError(
                     ("Decryption begin error, " + std::to_string(keymintTest->getError())).c_str());
@@ -649,9 +905,9 @@
 BENCHMARK_KM_CIPHER_ALL_MSGS(DESede/ECB/PKCS7Padding, 168);
 
 #define BENCHMARK_KM_CIPHER_ALL_RSA_KEYS(transform, msgSize) \
-    BENCHMARK_KM_CIPHER(transform, 2048, msgSize)            \
-    BENCHMARK_KM_CIPHER(transform, 3072, msgSize)            \
-    BENCHMARK_KM_CIPHER(transform, 4096, msgSize)
+    BENCHMARK_KM_ASYM_CIPHER(transform, 2048, msgSize)            \
+    BENCHMARK_KM_ASYM_CIPHER(transform, 3072, msgSize)            \
+    BENCHMARK_KM_ASYM_CIPHER(transform, 4096, msgSize)
 
 BENCHMARK_KM_CIPHER_ALL_RSA_KEYS(RSA/ECB/NoPadding, SMALL_MESSAGE_SIZE);
 BENCHMARK_KM_CIPHER_ALL_RSA_KEYS(RSA/ECB/PKCS1Padding, SMALL_MESSAGE_SIZE);
diff --git a/security/keymint/support/Android.bp b/security/keymint/support/Android.bp
index 3f48320..efd6fc7 100644
--- a/security/keymint/support/Android.bp
+++ b/security/keymint/support/Android.bp
@@ -63,6 +63,9 @@
     defaults: [
         "keymint_use_latest_hal_aidl_ndk_shared",
     ],
+    static_libs: [
+        "android.hardware.security.rkp-V3-ndk",
+    ],
     shared_libs: [
         "libbase",
         "libbinder_ndk",
@@ -78,6 +81,7 @@
     name: "libkeymint_remote_prov_support_test",
     srcs: ["remote_prov_utils_test.cpp"],
     static_libs: [
+        "android.hardware.security.rkp-V3-ndk",
         "libgmock",
         "libgtest_main",
     ],
diff --git a/security/keymint/support/include/remote_prov/remote_prov_utils.h b/security/keymint/support/include/remote_prov/remote_prov_utils.h
index 9ea20ac..1b94c62 100644
--- a/security/keymint/support/include/remote_prov/remote_prov_utils.h
+++ b/security/keymint/support/include/remote_prov/remote_prov_utils.h
@@ -177,4 +177,18 @@
         const EekChain& eekChain, const std::vector<uint8_t>& eekId, int32_t supportedEekCurve,
         IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge);
 
+/**
+ * Verify the CSR as if the device is still early in the factory process and may not
+ * have all device identifiers provisioned yet.
+ */
+ErrMsgOr<std::unique_ptr<cppbor::Array>> verifyFactoryCsr(
+        const cppbor::Array& keysToSign, const std::vector<uint8_t>& csr,
+        IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge);
+/**
+ * Verify the CSR as if the device is a final production sample.
+ */
+ErrMsgOr<std::unique_ptr<cppbor::Array>> verifyProductionCsr(
+        const cppbor::Array& keysToSign, const std::vector<uint8_t>& csr,
+        IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge);
+
 }  // namespace aidl::android::hardware::security::keymint::remote_prov
diff --git a/security/keymint/support/remote_prov_utils.cpp b/security/keymint/support/remote_prov_utils.cpp
index 0651496..7e164fd 100644
--- a/security/keymint/support/remote_prov_utils.cpp
+++ b/security/keymint/support/remote_prov_utils.cpp
@@ -32,6 +32,7 @@
 #include <openssl/base64.h>
 #include <openssl/evp.h>
 #include <openssl/rand.h>
+#include <openssl/x509.h>
 #include <remote_prov/remote_prov_utils.h>
 
 namespace aidl::android::hardware::security::keymint::remote_prov {
@@ -45,6 +46,8 @@
 using EC_KEY_Ptr = bssl::UniquePtr<EC_KEY>;
 using EVP_PKEY_Ptr = bssl::UniquePtr<EVP_PKEY>;
 using EVP_PKEY_CTX_Ptr = bssl::UniquePtr<EVP_PKEY_CTX>;
+using X509_Ptr = bssl::UniquePtr<X509>;
+using CRYPTO_BUFFER_Ptr = bssl::UniquePtr<CRYPTO_BUFFER>;
 
 ErrMsgOr<bytevec> ecKeyGetPrivateKey(const EC_KEY* ecKey) {
     // Extract private key.
@@ -518,31 +521,35 @@
         return errMsg;
     }
 
-    std::unique_ptr<cppbor::Map> parsed(parsedVerifiedDeviceInfo->asMap());
+    std::unique_ptr<cppbor::Map> parsed(parsedVerifiedDeviceInfo.release()->asMap());
     if (!parsed) {
         return "DeviceInfo must be a CBOR map.";
     }
-    parsedVerifiedDeviceInfo.release();
 
     if (parsed->clone()->asMap()->canonicalize().encode() != deviceInfoBytes) {
         return "DeviceInfo ordering is non-canonical.";
     }
-    const std::unique_ptr<cppbor::Item>& version = parsed->get("version");
-    if (!version) {
-        return "Device info is missing version";
-    }
-    if (!version->asUint()) {
-        return "version must be an unsigned integer";
-    }
+
     RpcHardwareInfo info;
     provisionable->getHardwareInfo(&info);
-    if (version->asUint()->value() != info.versionNumber) {
-        return "DeviceInfo version (" + std::to_string(version->asUint()->value()) +
-               ") does not match the remotely provisioned component version (" +
-               std::to_string(info.versionNumber) + ").";
+    if (info.versionNumber < 3) {
+        const std::unique_ptr<cppbor::Item>& version = parsed->get("version");
+        if (!version) {
+            return "Device info is missing version";
+        }
+        if (!version->asUint()) {
+            return "version must be an unsigned integer";
+        }
+        if (version->asUint()->value() != info.versionNumber) {
+            return "DeviceInfo version (" + std::to_string(version->asUint()->value()) +
+                   ") does not match the remotely provisioned component version (" +
+                   std::to_string(info.versionNumber) + ").";
+        }
     }
+
     std::string error;
-    switch (version->asUint()->value()) {
+    switch (info.versionNumber) {
+        case 3:
         case 2:
             for (const auto& entry : kAttestationIdEntrySet) {
                 error += checkMapEntry(isFactory && !entry.alwaysValidate, *parsed, cppbor::TSTR,
@@ -579,7 +586,7 @@
                                    kValidAttIdStates);
             break;
         default:
-            return "Unrecognized version: " + std::to_string(version->asUint()->value());
+            return "Unrecognized version: " + std::to_string(info.versionNumber);
     }
 
     if (!error.empty()) {
@@ -734,4 +741,296 @@
                                /*isFactory=*/false);
 }
 
-}  // namespace aidl::android::hardware::security::keymint::remote_prov
\ No newline at end of file
+ErrMsgOr<X509_Ptr> parseX509Cert(const std::vector<uint8_t>& cert) {
+    CRYPTO_BUFFER_Ptr certBuf(CRYPTO_BUFFER_new(cert.data(), cert.size(), nullptr));
+    if (!certBuf.get()) {
+        return "Failed to create crypto buffer.";
+    }
+    X509_Ptr result(X509_parse_from_buffer(certBuf.get()));
+    if (!result.get()) {
+        return "Failed to parse certificate.";
+    }
+    return result;
+}
+
+std::string getX509IssuerName(const X509_Ptr& cert) {
+    char* name = X509_NAME_oneline(X509_get_issuer_name(cert.get()), nullptr, 0);
+    std::string result(name);
+    OPENSSL_free(name);
+    return result;
+}
+
+std::string getX509SubjectName(const X509_Ptr& cert) {
+    char* name = X509_NAME_oneline(X509_get_subject_name(cert.get()), nullptr, 0);
+    std::string result(name);
+    OPENSSL_free(name);
+    return result;
+}
+
+// Validates the certificate chain and returns the leaf public key.
+ErrMsgOr<bytevec> validateCertChain(const cppbor::Array& chain) {
+    uint8_t rawPubKey[64];
+    size_t rawPubKeySize = sizeof(rawPubKey);
+    for (size_t i = 0; i < chain.size(); ++i) {
+        // Root must be self-signed.
+        size_t signingCertIndex = (i > 1) ? i - 1 : i;
+        auto& keyCertItem = chain[i];
+        auto& signingCertItem = chain[signingCertIndex];
+        if (!keyCertItem || !keyCertItem->asBstr()) {
+            return "Key certificate must be a Bstr.";
+        }
+        if (!signingCertItem || !signingCertItem->asBstr()) {
+            return "Signing certificate must be a Bstr.";
+        }
+
+        auto keyCert = parseX509Cert(keyCertItem->asBstr()->value());
+        if (!keyCert) {
+            return keyCert.message();
+        }
+        auto signingCert = parseX509Cert(keyCertItem->asBstr()->value());
+        if (!signingCert) {
+            return signingCert.message();
+        }
+
+        EVP_PKEY_Ptr pubKey(X509_get_pubkey(keyCert->get()));
+        if (!pubKey.get()) {
+            return "Failed to get public key.";
+        }
+        EVP_PKEY_Ptr signingPubKey(X509_get_pubkey(signingCert->get()));
+        if (!signingPubKey.get()) {
+            return "Failed to get signing public key.";
+        }
+
+        if (!X509_verify(keyCert->get(), signingPubKey.get())) {
+            return "Verification of certificate " + std::to_string(i) +
+                   " faile. OpenSSL error string: " + ERR_error_string(ERR_get_error(), NULL);
+        }
+
+        auto certIssuer = getX509IssuerName(*keyCert);
+        auto signerSubj = getX509SubjectName(*signingCert);
+        if (certIssuer != signerSubj) {
+            return "Certificate " + std::to_string(i) + " has wrong issuer. Signer subject is " +
+                   signerSubj + " Issuer subject is " + certIssuer;
+        }
+
+        rawPubKeySize = sizeof(rawPubKey);
+        if (!EVP_PKEY_get_raw_public_key(pubKey.get(), rawPubKey, &rawPubKeySize)) {
+            return "Failed to get raw public key.";
+        }
+    }
+
+    return bytevec(rawPubKey, rawPubKey + rawPubKeySize);
+}
+
+std::string validateUdsCerts(const cppbor::Map& udsCerts, const bytevec& udsPub) {
+    for (const auto& [signerName, udsCertChain] : udsCerts) {
+        if (!signerName || !signerName->asTstr()) {
+            return "Signer Name must be a Tstr.";
+        }
+        if (!udsCertChain || !udsCertChain->asArray()) {
+            return "UDS certificate chain must be an Array.";
+        }
+        if (udsCertChain->asArray()->size() < 2) {
+            return "UDS certificate chain must have at least two entries: root and leaf.";
+        }
+
+        auto leafPubKey = validateCertChain(*udsCertChain->asArray());
+        if (!leafPubKey) {
+            return leafPubKey.message();
+        }
+        if (*leafPubKey != udsPub) {
+            return "Leaf public key in UDS certificat chain doesn't match UDS public key.";
+        }
+    }
+    return "";
+}
+
+ErrMsgOr<std::unique_ptr<cppbor::Array>> parseAndValidateCsrPayload(
+        const cppbor::Array& keysToSign, const std::vector<uint8_t>& csrPayload,
+        IRemotelyProvisionedComponent* provisionable, bool isFactory) {
+    auto [parsedCsrPayload, _, errMsg] = cppbor::parse(csrPayload);
+    if (!parsedCsrPayload) {
+        return errMsg;
+    }
+
+    std::unique_ptr<cppbor::Array> parsed(parsedCsrPayload.release()->asArray());
+    if (!parsed) {
+        return "CSR payload is not a CBOR array.";
+    }
+
+    if (parsed->size() != 4U) {
+        return "CSR payload must contain version, certificate type, device info, keys. "
+               "However, the parsed CSR payload has " +
+               std::to_string(parsed->size()) + " entries.";
+    }
+
+    auto signedVersion = parsed->get(0)->asUint();
+    auto signedCertificateType = parsed->get(1)->asTstr();
+    auto signedDeviceInfo = parsed->get(2)->asMap();
+    auto signedKeys = parsed->get(3)->asArray();
+
+    if (!signedVersion || signedVersion->value() != 3U) {
+        return "CSR payload version must be an unsigned integer and must be equal to 3.";
+    }
+    if (!signedCertificateType) {
+        // Certificate type is allowed to be extendend by vendor, i.e. we can't
+        // enforce its value.
+        return "Certificate type must be a Tstr.";
+    }
+    if (!signedDeviceInfo) {
+        return "Device info must be an Map.";
+    }
+    if (!signedKeys) {
+        return "Keys must be an Array.";
+    }
+
+    auto result = parseAndValidateDeviceInfo(signedDeviceInfo->encode(), provisionable, isFactory);
+    if (!result) {
+        return result.message();
+    }
+
+    if (signedKeys->encode() != keysToSign.encode()) {
+        return "Signed keys do not match.";
+    }
+
+    return std::move(parsed);
+}
+
+ErrMsgOr<bytevec> parseAndValidateAuthenticatedRequestSignedPayload(
+        const std::vector<uint8_t>& signedPayload, const std::vector<uint8_t>& challenge) {
+    auto [parsedSignedPayload, _, errMsg] = cppbor::parse(signedPayload);
+    if (!parsedSignedPayload) {
+        return errMsg;
+    }
+    if (!parsedSignedPayload->asArray()) {
+        return "SignedData payload is not a CBOR array.";
+    }
+    if (parsedSignedPayload->asArray()->size() != 2U) {
+        return "SignedData payload must contain the challenge and request. However, the parsed "
+               "SignedData payload has " +
+               std::to_string(parsedSignedPayload->asArray()->size()) + " entries.";
+    }
+
+    auto signedChallenge = parsedSignedPayload->asArray()->get(0)->asBstr();
+    auto signedRequest = parsedSignedPayload->asArray()->get(1)->asBstr();
+
+    if (!signedChallenge) {
+        return "Challenge must be a Bstr.";
+    }
+
+    if (challenge.size() < 32 || challenge.size() > 64) {
+        return "Challenge size must be between 32 and 64 bytes inclusive. "
+               "However, challenge is " +
+               std::to_string(challenge.size()) + " bytes long.";
+    }
+
+    auto challengeBstr = cppbor::Bstr(challenge);
+    if (*signedChallenge != challengeBstr) {
+        return "Signed challenge does not match."
+               "\n  Actual: " +
+               cppbor::prettyPrint(signedChallenge->asBstr(), 64 /* maxBStrSize */) +
+               "\nExpected: " + cppbor::prettyPrint(&challengeBstr, 64 /* maxBStrSize */);
+    }
+
+    if (!signedRequest) {
+        return "Request must be a Bstr.";
+    }
+
+    return signedRequest->value();
+}
+
+ErrMsgOr<bytevec> parseAndValidateAuthenticatedRequest(const std::vector<uint8_t>& request,
+                                                       const std::vector<uint8_t>& challenge) {
+    auto [parsedRequest, _, csrErrMsg] = cppbor::parse(request);
+    if (!parsedRequest) {
+        return csrErrMsg;
+    }
+    if (!parsedRequest->asArray()) {
+        return "AuthenticatedRequest is not a CBOR array.";
+    }
+    if (parsedRequest->asArray()->size() != 4U) {
+        return "AuthenticatedRequest must contain version, UDS certificates, DICE chain, and "
+               "signed data. However, the parsed AuthenticatedRequest has " +
+               std::to_string(parsedRequest->asArray()->size()) + " entries.";
+    }
+
+    auto version = parsedRequest->asArray()->get(0)->asUint();
+    auto udsCerts = parsedRequest->asArray()->get(1)->asMap();
+    auto diceCertChain = parsedRequest->asArray()->get(2)->asArray();
+    auto signedData = parsedRequest->asArray()->get(3)->asArray();
+
+    if (!version || version->value() != 1U) {
+        return "AuthenticatedRequest version must be an unsigned integer and must be equal to 1.";
+    }
+    if (!udsCerts) {
+        return "AuthenticatedRequest UdsCerts must be an Map.";
+    }
+    if (!diceCertChain) {
+        return "AuthenticatedRequest DiceCertChain must be an Array.";
+    }
+    if (!signedData) {
+        return "AuthenticatedRequest SignedData must be an Array.";
+    }
+
+    // DICE chain is [ pubkey, + DiceChainEntry ]. Its format is the same as BCC from RKP v1-2.
+    auto diceContents = validateBcc(diceCertChain);
+    if (!diceContents) {
+        return diceContents.message() + "\n" + prettyPrint(diceCertChain);
+    }
+    if (diceContents->size() == 0U) {
+        return "The DICE chain is empty. It must contain at least one entry.";
+    }
+
+    auto& udsPub = diceContents->back().pubKey;
+
+    auto error = validateUdsCerts(*udsCerts, udsPub);
+    if (!error.empty()) {
+        return error;
+    }
+
+    auto signedPayload = verifyAndParseCoseSign1(signedData, udsPub, {} /* aad */);
+    if (!signedPayload) {
+        return signedPayload.message();
+    }
+
+    auto payload = parseAndValidateAuthenticatedRequestSignedPayload(*signedPayload, challenge);
+    if (!payload) {
+        return payload.message();
+    }
+
+    return payload;
+}
+
+ErrMsgOr<std::unique_ptr<cppbor::Array>> verifyCsr(const cppbor::Array& keysToSign,
+                                                   const std::vector<uint8_t>& csr,
+                                                   IRemotelyProvisionedComponent* provisionable,
+                                                   const std::vector<uint8_t>& challenge,
+                                                   bool isFactory) {
+    RpcHardwareInfo info;
+    provisionable->getHardwareInfo(&info);
+    if (info.versionNumber != 3) {
+        return "Remotely provisioned component version (" + std::to_string(info.versionNumber) +
+               ") does not match expected version (3).";
+    }
+
+    auto csrPayload = parseAndValidateAuthenticatedRequest(csr, challenge);
+    if (!csrPayload) {
+        return csrPayload.message();
+    }
+
+    return parseAndValidateCsrPayload(keysToSign, *csrPayload, provisionable, isFactory);
+}
+
+ErrMsgOr<std::unique_ptr<cppbor::Array>> verifyFactoryCsr(
+        const cppbor::Array& keysToSign, const std::vector<uint8_t>& csr,
+        IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge) {
+    return verifyCsr(keysToSign, csr, provisionable, challenge, /*isFactory=*/true);
+}
+
+ErrMsgOr<std::unique_ptr<cppbor::Array>> verifyProductionCsr(
+        const cppbor::Array& keysToSign, const std::vector<uint8_t>& csr,
+        IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge) {
+    return verifyCsr(keysToSign, csr, provisionable, challenge, /*isFactory=*/false);
+}
+
+}  // namespace aidl::android::hardware::security::keymint::remote_prov
diff --git a/security/rkp/CHANGELOG.md b/security/rkp/CHANGELOG.md
new file mode 100644
index 0000000..c3e3609
--- /dev/null
+++ b/security/rkp/CHANGELOG.md
@@ -0,0 +1,45 @@
+# Remote Provisioning Changelog
+
+This document provides an exact description of which changes have occurred in the
+`IRemotelyProvisionedComponent` HAL interface in each Android release.
+
+## Releases
+* **Android S (12):** IRemotelyProvisionedComponent v1
+* **Android T (13):** IRemotelyProvisionedComponent v2
+* **Android U (14):** IRemotelyProvisionedComponent v3
+
+## IRemotelyProvisionedComponent 1 -> 2
+* DeviceInfo
+  * Most entries are no longer optional.
+  * `att_id_state` is now `fused`. `fused` is used to indicate if SecureBoot is enabled.
+  * `version` is now `2`.
+  * `board` has been removed.
+  * `device` has been added.
+* RpcHardwareInfo
+  * `uniqueId` String added as a field in order to differentiate IRPC instances on device.
+
+## IRemotelyProvisionedComponent 2 -> 3
+* The RKP HAL now builds separately from KeyMint.
+  * The HAL remains under the `android.hardware.security.keymint` package for
+    compatibility with previous releases. ABI compatibility requires this.
+  * Dependencies on the RKP HAL must add a dependency on
+    `"android.hardware.security.rkp"` generated code (instead of
+    `"android.hardward.security.keymint"`).
+* ProtectedData has been removed.
+* DeviceInfo
+  * `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.
+  * 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/README.md b/security/rkp/README.md
new file mode 100644
index 0000000..5fb4948
--- /dev/null
+++ b/security/rkp/README.md
@@ -0,0 +1,374 @@
+# Remote Provisioning HAL
+
+## Objective
+
+Design a HAL to support over-the-air provisioning of certificates for asymmetric
+keys. The HAL must interact effectively with Keystore (and other daemons) and
+protect device privacy and security.
+
+Note that this API was originally designed for KeyMint, with the intention that
+it should be usable for other HALs that require certificate provisioning.
+Throughout this document we'll refer to the Keystore and KeyMint (formerly
+called Keymaster) components, but only for concreteness and convenience; those
+labels could be replaced with the names of any system and secure area
+components, respectively, that need certificates provisioned.
+
+## Key design decisions
+
+### General approach
+
+To more securely and reliably get keys and certificates to Android devices, we
+need to create a system where no party outside of the device's secure components
+is responsible for managing private keys. The strategy we've chosen is to
+deliver certificates over the air, using an asymmetric key pair created
+on-device in the factory as a root of trust to create an authenticated, secure
+channel. In this document we refer to this device-unique asymmetric key pair as
+Device Key (DK), its public half DK\_pub, its private half DK\_priv and a Device
+Key Certificate containing DK\_pub is denoted DKC.
+
+In order for the provisioning service to use DK (or a key authenticated by DK),
+it must know whether a given DK\_pub is known and trusted. To prove trust, we
+ask device OEMs to use one of two mechanisms:
+
+1.  (Preferred, recommended) The device OEM extracts DK\_pub from each device it
+    manufactures and uploads the public keys to a backend server.
+
+1.  The device OEM signs the DK\_pub to produce DKC and stores it on the device.
+    This has the advantage that they don't need to upload a DK\_pub for every
+    device immediately, but the disadvantage that they have to manage their
+    private signing keys, which means they have to have HSMs, configure and
+    secure them correctly, etc. Some backend providers may also require that the
+    OEM passes a factory security audit, and additionally promises to upload the
+    keys eventually as well.
+
+Note that in the full elaboration of this plan, DK\_pub is not the key used to
+establish a secure channel. Instead, DK\_pub is just the first public key in a
+chain of public keys which ends with the KeyMint public key, KM\_pub. All keys
+in the chain are device-unique and are joined in a certificate chain called the
+_Boot Certificate Chain_ (BCC), because in phases 2 and 3 of the remote
+provisioning project it is a chain of certificates corresponding to boot phases.
+We speak of the BCC even for phase 1, though in phase 1 it contains only a
+single self-signed DKC. This is described in more depth in the Phases section
+below.
+
+The BCC is authenticated by DK\_pub. To authenticate DK\_pub, we may have
+additional DKCs, from the SoC vendor, the device OEM, or both. Those are not
+part of the BCC but included as optional fields in the certificate request
+structure.
+
+The format of the the DK and BCC is specified within [Open Profile for DICE]
+(https://pigweed.googlesource.com/open-dice/+/HEAD/docs/specification.md).  To
+map phrases within this document to their equivalent terminology in the DICE
+specification, read the terms as follows: the DK corresponds to the UDS-derived
+key pair, DKC corresponds to the UDS certificate, and the BCC entries between
+DK\_pub and KM\_pub correspond to a chain of CDI certificates.
+
+Note: In addition to allowing 32 byte hash values for fields in the BCC payload,
+this spec additionally constrains some of the choices allowed in open-DICE.
+Specifically, these include which entries are required and which are optional in
+the BCC payload, and which algorithms are acceptable for use.
+
+### Phases
+
+RKP will be deployed in three phases, in terms of managing the root of trust
+binding between the device and the backend. To briefly describe them:
+
+* Phase 1: In phase 1 there is only one entry in the BCC; DK_pub and KM_pub are
+  the same key and the certificate is self-signed.
+* Phase 2: This is identical to phase 1, except it leverages the hardware root
+  of trust process described by DICE. Instead of trust being rooted in the TEE,
+  it is now rooted in the ROM by key material blown into fuses which are only
+  accessible to the ROM code.
+* Phase 3: This is identical to Phase 2, except the SoC vendor also does the
+  public key extraction or certification in their facilities, along with the OEM
+  doing it in the factory. This tightens up the "supply chain" and aims to make
+  key upload management more secure.
+
+### Privacy considerations
+
+Because DK and the DKCs are unique, immutable, unspoofable hardware-bound
+identifiers for the device, we must limit access to them to the absolute minimum
+possible. We do this in two ways:
+
+1.  We require KeyMint (which knows the BCC and either knows or at least has the
+ability to use KM\_priv) to refuse to ever divulge the BCC or additional
+signatures in plaintext. Instead, KeyMint requires the caller to provide an
+_Endpoint Encryption Key_ (EEK), with which it will encrypt the data before
+returning it. When provisioning production keys, the EEK must be signed by an
+approved authority whose public key is embedded in KeyMint. When certifying test
+keys, KeyMint will accept any EEK without checking the signature, but will
+encrypt and return a test BCC, rather than the real one.  The result is that
+only an entity in possession of an Trusted EEK (TEEK) private key can discover
+the plaintext of the production BCC.
+1.  Having thus limited access to the public keys to the trusted party only, we
+need to prevent the entity from abusing this unique device identifier.  The
+approach and mechanisms for doing that are beyond the scope of this document
+(they must be addressed in the server design), but generally involve taking care
+to ensure that we do not create any links between user IDs, IP addresses or
+issued certificates and the device pubkey.
+
+Although the details of the mechanisms for preventing the entity from abusing
+the BCC are, as stated, beyond the scope of this document, there is a subtle
+design decision here made specifically to enable abuse prevention. Specifically
+the `CertificateRequest` message sent to the server is (in
+[CDDL](https://tools.ietf.org/html/rfc8610)):
+
+```
+cddl
+CertificateRequest = [
+    DeviceInfo,
+    challenge : bstr,
+    ProtectedData,
+    MacedKeysToSign
+]
+```
+
+The public keys to be attested by the server are in `MacedKeysToSign`, which is
+a COSE\_Mac0 structure, MACed with a key that is found in `ProtectedData`. The
+MAC key is signed by DK\_pub.
+
+This structure allows the backend component that has access to EEK\_priv to
+decrypt `ProtectedData`, validate that the request is from an authorized device,
+check that the request is fresh and verify and extract the MAC key. That backend
+component never sees any data related to the keys to be signed, but can provide
+the MAC key to another backend component that can verify `MacedKeysToSign` and
+proceed to generate the certificates.
+
+In this way, we can partition the provisioning server into one component that
+knows the device identity, as represented by DK\_pub, but never sees the keys to
+be certified or certificates generated, and another component that sees the keys
+to be certified and certificates generated but does not know the device
+identity.
+
+### Key and cryptographic message formatting
+
+For simplicity of generation and parsing, compactness of wire representation,
+and flexibility and standardization, we've settled on using the CBOR Object
+Signing and Encryption (COSE) standard, defined in [RFC
+8152](https://tools.ietf.org/html/rfc8152). COSE provides compact and reasonably
+simple, yet easily-extensible, wire formats for:
+
+*   Keys,
+*   MACed messages,
+*   Signed messages, and
+*   Encrypted messages
+
+COSE enables easy layering of these message formats, such as using a COSE\_Sign
+structure to contain a COSE\_Key with a public key in it. We call this a
+"certificate".
+
+Due to the complexity of the standard, we'll spell out the COSE structures
+completely in this document and in the HAL and other documentation, so that
+although implementors will need to understand CBOR and the CBOR Data Definition
+Language ([CDDL, defined in RFC 8610](https://tools.ietf.org/html/rfc8610)),
+they shouldn't need to understand COSE.
+
+Note, however, that the certificate chains returned from the provisioning server
+are standard X.509 certificates.
+
+### Algorithm choices
+
+This document uses:
+
+*   ECDSA P-256 for attestation signing keys;
+*   Remote provisioning protocol signing keys:
+  *  Ed25519 / P-256
+*   ECDH keys:
+  *  X25519 / P-256
+*   AES-GCM for all encryption;
+*   SHA-256 for all message digesting;
+*   HMAC-SHA-256 for all MACing; and
+*   HKDF-SHA-256 for all key derivation.
+
+We believe that Curve25519 offers the best tradeoff in terms of security,
+efficiency and global trustworthiness, and that it is now sufficiently
+widely-used and widely-implemented to make it a practical choice.
+
+However, since Secure Elements (SE) do not currently offer support for curve
+25519, we are allowing implementations to instead make use of EC P-256 for
+signing and ECDH. To put it simply, the device unique key pair will be a P-256
+key pair for ECDSA instead of Ed25519, and the ProtectedData COSE\_Encrypt
+message will have its payload encrypted with P-256 ECDH key exchange instead of
+X25519.
+
+The CDDL in the rest of the document will use the '/' operator to show areas
+where either curve 25519 or P-256 may be used. Since there is no easy way to
+bind choices across different CDDL groups, it is important that the implementor
+stays consistent in which type is chosen. E.g. taking ES256 as the choice for
+algorithm implies the implementor should also choose the P256 public key group
+further down in the COSE structure.
+
+### Testability
+
+It's critical that the remote provisioning implementation be testable, to
+minimize the probability that broken devices are sold to end users. To support
+testing, the remote provisioning HAL methods take a `testMode` argument. Keys
+created in test mode are tagged to indicate this. The provisioning server will
+check for the test mode tag and issue test certificates that do not chain back
+to a trusted public key. In test mode, any EEK will be accepted, enabling
+testing tools to use EEKs for which they have the private key so they can
+validate the content of certificate requests. The BCC included in the
+`CertificateRequest` must contain freshly-generated keys, not the real BCC keys.
+
+Keystore (or similar) will need to be able to handle both testMode keys and
+production keys and keep them distinct, generating test certificate requests
+when asked with a test EEK and production certificate requests when asked with a
+production EEK. Likewise, the interface used to instruct Keystore to create keys
+will need to be able to specify whether test or production keys are desired.
+
+## Design
+
+### Certificate provisioning flow
+
+TODO(jbires): Replace this with a `.png` containing a sequence diagram.  The
+provisioning flow looks something like this:
+
+Provisioner -> Keystore: Prepare N keys
+Keystore -> KeyMint: generateKeyPair
+KeyMint -> KeyMint: Generate  key pair
+KeyMint --> Keystore: key\_blob,pubkey
+Keystore -> Keystore: Store key\_blob,pubkey
+Provisioner -> Server: Get TEEK
+Server --> Provisioner: TEEK
+Provisioner -> Keystore: genCertReq(N, TEEK)
+Keystore -> KeyMint: genCertReq(pubkeys, TEEK)
+KeyMint -> KeyMint: Sign pubkeys & encrypt BCC
+KeyMint --> Keystore: signature, encrypted BCC
+Keystore -> Keystore: Construct cert\_request
+Keystore --> Provisioner: cert\_request
+Provisioner --> Server: cert\_request
+Server -> Server: Validate cert\_request
+Server -> Server: Generate certificates
+Server --> Provisioner: certificates
+Provisioner -> Keystore: certificates
+Keystore -> Keystore: Store certificates
+
+The actors in the above diagram are:
+
+*   **Server** is the backend certificate provisioning server. It has access to
+    the uploaded device public keys and is responsible for providing encryption
+    keys, decrypting and validating requests, and generating certificates in
+    response to requests.
+*   **Provisioner** is an application that is responsible for communicating with
+    the server and all of the system components that require key certificates
+    from the server. It also implements the policy that defines how many key
+    pairs each client should keep in their pool.
+*   **Keystore** is the [Android keystore
+    daemon](https://developer.android.com/training/articles/keystore) (or, more
+    generally, whatever system component manages communications with a
+    particular secure aread component).
+*   **KeyMint** is the secure area component that manages cryptographic keys and
+    performs attestations (or perhaps some other secure area component).
+
+### `BCC`
+
+The _Boot Certificate Chain_ (BCC) is the chain of certificates that contains
+DK\_pub as well as other often device-unique certificates. The BCC is
+represented as a COSE\_Key containing DK\_pub followed by an array of
+COSE\_Sign1 "certificates" containing public keys and optional additional
+information, ordered from root to leaf, with each certificate signing the next.
+The first certificate in the array is signed by DK\_pub, the last certificate
+has the KeyMint (or whatever) signing key's public key, KM\_pub. In phase 1
+there is only one entry; DK\_pub and KM\_pub are the same key and the
+certificate is self-signed.
+
+Each COSE\_Sign1 certificate is a CBOR Web Token (CWT) as described in [RFC
+8392](https://tools.ietf.org/html/rfc8392) with additional fields as described
+in the Open Profile for DICE. Of these additional fields, only the
+_subjectPublicKey_ and _keyUsage_ fields are expected to be present for the
+KM\_pub entry (that is, the last entry) in a BCC, but all fields required by the
+Open Profile for DICE are expected for other entries (each of which corresponds
+to a particular firmware component or boot stage). The CWT fields _iss_ and
+_sub_ identify the issuer and subject of the certificate and are consistent
+along the BCC entries; the issuer of a given entry matches the subject of the
+previous entry.
+
+The BCC is designed to be constructed using the Open Profile for DICE. In this
+case the DK key pair is derived from the UDS as described by that profile and
+all BCC entries before the leaf are CBOR CDI certificates chained from DK\_pub.
+The KM key pair is not part of the derived DICE chain. It is generated (not
+derived) by the KeyMint module, certified by the last key in the DICE chain, and
+added as the leaf BCC entry. The key usage field in this leaf certificate must
+indicate the key is not used to sign certificates. If a UDS certificate is
+available on the device it should appear in the certificate request as the leaf
+of a DKCertChain in AdditionalDKSignatures (see
+[CertificateRequest](#certificaterequest)).
+
+The Open Profile for DICE allows for an arbitrary configuration descriptor. For
+BCC entries, this configuration descriptor is a CBOR map with the following
+optional fields. If no fields are relevant, an empty map should be encoded.
+Additional implementation-specific fields may be added using key values not in
+the range \[-70000, -70999\] (these are reserved for future additions here).
+
+```
+| Name              | Key    | Value type | Meaning                           |
+| ----------------- | ------ | ---------- | ----------------------------------|
+| Component name    | -70002 | tstr       | Name of firmware component / boot |
+:                   :        :            : stage                             :
+| Component version | -70003 | int        | Version of firmware component /   |
+:                   :        :            : boot stage                        :
+| Resettable        | -70004 | null       | If present, key changes on factory|
+:                   :        :            : reset                             :
+```
+
+Please see
+[ProtectedData.aidl](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/ProtectedData.aidl)
+for a full CDDL definition of the BCC.
+
+### `CertificateRequest`
+
+The full CBOR message that will be sent to the server to request certificates
+is:
+
+```cddl
+CertificateRequest = [
+    DeviceInfo,
+    challenge : bstr,       // Provided by the server
+    ProtectedData,          // See ProtectedData.aidl
+    MacedKeysToSign         // See IRemotelyProvisionedComponent.aidl
+]
+
+DeviceInfo = [
+    VerifiedDeviceInfo,     // See DeviceInfo.aidl
+    UnverifiedDeviceInfo
+]
+
+// Unverified info is anything provided by the HLOS. Subject to change out of
+// step with the HAL.
+UnverifiedDeviceInfo = {
+    ? "fingerprint" : tstr,
+}
+
+```
+
+It will be the responsibility of Keystore and the Provisioner to construct the
+`CertificateRequest`. The HAL provides a method to generate the elements that
+need to be constructed on the secure side, which are the tag field of
+`MacedKeysToSign`, `VerifiedDeviceInfo`, and the ciphertext field of
+`ProtectedData`.
+
+### HAL
+
+The remote provisioning HAL provides a simple interface that can be implemented
+by multiple secure components that require remote provisioning. It would be
+slightly simpler to extend the KeyMint API, but that approach would only serve
+the needs of KeyMint, this is more general.
+
+NOTE the data structures defined in this HAL may look a little bloated and
+complex. This is because the COSE data structures are fully spelled-out; we
+could make it much more compact by not re-specifying the standardized elements
+and instead just referencing the standard, but it seems better to fully specify
+them. If the apparent complexity seems daunting, consider what the same would
+look like if traditional ASN.1 DER-based structures from X.509 and related
+standards were used and also fully elaborated.
+
+Please see the related HAL documentation directly in the source code at the
+following links:
+
+*   [IRemotelyProvisionedComponent
+    HAL](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl)
+*   [ProtectedData](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/ProtectedData.aidl)
+*   [MacedPublicKey](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/MacedPublicKey.aidl)
+*   [RpcHardwareInfo](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl)
+*   [DeviceInfo](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/DeviceInfo.aidl)
+
diff --git a/security/rkp/aidl/Android.bp b/security/rkp/aidl/Android.bp
new file mode 100644
index 0000000..5285477
--- /dev/null
+++ b/security/rkp/aidl/Android.bp
@@ -0,0 +1,41 @@
+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.security.rkp",
+    vendor_available: true,
+    srcs: [
+        // This HAL was originally part of keymint.
+        "android/hardware/security/keymint/*.aidl",
+
+        // in the future
+        // "android/hardware/security/rkp/*.aidl",
+    ],
+    stability: "vintf",
+    backend: {
+        java: {
+            min_sdk_version: "33",
+            apex_available: [
+                "//apex_available:platform",
+                "com.android.rkpd",
+            ],
+        },
+        rust: {
+            enabled: true,
+        },
+    },
+    versions_with_info: [
+        {
+            version: "1",
+        },
+        {
+            version: "2",
+        },
+    ],
+}
diff --git a/security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/.hash b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/.hash
new file mode 100644
index 0000000..404553b
--- /dev/null
+++ b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/.hash
@@ -0,0 +1 @@
+d285480d2e0002adc0ace80edf34aa725679512e
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/android/hardware/security/keymint/DeviceInfo.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/android/hardware/security/keymint/DeviceInfo.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/android/hardware/security/keymint/DeviceInfo.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/android/hardware/security/keymint/DeviceInfo.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/android/hardware/security/keymint/MacedPublicKey.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/android/hardware/security/keymint/MacedPublicKey.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/android/hardware/security/keymint/MacedPublicKey.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/android/hardware/security/keymint/MacedPublicKey.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/android/hardware/security/keymint/ProtectedData.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/android/hardware/security/keymint/ProtectedData.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/android/hardware/security/keymint/ProtectedData.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/android/hardware/security/keymint/ProtectedData.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/android/hardware/security/keymint/RpcHardwareInfo.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/android/hardware/security/keymint/RpcHardwareInfo.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/android/hardware/security/keymint/RpcHardwareInfo.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/android/hardware/security/keymint/RpcHardwareInfo.aidl
diff --git a/security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/.hash b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/.hash
new file mode 100644
index 0000000..8700d33
--- /dev/null
+++ b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/.hash
@@ -0,0 +1 @@
+c8d34e56ae0807b61f028019622d8b60a37e0a8b
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/android/hardware/security/keymint/DeviceInfo.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/android/hardware/security/keymint/DeviceInfo.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/android/hardware/security/keymint/DeviceInfo.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/android/hardware/security/keymint/DeviceInfo.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/android/hardware/security/keymint/MacedPublicKey.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/android/hardware/security/keymint/MacedPublicKey.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/android/hardware/security/keymint/MacedPublicKey.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/android/hardware/security/keymint/MacedPublicKey.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/android/hardware/security/keymint/ProtectedData.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/android/hardware/security/keymint/ProtectedData.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/android/hardware/security/keymint/ProtectedData.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/android/hardware/security/keymint/ProtectedData.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/android/hardware/security/keymint/RpcHardwareInfo.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/android/hardware/security/keymint/RpcHardwareInfo.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/android/hardware/security/keymint/RpcHardwareInfo.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/android/hardware/security/keymint/RpcHardwareInfo.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/DeviceInfo.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/DeviceInfo.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/DeviceInfo.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/DeviceInfo.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/MacedPublicKey.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/MacedPublicKey.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/MacedPublicKey.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/MacedPublicKey.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/ProtectedData.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/ProtectedData.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/ProtectedData.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/ProtectedData.aidl
diff --git a/security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/RpcHardwareInfo.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
new file mode 100644
index 0000000..b1f99e1
--- /dev/null
+++ b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.security.keymint;
+/* @hide */
+@RustDerive(Clone=true, Eq=true, Hash=true, Ord=true, PartialEq=true, PartialOrd=true) @VintfStability
+parcelable RpcHardwareInfo {
+  int versionNumber;
+  @utf8InCpp String rpcAuthorName;
+  int supportedEekCurve = 0;
+  @nullable @utf8InCpp String uniqueId;
+  int supportedNumKeysInCsr = 4;
+  const int CURVE_NONE = 0;
+  const int CURVE_P256 = 1;
+  const int CURVE_25519 = 2;
+  const int MIN_SUPPORTED_NUM_KEYS_IN_CSR = 20;
+}
diff --git a/security/rkp/aidl/android/hardware/security/keymint/DeviceInfo.aidl b/security/rkp/aidl/android/hardware/security/keymint/DeviceInfo.aidl
new file mode 100644
index 0000000..f0af619
--- /dev/null
+++ b/security/rkp/aidl/android/hardware/security/keymint/DeviceInfo.aidl
@@ -0,0 +1,55 @@
+/*
+ * 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.security.keymint;
+
+/**
+ * DeviceInfo contains information about the device that's fed in as AAD in the signature of the
+ * device private key over the MAC key used for the bundle of public keys. These values are intended
+ * to be checked by the server to verify that the certificate signing request crafted by
+ * an IRemotelyProvisionedComponent HAL instance is coming from the expected device based
+ * on values initially uploaded during device manufacture in the factory.
+ * @hide
+ */
+@VintfStability
+parcelable DeviceInfo {
+    /**
+     * DeviceInfo is a CBOR Map structure described by the following CDDL. DeviceInfo must be
+     * canonicalized according to the specification in RFC 7049. The ordering presented here is
+     * non-canonical to group similar entries semantically.
+     *
+     *     DeviceInfo = {
+     *         "brand" : tstr,
+     *         "manufacturer" : tstr,
+     *         "product" : tstr,
+     *         "model" : tstr,
+     *         "device" : tstr,
+     *         "vb_state" : "green" / "yellow" / "orange",    ; Taken from the AVB values
+     *         "bootloader_state" : "locked" / "unlocked",    ; Taken from the AVB values
+     *         "vbmeta_digest": bstr,                         ; Taken from the AVB values
+     *         ? "os_version" : tstr,                         ; Same as
+     *                                                        ; android.os.Build.VERSION.release
+     *                                                        ; Not optional for TEE.
+     *         "system_patch_level" : uint,                   ; YYYYMMDD
+     *         "boot_patch_level" : uint,                     ; YYYYMMDD
+     *         "vendor_patch_level" : uint,                   ; YYYYMMDD
+     *         "security_level" : "tee" / "strongbox",
+     *         "fused": 1 / 0,  ; 1 if secure boot is enforced for the processor that the IRPC
+     *                          ; implementation is contained in. 0 otherwise.
+     *     }
+     */
+    byte[] deviceInfo;
+}
diff --git a/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl b/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
new file mode 100644
index 0000000..2fc780c
--- /dev/null
+++ b/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
@@ -0,0 +1,479 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.security.keymint;
+
+import android.hardware.security.keymint.DeviceInfo;
+import android.hardware.security.keymint.MacedPublicKey;
+import android.hardware.security.keymint.ProtectedData;
+import android.hardware.security.keymint.RpcHardwareInfo;
+
+/**
+ * An IRemotelyProvisionedComponent is a secure-side component for which certificates can be
+ * remotely provisioned. It provides an interface for generating asymmetric key pairs and then
+ * creating a CertificateRequest that contains the generated public keys, plus other information to
+ * authenticate the request origin. The CertificateRequest can be sent to a server, which can
+ * validate the request and create certificates.
+ *
+ * This interface does not provide any way to use the generated and certified key pairs. It's
+ * intended to be implemented by a HAL service that does other things with keys (e.g. KeyMint).
+ *
+ * The root of trust for secure provisioning is something called the Device Identifier Composition
+ * Engine (DICE) Chain. The DICE Chain is a chain of certificates, represented as COSE_Sign1 objects
+ * containing CBOR Web Tokens (CWT) which have descriptions about the stage of firmware being
+ * signed, including a COSE_Key representation of that stage's public key.
+ *
+ * DICE Chain Design
+ * =================
+ *
+ * For a more exhaustive and thorough look at DICE and the implementation used within this protocol,
+ * please see: https://pigweed.googlesource.com/open-dice/+/HEAD/docs/specification.md
+ *
+ * The DICE Chain is designed to mirror the boot stages of a device, and to prove the content and
+ * integrity of each firmware image. In a proper DICE Chain, each boot stage hashes its own private
+ * key material with the code and any relevant configuration parameters of the next stage to produce
+ * a Compound Device Identifier, or CDI, which is used as the secret key material for the next
+ * stage. From the CDI, a key pair - CDI_*_Pub and CDI_*_Priv - is derived and certified for the
+ * next stage by the current stages CDI_*_Priv. The next stage is then loaded and given its CDI and
+ * the DICE certificate chain generated so far in a manner that does not leak the previous stage's
+ * CDI_*_Priv or CDI to later boot stages. The final, "leaf" CDI certificate contains a public key,
+ * denoted CDI_Leaf_Pub, whose corresponding private key, denoted CDI_Leaf_Priv, is available for
+ * use by the IRemotelyProvisionedComponent.
+ *
+ * The root keypair is generated by immutable code (e.g. ROM), from a Unique Device Secret (UDS).
+ * The keypair that is generated from it can be referred to as the UDS_Pub/UDS_Priv keys. After the
+ * device-unique secret is used, it must be made unavailable to any later boot stage.
+ *
+ * In this way, booting the device incrementally builds a certificate chain that (a) identifies and
+ * validates the integrity of every stage and (b) contains a set of public keys that correspond to
+ * private keys, one known to each stage. Any stage can compute the secrets of all later stages
+ * (given the necessary input), but no stage can compute the secret of any preceding stage. Updating
+ * the firmware or configuration of any stage changes the key pair of that stage, and of all
+ * subsequent stages, and no attacker who compromised the previous version of the updated firmware
+ * can know or predict the post-update key pairs. It is recommended and expected that the DICE Chain
+ * is constructed using the Open Profile for DICE.
+ *
+ * When the provisioning server receives a message signed by CDI_Leaf_Priv and containing a DICE
+ * chain that chains from UDS_Pub to CDI_Leaf_Pub, it can be certain that (barring vulnerabilities
+ * in some boot stage), the CertificateRequest came from the device associated with UDS_Pub, running
+ * the specific software identified by the certificates in the chain. If the server has some
+ * mechanism for knowing the hash values of compromised stages, it can determine whether signing
+ * certificates is appropriate.
+ *
+ * Degenerate DICE Chains
+ * ======================
+ *
+ * While a proper DICE Chain, as described above, reflects the complete boot sequence from boot ROM
+ * to the secure area image of the IRemotelyProvisionedComponent, it's also possible to use a
+ * "degenerate" DICE Chain which consists only of a single, self-signed certificate containing the
+ * public key of a hardware-bound key pair. This is an appropriate solution for devices which
+ * haven't implemented everything necessary to produce a proper DICE Chain, but can derive a unique
+ * key pair in the secure area. In this degenerate case, UDS_Pub is the same as CDI_Leaf_Pub.
+ *
+ * DICE Chain Privacy
+ * ==================
+ *
+ * Because the DICE Chain constitutes an unspoofable, device-unique identifier, special care is
+ * taken to prevent its availability to entities who may wish to track devices. Three precautions
+ * are taken:
+ *
+ * 1) The DICE chain is only handled by the native Remote Key Provisioning Daemon (RKPD) service on
+ *    the HLOS and is not exposed to apps running on device.
+ *
+ * 2) The CDI_Leaf_Priv key cannot be used to sign arbitrary data.
+ *
+ * 3) Backend infrastructure does not correlate UDS_Pub with the certificates signed and sent back
+ *    to the device.
+ *
+ * Versioning
+ * ==========
+ * Versions 1 and 2 of the schema, as previously defined in DeviceInfo.aidl, diverge in
+ * functionality from Version 3. Version 3 removes the need to have testMode in function calls and
+ * deprecates the Endpoint Encryption Key (EEK) as well. Vendors implementing Version 1
+ * (Android S/12) or Version 2 (Android T/13) do not need to implement generateCertificateRequestV2.
+ * Vendors implementing Version 3 (Android U/14) need to implement generateCertificateRequestV2.
+ *
+ * For better coverage of changes from version to version, please see RKP_CHANGELOG.md in the root
+ * of the keymint interface directory.
+ *
+ * @hide
+ */
+@VintfStability
+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_TEST_KEY_IN_PRODUCTION_REQUEST = 4;
+    const int STATUS_INVALID_EEK = 5;
+    // --------- END: Versions 1 and 2 Only ------------
+    const int STATUS_REMOVED = 6;
+
+    /**
+     * @return info which contains information about the underlying IRemotelyProvisionedComponent
+     *         hardware, such as version number, component name, author name, and supported curve.
+     */
+    RpcHardwareInfo getHardwareInfo();
+
+    /**
+     * 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
+     *        are marked (see the definition of PublicKey in the MacedPublicKey structure) to
+     *        prevent them from being confused with production keys.
+     *
+     * @param out MacedPublicKey macedPublicKey contains the public key of the generated key pair,
+     *        MACed so that generateCertificateRequest can easily verify, without the
+     *        privateKeyHandle, that the contained public key is for remote certification.
+     *
+     * @return data representing a handle to the private key. The format is implementation-defined,
+     *         but note that specific services may define a required format. KeyMint does.
+     */
+    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
+     * ServiceSpecificException with an error code of STATUS_REMOVED.
+     *
+     * For v1 and v2 implementations:
+     * generateCertificateRequest creates a certificate request to be sent to the provisioning
+     * server.
+     *
+     * @param in boolean testMode indicates whether the generated certificate request is for testing
+     *        only.
+     *
+     * @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.
+     *
+     *        If testMode is true, the keysToCertify array must contain only keys flagged as test
+     *        keys. Otherwise, the method must return STATUS_PRODUCTION_KEY_IN_TEST_REQUEST.
+     *
+     *        If testMode is false, the keysToCertify array must not contain any keys flagged as
+     *        test keys. Otherwise, the method must return STATUS_TEST_KEY_IN_PRODUCTION_REQUEST.
+     *
+     * @param in endpointEncryptionKey contains an X25519 public key which will be used to encrypt
+     *        the BCC. For flexibility, this is represented as a certificate chain, represented as a
+     *        CBOR array of COSE_Sign1 objects, ordered from root to leaf. The leaf contains the
+     *        X25519 encryption key, each other element is an Ed25519 key signing the next in the
+     *        chain. The root is self-signed. An implementor may also choose to use P256 as an
+     *        alternative curve for signing and encryption instead of Curve 25519.
+     *
+     *            EekChain = [ + SignedSignatureKey, SignedEek ]
+     *
+     *            SignedSignatureKey = [              ; COSE_Sign1
+     *                protected: bstr .cbor {
+     *                    1 : AlgorithmEdDSA / AlgorithmES256,  ; Algorithm
+     *                },
+     *                unprotected: {},
+     *                payload: bstr .cbor SignatureKeyEd25519 /
+     *                         bstr .cbor SignatureKeyP256,
+     *                signature: bstr PureEd25519(.cbor SignatureKeySignatureInput) /
+     *                           bstr ECDSA(.cbor SignatureKeySignatureInput)
+     *            ]
+     *
+     *            SignatureKeyEd25519 = {             ; COSE_Key
+     *                 1 : 1,                         ; Key type : Octet Key Pair
+     *                 3 : AlgorithmEdDSA,            ; Algorithm
+     *                 -1 : 6,                        ; Curve : Ed25519
+     *                 -2 : bstr                      ; Ed25519 public key
+     *            }
+     *
+     *            SignatureKeyP256 = {                ; COSE_Key
+     *                 1 : 2,                         ; Key type : EC2
+     *                 3 : AlgorithmES256,            ; Algorithm
+     *                 -1 : 1,                        ; Curve: P256
+     *                 -2 : bstr,                     ; X coordinate
+     *                 -3 : bstr                      ; Y coordinate
+     *            }
+     *
+     *            SignatureKeySignatureInput = [
+     *                context: "Signature1",
+     *                body_protected: bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 },
+     *                external_aad: bstr .size 0,
+     *                payload: bstr .cbor SignatureKeyEd25519 /
+     *                         bstr .cbor SignatureKeyP256
+     *            ]
+     *
+     *            ; COSE_Sign1
+     *            SignedEek = [
+     *                protected: bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 },
+     *                unprotected: {},
+     *                payload: bstr .cbor EekX25519 / .cbor EekP256,
+     *                signature: bstr PureEd25519(.cbor EekSignatureInput) /
+     *                           bstr ECDSA(.cbor EekSignatureInput)
+     *            ]
+     *
+     *            EekX25519 = {            ; COSE_Key
+     *                1 : 1,               ; Key type : Octet Key Pair
+     *                2 : bstr             ; KID : EEK ID
+     *                3 : -25,             ; Algorithm : ECDH-ES + HKDF-256
+     *                -1 : 4,              ; Curve : X25519
+     *                -2 : bstr            ; X25519 public key
+     *            }
+     *
+     *            EekP256 = {              ; COSE_Key
+     *                1 : 2,               ; Key type : EC2
+     *                2 : bstr             ; KID : EEK ID
+     *                3 : -25,             ; Algorithm : ECDH-ES + HKDF-256
+     *                -1 : 1,              ; Curve : P256
+     *                -2 : bstr            ; Sender X coordinate
+     *                -3 : bstr            ; Sender Y coordinate
+     *            }
+     *
+     *            EekSignatureInput = [
+     *                context: "Signature1",
+     *                body_protected: bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 },
+     *                external_aad: bstr .size 0,
+     *                payload: bstr .cbor EekX25519 / .cbor EekP256
+     *            ]
+     *
+     *            AlgorithmES256 = -7      ; RFC 8152 section 8.1
+     *            AlgorithmEdDSA = -8      ; RFC 8152 section 8.2
+     *
+     *        If the contents of endpointEncryptionKey do not match the SignedEek structure above,
+     *        the method must return STATUS_INVALID_EEK.
+     *
+     *        If testMode is true, the method must ignore the length and content of the signatures
+     *        in the chain, which implies that it must not attempt to validate the signature.
+     *
+     *        If testMode is false, the method must validate the chain signatures, and must verify
+     *        that the public key in the root certificate is in its pre-configured set of
+     *        authorized EEK root keys. If the public key is not in the database, or if signature
+     *        verification fails, the method must return STATUS_INVALID_EEK.
+     *
+     * @param in challenge contains a byte string from the provisioning server that must be signed
+     *        by the secure area. See the description of the 'signature' output parameter for
+     *        details.
+     *
+     * @param out DeviceInfo contains the VerifiedDeviceInfo portion of the DeviceInfo array in
+     *        CertificateRequest. The structure is described within the DeviceInfo.aidl file.
+     *
+     * @param out ProtectedData contains the encrypted BCC and the ephemeral MAC key used to
+     *        authenticate the keysToSign (see keysToSignMac output argument).
+     *
+     * @return The MAC of KeysToSign in the CertificateRequest structure. Specifically, it contains:
+     *
+     *            HMAC-256(EK_mac, .cbor KeysToMacStructure)
+     *
+     *        Where EK_mac is an ephemeral MAC key, found in ProtectedData (see below).  The MACed
+     *        data is the "tag" field of a COSE_Mac0 structure like:
+     *
+     *            MacedKeys = [                            ; COSE_Mac0
+     *                protected : bstr .cbor {
+     *                    1 : 5,                           ; Algorithm : HMAC-256
+     *                },
+     *                unprotected : {},
+     *                ; Payload is PublicKeys from keysToSign argument, in provided order.
+     *                payload: bstr .cbor [ * PublicKey ],
+     *                tag: bstr
+     *            ]
+     *
+     *            KeysToMacStructure = [
+     *                context : "MAC0",
+     *                protected : bstr .cbor { 1 : 5 },    ; Algorithm : HMAC-256
+     *                external_aad : bstr .size 0,
+     *                ; Payload is PublicKeys from keysToSign argument, in provided order.
+     *                payload : bstr .cbor [ * PublicKey ]
+     *            ]
+     */
+    byte[] generateCertificateRequest(in boolean testMode, in MacedPublicKey[] keysToSign,
+            in byte[] endpointEncryptionCertChain, in byte[] challenge, out DeviceInfo deviceInfo,
+            out ProtectedData protectedData);
+
+    /**
+     * generateCertificateRequestV2 creates a certificate signing request to be sent to the
+     * provisioning server.
+     *
+     * @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.
+     *
+     * @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
+     *        use different semantic data for this field, but the supported sizes must be between 32
+     *        and 64 bytes, inclusive.
+     *
+     * @return the following CBOR Certificate Signing Request (Csr) serialized into a byte array:
+     *
+     * Csr = AuthenticatedRequest<CsrPayload>
+     *
+     * CsrPayload = [                      ; CBOR Array defining the payload for Csr
+     *     version: 3,                     ; The CsrPayload CDDL Schema version.
+     *     CertificateType,                ; The type of certificate being requested.
+     *     DeviceInfo,                     ; Defined in DeviceInfo.aidl
+     *     KeysToSign,                     ; Provided by the method parameters
+     * ]
+     *
+     *  ; A tstr identifying the type of certificate. The set of supported certificate types may
+     *  ; be extended without requiring a version bump of the HAL. Custom certificate types may
+     *  ; be used, but the provisioning server may reject the request for an unknown certificate
+     *  ; type. The currently defined certificate types are:
+     *  ;  - "widevine"
+     *  ;  - "keymint"
+     *  CertificateType = tstr
+     *
+     * KeysToSign = [ * PublicKey ]   ; Please see MacedPublicKey.aidl for the PublicKey definition.
+     *
+     * AuthenticatedRequest<T> = [
+     *     version: 1,              ; The AuthenticatedRequest CDDL Schema version.
+     *     UdsCerts,
+     *     DiceCertChain,
+     *     SignedData<[
+     *         challenge: bstr .size (32..64), ; Provided by the method parameters
+     *         bstr .cbor T,
+     *     ]>,
+     * ]
+     *
+     * ; COSE_Sign1 (untagged)
+     * SignedData<Data> = [
+     *     protected: bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 },
+     *     unprotected: {},
+     *     payload: bstr .cbor Data / nil,
+     *     signature: bstr      ; PureEd25519(CDI_Leaf_Priv, bstr .cbor SignedDataSigStruct<Data>) /
+     *                          ; ECDSA(CDI_Leaf_Priv, bstr .cbor SignedDataSigStruct<Data>)
+     * ]
+     *
+     * ; Sig_structure for SignedData
+     * SignedDataSigStruct<Data> = [
+     *     context: "Signature1",
+     *     protected: bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 },
+     *     external_aad: bstr .size 0,
+     *     payload: bstr .cbor Data / nil,
+     * ]
+     *
+     * ; UdsCerts allows the platform to provide additional certifications for the UDS_Pub. For
+     * ; example, this could be provided by the hardware vendor, who certifies all of their chips.
+     * ; The SignerName is a free-form string describing who generated the signature. The root
+     * ; certificate will need to be communicated to the verifier out of band, along with the
+     * ; SignerName that is expected for the given root certificate.
+     * UdsCerts = {
+     *     * SignerName => UdsCertChain
+     * }
+     *
+     * ; SignerName is a string identifier that indicates both the signing authority as
+     * ; well as the format of the UdsCertChain
+     * SignerName = tstr
+     *
+     * UdsCertChain = [
+     *     2* X509Certificate       ; Root -> ... -> Leaf. "Root" is the vendor self-signed
+     *                              ; cert, "Leaf" contains UDS_Public. There may also be
+     *                              ; intermediate certificates between Root and Leaf.
+     * ]
+     *
+     * ; A bstr containing a DER-encoded X.509 certificate (RSA, NIST P-curve, or EdDSA)
+     * X509Certificate = bstr
+     *
+     * ; The DICE Chain contains measurements about the device firmware.
+     * ; The first entry in the DICE Chain is the UDS_Pub, encoded as a COSE_key. All entries
+     * ; after the first describe a link in the boot chain (e.g. bootloaders: BL1, BL2, ... BLN)
+     * ; Note that there is no DiceChainEntry for UDS_pub, only a "bare" COSE_key.
+     * DiceCertChain = [
+     *     PubKeyEd25519 / PubKeyECDSA256,  ; UDS_Pub
+     *     + DiceChainEntry,                ; First CDI_Certificate -> Last CDI_Certificate
+     *                                      ; Last certificate corresponds to KeyMint's DICE key.
+     * ]
+     *
+     * ; This is the signed payload for each entry in the DICE chain. Note that the "Configuration
+     * ; Input Values" described by the Open Profile are not used here. Instead, the DICE chain
+     * ; defines its own configuration values for the Configuration Descriptor field. See
+     * ; the Open Profile for DICE for more details on the fields. SHA256 and SHA512 are acceptable
+     * ; hash algorithms. The digest bstr values in the payload are the digest values without any
+     * ; padding. Note that for SHA256, this implies the digest bstr is 32 bytes. This is an
+     * ; intentional, minor deviation from Open Profile for DICE, which specifies all digests are
+     * ; 64 bytes.
+     * DiceChainEntryPayload = {                    ; CWT [RFC8392]
+     *     1 : tstr,                                ; Issuer
+     *     2 : tstr,                                ; Subject
+     *     -4670552 : bstr .cbor PubKeyEd25519 /
+     *                bstr .cbor PubKeyECDSA256,    ; Subject Public Key
+     *     -4670553 : bstr                          ; Key Usage
+     *
+     *     ; NOTE: All of the following fields may be omitted for a "Degenerate DICE Chain", as
+     *     ;       described above.
+     *     -4670545 : bstr,                         ; Code Hash
+     *     ? -4670546 : bstr,                       ; Code Descriptor
+     *     ? -4670547 : bstr,                       ; Configuration Hash
+     *     -4670548 : bstr .cbor {                  ; Configuration Descriptor
+     *         ? -70002 : tstr,                         ; Component name
+     *         ? -70003 : int,                          ; Firmware version
+     *         ? -70004 : null,                         ; Resettable
+     *     },
+     *     -4670549 : bstr,                         ; Authority Hash
+     *     ? -4670550 : bstr,                       ; Authority Descriptor
+     *     -4670551 : bstr,                         ; Mode
+     * }
+     *
+     * ; Each entry in the DICE chain is a DiceChainEntryPayload signed by the key from the previous
+     * ; entry in the DICE chain array.
+     * DiceChainEntry = [                            ; COSE_Sign1 (untagged)
+     *     protected : bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 },
+     *     unprotected: {},
+     *     payload: bstr .cbor DiceChainEntryPayload,
+     *     signature: bstr ; PureEd25519(SigningKey, bstr .cbor DiceChainEntryInput) /
+     *                     ; ECDSA(SigningKey, bstr .cbor DiceChainEntryInput)
+     *                     ; See RFC 8032 for details of how to encode the signature value
+     *                     ; for Ed25519.
+     * ]
+     *
+     * DiceChainEntryInput = [
+     *     context: "Signature1",
+     *     protected: bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 },
+     *     external_aad: bstr .size 0,
+     *     payload: bstr .cbor DiceChainEntryPayload
+     * ]
+     *
+     * ; 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
+     *     -1 : 6,                      ; Curve : Ed25519
+     *     -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
+     *     -1 : 1,                      ; Curve: P256
+     *     -2 : bstr,                   ; X coordinate
+     *     -3 : bstr                    ; Y coordinate
+     * }
+     *
+     * AlgorithmES256 = -7
+     * AlgorithmEdDSA = -8
+     */
+    byte[] generateCertificateRequestV2(in MacedPublicKey[] keysToSign, in byte[] challenge);
+}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/MacedPublicKey.aidl b/security/rkp/aidl/android/hardware/security/keymint/MacedPublicKey.aidl
similarity index 100%
rename from security/keymint/aidl/android/hardware/security/keymint/MacedPublicKey.aidl
rename to security/rkp/aidl/android/hardware/security/keymint/MacedPublicKey.aidl
diff --git a/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl b/security/rkp/aidl/android/hardware/security/keymint/ProtectedData.aidl
similarity index 100%
rename from security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl
rename to security/rkp/aidl/android/hardware/security/keymint/ProtectedData.aidl
diff --git a/security/rkp/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl b/security/rkp/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl
new file mode 100644
index 0000000..d0b059d
--- /dev/null
+++ b/security/rkp/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.security.keymint;
+
+/**
+ * RpcHardwareInfo is the hardware information returned by calling RemotelyProvisionedComponent
+ * getHardwareInfo()
+ * @hide
+ */
+@VintfStability
+@RustDerive(Clone=true, Eq=true, PartialEq=true, Ord=true, PartialOrd=true, Hash=true)
+parcelable RpcHardwareInfo {
+    const int CURVE_NONE = 0;
+    const int CURVE_P256 = 1;
+    const int CURVE_25519 = 2;
+
+    /**
+     * 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;
+
+    /**
+     * rpcAuthorName is the name of the author of the IRemotelyProvisionedComponent implementation
+     * (organization name, not individual). This name is implementation defined, so it can be used
+     * to distinguish between different implementations from the same author.
+     */
+    @utf8InCpp String 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
+     * if it's available. These values are defined as constants above.
+     *
+     * CURVE_NONE is made the default to help ensure that an implementor doesn't accidentally forget
+     * to provide the correct information here, as the VTS tests will check to make certain that
+     * a passing implementation does not provide CURVE_NONE.
+     */
+    int supportedEekCurve = CURVE_NONE;
+
+    /**
+     * uniqueId is an opaque identifier for this IRemotelyProvisionedComponent implementation. The
+     * client should NOT interpret the content of the identifier in any way. The client can only
+     * compare identifiers to determine if two IRemotelyProvisionedComponents share the same
+     * implementation. Each IRemotelyProvisionedComponent implementation must have a distinct
+     * identifier from all other implementations, and it must be consistent across all devices.
+     * It's critical that this identifier not be usable to uniquely identify a specific device.
+     *
+     * This identifier must be consistent across reboots, as it is used to store and track
+     * provisioned keys in a persistent, on-device database.
+     *
+     * uniqueId may not be empty, and must not be any longer than 32 characters.
+     *
+     * A recommended construction for this value is "[Vendor] [Component Name] [Major Version]",
+     * e.g. "Google Trusty KeyMint 1".
+     *
+     * This field was added in API version 2.
+     *
+     */
+    @nullable @utf8InCpp String uniqueId;
+
+    /**
+     * supportedNumKeysInCsr is the maximum number of keys in a CSR that this implementation can
+     * support. This value is implementation defined.
+     *
+     * From version 3 onwards, supportedNumKeysInCsr must be larger or equal to
+     * MIN_SUPPORTED_NUM_KEYS_IN_CSR.
+     *
+     * The default value was chosen as the value enforced by the VTS test in versions 1 and 2 of
+     * this interface.
+     */
+    const int MIN_SUPPORTED_NUM_KEYS_IN_CSR = 20;
+    int supportedNumKeysInCsr = 4;
+}
diff --git a/sensors/aidl/Android.bp b/sensors/aidl/Android.bp
index d04017c..9673190 100644
--- a/sensors/aidl/Android.bp
+++ b/sensors/aidl/Android.bp
@@ -11,6 +11,7 @@
     name: "android.hardware.sensors",
     vendor_available: true,
     srcs: ["android/hardware/sensors/*.aidl"],
+    host_supported: true,
     imports: [
         "android.hardware.common-V2",
         "android.hardware.common.fmq-V1",
diff --git a/sensors/aidl/convert/Android.bp b/sensors/aidl/convert/Android.bp
new file mode 100644
index 0000000..d47de8e
--- /dev/null
+++ b/sensors/aidl/convert/Android.bp
@@ -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 {
+    // 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.sensors-V1-convert",
+    vendor_available: true,
+    host_supported: true,
+    srcs: ["convert.cpp"],
+    export_include_dirs: ["include"],
+    shared_libs: [
+        "liblog",
+        "libcutils",
+        "libhardware",
+        "libbase",
+        "libutils",
+        "android.hardware.sensors-V1-ndk",
+    ],
+    local_include_dirs: ["include/aidl/sensors"],
+    export_shared_lib_headers: [
+        "libhardware",
+    ],
+}
diff --git a/sensors/aidl/convert/convert.cpp b/sensors/aidl/convert/convert.cpp
new file mode 100644
index 0000000..415f435
--- /dev/null
+++ b/sensors/aidl/convert/convert.cpp
@@ -0,0 +1,496 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/sensors/convert.h"
+#include "android-base/logging.h"
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace implementation {
+
+using aidl::android::hardware::sensors::AdditionalInfo;
+using aidl::android::hardware::sensors::DynamicSensorInfo;
+using aidl::android::hardware::sensors::Event;
+using aidl::android::hardware::sensors::ISensors;
+using aidl::android::hardware::sensors::SensorInfo;
+using aidl::android::hardware::sensors::SensorStatus;
+using aidl::android::hardware::sensors::SensorType;
+
+status_t convertToStatus(ndk::ScopedAStatus status) {
+    if (status.isOk()) {
+        return OK;
+    } else {
+        switch (status.getExceptionCode()) {
+            case EX_ILLEGAL_ARGUMENT: {
+                return BAD_VALUE;
+            }
+            case EX_SECURITY: {
+                return PERMISSION_DENIED;
+            }
+            case EX_UNSUPPORTED_OPERATION: {
+                return INVALID_OPERATION;
+            }
+            case EX_SERVICE_SPECIFIC: {
+                switch (status.getServiceSpecificError()) {
+                    case ISensors::ERROR_BAD_VALUE: {
+                        return BAD_VALUE;
+                    }
+                    case ISensors::ERROR_NO_MEMORY: {
+                        return NO_MEMORY;
+                    }
+                    default: {
+                        return UNKNOWN_ERROR;
+                    }
+                }
+            }
+            default: {
+                return UNKNOWN_ERROR;
+            }
+        }
+    }
+}
+
+void convertToSensor(const SensorInfo& src, sensor_t* dst) {
+    dst->name = strdup(src.name.c_str());
+    dst->vendor = strdup(src.vendor.c_str());
+    dst->version = src.version;
+    dst->handle = src.sensorHandle;
+    dst->type = (int)src.type;
+    dst->maxRange = src.maxRange;
+    dst->resolution = src.resolution;
+    dst->power = src.power;
+    dst->minDelay = src.minDelayUs;
+    dst->fifoReservedEventCount = src.fifoReservedEventCount;
+    dst->fifoMaxEventCount = src.fifoMaxEventCount;
+    dst->stringType = strdup(src.typeAsString.c_str());
+    dst->requiredPermission = strdup(src.requiredPermission.c_str());
+    dst->maxDelay = src.maxDelayUs;
+    dst->flags = src.flags;
+    dst->reserved[0] = dst->reserved[1] = 0;
+}
+
+void convertToSensorEvent(const Event& src, sensors_event_t* dst) {
+    *dst = {.version = sizeof(sensors_event_t),
+            .sensor = src.sensorHandle,
+            .type = (int32_t)src.sensorType,
+            .reserved0 = 0,
+            .timestamp = src.timestamp};
+
+    switch (src.sensorType) {
+        case SensorType::META_DATA: {
+            // Legacy HALs expect the handle reference in the meta data field.
+            // Copy it over from the handle of the event.
+            dst->meta_data.what = (int32_t)src.payload.get<Event::EventPayload::meta>().what;
+            dst->meta_data.sensor = src.sensorHandle;
+            // Set the sensor handle to 0 to maintain compatibility.
+            dst->sensor = 0;
+            break;
+        }
+
+        case SensorType::ACCELEROMETER:
+        case SensorType::MAGNETIC_FIELD:
+        case SensorType::ORIENTATION:
+        case SensorType::GYROSCOPE:
+        case SensorType::GRAVITY:
+        case SensorType::LINEAR_ACCELERATION: {
+            dst->acceleration.x = src.payload.get<Event::EventPayload::vec3>().x;
+            dst->acceleration.y = src.payload.get<Event::EventPayload::vec3>().y;
+            dst->acceleration.z = src.payload.get<Event::EventPayload::vec3>().z;
+            dst->acceleration.status = (int32_t)src.payload.get<Event::EventPayload::vec3>().status;
+            break;
+        }
+
+        case SensorType::GAME_ROTATION_VECTOR: {
+            dst->data[0] = src.payload.get<Event::EventPayload::vec4>().x;
+            dst->data[1] = src.payload.get<Event::EventPayload::vec4>().y;
+            dst->data[2] = src.payload.get<Event::EventPayload::vec4>().z;
+            dst->data[3] = src.payload.get<Event::EventPayload::vec4>().w;
+            break;
+        }
+
+        case SensorType::ROTATION_VECTOR:
+        case SensorType::GEOMAGNETIC_ROTATION_VECTOR: {
+            dst->data[0] = src.payload.get<Event::EventPayload::data>().values[0];
+            dst->data[1] = src.payload.get<Event::EventPayload::data>().values[1];
+            dst->data[2] = src.payload.get<Event::EventPayload::data>().values[2];
+            dst->data[3] = src.payload.get<Event::EventPayload::data>().values[3];
+            dst->data[4] = src.payload.get<Event::EventPayload::data>().values[4];
+            break;
+        }
+
+        case SensorType::MAGNETIC_FIELD_UNCALIBRATED:
+        case SensorType::GYROSCOPE_UNCALIBRATED:
+        case SensorType::ACCELEROMETER_UNCALIBRATED: {
+            dst->uncalibrated_gyro.x_uncalib = src.payload.get<Event::EventPayload::uncal>().x;
+            dst->uncalibrated_gyro.y_uncalib = src.payload.get<Event::EventPayload::uncal>().y;
+            dst->uncalibrated_gyro.z_uncalib = src.payload.get<Event::EventPayload::uncal>().z;
+            dst->uncalibrated_gyro.x_bias = src.payload.get<Event::EventPayload::uncal>().xBias;
+            dst->uncalibrated_gyro.y_bias = src.payload.get<Event::EventPayload::uncal>().yBias;
+            dst->uncalibrated_gyro.z_bias = src.payload.get<Event::EventPayload::uncal>().zBias;
+            break;
+        }
+
+        case SensorType::HINGE_ANGLE:
+        case SensorType::DEVICE_ORIENTATION:
+        case SensorType::LIGHT:
+        case SensorType::PRESSURE:
+        case SensorType::PROXIMITY:
+        case SensorType::RELATIVE_HUMIDITY:
+        case SensorType::AMBIENT_TEMPERATURE:
+        case SensorType::SIGNIFICANT_MOTION:
+        case SensorType::STEP_DETECTOR:
+        case SensorType::TILT_DETECTOR:
+        case SensorType::WAKE_GESTURE:
+        case SensorType::GLANCE_GESTURE:
+        case SensorType::PICK_UP_GESTURE:
+        case SensorType::WRIST_TILT_GESTURE:
+        case SensorType::STATIONARY_DETECT:
+        case SensorType::MOTION_DETECT:
+        case SensorType::HEART_BEAT:
+        case SensorType::LOW_LATENCY_OFFBODY_DETECT: {
+            dst->data[0] = src.payload.get<Event::EventPayload::scalar>();
+            break;
+        }
+
+        case SensorType::STEP_COUNTER: {
+            dst->u64.step_counter = src.payload.get<Event::EventPayload::stepCount>();
+            break;
+        }
+
+        case SensorType::HEART_RATE: {
+            dst->heart_rate.bpm = src.payload.get<Event::EventPayload::heartRate>().bpm;
+            dst->heart_rate.status =
+                    (int8_t)src.payload.get<Event::EventPayload::heartRate>().status;
+            break;
+        }
+
+        case SensorType::POSE_6DOF: {  // 15 floats
+            for (size_t i = 0; i < 15; ++i) {
+                dst->data[i] = src.payload.get<Event::EventPayload::pose6DOF>().values[i];
+            }
+            break;
+        }
+
+        case SensorType::DYNAMIC_SENSOR_META: {
+            dst->dynamic_sensor_meta.connected =
+                    src.payload.get<Event::EventPayload::dynamic>().connected;
+            dst->dynamic_sensor_meta.handle =
+                    src.payload.get<Event::EventPayload::dynamic>().sensorHandle;
+            dst->dynamic_sensor_meta.sensor = NULL;  // to be filled in later
+
+            memcpy(dst->dynamic_sensor_meta.uuid,
+                   src.payload.get<Event::EventPayload::dynamic>().uuid.values.data(), 16);
+
+            break;
+        }
+
+        case SensorType::ADDITIONAL_INFO: {
+            const AdditionalInfo& srcInfo = src.payload.get<Event::EventPayload::additional>();
+
+            additional_info_event_t* dstInfo = &dst->additional_info;
+            dstInfo->type = (int32_t)srcInfo.type;
+            dstInfo->serial = srcInfo.serial;
+
+            switch (srcInfo.payload.getTag()) {
+                case AdditionalInfo::AdditionalInfoPayload::Tag::dataInt32: {
+                    const auto& values =
+                            srcInfo.payload.get<AdditionalInfo::AdditionalInfoPayload::dataInt32>()
+                                    .values;
+                    CHECK_EQ(values.size() * sizeof(int32_t), sizeof(dstInfo->data_int32));
+                    memcpy(dstInfo->data_int32, values.data(), sizeof(dstInfo->data_int32));
+                    break;
+                }
+                case AdditionalInfo::AdditionalInfoPayload::Tag::dataFloat: {
+                    const auto& values =
+                            srcInfo.payload.get<AdditionalInfo::AdditionalInfoPayload::dataFloat>()
+                                    .values;
+                    CHECK_EQ(values.size() * sizeof(float), sizeof(dstInfo->data_float));
+                    memcpy(dstInfo->data_float, values.data(), sizeof(dstInfo->data_float));
+                    break;
+                }
+                default: {
+                    LOG(ERROR) << "Invalid sensor additional info tag: ",
+                            (int)srcInfo.payload.getTag();
+                }
+            }
+            break;
+        }
+
+        case SensorType::HEAD_TRACKER: {
+            const auto& ht = src.payload.get<Event::EventPayload::headTracker>();
+            dst->head_tracker.rx = ht.rx;
+            dst->head_tracker.ry = ht.ry;
+            dst->head_tracker.rz = ht.rz;
+            dst->head_tracker.vx = ht.vx;
+            dst->head_tracker.vy = ht.vy;
+            dst->head_tracker.vz = ht.vz;
+            dst->head_tracker.discontinuity_count = ht.discontinuityCount;
+            break;
+        }
+
+        case SensorType::ACCELEROMETER_LIMITED_AXES:
+        case SensorType::GYROSCOPE_LIMITED_AXES:
+            dst->limited_axes_imu.x = src.payload.get<Event::EventPayload::limitedAxesImu>().x;
+            dst->limited_axes_imu.y = src.payload.get<Event::EventPayload::limitedAxesImu>().y;
+            dst->limited_axes_imu.z = src.payload.get<Event::EventPayload::limitedAxesImu>().z;
+            dst->limited_axes_imu.x_supported =
+                    src.payload.get<Event::EventPayload::limitedAxesImu>().xSupported;
+            dst->limited_axes_imu.y_supported =
+                    src.payload.get<Event::EventPayload::limitedAxesImu>().ySupported;
+            dst->limited_axes_imu.z_supported =
+                    src.payload.get<Event::EventPayload::limitedAxesImu>().zSupported;
+            break;
+
+        case SensorType::ACCELEROMETER_LIMITED_AXES_UNCALIBRATED:
+        case SensorType::GYROSCOPE_LIMITED_AXES_UNCALIBRATED:
+            dst->limited_axes_imu_uncalibrated.x_uncalib =
+                    src.payload.get<Event::EventPayload::limitedAxesImuUncal>().x;
+            dst->limited_axes_imu_uncalibrated.y_uncalib =
+                    src.payload.get<Event::EventPayload::limitedAxesImuUncal>().y;
+            dst->limited_axes_imu_uncalibrated.z_uncalib =
+                    src.payload.get<Event::EventPayload::limitedAxesImuUncal>().z;
+            dst->limited_axes_imu_uncalibrated.x_bias =
+                    src.payload.get<Event::EventPayload::limitedAxesImuUncal>().xBias;
+            dst->limited_axes_imu_uncalibrated.y_bias =
+                    src.payload.get<Event::EventPayload::limitedAxesImuUncal>().yBias;
+            dst->limited_axes_imu_uncalibrated.z_bias =
+                    src.payload.get<Event::EventPayload::limitedAxesImuUncal>().zBias;
+            dst->limited_axes_imu_uncalibrated.x_supported =
+                    src.payload.get<Event::EventPayload::limitedAxesImuUncal>().xSupported;
+            dst->limited_axes_imu_uncalibrated.y_supported =
+                    src.payload.get<Event::EventPayload::limitedAxesImuUncal>().ySupported;
+            dst->limited_axes_imu_uncalibrated.z_supported =
+                    src.payload.get<Event::EventPayload::limitedAxesImuUncal>().zSupported;
+            break;
+
+        case SensorType::HEADING:
+            dst->heading.heading = src.payload.get<Event::EventPayload::heading>().heading;
+            dst->heading.accuracy = src.payload.get<Event::EventPayload::heading>().accuracy;
+            break;
+
+        default: {
+            CHECK_GE((int32_t)src.sensorType, (int32_t)SensorType::DEVICE_PRIVATE_BASE);
+
+            memcpy(dst->data, src.payload.get<Event::EventPayload::data>().values.data(),
+                   16 * sizeof(float));
+            break;
+        }
+    }
+}
+
+void convertFromSensorEvent(const sensors_event_t& src, Event* dst) {
+    *dst = {
+            .timestamp = src.timestamp,
+            .sensorHandle = src.sensor,
+            .sensorType = (SensorType)src.type,
+    };
+
+    switch (dst->sensorType) {
+        case SensorType::META_DATA: {
+            Event::EventPayload::MetaData meta;
+            meta.what = (Event::EventPayload::MetaData::MetaDataEventType)src.meta_data.what;
+            // Legacy HALs contain the handle reference in the meta data field.
+            // Copy that over to the handle of the event. In legacy HALs this
+            // field was expected to be 0.
+            dst->sensorHandle = src.meta_data.sensor;
+            dst->payload.set<Event::EventPayload::Tag::meta>(meta);
+            break;
+        }
+
+        case SensorType::ACCELEROMETER:
+        case SensorType::MAGNETIC_FIELD:
+        case SensorType::ORIENTATION:
+        case SensorType::GYROSCOPE:
+        case SensorType::GRAVITY:
+        case SensorType::LINEAR_ACCELERATION: {
+            Event::EventPayload::Vec3 vec3;
+            vec3.x = src.acceleration.x;
+            vec3.y = src.acceleration.y;
+            vec3.z = src.acceleration.z;
+            vec3.status = (SensorStatus)src.acceleration.status;
+            dst->payload.set<Event::EventPayload::Tag::vec3>(vec3);
+            break;
+        }
+
+        case SensorType::GAME_ROTATION_VECTOR: {
+            Event::EventPayload::Vec4 vec4;
+            vec4.x = src.data[0];
+            vec4.y = src.data[1];
+            vec4.z = src.data[2];
+            vec4.w = src.data[3];
+            dst->payload.set<Event::EventPayload::Tag::vec4>(vec4);
+            break;
+        }
+
+        case SensorType::ROTATION_VECTOR:
+        case SensorType::GEOMAGNETIC_ROTATION_VECTOR: {
+            Event::EventPayload::Data data;
+            memcpy(data.values.data(), src.data, 5 * sizeof(float));
+            dst->payload.set<Event::EventPayload::Tag::data>(data);
+            break;
+        }
+
+        case SensorType::MAGNETIC_FIELD_UNCALIBRATED:
+        case SensorType::GYROSCOPE_UNCALIBRATED:
+        case SensorType::ACCELEROMETER_UNCALIBRATED: {
+            Event::EventPayload::Uncal uncal;
+            uncal.x = src.uncalibrated_gyro.x_uncalib;
+            uncal.y = src.uncalibrated_gyro.y_uncalib;
+            uncal.z = src.uncalibrated_gyro.z_uncalib;
+            uncal.xBias = src.uncalibrated_gyro.x_bias;
+            uncal.yBias = src.uncalibrated_gyro.y_bias;
+            uncal.zBias = src.uncalibrated_gyro.z_bias;
+            dst->payload.set<Event::EventPayload::Tag::uncal>(uncal);
+            break;
+        }
+
+        case SensorType::DEVICE_ORIENTATION:
+        case SensorType::LIGHT:
+        case SensorType::PRESSURE:
+        case SensorType::PROXIMITY:
+        case SensorType::RELATIVE_HUMIDITY:
+        case SensorType::AMBIENT_TEMPERATURE:
+        case SensorType::SIGNIFICANT_MOTION:
+        case SensorType::STEP_DETECTOR:
+        case SensorType::TILT_DETECTOR:
+        case SensorType::WAKE_GESTURE:
+        case SensorType::GLANCE_GESTURE:
+        case SensorType::PICK_UP_GESTURE:
+        case SensorType::WRIST_TILT_GESTURE:
+        case SensorType::STATIONARY_DETECT:
+        case SensorType::MOTION_DETECT:
+        case SensorType::HEART_BEAT:
+        case SensorType::LOW_LATENCY_OFFBODY_DETECT:
+        case SensorType::HINGE_ANGLE: {
+            dst->payload.set<Event::EventPayload::Tag::scalar>((float)src.data[0]);
+            break;
+        }
+
+        case SensorType::STEP_COUNTER: {
+            dst->payload.set<Event::EventPayload::Tag::stepCount>(src.u64.step_counter);
+            break;
+        }
+
+        case SensorType::HEART_RATE: {
+            Event::EventPayload::HeartRate heartRate;
+            heartRate.bpm = src.heart_rate.bpm;
+            heartRate.status = (SensorStatus)src.heart_rate.status;
+            dst->payload.set<Event::EventPayload::Tag::heartRate>(heartRate);
+            break;
+        }
+
+        case SensorType::POSE_6DOF: {  // 15 floats
+            Event::EventPayload::Pose6Dof pose6DOF;
+            for (size_t i = 0; i < 15; ++i) {
+                pose6DOF.values[i] = src.data[i];
+            }
+            dst->payload.set<Event::EventPayload::Tag::pose6DOF>(pose6DOF);
+            break;
+        }
+
+        case SensorType::DYNAMIC_SENSOR_META: {
+            DynamicSensorInfo dynamic;
+            dynamic.connected = src.dynamic_sensor_meta.connected;
+            dynamic.sensorHandle = src.dynamic_sensor_meta.handle;
+
+            memcpy(dynamic.uuid.values.data(), src.dynamic_sensor_meta.uuid, 16);
+            dst->payload.set<Event::EventPayload::Tag::dynamic>(dynamic);
+            break;
+        }
+
+        case SensorType::ADDITIONAL_INFO: {
+            AdditionalInfo info;
+            const additional_info_event_t& srcInfo = src.additional_info;
+            info.type = (AdditionalInfo::AdditionalInfoType)srcInfo.type;
+            info.serial = srcInfo.serial;
+
+            AdditionalInfo::AdditionalInfoPayload::Int32Values data;
+            CHECK_EQ(data.values.size() * sizeof(int32_t), sizeof(srcInfo.data_int32));
+            memcpy(data.values.data(), srcInfo.data_int32, sizeof(srcInfo.data_int32));
+            info.payload.set<AdditionalInfo::AdditionalInfoPayload::Tag::dataInt32>(data);
+
+            dst->payload.set<Event::EventPayload::Tag::additional>(info);
+            break;
+        }
+
+        case SensorType::HEAD_TRACKER: {
+            Event::EventPayload::HeadTracker headTracker;
+            headTracker.rx = src.head_tracker.rx;
+            headTracker.ry = src.head_tracker.ry;
+            headTracker.rz = src.head_tracker.rz;
+            headTracker.vx = src.head_tracker.vx;
+            headTracker.vy = src.head_tracker.vy;
+            headTracker.vz = src.head_tracker.vz;
+            headTracker.discontinuityCount = src.head_tracker.discontinuity_count;
+
+            dst->payload.set<Event::EventPayload::Tag::headTracker>(headTracker);
+            break;
+        }
+
+        case SensorType::ACCELEROMETER_LIMITED_AXES:
+        case SensorType::GYROSCOPE_LIMITED_AXES: {
+            Event::EventPayload::LimitedAxesImu limitedAxesImu;
+            limitedAxesImu.x = src.limited_axes_imu.x;
+            limitedAxesImu.y = src.limited_axes_imu.y;
+            limitedAxesImu.z = src.limited_axes_imu.z;
+            limitedAxesImu.xSupported = src.limited_axes_imu.x_supported;
+            limitedAxesImu.ySupported = src.limited_axes_imu.y_supported;
+            limitedAxesImu.zSupported = src.limited_axes_imu.z_supported;
+            dst->payload.set<Event::EventPayload::Tag::limitedAxesImu>(limitedAxesImu);
+            break;
+        }
+
+        case SensorType::ACCELEROMETER_LIMITED_AXES_UNCALIBRATED:
+        case SensorType::GYROSCOPE_LIMITED_AXES_UNCALIBRATED: {
+            Event::EventPayload::LimitedAxesImuUncal limitedAxesImuUncal;
+            limitedAxesImuUncal.x = src.limited_axes_imu_uncalibrated.x_uncalib;
+            limitedAxesImuUncal.y = src.limited_axes_imu_uncalibrated.y_uncalib;
+            limitedAxesImuUncal.z = src.limited_axes_imu_uncalibrated.z_uncalib;
+            limitedAxesImuUncal.xBias = src.limited_axes_imu_uncalibrated.x_bias;
+            limitedAxesImuUncal.yBias = src.limited_axes_imu_uncalibrated.y_bias;
+            limitedAxesImuUncal.yBias = src.limited_axes_imu_uncalibrated.y_bias;
+            limitedAxesImuUncal.zBias = src.limited_axes_imu_uncalibrated.z_bias;
+            limitedAxesImuUncal.xSupported = src.limited_axes_imu_uncalibrated.x_supported;
+            limitedAxesImuUncal.ySupported = src.limited_axes_imu_uncalibrated.y_supported;
+            limitedAxesImuUncal.zSupported = src.limited_axes_imu_uncalibrated.z_supported;
+            dst->payload.set<Event::EventPayload::Tag::limitedAxesImuUncal>(limitedAxesImuUncal);
+            break;
+        }
+
+        case SensorType::HEADING: {
+            Event::EventPayload::Heading heading;
+            heading.heading = src.heading.heading;
+            heading.accuracy = src.heading.accuracy;
+            dst->payload.set<Event::EventPayload::heading>(heading);
+            break;
+        }
+
+        default: {
+            CHECK_GE((int32_t)dst->sensorType, (int32_t)SensorType::DEVICE_PRIVATE_BASE);
+
+            Event::EventPayload::Data data;
+            memcpy(data.values.data(), src.data, 16 * sizeof(float));
+            dst->payload.set<Event::EventPayload::Tag::data>(data);
+            break;
+        }
+    }
+}
+
+}  // namespace implementation
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
diff --git a/sensors/aidl/convert/include/aidl/sensors/convert.h b/sensors/aidl/convert/include/aidl/sensors/convert.h
new file mode 100644
index 0000000..702b226
--- /dev/null
+++ b/sensors/aidl/convert/include/aidl/sensors/convert.h
@@ -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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/sensors/ISensors.h>
+#include <hardware/sensors.h>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace implementation {
+
+status_t convertToStatus(ndk::ScopedAStatus status);
+void convertToSensor(const aidl::android::hardware::sensors::SensorInfo& src, sensor_t* dst);
+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);
+
+}  // namespace implementation
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
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/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/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/thermal/OWNERS b/thermal/OWNERS
new file mode 100644
index 0000000..7229b22
--- /dev/null
+++ b/thermal/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 826709
+
+# ADPF virtual team
+lpy@google.com
+wvw@google.com
diff --git a/thermal/aidl/Android.bp b/thermal/aidl/Android.bp
new file mode 100644
index 0000000..b132746
--- /dev/null
+++ b/thermal/aidl/Android.bp
@@ -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 {
+    // 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.thermal",
+    vendor_available: true,
+    srcs: [
+        "android/hardware/thermal/*.aidl",
+    ],
+    stability: "vintf",
+    backend: {
+        cpp: {
+            enabled: true,
+        },
+        java: {
+            platform_apis: true,
+        },
+    },
+}
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
new file mode 100644
index 0000000..50be508
--- /dev/null
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingDevice.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
+ *
+1 *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.thermal;
+@VintfStability
+parcelable CoolingDevice {
+  android.hardware.thermal.CoolingType type;
+  String name;
+  long value;
+}
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
new file mode 100644
index 0000000..57c8939
--- /dev/null
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingType.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.thermal;
+@Backing(type="int") @VintfStability
+enum CoolingType {
+  FAN = 0,
+  BATTERY = 1,
+  CPU = 2,
+  GPU = 3,
+  MODEM = 4,
+  NPU = 5,
+  COMPONENT = 6,
+  TPU = 7,
+  POWER_AMPLIFIER = 8,
+  DISPLAY = 9,
+  SPEAKER = 10,
+}
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
new file mode 100644
index 0000000..0aed5ec
--- /dev/null
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermal.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.thermal;
+@VintfStability
+interface IThermal {
+  android.hardware.thermal.CoolingDevice[] getCoolingDevices();
+  android.hardware.thermal.CoolingDevice[] getCoolingDevicesWithType(in android.hardware.thermal.CoolingType type);
+  android.hardware.thermal.Temperature[] getTemperatures();
+  android.hardware.thermal.Temperature[] getTemperaturesWithType(in android.hardware.thermal.TemperatureType type);
+  android.hardware.thermal.TemperatureThreshold[] getTemperatureThresholds();
+  android.hardware.thermal.TemperatureThreshold[] getTemperatureThresholdsWithType(in android.hardware.thermal.TemperatureType type);
+  void registerThermalChangedCallback(in android.hardware.thermal.IThermalChangedCallback callback);
+  void registerThermalChangedCallbackWithType(in android.hardware.thermal.IThermalChangedCallback callback, in android.hardware.thermal.TemperatureType type);
+  void unregisterThermalChangedCallback(in android.hardware.thermal.IThermalChangedCallback callback);
+}
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
new file mode 100644
index 0000000..6b3f922
--- /dev/null
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermalChangedCallback.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.thermal;
+@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
new file mode 100644
index 0000000..7156415
--- /dev/null
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/Temperature.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.thermal;
+@VintfStability
+parcelable Temperature {
+  android.hardware.thermal.TemperatureType type;
+  String name;
+  float value;
+  android.hardware.thermal.ThrottlingSeverity throttlingStatus;
+}
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
new file mode 100644
index 0000000..6da561f
--- /dev/null
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/TemperatureThreshold.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.thermal;
+@VintfStability
+parcelable TemperatureThreshold {
+  android.hardware.thermal.TemperatureType type;
+  String name;
+  float[] hotThrottlingThresholds;
+  float[] coldThrottlingThresholds;
+}
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
new file mode 100644
index 0000000..c6a08c1
--- /dev/null
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/TemperatureType.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.thermal;
+@Backing(type="int") @VintfStability
+enum TemperatureType {
+  UNKNOWN = -1,
+  CPU = 0,
+  GPU = 1,
+  BATTERY = 2,
+  SKIN = 3,
+  USB_PORT = 4,
+  POWER_AMPLIFIER = 5,
+  BCL_VOLTAGE = 6,
+  BCL_CURRENT = 7,
+  BCL_PERCENTAGE = 8,
+  NPU = 9,
+  TPU = 10,
+  DISPLAY = 11,
+  MODEM = 12,
+  SOC = 13,
+}
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
new file mode 100644
index 0000000..e86b581
--- /dev/null
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/ThrottlingSeverity.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.thermal;
+@Backing(type="int") @VintfStability
+enum ThrottlingSeverity {
+  NONE = 0,
+  LIGHT = 1,
+  MODERATE = 2,
+  SEVERE = 3,
+  CRITICAL = 4,
+  EMERGENCY = 5,
+  SHUTDOWN = 6,
+}
diff --git a/thermal/aidl/android/hardware/thermal/CoolingDevice.aidl b/thermal/aidl/android/hardware/thermal/CoolingDevice.aidl
new file mode 100644
index 0000000..6d974a5
--- /dev/null
+++ b/thermal/aidl/android/hardware/thermal/CoolingDevice.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
+ *
+1 *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.thermal;
+
+import android.hardware.thermal.CoolingType;
+
+@VintfStability
+parcelable CoolingDevice {
+    /**
+     * This cooling device type, CPU, GPU, BATTERY, and etc.
+     */
+    CoolingType type;
+    /**
+     * Name of this cooling device.
+     * All cooling devices of the same "type" must have a different "name".
+     * The name is usually defined in kernel device tree, and this is for client
+     * logging purpose.
+     */
+    String name;
+    /**
+     * Current throttle state of the cooling device. The value can any unsigned integer
+     * numbers between 0 and max_state defined in its driver, usually representing the
+     * associated device's power state. 0 means device is not in throttling, higher value
+     * means deeper throttling.
+     */
+    long value;
+}
diff --git a/thermal/aidl/android/hardware/thermal/CoolingType.aidl b/thermal/aidl/android/hardware/thermal/CoolingType.aidl
new file mode 100644
index 0000000..1b430d2
--- /dev/null
+++ b/thermal/aidl/android/hardware/thermal/CoolingType.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.thermal;
+
+/**
+ * Device cooling device types
+ */
+@VintfStability
+@Backing(type="int")
+enum CoolingType {
+    FAN,
+    BATTERY,
+    CPU,
+    GPU,
+    MODEM,
+    NPU,
+    COMPONENT,
+    TPU,
+    POWER_AMPLIFIER,
+    DISPLAY,
+    SPEAKER,
+}
diff --git a/thermal/aidl/android/hardware/thermal/IThermal.aidl b/thermal/aidl/android/hardware/thermal/IThermal.aidl
new file mode 100644
index 0000000..8b79cb4
--- /dev/null
+++ b/thermal/aidl/android/hardware/thermal/IThermal.aidl
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.thermal;
+
+import android.hardware.thermal.CoolingDevice;
+import android.hardware.thermal.CoolingType;
+import android.hardware.thermal.IThermalChangedCallback;
+import android.hardware.thermal.Temperature;
+import android.hardware.thermal.TemperatureThreshold;
+import android.hardware.thermal.TemperatureType;
+
+@VintfStability
+interface IThermal {
+    /**
+     * Retrieves the cooling devices information.
+     *
+     * @return devices If succeed, it's filled with the
+     *    current cooling device information. The order of built-in cooling
+     *    devices in the list must be kept the same regardless the number
+     *    of calls to this method even if they go offline, if these devices
+     *    exist on boot. The method always returns and never removes from
+     *    the list such cooling devices.
+     *
+     * @throws ScopedAStatus Status of the operation. If status code is not
+     *    STATUS_OK, getMessage() must be populated with the human-readable
+     *    error message.
+     */
+    CoolingDevice[] getCoolingDevices();
+
+    /**
+     * Retrieves the cooling devices information of a given CoolingType.
+     *
+     * @param type the CoolingDevice such as CPU/GPU.
+     *
+     * @return devices If succeed, it's filled with the current
+     *    cooling device information. The order of built-in cooling
+     *    devices in the list must be kept the same regardless of the number
+     *    of calls to this method even if they go offline, if these devices
+     *    exist on boot. The method always returns and never removes from
+     *    the list such cooling devices.
+     *
+     * @throws ScopedAStatus Status of the operation. If status code is not
+     *    STATUS_OK, the getMessage() must be populated with the human-readable
+     *    error message.
+     */
+    CoolingDevice[] getCoolingDevicesWithType(in CoolingType type);
+
+    /**
+     * Retrieves temperatures in Celsius.
+     *
+     * @return temperatures If succeed, it's filled with the
+     *    current temperatures. The order of temperatures of built-in
+     *    devices (such as CPUs, GPUs and etc.) in the list must be kept
+     *    the same regardless the number of calls to this method even if
+     *    they go offline, if these devices exist on boot. The method
+     *    always returns and never removes such temperatures.
+     *
+     * @throws ScopedAStatus Status of the operation. If status code is not
+     *    STATUS_OK, the getMessage() must be populated with the human-readable
+     *    error message.
+     */
+    Temperature[] getTemperatures();
+
+    /**
+     * Retrieves temperatures in Celsius with a given TemperatureType.
+     *
+     * @param type the TemperatureType such as battery or skin.
+     *
+     * @return temperatures If succeed, it's filled with the
+     *    current temperatures. The order of temperatures of built-in
+     *    devices (such as CPUs, GPUs and etc.) in the list must be kept
+     *    the same regardless of the number of calls to this method even if
+     *    they go offline, if these devices exist on boot. The method
+     *    always returns and never removes such temperatures.
+     *
+     * @throws ScopedAStatus Status of the operation. If status code is not
+     *    STATUS_OK, the getMessage() must be populated with the human-readable
+     *    error message.
+     */
+    Temperature[] getTemperaturesWithType(in TemperatureType type);
+
+    /**
+     * Retrieves static temperature thresholds in Celsius.
+     *
+     * @return temperatureThresholds If succeed, it's filled with the
+     *    temperatures thresholds. The order of temperatures of built-in
+     *    devices (such as CPUs, GPUs and etc.) in the list must be kept
+     *    the same regardless of the number of calls to this method even if
+     *    they go offline, if these devices exist on boot. The method
+     *    always returns and never removes such temperatures. The thresholds
+     *    are returned as static values and must not change across calls. The actual
+     *    throttling state is determined in device thermal mitigation policy/agorithm
+     *    which might not be simple thresholds so these values Thermal HAL provided
+     *    may not be accurate to detemin the throttling status. To get accurate
+     *    throttling status, use getTemperatures or registerThermalChangedCallback
+     *    and listen to the callback.
+     *
+     * @throws ScopedAStatus Status of the operation. If status code is not
+     *    STATUS_OK, the getMessage() must be populated with the human-readable
+     *    error message.
+     */
+    TemperatureThreshold[] getTemperatureThresholds();
+
+    /**
+     * Retrieves static temperature thresholds in Celsius of a given temperature
+     * type.
+     *
+     * @param type the TemperatureType such as battery or skin.
+     *
+     * @return temperatureThresholds If succeed, it's filled with the
+     *    temperatures thresholds. The order of temperatures of built-in
+     *    devices (such as CPUs, GPUs and etc.) in the list must be kept
+     *    the same regardless of the number of calls to this method even if
+     *    they go offline, if these devices exist on boot. The method
+     *    always returns and never removes such temperatures. The thresholds
+     *    are returned as static values and must not change across calls. The actual
+     *    throttling state is determined in device thermal mitigation policy/agorithm
+     *    which might not be simple thresholds so these values Thermal HAL provided
+     *    may not be accurate to detemin the throttling status. To get accurate
+     *    throttling status, use getTemperatures or registerThermalChangedCallback
+     *    and listen to the callback.
+     *
+     * @throws ScopedAStatus Status of the operation. If status code is not
+     *    STATUS_OK, the getMessage() must be populated with the human-readable
+     *    error message.
+     */
+    TemperatureThreshold[] getTemperatureThresholdsWithType(in TemperatureType type);
+
+    /**
+     * Register an IThermalChangedCallback, used by the Thermal HAL to receive
+     * thermal events when thermal mitigation status changed.
+     * Multiple registrations with different IThermalChangedCallback must be allowed.
+     * Multiple registrations with same IThermalChangedCallback is not allowed, client
+     * should unregister the given IThermalChangedCallback first.
+     *
+     * @param callback the IThermalChangedCallback to use for receiving
+     *    thermal events. if nullptr callback is given, the status code will be
+     *    STATUS_BAD_VALUE and the operation will fail.
+     *
+     * @throws ScopedAStatus Status of the operation. If status code is not
+     *    STATUS_OK, the getMessage() must be populated with the human-readable
+     *    error message. If callback is given nullptr, the returned status code
+     *    will be STATUS_BAD_VALUE and the exception will be EX_ILLEGAL_ARGUMENT.
+     *    if callback is already registered, the returned status code will be
+     *    STATUS_INVALID_OPERATION, the exception will be EX_ILLEGAL_ARGUMENT.
+     */
+    void registerThermalChangedCallback(in IThermalChangedCallback callback);
+
+    /**
+     * Register an IThermalChangedCallback for a given TemperatureType, used by
+     * the Thermal HAL to receive thermal events when thermal mitigation status
+     * changed.
+     * Multiple registrations with different IThermalChangedCallback must be allowed.
+     * Multiple registrations with same IThermalChangedCallback is not allowed, client
+     * should unregister the given IThermalChangedCallback first.
+     *
+     * @param callback the IThermalChangedCallback to use for receiving
+     *    thermal events. if nullptr callback is given, the status code will be
+     *    STATUS_BAD_VALUE and the operation will fail.
+     * @param type the type to be filtered.
+     *
+     * @throws ScopedAStatus Status of the operation. If status code is not
+     *    STATUS_OK, the getMessage() must be populated with the human-readable
+     *    error message. If callback is given nullptr, the returned status code
+     *    will be STATUS_BAD_VALUE and the exception will be EX_ILLEGAL_ARGUMENT.
+     *    if callback is already registered, the returned status code will be
+     *    STATUS_INVALID_OPERATION, the exception will be EX_ILLEGAL_ARGUMENT.
+     */
+    void registerThermalChangedCallbackWithType(
+            in IThermalChangedCallback callback, in TemperatureType type);
+
+    /**
+     * Unregister an IThermalChangedCallback, used by the Thermal HAL
+     * to receive thermal events when thermal mitigation status changed.
+     *
+     * @param callback the IThermalChangedCallback to use for receiving
+     *    thermal events. if nullptr callback is given, the status code will be
+     *    STATUS_BAD_VALUE and the operation will fail.
+     *
+     * @throws ScopedAStatus Status of the operation. If status code is not
+     *    STATUS_OK, the getMessage() must be populated with the human-readable
+     *    error message. If callback is given nullptr, the returned status code
+     *    will be STATUS_BAD_VALUE and the exception will be EX_ILLEGAL_ARGUMENT.
+     *    if callback is not registered, the returned status code will be
+     *    STATUS_INVALID_OPERATION, the exception will be EX_ILLEGAL_ARGUMENT.
+     */
+    void unregisterThermalChangedCallback(in IThermalChangedCallback callback);
+}
diff --git a/thermal/aidl/android/hardware/thermal/IThermalChangedCallback.aidl b/thermal/aidl/android/hardware/thermal/IThermalChangedCallback.aidl
new file mode 100644
index 0000000..6fe2dac
--- /dev/null
+++ b/thermal/aidl/android/hardware/thermal/IThermalChangedCallback.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.
+ */
+
+package android.hardware.thermal;
+
+import android.hardware.thermal.Temperature;
+
+/**
+ * IThermalChangedCallback send throttling notification to clients.
+ */
+@VintfStability
+interface IThermalChangedCallback {
+    /**
+     * Send a thermal throttling event to all ThermalHAL
+     * thermal event listeners.
+     *
+     * @param temperature The temperature associated with the
+     *    throttling event.
+     */
+    oneway void notifyThrottling(in Temperature temperature);
+}
diff --git a/thermal/aidl/android/hardware/thermal/Temperature.aidl b/thermal/aidl/android/hardware/thermal/Temperature.aidl
new file mode 100644
index 0000000..f0041ed
--- /dev/null
+++ b/thermal/aidl/android/hardware/thermal/Temperature.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.
+ */
+
+package android.hardware.thermal;
+
+import android.hardware.thermal.TemperatureType;
+import android.hardware.thermal.ThrottlingSeverity;
+
+@VintfStability
+parcelable Temperature {
+    /**
+     * This temperature's type.
+     */
+    TemperatureType type;
+    /**
+     * Name of this temperature matching the TemperatureThreshold.
+     * All temperatures of the same "type" must have a different "name",
+     * e.g., cpu0, battery. Clients use it to match with TemperatureThreshold
+     * struct.
+     */
+    String name;
+    /**
+     * For BCL, this is the current reading of the virtual sensor and the unit is
+     * millivolt, milliamp, percentage for BCL_VOLTAGE, BCL_CURRENT and BCL_PERCENTAGE
+     * respectively. For everything else, this is the current temperature in Celsius.
+     * If not available set by HAL to NAN.
+     */
+    float value;
+    /**
+     * The current throttling level of the sensor.
+     */
+    ThrottlingSeverity throttlingStatus;
+}
diff --git a/thermal/aidl/android/hardware/thermal/TemperatureThreshold.aidl b/thermal/aidl/android/hardware/thermal/TemperatureThreshold.aidl
new file mode 100644
index 0000000..9ecdab3
--- /dev/null
+++ b/thermal/aidl/android/hardware/thermal/TemperatureThreshold.aidl
@@ -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.
+ */
+
+package android.hardware.thermal;
+
+import android.hardware.thermal.TemperatureType;
+
+@VintfStability
+parcelable TemperatureThreshold {
+    /**
+     * This temperature's type.
+     */
+    TemperatureType type;
+    /**
+     * Name of this temperature matching the Temperature struct.
+     * All temperatures of the same "type" must have a different "name",
+     * e.g., cpu0, battery. Clients use it to match Temperature struct.
+     */
+    String name;
+    /**
+     * Hot throttling temperature constant for this temperature sensor in
+     * level defined in ThrottlingSeverity including shutdown. Throttling
+     * happens when temperature >= threshold. If not available, set to NAN.
+     * Unit is same as Temperature's value.
+     * The number of thresholds must be the same as ThrottlingSeverity#len.
+     */
+    float[] hotThrottlingThresholds;
+    /**
+     * Cold throttling temperature constant for this temperature sensor in
+     * level defined in ThrottlingSeverity including shutdown. Throttling
+     * happens when temperature <= threshold. If not available, set to NAN.
+     * Unit is same as Temperature's value.
+     * The number of theresholds must be the same as ThrottlingSeverity#len.
+     */
+    float[] coldThrottlingThresholds;
+}
diff --git a/thermal/aidl/android/hardware/thermal/TemperatureType.aidl b/thermal/aidl/android/hardware/thermal/TemperatureType.aidl
new file mode 100644
index 0000000..aebe7ce
--- /dev/null
+++ b/thermal/aidl/android/hardware/thermal/TemperatureType.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.
+ */
+
+package android.hardware.thermal;
+
+/**
+ * Device temperature types
+ */
+@VintfStability
+@Backing(type="int")
+enum TemperatureType {
+    UNKNOWN = -1,
+    CPU = 0,
+    GPU = 1,
+    BATTERY = 2,
+    SKIN = 3,
+    USB_PORT = 4,
+    POWER_AMPLIFIER = 5,
+    /**
+     * Battery Current Limit - virtual sensors
+     */
+    BCL_VOLTAGE = 6,
+    BCL_CURRENT = 7,
+    BCL_PERCENTAGE = 8,
+    /**
+     * Neural Processing Unit
+     */
+    NPU = 9,
+    TPU = 10,
+    DISPLAY = 11,
+    MODEM = 12,
+    SOC = 13,
+}
diff --git a/thermal/aidl/android/hardware/thermal/ThrottlingSeverity.aidl b/thermal/aidl/android/hardware/thermal/ThrottlingSeverity.aidl
new file mode 100644
index 0000000..29f0724
--- /dev/null
+++ b/thermal/aidl/android/hardware/thermal/ThrottlingSeverity.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.thermal;
+
+/**
+ * Device throttling severity
+ */
+@VintfStability
+@Backing(type="int")
+enum ThrottlingSeverity {
+    /**
+     * Not under throttling.
+     */
+    NONE = 0,
+    /**
+     * Light throttling where UX is not impacted.
+     */
+    LIGHT,
+    /**
+     * Moderate throttling where UX is not largely impacted.
+     */
+    MODERATE,
+    /**
+     * Severe throttling where UX is largely impacted.
+     * Similar to 1.0 throttlingThreshold.
+     */
+    SEVERE,
+    /**
+     * Platform has done everything to reduce power.
+     */
+    CRITICAL,
+    /**
+     * Key components in platform are shutting down due to thermal condition.
+     * Device functionalities will be limited.
+     */
+    EMERGENCY,
+    /**
+     * Need shutdown immediately.
+     */
+    SHUTDOWN,
+}
diff --git a/thermal/aidl/default/Android.bp b/thermal/aidl/default/Android.bp
new file mode 100644
index 0000000..49a578b
--- /dev/null
+++ b/thermal/aidl/default/Android.bp
@@ -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.
+
+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.thermal-service.example",
+    relative_install_path: "hw",
+    init_rc: [":android.hardware.thermal.example.rc"],
+    vintf_fragments: [":android.hardware.thermal.example.xml"],
+    vendor: true,
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "android.hardware.thermal-V1-ndk",
+    ],
+    srcs: [
+        "main.cpp",
+        "Thermal.cpp",
+    ],
+}
+
+filegroup {
+    name: "android.hardware.thermal.example.xml",
+    srcs: ["thermal-example.xml"],
+}
+
+filegroup {
+    name: "android.hardware.thermal.example.rc",
+    srcs: ["thermal-example.rc"],
+}
diff --git a/thermal/aidl/default/Thermal.cpp b/thermal/aidl/default/Thermal.cpp
new file mode 100644
index 0000000..5771e0e
--- /dev/null
+++ b/thermal/aidl/default/Thermal.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "Thermal.h"
+
+#include <android-base/logging.h>
+
+namespace aidl::android::hardware::thermal::impl::example {
+
+using ndk::ScopedAStatus;
+
+ScopedAStatus Thermal::getCoolingDevices(std::vector<CoolingDevice>* /* out_devices */) {
+    LOG(VERBOSE) << __func__;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus Thermal::getCoolingDevicesWithType(CoolingType in_type,
+                                                 std::vector<CoolingDevice>* /* out_devices */) {
+    LOG(VERBOSE) << __func__ << " CoolingType: " << static_cast<int32_t>(in_type);
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus Thermal::getTemperatures(std::vector<Temperature>* /* out_temperatures */) {
+    LOG(VERBOSE) << __func__;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus Thermal::getTemperaturesWithType(TemperatureType in_type,
+                                               std::vector<Temperature>* /* out_temperatures */) {
+    LOG(VERBOSE) << __func__ << " TemperatureType: " << static_cast<int32_t>(in_type);
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus Thermal::getTemperatureThresholds(
+        std::vector<TemperatureThreshold>* /* out_temperatureThresholds */) {
+    LOG(VERBOSE) << __func__;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus Thermal::getTemperatureThresholdsWithType(
+        TemperatureType in_type,
+        std::vector<TemperatureThreshold>* /* out_temperatureThresholds */) {
+    LOG(VERBOSE) << __func__ << " TemperatureType: " << static_cast<int32_t>(in_type);
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus Thermal::registerThermalChangedCallback(
+        const std::shared_ptr<IThermalChangedCallback>& in_callback) {
+    LOG(VERBOSE) << __func__ << " IThermalChangedCallback: " << in_callback;
+    if (in_callback == nullptr) {
+        return ScopedAStatus::fromStatus(STATUS_BAD_VALUE);
+    }
+    if (mCallbacks.find(in_callback) != mCallbacks.end()) {
+        return ScopedAStatus::fromStatus(STATUS_INVALID_OPERATION);
+    }
+    mCallbacks.insert(in_callback);
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus Thermal::registerThermalChangedCallbackWithType(
+        const std::shared_ptr<IThermalChangedCallback>& in_callback, TemperatureType in_type) {
+    LOG(VERBOSE) << __func__ << " IThermalChangedCallback: " << in_callback
+                 << ", TemperatureType: " << static_cast<int32_t>(in_type);
+    if (in_callback == nullptr) {
+        return ScopedAStatus::fromStatus(STATUS_BAD_VALUE);
+    }
+    if (mCallbacks.find(in_callback) != mCallbacks.end()) {
+        return ScopedAStatus::fromStatus(STATUS_INVALID_OPERATION);
+    }
+    mCallbacks.insert(in_callback);
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus Thermal::unregisterThermalChangedCallback(
+        const std::shared_ptr<IThermalChangedCallback>& in_callback) {
+    LOG(VERBOSE) << __func__ << " IThermalChangedCallback: " << in_callback;
+    bool found = false;
+    if (in_callback == nullptr) {
+        return ScopedAStatus::fromStatus(STATUS_BAD_VALUE);
+    }
+    if (mCallbacks.find(in_callback) == mCallbacks.end()) {
+        return ScopedAStatus::fromStatus(STATUS_INVALID_OPERATION);
+    }
+    mCallbacks.erase(in_callback);
+    return ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::thermal::impl::example
diff --git a/thermal/aidl/default/Thermal.h b/thermal/aidl/default/Thermal.h
new file mode 100644
index 0000000..788af4a
--- /dev/null
+++ b/thermal/aidl/default/Thermal.h
@@ -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.
+ */
+
+#pragma once
+
+#include <set>
+
+#include <aidl/android/hardware/thermal/BnThermal.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace thermal {
+namespace impl {
+namespace example {
+
+class Thermal : public BnThermal {
+  public:
+    ndk::ScopedAStatus getCoolingDevices(std::vector<CoolingDevice>* out_devices) override;
+    ndk::ScopedAStatus getCoolingDevicesWithType(CoolingType in_type,
+                                                 std::vector<CoolingDevice>* out_devices) override;
+
+    ndk::ScopedAStatus getTemperatures(std::vector<Temperature>* out_temperatures) override;
+    ndk::ScopedAStatus getTemperaturesWithType(TemperatureType in_type,
+                                               std::vector<Temperature>* out_temperatures) override;
+
+    ndk::ScopedAStatus getTemperatureThresholds(
+            std::vector<TemperatureThreshold>* out_temperatureThresholds) override;
+
+    ndk::ScopedAStatus getTemperatureThresholdsWithType(
+            TemperatureType in_type,
+            std::vector<TemperatureThreshold>* out_temperatureThresholds) override;
+
+    ndk::ScopedAStatus registerThermalChangedCallback(
+            const std::shared_ptr<IThermalChangedCallback>& in_callback) override;
+    ndk::ScopedAStatus registerThermalChangedCallbackWithType(
+            const std::shared_ptr<IThermalChangedCallback>& in_callback,
+            TemperatureType in_type) override;
+
+    ndk::ScopedAStatus unregisterThermalChangedCallback(
+            const std::shared_ptr<IThermalChangedCallback>& in_callback) override;
+
+  private:
+    std::set<std::shared_ptr<IThermalChangedCallback>> mCallbacks;
+};
+
+}  // namespace example
+}  // namespace impl
+}  // namespace thermal
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/thermal/aidl/default/main.cpp b/thermal/aidl/default/main.cpp
new file mode 100644
index 0000000..61d8ad0
--- /dev/null
+++ b/thermal/aidl/default/main.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 "Thermal.h"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+using aidl::android::hardware::thermal::impl::example::Thermal;
+
+int main() {
+    ABinderProcess_setThreadPoolMaxThreadCount(0);
+    std::shared_ptr<Thermal> thermal = ndk::SharedRefBase::make<Thermal>();
+
+    const std::string instance = std::string() + Thermal::descriptor + "/default";
+    binder_status_t status =
+            AServiceManager_addService(thermal->asBinder().get(), instance.c_str());
+    CHECK(status == STATUS_OK);
+
+    ABinderProcess_joinThreadPool();
+    return EXIT_FAILURE;  // should not reach
+}
diff --git a/thermal/aidl/default/thermal-example.rc b/thermal/aidl/default/thermal-example.rc
new file mode 100644
index 0000000..591ca03
--- /dev/null
+++ b/thermal/aidl/default/thermal-example.rc
@@ -0,0 +1,4 @@
+service vendor.thermal-example /vendor/bin/hw/android.hardware.thermal-service.example
+    class hal
+    user nobody
+    group system
diff --git a/thermal/aidl/default/thermal-example.xml b/thermal/aidl/default/thermal-example.xml
new file mode 100644
index 0000000..bdee744
--- /dev/null
+++ b/thermal/aidl/default/thermal-example.xml
@@ -0,0 +1,7 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.thermal</name>
+        <version>1</version>
+        <fqname>IThermal/default</fqname>
+    </hal>
+</manifest>
diff --git a/thermal/aidl/vts/Android.bp b/thermal/aidl/vts/Android.bp
new file mode 100644
index 0000000..b00eb33
--- /dev/null
+++ b/thermal/aidl/vts/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_test {
+    name: "VtsHalThermalTargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: ["VtsHalThermalTargetTest.cpp"],
+    shared_libs: [
+        "libbinder_ndk",
+    ],
+    static_libs: [
+        "android.hardware.thermal-V1-ndk",
+    ],
+    test_suites: [
+        "vts",
+    ],
+}
diff --git a/thermal/aidl/vts/VtsHalThermalTargetTest.cpp b/thermal/aidl/vts/VtsHalThermalTargetTest.cpp
new file mode 100644
index 0000000..b93250e
--- /dev/null
+++ b/thermal/aidl/vts/VtsHalThermalTargetTest.cpp
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <memory>
+#include <string>
+#include <thread>
+#include <vector>
+
+#define LOG_TAG "thermal_aidl_hal_test"
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/thermal/BnThermal.h>
+#include <aidl/android/hardware/thermal/BnThermalChangedCallback.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android/binder_ibinder.h>
+#include <android/binder_interface_utils.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <android/binder_status.h>
+#include <gtest/gtest.h>
+
+#include <unistd.h>
+
+namespace aidl::android::hardware::thermal {
+
+namespace {
+
+using ::android::sp;
+using android::hardware::thermal::CoolingDevice;
+using android::hardware::thermal::IThermal;
+using android::hardware::thermal::Temperature;
+using android::hardware::thermal::TemperatureType;
+
+using namespace std::string_literals;
+using namespace std::chrono_literals;
+
+static const Temperature kThrottleTemp = {
+        .type = TemperatureType::SKIN,
+        .name = "test temperature sensor",
+        .value = 98.6,
+        .throttlingStatus = ThrottlingSeverity::CRITICAL,
+};
+
+// Callback class for receiving thermal event notifications from main class
+class ThermalCallback : public BnThermalChangedCallback {
+  public:
+    ndk::ScopedAStatus notifyThrottling(const Temperature&) override {
+        {
+            std::lock_guard<std::mutex> lock(mMutex);
+            mInvoke = true;
+        }
+        mNotifyThrottling.notify_all();
+        return ndk::ScopedAStatus::ok();
+    }
+
+    template <typename R, typename P>
+    [[nodiscard]] bool waitForCallback(std::chrono::duration<R, P> duration) {
+        std::unique_lock<std::mutex> lock(mMutex);
+        bool r = mNotifyThrottling.wait_for(lock, duration, [this] { return this->mInvoke; });
+        mInvoke = false;
+        return r;
+    }
+
+  private:
+    std::mutex mMutex;
+    std::condition_variable mNotifyThrottling;
+    bool mInvoke = false;
+};
+
+// The main test class for THERMAL HIDL HAL.
+class ThermalAidlTest : public testing::TestWithParam<std::string> {
+  public:
+    void SetUp() override {
+        AIBinder* binder = AServiceManager_waitForService(GetParam().c_str());
+        ASSERT_NE(binder, nullptr);
+        mThermal = IThermal::fromBinder(ndk::SpAIBinder(binder));
+
+        mThermalCallback = ndk::SharedRefBase::make<ThermalCallback>();
+        ASSERT_NE(mThermalCallback, nullptr);
+        auto ret = mThermal->registerThermalChangedCallback(mThermalCallback);
+        ASSERT_TRUE(ret.isOk());
+        // Expect to fail if register again
+        ret = mThermal->registerThermalChangedCallback(mThermalCallback);
+        ASSERT_FALSE(ret.isOk());
+        ASSERT_TRUE(ret.getStatus() == STATUS_INVALID_OPERATION);
+    }
+
+    void TearDown() override {
+        auto ret = mThermal->unregisterThermalChangedCallback(mThermalCallback);
+        ASSERT_TRUE(ret.isOk());
+        // Expect to fail if unregister again
+        ret = mThermal->unregisterThermalChangedCallback(mThermalCallback);
+        ASSERT_FALSE(ret.isOk());
+        ASSERT_TRUE(ret.getStatus() == STATUS_INVALID_OPERATION);
+    }
+
+  protected:
+    std::shared_ptr<IThermal> mThermal;
+    std::shared_ptr<ThermalCallback> mThermalCallback;
+};
+
+// Test ThermalChangedCallback::notifyThrottling().
+// This just calls into and back from our local ThermalChangedCallback impl.
+TEST_P(ThermalAidlTest, NotifyThrottlingTest) {
+    std::shared_ptr<ThermalCallback> thermalCallback = ndk::SharedRefBase::make<ThermalCallback>();
+    auto ret = thermalCallback->notifyThrottling(kThrottleTemp);
+    ASSERT_TRUE(ret.isOk());
+    ASSERT_TRUE(thermalCallback->waitForCallback(200ms));
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ThermalAidlTest);
+INSTANTIATE_TEST_SUITE_P(
+        Thermal, ThermalAidlTest,
+        testing::ValuesIn(::android::getAidlHalInstanceNames(IThermal::descriptor)),
+        ::android::PrintInstanceNameToString);
+
+}  // namespace
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}
+
+}  // namespace aidl::android::hardware::thermal
diff --git a/tv/cec/aidl/Android.bp b/tv/cec/aidl/Android.bp
new file mode 100644
index 0000000..0b0e7cf
--- /dev/null
+++ b/tv/cec/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.cec",
+    vendor_available: true,
+    srcs: ["android/hardware/tv/cec/*.aidl"],
+    stability: "vintf",
+    backend: {
+        java: {
+            sdk_version: "module_current",
+        },
+    },
+}
diff --git a/tv/cec/aidl/OWNERS b/tv/cec/aidl/OWNERS
new file mode 100644
index 0000000..d9c6783
--- /dev/null
+++ b/tv/cec/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/cec/aidl/TEST_MAPPING b/tv/cec/aidl/TEST_MAPPING
new file mode 100644
index 0000000..ef4bee1
--- /dev/null
+++ b/tv/cec/aidl/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "VtsHalTvCecAidlTargetTest"
+    }
+  ]
+}
diff --git a/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/AbortReason.aidl b/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/AbortReason.aidl
new file mode 100644
index 0000000..7377d81
--- /dev/null
+++ b/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/AbortReason.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.tv.cec;
+@Backing(type="int") @VintfStability
+enum AbortReason {
+  UNRECOGNIZED_MODE = 0,
+  NOT_IN_CORRECT_MODE = 1,
+  CANNOT_PROVIDE_SOURCE = 2,
+  INVALID_OPERAND = 3,
+  REFUSED = 4,
+  UNABLE_TO_DETERMINE = 5,
+}
diff --git a/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/CecDeviceType.aidl b/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/CecDeviceType.aidl
new file mode 100644
index 0000000..4d991cd
--- /dev/null
+++ b/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/CecDeviceType.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.tv.cec;
+@Backing(type="byte") @VintfStability
+enum CecDeviceType {
+  INACTIVE = -1,
+  TV = 0,
+  RECORDER = 1,
+  TUNER = 3,
+  PLAYBACK = 4,
+  AUDIO_SYSTEM = 5,
+}
diff --git a/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/CecLogicalAddress.aidl b/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/CecLogicalAddress.aidl
new file mode 100644
index 0000000..a36935b
--- /dev/null
+++ b/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/CecLogicalAddress.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.tv.cec;
+@Backing(type="byte") @VintfStability
+enum CecLogicalAddress {
+  TV = 0,
+  RECORDER_1 = 1,
+  RECORDER_2 = 2,
+  TUNER_1 = 3,
+  PLAYBACK_1 = 4,
+  AUDIO_SYSTEM = 5,
+  TUNER_2 = 6,
+  TUNER_3 = 7,
+  PLAYBACK_2 = 8,
+  RECORDER_3 = 9,
+  TUNER_4 = 10,
+  PLAYBACK_3 = 11,
+  BACKUP_1 = 12,
+  BACKUP_2 = 13,
+  FREE_USE = 14,
+  BROADCAST = 15,
+  UNREGISTERED = 15,
+}
diff --git a/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/CecMessage.aidl b/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/CecMessage.aidl
new file mode 100644
index 0000000..5ce5ce8
--- /dev/null
+++ b/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/CecMessage.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.cec;
+@VintfStability
+parcelable CecMessage {
+  android.hardware.tv.cec.CecLogicalAddress initiator;
+  android.hardware.tv.cec.CecLogicalAddress destination;
+  byte[] body;
+  const int MAX_MESSAGE_BODY_LENGTH = 15;
+}
diff --git a/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/CecMessageType.aidl b/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/CecMessageType.aidl
new file mode 100644
index 0000000..61ebb94
--- /dev/null
+++ b/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/CecMessageType.aidl
@@ -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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.cec;
+@Backing(type="int") @VintfStability
+enum CecMessageType {
+  FEATURE_ABORT = 0,
+  IMAGE_VIEW_ON = 4,
+  TUNER_STEP_INCREMENT = 5,
+  TUNER_STEP_DECREMENT = 6,
+  TUNER_DEVICE_STATUS = 7,
+  GIVE_TUNER_DEVICE_STATUS = 8,
+  RECORD_ON = 9,
+  RECORD_STATUS = 10,
+  RECORD_OFF = 11,
+  TEXT_VIEW_ON = 13,
+  RECORD_TV_SCREEN = 15,
+  GIVE_DECK_STATUS = 26,
+  DECK_STATUS = 27,
+  SET_MENU_LANGUAGE = 50,
+  CLEAR_ANALOG_TIMER = 51,
+  SET_ANALOG_TIMER = 52,
+  TIMER_STATUS = 53,
+  STANDBY = 54,
+  PLAY = 65,
+  DECK_CONTROL = 66,
+  TIMER_CLEARED_STATUS = 67,
+  USER_CONTROL_PRESSED = 68,
+  USER_CONTROL_RELEASED = 69,
+  GIVE_OSD_NAME = 70,
+  SET_OSD_NAME = 71,
+  SET_OSD_STRING = 100,
+  SET_TIMER_PROGRAM_TITLE = 103,
+  SYSTEM_AUDIO_MODE_REQUEST = 112,
+  GIVE_AUDIO_STATUS = 113,
+  SET_SYSTEM_AUDIO_MODE = 114,
+  REPORT_AUDIO_STATUS = 122,
+  GIVE_SYSTEM_AUDIO_MODE_STATUS = 125,
+  SYSTEM_AUDIO_MODE_STATUS = 126,
+  ROUTING_CHANGE = 128,
+  ROUTING_INFORMATION = 129,
+  ACTIVE_SOURCE = 130,
+  GIVE_PHYSICAL_ADDRESS = 131,
+  REPORT_PHYSICAL_ADDRESS = 132,
+  REQUEST_ACTIVE_SOURCE = 133,
+  SET_STREAM_PATH = 134,
+  DEVICE_VENDOR_ID = 135,
+  VENDOR_COMMAND = 137,
+  VENDOR_REMOTE_BUTTON_DOWN = 138,
+  VENDOR_REMOTE_BUTTON_UP = 139,
+  GIVE_DEVICE_VENDOR_ID = 140,
+  MENU_REQUEST = 141,
+  MENU_STATUS = 142,
+  GIVE_DEVICE_POWER_STATUS = 143,
+  REPORT_POWER_STATUS = 144,
+  GET_MENU_LANGUAGE = 145,
+  SELECT_ANALOG_SERVICE = 146,
+  SELECT_DIGITAL_SERVICE = 147,
+  SET_DIGITAL_TIMER = 151,
+  CLEAR_DIGITAL_TIMER = 153,
+  SET_AUDIO_RATE = 154,
+  INACTIVE_SOURCE = 157,
+  CEC_VERSION = 158,
+  GET_CEC_VERSION = 159,
+  VENDOR_COMMAND_WITH_ID = 160,
+  CLEAR_EXTERNAL_TIMER = 161,
+  SET_EXTERNAL_TIMER = 162,
+  REPORT_SHORT_AUDIO_DESCRIPTOR = 163,
+  REQUEST_SHORT_AUDIO_DESCRIPTOR = 164,
+  INITIATE_ARC = 192,
+  REPORT_ARC_INITIATED = 193,
+  REPORT_ARC_TERMINATED = 194,
+  REQUEST_ARC_INITIATION = 195,
+  REQUEST_ARC_TERMINATION = 196,
+  TERMINATE_ARC = 197,
+  ABORT = 255,
+  GIVE_FEATURES = 165,
+  REPORT_FEATURES = 166,
+  REQUEST_CURRENT_LATENCY = 167,
+  REPORT_CURRENT_LATENCY = 168,
+}
diff --git a/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/IHdmiCec.aidl b/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/IHdmiCec.aidl
new file mode 100644
index 0000000..cf8425e
--- /dev/null
+++ b/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/IHdmiCec.aidl
@@ -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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.cec;
+@VintfStability
+interface IHdmiCec {
+  android.hardware.tv.cec.Result addLogicalAddress(in android.hardware.tv.cec.CecLogicalAddress addr);
+  void clearLogicalAddress();
+  void enableAudioReturnChannel(in int portId, in boolean enable);
+  int getCecVersion();
+  int getPhysicalAddress();
+  int getVendorId();
+  android.hardware.tv.cec.SendMessageResult sendMessage(in android.hardware.tv.cec.CecMessage message);
+  void setCallback(in android.hardware.tv.cec.IHdmiCecCallback callback);
+  void setLanguage(in String language);
+  void enableWakeupByOtp(in boolean value);
+  void enableCec(in boolean value);
+  void enableSystemCecControl(in boolean value);
+}
diff --git a/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/IHdmiCecCallback.aidl b/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/IHdmiCecCallback.aidl
new file mode 100644
index 0000000..1918765
--- /dev/null
+++ b/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/IHdmiCecCallback.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.tv.cec;
+@VintfStability
+interface IHdmiCecCallback {
+  oneway void onCecMessage(in android.hardware.tv.cec.CecMessage message);
+}
diff --git a/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/Result.aidl b/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/Result.aidl
new file mode 100644
index 0000000..a5ba276
--- /dev/null
+++ b/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.cec;
+@Backing(type="byte") @VintfStability
+enum Result {
+  SUCCESS = 0,
+  FAILURE_UNKNOWN = 1,
+  FAILURE_INVALID_ARGS = 2,
+  FAILURE_INVALID_STATE = 3,
+  FAILURE_NOT_SUPPORTED = 4,
+  FAILURE_BUSY = 5,
+}
diff --git a/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/SendMessageResult.aidl b/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/SendMessageResult.aidl
new file mode 100644
index 0000000..58206c8
--- /dev/null
+++ b/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/SendMessageResult.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.cec;
+@Backing(type="byte") @VintfStability
+enum SendMessageResult {
+  SUCCESS = 0,
+  NACK = 1,
+  BUSY = 2,
+  FAIL = 3,
+}
diff --git a/tv/cec/aidl/android/hardware/tv/cec/AbortReason.aidl b/tv/cec/aidl/android/hardware/tv/cec/AbortReason.aidl
new file mode 100644
index 0000000..3ae23ec
--- /dev/null
+++ b/tv/cec/aidl/android/hardware/tv/cec/AbortReason.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.tv.cec;
+
+/**
+ * Operand description [Abort Reason]
+ */
+@VintfStability
+@Backing(type="int")
+enum AbortReason {
+    UNRECOGNIZED_MODE = 0,
+    NOT_IN_CORRECT_MODE = 1,
+    CANNOT_PROVIDE_SOURCE = 2,
+    INVALID_OPERAND = 3,
+    REFUSED = 4,
+    UNABLE_TO_DETERMINE = 5,
+}
diff --git a/tv/cec/aidl/android/hardware/tv/cec/CecDeviceType.aidl b/tv/cec/aidl/android/hardware/tv/cec/CecDeviceType.aidl
new file mode 100644
index 0000000..16dfbec
--- /dev/null
+++ b/tv/cec/aidl/android/hardware/tv/cec/CecDeviceType.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.tv.cec;
+
+@VintfStability
+@Backing(type="byte")
+enum CecDeviceType {
+    INACTIVE = -1,
+    TV = 0,
+    RECORDER = 1,
+    TUNER = 3,
+    PLAYBACK = 4,
+    AUDIO_SYSTEM = 5,
+}
diff --git a/tv/cec/aidl/android/hardware/tv/cec/CecLogicalAddress.aidl b/tv/cec/aidl/android/hardware/tv/cec/CecLogicalAddress.aidl
new file mode 100644
index 0000000..fbf5328
--- /dev/null
+++ b/tv/cec/aidl/android/hardware/tv/cec/CecLogicalAddress.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.tv.cec;
+
+@VintfStability
+@Backing(type="byte")
+enum CecLogicalAddress {
+    TV = 0,
+    RECORDER_1 = 1,
+    RECORDER_2 = 2,
+    TUNER_1 = 3,
+    PLAYBACK_1 = 4,
+    AUDIO_SYSTEM = 5,
+    TUNER_2 = 6,
+    TUNER_3 = 7,
+    PLAYBACK_2 = 8,
+    RECORDER_3 = 9,
+    TUNER_4 = 10,
+    PLAYBACK_3 = 11,
+    BACKUP_1 = 12,
+    BACKUP_2 = 13,
+    FREE_USE = 14,
+    BROADCAST = 15,
+    UNREGISTERED = 15,
+}
diff --git a/tv/cec/aidl/android/hardware/tv/cec/CecMessage.aidl b/tv/cec/aidl/android/hardware/tv/cec/CecMessage.aidl
new file mode 100644
index 0000000..b126045
--- /dev/null
+++ b/tv/cec/aidl/android/hardware/tv/cec/CecMessage.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.tv.cec;
+
+import android.hardware.tv.cec.CecLogicalAddress;
+
+@VintfStability
+parcelable CecMessage {
+    /**
+     * Maximum length of the message body
+     */
+    const int MAX_MESSAGE_BODY_LENGTH = 15;
+    /**
+     * logical address of the initiator
+     */
+    CecLogicalAddress initiator;
+    /**
+     * logical address of destination
+     */
+    CecLogicalAddress destination;
+    /**
+     * The maximum size of body is 15 (MAX_MESSAGE_BODY_LENGTH) as specified in
+     * the section 6 of the CEC Spec 1.4b. Overflowed data must be ignored.
+     */
+    byte[] body;
+}
diff --git a/tv/cec/aidl/android/hardware/tv/cec/CecMessageType.aidl b/tv/cec/aidl/android/hardware/tv/cec/CecMessageType.aidl
new file mode 100644
index 0000000..b544a91
--- /dev/null
+++ b/tv/cec/aidl/android/hardware/tv/cec/CecMessageType.aidl
@@ -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.
+ */
+
+package android.hardware.tv.cec;
+
+@VintfStability
+@Backing(type="int")
+enum CecMessageType {
+    FEATURE_ABORT = 0x00,
+    IMAGE_VIEW_ON = 0x04,
+    TUNER_STEP_INCREMENT = 0x05,
+    TUNER_STEP_DECREMENT = 0x06,
+    TUNER_DEVICE_STATUS = 0x07,
+    GIVE_TUNER_DEVICE_STATUS = 0x08,
+    RECORD_ON = 0x09,
+    RECORD_STATUS = 0x0A,
+    RECORD_OFF = 0x0B,
+    TEXT_VIEW_ON = 0x0D,
+    RECORD_TV_SCREEN = 0x0F,
+    GIVE_DECK_STATUS = 0x1A,
+    DECK_STATUS = 0x1B,
+    SET_MENU_LANGUAGE = 0x32,
+    CLEAR_ANALOG_TIMER = 0x33,
+    SET_ANALOG_TIMER = 0x34,
+    TIMER_STATUS = 0x35,
+    STANDBY = 0x36,
+    PLAY = 0x41,
+    DECK_CONTROL = 0x42,
+    TIMER_CLEARED_STATUS = 0x43,
+    USER_CONTROL_PRESSED = 0x44,
+    USER_CONTROL_RELEASED = 0x45,
+    GIVE_OSD_NAME = 0x46,
+    SET_OSD_NAME = 0x47,
+    SET_OSD_STRING = 0x64,
+    SET_TIMER_PROGRAM_TITLE = 0x67,
+    SYSTEM_AUDIO_MODE_REQUEST = 0x70,
+    GIVE_AUDIO_STATUS = 0x71,
+    SET_SYSTEM_AUDIO_MODE = 0x72,
+    REPORT_AUDIO_STATUS = 0x7A,
+    GIVE_SYSTEM_AUDIO_MODE_STATUS = 0x7D,
+    SYSTEM_AUDIO_MODE_STATUS = 0x7E,
+    ROUTING_CHANGE = 0x80,
+    ROUTING_INFORMATION = 0x81,
+    ACTIVE_SOURCE = 0x82,
+    GIVE_PHYSICAL_ADDRESS = 0x83,
+    REPORT_PHYSICAL_ADDRESS = 0x84,
+    REQUEST_ACTIVE_SOURCE = 0x85,
+    SET_STREAM_PATH = 0x86,
+    DEVICE_VENDOR_ID = 0x87,
+    VENDOR_COMMAND = 0x89,
+    VENDOR_REMOTE_BUTTON_DOWN = 0x8A,
+    VENDOR_REMOTE_BUTTON_UP = 0x8B,
+    GIVE_DEVICE_VENDOR_ID = 0x8C,
+    MENU_REQUEST = 0x8D,
+    MENU_STATUS = 0x8E,
+    GIVE_DEVICE_POWER_STATUS = 0x8F,
+    REPORT_POWER_STATUS = 0x90,
+    GET_MENU_LANGUAGE = 0x91,
+    SELECT_ANALOG_SERVICE = 0x92,
+    SELECT_DIGITAL_SERVICE = 0x93,
+    SET_DIGITAL_TIMER = 0x97,
+    CLEAR_DIGITAL_TIMER = 0x99,
+    SET_AUDIO_RATE = 0x9A,
+    INACTIVE_SOURCE = 0x9D,
+    CEC_VERSION = 0x9E,
+    GET_CEC_VERSION = 0x9F,
+    VENDOR_COMMAND_WITH_ID = 0xA0,
+    CLEAR_EXTERNAL_TIMER = 0xA1,
+    SET_EXTERNAL_TIMER = 0xA2,
+    REPORT_SHORT_AUDIO_DESCRIPTOR = 0xA3,
+    REQUEST_SHORT_AUDIO_DESCRIPTOR = 0xA4,
+    INITIATE_ARC = 0xC0,
+    REPORT_ARC_INITIATED = 0xC1,
+    REPORT_ARC_TERMINATED = 0xC2,
+    REQUEST_ARC_INITIATION = 0xC3,
+    REQUEST_ARC_TERMINATION = 0xC4,
+    TERMINATE_ARC = 0xC5,
+    ABORT = 0xFF,
+    GIVE_FEATURES = 0xA5,
+    REPORT_FEATURES = 0xA6,
+    REQUEST_CURRENT_LATENCY = 0xA7,
+    REPORT_CURRENT_LATENCY = 0xA8,
+}
diff --git a/tv/cec/aidl/android/hardware/tv/cec/IHdmiCec.aidl b/tv/cec/aidl/android/hardware/tv/cec/IHdmiCec.aidl
new file mode 100644
index 0000000..dbf7139
--- /dev/null
+++ b/tv/cec/aidl/android/hardware/tv/cec/IHdmiCec.aidl
@@ -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.
+ */
+
+package android.hardware.tv.cec;
+
+import android.hardware.tv.cec.CecLogicalAddress;
+import android.hardware.tv.cec.CecMessage;
+import android.hardware.tv.cec.IHdmiCecCallback;
+import android.hardware.tv.cec.Result;
+import android.hardware.tv.cec.SendMessageResult;
+
+/**
+ * HDMI-CEC HAL interface definition.
+ */
+@VintfStability
+interface IHdmiCec {
+    /**
+     * Passes the logical address that must be used in this system.
+     *
+     * HAL must use it to configure the hardware so that the CEC commands
+     * addressed the given logical address can be filtered in. This method must
+     * be able to be called as many times as necessary in order to support
+     * multiple logical devices.
+     *
+     * @param addr Logical address that must be used in this system. It must be
+     *        in the range of valid logical addresses for the call to succeed.
+     * @return Result status of the operation. SUCCESS if successful,
+     *         FAILURE_INVALID_ARGS if the given logical address is invalid,
+     *         FAILURE_BUSY if device or resource is busy
+     */
+    Result addLogicalAddress(in CecLogicalAddress addr);
+
+    /**
+     * Clears all the logical addresses.
+     *
+     * It is used when the system doesn't need to process CEC command any more,
+     * hence to tell HAL to stop receiving commands from the CEC bus, and change
+     * the state back to the beginning.
+     */
+    void clearLogicalAddress();
+
+    /**
+     * Configures ARC circuit in the hardware logic to start or stop the
+     * feature.
+     *
+     * @param portId Port id to be configured.
+     * @param enable Flag must be either true to start the feature or false to
+     *        stop it.
+     */
+    void enableAudioReturnChannel(in int portId, in boolean enable);
+
+    /**
+     * Returns the CEC version supported by underlying hardware.
+     *
+     * @return the CEC version supported by underlying hardware.
+     */
+    int getCecVersion();
+
+    /**
+     * Gets the CEC physical address.
+     *
+     * The physical address depends on the topology of the network formed by
+     * connected HDMI devices. It is therefore likely to change if the cable is
+     * plugged off and on again. It is advised to call getPhysicalAddress to get
+     * the updated address when hot plug event takes place.
+     *
+     * @param out addr Physical address of this device.
+     */
+    int getPhysicalAddress();
+
+    /**
+     * Gets the identifier of the vendor.
+     *
+     * @return Identifier of the vendor that is the 24-bit unique
+     *         company ID obtained from the IEEE Registration Authority
+     *         Committee (RAC). The upper 8 bits must be 0.
+     */
+    int getVendorId();
+
+    /**
+     * Transmits HDMI-CEC message to other HDMI device.
+     *
+     * The method must be designed to return in a certain amount of time and not
+     * hanging forever which may happen if CEC signal line is pulled low for
+     * some reason.
+     *
+     * It must try retransmission at least once as specified in the section '7.1
+     * Frame Re-transmissions' of the CEC Spec 1.4b.
+     *
+     * @param message CEC message to be sent to other HDMI device.
+     * @return Result status of the operation. SUCCESS if successful,
+     *         NACK if the sent message is not acknowledged,
+     *         BUSY if the CEC bus is busy,
+     *         FAIL if the message could not be sent.
+     */
+    SendMessageResult sendMessage(in CecMessage message);
+
+    /**
+     * Sets a callback that HDMI-CEC HAL must later use for incoming CEC
+     * messages.
+     *
+     * @param callback Callback object to pass hdmi events to the system. The
+     *        previously registered callback must be replaced with this one.
+     *        setCallback(null) should deregister the callback.
+     */
+    void setCallback(in IHdmiCecCallback callback);
+
+    /**
+     * Passes the updated language information of Android system. Contains
+     * three-letter code as defined in ISO/FDIS 639-2. Must be used for HAL to
+     * respond to <Get Menu Language> while in standby mode.
+     *
+     * @param language Three-letter code defined in ISO/FDIS 639-2. Must be
+     *        lowercase letters. (e.g., eng for English)
+     */
+    void setLanguage(in String language);
+
+    /**
+     * Determines whether a TV panel device in standby mode should wake up when
+     * it receives an OTP (One Touch Play) from a source device.
+     *
+     * @param value If true, the TV device will wake up when OTP is received
+     *              and if false, the TV device will not wake up for an OTP.
+     */
+    void enableWakeupByOtp(in boolean value);
+
+    /**
+     * Switch to enable or disable CEC on the device.
+     *
+     * @param value If true, the device will have all CEC functionalities
+     *              and if false, the device will not perform any CEC functions.
+     */
+    void enableCec(in boolean value);
+
+    /**
+     * Determines which module processes CEC messages - the Android framework or
+     * the HAL.
+     *
+     * @param value If true, the Android framework will actively process CEC
+     *        messages and if false, only the HAL will process the CEC messages.
+     */
+    void enableSystemCecControl(in boolean value);
+}
diff --git a/tv/cec/aidl/android/hardware/tv/cec/IHdmiCecCallback.aidl b/tv/cec/aidl/android/hardware/tv/cec/IHdmiCecCallback.aidl
new file mode 100644
index 0000000..4934a64
--- /dev/null
+++ b/tv/cec/aidl/android/hardware/tv/cec/IHdmiCecCallback.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.tv.cec;
+
+import android.hardware.tv.cec.CecMessage;
+
+/**
+ * Callbacks from the HAL implementation to notify the system of new events.
+ */
+@VintfStability
+oneway interface IHdmiCecCallback {
+    /**
+     * The callback function that must be called by HAL implementation to notify
+     * the system of new CEC message arrival.
+     */
+    void onCecMessage(in CecMessage message);
+}
diff --git a/tv/cec/aidl/android/hardware/tv/cec/Result.aidl b/tv/cec/aidl/android/hardware/tv/cec/Result.aidl
new file mode 100644
index 0000000..3184c46
--- /dev/null
+++ b/tv/cec/aidl/android/hardware/tv/cec/Result.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.tv.cec;
+
+@VintfStability
+@Backing(type="byte")
+enum Result {
+    SUCCESS = 0,
+    FAILURE_UNKNOWN = 1,
+    FAILURE_INVALID_ARGS = 2,
+    FAILURE_INVALID_STATE = 3,
+    FAILURE_NOT_SUPPORTED = 4,
+    FAILURE_BUSY = 5,
+}
diff --git a/tv/cec/aidl/android/hardware/tv/cec/SendMessageResult.aidl b/tv/cec/aidl/android/hardware/tv/cec/SendMessageResult.aidl
new file mode 100644
index 0000000..8cb98bc
--- /dev/null
+++ b/tv/cec/aidl/android/hardware/tv/cec/SendMessageResult.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.cec;
+
+/**
+ * error code used for send_message.
+ */
+@VintfStability
+@Backing(type="byte")
+enum SendMessageResult {
+    SUCCESS = 0,
+    NACK = 1,
+    BUSY = 2,
+    FAIL = 3,
+}
diff --git a/tv/cec/aidl/default/Android.bp b/tv/cec/aidl/default/Android.bp
new file mode 100644
index 0000000..5479601
--- /dev/null
+++ b/tv/cec/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.cec-service",
+    vintf_fragments: ["android.hardware.tv.cec-service.xml"],
+    relative_install_path: "hw",
+    vendor: true,
+    cflags: [
+        "-Wall",
+        "-Wextra",
+    ],
+    init_rc: ["android.hardware.tv.cec-service.rc"],
+    srcs: [
+        "serviceMock.cpp",
+        "HdmiCecMock.cpp",
+    ],
+    shared_libs: [
+        "libbinder_ndk",
+        "liblog",
+        "libbase",
+        "libutils",
+        "libhardware",
+        "libhidlbase",
+        "android.hardware.tv.cec-V1-ndk",
+    ],
+}
+
+cc_fuzz {
+    name: "android.hardware.tv.cec-service_fuzzer",
+    defaults: ["service_fuzzer_defaults"],
+    static_libs: [
+        "android.hardware.tv.cec-V1-ndk",
+        "liblog",
+    ],
+    srcs: [
+        "fuzzer.cpp",
+        "HdmiCecMock.cpp",
+    ],
+    fuzz_config: {
+        componentid: 826094,
+    },
+}
diff --git a/tv/cec/aidl/default/HdmiCecMock.cpp b/tv/cec/aidl/default/HdmiCecMock.cpp
new file mode 100644
index 0000000..d8d655b
--- /dev/null
+++ b/tv/cec/aidl/default/HdmiCecMock.cpp
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.cec"
+#include <android-base/logging.h>
+#include <fcntl.h>
+#include <utils/Log.h>
+
+#include <hardware/hardware.h>
+#include <hardware/hdmi_cec.h>
+#include "HdmiCecMock.h"
+
+using ndk::ScopedAStatus;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace cec {
+namespace implementation {
+
+void HdmiCecMock::serviceDied(void* cookie) {
+    ALOGE("HdmiCecMock died");
+    auto hdmiCecMock = static_cast<HdmiCecMock*>(cookie);
+    hdmiCecMock->mCecThreadRun = false;
+}
+
+ScopedAStatus HdmiCecMock::addLogicalAddress(CecLogicalAddress addr, Result* _aidl_return) {
+    // Have a list to maintain logical addresses
+    mLogicalAddresses.push_back(addr);
+    *_aidl_return = Result::SUCCESS;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus HdmiCecMock::clearLogicalAddress() {
+    // Remove logical address from the list
+    mLogicalAddresses = {};
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus HdmiCecMock::enableAudioReturnChannel(int32_t portId __unused, bool enable __unused) {
+    // Maintain ARC status
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus HdmiCecMock::getCecVersion(int32_t* _aidl_return) {
+    // Maintain a cec version and return it
+    *_aidl_return = mCecVersion;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus HdmiCecMock::getPhysicalAddress(int32_t* _aidl_return) {
+    // Maintain a physical address and return it
+    // Default 0xFFFF, update on hotplug event
+    *_aidl_return = mPhysicalAddress;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus HdmiCecMock::getVendorId(int32_t* _aidl_return) {
+    *_aidl_return = mCecVendorId;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus HdmiCecMock::sendMessage(const CecMessage& message, SendMessageResult* _aidl_return) {
+    if (message.body.size() == 0) {
+        *_aidl_return = SendMessageResult::NACK;
+    } else {
+        sendMessageToFifo(message);
+        *_aidl_return = SendMessageResult::SUCCESS;
+    }
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus HdmiCecMock::setCallback(const std::shared_ptr<IHdmiCecCallback>& callback) {
+    // If callback is null, mCallback is also set to null so we do not call the old callback.
+    mCallback = callback;
+
+    if (callback != nullptr) {
+        AIBinder_linkToDeath(this->asBinder().get(), mDeathRecipient.get(), 0 /* cookie */);
+
+        mInputFile = open(CEC_MSG_IN_FIFO, O_RDWR | O_CLOEXEC);
+        mOutputFile = open(CEC_MSG_OUT_FIFO, O_RDWR | O_CLOEXEC);
+        pthread_create(&mThreadId, NULL, __threadLoop, this);
+        pthread_setname_np(mThreadId, "hdmi_cec_loop");
+    }
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus HdmiCecMock::setLanguage(const std::string& language) {
+    if (language.size() != 3) {
+        LOG(ERROR) << "Wrong language code: expected 3 letters, but it was " << language.size()
+                   << ".";
+        return ScopedAStatus::ok();
+    }
+    // TODO Validate if language is a valid language code
+    const char* languageStr = language.c_str();
+    int convertedLanguage = ((languageStr[0] & 0xFF) << 16) | ((languageStr[1] & 0xFF) << 8) |
+                            (languageStr[2] & 0xFF);
+    mOptionLanguage = convertedLanguage;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus HdmiCecMock::enableWakeupByOtp(bool value) {
+    mOptionWakeUp = value;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus HdmiCecMock::enableCec(bool value) {
+    mOptionEnableCec = value;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus HdmiCecMock::enableSystemCecControl(bool value) {
+    mOptionSystemCecControl = value;
+    return ScopedAStatus::ok();
+}
+
+void* HdmiCecMock::__threadLoop(void* user) {
+    HdmiCecMock* const self = static_cast<HdmiCecMock*>(user);
+    self->threadLoop();
+    return 0;
+}
+
+int HdmiCecMock::readMessageFromFifo(unsigned char* buf, int msgCount) {
+    if (msgCount <= 0 || !buf) {
+        return 0;
+    }
+
+    int ret = -1;
+    // Maybe blocked at driver
+    ret = read(mInputFile, buf, msgCount);
+    if (ret < 0) {
+        ALOGE("[halimp_aidl] read :%s failed, ret:%d\n", CEC_MSG_IN_FIFO, ret);
+        return -1;
+    }
+
+    return ret;
+}
+
+int HdmiCecMock::sendMessageToFifo(const CecMessage& message) {
+    unsigned char msgBuf[CEC_MESSAGE_BODY_MAX_LENGTH + 1] = {0};
+    int ret = -1;
+
+    msgBuf[0] = ((static_cast<uint8_t>(message.initiator) & 0xf) << 4) |
+                (static_cast<uint8_t>(message.destination) & 0xf);
+
+    size_t length = std::min(static_cast<size_t>(message.body.size()),
+                             static_cast<size_t>(CEC_MESSAGE_BODY_MAX_LENGTH));
+    for (size_t i = 0; i < length; ++i) {
+        msgBuf[i + 1] = static_cast<unsigned char>(message.body[i]);
+    }
+
+    // Open the output pipe for writing outgoing cec message
+    mOutputFile = open(CEC_MSG_OUT_FIFO, O_WRONLY | O_CLOEXEC);
+    if (mOutputFile < 0) {
+        ALOGD("[halimp_aidl] file open failed for writing");
+        return -1;
+    }
+
+    // Write message into the output pipe
+    ret = write(mOutputFile, msgBuf, length + 1);
+    close(mOutputFile);
+    if (ret < 0) {
+        ALOGE("[halimp_aidl] write :%s failed, ret:%d\n", CEC_MSG_OUT_FIFO, ret);
+        return -1;
+    }
+    return ret;
+}
+
+void HdmiCecMock::printCecMsgBuf(const char* msg_buf, int len) {
+    int i, size = 0;
+    const int bufSize = CEC_MESSAGE_BODY_MAX_LENGTH * 3;
+    // Use 2 characters for each byte in the message plus 1 space
+    char buf[bufSize] = {0};
+
+    // Messages longer than max length will be truncated.
+    for (i = 0; i < len && size < bufSize; i++) {
+        size += sprintf(buf + size, " %02x", msg_buf[i]);
+    }
+    ALOGD("[halimp_aidl] %s, msg:%.*s", __FUNCTION__, size, buf);
+}
+
+void HdmiCecMock::handleCecMessage(unsigned char* msgBuf, int msgSize) {
+    CecMessage message;
+    size_t length = std::min(static_cast<size_t>(msgSize - 1),
+                             static_cast<size_t>(CEC_MESSAGE_BODY_MAX_LENGTH));
+    message.body.resize(length);
+
+    for (size_t i = 0; i < length; ++i) {
+        message.body[i] = static_cast<uint8_t>(msgBuf[i + 1]);
+        ALOGD("[halimp_aidl] msg body %x", message.body[i]);
+    }
+
+    message.initiator = static_cast<CecLogicalAddress>((msgBuf[0] >> 4) & 0xf);
+    ALOGD("[halimp_aidl] msg init %hhd", message.initiator);
+    message.destination = static_cast<CecLogicalAddress>((msgBuf[0] >> 0) & 0xf);
+    ALOGD("[halimp_aidl] msg dest %hhd", message.destination);
+
+    if (mCallback != nullptr) {
+        mCallback->onCecMessage(message);
+    }
+}
+
+void HdmiCecMock::threadLoop() {
+    ALOGD("[halimp_aidl] threadLoop start.");
+    unsigned char msgBuf[CEC_MESSAGE_BODY_MAX_LENGTH];
+    int r = -1;
+
+    // Open the input pipe
+    while (mInputFile < 0) {
+        usleep(1000 * 1000);
+        mInputFile = open(CEC_MSG_IN_FIFO, O_RDONLY | O_CLOEXEC);
+    }
+    ALOGD("[halimp_aidl] file open ok, fd = %d.", mInputFile);
+
+    while (mCecThreadRun) {
+        if (!mOptionSystemCecControl) {
+            usleep(1000 * 1000);
+            continue;
+        }
+
+        memset(msgBuf, 0, sizeof(msgBuf));
+        // Try to get a message from dev.
+        // echo -n -e '\x04\x83' >> /dev/cec
+        r = readMessageFromFifo(msgBuf, CEC_MESSAGE_BODY_MAX_LENGTH);
+        if (r <= 1) {
+            // Ignore received ping messages
+            continue;
+        }
+
+        printCecMsgBuf((const char*)msgBuf, r);
+
+        if (((msgBuf[0] >> 4) & 0xf) == 0xf) {
+            // The message is a hotplug event, handled by HDMI HAL.
+            continue;
+        }
+
+        handleCecMessage(msgBuf, r);
+    }
+
+    ALOGD("[halimp_aidl] thread end.");
+}
+
+HdmiCecMock::HdmiCecMock() {
+    ALOGE("[halimp_aidl] Opening a virtual CEC HAL for testing and virtual machine.");
+    mCallback = nullptr;
+    mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient_new(serviceDied));
+}
+
+}  // namespace implementation
+}  // namespace cec
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
diff --git a/tv/cec/aidl/default/HdmiCecMock.h b/tv/cec/aidl/default/HdmiCecMock.h
new file mode 100644
index 0000000..08f4d6f
--- /dev/null
+++ b/tv/cec/aidl/default/HdmiCecMock.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.
+ */
+
+#include <aidl/android/hardware/tv/cec/BnHdmiCec.h>
+#include <algorithm>
+#include <vector>
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace cec {
+namespace implementation {
+
+using ::aidl::android::hardware::tv::cec::BnHdmiCec;
+using ::aidl::android::hardware::tv::cec::CecLogicalAddress;
+using ::aidl::android::hardware::tv::cec::CecMessage;
+using ::aidl::android::hardware::tv::cec::IHdmiCec;
+using ::aidl::android::hardware::tv::cec::IHdmiCecCallback;
+using ::aidl::android::hardware::tv::cec::Result;
+using ::aidl::android::hardware::tv::cec::SendMessageResult;
+
+#define CEC_MSG_IN_FIFO "/dev/cec_aidl_in_pipe"
+#define CEC_MSG_OUT_FIFO "/dev/cec_aidl_out_pipe"
+
+struct HdmiCecMock : public BnHdmiCec {
+    HdmiCecMock();
+    ::ndk::ScopedAStatus addLogicalAddress(CecLogicalAddress addr, Result* _aidl_return) override;
+    ::ndk::ScopedAStatus clearLogicalAddress() override;
+    ::ndk::ScopedAStatus enableAudioReturnChannel(int32_t portId, bool enable) override;
+    ::ndk::ScopedAStatus getCecVersion(int32_t* _aidl_return) override;
+    ::ndk::ScopedAStatus getPhysicalAddress(int32_t* _aidl_return) override;
+    ::ndk::ScopedAStatus getVendorId(int32_t* _aidl_return) override;
+    ::ndk::ScopedAStatus sendMessage(const CecMessage& message,
+                                     SendMessageResult* _aidl_return) override;
+    ::ndk::ScopedAStatus setCallback(const std::shared_ptr<IHdmiCecCallback>& callback) override;
+    ::ndk::ScopedAStatus setLanguage(const std::string& language) override;
+    ::ndk::ScopedAStatus enableWakeupByOtp(bool value) override;
+    ::ndk::ScopedAStatus enableCec(bool value) override;
+    ::ndk::ScopedAStatus enableSystemCecControl(bool value) override;
+    void printCecMsgBuf(const char* msg_buf, int len);
+
+  private:
+    static void* __threadLoop(void* data);
+    void threadLoop();
+    int readMessageFromFifo(unsigned char* buf, int msgCount);
+    int sendMessageToFifo(const CecMessage& message);
+    void handleCecMessage(unsigned char* msgBuf, int length);
+
+  private:
+    static void serviceDied(void* cookie);
+    std::shared_ptr<IHdmiCecCallback> mCallback;
+
+    // Variables for the virtual cec hal impl
+    uint16_t mPhysicalAddress = 0xFFFF;
+    vector<CecLogicalAddress> mLogicalAddresses;
+    int32_t mCecVersion = 0x06;
+    uint32_t mCecVendorId = 0x01;
+
+    // CEC Option value
+    bool mOptionWakeUp = 0;
+    bool mOptionEnableCec = 0;
+    bool mOptionSystemCecControl = 0;
+    int mOptionLanguage;
+
+    // Testing variables
+    // Input file descriptor
+    int mInputFile;
+    // Output file descriptor
+    int mOutputFile;
+    bool mCecThreadRun = true;
+    pthread_t mThreadId = 0;
+
+    ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
+};
+}  // namespace implementation
+}  // namespace cec
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
diff --git a/tv/cec/aidl/default/android.hardware.tv.cec-service.rc b/tv/cec/aidl/default/android.hardware.tv.cec-service.rc
new file mode 100644
index 0000000..c79520c
--- /dev/null
+++ b/tv/cec/aidl/default/android.hardware.tv.cec-service.rc
@@ -0,0 +1,5 @@
+service vendor.cec-default /vendor/bin/hw/android.hardware.tv.cec-service
+    interface aidl android.hardware.tv.cec.IHdmiCec/default
+    class hal
+    user system
+    group system
diff --git a/tv/cec/aidl/default/android.hardware.tv.cec-service.xml b/tv/cec/aidl/default/android.hardware.tv.cec-service.xml
new file mode 100644
index 0000000..e68450d
--- /dev/null
+++ b/tv/cec/aidl/default/android.hardware.tv.cec-service.xml
@@ -0,0 +1,10 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.tv.cec</name>
+        <version>1</version>
+        <interface>
+            <name>IHdmiCec</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/tv/cec/aidl/default/fuzzer.cpp b/tv/cec/aidl/default/fuzzer.cpp
new file mode 100644
index 0000000..9f6a9ac
--- /dev/null
+++ b/tv/cec/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 <HdmiCecMock.h>
+#include <fuzzbinder/libbinder_ndk_driver.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+using android::fuzzService;
+using android::hardware::tv::cec::implementation::HdmiCecMock;
+using ndk::SharedRefBase;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    auto hdmiCecAidl = SharedRefBase::make<HdmiCecMock>();
+
+    fuzzService(hdmiCecAidl->asBinder().get(), FuzzedDataProvider(data, size));
+
+    return 0;
+}
diff --git a/tv/cec/aidl/default/serviceMock.cpp b/tv/cec/aidl/default/serviceMock.cpp
new file mode 100644
index 0000000..ab86c3f
--- /dev/null
+++ b/tv/cec/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.cec-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 "HdmiCecMock.h"
+
+using android::hardware::tv::cec::implementation::HdmiCecMock;
+
+int main() {
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+
+    std::shared_ptr<HdmiCecMock> hdmiCecAidl = ndk::SharedRefBase::make<HdmiCecMock>();
+    const std::string instance = std::string() + HdmiCecMock::descriptor + "/default";
+    binder_status_t status =
+            AServiceManager_addService(hdmiCecAidl->asBinder().get(), instance.c_str());
+    CHECK_EQ(status, STATUS_OK);
+
+    ABinderProcess_joinThreadPool();
+    return 0;
+}
diff --git a/tv/cec/aidl/vts/functional/Android.bp b/tv/cec/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..37fbaf0
--- /dev/null
+++ b/tv/cec/aidl/vts/functional/Android.bp
@@ -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.
+
+package {
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_test {
+    name: "VtsHalTvCecAidlTargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: ["VtsHalTvCecAidlTargetTest.cpp"],
+    static_libs: [
+        "android.hardware.tv.cec-V1-ndk",
+        "android.hardware.tv.hdmi-V1-ndk",
+    ],
+    shared_libs: [
+        "libbinder_ndk",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+    disable_framework: true,
+}
diff --git a/tv/cec/aidl/vts/functional/AndroidTest.xml b/tv/cec/aidl/vts/functional/AndroidTest.xml
new file mode 100644
index 0000000..8604147
--- /dev/null
+++ b/tv/cec/aidl/vts/functional/AndroidTest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 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.
+-->
+<configuration description="Runs VtsHalTvCecAidlTargetTest.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="VtsHalTvCecAidlTargetTest->/data/local/tmp/VtsHalTvCecAidlTargetTest" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="VtsHalTvCecAidlTargetTest" />
+        <option name="native-test-timeout" value="30m" />
+    </test>
+</configuration>
diff --git a/tv/cec/aidl/vts/functional/VtsHalTvCecAidlTargetTest.cpp b/tv/cec/aidl/vts/functional/VtsHalTvCecAidlTargetTest.cpp
new file mode 100644
index 0000000..69c209f
--- /dev/null
+++ b/tv/cec/aidl/vts/functional/VtsHalTvCecAidlTargetTest.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.
+ */
+
+#define LOG_TAG "HdmiCec_hal_test"
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/tv/cec/BnHdmiCec.h>
+#include <aidl/android/hardware/tv/cec/BnHdmiCecCallback.h>
+#include <aidl/android/hardware/tv/cec/CecDeviceType.h>
+#include <aidl/android/hardware/tv/hdmi/BnHdmi.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::cec::BnHdmiCecCallback;
+using ::aidl::android::hardware::tv::cec::CecDeviceType;
+using ::aidl::android::hardware::tv::cec::CecLogicalAddress;
+using ::aidl::android::hardware::tv::cec::CecMessage;
+using ::aidl::android::hardware::tv::cec::IHdmiCec;
+using ::aidl::android::hardware::tv::cec::IHdmiCecCallback;
+using ::aidl::android::hardware::tv::cec::Result;
+using ::aidl::android::hardware::tv::cec::SendMessageResult;
+using ::aidl::android::hardware::tv::hdmi::HdmiPortInfo;
+using ::ndk::SpAIBinder;
+
+#define CEC_VERSION 0x05
+#define INCORRECT_VENDOR_ID 0x00
+#define TV_PHYSICAL_ADDRESS 0x0000
+
+// The main test class for TV CEC HAL.
+class HdmiCecTest : public ::testing::TestWithParam<std::string> {
+    static void serviceDied(void* /* cookie */) { ALOGE("VtsHalTvCecAidlTargetTest died"); }
+
+  public:
+    void SetUp() override {
+        hdmiCec = IHdmiCec::fromBinder(
+                SpAIBinder(AServiceManager_waitForService(GetParam().c_str())));
+        ASSERT_NE(hdmiCec, nullptr);
+        ALOGI("%s: getService() for hdmiCec is %s", __func__,
+              hdmiCec->isRemote() ? "remote" : "local");
+
+        hdmiCecCallback = ::ndk::SharedRefBase::make<CecCallback>();
+        ASSERT_NE(hdmiCecCallback, nullptr);
+        hdmiCecDeathRecipient =
+                ndk::ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient_new(&serviceDied));
+        ASSERT_EQ(AIBinder_linkToDeath(hdmiCec->asBinder().get(), hdmiCecDeathRecipient.get(), 0),
+                  STATUS_OK);
+    }
+
+    std::vector<int> getDeviceTypes() {
+        std::vector<int> deviceTypes;
+        FILE* p = popen("getprop ro.hdmi.device_type", "re");
+        if (p) {
+            char* line = NULL;
+            size_t len = 0;
+            if (getline(&line, &len, p) > 0) {
+                std::istringstream stream(line);
+                std::string number{};
+                while (std::getline(stream, number, ',')) {
+                    deviceTypes.push_back(stoi(number));
+                }
+            }
+            pclose(p);
+        }
+        return deviceTypes;
+    }
+
+    bool hasDeviceType(CecDeviceType type) {
+        std::vector<int> deviceTypes = getDeviceTypes();
+        return std::find(deviceTypes.begin(), deviceTypes.end(), (int)type) != deviceTypes.end();
+    }
+
+    class CecCallback : public BnHdmiCecCallback {
+      public:
+        ::ndk::ScopedAStatus onCecMessage(const CecMessage& message __unused) {
+            return ::ndk::ScopedAStatus::ok();
+        };
+    };
+
+    std::shared_ptr<IHdmiCec> hdmiCec;
+    std::shared_ptr<IHdmiCecCallback> hdmiCecCallback;
+    ::ndk::ScopedAIBinder_DeathRecipient hdmiCecDeathRecipient;
+};
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(HdmiCecTest);
+INSTANTIATE_TEST_SUITE_P(PerInstance, HdmiCecTest,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(IHdmiCec::descriptor)),
+                         android::PrintInstanceNameToString);
+
+TEST_P(HdmiCecTest, ClearAddLogicalAddress) {
+    Result addLaResult;
+    ASSERT_TRUE(hdmiCec->clearLogicalAddress().isOk());
+    ASSERT_TRUE(hdmiCec->addLogicalAddress(CecLogicalAddress::PLAYBACK_3, &addLaResult).isOk());
+    EXPECT_EQ(addLaResult, Result::SUCCESS);
+}
+
+TEST_P(HdmiCecTest, PhysicalAddress) {
+    int32_t addr;
+    ASSERT_TRUE(hdmiCec->getPhysicalAddress(&addr).isOk());
+    if (!hasDeviceType(CecDeviceType::TV)) {
+        EXPECT_NE(addr, TV_PHYSICAL_ADDRESS);
+    }
+}
+
+TEST_P(HdmiCecTest, SendMessage) {
+    CecMessage message;
+    message.initiator = CecLogicalAddress::PLAYBACK_1;
+    message.destination = CecLogicalAddress::BROADCAST;
+    message.body.resize(1);
+    message.body[0] = 131;
+    SendMessageResult result;
+    ASSERT_TRUE(hdmiCec->sendMessage(message, &result).isOk());
+    EXPECT_EQ(result, SendMessageResult::SUCCESS);
+}
+
+TEST_P(HdmiCecTest, CecVersion) {
+    int32_t version;
+    ASSERT_TRUE(hdmiCec->getCecVersion(&version).isOk());
+    EXPECT_GE(version, CEC_VERSION);
+}
+
+TEST_P(HdmiCecTest, SetCallback) {
+    ASSERT_TRUE(hdmiCec->setCallback(::ndk::SharedRefBase::make<CecCallback>()).isOk());
+}
+
+TEST_P(HdmiCecTest, VendorId) {
+    int32_t vendorId;
+    ASSERT_TRUE(hdmiCec->getVendorId(&vendorId).isOk());
+    EXPECT_NE(vendorId, INCORRECT_VENDOR_ID);
+}
+
+TEST_P(HdmiCecTest, EnableWakeupByOtp) {
+    ASSERT_TRUE(hdmiCec->enableWakeupByOtp(false).isOk());
+    // Restore option to its default value
+    ASSERT_TRUE(hdmiCec->enableWakeupByOtp(true).isOk());
+}
+
+TEST_P(HdmiCecTest, EnableCec) {
+    ASSERT_TRUE(hdmiCec->enableCec(false).isOk());
+    // Restore option to its default value
+    ASSERT_TRUE(hdmiCec->enableCec(true).isOk());
+}
+
+TEST_P(HdmiCecTest, EnableSystemCecControl) {
+    ASSERT_TRUE(hdmiCec->enableSystemCecControl(true).isOk());
+    // Restore option to its default value
+    ASSERT_TRUE(hdmiCec->enableSystemCecControl(false).isOk());
+}
+
+TEST_P(HdmiCecTest, SetLanguage) {
+    ASSERT_TRUE(hdmiCec->setLanguage("eng").isOk());
+}
diff --git a/tv/hdmi/aidl/Android.bp b/tv/hdmi/aidl/Android.bp
new file mode 100644
index 0000000..d8c6e5f
--- /dev/null
+++ b/tv/hdmi/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.hdmi",
+    vendor_available: true,
+    srcs: ["android/hardware/tv/hdmi/*.aidl"],
+    stability: "vintf",
+    backend: {
+        java: {
+            sdk_version: "module_current",
+        },
+    },
+}
diff --git a/tv/hdmi/aidl/OWNERS b/tv/hdmi/aidl/OWNERS
new file mode 100644
index 0000000..d9c6783
--- /dev/null
+++ b/tv/hdmi/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/hdmi/aidl/TEST_MAPPING b/tv/hdmi/aidl/TEST_MAPPING
new file mode 100644
index 0000000..6bd3b57
--- /dev/null
+++ b/tv/hdmi/aidl/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "VtsHalTvHdmiAidlTargetTest"
+    }
+  ]
+}
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
new file mode 100644
index 0000000..25c3be1
--- /dev/null
+++ b/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/HdmiPortInfo.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.tv.hdmi;
+@VintfStability
+parcelable HdmiPortInfo {
+  android.hardware.tv.hdmi.HdmiPortType type;
+  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/HdmiPortType.aidl b/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/HdmiPortType.aidl
new file mode 100644
index 0000000..af5f0f7
--- /dev/null
+++ b/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/HdmiPortType.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 HdmiPortType {
+  INPUT = 0,
+  OUTPUT = 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
new file mode 100644
index 0000000..3fc7f41
--- /dev/null
+++ b/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/IHdmi.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.tv.hdmi;
+@VintfStability
+interface IHdmi {
+  android.hardware.tv.hdmi.HdmiPortInfo[] getPortInfo();
+  boolean isConnected(in int portId);
+  void setCallback(in android.hardware.tv.hdmi.IHdmiCallback callback);
+}
diff --git a/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/IHdmiCallback.aidl b/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/IHdmiCallback.aidl
new file mode 100644
index 0000000..05fe623
--- /dev/null
+++ b/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/IHdmiCallback.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.tv.hdmi;
+@VintfStability
+interface IHdmiCallback {
+  oneway void onHotplugEvent(in boolean connected, in int portId);
+}
diff --git a/tv/hdmi/aidl/android/hardware/tv/hdmi/HdmiPortInfo.aidl b/tv/hdmi/aidl/android/hardware/tv/hdmi/HdmiPortInfo.aidl
new file mode 100644
index 0000000..2e2c858
--- /dev/null
+++ b/tv/hdmi/aidl/android/hardware/tv/hdmi/HdmiPortInfo.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.
+ */
+
+package android.hardware.tv.hdmi;
+
+import android.hardware.tv.hdmi.HdmiPortType;
+
+/**
+ * HDMI port descriptor
+ */
+@VintfStability
+parcelable HdmiPortInfo {
+    HdmiPortType type;
+    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/HdmiPortType.aidl b/tv/hdmi/aidl/android/hardware/tv/hdmi/HdmiPortType.aidl
new file mode 100644
index 0000000..59c0d42
--- /dev/null
+++ b/tv/hdmi/aidl/android/hardware/tv/hdmi/HdmiPortType.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;
+
+/**
+ * HDMI port type.
+ */
+@VintfStability
+@Backing(type="byte")
+enum HdmiPortType {
+    INPUT = 0,
+    OUTPUT = 1,
+}
diff --git a/tv/hdmi/aidl/android/hardware/tv/hdmi/IHdmi.aidl b/tv/hdmi/aidl/android/hardware/tv/hdmi/IHdmi.aidl
new file mode 100644
index 0000000..5536846
--- /dev/null
+++ b/tv/hdmi/aidl/android/hardware/tv/hdmi/IHdmi.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.
+ */
+
+package android.hardware.tv.hdmi;
+
+import android.hardware.tv.hdmi.HdmiPortInfo;
+import android.hardware.tv.hdmi.IHdmiCallback;
+
+/**
+ * HDMI HAL interface definition.
+ */
+@VintfStability
+interface IHdmi {
+    /**
+     * Gets the hdmi port information of underlying hardware.
+     *
+     * @return The list of HDMI port information
+     */
+    HdmiPortInfo[] getPortInfo();
+
+    /**
+     * Gets the connection status of the specified port.
+     *
+     * @param portId Port id to be inspected for the connection status.
+     * @return True if a device is connected, otherwise false. The HAL
+     *         must watch for +5V power signal to determine the status.
+     */
+    boolean isConnected(in int portId);
+
+    /**
+     * Sets a callback that HDMI HAL must later use for internal HDMI events
+     *
+     * @param callback Callback object to pass hdmi events to the system. The
+     *        previously registered callback must be replaced with this one.
+     *        setCallback(null) should deregister the callback.
+     */
+    void setCallback(in IHdmiCallback callback);
+}
diff --git a/tv/hdmi/aidl/android/hardware/tv/hdmi/IHdmiCallback.aidl b/tv/hdmi/aidl/android/hardware/tv/hdmi/IHdmiCallback.aidl
new file mode 100644
index 0000000..51275b0
--- /dev/null
+++ b/tv/hdmi/aidl/android/hardware/tv/hdmi/IHdmiCallback.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.hdmi;
+
+/**
+ * Callbacks from the HDMI HAL implementation to notify the system of new events.
+ */
+@VintfStability
+oneway interface IHdmiCallback {
+    /**
+     * The callback function that must be called by HAL implementation to notify
+     * the system of new hotplug event.
+     */
+    void onHotplugEvent(in boolean connected, in int portId);
+}
diff --git a/tv/hdmi/aidl/default/Android.bp b/tv/hdmi/aidl/default/Android.bp
new file mode 100644
index 0000000..3e466a0
--- /dev/null
+++ b/tv/hdmi/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.hdmi-service",
+    vintf_fragments: ["android.hardware.tv.hdmi-service.xml"],
+    relative_install_path: "hw",
+    vendor: true,
+    cflags: [
+        "-Wall",
+        "-Wextra",
+    ],
+    init_rc: ["android.hardware.tv.hdmi-service.rc"],
+    srcs: [
+        "serviceMock.cpp",
+        "HdmiMock.cpp",
+    ],
+    shared_libs: [
+        "libbinder_ndk",
+        "liblog",
+        "libbase",
+        "libutils",
+        "libhardware",
+        "libhidlbase",
+        "android.hardware.tv.hdmi-V1-ndk",
+    ],
+}
+
+cc_fuzz {
+    name: "android.hardware.tv.hdmi-service_fuzzer",
+    defaults: ["service_fuzzer_defaults"],
+    static_libs: [
+        "android.hardware.tv.hdmi-V1-ndk",
+        "liblog",
+    ],
+    srcs: [
+        "fuzzer.cpp",
+        "HdmiMock.cpp",
+    ],
+    fuzz_config: {
+        componentid: 826094,
+    },
+}
diff --git a/tv/hdmi/aidl/default/HdmiMock.cpp b/tv/hdmi/aidl/default/HdmiMock.cpp
new file mode 100644
index 0000000..bbc4705
--- /dev/null
+++ b/tv/hdmi/aidl/default/HdmiMock.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 "android.hardware.tv.hdmi"
+#include <android-base/logging.h>
+#include <fcntl.h>
+#include <utils/Log.h>
+
+#include "HdmiMock.h"
+
+using ndk::ScopedAStatus;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace hdmi {
+namespace implementation {
+
+void HdmiMock::serviceDied(void* cookie) {
+    ALOGE("HdmiMock died");
+    auto hdmi = static_cast<HdmiMock*>(cookie);
+    hdmi->mHdmiThreadRun = false;
+}
+
+ScopedAStatus HdmiMock::getPortInfo(std::vector<HdmiPortInfo>* _aidl_return) {
+    *_aidl_return = mPortInfos;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus HdmiMock::isConnected(int32_t portId, bool* _aidl_return) {
+    // Maintain port connection status and update on hotplug event
+    if (portId <= mTotalPorts && portId >= 1) {
+        *_aidl_return = mPortConnectionStatus[portId];
+    } else {
+        *_aidl_return = false;
+    }
+
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus HdmiMock::setCallback(const std::shared_ptr<IHdmiCallback>& callback) {
+    if (mCallback != nullptr) {
+        mCallback = nullptr;
+    }
+
+    if (callback != nullptr) {
+        mCallback = callback;
+        AIBinder_linkToDeath(this->asBinder().get(), mDeathRecipient.get(), 0 /* cookie */);
+
+        mInputFile = open(HDMI_MSG_IN_FIFO, O_RDWR | O_CLOEXEC);
+        pthread_create(&mThreadId, NULL, __threadLoop, this);
+        pthread_setname_np(mThreadId, "hdmi_loop");
+    }
+    return ScopedAStatus::ok();
+}
+
+void* HdmiMock::__threadLoop(void* user) {
+    HdmiMock* const self = static_cast<HdmiMock*>(user);
+    self->threadLoop();
+    return 0;
+}
+
+int HdmiMock::readMessageFromFifo(unsigned char* buf, int msgCount) {
+    if (msgCount <= 0 || !buf) {
+        return 0;
+    }
+
+    int ret = -1;
+    // Maybe blocked at driver
+    ret = read(mInputFile, buf, msgCount);
+    if (ret < 0) {
+        ALOGE("[halimp_aidl] read :%s failed, ret:%d\n", HDMI_MSG_IN_FIFO, ret);
+        return -1;
+    }
+
+    return ret;
+}
+
+void HdmiMock::printEventBuf(const char* msg_buf, int len) {
+    int i, size = 0;
+    const int bufSize = MESSAGE_BODY_MAX_LENGTH * 3;
+    // Use 2 characters for each byte in the message plus 1 space
+    char buf[bufSize] = {0};
+
+    // Messages longer than max length will be truncated.
+    for (i = 0; i < len && size < bufSize; i++) {
+        size += sprintf(buf + size, " %02x", msg_buf[i]);
+    }
+    ALOGD("[halimp_aidl] %s, msg:%.*s", __FUNCTION__, size, buf);
+}
+
+void HdmiMock::handleHotplugMessage(unsigned char* msgBuf) {
+    bool connected = ((msgBuf[3]) & 0xf) > 0;
+    int32_t portId = static_cast<uint32_t>(msgBuf[0] & 0xf);
+
+    if (portId > static_cast<int32_t>(mPortInfos.size())) {
+        ALOGD("[halimp_aidl] ignore hot plug message, id %x does not exist", portId);
+        return;
+    }
+
+    ALOGD("[halimp_aidl] hot plug port id %x, is connected %x", (msgBuf[0] & 0xf),
+          (msgBuf[3] & 0xf));
+    mPortConnectionStatus[portId] = connected;
+    if (mPortInfos[portId].type == HdmiPortType::OUTPUT) {
+        mPhysicalAddress = (connected ? 0xffff : ((msgBuf[1] << 8) | (msgBuf[2])));
+        mPortInfos[portId].physicalAddress = mPhysicalAddress;
+        ALOGD("[halimp_aidl] hot plug physical address %x", mPhysicalAddress);
+    }
+
+    if (mCallback != nullptr) {
+        mCallback->onHotplugEvent(connected, portId);
+    }
+}
+
+void HdmiMock::threadLoop() {
+    ALOGD("[halimp_aidl] threadLoop start.");
+    unsigned char msgBuf[MESSAGE_BODY_MAX_LENGTH];
+    int r = -1;
+
+    // Open the input pipe
+    while (mInputFile < 0) {
+        usleep(1000 * 1000);
+        mInputFile = open(HDMI_MSG_IN_FIFO, O_RDONLY | O_CLOEXEC);
+    }
+    ALOGD("[halimp_aidl] file open ok, fd = %d.", mInputFile);
+
+    while (mHdmiThreadRun) {
+        memset(msgBuf, 0, sizeof(msgBuf));
+        // Try to get a message from dev.
+        // echo -n -e '\x04\x83' >> /dev/cec
+        r = readMessageFromFifo(msgBuf, MESSAGE_BODY_MAX_LENGTH);
+        if (r <= 1) {
+            // Ignore received ping messages
+            continue;
+        }
+
+        printEventBuf((const char*)msgBuf, r);
+
+        if (((msgBuf[0] >> 4) & 0xf) == 0xf) {
+            handleHotplugMessage(msgBuf);
+        }
+    }
+
+    ALOGD("[halimp_aidl] thread end.");
+}
+
+HdmiMock::HdmiMock() {
+    ALOGE("[halimp_aidl] Opening a virtual HDMI HAL for testing and virtual machine.");
+    mCallback = nullptr;
+    mPortInfos.resize(mTotalPorts);
+    mPortConnectionStatus.resize(mTotalPorts);
+    mPortInfos[0] = {.type = HdmiPortType::OUTPUT,
+                     .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));
+}
+
+}  // namespace implementation
+}  // namespace hdmi
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
diff --git a/tv/hdmi/aidl/default/HdmiMock.h b/tv/hdmi/aidl/default/HdmiMock.h
new file mode 100644
index 0000000..05795dd
--- /dev/null
+++ b/tv/hdmi/aidl/default/HdmiMock.h
@@ -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.
+ */
+
+#include <aidl/android/hardware/tv/hdmi/BnHdmi.h>
+#include <algorithm>
+#include <vector>
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace hdmi {
+namespace implementation {
+
+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::IHdmi;
+using ::aidl::android::hardware::tv::hdmi::IHdmiCallback;
+
+#define HDMI_MSG_IN_FIFO "/dev/hdmi_in_pipe"
+#define MESSAGE_BODY_MAX_LENGTH 4
+
+struct HdmiMock : public BnHdmi {
+    HdmiMock();
+
+    ::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;
+
+    void printEventBuf(const char* msg_buf, int len);
+
+  private:
+    static void* __threadLoop(void* data);
+    void threadLoop();
+    int readMessageFromFifo(unsigned char* buf, int msgCount);
+    void handleHotplugMessage(unsigned char* msgBuf);
+
+  private:
+    static void serviceDied(void* cookie);
+    std::shared_ptr<IHdmiCallback> mCallback;
+
+    // Variables for the virtual HDMI hal impl
+    std::vector<HdmiPortInfo> mPortInfos;
+    std::vector<bool> mPortConnectionStatus;
+
+    // Port configuration
+    uint16_t mPhysicalAddress = 0xFFFF;
+    int mTotalPorts = 1;
+
+    // Testing variables
+    // Input file descriptor
+    int mInputFile;
+    bool mHdmiThreadRun = true;
+    pthread_t mThreadId = 0;
+
+    ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
+};
+}  // namespace implementation
+}  // namespace hdmi
+}  // Namespace tv
+}  // namespace hardware
+}  // namespace android
diff --git a/tv/hdmi/aidl/default/android.hardware.tv.hdmi-service.rc b/tv/hdmi/aidl/default/android.hardware.tv.hdmi-service.rc
new file mode 100644
index 0000000..c926221
--- /dev/null
+++ b/tv/hdmi/aidl/default/android.hardware.tv.hdmi-service.rc
@@ -0,0 +1,5 @@
+service vendor.hdmi-default /vendor/bin/hw/android.hardware.tv.hdmi-service
+    interface aidl android.hardware.tv.hdmi.IHdmi/default
+    class hal
+    user system
+    group system
diff --git a/tv/hdmi/aidl/default/android.hardware.tv.hdmi-service.xml b/tv/hdmi/aidl/default/android.hardware.tv.hdmi-service.xml
new file mode 100644
index 0000000..a03c199
--- /dev/null
+++ b/tv/hdmi/aidl/default/android.hardware.tv.hdmi-service.xml
@@ -0,0 +1,10 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.tv.hdmi</name>
+        <version>1</version>
+        <interface>
+            <name>IHdmi</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/tv/hdmi/aidl/default/fuzzer.cpp b/tv/hdmi/aidl/default/fuzzer.cpp
new file mode 100644
index 0000000..06a2bc0
--- /dev/null
+++ b/tv/hdmi/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 <HdmiMock.h>
+#include <fuzzbinder/libbinder_ndk_driver.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+using android::fuzzService;
+using android::hardware::tv::hdmi::implementation::HdmiMock;
+using ndk::SharedRefBase;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    auto hdmiAidl = SharedRefBase::make<HdmiMock>();
+
+    fuzzService(hdmiAidl->asBinder().get(), FuzzedDataProvider(data, size));
+
+    return 0;
+}
diff --git a/tv/hdmi/aidl/default/serviceMock.cpp b/tv/hdmi/aidl/default/serviceMock.cpp
new file mode 100644
index 0000000..1d8bf51
--- /dev/null
+++ b/tv/hdmi/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.hdmi-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 "HdmiMock.h"
+
+using android::hardware::tv::hdmi::implementation::HdmiMock;
+
+int main() {
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+
+    std::shared_ptr<HdmiMock> hdmiAidl = ndk::SharedRefBase::make<HdmiMock>();
+    const std::string instance = std::string() + HdmiMock::descriptor + "/default";
+    binder_status_t status =
+            AServiceManager_addService(hdmiAidl->asBinder().get(), instance.c_str());
+    CHECK_EQ(status, STATUS_OK);
+
+    ABinderProcess_joinThreadPool();
+    return 0;
+}
diff --git a/tv/hdmi/aidl/vts/functional/Android.bp b/tv/hdmi/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..f9af58d
--- /dev/null
+++ b/tv/hdmi/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: "VtsHalTvHdmiAidlTargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: ["VtsHalTvHdmiAidlTargetTest.cpp"],
+    static_libs: [
+        "android.hardware.tv.hdmi-V1-ndk",
+    ],
+    shared_libs: [
+        "libbinder_ndk",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+    disable_framework: true,
+}
diff --git a/tv/hdmi/aidl/vts/functional/AndroidTest.xml b/tv/hdmi/aidl/vts/functional/AndroidTest.xml
new file mode 100644
index 0000000..0640b2d
--- /dev/null
+++ b/tv/hdmi/aidl/vts/functional/AndroidTest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 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.
+-->
+<configuration description="Runs VtsHalTvHdmiAidlTargetTest.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="VtsHalTvHdmiAidlTargetTest->/data/local/tmp/VtsHalTvHdmiAidlTargetTest" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="VtsHalTvHdmiAidlTargetTest" />
+        <option name="native-test-timeout" value="30m" />
+    </test>
+</configuration>
diff --git a/tv/hdmi/aidl/vts/functional/VtsHalTvHdmiAidlTargetTest.cpp b/tv/hdmi/aidl/vts/functional/VtsHalTvHdmiAidlTargetTest.cpp
new file mode 100644
index 0000000..78c2590
--- /dev/null
+++ b/tv/hdmi/aidl/vts/functional/VtsHalTvHdmiAidlTargetTest.cpp
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "Hdmi_hal_test"
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/tv/hdmi/BnHdmi.h>
+#include <aidl/android/hardware/tv/hdmi/BnHdmiCallback.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::hdmi::BnHdmiCallback;
+using ::aidl::android::hardware::tv::hdmi::HdmiPortInfo;
+using ::aidl::android::hardware::tv::hdmi::HdmiPortType;
+using ::aidl::android::hardware::tv::hdmi::IHdmi;
+using ::aidl::android::hardware::tv::hdmi::IHdmiCallback;
+using ::ndk::SpAIBinder;
+
+#define INCORRECT_VENDOR_ID 0x00
+#define TV_PHYSICAL_ADDRESS 0x0000
+
+// The main test class for TV HDMI HAL.
+class HdmiTest : public ::testing::TestWithParam<std::string> {
+    static void serviceDied(void* /* cookie */) { ALOGE("VtsHalTvCecAidlTargetTest died"); }
+
+  public:
+    void SetUp() override {
+        hdmi = IHdmi::fromBinder(SpAIBinder(AServiceManager_waitForService(GetParam().c_str())));
+        ASSERT_NE(hdmi, nullptr);
+        ALOGI("%s: getService() for hdmi is %s", __func__, hdmi->isRemote() ? "remote" : "local");
+
+        hdmiCallback = ::ndk::SharedRefBase::make<HdmiCallback>();
+        ASSERT_NE(hdmiCallback, nullptr);
+        hdmiDeathRecipient =
+                ndk::ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient_new(&serviceDied));
+        ASSERT_EQ(AIBinder_linkToDeath(hdmi->asBinder().get(), hdmiDeathRecipient.get(), 0),
+                  STATUS_OK);
+    }
+
+    class HdmiCallback : public BnHdmiCallback {
+      public:
+        ::ndk::ScopedAStatus onHotplugEvent(bool connected __unused, int32_t portId __unused) {
+            return ::ndk::ScopedAStatus::ok();
+        };
+    };
+
+    std::shared_ptr<IHdmi> hdmi;
+    std::shared_ptr<IHdmiCallback> hdmiCallback;
+    ::ndk::ScopedAIBinder_DeathRecipient hdmiDeathRecipient;
+};
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(HdmiTest);
+INSTANTIATE_TEST_SUITE_P(PerInstance, HdmiTest,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(IHdmi::descriptor)),
+                         android::PrintInstanceNameToString);
+
+TEST_P(HdmiTest, SetCallback) {
+    ASSERT_TRUE(hdmi->setCallback(::ndk::SharedRefBase::make<HdmiCallback>()).isOk());
+}
+
+TEST_P(HdmiTest, GetPortInfo) {
+    std::vector<HdmiPortInfo> ports;
+    ASSERT_TRUE(hdmi->getPortInfo(&ports).isOk());
+
+    bool cecSupportedOnDevice = false;
+    for (size_t i = 0; i < ports.size(); ++i) {
+        EXPECT_TRUE((ports[i].type == HdmiPortType::OUTPUT) ||
+                    (ports[i].type == HdmiPortType::INPUT));
+        if (ports[i].portId == 0) {
+            ALOGW("%s: Port id should start from 1", __func__);
+        }
+        cecSupportedOnDevice = cecSupportedOnDevice | ports[i].cecSupported;
+    }
+    EXPECT_NE(cecSupportedOnDevice, false) << "At least one port should support CEC";
+}
+
+TEST_P(HdmiTest, IsConnected) {
+    std::vector<HdmiPortInfo> ports;
+    ASSERT_TRUE(hdmi->getPortInfo(&ports).isOk());
+    for (size_t i = 0; i < ports.size(); ++i) {
+        bool connected;
+        ASSERT_TRUE(hdmi->isConnected(ports[i].portId, &connected).isOk());
+    }
+}
diff --git a/tv/input/aidl/default/TvInput.cpp b/tv/input/aidl/default/TvInput.cpp
index 6c3a138..ed12cbc 100644
--- a/tv/input/aidl/default/TvInput.cpp
+++ b/tv/input/aidl/default/TvInput.cpp
@@ -96,8 +96,7 @@
     }
     mStreamConfigs[in_deviceId][in_streamId]->handle = createNativeHandle(in_streamId);
     mStreamConfigs[in_deviceId][in_streamId]->isOpen = true;
-    NativeHandle aidlHandle = makeToAidl(mStreamConfigs[in_deviceId][in_streamId]->handle);
-    _aidl_return = &aidlHandle;
+    *_aidl_return = makeToAidl(mStreamConfigs[in_deviceId][in_streamId]->handle);
     return ::ndk::ScopedAStatus::ok();
 }
 
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/IDvr.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/IDvr.aidl
index 450cd79..4648712 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/IDvr.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/IDvr.aidl
@@ -43,4 +43,5 @@
   void stop();
   void flush();
   void close();
+  void setStatusCheckIntervalHint(in long milliseconds);
 }
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/android/hardware/tv/tuner/IDvr.aidl b/tv/tuner/aidl/android/hardware/tv/tuner/IDvr.aidl
index 0534f9d..4cb5b15 100644
--- a/tv/tuner/aidl/android/hardware/tv/tuner/IDvr.aidl
+++ b/tv/tuner/aidl/android/hardware/tv/tuner/IDvr.aidl
@@ -18,7 +18,6 @@
 
 import android.hardware.common.fmq.MQDescriptor;
 import android.hardware.common.fmq.SynchronizedReadWrite;
-
 import android.hardware.tv.tuner.DvrSettings;
 import android.hardware.tv.tuner.IFilter;
 
@@ -101,4 +100,12 @@
      * instance any more and all methods should return a failure.
      */
     void close();
+
+    /**
+     * Set status check time interval.
+     *
+     * This time interval hint will be used by the Dvr to decide how often
+     * to evaluate data.
+     */
+    void setStatusCheckIntervalHint(in long milliseconds);
 }
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/default/Android.bp b/tv/tuner/aidl/default/Android.bp
index c10ad22..65fa821 100644
--- a/tv/tuner/aidl/default/Android.bp
+++ b/tv/tuner/aidl/default/Android.bp
@@ -29,7 +29,7 @@
     ],
     shared_libs: [
         "android.hardware.common.fmq-V1-ndk",
-        "android.hardware.tv.tuner-V1-ndk",
+        "android.hardware.tv.tuner-V2-ndk",
         "libbase",
         "libbinder_ndk",
         "libcutils",
diff --git a/tv/tuner/aidl/default/Dvr.cpp b/tv/tuner/aidl/default/Dvr.cpp
index 9928a59..c9dd8ee 100644
--- a/tv/tuner/aidl/default/Dvr.cpp
+++ b/tv/tuner/aidl/default/Dvr.cpp
@@ -154,6 +154,14 @@
     return ::ndk::ScopedAStatus::ok();
 }
 
+::ndk::ScopedAStatus Dvr::setStatusCheckIntervalHint(int64_t /* in_milliseconds */) {
+    ALOGV("%s", __FUNCTION__);
+
+    // There is no active polling in this default implementation,
+    // so directly return ok here.
+    return ::ndk::ScopedAStatus::ok();
+}
+
 bool Dvr::createDvrMQ() {
     ALOGV("%s", __FUNCTION__);
 
diff --git a/tv/tuner/aidl/default/Dvr.h b/tv/tuner/aidl/default/Dvr.h
index 6ff71cd..293c533 100644
--- a/tv/tuner/aidl/default/Dvr.h
+++ b/tv/tuner/aidl/default/Dvr.h
@@ -70,6 +70,7 @@
     ::ndk::ScopedAStatus stop() override;
     ::ndk::ScopedAStatus flush() override;
     ::ndk::ScopedAStatus close() override;
+    ::ndk::ScopedAStatus setStatusCheckIntervalHint(int64_t in_milliseconds) override;
 
     binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
 
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/tv/tuner/aidl/vts/functional/Android.bp b/tv/tuner/aidl/vts/functional/Android.bp
index e5fb1e6..6a71544 100644
--- a/tv/tuner/aidl/vts/functional/Android.bp
+++ b/tv/tuner/aidl/vts/functional/Android.bp
@@ -53,7 +53,7 @@
         "android.hardware.cas@1.2",
         "android.hardware.common-V2-ndk",
         "android.hardware.common.fmq-V1-ndk",
-        "android.hardware.tv.tuner-V1-ndk",
+        "android.hardware.tv.tuner-V2-ndk",
         "libaidlcommonsupport",
         "libfmq",
         "libcutils",
diff --git a/tv/tuner/aidl/vts/functional/DvrTests.cpp b/tv/tuner/aidl/vts/functional/DvrTests.cpp
index a9c3b51..50f4de2 100644
--- a/tv/tuner/aidl/vts/functional/DvrTests.cpp
+++ b/tv/tuner/aidl/vts/functional/DvrTests.cpp
@@ -323,3 +323,41 @@
     ASSERT_TRUE(mDvrRecord);
     ASSERT_TRUE(mDvrRecord->close().isOk());
 }
+
+AssertionResult DvrTests::setPlaybackStatusCheckIntervalHint(int64_t milliseconds) {
+    ndk::ScopedAStatus status;
+    EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+    EXPECT_TRUE(mDvrPlayback) << "Test with openDvr first.";
+
+    status = mDvrPlayback->setStatusCheckIntervalHint(milliseconds);
+
+    if (getDvrPlaybackInterfaceVersion() < 2) {
+        return AssertionResult(status.getStatus() == STATUS_UNKNOWN_TRANSACTION);
+    }
+    return AssertionResult(status.isOk());
+}
+
+AssertionResult DvrTests::setRecordStatusCheckIntervalHint(int64_t milliseconds) {
+    ndk::ScopedAStatus status;
+    EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+    EXPECT_TRUE(mDvrRecord) << "Test with openDvr first.";
+
+    status = mDvrRecord->setStatusCheckIntervalHint(milliseconds);
+
+    if (getDvrRecordInterfaceVersion() < 2) {
+        return AssertionResult(status.getStatus() == STATUS_UNKNOWN_TRANSACTION);
+    }
+    return AssertionResult(status.isOk());
+}
+
+int32_t DvrTests::getDvrPlaybackInterfaceVersion() {
+    int32_t version;
+    mDvrPlayback->getInterfaceVersion(&version);
+    return version;
+}
+
+int32_t DvrTests::getDvrRecordInterfaceVersion() {
+    int32_t version;
+    mDvrRecord->getInterfaceVersion(&version);
+    return version;
+}
diff --git a/tv/tuner/aidl/vts/functional/DvrTests.h b/tv/tuner/aidl/vts/functional/DvrTests.h
index 6662637..a88ba24 100644
--- a/tv/tuner/aidl/vts/functional/DvrTests.h
+++ b/tv/tuner/aidl/vts/functional/DvrTests.h
@@ -162,8 +162,12 @@
     AssertionResult startDvrPlayback();
     AssertionResult stopDvrRecord();
     AssertionResult startDvrRecord();
+    AssertionResult setPlaybackStatusCheckIntervalHint(int64_t milliseconds);
+    AssertionResult setRecordStatusCheckIntervalHint(int64_t milliseconds);
     void closeDvrPlayback();
     void closeDvrRecord();
+    int32_t getDvrPlaybackInterfaceVersion();
+    int32_t getDvrRecordInterfaceVersion();
 
   protected:
     static AssertionResult failure() { return ::testing::AssertionFailure(); }
diff --git a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp
index 9a17d05..6aa1e16 100644
--- a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp
+++ b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp
@@ -241,6 +241,28 @@
     ASSERT_TRUE(mDemuxTests.closeDemux());
 }
 
+void TunerPlaybackAidlTest::setStatusCheckIntervalHintTest(int64_t statusCheckIntervalHint,
+                                                           DvrConfig dvrConf) {
+    int32_t demuxId;
+    std::shared_ptr<IDemux> demux;
+
+    ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
+    mDvrTests.setDemux(demux);
+    ASSERT_TRUE(mDvrTests.openDvrInDemux(dvrConf.type, dvrConf.bufferSize));
+    ASSERT_TRUE(mDvrTests.configDvrPlayback(dvrConf.settings));
+    ASSERT_TRUE(mDvrTests.getDvrPlaybackMQDescriptor());
+
+    ASSERT_TRUE(mDvrTests.setPlaybackStatusCheckIntervalHint(statusCheckIntervalHint));
+
+    mDvrTests.startPlaybackInputThread(dvrConf.playbackInputFile,
+                                       dvrConf.settings.get<DvrSettings::Tag::playback>());
+    ASSERT_TRUE(mDvrTests.startDvrPlayback());
+    mDvrTests.stopPlaybackThread();
+    ASSERT_TRUE(mDvrTests.stopDvrPlayback());
+    mDvrTests.closeDvrPlayback();
+    ASSERT_TRUE(mDemuxTests.closeDemux());
+}
+
 void TunerRecordAidlTest::recordSingleFilterTestWithLnb(FilterConfig filterConf,
                                                         FrontendConfig frontendConf,
                                                         DvrConfig dvrConf, LnbConfig lnbConf) {
@@ -426,6 +448,45 @@
     ASSERT_TRUE(mDemuxTests.closeDemux());
 }
 
+void TunerRecordAidlTest::setStatusCheckIntervalHintTest(int64_t statusCheckIntervalHint,
+                                                         FrontendConfig frontendConf,
+                                                         DvrConfig dvrConf) {
+    int32_t demuxId;
+    std::shared_ptr<IDemux> demux;
+    ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
+    mDvrTests.setDemux(demux);
+
+    DvrConfig dvrSourceConfig;
+    if (record.hasFrontendConnection) {
+        int32_t feId;
+        mFrontendTests.getFrontendIdByType(frontendConf.type, feId);
+        ASSERT_TRUE(feId != INVALID_ID);
+        ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
+        ASSERT_TRUE(mFrontendTests.setFrontendCallback());
+        ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
+    } else {
+        dvrSourceConfig = dvrMap[record.dvrSourceId];
+        ASSERT_TRUE(mDvrTests.openDvrInDemux(dvrSourceConfig.type, dvrSourceConfig.bufferSize));
+        ASSERT_TRUE(mDvrTests.configDvrPlayback(dvrSourceConfig.settings));
+        ASSERT_TRUE(mDvrTests.getDvrPlaybackMQDescriptor());
+    }
+
+    ASSERT_TRUE(mDvrTests.openDvrInDemux(dvrConf.type, dvrConf.bufferSize));
+    ASSERT_TRUE(mDvrTests.configDvrRecord(dvrConf.settings));
+    ASSERT_TRUE(mDvrTests.getDvrRecordMQDescriptor());
+
+    ASSERT_TRUE(mDvrTests.setRecordStatusCheckIntervalHint(statusCheckIntervalHint));
+
+    ASSERT_TRUE(mDvrTests.startDvrRecord());
+    ASSERT_TRUE(mDvrTests.stopDvrRecord());
+    mDvrTests.closeDvrRecord();
+    ASSERT_TRUE(mDemuxTests.closeDemux());
+
+    if (record.hasFrontendConnection) {
+        ASSERT_TRUE(mFrontendTests.closeFrontend());
+    }
+}
+
 void TunerDescramblerAidlTest::scrambledBroadcastTest(set<struct FilterConfig> mediaFilterConfs,
                                                       FrontendConfig frontendConf,
                                                       DescramblerConfig descConfig,
@@ -1000,6 +1061,18 @@
     }
 }
 
+TEST_P(TunerPlaybackAidlTest, SetStatusCheckIntervalHintToPlaybackTest) {
+    description("Set status check interval hint to playback test.");
+    if (!playback.support) {
+        return;
+    }
+    vector<DvrPlaybackHardwareConnections> playback_configs = generatePlaybackConfigs();
+    for (auto& configuration : playback_configs) {
+        playback = configuration;
+        setStatusCheckIntervalHintTest(STATUS_CHECK_INTERVAL_MS, dvrMap[playback.dvrId]);
+    }
+}
+
 TEST_P(TunerRecordAidlTest, RecordDataFlowWithTsRecordFilterTest) {
     description("Feed ts data from frontend to recording and test with ts record filter");
     if (!record.support) {
@@ -1046,6 +1119,19 @@
     }
 }
 
+TEST_P(TunerRecordAidlTest, SetStatusCheckIntervalHintToRecordTest) {
+    description("Set status check interval hint to record test.");
+    if (!record.support) {
+        return;
+    }
+    auto record_configs = generateRecordConfigurations();
+    for (auto& configuration : record_configs) {
+        record = configuration;
+        setStatusCheckIntervalHintTest(STATUS_CHECK_INTERVAL_MS, frontendMap[record.frontendId],
+                                       dvrMap[record.dvrRecordId]);
+    }
+}
+
 TEST_P(TunerFrontendAidlTest, TuneFrontend) {
     description("Tune one Frontend with specific setting and check Lock event");
     if (!live.hasFrontendConnection) {
diff --git a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h
index f68e1ec..3bfa78f 100644
--- a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h
+++ b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h
@@ -255,6 +255,8 @@
     AssertionResult filterDataOutputTest();
 
     void playbackSingleFilterTest(FilterConfig filterConf, DvrConfig dvrConf);
+
+    void setStatusCheckIntervalHintTest(int64_t milliseconds, DvrConfig dvrConf);
 };
 
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TunerPlaybackAidlTest);
@@ -294,6 +296,8 @@
                                        DvrConfig dvrConf, LnbConfig lnbConf);
     void recordSingleFilterTest(FilterConfig filterConf, FrontendConfig frontendConf,
                                 DvrConfig dvrConf, Dataflow_Context context);
+    void setStatusCheckIntervalHintTest(int64_t milliseconds, FrontendConfig frontendConf,
+                                        DvrConfig dvrConf);
 
     std::shared_ptr<ITuner> mService;
     FrontendTests mFrontendTests;
diff --git a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTestConfigurations.h b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTestConfigurations.h
index fea5f83..516cb62 100644
--- a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTestConfigurations.h
+++ b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTestConfigurations.h
@@ -55,6 +55,7 @@
 const string configFilePath = "/vendor/etc/tuner_vts_config_aidl_V1.xml";
 
 #define FILTER_MAIN_TYPE_BIT_COUNT 5
+#define STATUS_CHECK_INTERVAL_MS 100L
 
 // Hardware configs
 static map<string, FrontendConfig> frontendMap;
diff --git a/usb/1.0/default/Android.bp b/usb/1.0/default/Android.bp
index 4bed2c7..5f56fe0 100644
--- a/usb/1.0/default/Android.bp
+++ b/usb/1.0/default/Android.bp
@@ -21,21 +21,11 @@
     default_applicable_licenses: ["hardware_interfaces_license"],
 }
 
-filegroup {
-    name: "android.hardware.usb@1.0-service.xml",
-    srcs: ["android.hardware.usb@1.0-service.xml"],
-}
-
-filegroup {
-    name: "android.hardware.usb@1.0-service.rc",
-    srcs: ["android.hardware.usb@1.0-service.rc"],
-}
-
 cc_binary {
     name: "android.hardware.usb@1.0-service",
     defaults: ["hidl_defaults"],
-    init_rc: [":android.hardware.usb@1.0-service.rc"],
-    vintf_fragments: [":android.hardware.usb@1.0-service.xml"],
+    init_rc: ["android.hardware.usb@1.0-service.rc"],
+    vintf_fragments: ["android.hardware.usb@1.0-service.xml"],
     relative_install_path: "hw",
     vendor: true,
     srcs: [
diff --git a/usb/1.0/default/apex/Android.bp b/usb/1.0/default/apex/Android.bp
deleted file mode 100644
index ee50fdf..0000000
--- a/usb/1.0/default/apex/Android.bp
+++ /dev/null
@@ -1,59 +0,0 @@
-// 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 {
-    default_applicable_licenses: ["hardware_interfaces_license"],
-}
-
-apex_key {
-    name: "com.android.hardware.usb.key",
-    public_key: "com.android.hardware.usb.avbpubkey",
-    private_key: "com.android.hardware.usb.pem",
-}
-
-android_app_certificate {
-    name: "com.android.hardware.usb.certificate",
-    certificate: "com.android.hardware.usb",
-}
-
-genrule {
-    name: "com.android.hardware.usb.rc-gen",
-    srcs: [":android.hardware.usb@1.0-service.rc"],
-    out: ["com.android.hardware.usb.rc"],
-    cmd: "sed -E 's/\\/vendor/\\/apex\\/com.android.hardware.usb/' $(in) > $(out)",
-}
-
-prebuilt_etc {
-    name: "com.android.hardware.usb.rc",
-    src: ":com.android.hardware.usb.rc-gen",
-    installable: false,
-}
-
-apex {
-    name: "com.android.hardware.usb",
-    manifest: "manifest.json",
-    file_contexts: "file_contexts",
-    key: "com.android.hardware.usb.key",
-    certificate: ":com.android.hardware.usb.certificate",
-    updatable: false,
-    soc_specific: true,
-    use_vndk_as_stable: true,
-    binaries: ["android.hardware.usb@1.0-service"],
-    prebuilts: [
-        "com.android.hardware.usb.rc",
-        "android.hardware.usb.accessory.prebuilt.xml",
-        "android.hardware.usb.host.prebuilt.xml",
-    ],
-    vintf_fragments: [":android.hardware.usb@1.0-service.xml"],
-}
diff --git a/usb/1.0/default/apex/file_contexts b/usb/1.0/default/apex/file_contexts
deleted file mode 100644
index bc84ac4..0000000
--- a/usb/1.0/default/apex/file_contexts
+++ /dev/null
@@ -1,5 +0,0 @@
-(/.*)?                                         u:object_r:vendor_file:s0
-# Permission XMLs
-/etc/permissions(/.*)?                         u:object_r:vendor_configs_file:s0
-# binary
-/bin/hw/android\.hardware\.usb@1\.0-service    u:object_r:hal_usb_default_exec:s0
\ No newline at end of file
diff --git a/usb/1.0/default/apex/manifest.json b/usb/1.0/default/apex/manifest.json
deleted file mode 100644
index 6a1095f..0000000
--- a/usb/1.0/default/apex/manifest.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
-  "name": "com.android.hardware.usb",
-  "version": 1
-}
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/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/default/Android.bp b/usb/aidl/default/Android.bp
index 7cb2822..472e732 100644
--- a/usb/aidl/default/Android.bp
+++ b/usb/aidl/default/Android.bp
@@ -34,11 +34,21 @@
         "Usb.cpp",
     ],
     shared_libs: [
-        "android.hardware.usb-V1-ndk",
+        "android.hardware.usb-V2-ndk",
         "libbase",
         "libbinder_ndk",
-	"libcutils",
+        "libcutils",
         "liblog",
         "libutils",
     ],
 }
+
+filegroup {
+    name: "android.hardware.usb-service.example.xml",
+    srcs: ["android.hardware.usb-service.example.xml"],
+}
+
+filegroup {
+    name: "android.hardware.usb-service.example.rc",
+    srcs: ["android.hardware.usb-service.example.rc"],
+}
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..c4ec8a4 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;
@@ -560,6 +561,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/apex/Android.bp b/usb/apex/Android.bp
new file mode 100644
index 0000000..765aa21
--- /dev/null
+++ b/usb/apex/Android.bp
@@ -0,0 +1,60 @@
+// 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 {
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+apex_key {
+    name: "com.android.hardware.usb.key",
+    public_key: "com.android.hardware.usb.avbpubkey",
+    private_key: "com.android.hardware.usb.pem",
+}
+
+android_app_certificate {
+    name: "com.android.hardware.usb.certificate",
+    certificate: "com.android.hardware.usb",
+}
+
+apex {
+    name: "com.android.hardware.usb",
+    manifest: "manifest.json",
+    file_contexts: "file_contexts",
+    key: "com.android.hardware.usb.key",
+    certificate: ":com.android.hardware.usb.certificate",
+    updatable: false,
+    soc_specific: true,
+    use_vndk_as_stable: true,
+    binaries: ["android.hardware.usb-service.example"],
+    prebuilts: [
+        "com.android.hardware.usb.rc", // init .rc
+        "android.hardware.usb.accessory.prebuilt.xml",
+        "android.hardware.usb.host.prebuilt.xml",
+    ],
+    vintf_fragments: [":android.hardware.usb-service.example.xml"],
+}
+
+// Replace the binary path from /vendor/bin to /apex/{name}/bin in the init .rc file
+genrule {
+    name: "com.android.hardware.usb.rc-gen",
+    srcs: [":android.hardware.usb-service.example.rc"],
+    out: ["com.android.hardware.usb.rc"],
+    cmd: "sed -E 's/\\/vendor/\\/apex\\/com.android.hardware.usb/' $(in) > $(out)",
+}
+
+prebuilt_etc {
+    name: "com.android.hardware.usb.rc",
+    src: ":com.android.hardware.usb.rc-gen",
+    installable: false,
+}
diff --git a/usb/1.0/default/apex/com.android.hardware.usb.avbpubkey b/usb/apex/com.android.hardware.usb.avbpubkey
similarity index 100%
rename from usb/1.0/default/apex/com.android.hardware.usb.avbpubkey
rename to usb/apex/com.android.hardware.usb.avbpubkey
Binary files differ
diff --git a/usb/1.0/default/apex/com.android.hardware.usb.pem b/usb/apex/com.android.hardware.usb.pem
similarity index 100%
rename from usb/1.0/default/apex/com.android.hardware.usb.pem
rename to usb/apex/com.android.hardware.usb.pem
diff --git a/usb/1.0/default/apex/com.android.hardware.usb.pk8 b/usb/apex/com.android.hardware.usb.pk8
similarity index 100%
rename from usb/1.0/default/apex/com.android.hardware.usb.pk8
rename to usb/apex/com.android.hardware.usb.pk8
Binary files differ
diff --git a/usb/1.0/default/apex/com.android.hardware.usb.x509.pem b/usb/apex/com.android.hardware.usb.x509.pem
similarity index 100%
rename from usb/1.0/default/apex/com.android.hardware.usb.x509.pem
rename to usb/apex/com.android.hardware.usb.x509.pem
diff --git a/usb/apex/file_contexts b/usb/apex/file_contexts
new file mode 100644
index 0000000..f223a56
--- /dev/null
+++ b/usb/apex/file_contexts
@@ -0,0 +1,5 @@
+(/.*)?                                         u:object_r:vendor_file:s0
+# Permission XMLs
+/etc/permissions(/.*)?                         u:object_r:vendor_configs_file:s0
+# binary
+/bin/hw/android\.hardware\.usb-service\.example        u:object_r:hal_usb_default_exec:s0
\ No newline at end of file
diff --git a/usb/apex/manifest.json b/usb/apex/manifest.json
new file mode 100644
index 0000000..1a41b90
--- /dev/null
+++ b/usb/apex/manifest.json
@@ -0,0 +1,4 @@
+{
+    "name": "com.android.hardware.usb",
+    "version": 1
+}
diff --git a/usb/gadget/1.2/default/lib/UsbGadgetUtils.cpp b/usb/gadget/1.2/default/lib/UsbGadgetUtils.cpp
index fa50821..0924da7 100644
--- a/usb/gadget/1.2/default/lib/UsbGadgetUtils.cpp
+++ b/usb/gadget/1.2/default/lib/UsbGadgetUtils.cpp
@@ -170,7 +170,6 @@
 
     if ((functions & GadgetFunction::RNDIS) != 0) {
         ALOGI("setCurrentUsbFunctions rndis");
-        if (linkFunction("gsi.rndis", (*functionCount)++)) return Status::ERROR;
         std::string rndisFunction = GetProperty(kVendorRndisConfig, "");
         if (rndisFunction != "") {
             if (linkFunction(rndisFunction.c_str(), (*functionCount)++)) return Status::ERROR;
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 39bb5d9..6ec8d57 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
@@ -48,4 +48,5 @@
   SUPPORTED_RANGE_DATA_NTF_CONFIG = 229,
   SUPPORTED_RSSI_REPORTING = 230,
   SUPPORTED_DIAGNOSTICS = 231,
+  SUPPORTED_MIN_SLOT_DURATION = 232,
 }
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
index 86479fb..b182f9d 100644
--- a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
@@ -179,4 +179,9 @@
      *  0 - Feature not supported.
      */
     SUPPORTED_DIAGNOSTICS = 0xE7,
+
+    /**
+     * 4 byte value to indicate supported min slot duration in ms.
+     */
+    SUPPORTED_MIN_SLOT_DURATION = 0xE8,
 }
diff --git a/vibrator/aidl/Android.bp b/vibrator/aidl/Android.bp
index 86ef027..c5936e3 100644
--- a/vibrator/aidl/Android.bp
+++ b/vibrator/aidl/Android.bp
@@ -17,7 +17,7 @@
     stability: "vintf",
     backend: {
         java: {
-            sdk_version: "module_current",
+            sdk_version: "system_current",
         },
     },
     versions: [
diff --git a/vibrator/aidl/default/example_vendor_java_client/Android.bp b/vibrator/aidl/default/example_vendor_java_client/Android.bp
new file mode 100644
index 0000000..f615cb1
--- /dev/null
+++ b/vibrator/aidl/default/example_vendor_java_client/Android.bp
@@ -0,0 +1,34 @@
+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 {
+    name: "libexample_vib_getter",
+    srcs: ["getter.cpp"],
+    vendor: true,
+    shared_libs: [
+        "liblog",
+        "libbinder_ndk",
+    ],
+    header_libs: ["jni_headers"],
+    stl: "c++_shared",
+    visibility: [":__subpackages__"],
+}
+
+android_app {
+    name: "ExampleVibratorJavaVendorClient",
+    privileged: true,
+    vendor: true,
+    static_libs: ["android.hardware.vibrator-V1-java"],
+    jni_libs: ["libexample_vib_getter"],
+    jarjar_rules: "jarjar.txt",
+    stl: "c++_shared",
+    srcs: ["example/vib/MyActivity.java"],
+    sdk_version: "system_current",
+    visibility: [":__subpackages__"],
+}
diff --git a/vibrator/aidl/default/example_vendor_java_client/AndroidManifest.xml b/vibrator/aidl/default/example_vendor_java_client/AndroidManifest.xml
new file mode 100644
index 0000000..0561066
--- /dev/null
+++ b/vibrator/aidl/default/example_vendor_java_client/AndroidManifest.xml
@@ -0,0 +1,7 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          xmlns:tools="http://schemas.android.com/tools"
+          package="example.vib">
+    <application>
+        <activity android:name=".MyActivity"/>
+    </application>
+</manifest>
diff --git a/vibrator/aidl/default/example_vendor_java_client/example/vib/MyActivity.java b/vibrator/aidl/default/example_vendor_java_client/example/vib/MyActivity.java
new file mode 100644
index 0000000..aadce8e
--- /dev/null
+++ b/vibrator/aidl/default/example_vendor_java_client/example/vib/MyActivity.java
@@ -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 example.vib;
+
+import android.app.Activity;
+import android.hardware.vibrator.IVibrator;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+public class MyActivity extends Activity {
+    private static native IBinder gimme(String name);
+
+    @Override
+    public void onCreate(Bundle b) {
+        super.onCreate(b);
+        System.loadLibrary("example_vib_getter");
+
+        // There is no API to get ahold of a Stable AIDL service from a vendor app
+        // in Java. This is because this is not the recommended way to get ahold
+        // of functionality in Android. The Android API Council recommendation is to
+        // implement uses-library APIs in the system/system_ext partition which add
+        // new APIs. AIDL as an API in Java is not recommended or supported way to
+        // communicate by apps - the recommendation is to use Java APIs. However,
+        // there also exists a large number of vendor apps which are coupled with
+        // hardware-specific code, and are therefore on the vendor partition. A
+        // large number of these use HIDL, and this is how they can continue to
+        // use that structure with AIDL.
+        IVibrator v =
+                IVibrator.Stub.asInterface(gimme("android.hardware.vibrator.IVibrator/default"));
+
+        try {
+            v.on(100 /*ms*/, null /*cb*/);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+
+        finish();
+    }
+}
diff --git a/vibrator/aidl/default/example_vendor_java_client/getter.cpp b/vibrator/aidl/default/example_vendor_java_client/getter.cpp
new file mode 100644
index 0000000..6115445
--- /dev/null
+++ b/vibrator/aidl/default/example_vendor_java_client/getter.cpp
@@ -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.
+ */
+
+#include <android/binder_auto_utils.h>
+#include <android/binder_ibinder_jni.h>
+#include <android/binder_manager.h>
+#include <jni.h>
+#include <log/log.h>
+
+extern "C" JNIEXPORT jobject JNICALL
+Java_example_vib_MyActivity_gimme__Ljava_lang_String_2(JNIEnv* env, jclass /**/, jstring str) {
+    ALOGI("%s", __func__);
+
+    // Best practice is probably libnativehelper ScopedUtfChars or
+    // libbase ScopeGuard (for platform code), but this is with minimal
+    // dependencies.
+    const char* name = env->GetStringUTFChars(str, nullptr);
+
+    ALOGI("example vib gimme %s", name);
+
+    jobject jbinder = nullptr;
+
+    // Java does not have vendor variants. It's only safe to pass a service when
+    // 'vendor: true' if it is @VintfStability.
+    if (AServiceManager_isDeclared(name)) {
+        ndk::SpAIBinder binder = ndk::SpAIBinder(AServiceManager_waitForService(name));
+        jbinder = AIBinder_toJavaBinder(env, binder.get());
+    } else {
+        ALOGI("not declared");
+    }
+
+    env->ReleaseStringUTFChars(str, name);
+
+    return jbinder;
+}
diff --git a/vibrator/aidl/default/example_vendor_java_client/jarjar.txt b/vibrator/aidl/default/example_vendor_java_client/jarjar.txt
new file mode 100644
index 0000000..e7613a0
--- /dev/null
+++ b/vibrator/aidl/default/example_vendor_java_client/jarjar.txt
@@ -0,0 +1,2 @@
+rule android.hardware.** example.vib.ah.@1
+
diff --git a/wifi/1.0/vts/OWNERS b/wifi/1.0/vts/OWNERS
deleted file mode 100644
index 287152d..0000000
--- a/wifi/1.0/vts/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 33618
-arabawy@google.com
-etancohen@google.com
diff --git a/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp b/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
index e6e61cf..02f8209 100644
--- a/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
+++ b/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
@@ -66,7 +66,7 @@
 bool configureChipToSupportIfaceTypeInternal(const sp<IWifiChip>& wifi_chip,
                                              IfaceType type,
                                              ChipModeId* configured_mode_id) {
-    if (!configured_mode_id) {
+    if (!configured_mode_id || !wifi_chip.get()) {
         return false;
     }
     const auto& status_and_modes = HIDL_INVOKE(wifi_chip, getAvailableModes);
diff --git a/wifi/1.1/vts/OWNERS b/wifi/1.1/vts/OWNERS
deleted file mode 100644
index 294fc82..0000000
--- a/wifi/1.1/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 33618
-include ../../1.0/vts/OWNERS
diff --git a/wifi/1.2/vts/OWNERS b/wifi/1.2/vts/OWNERS
deleted file mode 100644
index 294fc82..0000000
--- a/wifi/1.2/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 33618
-include ../../1.0/vts/OWNERS
diff --git a/wifi/1.3/vts/OWNERS b/wifi/1.3/vts/OWNERS
deleted file mode 100644
index 294fc82..0000000
--- a/wifi/1.3/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 33618
-include ../../1.0/vts/OWNERS
diff --git a/wifi/1.4/vts/OWNERS b/wifi/1.4/vts/OWNERS
deleted file mode 100644
index 294fc82..0000000
--- a/wifi/1.4/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 33618
-include ../../1.0/vts/OWNERS
diff --git a/wifi/1.5/vts/OWNERS b/wifi/1.5/vts/OWNERS
deleted file mode 100644
index 294fc82..0000000
--- a/wifi/1.5/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 33618
-include ../../1.0/vts/OWNERS
diff --git a/wifi/1.6/default/Android.bp b/wifi/1.6/default/Android.bp
deleted file mode 100644
index a132dee..0000000
--- a/wifi/1.6/default/Android.bp
+++ /dev/null
@@ -1,228 +0,0 @@
-// 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 {
-    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@1.0-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@1.0-service-lib",
-    defaults: ["android.hardware.wifi@1.0-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: [
-        "hidl_struct_util.cpp",
-        "hidl_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",
-        "libcutils",
-        "libhidlbase",
-        "liblog",
-        "libnl",
-        "libutils",
-        "libwifi-hal",
-        "libwifi-system-iface",
-        "libxml2",
-        "android.hardware.wifi@1.0",
-        "android.hardware.wifi@1.1",
-        "android.hardware.wifi@1.2",
-        "android.hardware.wifi@1.3",
-        "android.hardware.wifi@1.4",
-        "android.hardware.wifi@1.5",
-        "android.hardware.wifi@1.6",
-    ],
-
-    export_include_dirs: ["."],
-}
-
-cc_binary {
-    name: "android.hardware.wifi@1.0-service",
-    vintf_fragments: ["android.hardware.wifi@1.0-service.xml"],
-    relative_install_path: "hw",
-    proprietary: true,
-    cppflags: [
-        "-Wall",
-        "-Werror",
-        "-Wextra",
-    ],
-    srcs: ["service.cpp"],
-    shared_libs: [
-        "libbase",
-        "libcutils",
-        "libhidlbase",
-        "liblog",
-        "libnl",
-        "libutils",
-        "libwifi-hal",
-        "libwifi-system-iface",
-        "libxml2",
-        "android.hardware.wifi@1.0",
-        "android.hardware.wifi@1.1",
-        "android.hardware.wifi@1.2",
-        "android.hardware.wifi@1.3",
-        "android.hardware.wifi@1.4",
-        "android.hardware.wifi@1.5",
-        "android.hardware.wifi@1.6",
-    ],
-    static_libs: ["android.hardware.wifi@1.0-service-lib"],
-    init_rc: ["android.hardware.wifi@1.0-service.rc"],
-}
-
-cc_binary {
-    name: "android.hardware.wifi@1.0-service-lazy",
-    vintf_fragments: ["android.hardware.wifi@1.0-service.xml"],
-    overrides: ["android.hardware.wifi@1.0-service"],
-    cflags: ["-DLAZY_SERVICE"],
-    relative_install_path: "hw",
-    proprietary: true,
-    cppflags: [
-        "-Wall",
-        "-Werror",
-        "-Wextra",
-    ],
-    srcs: ["service.cpp"],
-    shared_libs: [
-        "libbase",
-        "libcutils",
-        "libhidlbase",
-        "liblog",
-        "libnl",
-        "libutils",
-        "libwifi-hal",
-        "libwifi-system-iface",
-        "libxml2",
-        "android.hardware.wifi@1.0",
-        "android.hardware.wifi@1.1",
-        "android.hardware.wifi@1.2",
-        "android.hardware.wifi@1.3",
-        "android.hardware.wifi@1.4",
-        "android.hardware.wifi@1.5",
-        "android.hardware.wifi@1.6",
-    ],
-    static_libs: ["android.hardware.wifi@1.0-service-lib"],
-    init_rc: ["android.hardware.wifi@1.0-service-lazy.rc"],
-}
-
-cc_test {
-    name: "android.hardware.wifi@1.0-service-tests",
-    proprietary: true,
-    compile_multilib: "first",
-    cppflags: [
-        "-Wall",
-        "-Werror",
-        "-Wextra",
-    ],
-    srcs: [
-        "tests/hidl_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@1.0",
-        "android.hardware.wifi@1.1",
-        "android.hardware.wifi@1.2",
-        "android.hardware.wifi@1.3",
-        "android.hardware.wifi@1.4",
-        "android.hardware.wifi@1.5",
-        "android.hardware.wifi@1.6",
-        "android.hardware.wifi@1.0-service-lib",
-    ],
-    shared_libs: [
-        "libbase",
-        "libcutils",
-        "libhidlbase",
-        "liblog",
-        "libnl",
-        "libutils",
-        "libwifi-hal",
-        "libwifi-system-iface",
-    ],
-}
diff --git a/wifi/1.6/default/OWNERS b/wifi/1.6/default/OWNERS
deleted file mode 100644
index cf81c79..0000000
--- a/wifi/1.6/default/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-arabawy@google.com
-etancohen@google.com
diff --git a/wifi/1.6/default/THREADING.README b/wifi/1.6/default/THREADING.README
deleted file mode 100644
index 8366ca0..0000000
--- a/wifi/1.6/default/THREADING.README
+++ /dev/null
@@ -1,35 +0,0 @@
-Vendor HAL Threading Model
-==========================
-The vendor HAL service has two threads:
-1. HIDL thread: This is the main thread which processes all the incoming HIDL
-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 function 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 HIDL
-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 HIDL methods will also acquire the global lock before processing
-(in hidl_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
-HIDL 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/1.6/default/android.hardware.wifi@1.0-service-lazy.rc b/wifi/1.6/default/android.hardware.wifi@1.0-service-lazy.rc
deleted file mode 100644
index ee8c818..0000000
--- a/wifi/1.6/default/android.hardware.wifi@1.0-service-lazy.rc
+++ /dev/null
@@ -1,14 +0,0 @@
-service vendor.wifi_hal_legacy /vendor/bin/hw/android.hardware.wifi@1.0-service-lazy
-    interface android.hardware.wifi@1.0::IWifi default
-    interface android.hardware.wifi@1.1::IWifi default
-    interface android.hardware.wifi@1.2::IWifi default
-    interface android.hardware.wifi@1.3::IWifi default
-    interface android.hardware.wifi@1.4::IWifi default
-    interface android.hardware.wifi@1.5::IWifi default
-    interface android.hardware.wifi@1.6::IWifi default
-    oneshot
-    disabled
-    class hal
-    capabilities NET_ADMIN NET_RAW SYS_MODULE
-    user wifi
-    group wifi gps
diff --git a/wifi/1.6/default/android.hardware.wifi@1.0-service.rc b/wifi/1.6/default/android.hardware.wifi@1.0-service.rc
deleted file mode 100644
index 18f40d0..0000000
--- a/wifi/1.6/default/android.hardware.wifi@1.0-service.rc
+++ /dev/null
@@ -1,12 +0,0 @@
-service vendor.wifi_hal_legacy /vendor/bin/hw/android.hardware.wifi@1.0-service
-    interface android.hardware.wifi@1.0::IWifi default
-    interface android.hardware.wifi@1.1::IWifi default
-    interface android.hardware.wifi@1.2::IWifi default
-    interface android.hardware.wifi@1.3::IWifi default
-    interface android.hardware.wifi@1.4::IWifi default
-    interface android.hardware.wifi@1.5::IWifi default
-    interface android.hardware.wifi@1.6::IWifi default
-    class hal
-    capabilities NET_ADMIN NET_RAW SYS_MODULE
-    user wifi
-    group wifi gps
diff --git a/wifi/1.6/default/android.hardware.wifi@1.0-service.xml b/wifi/1.6/default/android.hardware.wifi@1.0-service.xml
deleted file mode 100644
index 771fbaa..0000000
--- a/wifi/1.6/default/android.hardware.wifi@1.0-service.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<manifest version="1.0" type="device">
-    <hal format="hidl">
-        <name>android.hardware.wifi</name>
-        <transport>hwbinder</transport>
-        <version>1.6</version>
-        <interface>
-            <name>IWifi</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-</manifest>
diff --git a/wifi/1.6/default/hidl_callback_util.h b/wifi/1.6/default/hidl_callback_util.h
deleted file mode 100644
index aab0ae5..0000000
--- a/wifi/1.6/default/hidl_callback_util.h
+++ /dev/null
@@ -1,122 +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 HIDL_CALLBACK_UTIL_H_
-#define HIDL_CALLBACK_UTIL_H_
-
-#include <set>
-
-#include <hidl/HidlSupport.h>
-#include <hidl/HidlTransportSupport.h>
-
-namespace {
-// Type of callback invoked by the death handler.
-using on_death_cb_function = std::function<void(uint64_t)>;
-
-// Private class used to keep track of death of individual
-// callbacks stored in HidlCallbackHandler.
-template <typename CallbackType>
-class HidlDeathHandler : public android::hardware::hidl_death_recipient {
-  public:
-    HidlDeathHandler(const on_death_cb_function& user_cb_function)
-        : cb_function_(user_cb_function) {}
-    ~HidlDeathHandler() = default;
-
-    // Death notification for callbacks.
-    void serviceDied(uint64_t cookie,
-                     const android::wp<android::hidl::base::V1_0::IBase>& /* who */) override {
-        cb_function_(cookie);
-    }
-
-  private:
-    on_death_cb_function cb_function_;
-
-    DISALLOW_COPY_AND_ASSIGN(HidlDeathHandler);
-};
-}  // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-namespace hidl_callback_util {
-template <typename CallbackType>
-// Provides a class to manage callbacks for the various HIDL interfaces and
-// handle the death of the process hosting each callback.
-class HidlCallbackHandler {
-  public:
-    HidlCallbackHandler()
-        : death_handler_(new HidlDeathHandler<CallbackType>(
-                  std::bind(&HidlCallbackHandler::onObjectDeath, this, std::placeholders::_1))) {}
-    ~HidlCallbackHandler() = default;
-
-    bool addCallback(const sp<CallbackType>& cb) {
-        // TODO(b/33818800): Can't compare proxies yet. So, use the cookie
-        // (callback proxy's raw pointer) to track the death of individual
-        // clients.
-        uint64_t cookie = reinterpret_cast<uint64_t>(cb.get());
-        for (const auto& s : cb_set_) {
-            if (interfacesEqual(cb, s)) {
-                LOG(ERROR) << "Duplicate death notification registration";
-                return true;
-            }
-        }
-        if (!cb->linkToDeath(death_handler_, cookie)) {
-            LOG(ERROR) << "Failed to register death notification";
-            return false;
-        }
-        cb_set_.insert(cb);
-        return true;
-    }
-
-    const std::set<android::sp<CallbackType>>& getCallbacks() { return cb_set_; }
-
-    // Death notification for callbacks.
-    void onObjectDeath(uint64_t cookie) {
-        CallbackType* cb = reinterpret_cast<CallbackType*>(cookie);
-        const auto& iter = cb_set_.find(cb);
-        if (iter == cb_set_.end()) {
-            LOG(ERROR) << "Unknown callback death notification received";
-            return;
-        }
-        cb_set_.erase(iter);
-        LOG(DEBUG) << "Dead callback removed from list";
-    }
-
-    void invalidate() {
-        for (const sp<CallbackType>& cb : cb_set_) {
-            if (!cb->unlinkToDeath(death_handler_)) {
-                LOG(ERROR) << "Failed to deregister death notification";
-            }
-        }
-        cb_set_.clear();
-    }
-
-  private:
-    std::set<sp<CallbackType>> cb_set_;
-    sp<HidlDeathHandler<CallbackType>> death_handler_;
-
-    DISALLOW_COPY_AND_ASSIGN(HidlCallbackHandler);
-};
-
-}  // namespace hidl_callback_util
-}  // namespace implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-#endif  // HIDL_CALLBACK_UTIL_H_
diff --git a/wifi/1.6/default/hidl_return_util.h b/wifi/1.6/default/hidl_return_util.h
deleted file mode 100644
index a0efac2..0000000
--- a/wifi/1.6/default/hidl_return_util.h
+++ /dev/null
@@ -1,118 +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 HIDL_RETURN_UTIL_H_
-#define HIDL_RETURN_UTIL_H_
-
-#include "hidl_sync_util.h"
-#include "wifi_status_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-namespace hidl_return_util {
-using namespace android::hardware::wifi::V1_0;
-
-/**
- * These utility functions are used to invoke a method on the provided
- * HIDL interface object.
- * These functions checks if the provided HIDL interface object is valid.
- * a) if valid, Invokes the corresponding internal implementation function of
- * the HIDL method. It then invokes the HIDL continuation callback with
- * the status and any returned values.
- * b) if invalid, invokes the HIDL continuation callback with the
- * provided error status and default values.
- */
-// Use for HIDL methods which return only an instance of WifiStatus.
-template <typename ObjT, typename WorkFuncT, typename... Args>
-Return<void> validateAndCall(ObjT* obj, WifiStatusCode status_code_if_invalid, WorkFuncT&& work,
-                             const std::function<void(const WifiStatus&)>& hidl_cb,
-                             Args&&... args) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (obj->isValid()) {
-        hidl_cb((obj->*work)(std::forward<Args>(args)...));
-    } else {
-        hidl_cb(createWifiStatus(status_code_if_invalid));
-    }
-    return Void();
-}
-
-// Use for HIDL methods which return only an instance of WifiStatus.
-// This version passes the global lock acquired to the body of the method.
-// Note: Only used by IWifi::stop() currently.
-template <typename ObjT, typename WorkFuncT, typename... Args>
-Return<void> validateAndCallWithLock(ObjT* obj, WifiStatusCode status_code_if_invalid,
-                                     WorkFuncT&& work,
-                                     const std::function<void(const WifiStatus&)>& hidl_cb,
-                                     Args&&... args) {
-    auto lock = hidl_sync_util::acquireGlobalLock();
-    if (obj->isValid()) {
-        hidl_cb((obj->*work)(&lock, std::forward<Args>(args)...));
-    } else {
-        hidl_cb(createWifiStatus(status_code_if_invalid));
-    }
-    return Void();
-}
-
-// Use for HIDL methods which return instance of WifiStatus and a single return
-// value.
-template <typename ObjT, typename WorkFuncT, typename ReturnT, typename... Args>
-Return<void> validateAndCall(ObjT* obj, WifiStatusCode status_code_if_invalid, WorkFuncT&& work,
-                             const std::function<void(const WifiStatus&, ReturnT)>& hidl_cb,
-                             Args&&... args) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (obj->isValid()) {
-        const auto& ret_pair = (obj->*work)(std::forward<Args>(args)...);
-        const WifiStatus& status = std::get<0>(ret_pair);
-        const auto& ret_value = std::get<1>(ret_pair);
-        hidl_cb(status, ret_value);
-    } else {
-        hidl_cb(createWifiStatus(status_code_if_invalid),
-                typename std::remove_reference<ReturnT>::type());
-    }
-    return Void();
-}
-
-// Use for HIDL methods which return instance of WifiStatus and 2 return
-// values.
-template <typename ObjT, typename WorkFuncT, typename ReturnT1, typename ReturnT2, typename... Args>
-Return<void> validateAndCall(
-        ObjT* obj, WifiStatusCode status_code_if_invalid, WorkFuncT&& work,
-        const std::function<void(const WifiStatus&, ReturnT1, ReturnT2)>& hidl_cb, Args&&... args) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (obj->isValid()) {
-        const auto& ret_tuple = (obj->*work)(std::forward<Args>(args)...);
-        const WifiStatus& status = std::get<0>(ret_tuple);
-        const auto& ret_value1 = std::get<1>(ret_tuple);
-        const auto& ret_value2 = std::get<2>(ret_tuple);
-        hidl_cb(status, ret_value1, ret_value2);
-    } else {
-        hidl_cb(createWifiStatus(status_code_if_invalid),
-                typename std::remove_reference<ReturnT1>::type(),
-                typename std::remove_reference<ReturnT2>::type());
-    }
-    return Void();
-}
-
-}  // namespace hidl_return_util
-}  // namespace implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-#endif  // HIDL_RETURN_UTIL_H_
diff --git a/wifi/1.6/default/hidl_struct_util.cpp b/wifi/1.6/default/hidl_struct_util.cpp
deleted file mode 100644
index 2112b26..0000000
--- a/wifi/1.6/default/hidl_struct_util.cpp
+++ /dev/null
@@ -1,3007 +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.
- */
-
-#include <android-base/logging.h>
-#include <utils/SystemClock.h>
-
-#include "hidl_struct_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-namespace hidl_struct_util {
-
-using V1_6::NanConfigRequestSupplemental;
-
-WifiChannelWidthInMhz convertLegacyWifiChannelWidthToHidl(legacy_hal::wifi_channel_width type);
-
-hidl_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 hidl_string(str, size);
-}
-
-IWifiChip::ChipCapabilityMask convertLegacyLoggerFeatureToHidlChipCapability(uint32_t feature) {
-    using HidlChipCaps = IWifiChip::ChipCapabilityMask;
-    switch (feature) {
-        case legacy_hal::WIFI_LOGGER_MEMORY_DUMP_SUPPORTED:
-            return HidlChipCaps::DEBUG_MEMORY_FIRMWARE_DUMP;
-        case legacy_hal::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED:
-            return HidlChipCaps::DEBUG_MEMORY_DRIVER_DUMP;
-        case legacy_hal::WIFI_LOGGER_CONNECT_EVENT_SUPPORTED:
-            return HidlChipCaps::DEBUG_RING_BUFFER_CONNECT_EVENT;
-        case legacy_hal::WIFI_LOGGER_POWER_EVENT_SUPPORTED:
-            return HidlChipCaps::DEBUG_RING_BUFFER_POWER_EVENT;
-        case legacy_hal::WIFI_LOGGER_WAKE_LOCK_SUPPORTED:
-            return HidlChipCaps::DEBUG_RING_BUFFER_WAKELOCK_EVENT;
-    };
-    CHECK(false) << "Unknown legacy feature: " << feature;
-    return {};
-}
-
-IWifiStaIface::StaIfaceCapabilityMask convertLegacyLoggerFeatureToHidlStaIfaceCapability(
-        uint32_t feature) {
-    using HidlStaIfaceCaps = IWifiStaIface::StaIfaceCapabilityMask;
-    switch (feature) {
-        case legacy_hal::WIFI_LOGGER_PACKET_FATE_SUPPORTED:
-            return HidlStaIfaceCaps::DEBUG_PACKET_FATE;
-    };
-    CHECK(false) << "Unknown legacy feature: " << feature;
-    return {};
-}
-
-V1_5::IWifiChip::ChipCapabilityMask convertLegacyFeatureToHidlChipCapability(uint64_t feature) {
-    using HidlChipCaps = V1_5::IWifiChip::ChipCapabilityMask;
-    switch (feature) {
-        case WIFI_FEATURE_SET_TX_POWER_LIMIT:
-            return HidlChipCaps::SET_TX_POWER_LIMIT;
-        case WIFI_FEATURE_USE_BODY_HEAD_SAR:
-            return HidlChipCaps::USE_BODY_HEAD_SAR;
-        case WIFI_FEATURE_D2D_RTT:
-            return HidlChipCaps::D2D_RTT;
-        case WIFI_FEATURE_D2AP_RTT:
-            return HidlChipCaps::D2AP_RTT;
-        case WIFI_FEATURE_INFRA_60G:
-            return HidlChipCaps::WIGIG;
-        case WIFI_FEATURE_SET_LATENCY_MODE:
-            return HidlChipCaps::SET_LATENCY_MODE;
-        case WIFI_FEATURE_P2P_RAND_MAC:
-            return HidlChipCaps::P2P_RAND_MAC;
-    };
-    CHECK(false) << "Unknown legacy feature: " << feature;
-    return {};
-}
-
-IWifiStaIface::StaIfaceCapabilityMask convertLegacyFeatureToHidlStaIfaceCapability(
-        uint64_t feature) {
-    using HidlStaIfaceCaps = IWifiStaIface::StaIfaceCapabilityMask;
-    switch (feature) {
-        case WIFI_FEATURE_GSCAN:
-            return HidlStaIfaceCaps::BACKGROUND_SCAN;
-        case WIFI_FEATURE_LINK_LAYER_STATS:
-            return HidlStaIfaceCaps::LINK_LAYER_STATS;
-        case WIFI_FEATURE_RSSI_MONITOR:
-            return HidlStaIfaceCaps::RSSI_MONITOR;
-        case WIFI_FEATURE_CONTROL_ROAMING:
-            return HidlStaIfaceCaps::CONTROL_ROAMING;
-        case WIFI_FEATURE_IE_WHITELIST:
-            return HidlStaIfaceCaps::PROBE_IE_WHITELIST;
-        case WIFI_FEATURE_SCAN_RAND:
-            return HidlStaIfaceCaps::SCAN_RAND;
-        case WIFI_FEATURE_INFRA_5G:
-            return HidlStaIfaceCaps::STA_5G;
-        case WIFI_FEATURE_HOTSPOT:
-            return HidlStaIfaceCaps::HOTSPOT;
-        case WIFI_FEATURE_PNO:
-            return HidlStaIfaceCaps::PNO;
-        case WIFI_FEATURE_TDLS:
-            return HidlStaIfaceCaps::TDLS;
-        case WIFI_FEATURE_TDLS_OFFCHANNEL:
-            return HidlStaIfaceCaps::TDLS_OFFCHANNEL;
-        case WIFI_FEATURE_CONFIG_NDO:
-            return HidlStaIfaceCaps::ND_OFFLOAD;
-        case WIFI_FEATURE_MKEEP_ALIVE:
-            return HidlStaIfaceCaps::KEEP_ALIVE;
-    };
-    CHECK(false) << "Unknown legacy feature: " << feature;
-    return {};
-}
-
-bool convertLegacyFeaturesToHidlChipCapabilities(uint64_t legacy_feature_set,
-                                                 uint32_t legacy_logger_feature_set,
-                                                 uint32_t* hidl_caps) {
-    if (!hidl_caps) {
-        return false;
-    }
-    *hidl_caps = {};
-    using HidlChipCaps = IWifiChip::ChipCapabilityMask;
-    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) {
-            *hidl_caps |= convertLegacyLoggerFeatureToHidlChipCapability(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) {
-            *hidl_caps |= convertLegacyFeatureToHidlChipCapability(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.
-    *hidl_caps |= HidlChipCaps::DEBUG_RING_BUFFER_VENDOR_DATA;
-    *hidl_caps |= HidlChipCaps::DEBUG_HOST_WAKE_REASON_STATS;
-    *hidl_caps |= HidlChipCaps::DEBUG_ERROR_ALERTS;
-    return true;
-}
-
-WifiDebugRingBufferFlags convertLegacyDebugRingBufferFlagsToHidl(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 convertLegacyDebugRingBufferStatusToHidl(
-        const legacy_hal::wifi_ring_buffer_status& legacy_status,
-        WifiDebugRingBufferStatus* hidl_status) {
-    if (!hidl_status) {
-        return false;
-    }
-    *hidl_status = {};
-    hidl_status->ringName = safeConvertChar(reinterpret_cast<const char*>(legacy_status.name),
-                                            sizeof(legacy_status.name));
-    hidl_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) {
-            hidl_status->flags |= static_cast<std::underlying_type<WifiDebugRingBufferFlags>::type>(
-                    convertLegacyDebugRingBufferFlagsToHidl(flag));
-        }
-    }
-    hidl_status->ringId = legacy_status.ring_id;
-    hidl_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) {
-        hidl_status->freeSizeInBytes = legacy_status.ring_buffer_byte_size -
-                                       (legacy_status.written_bytes - legacy_status.read_bytes);
-    } else {
-        hidl_status->freeSizeInBytes = legacy_status.read_bytes - legacy_status.written_bytes;
-    }
-    hidl_status->verboseLevel = legacy_status.verbose_level;
-    return true;
-}
-
-bool convertLegacyVectorOfDebugRingBufferStatusToHidl(
-        const std::vector<legacy_hal::wifi_ring_buffer_status>& legacy_status_vec,
-        std::vector<WifiDebugRingBufferStatus>* hidl_status_vec) {
-    if (!hidl_status_vec) {
-        return false;
-    }
-    *hidl_status_vec = {};
-    for (const auto& legacy_status : legacy_status_vec) {
-        WifiDebugRingBufferStatus hidl_status;
-        if (!convertLegacyDebugRingBufferStatusToHidl(legacy_status, &hidl_status)) {
-            return false;
-        }
-        hidl_status_vec->push_back(hidl_status);
-    }
-    return true;
-}
-
-bool convertLegacyWakeReasonStatsToHidl(const legacy_hal::WakeReasonStats& legacy_stats,
-                                        WifiDebugHostWakeReasonStats* hidl_stats) {
-    if (!hidl_stats) {
-        return false;
-    }
-    *hidl_stats = {};
-    hidl_stats->totalCmdEventWakeCnt = legacy_stats.wake_reason_cnt.total_cmd_event_wake;
-    hidl_stats->cmdEventWakeCntPerType = legacy_stats.cmd_event_wake_cnt;
-    hidl_stats->totalDriverFwLocalWakeCnt = legacy_stats.wake_reason_cnt.total_driver_fw_local_wake;
-    hidl_stats->driverFwLocalWakeCntPerType = legacy_stats.driver_fw_local_wake_cnt;
-    hidl_stats->totalRxPacketWakeCnt = legacy_stats.wake_reason_cnt.total_rx_data_wake;
-    hidl_stats->rxPktWakeDetails.rxUnicastCnt =
-            legacy_stats.wake_reason_cnt.rx_wake_details.rx_unicast_cnt;
-    hidl_stats->rxPktWakeDetails.rxMulticastCnt =
-            legacy_stats.wake_reason_cnt.rx_wake_details.rx_multicast_cnt;
-    hidl_stats->rxPktWakeDetails.rxBroadcastCnt =
-            legacy_stats.wake_reason_cnt.rx_wake_details.rx_broadcast_cnt;
-    hidl_stats->rxMulticastPkWakeDetails.ipv4RxMulticastAddrCnt =
-            legacy_stats.wake_reason_cnt.rx_multicast_wake_pkt_info.ipv4_rx_multicast_addr_cnt;
-    hidl_stats->rxMulticastPkWakeDetails.ipv6RxMulticastAddrCnt =
-            legacy_stats.wake_reason_cnt.rx_multicast_wake_pkt_info.ipv6_rx_multicast_addr_cnt;
-    hidl_stats->rxMulticastPkWakeDetails.otherRxMulticastAddrCnt =
-            legacy_stats.wake_reason_cnt.rx_multicast_wake_pkt_info.other_rx_multicast_addr_cnt;
-    hidl_stats->rxIcmpPkWakeDetails.icmpPkt =
-            legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp_pkt;
-    hidl_stats->rxIcmpPkWakeDetails.icmp6Pkt =
-            legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_pkt;
-    hidl_stats->rxIcmpPkWakeDetails.icmp6Ra =
-            legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_ra;
-    hidl_stats->rxIcmpPkWakeDetails.icmp6Na =
-            legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_na;
-    hidl_stats->rxIcmpPkWakeDetails.icmp6Ns =
-            legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_ns;
-    return true;
-}
-
-legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy(
-        V1_1::IWifiChip::TxPowerScenario hidl_scenario) {
-    switch (hidl_scenario) {
-        // This is the only supported scenario for V1_1
-        case V1_1::IWifiChip::TxPowerScenario::VOICE_CALL:
-            return legacy_hal::WIFI_POWER_SCENARIO_VOICE_CALL;
-    };
-    CHECK(false);
-}
-
-legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy_1_2(
-        V1_2::IWifiChip::TxPowerScenario hidl_scenario) {
-    switch (hidl_scenario) {
-        // This is the only supported scenario for V1_1
-        case V1_2::IWifiChip::TxPowerScenario::VOICE_CALL:
-            return legacy_hal::WIFI_POWER_SCENARIO_VOICE_CALL;
-        // Those are the supported scenarios for V1_2
-        case V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF:
-            return legacy_hal::WIFI_POWER_SCENARIO_ON_HEAD_CELL_OFF;
-        case V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_ON:
-            return legacy_hal::WIFI_POWER_SCENARIO_ON_HEAD_CELL_ON;
-        case V1_2::IWifiChip::TxPowerScenario::ON_BODY_CELL_OFF:
-            return legacy_hal::WIFI_POWER_SCENARIO_ON_BODY_CELL_OFF;
-        case V1_2::IWifiChip::TxPowerScenario::ON_BODY_CELL_ON:
-            return legacy_hal::WIFI_POWER_SCENARIO_ON_BODY_CELL_ON;
-    };
-    CHECK(false);
-}
-
-legacy_hal::wifi_latency_mode convertHidlLatencyModeToLegacy(
-        V1_3::IWifiChip::LatencyMode hidl_latency_mode) {
-    switch (hidl_latency_mode) {
-        case V1_3::IWifiChip::LatencyMode::NORMAL:
-            return legacy_hal::WIFI_LATENCY_MODE_NORMAL;
-        case V1_3::IWifiChip::LatencyMode::LOW:
-            return legacy_hal::WIFI_LATENCY_MODE_LOW;
-    }
-    CHECK(false);
-}
-
-bool convertLegacyWifiMacInfoToHidl(
-        const legacy_hal::WifiMacInfo& legacy_mac_info,
-        V1_4::IWifiChipEventCallback::RadioModeInfo* hidl_radio_mode_info) {
-    if (!hidl_radio_mode_info) {
-        return false;
-    }
-    *hidl_radio_mode_info = {};
-
-    hidl_radio_mode_info->radioId = legacy_mac_info.wlan_mac_id;
-    // Convert from bitmask of bands in the legacy HAL to enum value in
-    // the HIDL interface.
-    if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_6_0_BAND &&
-        legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND &&
-        legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_2_4_BAND) {
-        hidl_radio_mode_info->bandInfo = V1_4::WifiBand::BAND_24GHZ_5GHZ_6GHZ;
-    } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_6_0_BAND &&
-               legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND) {
-        hidl_radio_mode_info->bandInfo = V1_4::WifiBand::BAND_5GHZ_6GHZ;
-    } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_6_0_BAND) {
-        hidl_radio_mode_info->bandInfo = V1_4::WifiBand::BAND_6GHZ;
-    } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_2_4_BAND &&
-               legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND) {
-        hidl_radio_mode_info->bandInfo = V1_4::WifiBand::BAND_24GHZ_5GHZ;
-    } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_2_4_BAND) {
-        hidl_radio_mode_info->bandInfo = V1_4::WifiBand::BAND_24GHZ;
-    } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND) {
-        hidl_radio_mode_info->bandInfo = V1_4::WifiBand::BAND_5GHZ;
-    } else {
-        hidl_radio_mode_info->bandInfo = V1_4::WifiBand::BAND_UNSPECIFIED;
-    }
-    std::vector<V1_2::IWifiChipEventCallback::IfaceInfo> iface_info_vec;
-    for (const auto& legacy_iface_info : legacy_mac_info.iface_infos) {
-        V1_2::IWifiChipEventCallback::IfaceInfo iface_info;
-        iface_info.name = legacy_iface_info.name;
-        iface_info.channel = legacy_iface_info.channel;
-        iface_info_vec.push_back(iface_info);
-    }
-    hidl_radio_mode_info->ifaceInfos = iface_info_vec;
-    return true;
-}
-
-uint32_t convertHidlWifiBandToLegacyMacBand(V1_5::WifiBand hidl_band) {
-    switch (hidl_band) {
-        case V1_5::WifiBand::BAND_24GHZ:
-            return legacy_hal::WLAN_MAC_2_4_BAND;
-        case V1_5::WifiBand::BAND_5GHZ:
-        case V1_5::WifiBand::BAND_5GHZ_DFS:
-        case V1_5::WifiBand::BAND_5GHZ_WITH_DFS:
-            return legacy_hal::WLAN_MAC_5_0_BAND;
-        case V1_5::WifiBand::BAND_24GHZ_5GHZ:
-        case V1_5::WifiBand::BAND_24GHZ_5GHZ_WITH_DFS:
-            return (legacy_hal::WLAN_MAC_2_4_BAND | legacy_hal::WLAN_MAC_5_0_BAND);
-        case V1_5::WifiBand::BAND_6GHZ:
-            return legacy_hal::WLAN_MAC_6_0_BAND;
-        case V1_5::WifiBand::BAND_5GHZ_6GHZ:
-            return (legacy_hal::WLAN_MAC_5_0_BAND | legacy_hal::WLAN_MAC_6_0_BAND);
-        case V1_5::WifiBand::BAND_24GHZ_5GHZ_6GHZ:
-        case V1_5::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 V1_5::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);
-    }
-}
-
-V1_5::WifiBand convertLegacyMacBandToHidlWifiBand(uint32_t band) {
-    switch (band) {
-        case legacy_hal::WLAN_MAC_2_4_BAND:
-            return V1_5::WifiBand::BAND_24GHZ;
-        case legacy_hal::WLAN_MAC_5_0_BAND:
-            return V1_5::WifiBand::BAND_5GHZ;
-        case legacy_hal::WLAN_MAC_6_0_BAND:
-            return V1_5::WifiBand::BAND_6GHZ;
-        case legacy_hal::WLAN_MAC_60_0_BAND:
-            return V1_5::WifiBand::BAND_60GHZ;
-        default:
-            return V1_5::WifiBand::BAND_UNSPECIFIED;
-    }
-}
-
-uint32_t convertHidlWifiIfaceModeToLegacy(uint32_t hidl_iface_mask) {
-    uint32_t legacy_iface_mask = 0;
-    if (hidl_iface_mask & V1_5::WifiIfaceMode::IFACE_MODE_STA) {
-        legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_STA);
-    }
-    if (hidl_iface_mask & V1_5::WifiIfaceMode::IFACE_MODE_SOFTAP) {
-        legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_SOFTAP);
-    }
-    if (hidl_iface_mask & V1_5::WifiIfaceMode::IFACE_MODE_P2P_CLIENT) {
-        legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_P2P_CLIENT);
-    }
-    if (hidl_iface_mask & V1_5::WifiIfaceMode::IFACE_MODE_P2P_GO) {
-        legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_P2P_GO);
-    }
-    if (hidl_iface_mask & V1_5::WifiIfaceMode::IFACE_MODE_NAN) {
-        legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_NAN);
-    }
-    if (hidl_iface_mask & V1_5::WifiIfaceMode::IFACE_MODE_TDLS) {
-        legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_TDLS);
-    }
-    if (hidl_iface_mask & V1_5::WifiIfaceMode::IFACE_MODE_MESH) {
-        legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_MESH);
-    }
-    if (hidl_iface_mask & V1_5::WifiIfaceMode::IFACE_MODE_IBSS) {
-        legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_IBSS);
-    }
-    return legacy_iface_mask;
-}
-
-uint32_t convertLegacyWifiInterfaceModeToHidl(uint32_t legacy_iface_mask) {
-    uint32_t hidl_iface_mask = 0;
-    if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_STA)) {
-        hidl_iface_mask |= V1_5::WifiIfaceMode::IFACE_MODE_STA;
-    }
-    if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_SOFTAP)) {
-        hidl_iface_mask |= V1_5::WifiIfaceMode::IFACE_MODE_SOFTAP;
-    }
-    if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_P2P_CLIENT)) {
-        hidl_iface_mask |= V1_5::WifiIfaceMode::IFACE_MODE_P2P_CLIENT;
-    }
-    if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_P2P_GO)) {
-        hidl_iface_mask |= V1_5::WifiIfaceMode::IFACE_MODE_P2P_GO;
-    }
-    if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_NAN)) {
-        hidl_iface_mask |= V1_5::WifiIfaceMode::IFACE_MODE_NAN;
-    }
-    if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_TDLS)) {
-        hidl_iface_mask |= V1_5::WifiIfaceMode::IFACE_MODE_TDLS;
-    }
-    if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_MESH)) {
-        hidl_iface_mask |= V1_5::WifiIfaceMode::IFACE_MODE_MESH;
-    }
-    if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_IBSS)) {
-        hidl_iface_mask |= V1_5::WifiIfaceMode::IFACE_MODE_IBSS;
-    }
-    return hidl_iface_mask;
-}
-
-uint32_t convertHidlUsableChannelFilterToLegacy(uint32_t hidl_filter_mask) {
-    uint32_t legacy_filter_mask = 0;
-    if (hidl_filter_mask & V1_5::IWifiChip::UsableChannelFilter::CELLULAR_COEXISTENCE) {
-        legacy_filter_mask |= legacy_hal::WIFI_USABLE_CHANNEL_FILTER_CELLULAR_COEXISTENCE;
-    }
-    if (hidl_filter_mask & V1_5::IWifiChip::UsableChannelFilter::CONCURRENCY) {
-        legacy_filter_mask |= legacy_hal::WIFI_USABLE_CHANNEL_FILTER_CONCURRENCY;
-    }
-    if (hidl_filter_mask & V1_6::IWifiChip::UsableChannelFilter::NAN_INSTANT_MODE) {
-        legacy_filter_mask |= WIFI_USABLE_CHANNEL_FILTER_NAN_INSTANT_MODE;
-    }
-    return legacy_filter_mask;
-}
-
-bool convertLegacyWifiUsableChannelToHidl(
-        const legacy_hal::wifi_usable_channel& legacy_usable_channel,
-        V1_6::WifiUsableChannel* hidl_usable_channel) {
-    if (!hidl_usable_channel) {
-        return false;
-    }
-    *hidl_usable_channel = {};
-    hidl_usable_channel->channel = legacy_usable_channel.freq;
-    hidl_usable_channel->channelBandwidth =
-            convertLegacyWifiChannelWidthToHidl(legacy_usable_channel.width);
-    hidl_usable_channel->ifaceModeMask =
-            convertLegacyWifiInterfaceModeToHidl(legacy_usable_channel.iface_mode_mask);
-
-    return true;
-}
-
-bool convertLegacyWifiUsableChannelsToHidl(
-        const std::vector<legacy_hal::wifi_usable_channel>& legacy_usable_channels,
-        std::vector<V1_6::WifiUsableChannel>* hidl_usable_channels) {
-    if (!hidl_usable_channels) {
-        return false;
-    }
-    *hidl_usable_channels = {};
-    for (const auto& legacy_usable_channel : legacy_usable_channels) {
-        V1_6::WifiUsableChannel hidl_usable_channel;
-        if (!convertLegacyWifiUsableChannelToHidl(legacy_usable_channel, &hidl_usable_channel)) {
-            return false;
-        }
-        hidl_usable_channels->push_back(hidl_usable_channel);
-    }
-    return true;
-}
-
-bool convertLegacyWifiMacInfosToHidl(
-        const std::vector<legacy_hal::WifiMacInfo>& legacy_mac_infos,
-        std::vector<V1_4::IWifiChipEventCallback::RadioModeInfo>* hidl_radio_mode_infos) {
-    if (!hidl_radio_mode_infos) {
-        return false;
-    }
-    *hidl_radio_mode_infos = {};
-
-    for (const auto& legacy_mac_info : legacy_mac_infos) {
-        V1_4::IWifiChipEventCallback::RadioModeInfo hidl_radio_mode_info;
-        if (!convertLegacyWifiMacInfoToHidl(legacy_mac_info, &hidl_radio_mode_info)) {
-            return false;
-        }
-        hidl_radio_mode_infos->push_back(hidl_radio_mode_info);
-    }
-    return true;
-}
-
-bool convertLegacyFeaturesToHidlStaCapabilities(uint64_t legacy_feature_set,
-                                                uint32_t legacy_logger_feature_set,
-                                                uint32_t* hidl_caps) {
-    if (!hidl_caps) {
-        return false;
-    }
-    *hidl_caps = {};
-    using HidlStaIfaceCaps = IWifiStaIface::StaIfaceCapabilityMask;
-    for (const auto feature : {legacy_hal::WIFI_LOGGER_PACKET_FATE_SUPPORTED}) {
-        if (feature & legacy_logger_feature_set) {
-            *hidl_caps |= convertLegacyLoggerFeatureToHidlStaIfaceCapability(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) {
-            *hidl_caps |= convertLegacyFeatureToHidlStaIfaceCapability(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.
-    *hidl_caps |= HidlStaIfaceCaps::APF;
-    return true;
-}
-
-bool convertLegacyApfCapabilitiesToHidl(const legacy_hal::PacketFilterCapabilities& legacy_caps,
-                                        StaApfPacketFilterCapabilities* hidl_caps) {
-    if (!hidl_caps) {
-        return false;
-    }
-    *hidl_caps = {};
-    hidl_caps->version = legacy_caps.version;
-    hidl_caps->maxLength = legacy_caps.max_len;
-    return true;
-}
-
-uint8_t convertHidlGscanReportEventFlagToLegacy(
-        StaBackgroundScanBucketEventReportSchemeMask hidl_flag) {
-    using HidlFlag = StaBackgroundScanBucketEventReportSchemeMask;
-    switch (hidl_flag) {
-        case HidlFlag::EACH_SCAN:
-            return REPORT_EVENTS_EACH_SCAN;
-        case HidlFlag::FULL_RESULTS:
-            return REPORT_EVENTS_FULL_RESULTS;
-        case HidlFlag::NO_BATCH:
-            return REPORT_EVENTS_NO_BATCH;
-    };
-    CHECK(false);
-}
-
-StaScanDataFlagMask convertLegacyGscanDataFlagToHidl(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 convertLegacyGscanCapabilitiesToHidl(const legacy_hal::wifi_gscan_capabilities& legacy_caps,
-                                          StaBackgroundScanCapabilities* hidl_caps) {
-    if (!hidl_caps) {
-        return false;
-    }
-    *hidl_caps = {};
-    hidl_caps->maxCacheSize = legacy_caps.max_scan_cache_size;
-    hidl_caps->maxBuckets = legacy_caps.max_scan_buckets;
-    hidl_caps->maxApCachePerScan = legacy_caps.max_ap_cache_per_scan;
-    hidl_caps->maxReportingThreshold = legacy_caps.max_scan_reporting_threshold;
-    return true;
-}
-
-legacy_hal::wifi_band convertHidlWifiBandToLegacy(V1_0::WifiBand band) {
-    switch (band) {
-        case V1_0::WifiBand::BAND_UNSPECIFIED:
-            return legacy_hal::WIFI_BAND_UNSPECIFIED;
-        case V1_0::WifiBand::BAND_24GHZ:
-            return legacy_hal::WIFI_BAND_BG;
-        case V1_0::WifiBand::BAND_5GHZ:
-            return legacy_hal::WIFI_BAND_A;
-        case V1_0::WifiBand::BAND_5GHZ_DFS:
-            return legacy_hal::WIFI_BAND_A_DFS;
-        case V1_0::WifiBand::BAND_5GHZ_WITH_DFS:
-            return legacy_hal::WIFI_BAND_A_WITH_DFS;
-        case V1_0::WifiBand::BAND_24GHZ_5GHZ:
-            return legacy_hal::WIFI_BAND_ABG;
-        case V1_0::WifiBand::BAND_24GHZ_5GHZ_WITH_DFS:
-            return legacy_hal::WIFI_BAND_ABG_WITH_DFS;
-    };
-    CHECK(false);
-}
-
-bool convertHidlGscanParamsToLegacy(const StaBackgroundScanParameters& hidl_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 = hidl_scan_params.basePeriodInMs;
-    legacy_scan_params->max_ap_per_scan = hidl_scan_params.maxApPerScan;
-    legacy_scan_params->report_threshold_percent = hidl_scan_params.reportThresholdPercent;
-    legacy_scan_params->report_threshold_num_scans = hidl_scan_params.reportThresholdNumScans;
-    if (hidl_scan_params.buckets.size() > MAX_BUCKETS) {
-        return false;
-    }
-    legacy_scan_params->num_buckets = hidl_scan_params.buckets.size();
-    for (uint32_t bucket_idx = 0; bucket_idx < hidl_scan_params.buckets.size(); bucket_idx++) {
-        const StaBackgroundScanBucketParameters& hidl_bucket_spec =
-                hidl_scan_params.buckets[bucket_idx];
-        legacy_hal::wifi_scan_bucket_spec& legacy_bucket_spec =
-                legacy_scan_params->buckets[bucket_idx];
-        if (hidl_bucket_spec.bucketIdx >= MAX_BUCKETS) {
-            return false;
-        }
-        legacy_bucket_spec.bucket = hidl_bucket_spec.bucketIdx;
-        legacy_bucket_spec.band = convertHidlWifiBandToLegacy(hidl_bucket_spec.band);
-        legacy_bucket_spec.period = hidl_bucket_spec.periodInMs;
-        legacy_bucket_spec.max_period = hidl_bucket_spec.exponentialMaxPeriodInMs;
-        legacy_bucket_spec.base = hidl_bucket_spec.exponentialBase;
-        legacy_bucket_spec.step_count = hidl_bucket_spec.exponentialStepCount;
-        legacy_bucket_spec.report_events = 0;
-        using HidlFlag = StaBackgroundScanBucketEventReportSchemeMask;
-        for (const auto flag : {HidlFlag::EACH_SCAN, HidlFlag::FULL_RESULTS, HidlFlag::NO_BATCH}) {
-            if (hidl_bucket_spec.eventReportScheme &
-                static_cast<std::underlying_type<HidlFlag>::type>(flag)) {
-                legacy_bucket_spec.report_events |= convertHidlGscanReportEventFlagToLegacy(flag);
-            }
-        }
-        if (hidl_bucket_spec.frequencies.size() > MAX_CHANNELS) {
-            return false;
-        }
-        legacy_bucket_spec.num_channels = hidl_bucket_spec.frequencies.size();
-        for (uint32_t freq_idx = 0; freq_idx < hidl_bucket_spec.frequencies.size(); freq_idx++) {
-            legacy_bucket_spec.channels[freq_idx].channel = hidl_bucket_spec.frequencies[freq_idx];
-        }
-    }
-    return true;
-}
-
-bool convertLegacyIeToHidl(const legacy_hal::wifi_information_element& legacy_ie,
-                           WifiInformationElement* hidl_ie) {
-    if (!hidl_ie) {
-        return false;
-    }
-    *hidl_ie = {};
-    hidl_ie->id = legacy_ie.id;
-    hidl_ie->data = std::vector<uint8_t>(legacy_ie.data, legacy_ie.data + legacy_ie.len);
-    return true;
-}
-
-bool convertLegacyIeBlobToHidl(const uint8_t* ie_blob, uint32_t ie_blob_len,
-                               std::vector<WifiInformationElement>* hidl_ies) {
-    if (!ie_blob || !hidl_ies) {
-        return false;
-    }
-    *hidl_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 atleast 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 hidl_ie;
-        if (!convertLegacyIeToHidl(legacy_ie, &hidl_ie)) {
-            LOG(ERROR) << "Error converting IE. Id: " << legacy_ie.id << ", len: " << legacy_ie.len;
-            break;
-        }
-        hidl_ies->push_back(std::move(hidl_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 convertLegacyGscanResultToHidl(const legacy_hal::wifi_scan_result& legacy_scan_result,
-                                    bool has_ie_data, StaScanResult* hidl_scan_result) {
-    if (!hidl_scan_result) {
-        return false;
-    }
-    *hidl_scan_result = {};
-    hidl_scan_result->timeStampInUs = legacy_scan_result.ts;
-    hidl_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));
-    memcpy(hidl_scan_result->bssid.data(), legacy_scan_result.bssid,
-           hidl_scan_result->bssid.size());
-    hidl_scan_result->frequency = legacy_scan_result.channel;
-    hidl_scan_result->rssi = legacy_scan_result.rssi;
-    hidl_scan_result->beaconPeriodInMs = legacy_scan_result.beacon_period;
-    hidl_scan_result->capability = legacy_scan_result.capability;
-    if (has_ie_data) {
-        std::vector<WifiInformationElement> ies;
-        if (!convertLegacyIeBlobToHidl(reinterpret_cast<const uint8_t*>(legacy_scan_result.ie_data),
-                                       legacy_scan_result.ie_length, &ies)) {
-            return false;
-        }
-        hidl_scan_result->informationElements = std::move(ies);
-    }
-    return true;
-}
-
-bool convertLegacyCachedGscanResultsToHidl(
-        const legacy_hal::wifi_cached_scan_results& legacy_cached_scan_result,
-        StaScanData* hidl_scan_data) {
-    if (!hidl_scan_data) {
-        return false;
-    }
-    *hidl_scan_data = {};
-    hidl_scan_data->flags = 0;
-    for (const auto flag : {legacy_hal::WIFI_SCAN_FLAG_INTERRUPTED}) {
-        if (legacy_cached_scan_result.flags & flag) {
-            hidl_scan_data->flags |= static_cast<std::underlying_type<StaScanDataFlagMask>::type>(
-                    convertLegacyGscanDataFlagToHidl(flag));
-        }
-    }
-    hidl_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> hidl_scan_results;
-    for (int32_t result_idx = 0; result_idx < legacy_cached_scan_result.num_results; result_idx++) {
-        StaScanResult hidl_scan_result;
-        if (!convertLegacyGscanResultToHidl(legacy_cached_scan_result.results[result_idx], false,
-                                            &hidl_scan_result)) {
-            return false;
-        }
-        hidl_scan_results.push_back(hidl_scan_result);
-    }
-    hidl_scan_data->results = std::move(hidl_scan_results);
-    return true;
-}
-
-bool convertLegacyVectorOfCachedGscanResultsToHidl(
-        const std::vector<legacy_hal::wifi_cached_scan_results>& legacy_cached_scan_results,
-        std::vector<StaScanData>* hidl_scan_datas) {
-    if (!hidl_scan_datas) {
-        return false;
-    }
-    *hidl_scan_datas = {};
-    for (const auto& legacy_cached_scan_result : legacy_cached_scan_results) {
-        StaScanData hidl_scan_data;
-        if (!convertLegacyCachedGscanResultsToHidl(legacy_cached_scan_result, &hidl_scan_data)) {
-            return false;
-        }
-        hidl_scan_datas->push_back(hidl_scan_data);
-    }
-    return true;
-}
-
-WifiDebugTxPacketFate convertLegacyDebugTxPacketFateToHidl(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 convertLegacyDebugRxPacketFateToHidl(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 convertLegacyDebugPacketFateFrameTypeToHidl(
-        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 convertLegacyDebugPacketFateFrameToHidl(const legacy_hal::frame_info& legacy_frame,
-                                             WifiDebugPacketFateFrameInfo* hidl_frame) {
-    if (!hidl_frame) {
-        return false;
-    }
-    *hidl_frame = {};
-    hidl_frame->frameType = convertLegacyDebugPacketFateFrameTypeToHidl(legacy_frame.payload_type);
-    hidl_frame->frameLen = legacy_frame.frame_len;
-    hidl_frame->driverTimestampUsec = legacy_frame.driver_timestamp_usec;
-    hidl_frame->firmwareTimestampUsec = legacy_frame.firmware_timestamp_usec;
-    const uint8_t* frame_begin =
-            reinterpret_cast<const uint8_t*>(legacy_frame.frame_content.ethernet_ii_bytes);
-    hidl_frame->frameContent =
-            std::vector<uint8_t>(frame_begin, frame_begin + legacy_frame.frame_len);
-    return true;
-}
-
-bool convertLegacyDebugTxPacketFateToHidl(const legacy_hal::wifi_tx_report& legacy_fate,
-                                          WifiDebugTxPacketFateReport* hidl_fate) {
-    if (!hidl_fate) {
-        return false;
-    }
-    *hidl_fate = {};
-    hidl_fate->fate = convertLegacyDebugTxPacketFateToHidl(legacy_fate.fate);
-    return convertLegacyDebugPacketFateFrameToHidl(legacy_fate.frame_inf, &hidl_fate->frameInfo);
-}
-
-bool convertLegacyVectorOfDebugTxPacketFateToHidl(
-        const std::vector<legacy_hal::wifi_tx_report>& legacy_fates,
-        std::vector<WifiDebugTxPacketFateReport>* hidl_fates) {
-    if (!hidl_fates) {
-        return false;
-    }
-    *hidl_fates = {};
-    for (const auto& legacy_fate : legacy_fates) {
-        WifiDebugTxPacketFateReport hidl_fate;
-        if (!convertLegacyDebugTxPacketFateToHidl(legacy_fate, &hidl_fate)) {
-            return false;
-        }
-        hidl_fates->push_back(hidl_fate);
-    }
-    return true;
-}
-
-bool convertLegacyDebugRxPacketFateToHidl(const legacy_hal::wifi_rx_report& legacy_fate,
-                                          WifiDebugRxPacketFateReport* hidl_fate) {
-    if (!hidl_fate) {
-        return false;
-    }
-    *hidl_fate = {};
-    hidl_fate->fate = convertLegacyDebugRxPacketFateToHidl(legacy_fate.fate);
-    return convertLegacyDebugPacketFateFrameToHidl(legacy_fate.frame_inf, &hidl_fate->frameInfo);
-}
-
-bool convertLegacyVectorOfDebugRxPacketFateToHidl(
-        const std::vector<legacy_hal::wifi_rx_report>& legacy_fates,
-        std::vector<WifiDebugRxPacketFateReport>* hidl_fates) {
-    if (!hidl_fates) {
-        return false;
-    }
-    *hidl_fates = {};
-    for (const auto& legacy_fate : legacy_fates) {
-        WifiDebugRxPacketFateReport hidl_fate;
-        if (!convertLegacyDebugRxPacketFateToHidl(legacy_fate, &hidl_fate)) {
-            return false;
-        }
-        hidl_fates->push_back(hidl_fate);
-    }
-    return true;
-}
-
-bool convertLegacyLinkLayerRadioStatsToHidl(
-        const legacy_hal::LinkLayerRadioStats& legacy_radio_stat,
-        V1_6::StaLinkLayerRadioStats* hidl_radio_stat) {
-    if (!hidl_radio_stat) {
-        return false;
-    }
-    *hidl_radio_stat = {};
-
-    hidl_radio_stat->radioId = legacy_radio_stat.stats.radio;
-    hidl_radio_stat->V1_0.onTimeInMs = legacy_radio_stat.stats.on_time;
-    hidl_radio_stat->V1_0.txTimeInMs = legacy_radio_stat.stats.tx_time;
-    hidl_radio_stat->V1_0.rxTimeInMs = legacy_radio_stat.stats.rx_time;
-    hidl_radio_stat->V1_0.onTimeInMsForScan = legacy_radio_stat.stats.on_time_scan;
-    hidl_radio_stat->V1_0.txTimeInMsPerLevel = legacy_radio_stat.tx_time_per_levels;
-    hidl_radio_stat->onTimeInMsForNanScan = legacy_radio_stat.stats.on_time_nbd;
-    hidl_radio_stat->onTimeInMsForBgScan = legacy_radio_stat.stats.on_time_gscan;
-    hidl_radio_stat->onTimeInMsForRoamScan = legacy_radio_stat.stats.on_time_roam_scan;
-    hidl_radio_stat->onTimeInMsForPnoScan = legacy_radio_stat.stats.on_time_pno_scan;
-    hidl_radio_stat->onTimeInMsForHs20Scan = legacy_radio_stat.stats.on_time_hs20;
-
-    std::vector<V1_6::WifiChannelStats> hidl_channel_stats;
-
-    for (const auto& channel_stat : legacy_radio_stat.channel_stats) {
-        V1_6::WifiChannelStats hidl_channel_stat;
-        hidl_channel_stat.onTimeInMs = channel_stat.on_time;
-        hidl_channel_stat.ccaBusyTimeInMs = channel_stat.cca_busy_time;
-        /*
-         * TODO once b/119142899 is fixed,
-         * replace below code with convertLegacyWifiChannelInfoToHidl()
-         */
-        hidl_channel_stat.channel.width = WifiChannelWidthInMhz::WIDTH_20;
-        hidl_channel_stat.channel.centerFreq = channel_stat.channel.center_freq;
-        hidl_channel_stat.channel.centerFreq0 = channel_stat.channel.center_freq0;
-        hidl_channel_stat.channel.centerFreq1 = channel_stat.channel.center_freq1;
-        hidl_channel_stats.push_back(hidl_channel_stat);
-    }
-
-    hidl_radio_stat->channelStats = hidl_channel_stats;
-
-    return true;
-}
-
-bool convertLegacyLinkLayerStatsToHidl(const legacy_hal::LinkLayerStats& legacy_stats,
-                                       V1_6::StaLinkLayerStats* hidl_stats) {
-    if (!hidl_stats) {
-        return false;
-    }
-    *hidl_stats = {};
-    // iface legacy_stats conversion.
-    hidl_stats->iface.V1_0.beaconRx = legacy_stats.iface.beacon_rx;
-    hidl_stats->iface.V1_0.avgRssiMgmt = legacy_stats.iface.rssi_mgmt;
-    hidl_stats->iface.V1_0.wmeBePktStats.rxMpdu =
-            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu;
-    hidl_stats->iface.V1_0.wmeBePktStats.txMpdu =
-            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu;
-    hidl_stats->iface.V1_0.wmeBePktStats.lostMpdu =
-            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost;
-    hidl_stats->iface.V1_0.wmeBePktStats.retries =
-            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries;
-    hidl_stats->iface.wmeBeContentionTimeStats.contentionTimeMinInUsec =
-            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_min;
-    hidl_stats->iface.wmeBeContentionTimeStats.contentionTimeMaxInUsec =
-            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_max;
-    hidl_stats->iface.wmeBeContentionTimeStats.contentionTimeAvgInUsec =
-            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_avg;
-    hidl_stats->iface.wmeBeContentionTimeStats.contentionNumSamples =
-            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_num_samples;
-    hidl_stats->iface.V1_0.wmeBkPktStats.rxMpdu =
-            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu;
-    hidl_stats->iface.V1_0.wmeBkPktStats.txMpdu =
-            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu;
-    hidl_stats->iface.V1_0.wmeBkPktStats.lostMpdu =
-            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost;
-    hidl_stats->iface.V1_0.wmeBkPktStats.retries =
-            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries;
-    hidl_stats->iface.wmeBkContentionTimeStats.contentionTimeMinInUsec =
-            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_min;
-    hidl_stats->iface.wmeBkContentionTimeStats.contentionTimeMaxInUsec =
-            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_max;
-    hidl_stats->iface.wmeBkContentionTimeStats.contentionTimeAvgInUsec =
-            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_avg;
-    hidl_stats->iface.wmeBkContentionTimeStats.contentionNumSamples =
-            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_num_samples;
-    hidl_stats->iface.V1_0.wmeViPktStats.rxMpdu =
-            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu;
-    hidl_stats->iface.V1_0.wmeViPktStats.txMpdu =
-            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu;
-    hidl_stats->iface.V1_0.wmeViPktStats.lostMpdu =
-            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost;
-    hidl_stats->iface.V1_0.wmeViPktStats.retries =
-            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries;
-    hidl_stats->iface.wmeViContentionTimeStats.contentionTimeMinInUsec =
-            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_min;
-    hidl_stats->iface.wmeViContentionTimeStats.contentionTimeMaxInUsec =
-            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_max;
-    hidl_stats->iface.wmeViContentionTimeStats.contentionTimeAvgInUsec =
-            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_avg;
-    hidl_stats->iface.wmeViContentionTimeStats.contentionNumSamples =
-            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_num_samples;
-    hidl_stats->iface.V1_0.wmeVoPktStats.rxMpdu =
-            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu;
-    hidl_stats->iface.V1_0.wmeVoPktStats.txMpdu =
-            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu;
-    hidl_stats->iface.V1_0.wmeVoPktStats.lostMpdu =
-            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost;
-    hidl_stats->iface.V1_0.wmeVoPktStats.retries =
-            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries;
-    hidl_stats->iface.wmeVoContentionTimeStats.contentionTimeMinInUsec =
-            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_min;
-    hidl_stats->iface.wmeVoContentionTimeStats.contentionTimeMaxInUsec =
-            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_max;
-    hidl_stats->iface.wmeVoContentionTimeStats.contentionTimeAvgInUsec =
-            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_avg;
-    hidl_stats->iface.wmeVoContentionTimeStats.contentionNumSamples =
-            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_num_samples;
-    hidl_stats->iface.timeSliceDutyCycleInPercent =
-            legacy_stats.iface.info.time_slicing_duty_cycle_percent;
-    // peer info legacy_stats conversion.
-    std::vector<V1_6::StaPeerInfo> hidl_peers_info_stats;
-    for (const auto& legacy_peer_info_stats : legacy_stats.peers) {
-        V1_6::StaPeerInfo hidl_peer_info_stats;
-        if (!convertLegacyPeerInfoStatsToHidl(legacy_peer_info_stats, &hidl_peer_info_stats)) {
-            return false;
-        }
-        hidl_peers_info_stats.push_back(hidl_peer_info_stats);
-    }
-    hidl_stats->iface.peers = hidl_peers_info_stats;
-    // radio legacy_stats conversion.
-    std::vector<V1_6::StaLinkLayerRadioStats> hidl_radios_stats;
-    for (const auto& legacy_radio_stats : legacy_stats.radios) {
-        V1_6::StaLinkLayerRadioStats hidl_radio_stats;
-        if (!convertLegacyLinkLayerRadioStatsToHidl(legacy_radio_stats, &hidl_radio_stats)) {
-            return false;
-        }
-        hidl_radios_stats.push_back(hidl_radio_stats);
-    }
-    hidl_stats->radios = hidl_radios_stats;
-    // Timestamp in the HAL wrapper here since it's not provided in the legacy
-    // HAL API.
-    hidl_stats->timeStampInMs = uptimeMillis();
-    return true;
-}
-
-bool convertLegacyPeerInfoStatsToHidl(const legacy_hal::WifiPeerInfo& legacy_peer_info_stats,
-                                      V1_6::StaPeerInfo* hidl_peer_info_stats) {
-    if (!hidl_peer_info_stats) {
-        return false;
-    }
-    *hidl_peer_info_stats = {};
-    hidl_peer_info_stats->staCount = legacy_peer_info_stats.peer_info.bssload.sta_count;
-    hidl_peer_info_stats->chanUtil = legacy_peer_info_stats.peer_info.bssload.chan_util;
-
-    std::vector<V1_6::StaRateStat> hidlRateStats;
-    for (const auto& legacy_rate_stats : legacy_peer_info_stats.rate_stats) {
-        V1_6::StaRateStat rateStat;
-        if (!convertLegacyWifiRateInfoToHidl(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;
-        hidlRateStats.push_back(rateStat);
-    }
-    hidl_peer_info_stats->rateStats = hidlRateStats;
-    return true;
-}
-
-bool convertLegacyRoamingCapabilitiesToHidl(
-        const legacy_hal::wifi_roaming_capabilities& legacy_caps,
-        StaRoamingCapabilities* hidl_caps) {
-    if (!hidl_caps) {
-        return false;
-    }
-    *hidl_caps = {};
-    hidl_caps->maxBlacklistSize = legacy_caps.max_blacklist_size;
-    hidl_caps->maxWhitelistSize = legacy_caps.max_whitelist_size;
-    return true;
-}
-
-bool convertHidlRoamingConfigToLegacy(const StaRoamingConfig& hidl_config,
-                                      legacy_hal::wifi_roaming_config* legacy_config) {
-    if (!legacy_config) {
-        return false;
-    }
-    *legacy_config = {};
-    if (hidl_config.bssidBlacklist.size() > MAX_BLACKLIST_BSSID ||
-        hidl_config.ssidWhitelist.size() > MAX_WHITELIST_SSID) {
-        return false;
-    }
-    legacy_config->num_blacklist_bssid = hidl_config.bssidBlacklist.size();
-    uint32_t i = 0;
-    for (const auto& bssid : hidl_config.bssidBlacklist) {
-        CHECK(bssid.size() == sizeof(legacy_hal::mac_addr));
-        memcpy(legacy_config->blacklist_bssid[i++], bssid.data(), bssid.size());
-    }
-    legacy_config->num_whitelist_ssid = hidl_config.ssidWhitelist.size();
-    i = 0;
-    for (const auto& ssid : hidl_config.ssidWhitelist) {
-        CHECK(ssid.size() <= sizeof(legacy_hal::ssid_t::ssid_str));
-        legacy_config->whitelist_ssid[i].length = ssid.size();
-        memcpy(legacy_config->whitelist_ssid[i].ssid_str, ssid.data(), ssid.size());
-        i++;
-    }
-    return true;
-}
-
-legacy_hal::fw_roaming_state_t convertHidlRoamingStateToLegacy(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 convertHidlNanMatchAlgToLegacy(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 convertHidlNanPublishTypeToLegacy(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 convertHidlNanTxTypeToLegacy(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 convertHidlNanSubscribeTypeToLegacy(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 convertHidlNanSrfTypeToLegacy(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 convertHidlNanDataPathChannelCfgToLegacy(
-        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);
-}
-
-NanStatusType convertLegacyNanStatusTypeToHidl(legacy_hal::NanStatusType type) {
-    switch (type) {
-        case legacy_hal::NAN_STATUS_SUCCESS:
-            return NanStatusType::SUCCESS;
-        case legacy_hal::NAN_STATUS_INTERNAL_FAILURE:
-            return NanStatusType::INTERNAL_FAILURE;
-        case legacy_hal::NAN_STATUS_PROTOCOL_FAILURE:
-            return NanStatusType::PROTOCOL_FAILURE;
-        case legacy_hal::NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID:
-            return NanStatusType::INVALID_SESSION_ID;
-        case legacy_hal::NAN_STATUS_NO_RESOURCE_AVAILABLE:
-            return NanStatusType::NO_RESOURCES_AVAILABLE;
-        case legacy_hal::NAN_STATUS_INVALID_PARAM:
-            return NanStatusType::INVALID_ARGS;
-        case legacy_hal::NAN_STATUS_INVALID_REQUESTOR_INSTANCE_ID:
-            return NanStatusType::INVALID_PEER_ID;
-        case legacy_hal::NAN_STATUS_INVALID_NDP_ID:
-            return NanStatusType::INVALID_NDP_ID;
-        case legacy_hal::NAN_STATUS_NAN_NOT_ALLOWED:
-            return NanStatusType::NAN_NOT_ALLOWED;
-        case legacy_hal::NAN_STATUS_NO_OTA_ACK:
-            return NanStatusType::NO_OTA_ACK;
-        case legacy_hal::NAN_STATUS_ALREADY_ENABLED:
-            return NanStatusType::ALREADY_ENABLED;
-        case legacy_hal::NAN_STATUS_FOLLOWUP_QUEUE_FULL:
-            return NanStatusType::FOLLOWUP_TX_QUEUE_FULL;
-        case legacy_hal::NAN_STATUS_UNSUPPORTED_CONCURRENCY_NAN_DISABLED:
-            return NanStatusType::UNSUPPORTED_CONCURRENCY_NAN_DISABLED;
-    }
-    CHECK(false);
-}
-
-void convertToWifiNanStatus(legacy_hal::NanStatusType type, const char* str, size_t max_len,
-                            WifiNanStatus* wifiNanStatus) {
-    wifiNanStatus->status = convertLegacyNanStatusTypeToHidl(type);
-    wifiNanStatus->description = safeConvertChar(str, max_len);
-}
-
-bool convertHidlNanEnableRequestToLegacy(const V1_4::NanEnableRequest& hidl_request,
-                                         legacy_hal::NanEnableRequest* legacy_request) {
-    if (!legacy_request) {
-        LOG(ERROR) << "convertHidlNanEnableRequestToLegacy: null legacy_request";
-        return false;
-    }
-    *legacy_request = {};
-
-    legacy_request->config_2dot4g_support = 1;
-    legacy_request->support_2dot4g_val =
-            hidl_request.operateInBand[(size_t)NanBandIndex::NAN_BAND_24GHZ];
-    legacy_request->config_support_5g = 1;
-    legacy_request->support_5g_val =
-            hidl_request.operateInBand[(size_t)NanBandIndex::NAN_BAND_5GHZ];
-    legacy_request->config_hop_count_limit = 1;
-    legacy_request->hop_count_limit_val = hidl_request.hopCountMax;
-    legacy_request->master_pref = hidl_request.configParams.masterPref;
-    legacy_request->discovery_indication_cfg = 0;
-    legacy_request->discovery_indication_cfg |=
-            hidl_request.configParams.disableDiscoveryAddressChangeIndication ? 0x1 : 0x0;
-    legacy_request->discovery_indication_cfg |=
-            hidl_request.configParams.disableStartedClusterIndication ? 0x2 : 0x0;
-    legacy_request->discovery_indication_cfg |=
-            hidl_request.configParams.disableJoinedClusterIndication ? 0x4 : 0x0;
-    legacy_request->config_sid_beacon = 1;
-    if (hidl_request.configParams.numberOfPublishServiceIdsInBeacon > 127) {
-        LOG(ERROR) << "convertHidlNanEnableRequestToLegacy: "
-                      "numberOfPublishServiceIdsInBeacon > 127";
-        return false;
-    }
-    legacy_request->sid_beacon_val =
-            (hidl_request.configParams.includePublishServiceIdsInBeacon ? 0x1 : 0x0) |
-            (hidl_request.configParams.numberOfPublishServiceIdsInBeacon << 1);
-    legacy_request->config_subscribe_sid_beacon = 1;
-    if (hidl_request.configParams.numberOfSubscribeServiceIdsInBeacon > 127) {
-        LOG(ERROR) << "convertHidlNanEnableRequestToLegacy: "
-                      "numberOfSubscribeServiceIdsInBeacon > 127";
-        return false;
-    }
-    legacy_request->subscribe_sid_beacon_val =
-            (hidl_request.configParams.includeSubscribeServiceIdsInBeacon ? 0x1 : 0x0) |
-            (hidl_request.configParams.numberOfSubscribeServiceIdsInBeacon << 1);
-    legacy_request->config_rssi_window_size = 1;
-    legacy_request->rssi_window_size_val = hidl_request.configParams.rssiWindowSize;
-    legacy_request->config_disc_mac_addr_randomization = 1;
-    legacy_request->disc_mac_addr_rand_interval_sec =
-            hidl_request.configParams.macAddressRandomizationIntervalSec;
-    legacy_request->config_2dot4g_rssi_close = 1;
-    if (hidl_request.configParams.bandSpecificConfig.size() != 3) {
-        LOG(ERROR) << "convertHidlNanEnableRequestToLegacy: "
-                      "bandSpecificConfig.size() != 3";
-        return false;
-    }
-    legacy_request->rssi_close_2dot4g_val =
-            hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
-                    .rssiClose;
-    legacy_request->config_2dot4g_rssi_middle = 1;
-    legacy_request->rssi_middle_2dot4g_val =
-            hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
-                    .rssiMiddle;
-    legacy_request->config_2dot4g_rssi_proximity = 1;
-    legacy_request->rssi_proximity_2dot4g_val =
-            hidl_request.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] =
-            hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
-                    .dwellTimeMs;
-    legacy_request->scan_params_val.scan_period[legacy_hal::NAN_CHANNEL_24G_BAND] =
-            hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
-                    .scanPeriodSec;
-    legacy_request->config_dw.config_2dot4g_dw_band =
-            hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
-                    .validDiscoveryWindowIntervalVal;
-    legacy_request->config_dw.dw_2dot4g_interval_val =
-            hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
-                    .discoveryWindowIntervalVal;
-    legacy_request->config_5g_rssi_close = 1;
-    legacy_request->rssi_close_5g_val =
-            hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
-                    .rssiClose;
-    legacy_request->config_5g_rssi_middle = 1;
-    legacy_request->rssi_middle_5g_val =
-            hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
-                    .rssiMiddle;
-    legacy_request->config_5g_rssi_close_proximity = 1;
-    legacy_request->rssi_close_proximity_5g_val =
-            hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
-                    .rssiCloseProximity;
-    legacy_request->scan_params_val.dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
-            hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
-                    .dwellTimeMs;
-    legacy_request->scan_params_val.scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
-            hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
-                    .scanPeriodSec;
-    legacy_request->scan_params_val.dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
-            hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
-                    .dwellTimeMs;
-    legacy_request->scan_params_val.scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
-            hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
-                    .scanPeriodSec;
-    legacy_request->config_dw.config_5g_dw_band =
-            hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
-                    .validDiscoveryWindowIntervalVal;
-    legacy_request->config_dw.dw_5g_interval_val =
-            hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
-                    .discoveryWindowIntervalVal;
-    if (hidl_request.debugConfigs.validClusterIdVals) {
-        legacy_request->cluster_low = hidl_request.debugConfigs.clusterIdBottomRangeVal;
-        legacy_request->cluster_high = hidl_request.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 = hidl_request.debugConfigs.validIntfAddrVal;
-    memcpy(legacy_request->intf_addr_val, hidl_request.debugConfigs.intfAddrVal.data(), 6);
-    legacy_request->config_oui = hidl_request.debugConfigs.validOuiVal;
-    legacy_request->oui_val = hidl_request.debugConfigs.ouiVal;
-    legacy_request->config_random_factor_force =
-            hidl_request.debugConfigs.validRandomFactorForceVal;
-    legacy_request->random_factor_force_val = hidl_request.debugConfigs.randomFactorForceVal;
-    legacy_request->config_hop_count_force = hidl_request.debugConfigs.validHopCountForceVal;
-    legacy_request->hop_count_force_val = hidl_request.debugConfigs.hopCountForceVal;
-    legacy_request->config_24g_channel = hidl_request.debugConfigs.validDiscoveryChannelVal;
-    legacy_request->channel_24g_val =
-            hidl_request.debugConfigs.discoveryChannelMhzVal[(size_t)NanBandIndex::NAN_BAND_24GHZ];
-    legacy_request->config_5g_channel = hidl_request.debugConfigs.validDiscoveryChannelVal;
-    legacy_request->channel_5g_val =
-            hidl_request.debugConfigs.discoveryChannelMhzVal[(size_t)NanBandIndex::NAN_BAND_5GHZ];
-    legacy_request->config_2dot4g_beacons = hidl_request.debugConfigs.validUseBeaconsInBandVal;
-    legacy_request->beacon_2dot4g_val =
-            hidl_request.debugConfigs.useBeaconsInBandVal[(size_t)NanBandIndex::NAN_BAND_24GHZ];
-    legacy_request->config_5g_beacons = hidl_request.debugConfigs.validUseBeaconsInBandVal;
-    legacy_request->beacon_5g_val =
-            hidl_request.debugConfigs.useBeaconsInBandVal[(size_t)NanBandIndex::NAN_BAND_5GHZ];
-    legacy_request->config_2dot4g_sdf = hidl_request.debugConfigs.validUseSdfInBandVal;
-    legacy_request->sdf_2dot4g_val =
-            hidl_request.debugConfigs.useSdfInBandVal[(size_t)NanBandIndex::NAN_BAND_24GHZ];
-    legacy_request->config_5g_sdf = hidl_request.debugConfigs.validUseSdfInBandVal;
-    legacy_request->sdf_5g_val =
-            hidl_request.debugConfigs.useSdfInBandVal[(size_t)NanBandIndex::NAN_BAND_5GHZ];
-
-    /* TODO: b/145609058
-     * Missing updates needed to legacy_hal::NanEnableRequest and conversion to
-     * it for 6GHz band */
-
-    return true;
-}
-
-bool convertHidlNanEnableRequest_1_6ToLegacy(const V1_4::NanEnableRequest& hidl_request1,
-                                             const NanConfigRequestSupplemental& hidl_request2,
-                                             legacy_hal::NanEnableRequest* legacy_request) {
-    if (!legacy_request) {
-        LOG(ERROR) << "convertHidlNanEnableRequest_1_6ToLegacy: null legacy_request";
-        return false;
-    }
-
-    *legacy_request = {};
-    if (!convertHidlNanEnableRequestToLegacy(hidl_request1, legacy_request)) {
-        return false;
-    }
-
-    legacy_request->config_discovery_beacon_int = 1;
-    legacy_request->discovery_beacon_interval = hidl_request2.V1_5.V1_2.discoveryBeaconIntervalMs;
-    legacy_request->config_nss = 1;
-    legacy_request->nss = hidl_request2.V1_5.V1_2.numberOfSpatialStreamsInDiscovery;
-    legacy_request->config_dw_early_termination = 1;
-    legacy_request->enable_dw_termination =
-            hidl_request2.V1_5.V1_2.enableDiscoveryWindowEarlyTermination;
-    legacy_request->config_enable_ranging = 1;
-    legacy_request->enable_ranging = hidl_request2.V1_5.V1_2.enableRanging;
-
-    legacy_request->config_enable_instant_mode = 1;
-    legacy_request->enable_instant_mode = hidl_request2.V1_5.enableInstantCommunicationMode;
-    legacy_request->config_instant_mode_channel = 1;
-    legacy_request->instant_mode_channel = hidl_request2.instantModeChannel;
-
-    return true;
-}
-
-bool convertHidlNanConfigRequest_1_6ToLegacy(const V1_4::NanConfigRequest& hidl_request1,
-                                             const NanConfigRequestSupplemental& hidl_request2,
-                                             legacy_hal::NanConfigRequest* legacy_request) {
-    if (!legacy_request) {
-        LOG(ERROR) << "convertHidlNanConfigRequest_1_6ToLegacy: null legacy_request";
-        return false;
-    }
-
-    *legacy_request = {};
-    if (!convertHidlNanConfigRequestToLegacy(hidl_request1, legacy_request)) {
-        return false;
-    }
-
-    legacy_request->config_discovery_beacon_int = 1;
-    legacy_request->discovery_beacon_interval = hidl_request2.V1_5.V1_2.discoveryBeaconIntervalMs;
-    legacy_request->config_nss = 1;
-    legacy_request->nss = hidl_request2.V1_5.V1_2.numberOfSpatialStreamsInDiscovery;
-    legacy_request->config_dw_early_termination = 1;
-    legacy_request->enable_dw_termination =
-            hidl_request2.V1_5.V1_2.enableDiscoveryWindowEarlyTermination;
-    legacy_request->config_enable_ranging = 1;
-    legacy_request->enable_ranging = hidl_request2.V1_5.V1_2.enableRanging;
-
-    legacy_request->config_enable_instant_mode = 1;
-    legacy_request->enable_instant_mode = hidl_request2.V1_5.enableInstantCommunicationMode;
-    legacy_request->config_instant_mode_channel = 1;
-    legacy_request->instant_mode_channel = hidl_request2.instantModeChannel;
-
-    return true;
-}
-
-bool convertHidlNanPublishRequestToLegacy(const V1_6::NanPublishRequest& hidl_request,
-                                          legacy_hal::NanPublishRequest* legacy_request) {
-    if (!legacy_request) {
-        LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: null legacy_request";
-        return false;
-    }
-    *legacy_request = {};
-
-    legacy_request->publish_id = hidl_request.baseConfigs.sessionId;
-    legacy_request->ttl = hidl_request.baseConfigs.ttlSec;
-    legacy_request->period = hidl_request.baseConfigs.discoveryWindowPeriod;
-    legacy_request->publish_count = hidl_request.baseConfigs.discoveryCount;
-    legacy_request->service_name_len = hidl_request.baseConfigs.serviceName.size();
-    if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
-        LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: service_name_len "
-                      "too large";
-        return false;
-    }
-    memcpy(legacy_request->service_name, hidl_request.baseConfigs.serviceName.data(),
-           legacy_request->service_name_len);
-    legacy_request->publish_match_indicator =
-            convertHidlNanMatchAlgToLegacy(hidl_request.baseConfigs.discoveryMatchIndicator);
-    legacy_request->service_specific_info_len = hidl_request.baseConfigs.serviceSpecificInfo.size();
-    if (legacy_request->service_specific_info_len > NAN_MAX_SERVICE_SPECIFIC_INFO_LEN) {
-        LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
-                      "service_specific_info_len too large";
-        return false;
-    }
-    memcpy(legacy_request->service_specific_info,
-           hidl_request.baseConfigs.serviceSpecificInfo.data(),
-           legacy_request->service_specific_info_len);
-    legacy_request->sdea_service_specific_info_len =
-            hidl_request.baseConfigs.extendedServiceSpecificInfo.size();
-    if (legacy_request->sdea_service_specific_info_len > NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN) {
-        LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
-                      "sdea_service_specific_info_len too large";
-        return false;
-    }
-    memcpy(legacy_request->sdea_service_specific_info,
-           hidl_request.baseConfigs.extendedServiceSpecificInfo.data(),
-           legacy_request->sdea_service_specific_info_len);
-    legacy_request->rx_match_filter_len = hidl_request.baseConfigs.rxMatchFilter.size();
-    if (legacy_request->rx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
-        LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
-                      "rx_match_filter_len too large";
-        return false;
-    }
-    memcpy(legacy_request->rx_match_filter, hidl_request.baseConfigs.rxMatchFilter.data(),
-           legacy_request->rx_match_filter_len);
-    legacy_request->tx_match_filter_len = hidl_request.baseConfigs.txMatchFilter.size();
-    if (legacy_request->tx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
-        LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
-                      "tx_match_filter_len too large";
-        return false;
-    }
-    memcpy(legacy_request->tx_match_filter, hidl_request.baseConfigs.txMatchFilter.data(),
-           legacy_request->tx_match_filter_len);
-    legacy_request->rssi_threshold_flag = hidl_request.baseConfigs.useRssiThreshold;
-    legacy_request->recv_indication_cfg = 0;
-    legacy_request->recv_indication_cfg |=
-            hidl_request.baseConfigs.disableDiscoveryTerminationIndication ? 0x1 : 0x0;
-    legacy_request->recv_indication_cfg |=
-            hidl_request.baseConfigs.disableMatchExpirationIndication ? 0x2 : 0x0;
-    legacy_request->recv_indication_cfg |=
-            hidl_request.baseConfigs.disableFollowupReceivedIndication ? 0x4 : 0x0;
-    legacy_request->recv_indication_cfg |= 0x8;
-    legacy_request->cipher_type = (unsigned int)hidl_request.baseConfigs.securityConfig.cipherType;
-
-    legacy_request->scid_len = hidl_request.baseConfigs.securityConfig.scid.size();
-    if (legacy_request->scid_len > NAN_MAX_SCID_BUF_LEN) {
-        LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: scid_len too large";
-        return false;
-    }
-    memcpy(legacy_request->scid, hidl_request.baseConfigs.securityConfig.scid.data(),
-           legacy_request->scid_len);
-
-    if (hidl_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 =
-                hidl_request.baseConfigs.securityConfig.pmk.size();
-        if (legacy_request->key_info.body.pmk_info.pmk_len != NAN_PMK_INFO_LEN) {
-            LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: invalid pmk_len";
-            return false;
-        }
-        memcpy(legacy_request->key_info.body.pmk_info.pmk,
-               hidl_request.baseConfigs.securityConfig.pmk.data(),
-               legacy_request->key_info.body.pmk_info.pmk_len);
-    }
-    if (hidl_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 =
-                hidl_request.baseConfigs.securityConfig.passphrase.size();
-        if (legacy_request->key_info.body.passphrase_info.passphrase_len <
-            NAN_SECURITY_MIN_PASSPHRASE_LEN) {
-            LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
-                          "passphrase_len too small";
-            return false;
-        }
-        if (legacy_request->key_info.body.passphrase_info.passphrase_len >
-            NAN_SECURITY_MAX_PASSPHRASE_LEN) {
-            LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
-                          "passphrase_len too large";
-            return false;
-        }
-        memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
-               hidl_request.baseConfigs.securityConfig.passphrase.data(),
-               legacy_request->key_info.body.passphrase_info.passphrase_len);
-    }
-    legacy_request->sdea_params.security_cfg =
-            (hidl_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 = hidl_request.baseConfigs.rangingRequired
-                                                        ? legacy_hal::NAN_RANGING_ENABLE
-                                                        : legacy_hal::NAN_RANGING_DISABLE;
-    legacy_request->ranging_cfg.ranging_interval_msec =
-            hidl_request.baseConfigs.rangingIntervalMsec;
-    legacy_request->ranging_cfg.config_ranging_indications =
-            hidl_request.baseConfigs.configRangingIndications;
-    legacy_request->ranging_cfg.distance_ingress_mm =
-            hidl_request.baseConfigs.distanceIngressCm * 10;
-    legacy_request->ranging_cfg.distance_egress_mm = hidl_request.baseConfigs.distanceEgressCm * 10;
-    legacy_request->ranging_auto_response = hidl_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 = convertHidlNanPublishTypeToLegacy(hidl_request.publishType);
-    legacy_request->tx_type = convertHidlNanTxTypeToLegacy(hidl_request.txType);
-    legacy_request->service_responder_policy = hidl_request.autoAcceptDataPathRequests
-                                                       ? legacy_hal::NAN_SERVICE_ACCEPT_POLICY_ALL
-                                                       : legacy_hal::NAN_SERVICE_ACCEPT_POLICY_NONE;
-
-    return true;
-}
-
-bool convertHidlNanSubscribeRequestToLegacy(const V1_0::NanSubscribeRequest& hidl_request,
-                                            legacy_hal::NanSubscribeRequest* legacy_request) {
-    if (!legacy_request) {
-        LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: legacy_request is null";
-        return false;
-    }
-    *legacy_request = {};
-
-    legacy_request->subscribe_id = hidl_request.baseConfigs.sessionId;
-    legacy_request->ttl = hidl_request.baseConfigs.ttlSec;
-    legacy_request->period = hidl_request.baseConfigs.discoveryWindowPeriod;
-    legacy_request->subscribe_count = hidl_request.baseConfigs.discoveryCount;
-    legacy_request->service_name_len = hidl_request.baseConfigs.serviceName.size();
-    if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
-        LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
-                      "service_name_len too large";
-        return false;
-    }
-    memcpy(legacy_request->service_name, hidl_request.baseConfigs.serviceName.data(),
-           legacy_request->service_name_len);
-    legacy_request->subscribe_match_indicator =
-            convertHidlNanMatchAlgToLegacy(hidl_request.baseConfigs.discoveryMatchIndicator);
-    legacy_request->service_specific_info_len = hidl_request.baseConfigs.serviceSpecificInfo.size();
-    if (legacy_request->service_specific_info_len > NAN_MAX_SERVICE_SPECIFIC_INFO_LEN) {
-        LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
-                      "service_specific_info_len too large";
-        return false;
-    }
-    memcpy(legacy_request->service_specific_info,
-           hidl_request.baseConfigs.serviceSpecificInfo.data(),
-           legacy_request->service_specific_info_len);
-    legacy_request->sdea_service_specific_info_len =
-            hidl_request.baseConfigs.extendedServiceSpecificInfo.size();
-    if (legacy_request->sdea_service_specific_info_len > NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN) {
-        LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
-                      "sdea_service_specific_info_len too large";
-        return false;
-    }
-    memcpy(legacy_request->sdea_service_specific_info,
-           hidl_request.baseConfigs.extendedServiceSpecificInfo.data(),
-           legacy_request->sdea_service_specific_info_len);
-    legacy_request->rx_match_filter_len = hidl_request.baseConfigs.rxMatchFilter.size();
-    if (legacy_request->rx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
-        LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
-                      "rx_match_filter_len too large";
-        return false;
-    }
-    memcpy(legacy_request->rx_match_filter, hidl_request.baseConfigs.rxMatchFilter.data(),
-           legacy_request->rx_match_filter_len);
-    legacy_request->tx_match_filter_len = hidl_request.baseConfigs.txMatchFilter.size();
-    if (legacy_request->tx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
-        LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
-                      "tx_match_filter_len too large";
-        return false;
-    }
-    memcpy(legacy_request->tx_match_filter, hidl_request.baseConfigs.txMatchFilter.data(),
-           legacy_request->tx_match_filter_len);
-    legacy_request->rssi_threshold_flag = hidl_request.baseConfigs.useRssiThreshold;
-    legacy_request->recv_indication_cfg = 0;
-    legacy_request->recv_indication_cfg |=
-            hidl_request.baseConfigs.disableDiscoveryTerminationIndication ? 0x1 : 0x0;
-    legacy_request->recv_indication_cfg |=
-            hidl_request.baseConfigs.disableMatchExpirationIndication ? 0x2 : 0x0;
-    legacy_request->recv_indication_cfg |=
-            hidl_request.baseConfigs.disableFollowupReceivedIndication ? 0x4 : 0x0;
-    legacy_request->cipher_type = (unsigned int)hidl_request.baseConfigs.securityConfig.cipherType;
-    if (hidl_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 =
-                hidl_request.baseConfigs.securityConfig.pmk.size();
-        if (legacy_request->key_info.body.pmk_info.pmk_len != NAN_PMK_INFO_LEN) {
-            LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: invalid pmk_len";
-            return false;
-        }
-        memcpy(legacy_request->key_info.body.pmk_info.pmk,
-               hidl_request.baseConfigs.securityConfig.pmk.data(),
-               legacy_request->key_info.body.pmk_info.pmk_len);
-    }
-    if (hidl_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 =
-                hidl_request.baseConfigs.securityConfig.passphrase.size();
-        if (legacy_request->key_info.body.passphrase_info.passphrase_len <
-            NAN_SECURITY_MIN_PASSPHRASE_LEN) {
-            LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
-                          "passphrase_len too small";
-            return false;
-        }
-        if (legacy_request->key_info.body.passphrase_info.passphrase_len >
-            NAN_SECURITY_MAX_PASSPHRASE_LEN) {
-            LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
-                          "passphrase_len too large";
-            return false;
-        }
-        memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
-               hidl_request.baseConfigs.securityConfig.passphrase.data(),
-               legacy_request->key_info.body.passphrase_info.passphrase_len);
-    }
-    legacy_request->sdea_params.security_cfg =
-            (hidl_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 = hidl_request.baseConfigs.rangingRequired
-                                                        ? legacy_hal::NAN_RANGING_ENABLE
-                                                        : legacy_hal::NAN_RANGING_DISABLE;
-    legacy_request->ranging_cfg.ranging_interval_msec =
-            hidl_request.baseConfigs.rangingIntervalMsec;
-    legacy_request->ranging_cfg.config_ranging_indications =
-            hidl_request.baseConfigs.configRangingIndications;
-    legacy_request->ranging_cfg.distance_ingress_mm =
-            hidl_request.baseConfigs.distanceIngressCm * 10;
-    legacy_request->ranging_cfg.distance_egress_mm = hidl_request.baseConfigs.distanceEgressCm * 10;
-    legacy_request->ranging_auto_response = hidl_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 =
-            convertHidlNanSubscribeTypeToLegacy(hidl_request.subscribeType);
-    legacy_request->serviceResponseFilter = convertHidlNanSrfTypeToLegacy(hidl_request.srfType);
-    legacy_request->serviceResponseInclude = hidl_request.srfRespondIfInAddressSet
-                                                     ? legacy_hal::NAN_SRF_INCLUDE_RESPOND
-                                                     : legacy_hal::NAN_SRF_INCLUDE_DO_NOT_RESPOND;
-    legacy_request->useServiceResponseFilter =
-            hidl_request.shouldUseSrf ? legacy_hal::NAN_USE_SRF : legacy_hal::NAN_DO_NOT_USE_SRF;
-    legacy_request->ssiRequiredForMatchIndication =
-            hidl_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 = hidl_request.intfAddr.size();
-    if (legacy_request->num_intf_addr_present > NAN_MAX_SUBSCRIBE_MAX_ADDRESS) {
-        LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
-                      "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], hidl_request.intfAddr[i].data(), 6);
-    }
-
-    return true;
-}
-
-bool convertHidlNanTransmitFollowupRequestToLegacy(
-        const NanTransmitFollowupRequest& hidl_request,
-        legacy_hal::NanTransmitFollowupRequest* legacy_request) {
-    if (!legacy_request) {
-        LOG(ERROR) << "convertHidlNanTransmitFollowupRequestToLegacy: "
-                      "legacy_request is null";
-        return false;
-    }
-    *legacy_request = {};
-
-    legacy_request->publish_subscribe_id = hidl_request.discoverySessionId;
-    legacy_request->requestor_instance_id = hidl_request.peerId;
-    memcpy(legacy_request->addr, hidl_request.addr.data(), 6);
-    legacy_request->priority = hidl_request.isHighPriority ? legacy_hal::NAN_TX_PRIORITY_HIGH
-                                                           : legacy_hal::NAN_TX_PRIORITY_NORMAL;
-    legacy_request->dw_or_faw = hidl_request.shouldUseDiscoveryWindow
-                                        ? legacy_hal::NAN_TRANSMIT_IN_DW
-                                        : legacy_hal::NAN_TRANSMIT_IN_FAW;
-    legacy_request->service_specific_info_len = hidl_request.serviceSpecificInfo.size();
-    if (legacy_request->service_specific_info_len > NAN_MAX_SERVICE_SPECIFIC_INFO_LEN) {
-        LOG(ERROR) << "convertHidlNanTransmitFollowupRequestToLegacy: "
-                      "service_specific_info_len too large";
-        return false;
-    }
-    memcpy(legacy_request->service_specific_info, hidl_request.serviceSpecificInfo.data(),
-           legacy_request->service_specific_info_len);
-    legacy_request->sdea_service_specific_info_len =
-            hidl_request.extendedServiceSpecificInfo.size();
-    if (legacy_request->sdea_service_specific_info_len > NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN) {
-        LOG(ERROR) << "convertHidlNanTransmitFollowupRequestToLegacy: "
-                      "sdea_service_specific_info_len too large";
-        return false;
-    }
-    memcpy(legacy_request->sdea_service_specific_info,
-           hidl_request.extendedServiceSpecificInfo.data(),
-           legacy_request->sdea_service_specific_info_len);
-    legacy_request->recv_indication_cfg = hidl_request.disableFollowupResultIndication ? 0x1 : 0x0;
-
-    return true;
-}
-
-bool convertHidlNanConfigRequestToLegacy(const V1_4::NanConfigRequest& hidl_request,
-                                         legacy_hal::NanConfigRequest* legacy_request) {
-    if (!legacy_request) {
-        LOG(ERROR) << "convertHidlNanConfigRequestToLegacy: legacy_request is null";
-        return false;
-    }
-    *legacy_request = {};
-
-    // TODO: b/34059183 tracks missing configurations in legacy HAL or uknown
-    // defaults
-    legacy_request->master_pref = hidl_request.masterPref;
-    legacy_request->discovery_indication_cfg = 0;
-    legacy_request->discovery_indication_cfg |=
-            hidl_request.disableDiscoveryAddressChangeIndication ? 0x1 : 0x0;
-    legacy_request->discovery_indication_cfg |=
-            hidl_request.disableStartedClusterIndication ? 0x2 : 0x0;
-    legacy_request->discovery_indication_cfg |=
-            hidl_request.disableJoinedClusterIndication ? 0x4 : 0x0;
-    legacy_request->config_sid_beacon = 1;
-    if (hidl_request.numberOfPublishServiceIdsInBeacon > 127) {
-        LOG(ERROR) << "convertHidlNanConfigRequestToLegacy: "
-                      "numberOfPublishServiceIdsInBeacon > 127";
-        return false;
-    }
-    legacy_request->sid_beacon = (hidl_request.includePublishServiceIdsInBeacon ? 0x1 : 0x0) |
-                                 (hidl_request.numberOfPublishServiceIdsInBeacon << 1);
-    legacy_request->config_subscribe_sid_beacon = 1;
-    if (hidl_request.numberOfSubscribeServiceIdsInBeacon > 127) {
-        LOG(ERROR) << "convertHidlNanConfigRequestToLegacy: "
-                      "numberOfSubscribeServiceIdsInBeacon > 127";
-        return false;
-    }
-    legacy_request->subscribe_sid_beacon_val =
-            (hidl_request.includeSubscribeServiceIdsInBeacon ? 0x1 : 0x0) |
-            (hidl_request.numberOfSubscribeServiceIdsInBeacon << 1);
-    legacy_request->config_rssi_window_size = 1;
-    legacy_request->rssi_window_size_val = hidl_request.rssiWindowSize;
-    legacy_request->config_disc_mac_addr_randomization = 1;
-    legacy_request->disc_mac_addr_rand_interval_sec =
-            hidl_request.macAddressRandomizationIntervalSec;
-    /* TODO : missing
-    legacy_request->config_2dot4g_rssi_close = 1;
-    legacy_request->rssi_close_2dot4g_val =
-          hidl_request.bandSpecificConfig[
-              (size_t) NanBandIndex::NAN_BAND_24GHZ].rssiClose;
-    legacy_request->config_2dot4g_rssi_middle = 1;
-    legacy_request->rssi_middle_2dot4g_val =
-          hidl_request.bandSpecificConfig[
-              (size_t) NanBandIndex::NAN_BAND_24GHZ].rssiMiddle;
-    legacy_request->config_2dot4g_rssi_proximity = 1;
-    legacy_request->rssi_proximity_2dot4g_val =
-          hidl_request.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] =
-            hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ].dwellTimeMs;
-    legacy_request->scan_params_val.scan_period[legacy_hal::NAN_CHANNEL_24G_BAND] =
-            hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ].scanPeriodSec;
-    legacy_request->config_dw.config_2dot4g_dw_band =
-            hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
-                    .validDiscoveryWindowIntervalVal;
-    legacy_request->config_dw.dw_2dot4g_interval_val =
-            hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
-                    .discoveryWindowIntervalVal;
-    /* TODO: missing
-    legacy_request->config_5g_rssi_close = 1;
-    legacy_request->rssi_close_5g_val =
-          hidl_request.bandSpecificConfig[
-              (size_t) NanBandIndex::NAN_BAND_5GHZ].rssiClose;
-    legacy_request->config_5g_rssi_middle = 1;
-    legacy_request->rssi_middle_5g_val =
-          hidl_request.bandSpecificConfig[
-              (size_t) NanBandIndex::NAN_BAND_5GHZ].rssiMiddle;
-    */
-    legacy_request->config_5g_rssi_close_proximity = 1;
-    legacy_request->rssi_close_proximity_5g_val =
-            hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ].rssiCloseProximity;
-    legacy_request->scan_params_val.dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
-            hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ].dwellTimeMs;
-    legacy_request->scan_params_val.scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
-            hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ].scanPeriodSec;
-    legacy_request->scan_params_val.dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
-            hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ].dwellTimeMs;
-    legacy_request->scan_params_val.scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
-            hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ].scanPeriodSec;
-    legacy_request->config_dw.config_5g_dw_band =
-            hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
-                    .validDiscoveryWindowIntervalVal;
-    legacy_request->config_dw.dw_5g_interval_val =
-            hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
-                    .discoveryWindowIntervalVal;
-    /* TODO: b/145609058
-     * Missing updates needed to legacy_hal::NanConfigRequest and conversion to
-     * it for 6GHz band */
-
-    return true;
-}
-
-bool convertHidlNanDataPathInitiatorRequestToLegacy(
-        const V1_0::NanInitiateDataPathRequest& hidl_request,
-        legacy_hal::NanDataPathInitiatorRequest* legacy_request) {
-    if (!legacy_request) {
-        LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
-                      "legacy_request is null";
-        return false;
-    }
-    *legacy_request = {};
-
-    legacy_request->requestor_instance_id = hidl_request.peerId;
-    memcpy(legacy_request->peer_disc_mac_addr, hidl_request.peerDiscMacAddr.data(), 6);
-    legacy_request->channel_request_type =
-            convertHidlNanDataPathChannelCfgToLegacy(hidl_request.channelRequestType);
-    legacy_request->channel = hidl_request.channel;
-    if (strnlen(hidl_request.ifaceName.c_str(), IFNAMSIZ + 1) == IFNAMSIZ + 1) {
-        LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
-                      "ifaceName too long";
-        return false;
-    }
-    strlcpy(legacy_request->ndp_iface, hidl_request.ifaceName.c_str(), IFNAMSIZ + 1);
-    legacy_request->ndp_cfg.security_cfg =
-            (hidl_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 = hidl_request.appInfo.size();
-    if (legacy_request->app_info.ndp_app_info_len > NAN_DP_MAX_APP_INFO_LEN) {
-        LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
-                      "ndp_app_info_len too large";
-        return false;
-    }
-    memcpy(legacy_request->app_info.ndp_app_info, hidl_request.appInfo.data(),
-           legacy_request->app_info.ndp_app_info_len);
-    legacy_request->cipher_type = (unsigned int)hidl_request.securityConfig.cipherType;
-    if (hidl_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 = hidl_request.securityConfig.pmk.size();
-        if (legacy_request->key_info.body.pmk_info.pmk_len != NAN_PMK_INFO_LEN) {
-            LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
-                          "invalid pmk_len";
-            return false;
-        }
-        memcpy(legacy_request->key_info.body.pmk_info.pmk, hidl_request.securityConfig.pmk.data(),
-               legacy_request->key_info.body.pmk_info.pmk_len);
-    }
-    if (hidl_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 =
-                hidl_request.securityConfig.passphrase.size();
-        if (legacy_request->key_info.body.passphrase_info.passphrase_len <
-            NAN_SECURITY_MIN_PASSPHRASE_LEN) {
-            LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
-                          "passphrase_len too small";
-            return false;
-        }
-        if (legacy_request->key_info.body.passphrase_info.passphrase_len >
-            NAN_SECURITY_MAX_PASSPHRASE_LEN) {
-            LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
-                          "passphrase_len too large";
-            return false;
-        }
-        memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
-               hidl_request.securityConfig.passphrase.data(),
-               legacy_request->key_info.body.passphrase_info.passphrase_len);
-    }
-    legacy_request->service_name_len = hidl_request.serviceNameOutOfBand.size();
-    if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
-        LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
-                      "service_name_len too large";
-        return false;
-    }
-    memcpy(legacy_request->service_name, hidl_request.serviceNameOutOfBand.data(),
-           legacy_request->service_name_len);
-
-    return true;
-}
-
-bool convertHidlNanDataPathInitiatorRequest_1_6ToLegacy(
-        const V1_6::NanInitiateDataPathRequest& hidl_request,
-        legacy_hal::NanDataPathInitiatorRequest* legacy_request) {
-    if (!legacy_request) {
-        LOG(ERROR) << "convertHidlNanDataPathInitiatorRequest_1_6ToLegacy: "
-                      "legacy_request is null";
-        return false;
-    }
-    *legacy_request = {};
-
-    legacy_request->requestor_instance_id = hidl_request.peerId;
-    memcpy(legacy_request->peer_disc_mac_addr, hidl_request.peerDiscMacAddr.data(), 6);
-    legacy_request->channel_request_type =
-            convertHidlNanDataPathChannelCfgToLegacy(hidl_request.channelRequestType);
-    legacy_request->channel = hidl_request.channel;
-    if (strnlen(hidl_request.ifaceName.c_str(), IFNAMSIZ + 1) == IFNAMSIZ + 1) {
-        LOG(ERROR) << "convertHidlNanDataPathInitiatorRequest_1_6ToLegacy: "
-                      "ifaceName too long";
-        return false;
-    }
-    strlcpy(legacy_request->ndp_iface, hidl_request.ifaceName.c_str(), IFNAMSIZ + 1);
-    legacy_request->ndp_cfg.security_cfg =
-            (hidl_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 = hidl_request.appInfo.size();
-    if (legacy_request->app_info.ndp_app_info_len > NAN_DP_MAX_APP_INFO_LEN) {
-        LOG(ERROR) << "convertHidlNanDataPathInitiatorRequest_1_6ToLegacy: "
-                      "ndp_app_info_len too large";
-        return false;
-    }
-    memcpy(legacy_request->app_info.ndp_app_info, hidl_request.appInfo.data(),
-           legacy_request->app_info.ndp_app_info_len);
-    legacy_request->cipher_type = (unsigned int)hidl_request.securityConfig.cipherType;
-    if (hidl_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 = hidl_request.securityConfig.pmk.size();
-        if (legacy_request->key_info.body.pmk_info.pmk_len != NAN_PMK_INFO_LEN) {
-            LOG(ERROR) << "convertHidlNanDataPathInitiatorRequest_1_6ToLegacy: "
-                          "invalid pmk_len";
-            return false;
-        }
-        memcpy(legacy_request->key_info.body.pmk_info.pmk, hidl_request.securityConfig.pmk.data(),
-               legacy_request->key_info.body.pmk_info.pmk_len);
-    }
-    if (hidl_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 =
-                hidl_request.securityConfig.passphrase.size();
-        if (legacy_request->key_info.body.passphrase_info.passphrase_len <
-            NAN_SECURITY_MIN_PASSPHRASE_LEN) {
-            LOG(ERROR) << "convertHidlNanDataPathInitiatorRequest_1_6ToLegacy: "
-                          "passphrase_len too small";
-            return false;
-        }
-        if (legacy_request->key_info.body.passphrase_info.passphrase_len >
-            NAN_SECURITY_MAX_PASSPHRASE_LEN) {
-            LOG(ERROR) << "convertHidlNanDataPathInitiatorRequest_1_6ToLegacy: "
-                          "passphrase_len too large";
-            return false;
-        }
-        memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
-               hidl_request.securityConfig.passphrase.data(),
-               legacy_request->key_info.body.passphrase_info.passphrase_len);
-    }
-    legacy_request->service_name_len = hidl_request.serviceNameOutOfBand.size();
-    if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
-        LOG(ERROR) << "convertHidlNanDataPathInitiatorRequest_1_6ToLegacy: "
-                      "service_name_len too large";
-        return false;
-    }
-    memcpy(legacy_request->service_name, hidl_request.serviceNameOutOfBand.data(),
-           legacy_request->service_name_len);
-    legacy_request->scid_len = hidl_request.securityConfig.scid.size();
-    if (legacy_request->scid_len > NAN_MAX_SCID_BUF_LEN) {
-        LOG(ERROR) << "convertHidlNanDataPathInitiatorRequest_1_6ToLegacy: scid_len too large";
-        return false;
-    }
-    memcpy(legacy_request->scid, hidl_request.securityConfig.scid.data(), legacy_request->scid_len);
-
-    return true;
-}
-
-bool convertHidlNanDataPathIndicationResponseToLegacy(
-        const V1_0::NanRespondToDataPathIndicationRequest& hidl_request,
-        legacy_hal::NanDataPathIndicationResponse* legacy_request) {
-    if (!legacy_request) {
-        LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
-                      "legacy_request is null";
-        return false;
-    }
-    *legacy_request = {};
-
-    legacy_request->rsp_code = hidl_request.acceptRequest ? legacy_hal::NAN_DP_REQUEST_ACCEPT
-                                                          : legacy_hal::NAN_DP_REQUEST_REJECT;
-    legacy_request->ndp_instance_id = hidl_request.ndpInstanceId;
-    if (strnlen(hidl_request.ifaceName.c_str(), IFNAMSIZ + 1) == IFNAMSIZ + 1) {
-        LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
-                      "ifaceName too long";
-        return false;
-    }
-    strlcpy(legacy_request->ndp_iface, hidl_request.ifaceName.c_str(), IFNAMSIZ + 1);
-    legacy_request->ndp_cfg.security_cfg =
-            (hidl_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 = hidl_request.appInfo.size();
-    if (legacy_request->app_info.ndp_app_info_len > NAN_DP_MAX_APP_INFO_LEN) {
-        LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
-                      "ndp_app_info_len too large";
-        return false;
-    }
-    memcpy(legacy_request->app_info.ndp_app_info, hidl_request.appInfo.data(),
-           legacy_request->app_info.ndp_app_info_len);
-    legacy_request->cipher_type = (unsigned int)hidl_request.securityConfig.cipherType;
-    if (hidl_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 = hidl_request.securityConfig.pmk.size();
-        if (legacy_request->key_info.body.pmk_info.pmk_len != NAN_PMK_INFO_LEN) {
-            LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
-                          "invalid pmk_len";
-            return false;
-        }
-        memcpy(legacy_request->key_info.body.pmk_info.pmk, hidl_request.securityConfig.pmk.data(),
-               legacy_request->key_info.body.pmk_info.pmk_len);
-    }
-    if (hidl_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 =
-                hidl_request.securityConfig.passphrase.size();
-        if (legacy_request->key_info.body.passphrase_info.passphrase_len <
-            NAN_SECURITY_MIN_PASSPHRASE_LEN) {
-            LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
-                          "passphrase_len too small";
-            return false;
-        }
-        if (legacy_request->key_info.body.passphrase_info.passphrase_len >
-            NAN_SECURITY_MAX_PASSPHRASE_LEN) {
-            LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
-                          "passphrase_len too large";
-            return false;
-        }
-        memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
-               hidl_request.securityConfig.passphrase.data(),
-               legacy_request->key_info.body.passphrase_info.passphrase_len);
-    }
-    legacy_request->service_name_len = hidl_request.serviceNameOutOfBand.size();
-    if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
-        LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
-                      "service_name_len too large";
-        return false;
-    }
-    memcpy(legacy_request->service_name, hidl_request.serviceNameOutOfBand.data(),
-           legacy_request->service_name_len);
-
-    return true;
-}
-
-bool convertHidlNanDataPathIndicationResponse_1_6ToLegacy(
-        const V1_6::NanRespondToDataPathIndicationRequest& hidl_request,
-        legacy_hal::NanDataPathIndicationResponse* legacy_request) {
-    if (!legacy_request) {
-        LOG(ERROR) << "convertHidlNanDataPathIndicationResponse_1_6ToLegacy: "
-                      "legacy_request is null";
-        return false;
-    }
-    *legacy_request = {};
-
-    legacy_request->rsp_code = hidl_request.acceptRequest ? legacy_hal::NAN_DP_REQUEST_ACCEPT
-                                                          : legacy_hal::NAN_DP_REQUEST_REJECT;
-    legacy_request->ndp_instance_id = hidl_request.ndpInstanceId;
-    if (strnlen(hidl_request.ifaceName.c_str(), IFNAMSIZ + 1) == IFNAMSIZ + 1) {
-        LOG(ERROR) << "convertHidlNanDataPathIndicationResponse_1_6ToLegacy: "
-                      "ifaceName too long";
-        return false;
-    }
-    strlcpy(legacy_request->ndp_iface, hidl_request.ifaceName.c_str(), IFNAMSIZ + 1);
-    legacy_request->ndp_cfg.security_cfg =
-            (hidl_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 = hidl_request.appInfo.size();
-    if (legacy_request->app_info.ndp_app_info_len > NAN_DP_MAX_APP_INFO_LEN) {
-        LOG(ERROR) << "convertHidlNanDataPathIndicationResponse_1_6ToLegacy: "
-                      "ndp_app_info_len too large";
-        return false;
-    }
-    memcpy(legacy_request->app_info.ndp_app_info, hidl_request.appInfo.data(),
-           legacy_request->app_info.ndp_app_info_len);
-    legacy_request->cipher_type = (unsigned int)hidl_request.securityConfig.cipherType;
-    if (hidl_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 = hidl_request.securityConfig.pmk.size();
-        if (legacy_request->key_info.body.pmk_info.pmk_len != NAN_PMK_INFO_LEN) {
-            LOG(ERROR) << "convertHidlNanDataPathIndicationResponse_1_6ToLegacy: "
-                          "invalid pmk_len";
-            return false;
-        }
-        memcpy(legacy_request->key_info.body.pmk_info.pmk, hidl_request.securityConfig.pmk.data(),
-               legacy_request->key_info.body.pmk_info.pmk_len);
-    }
-    if (hidl_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 =
-                hidl_request.securityConfig.passphrase.size();
-        if (legacy_request->key_info.body.passphrase_info.passphrase_len <
-            NAN_SECURITY_MIN_PASSPHRASE_LEN) {
-            LOG(ERROR) << "convertHidlNanDataPathIndicationResponse_1_6ToLegacy: "
-                          "passphrase_len too small";
-            return false;
-        }
-        if (legacy_request->key_info.body.passphrase_info.passphrase_len >
-            NAN_SECURITY_MAX_PASSPHRASE_LEN) {
-            LOG(ERROR) << "convertHidlNanDataPathIndicationResponse_1_6ToLegacy: "
-                          "passphrase_len too large";
-            return false;
-        }
-        memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
-               hidl_request.securityConfig.passphrase.data(),
-               legacy_request->key_info.body.passphrase_info.passphrase_len);
-    }
-    legacy_request->service_name_len = hidl_request.serviceNameOutOfBand.size();
-    if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
-        LOG(ERROR) << "convertHidlNanDataPathIndicationResponse_1_6ToLegacy: "
-                      "service_name_len too large";
-        return false;
-    }
-    memcpy(legacy_request->service_name, hidl_request.serviceNameOutOfBand.data(),
-           legacy_request->service_name_len);
-    legacy_request->scid_len = hidl_request.securityConfig.scid.size();
-    if (legacy_request->scid_len > NAN_MAX_SCID_BUF_LEN) {
-        LOG(ERROR) << "convertHidlNanDataPathIndicationResponse_1_6ToLegacy: scid_len too large";
-        return false;
-    }
-    memcpy(legacy_request->scid, hidl_request.securityConfig.scid.data(), legacy_request->scid_len);
-
-    return true;
-}
-
-bool convertLegacyNanResponseHeaderToHidl(const legacy_hal::NanResponseMsg& legacy_response,
-                                          WifiNanStatus* wifiNanStatus) {
-    if (!wifiNanStatus) {
-        LOG(ERROR) << "convertLegacyNanResponseHeaderToHidl: wifiNanStatus is null";
-        return false;
-    }
-    *wifiNanStatus = {};
-
-    convertToWifiNanStatus(legacy_response.status, legacy_response.nan_error,
-                           sizeof(legacy_response.nan_error), wifiNanStatus);
-    return true;
-}
-
-bool convertLegacyNanCapabilitiesResponseToHidl(const legacy_hal::NanCapabilities& legacy_response,
-                                                V1_6::NanCapabilities* hidl_response) {
-    if (!hidl_response) {
-        LOG(ERROR) << "convertLegacyNanCapabilitiesResponseToHidl: "
-                      "hidl_response is null";
-        return false;
-    }
-    *hidl_response = {};
-
-    hidl_response->maxConcurrentClusters = legacy_response.max_concurrent_nan_clusters;
-    hidl_response->maxPublishes = legacy_response.max_publishes;
-    hidl_response->maxSubscribes = legacy_response.max_subscribes;
-    hidl_response->maxServiceNameLen = legacy_response.max_service_name_len;
-    hidl_response->maxMatchFilterLen = legacy_response.max_match_filter_len;
-    hidl_response->maxTotalMatchFilterLen = legacy_response.max_total_match_filter_len;
-    hidl_response->maxServiceSpecificInfoLen = legacy_response.max_service_specific_info_len;
-    hidl_response->maxExtendedServiceSpecificInfoLen =
-            legacy_response.max_sdea_service_specific_info_len;
-    hidl_response->maxNdiInterfaces = legacy_response.max_ndi_interfaces;
-    hidl_response->maxNdpSessions = legacy_response.max_ndp_sessions;
-    hidl_response->maxAppInfoLen = legacy_response.max_app_info_len;
-    hidl_response->maxQueuedTransmitFollowupMsgs =
-            legacy_response.max_queued_transmit_followup_msgs;
-    hidl_response->maxSubscribeInterfaceAddresses = legacy_response.max_subscribe_address;
-    hidl_response->supportedCipherSuites = legacy_response.cipher_suites_supported;
-    hidl_response->instantCommunicationModeSupportFlag = legacy_response.is_instant_mode_supported;
-
-    return true;
-}
-
-bool convertLegacyNanMatchIndToHidl(const legacy_hal::NanMatchInd& legacy_ind,
-                                    V1_6::NanMatchInd* hidl_ind) {
-    if (!hidl_ind) {
-        LOG(ERROR) << "convertLegacyNanMatchIndToHidl: hidl_ind is null";
-        return false;
-    }
-    *hidl_ind = {};
-
-    hidl_ind->discoverySessionId = legacy_ind.publish_subscribe_id;
-    hidl_ind->peerId = legacy_ind.requestor_instance_id;
-    hidl_ind->addr = hidl_array<uint8_t, 6>(legacy_ind.addr);
-    hidl_ind->serviceSpecificInfo = std::vector<uint8_t>(
-            legacy_ind.service_specific_info,
-            legacy_ind.service_specific_info + legacy_ind.service_specific_info_len);
-    hidl_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);
-    hidl_ind->matchFilter =
-            std::vector<uint8_t>(legacy_ind.sdf_match_filter,
-                                 legacy_ind.sdf_match_filter + legacy_ind.sdf_match_filter_len);
-    hidl_ind->matchOccuredInBeaconFlag = legacy_ind.match_occured_flag == 1;
-    hidl_ind->outOfResourceFlag = legacy_ind.out_of_resource_flag == 1;
-    hidl_ind->rssiValue = legacy_ind.rssi_value;
-    hidl_ind->peerCipherType = (V1_6::NanCipherSuiteType)legacy_ind.peer_cipher_type;
-    hidl_ind->peerRequiresSecurityEnabledInNdp =
-            legacy_ind.peer_sdea_params.security_cfg == legacy_hal::NAN_DP_CONFIG_SECURITY;
-    hidl_ind->peerRequiresRanging =
-            legacy_ind.peer_sdea_params.ranging_state == legacy_hal::NAN_RANGING_ENABLE;
-    hidl_ind->rangingMeasurementInMm = legacy_ind.range_info.range_measurement_mm;
-    hidl_ind->rangingIndicationType = legacy_ind.range_info.ranging_event_type;
-    hidl_ind->scid = std::vector<uint8_t>(legacy_ind.scid, legacy_ind.scid + legacy_ind.scid_len);
-    return true;
-}
-
-bool convertLegacyNanFollowupIndToHidl(const legacy_hal::NanFollowupInd& legacy_ind,
-                                       NanFollowupReceivedInd* hidl_ind) {
-    if (!hidl_ind) {
-        LOG(ERROR) << "convertLegacyNanFollowupIndToHidl: hidl_ind is null";
-        return false;
-    }
-    *hidl_ind = {};
-
-    hidl_ind->discoverySessionId = legacy_ind.publish_subscribe_id;
-    hidl_ind->peerId = legacy_ind.requestor_instance_id;
-    hidl_ind->addr = hidl_array<uint8_t, 6>(legacy_ind.addr);
-    hidl_ind->receivedInFaw = legacy_ind.dw_or_faw == 1;
-    hidl_ind->serviceSpecificInfo = std::vector<uint8_t>(
-            legacy_ind.service_specific_info,
-            legacy_ind.service_specific_info + legacy_ind.service_specific_info_len);
-    hidl_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 convertLegacyNanDataPathRequestIndToHidl(const legacy_hal::NanDataPathRequestInd& legacy_ind,
-                                              NanDataPathRequestInd* hidl_ind) {
-    if (!hidl_ind) {
-        LOG(ERROR) << "convertLegacyNanDataPathRequestIndToHidl: hidl_ind is null";
-        return false;
-    }
-    *hidl_ind = {};
-
-    hidl_ind->discoverySessionId = legacy_ind.service_instance_id;
-    hidl_ind->peerDiscMacAddr = hidl_array<uint8_t, 6>(legacy_ind.peer_disc_mac_addr);
-    hidl_ind->ndpInstanceId = legacy_ind.ndp_instance_id;
-    hidl_ind->securityRequired =
-            legacy_ind.ndp_cfg.security_cfg == legacy_hal::NAN_DP_CONFIG_SECURITY;
-    hidl_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 convertLegacyNdpChannelInfoToHidl(const legacy_hal::NanChannelInfo& legacy_struct,
-                                       V1_6::NanDataPathChannelInfo* hidl_struct) {
-    if (!hidl_struct) {
-        LOG(ERROR) << "convertLegacyNdpChannelInfoToHidl: hidl_struct is null";
-        return false;
-    }
-    *hidl_struct = {};
-
-    hidl_struct->channelFreq = legacy_struct.channel;
-    hidl_struct->channelBandwidth = convertLegacyWifiChannelWidthToHidl(
-            (legacy_hal::wifi_channel_width)legacy_struct.bandwidth);
-    hidl_struct->numSpatialStreams = legacy_struct.nss;
-
-    return true;
-}
-
-bool convertLegacyNanDataPathConfirmIndToHidl(const legacy_hal::NanDataPathConfirmInd& legacy_ind,
-                                              V1_6::NanDataPathConfirmInd* hidl_ind) {
-    if (!hidl_ind) {
-        LOG(ERROR) << "convertLegacyNanDataPathConfirmIndToHidl: hidl_ind is null";
-        return false;
-    }
-    *hidl_ind = {};
-
-    hidl_ind->V1_0.ndpInstanceId = legacy_ind.ndp_instance_id;
-    hidl_ind->V1_0.dataPathSetupSuccess = legacy_ind.rsp_code == legacy_hal::NAN_DP_REQUEST_ACCEPT;
-    hidl_ind->V1_0.peerNdiMacAddr = hidl_array<uint8_t, 6>(legacy_ind.peer_ndi_mac_addr);
-    hidl_ind->V1_0.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);
-    hidl_ind->V1_0.status.status = convertLegacyNanStatusTypeToHidl(legacy_ind.reason_code);
-    hidl_ind->V1_0.status.description = "";  // TODO: b/34059183
-
-    std::vector<V1_6::NanDataPathChannelInfo> channelInfo;
-    for (unsigned int i = 0; i < legacy_ind.num_channels; ++i) {
-        V1_6::NanDataPathChannelInfo hidl_struct;
-        if (!convertLegacyNdpChannelInfoToHidl(legacy_ind.channel_info[i], &hidl_struct)) {
-            return false;
-        }
-        channelInfo.push_back(hidl_struct);
-    }
-    hidl_ind->channelInfo = channelInfo;
-
-    return true;
-}
-
-bool convertLegacyNanDataPathScheduleUpdateIndToHidl(
-        const legacy_hal::NanDataPathScheduleUpdateInd& legacy_ind,
-        V1_6::NanDataPathScheduleUpdateInd* hidl_ind) {
-    if (!hidl_ind) {
-        LOG(ERROR) << "convertLegacyNanDataPathScheduleUpdateIndToHidl: "
-                      "hidl_ind is null";
-        return false;
-    }
-    *hidl_ind = {};
-
-    hidl_ind->peerDiscoveryAddress = hidl_array<uint8_t, 6>(legacy_ind.peer_mac_addr);
-    std::vector<V1_6::NanDataPathChannelInfo> channelInfo;
-    for (unsigned int i = 0; i < legacy_ind.num_channels; ++i) {
-        V1_6::NanDataPathChannelInfo hidl_struct;
-        if (!convertLegacyNdpChannelInfoToHidl(legacy_ind.channel_info[i], &hidl_struct)) {
-            return false;
-        }
-        channelInfo.push_back(hidl_struct);
-    }
-    hidl_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]);
-    }
-    hidl_ind->ndpInstanceIds = ndpInstanceIds;
-
-    return true;
-}
-
-legacy_hal::wifi_rtt_type convertHidlRttTypeToLegacy(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 convertLegacyRttTypeToHidl(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 convertHidlRttPeerTypeToLegacy(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:
-            return legacy_hal::RTT_PEER_NAN;
-    };
-    CHECK(false);
-}
-
-legacy_hal::wifi_channel_width convertHidlWifiChannelWidthToLegacy(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 V1_6::WifiChannelWidthInMhz::WIDTH_320:
-            return legacy_hal::WIFI_CHAN_WIDTH_320;
-        case WifiChannelWidthInMhz::WIDTH_INVALID:
-            return legacy_hal::WIFI_CHAN_WIDTH_INVALID;
-    };
-    CHECK(false);
-}
-
-V1_6::WifiChannelWidthInMhz convertLegacyWifiChannelWidthToHidl(
-        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 V1_6::WifiChannelWidthInMhz::WIDTH_320;
-        default:
-            return WifiChannelWidthInMhz::WIDTH_INVALID;
-    };
-}
-
-legacy_hal::wifi_rtt_preamble convertHidlRttPreambleToLegacy(V1_6::RttPreamble type) {
-    switch (type) {
-        case V1_6::RttPreamble::LEGACY:
-            return legacy_hal::WIFI_RTT_PREAMBLE_LEGACY;
-        case V1_6::RttPreamble::HT:
-            return legacy_hal::WIFI_RTT_PREAMBLE_HT;
-        case V1_6::RttPreamble::VHT:
-            return legacy_hal::WIFI_RTT_PREAMBLE_VHT;
-        case V1_6::RttPreamble::HE:
-            return legacy_hal::WIFI_RTT_PREAMBLE_HE;
-        case V1_6::RttPreamble::EHT:
-            return legacy_hal::WIFI_RTT_PREAMBLE_EHT;
-    };
-    CHECK(false);
-}
-
-V1_6::RttPreamble convertLegacyRttPreambleToHidl(legacy_hal::wifi_rtt_preamble type) {
-    switch (type) {
-        case legacy_hal::WIFI_RTT_PREAMBLE_LEGACY:
-            return V1_6::RttPreamble::LEGACY;
-        case legacy_hal::WIFI_RTT_PREAMBLE_HT:
-            return V1_6::RttPreamble::HT;
-        case legacy_hal::WIFI_RTT_PREAMBLE_VHT:
-            return V1_6::RttPreamble::VHT;
-        case legacy_hal::WIFI_RTT_PREAMBLE_HE:
-            return V1_6::RttPreamble::HE;
-        case legacy_hal::WIFI_RTT_PREAMBLE_EHT:
-            return V1_6::RttPreamble::EHT;
-    };
-    CHECK(false) << "Unknown legacy type: " << type;
-}
-
-legacy_hal::wifi_rtt_bw convertHidlRttBwToLegacy(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;
-    };
-    CHECK(false);
-}
-
-RttBw convertLegacyRttBwToHidl(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;
-    };
-    CHECK(false) << "Unknown legacy type: " << type;
-}
-
-legacy_hal::wifi_motion_pattern convertHidlRttMotionPatternToLegacy(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);
-}
-
-V1_6::WifiRatePreamble convertLegacyWifiRatePreambleToHidl(uint8_t preamble) {
-    switch (preamble) {
-        case 0:
-            return V1_6::WifiRatePreamble::OFDM;
-        case 1:
-            return V1_6::WifiRatePreamble::CCK;
-        case 2:
-            return V1_6::WifiRatePreamble::HT;
-        case 3:
-            return V1_6::WifiRatePreamble::VHT;
-        case 4:
-            return V1_6::WifiRatePreamble::HE;
-        case 5:
-            return V1_6::WifiRatePreamble::EHT;
-        default:
-            return V1_6::WifiRatePreamble::RESERVED;
-    };
-    CHECK(false) << "Unknown legacy preamble: " << preamble;
-}
-
-WifiRateNss convertLegacyWifiRateNssToHidl(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 convertLegacyRttStatusToHidl(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::FAILURE;  // TODO: add HIDL enumeration
-        case legacy_hal::RTT_STATUS_NAN_RANGING_CONCURRENCY_NOT_SUPPORTED:
-            return RttStatus::FAILURE;  // TODO: add HIDL enumeration
-    };
-    CHECK(false) << "Unknown legacy status: " << status;
-}
-
-bool convertHidlWifiChannelInfoToLegacy(const WifiChannelInfo& hidl_info,
-                                        legacy_hal::wifi_channel_info* legacy_info) {
-    if (!legacy_info) {
-        return false;
-    }
-    *legacy_info = {};
-    legacy_info->width = convertHidlWifiChannelWidthToLegacy(hidl_info.width);
-    legacy_info->center_freq = hidl_info.centerFreq;
-    legacy_info->center_freq0 = hidl_info.centerFreq0;
-    legacy_info->center_freq1 = hidl_info.centerFreq1;
-    return true;
-}
-
-bool convertLegacyWifiChannelInfoToHidl(const legacy_hal::wifi_channel_info& legacy_info,
-                                        WifiChannelInfo* hidl_info) {
-    if (!hidl_info) {
-        return false;
-    }
-    *hidl_info = {};
-    hidl_info->width = convertLegacyWifiChannelWidthToHidl(legacy_info.width);
-    hidl_info->centerFreq = legacy_info.center_freq;
-    hidl_info->centerFreq0 = legacy_info.center_freq0;
-    hidl_info->centerFreq1 = legacy_info.center_freq1;
-    return true;
-}
-
-bool convertHidlRttConfigToLegacy(const V1_6::RttConfig& hidl_config,
-                                  legacy_hal::wifi_rtt_config* legacy_config) {
-    if (!legacy_config) {
-        return false;
-    }
-    *legacy_config = {};
-    CHECK(hidl_config.addr.size() == sizeof(legacy_config->addr));
-    memcpy(legacy_config->addr, hidl_config.addr.data(), hidl_config.addr.size());
-    legacy_config->type = convertHidlRttTypeToLegacy(hidl_config.type);
-    legacy_config->peer = convertHidlRttPeerTypeToLegacy(hidl_config.peer);
-    if (!convertHidlWifiChannelInfoToLegacy(hidl_config.channel, &legacy_config->channel)) {
-        return false;
-    }
-    legacy_config->burst_period = hidl_config.burstPeriod;
-    legacy_config->num_burst = hidl_config.numBurst;
-    legacy_config->num_frames_per_burst = hidl_config.numFramesPerBurst;
-    legacy_config->num_retries_per_rtt_frame = hidl_config.numRetriesPerRttFrame;
-    legacy_config->num_retries_per_ftmr = hidl_config.numRetriesPerFtmr;
-    legacy_config->LCI_request = hidl_config.mustRequestLci;
-    legacy_config->LCR_request = hidl_config.mustRequestLcr;
-    legacy_config->burst_duration = hidl_config.burstDuration;
-    legacy_config->preamble = convertHidlRttPreambleToLegacy(hidl_config.preamble);
-    legacy_config->bw = convertHidlRttBwToLegacy(hidl_config.bw);
-    return true;
-}
-
-bool convertHidlVectorOfRttConfigToLegacy(
-        const std::vector<V1_6::RttConfig>& hidl_configs,
-        std::vector<legacy_hal::wifi_rtt_config>* legacy_configs) {
-    if (!legacy_configs) {
-        return false;
-    }
-    *legacy_configs = {};
-    for (const auto& hidl_config : hidl_configs) {
-        legacy_hal::wifi_rtt_config legacy_config;
-        if (!convertHidlRttConfigToLegacy(hidl_config, &legacy_config)) {
-            return false;
-        }
-        legacy_configs->push_back(legacy_config);
-    }
-    return true;
-}
-
-bool convertHidlRttLciInformationToLegacy(const RttLciInformation& hidl_info,
-                                          legacy_hal::wifi_lci_information* legacy_info) {
-    if (!legacy_info) {
-        return false;
-    }
-    *legacy_info = {};
-    legacy_info->latitude = hidl_info.latitude;
-    legacy_info->longitude = hidl_info.longitude;
-    legacy_info->altitude = hidl_info.altitude;
-    legacy_info->latitude_unc = hidl_info.latitudeUnc;
-    legacy_info->longitude_unc = hidl_info.longitudeUnc;
-    legacy_info->altitude_unc = hidl_info.altitudeUnc;
-    legacy_info->motion_pattern = convertHidlRttMotionPatternToLegacy(hidl_info.motionPattern);
-    legacy_info->floor = hidl_info.floor;
-    legacy_info->height_above_floor = hidl_info.heightAboveFloor;
-    legacy_info->height_unc = hidl_info.heightUnc;
-    return true;
-}
-
-bool convertHidlRttLcrInformationToLegacy(const RttLcrInformation& hidl_info,
-                                          legacy_hal::wifi_lcr_information* legacy_info) {
-    if (!legacy_info) {
-        return false;
-    }
-    *legacy_info = {};
-    CHECK(hidl_info.countryCode.size() == sizeof(legacy_info->country_code));
-    memcpy(legacy_info->country_code, hidl_info.countryCode.data(), hidl_info.countryCode.size());
-    if (hidl_info.civicInfo.size() > sizeof(legacy_info->civic_info)) {
-        return false;
-    }
-    legacy_info->length = hidl_info.civicInfo.size();
-    memcpy(legacy_info->civic_info, hidl_info.civicInfo.c_str(), hidl_info.civicInfo.size());
-    return true;
-}
-
-bool convertHidlRttResponderToLegacy(const V1_6::RttResponder& hidl_responder,
-                                     legacy_hal::wifi_rtt_responder* legacy_responder) {
-    if (!legacy_responder) {
-        return false;
-    }
-    *legacy_responder = {};
-    if (!convertHidlWifiChannelInfoToLegacy(hidl_responder.channel, &legacy_responder->channel)) {
-        return false;
-    }
-    legacy_responder->preamble = convertHidlRttPreambleToLegacy(hidl_responder.preamble);
-    return true;
-}
-
-bool convertLegacyRttResponderToHidl(const legacy_hal::wifi_rtt_responder& legacy_responder,
-                                     V1_6::RttResponder* hidl_responder) {
-    if (!hidl_responder) {
-        return false;
-    }
-    *hidl_responder = {};
-    if (!convertLegacyWifiChannelInfoToHidl(legacy_responder.channel, &hidl_responder->channel)) {
-        return false;
-    }
-    hidl_responder->preamble = convertLegacyRttPreambleToHidl(legacy_responder.preamble);
-    return true;
-}
-
-bool convertLegacyRttCapabilitiesToHidl(
-        const legacy_hal::wifi_rtt_capabilities& legacy_capabilities,
-        V1_6::RttCapabilities* hidl_capabilities) {
-    if (!hidl_capabilities) {
-        return false;
-    }
-    *hidl_capabilities = {};
-    hidl_capabilities->rttOneSidedSupported = legacy_capabilities.rtt_one_sided_supported;
-    hidl_capabilities->rttFtmSupported = legacy_capabilities.rtt_ftm_supported;
-    hidl_capabilities->lciSupported = legacy_capabilities.lci_support;
-    hidl_capabilities->lcrSupported = legacy_capabilities.lcr_support;
-    hidl_capabilities->responderSupported = legacy_capabilities.responder_supported;
-    hidl_capabilities->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) {
-            hidl_capabilities->preambleSupport |=
-                    static_cast<std::underlying_type<V1_6::RttPreamble>::type>(
-                            convertLegacyRttPreambleToHidl(flag));
-        }
-    }
-    hidl_capabilities->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) {
-            hidl_capabilities->bwSupport |=
-                    static_cast<std::underlying_type<RttBw>::type>(convertLegacyRttBwToHidl(flag));
-        }
-    }
-    hidl_capabilities->mcVersion = legacy_capabilities.mc_version;
-    return true;
-}
-
-bool convertLegacyWifiRateInfoToHidl(const legacy_hal::wifi_rate& legacy_rate,
-                                     V1_6::WifiRateInfo* hidl_rate) {
-    if (!hidl_rate) {
-        return false;
-    }
-    *hidl_rate = {};
-    hidl_rate->preamble = convertLegacyWifiRatePreambleToHidl(legacy_rate.preamble);
-    hidl_rate->nss = convertLegacyWifiRateNssToHidl(legacy_rate.nss);
-    hidl_rate->bw = convertLegacyWifiChannelWidthToHidl(
-            static_cast<legacy_hal::wifi_channel_width>(legacy_rate.bw));
-    hidl_rate->rateMcsIdx = legacy_rate.rateMcsIdx;
-    hidl_rate->bitRateInKbps = legacy_rate.bitrate;
-    return true;
-}
-
-bool convertLegacyRttResultToHidl(const legacy_hal::wifi_rtt_result& legacy_result,
-                                  V1_6::RttResult* hidl_result) {
-    if (!hidl_result) {
-        return false;
-    }
-    *hidl_result = {};
-    CHECK(sizeof(legacy_result.addr) == hidl_result->addr.size());
-    memcpy(hidl_result->addr.data(), legacy_result.addr, sizeof(legacy_result.addr));
-    hidl_result->burstNum = legacy_result.burst_num;
-    hidl_result->measurementNumber = legacy_result.measurement_number;
-    hidl_result->successNumber = legacy_result.success_number;
-    hidl_result->numberPerBurstPeer = legacy_result.number_per_burst_peer;
-    hidl_result->status = convertLegacyRttStatusToHidl(legacy_result.status);
-    hidl_result->retryAfterDuration = legacy_result.retry_after_duration;
-    hidl_result->type = convertLegacyRttTypeToHidl(legacy_result.type);
-    hidl_result->rssi = legacy_result.rssi;
-    hidl_result->rssiSpread = legacy_result.rssi_spread;
-    if (!convertLegacyWifiRateInfoToHidl(legacy_result.tx_rate, &hidl_result->txRate)) {
-        return false;
-    }
-    if (!convertLegacyWifiRateInfoToHidl(legacy_result.rx_rate, &hidl_result->rxRate)) {
-        return false;
-    }
-    hidl_result->rtt = legacy_result.rtt;
-    hidl_result->rttSd = legacy_result.rtt_sd;
-    hidl_result->rttSpread = legacy_result.rtt_spread;
-    hidl_result->distanceInMm = legacy_result.distance_mm;
-    hidl_result->distanceSdInMm = legacy_result.distance_sd_mm;
-    hidl_result->distanceSpreadInMm = legacy_result.distance_spread_mm;
-    hidl_result->timeStampInUs = legacy_result.ts;
-    hidl_result->burstDurationInMs = legacy_result.burst_duration;
-    hidl_result->negotiatedBurstNum = legacy_result.negotiated_burst_num;
-    if (legacy_result.LCI && !convertLegacyIeToHidl(*legacy_result.LCI, &hidl_result->lci)) {
-        return false;
-    }
-    if (legacy_result.LCR && !convertLegacyIeToHidl(*legacy_result.LCR, &hidl_result->lcr)) {
-        return false;
-    }
-    return true;
-}
-
-bool convertLegacyVectorOfRttResultToHidl(
-        const std::vector<const legacy_hal::wifi_rtt_result*>& legacy_results,
-        std::vector<V1_6::RttResult>* hidl_results) {
-    if (!hidl_results) {
-        return false;
-    }
-    *hidl_results = {};
-    for (const auto legacy_result : legacy_results) {
-        V1_6::RttResult hidl_result;
-        if (!convertLegacyRttResultToHidl(*legacy_result, &hidl_result)) {
-            return false;
-        }
-        hidl_results->push_back(hidl_result);
-    }
-    return true;
-}
-
-legacy_hal::wifi_interface_type convertHidlIfaceTypeToLegacy(IfaceType hidl_interface_type) {
-    switch (hidl_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:
-            return legacy_hal::WIFI_INTERFACE_TYPE_NAN;
-    }
-    CHECK(false);
-}
-
-legacy_hal::wifi_multi_sta_use_case convertHidlMultiStaUseCaseToLegacy(
-        V1_5::IWifiChip::MultiStaUseCase use_case) {
-    switch (use_case) {
-        case V1_5::IWifiChip::MultiStaUseCase::DUAL_STA_TRANSIENT_PREFER_PRIMARY:
-            return legacy_hal::WIFI_DUAL_STA_TRANSIENT_PREFER_PRIMARY;
-        case V1_5::IWifiChip::MultiStaUseCase::DUAL_STA_NON_TRANSIENT_UNBIASED:
-            return legacy_hal::WIFI_DUAL_STA_NON_TRANSIENT_UNBIASED;
-    }
-    CHECK(false);
-}
-
-bool convertHidlCoexUnsafeChannelToLegacy(
-        const V1_5::IWifiChip::CoexUnsafeChannel& hidl_unsafe_channel,
-        legacy_hal::wifi_coex_unsafe_channel* legacy_unsafe_channel) {
-    if (!legacy_unsafe_channel) {
-        return false;
-    }
-    *legacy_unsafe_channel = {};
-    switch (hidl_unsafe_channel.band) {
-        case V1_5::WifiBand::BAND_24GHZ:
-            legacy_unsafe_channel->band = legacy_hal::WLAN_MAC_2_4_BAND;
-            break;
-        case V1_5::WifiBand::BAND_5GHZ:
-            legacy_unsafe_channel->band = legacy_hal::WLAN_MAC_5_0_BAND;
-            break;
-        default:
-            return false;
-    };
-    legacy_unsafe_channel->channel = hidl_unsafe_channel.channel;
-    legacy_unsafe_channel->power_cap_dbm = hidl_unsafe_channel.powerCapDbm;
-    return true;
-}
-
-bool convertHidlVectorOfCoexUnsafeChannelToLegacy(
-        const std::vector<V1_5::IWifiChip::CoexUnsafeChannel>& hidl_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& hidl_unsafe_channel : hidl_unsafe_channels) {
-        legacy_hal::wifi_coex_unsafe_channel legacy_unsafe_channel;
-        if (!hidl_struct_util::convertHidlCoexUnsafeChannelToLegacy(hidl_unsafe_channel,
-                                                                    &legacy_unsafe_channel)) {
-            return false;
-        }
-        legacy_unsafe_channels->push_back(legacy_unsafe_channel);
-    }
-    return true;
-}
-
-V1_6::WifiAntennaMode convertLegacyAntennaConfigurationToHidl(uint32_t antenna_cfg) {
-    switch (antenna_cfg) {
-        case legacy_hal::WIFI_ANTENNA_1X1:
-            return V1_6::WifiAntennaMode::WIFI_ANTENNA_MODE_1X1;
-        case legacy_hal::WIFI_ANTENNA_2X2:
-            return V1_6::WifiAntennaMode::WIFI_ANTENNA_MODE_2X2;
-        case legacy_hal::WIFI_ANTENNA_3X3:
-            return V1_6::WifiAntennaMode::WIFI_ANTENNA_MODE_3X3;
-        case legacy_hal::WIFI_ANTENNA_4X4:
-            return V1_6::WifiAntennaMode::WIFI_ANTENNA_MODE_4X4;
-        default:
-            return V1_6::WifiAntennaMode::WIFI_ANTENNA_MODE_UNSPECIFIED;
-    }
-}
-
-bool convertLegacyWifiRadioConfigurationToHidl(
-        legacy_hal::wifi_radio_configuration* radio_configuration,
-        V1_6::WifiRadioConfiguration* hidl_radio_configuration) {
-    if (!hidl_radio_configuration) {
-        return false;
-    }
-    *hidl_radio_configuration = {};
-    hidl_radio_configuration->bandInfo =
-            hidl_struct_util::convertLegacyMacBandToHidlWifiBand(radio_configuration->band);
-    if (hidl_radio_configuration->bandInfo == V1_5::WifiBand::BAND_UNSPECIFIED) {
-        LOG(ERROR) << "Unspecified band";
-        return false;
-    }
-    hidl_radio_configuration->antennaMode =
-            hidl_struct_util::convertLegacyAntennaConfigurationToHidl(
-                    radio_configuration->antenna_cfg);
-    return true;
-}
-
-bool convertLegacyRadioCombinationsMatrixToHidl(
-        legacy_hal::wifi_radio_combination_matrix* legacy_matrix,
-        WifiRadioCombinationMatrix* hidl_matrix) {
-    if (!hidl_matrix || !legacy_matrix) {
-        return false;
-    }
-    *hidl_matrix = {};
-
-    int num_combinations = legacy_matrix->num_radio_combinations;
-    std::vector<V1_6::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<V1_6::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 (!hidl_struct_util::convertLegacyWifiRadioConfigurationToHidl(
-                        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));
-    }
-    hidl_matrix->radioCombinations = radio_combinations_vec;
-    return true;
-}
-
-}  // namespace hidl_struct_util
-}  // namespace implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.6/default/hidl_struct_util.h b/wifi/1.6/default/hidl_struct_util.h
deleted file mode 100644
index 2d4a5f1..0000000
--- a/wifi/1.6/default/hidl_struct_util.h
+++ /dev/null
@@ -1,204 +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 HIDL_STRUCT_UTIL_H_
-#define HIDL_STRUCT_UTIL_H_
-
-#include <vector>
-
-#include <android/hardware/wifi/1.0/IWifiChip.h>
-#include <android/hardware/wifi/1.0/types.h>
-#include <android/hardware/wifi/1.2/types.h>
-#include <android/hardware/wifi/1.3/types.h>
-#include <android/hardware/wifi/1.4/IWifiChipEventCallback.h>
-#include <android/hardware/wifi/1.4/types.h>
-#include <android/hardware/wifi/1.6/IWifiChip.h>
-#include <android/hardware/wifi/1.6/types.h>
-
-#include "wifi_legacy_hal.h"
-
-/**
- * This file contains a bunch of functions to convert structs from the legacy
- * HAL to HIDL and vice versa.
- * TODO(b/32093047): Add unit tests for these conversion methods in the VTS test
- * suite.
- */
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-namespace hidl_struct_util {
-using namespace android::hardware::wifi::V1_0;
-
-// Chip conversion methods.
-bool convertLegacyFeaturesToHidlChipCapabilities(uint64_t legacy_feature_set,
-                                                 uint32_t legacy_logger_feature_set,
-                                                 uint32_t* hidl_caps);
-bool convertLegacyDebugRingBufferStatusToHidl(
-        const legacy_hal::wifi_ring_buffer_status& legacy_status,
-        WifiDebugRingBufferStatus* hidl_status);
-bool convertLegacyVectorOfDebugRingBufferStatusToHidl(
-        const std::vector<legacy_hal::wifi_ring_buffer_status>& legacy_status_vec,
-        std::vector<WifiDebugRingBufferStatus>* hidl_status_vec);
-bool convertLegacyWakeReasonStatsToHidl(const legacy_hal::WakeReasonStats& legacy_stats,
-                                        WifiDebugHostWakeReasonStats* hidl_stats);
-legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy(
-        V1_1::IWifiChip::TxPowerScenario hidl_scenario);
-legacy_hal::wifi_latency_mode convertHidlLatencyModeToLegacy(
-        V1_3::IWifiChip::LatencyMode hidl_latency_mode);
-legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy_1_2(
-        V1_2::IWifiChip::TxPowerScenario hidl_scenario);
-bool convertLegacyWifiMacInfosToHidl(
-        const std::vector<legacy_hal::WifiMacInfo>& legacy_mac_infos,
-        std::vector<V1_4::IWifiChipEventCallback::RadioModeInfo>* hidl_radio_mode_infos);
-legacy_hal::wifi_interface_type convertHidlIfaceTypeToLegacy(IfaceType hidl_interface_type);
-legacy_hal::wifi_multi_sta_use_case convertHidlMultiStaUseCaseToLegacy(
-        V1_5::IWifiChip::MultiStaUseCase use_case);
-bool convertHidlCoexUnsafeChannelToLegacy(
-        const V1_5::IWifiChip::CoexUnsafeChannel& hidl_unsafe_channel,
-        legacy_hal::wifi_coex_unsafe_channel* legacy_unsafe_channel);
-bool convertHidlVectorOfCoexUnsafeChannelToLegacy(
-        const std::vector<V1_5::IWifiChip::CoexUnsafeChannel>& hidl_unsafe_channels,
-        std::vector<legacy_hal::wifi_coex_unsafe_channel>* legacy_unsafe_channels);
-bool convertLegacyRadioCombinationsMatrixToHidl(
-        legacy_hal::wifi_radio_combination_matrix* legacy_matrix,
-        V1_6::WifiRadioCombinationMatrix* hidl_matrix);
-V1_5::WifiBand convertLegacyMacBandToHidlWifiBand(uint32_t band);
-V1_6::WifiAntennaMode convertLegacyAntennaConfigurationToHidl(uint32_t antenna_cfg);
-
-// STA iface conversion methods.
-bool convertLegacyFeaturesToHidlStaCapabilities(uint64_t legacy_feature_set,
-                                                uint32_t legacy_logger_feature_set,
-                                                uint32_t* hidl_caps);
-bool convertLegacyApfCapabilitiesToHidl(const legacy_hal::PacketFilterCapabilities& legacy_caps,
-                                        StaApfPacketFilterCapabilities* hidl_caps);
-bool convertLegacyGscanCapabilitiesToHidl(const legacy_hal::wifi_gscan_capabilities& legacy_caps,
-                                          StaBackgroundScanCapabilities* hidl_caps);
-legacy_hal::wifi_band convertHidlWifiBandToLegacy(V1_0::WifiBand band);
-bool convertHidlGscanParamsToLegacy(const StaBackgroundScanParameters& hidl_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 convertLegacyGscanResultToHidl(const legacy_hal::wifi_scan_result& legacy_scan_result,
-                                    bool has_ie_data, StaScanResult* hidl_scan_result);
-// |cached_results| is assumed to not include IEs.
-bool convertLegacyVectorOfCachedGscanResultsToHidl(
-        const std::vector<legacy_hal::wifi_cached_scan_results>& legacy_cached_scan_results,
-        std::vector<StaScanData>* hidl_scan_datas);
-bool convertLegacyLinkLayerStatsToHidl(const legacy_hal::LinkLayerStats& legacy_stats,
-                                       V1_6::StaLinkLayerStats* hidl_stats);
-bool convertLegacyRoamingCapabilitiesToHidl(
-        const legacy_hal::wifi_roaming_capabilities& legacy_caps,
-        StaRoamingCapabilities* hidl_caps);
-bool convertHidlRoamingConfigToLegacy(const StaRoamingConfig& hidl_config,
-                                      legacy_hal::wifi_roaming_config* legacy_config);
-legacy_hal::fw_roaming_state_t convertHidlRoamingStateToLegacy(StaRoamingState state);
-bool convertLegacyVectorOfDebugTxPacketFateToHidl(
-        const std::vector<legacy_hal::wifi_tx_report>& legacy_fates,
-        std::vector<WifiDebugTxPacketFateReport>* hidl_fates);
-bool convertLegacyVectorOfDebugRxPacketFateToHidl(
-        const std::vector<legacy_hal::wifi_rx_report>& legacy_fates,
-        std::vector<WifiDebugRxPacketFateReport>* hidl_fates);
-
-// NAN iface conversion methods.
-void convertToWifiNanStatus(legacy_hal::NanStatusType type, const char* str, size_t max_len,
-                            WifiNanStatus* wifiNanStatus);
-bool convertHidlNanEnableRequestToLegacy(const V1_4::NanEnableRequest& hidl_request,
-                                         legacy_hal::NanEnableRequest* legacy_request);
-bool convertHidlNanConfigRequestToLegacy(const V1_4::NanConfigRequest& hidl_request,
-                                         legacy_hal::NanConfigRequest* legacy_request);
-bool convertHidlNanEnableRequest_1_6ToLegacy(
-        const V1_4::NanEnableRequest& hidl_request1,
-        const V1_6::NanConfigRequestSupplemental& hidl_request2,
-        legacy_hal::NanEnableRequest* legacy_request);
-bool convertHidlNanConfigRequest_1_6ToLegacy(
-        const V1_4::NanConfigRequest& hidl_request1,
-        const V1_6::NanConfigRequestSupplemental& hidl_request2,
-        legacy_hal::NanConfigRequest* legacy_request);
-bool convertHidlNanPublishRequestToLegacy(const V1_6::NanPublishRequest& hidl_request,
-                                          legacy_hal::NanPublishRequest* legacy_request);
-bool convertHidlNanSubscribeRequestToLegacy(const V1_0::NanSubscribeRequest& hidl_request,
-                                            legacy_hal::NanSubscribeRequest* legacy_request);
-bool convertHidlNanTransmitFollowupRequestToLegacy(
-        const NanTransmitFollowupRequest& hidl_request,
-        legacy_hal::NanTransmitFollowupRequest* legacy_request);
-bool convertHidlNanDataPathInitiatorRequestToLegacy(
-        const V1_0::NanInitiateDataPathRequest& hidl_request,
-        legacy_hal::NanDataPathInitiatorRequest* legacy_request);
-bool convertHidlNanDataPathIndicationResponseToLegacy(
-        const V1_0::NanRespondToDataPathIndicationRequest& hidl_response,
-        legacy_hal::NanDataPathIndicationResponse* legacy_response);
-bool convertHidlNanDataPathInitiatorRequest_1_6ToLegacy(
-        const V1_6::NanInitiateDataPathRequest& hidl_request,
-        legacy_hal::NanDataPathInitiatorRequest* legacy_request);
-bool convertHidlNanDataPathIndicationResponse_1_6ToLegacy(
-        const V1_6::NanRespondToDataPathIndicationRequest& hidl_response,
-        legacy_hal::NanDataPathIndicationResponse* legacy_response);
-
-bool convertLegacyNanResponseHeaderToHidl(const legacy_hal::NanResponseMsg& legacy_response,
-                                          WifiNanStatus* wifiNanStatus);
-bool convertLegacyNanCapabilitiesResponseToHidl(const legacy_hal::NanCapabilities& legacy_response,
-                                                V1_6::NanCapabilities* hidl_response);
-bool convertLegacyNanMatchIndToHidl(const legacy_hal::NanMatchInd& legacy_ind,
-                                    V1_6::NanMatchInd* hidl_ind);
-bool convertLegacyNanFollowupIndToHidl(const legacy_hal::NanFollowupInd& legacy_ind,
-                                       NanFollowupReceivedInd* hidl_ind);
-bool convertLegacyNanDataPathRequestIndToHidl(const legacy_hal::NanDataPathRequestInd& legacy_ind,
-                                              NanDataPathRequestInd* hidl_ind);
-bool convertLegacyNanDataPathConfirmIndToHidl(const legacy_hal::NanDataPathConfirmInd& legacy_ind,
-                                              V1_6::NanDataPathConfirmInd* hidl_ind);
-bool convertLegacyNanDataPathScheduleUpdateIndToHidl(
-        const legacy_hal::NanDataPathScheduleUpdateInd& legacy_ind,
-        V1_6::NanDataPathScheduleUpdateInd* hidl_ind);
-
-// RTT controller conversion methods.
-bool convertHidlVectorOfRttConfigToLegacy(const std::vector<V1_6::RttConfig>& hidl_configs,
-                                          std::vector<legacy_hal::wifi_rtt_config>* legacy_configs);
-bool convertHidlRttLciInformationToLegacy(const RttLciInformation& hidl_info,
-                                          legacy_hal::wifi_lci_information* legacy_info);
-bool convertHidlRttLcrInformationToLegacy(const RttLcrInformation& hidl_info,
-                                          legacy_hal::wifi_lcr_information* legacy_info);
-bool convertHidlRttResponderToLegacy(const V1_6::RttResponder& hidl_responder,
-                                     legacy_hal::wifi_rtt_responder* legacy_responder);
-bool convertHidlWifiChannelInfoToLegacy(const V1_6::WifiChannelInfo& hidl_info,
-                                        legacy_hal::wifi_channel_info* legacy_info);
-bool convertLegacyRttResponderToHidl(const legacy_hal::wifi_rtt_responder& legacy_responder,
-                                     V1_6::RttResponder* hidl_responder);
-bool convertLegacyRttCapabilitiesToHidl(
-        const legacy_hal::wifi_rtt_capabilities& legacy_capabilities,
-        V1_6::RttCapabilities* hidl_capabilities);
-bool convertLegacyVectorOfRttResultToHidl(
-        const std::vector<const legacy_hal::wifi_rtt_result*>& legacy_results,
-        std::vector<V1_6::RttResult>* hidl_results);
-uint32_t convertHidlWifiBandToLegacyMacBand(V1_5::WifiBand band);
-uint32_t convertHidlWifiIfaceModeToLegacy(uint32_t hidl_iface_mask);
-uint32_t convertHidlUsableChannelFilterToLegacy(uint32_t hidl_filter_mask);
-bool convertLegacyWifiUsableChannelsToHidl(
-        const std::vector<legacy_hal::wifi_usable_channel>& legacy_usable_channels,
-        std::vector<V1_6::WifiUsableChannel>* hidl_usable_channels);
-bool convertLegacyPeerInfoStatsToHidl(const legacy_hal::WifiPeerInfo& legacy_peer_info_stats,
-                                      V1_6::StaPeerInfo* hidl_peer_info_stats);
-bool convertLegacyWifiRateInfoToHidl(const legacy_hal::wifi_rate& legacy_rate,
-                                     V1_6::WifiRateInfo* hidl_rate);
-}  // namespace hidl_struct_util
-}  // namespace implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // HIDL_STRUCT_UTIL_H_
diff --git a/wifi/1.6/default/hidl_sync_util.cpp b/wifi/1.6/default/hidl_sync_util.cpp
deleted file mode 100644
index 358d95e..0000000
--- a/wifi/1.6/default/hidl_sync_util.cpp
+++ /dev/null
@@ -1,39 +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.
- */
-
-#include "hidl_sync_util.h"
-
-namespace {
-std::recursive_mutex g_mutex;
-}  // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-namespace hidl_sync_util {
-
-std::unique_lock<std::recursive_mutex> acquireGlobalLock() {
-    return std::unique_lock<std::recursive_mutex>{g_mutex};
-}
-
-}  // namespace hidl_sync_util
-}  // namespace implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.6/default/hidl_sync_util.h b/wifi/1.6/default/hidl_sync_util.h
deleted file mode 100644
index 2c1c37b..0000000
--- a/wifi/1.6/default/hidl_sync_util.h
+++ /dev/null
@@ -1,37 +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 HIDL_SYNC_UTIL_H_
-#define HIDL_SYNC_UTIL_H_
-
-#include <mutex>
-
-// Utility that provides a global lock to synchronize access between
-// the HIDL thread and the legacy HAL's event loop.
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-namespace hidl_sync_util {
-std::unique_lock<std::recursive_mutex> acquireGlobalLock();
-}  // namespace hidl_sync_util
-}  // namespace implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-#endif  // HIDL_SYNC_UTIL_H_
diff --git a/wifi/1.6/default/ringbuffer.cpp b/wifi/1.6/default/ringbuffer.cpp
deleted file mode 100644
index 981bf7b..0000000
--- a/wifi/1.6/default/ringbuffer.cpp
+++ /dev/null
@@ -1,64 +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.
- */
-
-#include <android-base/logging.h>
-
-#include "ringbuffer.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-
-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 implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.6/default/ringbuffer.h b/wifi/1.6/default/ringbuffer.h
deleted file mode 100644
index c6a1e4c..0000000
--- a/wifi/1.6/default/ringbuffer.h
+++ /dev/null
@@ -1,62 +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 RINGBUFFER_H_
-#define RINGBUFFER_H_
-
-#include <list>
-#include <vector>
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-
-/**
- * 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 implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // RINGBUFFER_H_
diff --git a/wifi/1.6/default/service.cpp b/wifi/1.6/default/service.cpp
deleted file mode 100644
index c874d8b..0000000
--- a/wifi/1.6/default/service.cpp
+++ /dev/null
@@ -1,71 +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.
- */
-
-#include <android-base/logging.h>
-#include <hidl/HidlLazyUtils.h>
-#include <hidl/HidlTransportSupport.h>
-#include <signal.h>
-#include <utils/Looper.h>
-#include <utils/StrongPointer.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 android::hardware::configureRpcThreadpool;
-using android::hardware::joinRpcThreadpool;
-using android::hardware::LazyServiceRegistrar;
-using android::hardware::wifi::V1_6::implementation::feature_flags::WifiFeatureFlags;
-using android::hardware::wifi::V1_6::implementation::legacy_hal::WifiLegacyHal;
-using android::hardware::wifi::V1_6::implementation::legacy_hal::WifiLegacyHalFactory;
-using android::hardware::wifi::V1_6::implementation::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...";
-
-    configureRpcThreadpool(1, true /* callerWillJoin */);
-
-    const auto iface_tool = std::make_shared<android::wifi_system::InterfaceTool>();
-    const auto legacy_hal_factory = std::make_shared<WifiLegacyHalFactory>(iface_tool);
-
-    // Setup hwbinder service
-    android::sp<android::hardware::wifi::V1_6::IWifi> service =
-            new android::hardware::wifi::V1_6::implementation::Wifi(
-                    iface_tool, legacy_hal_factory, std::make_shared<WifiModeController>(),
-                    std::make_shared<WifiFeatureFlags>());
-    if (kLazyService) {
-        auto registrar = LazyServiceRegistrar::getInstance();
-        CHECK_EQ(registrar.registerService(service), android::NO_ERROR)
-                << "Failed to register wifi HAL";
-    } else {
-        CHECK_EQ(service->registerAsService(), android::NO_ERROR) << "Failed to register wifi HAL";
-    }
-
-    joinRpcThreadpool();
-
-    LOG(INFO) << "Wifi Hal is terminating...";
-    return 0;
-}
diff --git a/wifi/1.6/default/tests/hidl_struct_util_unit_tests.cpp b/wifi/1.6/default/tests/hidl_struct_util_unit_tests.cpp
deleted file mode 100644
index 0dd0aa1..0000000
--- a/wifi/1.6/default/tests/hidl_struct_util_unit_tests.cpp
+++ /dev/null
@@ -1,486 +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.
- */
-
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <gmock/gmock.h>
-
-#undef NAN
-#include "hidl_struct_util.h"
-
-using testing::Test;
-
-namespace {
-constexpr uint32_t kMacId1 = 1;
-constexpr uint32_t kMacId2 = 2;
-constexpr uint32_t kIfaceChannel1 = 3;
-constexpr uint32_t kIfaceChannel2 = 5;
-constexpr char kIfaceName1[] = "wlan0";
-constexpr char kIfaceName2[] = "wlan1";
-}  // namespace
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-using namespace android::hardware::wifi::V1_0;
-using ::android::hardware::wifi::V1_6::WifiChannelWidthInMhz;
-
-class HidlStructUtilTest : public Test {};
-
-TEST_F(HidlStructUtilTest, CanConvertLegacyWifiMacInfosToHidlWithOneMac) {
-    std::vector<legacy_hal::WifiMacInfo> legacy_mac_infos;
-    legacy_hal::WifiMacInfo legacy_mac_info1 = {
-            .wlan_mac_id = kMacId1,
-            .mac_band = legacy_hal::WLAN_MAC_5_0_BAND | legacy_hal::WLAN_MAC_2_4_BAND};
-    legacy_hal::WifiIfaceInfo legacy_iface_info1 = {.name = kIfaceName1, .channel = kIfaceChannel1};
-    legacy_hal::WifiIfaceInfo legacy_iface_info2 = {.name = kIfaceName2, .channel = kIfaceChannel2};
-    legacy_mac_info1.iface_infos.push_back(legacy_iface_info1);
-    legacy_mac_info1.iface_infos.push_back(legacy_iface_info2);
-    legacy_mac_infos.push_back(legacy_mac_info1);
-
-    std::vector<V1_4::IWifiChipEventCallback::RadioModeInfo> hidl_radio_mode_infos;
-    ASSERT_TRUE(hidl_struct_util::convertLegacyWifiMacInfosToHidl(legacy_mac_infos,
-                                                                  &hidl_radio_mode_infos));
-
-    ASSERT_EQ(1u, hidl_radio_mode_infos.size());
-    auto hidl_radio_mode_info1 = hidl_radio_mode_infos[0];
-    EXPECT_EQ(legacy_mac_info1.wlan_mac_id, hidl_radio_mode_info1.radioId);
-    EXPECT_EQ(V1_4::WifiBand::BAND_24GHZ_5GHZ, hidl_radio_mode_info1.bandInfo);
-    ASSERT_EQ(2u, hidl_radio_mode_info1.ifaceInfos.size());
-    auto hidl_iface_info1 = hidl_radio_mode_info1.ifaceInfos[0];
-    EXPECT_EQ(legacy_iface_info1.name, hidl_iface_info1.name);
-    EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info1.channel), hidl_iface_info1.channel);
-    auto hidl_iface_info2 = hidl_radio_mode_info1.ifaceInfos[1];
-    EXPECT_EQ(legacy_iface_info2.name, hidl_iface_info2.name);
-    EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info2.channel), hidl_iface_info2.channel);
-}
-
-TEST_F(HidlStructUtilTest, CanConvertLegacyWifiMacInfosToHidlWithTwoMac) {
-    std::vector<legacy_hal::WifiMacInfo> legacy_mac_infos;
-    legacy_hal::WifiMacInfo legacy_mac_info1 = {.wlan_mac_id = kMacId1,
-                                                .mac_band = legacy_hal::WLAN_MAC_5_0_BAND};
-    legacy_hal::WifiIfaceInfo legacy_iface_info1 = {.name = kIfaceName1, .channel = kIfaceChannel1};
-    legacy_hal::WifiMacInfo legacy_mac_info2 = {.wlan_mac_id = kMacId2,
-                                                .mac_band = legacy_hal::WLAN_MAC_2_4_BAND};
-    legacy_hal::WifiIfaceInfo legacy_iface_info2 = {.name = kIfaceName2, .channel = kIfaceChannel2};
-    legacy_mac_info1.iface_infos.push_back(legacy_iface_info1);
-    legacy_mac_infos.push_back(legacy_mac_info1);
-    legacy_mac_info2.iface_infos.push_back(legacy_iface_info2);
-    legacy_mac_infos.push_back(legacy_mac_info2);
-
-    std::vector<V1_4::IWifiChipEventCallback::RadioModeInfo> hidl_radio_mode_infos;
-    ASSERT_TRUE(hidl_struct_util::convertLegacyWifiMacInfosToHidl(legacy_mac_infos,
-                                                                  &hidl_radio_mode_infos));
-
-    ASSERT_EQ(2u, hidl_radio_mode_infos.size());
-
-    // Find mac info 1.
-    const auto hidl_radio_mode_info1 =
-            std::find_if(hidl_radio_mode_infos.begin(), hidl_radio_mode_infos.end(),
-                         [&legacy_mac_info1](const V1_4::IWifiChipEventCallback::RadioModeInfo& x) {
-                             return x.radioId == legacy_mac_info1.wlan_mac_id;
-                         });
-    ASSERT_NE(hidl_radio_mode_infos.end(), hidl_radio_mode_info1);
-    EXPECT_EQ(V1_4::WifiBand::BAND_5GHZ, hidl_radio_mode_info1->bandInfo);
-    ASSERT_EQ(1u, hidl_radio_mode_info1->ifaceInfos.size());
-    auto hidl_iface_info1 = hidl_radio_mode_info1->ifaceInfos[0];
-    EXPECT_EQ(legacy_iface_info1.name, hidl_iface_info1.name);
-    EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info1.channel), hidl_iface_info1.channel);
-
-    // Find mac info 2.
-    const auto hidl_radio_mode_info2 =
-            std::find_if(hidl_radio_mode_infos.begin(), hidl_radio_mode_infos.end(),
-                         [&legacy_mac_info2](const V1_4::IWifiChipEventCallback::RadioModeInfo& x) {
-                             return x.radioId == legacy_mac_info2.wlan_mac_id;
-                         });
-    ASSERT_NE(hidl_radio_mode_infos.end(), hidl_radio_mode_info2);
-    EXPECT_EQ(V1_4::WifiBand::BAND_24GHZ, hidl_radio_mode_info2->bandInfo);
-    ASSERT_EQ(1u, hidl_radio_mode_info2->ifaceInfos.size());
-    auto hidl_iface_info2 = hidl_radio_mode_info2->ifaceInfos[0];
-    EXPECT_EQ(legacy_iface_info2.name, hidl_iface_info2.name);
-    EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info2.channel), hidl_iface_info2.channel);
-}
-
-TEST_F(HidlStructUtilTest, canConvertLegacyLinkLayerStatsToHidl) {
-    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);
-    }
-
-    V1_6::StaLinkLayerStats converted{};
-    hidl_struct_util::convertLegacyLinkLayerStatsToHidl(legacy_stats, &converted);
-    EXPECT_EQ(legacy_stats.iface.beacon_rx, converted.iface.V1_0.beaconRx);
-    EXPECT_EQ(legacy_stats.iface.rssi_mgmt, converted.iface.V1_0.avgRssiMgmt);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu,
-              converted.iface.V1_0.wmeBePktStats.rxMpdu);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu,
-              converted.iface.V1_0.wmeBePktStats.txMpdu);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost,
-              converted.iface.V1_0.wmeBePktStats.lostMpdu);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries,
-              converted.iface.V1_0.wmeBePktStats.retries);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_min,
-              converted.iface.wmeBeContentionTimeStats.contentionTimeMinInUsec);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_max,
-              converted.iface.wmeBeContentionTimeStats.contentionTimeMaxInUsec);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_avg,
-              converted.iface.wmeBeContentionTimeStats.contentionTimeAvgInUsec);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_num_samples,
-              converted.iface.wmeBeContentionTimeStats.contentionNumSamples);
-
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu,
-              converted.iface.V1_0.wmeBkPktStats.rxMpdu);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu,
-              converted.iface.V1_0.wmeBkPktStats.txMpdu);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost,
-              converted.iface.V1_0.wmeBkPktStats.lostMpdu);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries,
-              converted.iface.V1_0.wmeBkPktStats.retries);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_min,
-              converted.iface.wmeBkContentionTimeStats.contentionTimeMinInUsec);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_max,
-              converted.iface.wmeBkContentionTimeStats.contentionTimeMaxInUsec);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_avg,
-              converted.iface.wmeBkContentionTimeStats.contentionTimeAvgInUsec);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_num_samples,
-              converted.iface.wmeBkContentionTimeStats.contentionNumSamples);
-
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu,
-              converted.iface.V1_0.wmeViPktStats.rxMpdu);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu,
-              converted.iface.V1_0.wmeViPktStats.txMpdu);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost,
-              converted.iface.V1_0.wmeViPktStats.lostMpdu);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries,
-              converted.iface.V1_0.wmeViPktStats.retries);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_min,
-              converted.iface.wmeViContentionTimeStats.contentionTimeMinInUsec);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_max,
-              converted.iface.wmeViContentionTimeStats.contentionTimeMaxInUsec);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_avg,
-              converted.iface.wmeViContentionTimeStats.contentionTimeAvgInUsec);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_num_samples,
-              converted.iface.wmeViContentionTimeStats.contentionNumSamples);
-
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu,
-              converted.iface.V1_0.wmeVoPktStats.rxMpdu);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu,
-              converted.iface.V1_0.wmeVoPktStats.txMpdu);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost,
-              converted.iface.V1_0.wmeVoPktStats.lostMpdu);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries,
-              converted.iface.V1_0.wmeVoPktStats.retries);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_min,
-              converted.iface.wmeVoContentionTimeStats.contentionTimeMinInUsec);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_max,
-              converted.iface.wmeVoContentionTimeStats.contentionTimeMaxInUsec);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_avg,
-              converted.iface.wmeVoContentionTimeStats.contentionTimeAvgInUsec);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_num_samples,
-              converted.iface.wmeVoContentionTimeStats.contentionNumSamples);
-
-    EXPECT_EQ(legacy_stats.iface.info.time_slicing_duty_cycle_percent,
-              converted.iface.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, converted.radios[i].V1_0.onTimeInMs);
-        EXPECT_EQ(legacy_stats.radios[i].stats.tx_time, converted.radios[i].V1_0.txTimeInMs);
-        EXPECT_EQ(legacy_stats.radios[i].stats.rx_time, converted.radios[i].V1_0.rxTimeInMs);
-        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_scan,
-                  converted.radios[i].V1_0.onTimeInMsForScan);
-        EXPECT_EQ(legacy_stats.radios[i].tx_time_per_levels.size(),
-                  converted.radios[i].V1_0.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],
-                      converted.radios[i].V1_0.txTimeInMsPerLevel[j]);
-        }
-        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_nbd,
-                  converted.radios[i].onTimeInMsForNanScan);
-        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_gscan,
-                  converted.radios[i].onTimeInMsForBgScan);
-        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_roam_scan,
-                  converted.radios[i].onTimeInMsForRoamScan);
-        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_pno_scan,
-                  converted.radios[i].onTimeInMsForPnoScan);
-        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_hs20,
-                  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(WifiChannelInMhz(legacy_channel_st.channel.center_freq),
-                      converted.radios[i].channelStats[k].channel.centerFreq);
-            EXPECT_EQ(WifiChannelInMhz(legacy_channel_st.channel.center_freq0),
-                      converted.radios[i].channelStats[k].channel.centerFreq0);
-            EXPECT_EQ(WifiChannelInMhz(legacy_channel_st.channel.center_freq1),
-                      converted.radios[i].channelStats[k].channel.centerFreq1);
-            EXPECT_EQ(legacy_channel_st.cca_busy_time,
-                      converted.radios[i].channelStats[k].ccaBusyTimeInMs);
-            EXPECT_EQ(legacy_channel_st.on_time, converted.radios[i].channelStats[k].onTimeInMs);
-        }
-    }
-
-    EXPECT_EQ(legacy_stats.peers.size(), converted.iface.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.peers[i].staCount);
-        EXPECT_EQ(legacy_stats.peers[i].peer_info.bssload.chan_util,
-                  converted.iface.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.peers[i].rateStats[j].rateInfo.preamble);
-            EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rate.nss,
-                      (uint32_t)converted.iface.peers[i].rateStats[j].rateInfo.nss);
-            EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rate.bw,
-                      (uint32_t)converted.iface.peers[i].rateStats[j].rateInfo.bw);
-            EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rate.rateMcsIdx,
-                      converted.iface.peers[i].rateStats[j].rateInfo.rateMcsIdx);
-            EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].tx_mpdu,
-                      converted.iface.peers[i].rateStats[j].txMpdu);
-            EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rx_mpdu,
-                      converted.iface.peers[i].rateStats[j].rxMpdu);
-            EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].mpdu_lost,
-                      converted.iface.peers[i].rateStats[j].mpduLost);
-            EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].retries,
-                      converted.iface.peers[i].rateStats[j].retries);
-        }
-    }
-}
-
-TEST_F(HidlStructUtilTest, CanConvertLegacyFeaturesToHidl) {
-    using HidlChipCaps = V1_3::IWifiChip::ChipCapabilityMask;
-
-    uint32_t hidle_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(hidl_struct_util::convertLegacyFeaturesToHidlChipCapabilities(
-            legacy_feature_set, legacy_logger_feature_set, &hidle_caps));
-
-    EXPECT_EQ(HidlChipCaps::DEBUG_RING_BUFFER_VENDOR_DATA |
-                      HidlChipCaps::DEBUG_HOST_WAKE_REASON_STATS |
-                      HidlChipCaps::DEBUG_ERROR_ALERTS | HidlChipCaps::D2D_RTT |
-                      HidlChipCaps::SET_LATENCY_MODE | HidlChipCaps::DEBUG_MEMORY_DRIVER_DUMP,
-              hidle_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(hidl_struct_util::convertLegacyMacBandToHidlWifiBand(radio_configuration->band),
-                  radioCombination->radioConfigurations[i].bandInfo);
-        EXPECT_EQ(hidl_struct_util::convertLegacyAntennaConfigurationToHidl(
-                          radio_configuration->antenna_cfg),
-                  radioCombination->radioConfigurations[i].antennaMode);
-        radio_configuration++;
-    }
-}
-
-TEST_F(HidlStructUtilTest, canConvertLegacyRadioCombinationsMatrixToHidl) {
-    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);
-
-    V1_6::WifiRadioCombinationMatrix converted_matrix{};
-    hidl_struct_util::convertLegacyRadioCombinationsMatrixToHidl(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);
-}
-}  // namespace implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.6/default/tests/main.cpp b/wifi/1.6/default/tests/main.cpp
deleted file mode 100644
index 9aac837..0000000
--- a/wifi/1.6/default/tests/main.cpp
+++ /dev/null
@@ -1,28 +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.
- */
-
-#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/1.6/default/tests/mock_interface_tool.cpp b/wifi/1.6/default/tests/mock_interface_tool.cpp
deleted file mode 100644
index b99a164..0000000
--- a/wifi/1.6/default/tests/mock_interface_tool.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <gmock/gmock.h>
-
-#undef NAN  // This is weird, NAN is defined in bionic/libc/include/math.h:38
-#include "mock_interface_tool.h"
-
-namespace android {
-namespace wifi_system {
-
-MockInterfaceTool::MockInterfaceTool() {}
-
-}  // namespace wifi_system
-}  // namespace android
diff --git a/wifi/1.6/default/tests/mock_interface_tool.h b/wifi/1.6/default/tests/mock_interface_tool.h
deleted file mode 100644
index 7ce3992..0000000
--- a/wifi/1.6/default/tests/mock_interface_tool.h
+++ /dev/null
@@ -1,42 +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.
- */
-
-#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/1.6/default/tests/mock_wifi_feature_flags.cpp b/wifi/1.6/default/tests/mock_wifi_feature_flags.cpp
deleted file mode 100644
index d10b74c..0000000
--- a/wifi/1.6/default/tests/mock_wifi_feature_flags.cpp
+++ /dev/null
@@ -1,35 +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.
- */
-
-#include <gmock/gmock.h>
-
-#include "mock_wifi_feature_flags.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-namespace feature_flags {
-
-MockWifiFeatureFlags::MockWifiFeatureFlags() {}
-
-}  // namespace feature_flags
-}  // namespace implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.6/default/tests/mock_wifi_feature_flags.h b/wifi/1.6/default/tests/mock_wifi_feature_flags.h
deleted file mode 100644
index fbe1f7a..0000000
--- a/wifi/1.6/default/tests/mock_wifi_feature_flags.h
+++ /dev/null
@@ -1,47 +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 MOCK_WIFI_FEATURE_FLAGS_H_
-#define MOCK_WIFI_FEATURE_FLAGS_H_
-
-#include <gmock/gmock.h>
-#undef NAN  // This is weird, NAN is defined in bionic/libc/include/math.h:38
-
-#include "wifi_feature_flags.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-namespace feature_flags {
-
-class MockWifiFeatureFlags : public WifiFeatureFlags {
-  public:
-    MockWifiFeatureFlags();
-
-    MOCK_METHOD1(getChipModes, std::vector<V1_6::IWifiChip::ChipMode>(bool is_primary));
-    MOCK_METHOD0(isApMacRandomizationDisabled, bool());
-};
-
-}  // namespace feature_flags
-}  // namespace implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // MOCK_WIFI_FEATURE_FLAGS_H_
diff --git a/wifi/1.6/default/tests/mock_wifi_iface_util.cpp b/wifi/1.6/default/tests/mock_wifi_iface_util.cpp
deleted file mode 100644
index 24b16cb..0000000
--- a/wifi/1.6/default/tests/mock_wifi_iface_util.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <gmock/gmock.h>
-
-#undef NAN  // This is weird, NAN is defined in bionic/libc/include/math.h:38
-#include "mock_wifi_iface_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-namespace iface_util {
-
-MockWifiIfaceUtil::MockWifiIfaceUtil(const std::weak_ptr<wifi_system::InterfaceTool> iface_tool,
-                                     const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
-    : WifiIfaceUtil(iface_tool, legacy_hal) {}
-}  // namespace iface_util
-}  // namespace implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.6/default/tests/mock_wifi_iface_util.h b/wifi/1.6/default/tests/mock_wifi_iface_util.h
deleted file mode 100644
index 2701c36..0000000
--- a/wifi/1.6/default/tests/mock_wifi_iface_util.h
+++ /dev/null
@@ -1,50 +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.
- */
-
-#ifndef MOCK_WIFI_IFACE_UTIL_H_
-#define MOCK_WIFI_IFACE_UTIL_H_
-
-#include <gmock/gmock.h>
-
-#include "wifi_iface_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-namespace iface_util {
-
-class MockWifiIfaceUtil : public WifiIfaceUtil {
-  public:
-    MockWifiIfaceUtil(const std::weak_ptr<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&, 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 implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // MOCK_WIFI_IFACE_UTIL_H_
diff --git a/wifi/1.6/default/tests/mock_wifi_legacy_hal.cpp b/wifi/1.6/default/tests/mock_wifi_legacy_hal.cpp
deleted file mode 100644
index 2c55861..0000000
--- a/wifi/1.6/default/tests/mock_wifi_legacy_hal.cpp
+++ /dev/null
@@ -1,39 +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.
- */
-
-#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_legacy_hal.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-namespace legacy_hal {
-
-MockWifiLegacyHal::MockWifiLegacyHal(const std::weak_ptr<wifi_system::InterfaceTool> iface_tool,
-                                     const wifi_hal_fn& fn, bool is_primary)
-    : WifiLegacyHal(iface_tool, fn, is_primary) {}
-}  // namespace legacy_hal
-}  // namespace implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.6/default/tests/mock_wifi_legacy_hal.h b/wifi/1.6/default/tests/mock_wifi_legacy_hal.h
deleted file mode 100644
index 85dbf0f..0000000
--- a/wifi/1.6/default/tests/mock_wifi_legacy_hal.h
+++ /dev/null
@@ -1,71 +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 MOCK_WIFI_LEGACY_HAL_H_
-#define MOCK_WIFI_LEGACY_HAL_H_
-
-#include <gmock/gmock.h>
-
-#include "wifi_legacy_hal.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-namespace legacy_hal {
-
-class MockWifiLegacyHal : public WifiLegacyHal {
-  public:
-    MockWifiLegacyHal(const std::weak_ptr<wifi_system::InterfaceTool> iface_tool,
-                      const wifi_hal_fn& fn, bool is_primary);
-    MOCK_METHOD0(initialize, wifi_error());
-    MOCK_METHOD0(start, wifi_error());
-    MOCK_METHOD2(stop,
-                 wifi_error(std::unique_lock<std::recursive_mutex>*, 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 implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // MOCK_WIFI_LEGACY_HAL_H_
diff --git a/wifi/1.6/default/tests/mock_wifi_mode_controller.cpp b/wifi/1.6/default/tests/mock_wifi_mode_controller.cpp
deleted file mode 100644
index 446f829..0000000
--- a/wifi/1.6/default/tests/mock_wifi_mode_controller.cpp
+++ /dev/null
@@ -1,37 +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.
- */
-
-#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 android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-namespace mode_controller {
-
-MockWifiModeController::MockWifiModeController() : WifiModeController() {}
-}  // namespace mode_controller
-}  // namespace implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.6/default/tests/mock_wifi_mode_controller.h b/wifi/1.6/default/tests/mock_wifi_mode_controller.h
deleted file mode 100644
index addcc81..0000000
--- a/wifi/1.6/default/tests/mock_wifi_mode_controller.h
+++ /dev/null
@@ -1,46 +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 MOCK_WIFI_MODE_CONTROLLER_H_
-#define MOCK_WIFI_MODE_CONTROLLER_H_
-
-#include <gmock/gmock.h>
-
-#include "wifi_mode_controller.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-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 implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // MOCK_WIFI_MODE_CONTROLLER_H_
diff --git a/wifi/1.6/default/tests/ringbuffer_unit_tests.cpp b/wifi/1.6/default/tests/ringbuffer_unit_tests.cpp
deleted file mode 100644
index eb86194..0000000
--- a/wifi/1.6/default/tests/ringbuffer_unit_tests.cpp
+++ /dev/null
@@ -1,97 +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.
- */
-
-#include <gmock/gmock.h>
-
-#include "ringbuffer.h"
-
-using testing::Return;
-using testing::Test;
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-
-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 implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.6/default/tests/runtests.sh b/wifi/1.6/default/tests/runtests.sh
deleted file mode 100755
index 6bce3ef..0000000
--- a/wifi/1.6/default/tests/runtests.sh
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/env bash
-
-# 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.
-
-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@1.0-service-tests
-adb root
-adb sync data
-adb shell /data/nativetest64/vendor/android.hardware.wifi@1.0-service-tests/android.hardware.wifi@1.0-service-tests
diff --git a/wifi/1.6/default/tests/wifi_chip_unit_tests.cpp b/wifi/1.6/default/tests/wifi_chip_unit_tests.cpp
deleted file mode 100644
index 81117c5..0000000
--- a/wifi/1.6/default/tests/wifi_chip_unit_tests.cpp
+++ /dev/null
@@ -1,864 +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.
- */
-
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <cutils/properties.h>
-#include <gmock/gmock.h>
-
-#undef NAN  // This is weird, NAN is defined in bionic/libc/include/math.h:38
-#include "wifi_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 {
-using android::hardware::wifi::V1_0::ChipId;
-
-constexpr ChipId kFakeChipId = 5;
-}  // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-
-class WifiChipTest : public Test {
-  protected:
-    void setupV1IfaceCombination() {
-        // clang-format off
-        const hidl_vec<IWifiChip::ChipConcurrencyCombination> combinationsSta = {
-            {{{{IfaceConcurrencyType::STA}, 1}, {{IfaceConcurrencyType::P2P}, 1}}}
-        };
-        const hidl_vec<IWifiChip::ChipConcurrencyCombination> combinationsAp = {
-            {{{{IfaceConcurrencyType::AP}, 1}}}
-        };
-        const std::vector<V1_6::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
-        const hidl_vec<IWifiChip::ChipConcurrencyCombination> combinationsSta = {
-            {{{{IfaceConcurrencyType::STA}, 1},
-              {{IfaceConcurrencyType::P2P, IfaceConcurrencyType::NAN}, 1}}}
-        };
-        const hidl_vec<IWifiChip::ChipConcurrencyCombination> combinationsAp = {
-            {{{{IfaceConcurrencyType::AP}, 1}}}
-        };
-        const std::vector<V1_6::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
-        const hidl_vec<IWifiChip::ChipConcurrencyCombination> combinationsSta = {
-            {{{{IfaceConcurrencyType::STA}, 1},
-              {{IfaceConcurrencyType::P2P, IfaceConcurrencyType::NAN}, 1}}}
-        };
-        const std::vector<V1_6::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
-        const hidl_vec<IWifiChip::ChipConcurrencyCombination> combinations = {
-            {{{{IfaceConcurrencyType::STA}, 1}, {{IfaceConcurrencyType::AP}, 1}}},
-            {{{{IfaceConcurrencyType::STA}, 1},
-              {{IfaceConcurrencyType::P2P, IfaceConcurrencyType::NAN}, 1}}}
-        };
-        const std::vector<V1_6::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
-        const hidl_vec<IWifiChip::ChipConcurrencyCombination> combinations = {
-            {{{{IfaceConcurrencyType::STA}, 1},
-              {{IfaceConcurrencyType::P2P, IfaceConcurrencyType::NAN}, 1}}}
-        };
-        const std::vector<V1_6::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
-        const hidl_vec<IWifiChip::ChipConcurrencyCombination> combinations = {
-            {{{{IfaceConcurrencyType::STA}, 3}, {{IfaceConcurrencyType::AP}, 1}}}
-        };
-        const std::vector<V1_6::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) {
-        chip_->getAvailableModes_1_6([num_modes](const WifiStatus& status,
-                                                 const std::vector<WifiChip::ChipMode>& modes) {
-            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-            // 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.
-        ChipModeId mode_id = UINT32_MAX;
-        chip_->getAvailableModes_1_6([&mode_id, &type](
-                                             const WifiStatus& status,
-                                             const std::vector<WifiChip::ChipMode>& modes) {
-            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-            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(UINT32_MAX, mode_id);
-
-        chip_->configureChip(mode_id, [](const WifiStatus& status) {
-            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-        });
-    }
-
-    // Returns an empty string on error.
-    std::string createIface(const IfaceType& type) {
-        std::string iface_name;
-        if (type == IfaceType::AP) {
-            chip_->createApIface(
-                    [&iface_name](const WifiStatus& status, const sp<V1_0::IWifiApIface>& iface) {
-                        if (WifiStatusCode::SUCCESS == status.code) {
-                            ASSERT_NE(iface.get(), nullptr);
-                            iface->getName([&iface_name](const WifiStatus& status,
-                                                         const hidl_string& name) {
-                                ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-                                iface_name = name.c_str();
-                            });
-                        }
-                    });
-        } else if (type == IfaceType::NAN) {
-            chip_->createNanIface(
-                    [&iface_name](const WifiStatus& status,
-                                  const sp<android::hardware::wifi::V1_0::IWifiNanIface>& iface) {
-                        if (WifiStatusCode::SUCCESS == status.code) {
-                            ASSERT_NE(iface.get(), nullptr);
-                            iface->getName([&iface_name](const WifiStatus& status,
-                                                         const hidl_string& name) {
-                                ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-                                iface_name = name.c_str();
-                            });
-                        }
-                    });
-        } else if (type == IfaceType::P2P) {
-            chip_->createP2pIface(
-                    [&iface_name](const WifiStatus& status, const sp<IWifiP2pIface>& iface) {
-                        if (WifiStatusCode::SUCCESS == status.code) {
-                            ASSERT_NE(iface.get(), nullptr);
-                            iface->getName([&iface_name](const WifiStatus& status,
-                                                         const hidl_string& name) {
-                                ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-                                iface_name = name.c_str();
-                            });
-                        }
-                    });
-        } else if (type == IfaceType::STA) {
-            chip_->createStaIface(
-                    [&iface_name](const WifiStatus& status, const sp<V1_0::IWifiStaIface>& iface) {
-                        if (WifiStatusCode::SUCCESS == status.code) {
-                            ASSERT_NE(iface.get(), nullptr);
-                            iface->getName([&iface_name](const WifiStatus& status,
-                                                         const hidl_string& name) {
-                                ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-                                iface_name = name.c_str();
-                            });
-                        }
-                    });
-        }
-        return iface_name;
-    }
-
-    void removeIface(const IfaceType& type, const std::string& iface_name) {
-        if (type == IfaceType::AP) {
-            chip_->removeApIface(iface_name, [](const WifiStatus& status) {
-                ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-            });
-        } else if (type == IfaceType::NAN) {
-            chip_->removeNanIface(iface_name, [](const WifiStatus& status) {
-                ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-            });
-        } else if (type == IfaceType::P2P) {
-            chip_->removeP2pIface(iface_name, [](const WifiStatus& status) {
-                ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-            });
-        } else if (type == IfaceType::STA) {
-            chip_->removeStaIface(iface_name, [](const WifiStatus& status) {
-                ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-            });
-        }
-    }
-
-    bool createRttController() {
-        bool success = false;
-        chip_->createRttController_1_6(
-                NULL, [&success](const WifiStatus& status, const sp<IWifiRttController>& rtt) {
-                    if (WifiStatusCode::SUCCESS == status.code) {
-                        ASSERT_NE(rtt.get(), nullptr);
-                        success = true;
-                    }
-                });
-        return success;
-    }
-
-    static void subsystemRestartHandler(const std::string& /*error*/) {}
-
-    sp<WifiChip> chip_;
-    ChipId chip_id_ = kFakeChipId;
-    legacy_hal::wifi_hal_fn fake_func_table_;
-    std::shared_ptr<NiceMock<wifi_system::MockInterfaceTool>> iface_tool_{
-            new NiceMock<wifi_system::MockInterfaceTool>};
-    std::shared_ptr<NiceMock<legacy_hal::MockWifiLegacyHal>> legacy_hal_{
-            new NiceMock<legacy_hal::MockWifiLegacyHal>(iface_tool_, 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_ = new WifiChip(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(2u);
-    }
-};
-
-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).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).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).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).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).empty());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateStaNan_AfterP2pRemove_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    const auto p2p_iface_name = createIface(IfaceType::P2P);
-    ASSERT_FALSE(p2p_iface_name.empty());
-    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
-
-    // After removing P2P iface, NAN iface creation should succeed.
-    removeIface(IfaceType::P2P, p2p_iface_name);
-    ASSERT_FALSE(createIface(IfaceType::NAN).empty());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateStaP2p_AfterNanRemove_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    const auto nan_iface_name = createIface(IfaceType::NAN);
-    ASSERT_FALSE(nan_iface_name.empty());
-    ASSERT_TRUE(createIface(IfaceType::P2P).empty());
-
-    // After removing NAN iface, P2P iface creation should succeed.
-    removeIface(IfaceType::NAN, 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).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);
-    const auto 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));
-    chip_->selectTxPowerScenario_1_2(
-            V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF,
-            [](const WifiStatus& status) { ASSERT_EQ(WifiStatusCode::SUCCESS, status.code); });
-}
-
-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));
-    chip_->selectTxPowerScenario_1_2(
-            V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF,
-            [](const WifiStatus& status) { ASSERT_EQ(WifiStatusCode::SUCCESS, status.code); });
-}
-
-////////// 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).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);
-    const auto sta_iface_name = createIface(IfaceType::STA);
-    ASSERT_FALSE(sta_iface_name.empty());
-    const auto 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).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).empty());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaNan_AfterP2pRemove_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    const auto p2p_iface_name = createIface(IfaceType::P2P);
-    ASSERT_FALSE(p2p_iface_name.empty());
-    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
-
-    // After removing P2P iface, NAN iface creation should succeed.
-    removeIface(IfaceType::P2P, p2p_iface_name);
-    ASSERT_FALSE(createIface(IfaceType::NAN).empty());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaP2p_AfterNanRemove_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    const auto nan_iface_name = createIface(IfaceType::NAN);
-    ASSERT_FALSE(nan_iface_name.empty());
-    ASSERT_TRUE(createIface(IfaceType::P2P).empty());
-
-    // After removing NAN iface, P2P iface creation should succeed.
-    removeIface(IfaceType::NAN, 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).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());
-    const auto p2p_iface_name = createIface(IfaceType::P2P);
-    ASSERT_FALSE(p2p_iface_name.empty());
-    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
-
-    // After removing P2P iface, NAN iface creation should succeed.
-    removeIface(IfaceType::P2P, p2p_iface_name);
-    ASSERT_FALSE(createIface(IfaceType::NAN).empty());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, StaMode_CreateStaP2p_AfterNanRemove_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    const auto nan_iface_name = createIface(IfaceType::NAN);
-    ASSERT_FALSE(nan_iface_name.empty());
-    ASSERT_TRUE(createIface(IfaceType::P2P).empty());
-
-    // After removing NAN iface, P2P iface creation should succeed.
-    removeIface(IfaceType::NAN, nan_iface_name);
-    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaAp_EnsureDifferentIfaceNames) {
-    findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
-    const auto sta_iface_name = createIface(IfaceType::STA);
-    const auto 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));
-    chip_->selectTxPowerScenario_1_2(
-            V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF,
-            [](const WifiStatus& status) { ASSERT_EQ(WifiStatusCode::SUCCESS, status.code); });
-}
-
-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));
-    chip_->selectTxPowerScenario_1_2(
-            V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF,
-            [](const WifiStatus& status) { ASSERT_EQ(WifiStatusCode::SUCCESS, status.code); });
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, InvalidateAndRemoveNanOnStaRemove) {
-    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
-    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
-
-    // Create NAN iface
-    ASSERT_EQ(createIface(IfaceType::NAN), "wlan0");
-
-    // We should have 1 nan iface.
-    chip_->getNanIfaceNames([](const WifiStatus& status, const hidl_vec<hidl_string>& iface_names) {
-        ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-        ASSERT_EQ(iface_names.size(), 1u);
-        ASSERT_EQ(iface_names[0], "wlan0");
-    });
-    // Retrieve the exact iface object.
-    sp<android::hardware::wifi::V1_0::IWifiNanIface> nan_iface;
-    chip_->getNanIface("wlan0",
-                       [&nan_iface](const WifiStatus& status,
-                                    const sp<android::hardware::wifi::V1_0::IWifiNanIface>& iface) {
-                           ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-                           ASSERT_NE(iface.get(), nullptr);
-                           nan_iface = iface;
-                       });
-
-    // Remove the STA iface.
-    removeIface(IfaceType::STA, "wlan0");
-    // We should have 0 nan iface now.
-    chip_->getNanIfaceNames([](const WifiStatus& status, const hidl_vec<hidl_string>& iface_names) {
-        ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-        ASSERT_EQ(iface_names.size(), 0u);
-    });
-    // Any operation on the nan iface object should return error now.
-    nan_iface->getName([](const WifiStatus& status, const std::string& /* iface_name */) {
-        ASSERT_EQ(WifiStatusCode::ERROR_WIFI_IFACE_INVALID, status.code);
-    });
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, InvalidateAndRemoveRttControllerOnStaRemove) {
-    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
-    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
-
-    // Create RTT controller
-    sp<IWifiRttController> rtt_controller;
-    chip_->createRttController_1_6(
-            NULL, [&rtt_controller](const WifiStatus& status, const sp<IWifiRttController>& rtt) {
-                if (WifiStatusCode::SUCCESS == status.code) {
-                    ASSERT_NE(rtt.get(), nullptr);
-                    rtt_controller = rtt;
-                }
-            });
-
-    // Remove the STA iface.
-    removeIface(IfaceType::STA, "wlan0");
-
-    // Any operation on the rtt controller object should return error now.
-    rtt_controller->getBoundIface([](const WifiStatus& status, const sp<IWifiIface>& /* iface */) {
-        ASSERT_EQ(WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID, status.code);
-    });
-}
-
-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), "wlan0");
-    removeIface(IfaceType::NAN, "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), "aware0");
-
-    EXPECT_CALL(*iface_util_, setUpState("aware0", false)).WillOnce(testing::Return(true));
-    removeIface(IfaceType::NAN, "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 implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.6/default/tests/wifi_iface_util_unit_tests.cpp b/wifi/1.6/default/tests/wifi_iface_util_unit_tests.cpp
deleted file mode 100644
index cc9a334..0000000
--- a/wifi/1.6/default/tests/wifi_iface_util_unit_tests.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <gmock/gmock.h>
-
-#undef NAN
-#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 android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-namespace iface_util {
-class WifiIfaceUtilTest : public Test {
-  protected:
-    std::shared_ptr<NiceMock<wifi_system::MockInterfaceTool>> iface_tool_{
-            new NiceMock<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 implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.6/default/tests/wifi_nan_iface_unit_tests.cpp b/wifi/1.6/default/tests/wifi_nan_iface_unit_tests.cpp
deleted file mode 100644
index 8a5ddcd..0000000
--- a/wifi/1.6/default/tests/wifi_nan_iface_unit_tests.cpp
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <cutils/properties.h>
-#include <gmock/gmock.h>
-
-#undef NAN  // This is weird, NAN is defined in bionic/libc/include/math.h:38
-#include "wifi_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 android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-
-using android::hardware::wifi::V1_2::NanDataPathConfirmInd;
-
-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 MockNanIfaceEventCallback : public V1_5::IWifiNanIfaceEventCallback {
-  public:
-    MockNanIfaceEventCallback() = default;
-
-    MOCK_METHOD3(notifyCapabilitiesResponse,
-                 Return<void>(uint16_t, const WifiNanStatus&,
-                              const android::hardware::wifi::V1_0::NanCapabilities&));
-    MOCK_METHOD2(notifyEnableResponse, Return<void>(uint16_t, const WifiNanStatus&));
-    MOCK_METHOD2(notifyConfigResponse, Return<void>(uint16_t, const WifiNanStatus&));
-    MOCK_METHOD2(notifyDisableResponse, Return<void>(uint16_t, const WifiNanStatus&));
-    MOCK_METHOD3(notifyStartPublishResponse, Return<void>(uint16_t, const WifiNanStatus&, uint8_t));
-    MOCK_METHOD2(notifyStopPublishResponse, Return<void>(uint16_t, const WifiNanStatus&));
-    MOCK_METHOD3(notifyStartSubscribeResponse,
-                 Return<void>(uint16_t, const WifiNanStatus&, uint8_t));
-    MOCK_METHOD2(notifyStopSubscribeResponse, Return<void>(uint16_t, const WifiNanStatus&));
-    MOCK_METHOD2(notifyTransmitFollowupResponse, Return<void>(uint16_t, const WifiNanStatus&));
-    MOCK_METHOD2(notifyCreateDataInterfaceResponse, Return<void>(uint16_t, const WifiNanStatus&));
-    MOCK_METHOD2(notifyDeleteDataInterfaceResponse, Return<void>(uint16_t, const WifiNanStatus&));
-    MOCK_METHOD3(notifyInitiateDataPathResponse,
-                 Return<void>(uint16_t, const WifiNanStatus&, uint32_t));
-    MOCK_METHOD2(notifyRespondToDataPathIndicationResponse,
-                 Return<void>(uint16_t, const WifiNanStatus&));
-    MOCK_METHOD2(notifyTerminateDataPathResponse, Return<void>(uint16_t, const WifiNanStatus&));
-    MOCK_METHOD1(eventClusterEvent, Return<void>(const NanClusterEventInd&));
-    MOCK_METHOD1(eventDisabled, Return<void>(const WifiNanStatus&));
-    MOCK_METHOD2(eventPublishTerminated, Return<void>(uint8_t, const WifiNanStatus&));
-    MOCK_METHOD2(eventSubscribeTerminated, Return<void>(uint8_t, const WifiNanStatus&));
-    MOCK_METHOD1(eventMatch, Return<void>(const V1_0::NanMatchInd&));
-    MOCK_METHOD1(eventMatch_1_6, Return<void>(const NanMatchInd&));
-    MOCK_METHOD2(eventMatchExpired, Return<void>(uint8_t, uint32_t));
-    MOCK_METHOD1(eventFollowupReceived, Return<void>(const NanFollowupReceivedInd&));
-    MOCK_METHOD2(eventTransmitFollowup, Return<void>(uint16_t, const WifiNanStatus&));
-    MOCK_METHOD1(eventDataPathRequest, Return<void>(const NanDataPathRequestInd&));
-    MOCK_METHOD1(eventDataPathConfirm,
-                 Return<void>(const android::hardware::wifi::V1_0::NanDataPathConfirmInd&));
-    MOCK_METHOD1(eventDataPathTerminated, Return<void>(uint32_t));
-    MOCK_METHOD1(eventDataPathConfirm_1_2,
-                 Return<void>(const android::hardware::wifi::V1_2::NanDataPathConfirmInd&));
-    MOCK_METHOD1(eventDataPathConfirm_1_6, Return<void>(const NanDataPathConfirmInd&));
-    MOCK_METHOD1(eventDataPathScheduleUpdate,
-                 Return<void>(const android::hardware::wifi::V1_2::NanDataPathScheduleUpdateInd&));
-    MOCK_METHOD1(eventDataPathScheduleUpdate_1_6,
-                 Return<void>(const NanDataPathScheduleUpdateInd&));
-    MOCK_METHOD3(notifyCapabilitiesResponse_1_5,
-                 Return<void>(uint16_t, const WifiNanStatus&, const V1_5::NanCapabilities&));
-};
-
-class WifiNanIfaceTest : public Test {
-  protected:
-    legacy_hal::wifi_hal_fn fake_func_table_;
-    std::shared_ptr<NiceMock<wifi_system::MockInterfaceTool>> iface_tool_{
-            new NiceMock<wifi_system::MockInterfaceTool>};
-    std::shared_ptr<NiceMock<legacy_hal::MockWifiLegacyHal>> legacy_hal_{
-            new NiceMock<legacy_hal::MockWifiLegacyHal>(iface_tool_, 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) {
-    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)));
-    sp<WifiNanIface> nan_iface = new WifiNanIface(kIfaceName, false, legacy_hal_, iface_util_);
-
-    // Register a mock nan event callback.
-    sp<NiceMock<MockNanIfaceEventCallback>> mock_event_callback{
-            new NiceMock<MockNanIfaceEventCallback>};
-    nan_iface->registerEventCallback(mock_event_callback, [](const WifiStatus& status) {
-        ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-    });
-    // Ensure that the eventDisabled() function in mock callback will be
-    // invoked.
-    WifiNanStatus expected_nan_status = {NanStatusType::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 implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.6/default/wifi.cpp b/wifi/1.6/default/wifi.cpp
deleted file mode 100644
index c302ce2..0000000
--- a/wifi/1.6/default/wifi.cpp
+++ /dev/null
@@ -1,294 +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.
- */
-
-#include <android-base/logging.h>
-
-#include "hidl_return_util.h"
-#include "wifi.h"
-#include "wifi_status_util.h"
-
-namespace {
-// Starting Chip ID, will be assigned to primary chip
-static constexpr android::hardware::wifi::V1_0::ChipId kPrimaryChipId = 0;
-}  // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-using hidl_return_util::validateAndCall;
-using hidl_return_util::validateAndCallWithLock;
-
-Wifi::Wifi(const std::shared_ptr<wifi_system::InterfaceTool> iface_tool,
-           const std::shared_ptr<legacy_hal::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;
-}
-
-Return<void> Wifi::registerEventCallback(const sp<V1_0::IWifiEventCallback>& event_callback,
-                                         registerEventCallback_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN,
-                           &Wifi::registerEventCallbackInternal, hidl_status_cb, event_callback);
-}
-
-Return<void> Wifi::registerEventCallback_1_5(const sp<V1_5::IWifiEventCallback>& event_callback,
-                                             registerEventCallback_1_5_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN,
-                           &Wifi::registerEventCallbackInternal_1_5, hidl_status_cb,
-                           event_callback);
-}
-
-Return<bool> Wifi::isStarted() {
-    return run_state_ != RunState::STOPPED;
-}
-
-Return<void> Wifi::start(start_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN, &Wifi::startInternal,
-                           hidl_status_cb);
-}
-
-Return<void> Wifi::stop(stop_cb hidl_status_cb) {
-    return validateAndCallWithLock(this, WifiStatusCode::ERROR_UNKNOWN, &Wifi::stopInternal,
-                                   hidl_status_cb);
-}
-
-Return<void> Wifi::getChipIds(getChipIds_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN, &Wifi::getChipIdsInternal,
-                           hidl_status_cb);
-}
-
-Return<void> Wifi::getChip(ChipId chip_id, getChip_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN, &Wifi::getChipInternal,
-                           hidl_status_cb, chip_id);
-}
-
-Return<void> Wifi::debug(const hidl_handle& handle, const hidl_vec<hidl_string>&) {
-    LOG(INFO) << "-----------Debug is called----------------";
-    if (chips_.size() == 0) {
-        return Void();
-    }
-
-    for (sp<WifiChip> chip : chips_) {
-        if (!chip.get()) continue;
-
-        chip->debug(handle, {});
-    }
-    return Void();
-}
-
-WifiStatus Wifi::registerEventCallbackInternal(
-        const sp<V1_0::IWifiEventCallback>& event_callback __unused) {
-    // Deprecated support for this callback.
-    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
-}
-
-WifiStatus Wifi::registerEventCallbackInternal_1_5(
-        const sp<V1_5::IWifiEventCallback>& event_callback) {
-    if (!event_cb_handler_.addCallback(event_callback)) {
-        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-    }
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus Wifi::startInternal() {
-    if (run_state_ == RunState::STARTED) {
-        return createWifiStatus(WifiStatusCode::SUCCESS);
-    } else if (run_state_ == RunState::STOPPING) {
-        return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE, "HAL is stopping");
-    }
-    WifiStatus wifi_status = initializeModeControllerAndLegacyHal();
-    if (wifi_status.code == WifiStatusCode::SUCCESS) {
-        // Register the callback for subsystem restart
-        const auto& on_subsystem_restart_callback = [this](const std::string& error) {
-            WifiStatus wifi_status = createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, error);
-            for (const auto& callback : event_cb_handler_.getCallbacks()) {
-                LOG(INFO) << "Attempting to invoke onSubsystemRestart "
-                             "callback";
-                if (!callback->onSubsystemRestart(wifi_status).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.
-        android::hardware::wifi::V1_0::ChipId chipId = kPrimaryChipId;
-        for (auto& hal : legacy_hals_) {
-            chips_.push_back(
-                    new WifiChip(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()) {
-            if (!callback->onFailure(wifi_status).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;
-}
-
-WifiStatus Wifi::stopInternal(
-        /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock) {
-    if (run_state_ == RunState::STOPPED) {
-        return createWifiStatus(WifiStatusCode::SUCCESS);
-    } 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.clear();
-        }
-    }
-    chips_.clear();
-    WifiStatus wifi_status = stopLegacyHalAndDeinitializeModeController(lock);
-    if (wifi_status.code == WifiStatusCode::SUCCESS) {
-        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()) {
-            if (!callback->onFailure(wifi_status).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<WifiStatus, std::vector<ChipId>> Wifi::getChipIdsInternal() {
-    std::vector<ChipId> chip_ids;
-
-    for (auto& chip : chips_) {
-        ChipId chip_id = getChipIdFromWifiChip(chip);
-        if (chip_id != UINT32_MAX) chip_ids.emplace_back(chip_id);
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), std::move(chip_ids)};
-}
-
-std::pair<WifiStatus, sp<V1_4::IWifiChip>> Wifi::getChipInternal(ChipId chip_id) {
-    for (auto& chip : chips_) {
-        ChipId cand_id = getChipIdFromWifiChip(chip);
-        if ((cand_id != UINT32_MAX) && (cand_id == chip_id))
-            return {createWifiStatus(WifiStatusCode::SUCCESS), chip};
-    }
-
-    return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
-}
-
-WifiStatus 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 createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus Wifi::stopLegacyHalAndDeinitializeModeController(
-        /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock) {
-    legacy_hal::wifi_error legacy_status = legacy_hal::WIFI_SUCCESS;
-    int index = 0;
-
-    run_state_ = RunState::STOPPING;
-    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 createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-ChipId Wifi::getChipIdFromWifiChip(sp<WifiChip>& chip) {
-    ChipId chip_id = UINT32_MAX;
-    if (chip.get()) {
-        chip->getId([&](WifiStatus status, uint32_t id) {
-            if (status.code == WifiStatusCode::SUCCESS) {
-                chip_id = id;
-            }
-        });
-    }
-
-    return chip_id;
-}
-}  // namespace implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.6/default/wifi.h b/wifi/1.6/default/wifi.h
deleted file mode 100644
index 435358e..0000000
--- a/wifi/1.6/default/wifi.h
+++ /dev/null
@@ -1,105 +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 WIFI_H_
-#define WIFI_H_
-
-// HACK: NAN is a macro defined in math.h, which can be included in various
-// headers. This wifi HAL uses an enum called NAN, which does not compile when
-// the macro is defined. Undefine NAN to work around it.
-#undef NAN
-#include <android/hardware/wifi/1.6/IWifi.h>
-
-#include <android-base/macros.h>
-#include <utils/Looper.h>
-#include <functional>
-
-#include "hidl_callback_util.h"
-#include "wifi_chip.h"
-#include "wifi_feature_flags.h"
-#include "wifi_legacy_hal.h"
-#include "wifi_legacy_hal_factory.h"
-#include "wifi_mode_controller.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-
-/**
- * Root HIDL interface object used to control the Wifi HAL.
- */
-class Wifi : public V1_6::IWifi {
-  public:
-    Wifi(const std::shared_ptr<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();
-
-    // HIDL methods exposed.
-    Return<void> registerEventCallback(const sp<V1_0::IWifiEventCallback>& event_callback,
-                                       registerEventCallback_cb hidl_status_cb) override;
-    Return<void> registerEventCallback_1_5(const sp<V1_5::IWifiEventCallback>& event_callback,
-                                           registerEventCallback_1_5_cb hidl_status_cb) override;
-    Return<bool> isStarted() override;
-    Return<void> start(start_cb hidl_status_cb) override;
-    Return<void> stop(stop_cb hidl_status_cb) override;
-    Return<void> getChipIds(getChipIds_cb hidl_status_cb) override;
-    Return<void> getChip(ChipId chip_id, getChip_cb hidl_status_cb) override;
-    Return<void> debug(const hidl_handle& handle, const hidl_vec<hidl_string>& options) override;
-
-  private:
-    enum class RunState { STOPPED, STARTED, STOPPING };
-
-    // Corresponding worker functions for the HIDL methods.
-    WifiStatus registerEventCallbackInternal(
-            const sp<V1_0::IWifiEventCallback>& event_callback __unused);
-    WifiStatus registerEventCallbackInternal_1_5(
-            const sp<V1_5::IWifiEventCallback>& event_callback);
-    WifiStatus startInternal();
-    WifiStatus stopInternal(std::unique_lock<std::recursive_mutex>* lock);
-    std::pair<WifiStatus, std::vector<ChipId>> getChipIdsInternal();
-    std::pair<WifiStatus, sp<V1_4::IWifiChip>> getChipInternal(ChipId chip_id);
-
-    WifiStatus initializeModeControllerAndLegacyHal();
-    WifiStatus stopLegacyHalAndDeinitializeModeController(
-            std::unique_lock<std::recursive_mutex>* lock);
-    ChipId getChipIdFromWifiChip(sp<WifiChip>& chip);
-
-    // Instance is created in this root level |IWifi| HIDL interface object
-    // and shared with all the child HIDL interface objects.
-    std::shared_ptr<wifi_system::InterfaceTool> iface_tool_;
-    std::shared_ptr<legacy_hal::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<sp<WifiChip>> chips_;
-    hidl_callback_util::HidlCallbackHandler<V1_5::IWifiEventCallback> event_cb_handler_;
-
-    DISALLOW_COPY_AND_ASSIGN(Wifi);
-};
-
-}  // namespace implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_H_
diff --git a/wifi/1.6/default/wifi_ap_iface.cpp b/wifi/1.6/default/wifi_ap_iface.cpp
deleted file mode 100644
index b2957db..0000000
--- a/wifi/1.6/default/wifi_ap_iface.cpp
+++ /dev/null
@@ -1,204 +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.
- */
-
-#include <android-base/logging.h>
-
-#include "hidl_return_util.h"
-#include "hidl_struct_util.h"
-#include "wifi_ap_iface.h"
-#include "wifi_status_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-using hidl_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());
-}
-
-Return<void> WifiApIface::getName(getName_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiApIface::getNameInternal, hidl_status_cb);
-}
-
-Return<void> WifiApIface::getType(getType_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiApIface::getTypeInternal, hidl_status_cb);
-}
-
-Return<void> WifiApIface::setCountryCode(const hidl_array<int8_t, 2>& code,
-                                         setCountryCode_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiApIface::setCountryCodeInternal, hidl_status_cb, code);
-}
-
-Return<void> WifiApIface::getValidFrequenciesForBand(V1_0::WifiBand band,
-                                                     getValidFrequenciesForBand_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiApIface::getValidFrequenciesForBandInternal, hidl_status_cb, band);
-}
-
-Return<void> WifiApIface::setMacAddress(const hidl_array<uint8_t, 6>& mac,
-                                        setMacAddress_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiApIface::setMacAddressInternal, hidl_status_cb, mac);
-}
-
-Return<void> WifiApIface::getFactoryMacAddress(getFactoryMacAddress_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiApIface::getFactoryMacAddressInternal, hidl_status_cb,
-                           instances_.size() > 0 ? instances_[0] : ifname_);
-}
-
-Return<void> WifiApIface::resetToFactoryMacAddress(resetToFactoryMacAddress_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiApIface::resetToFactoryMacAddressInternal, hidl_status_cb);
-}
-
-Return<void> WifiApIface::getBridgedInstances(getBridgedInstances_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiApIface::getBridgedInstancesInternal, hidl_status_cb);
-}
-
-std::pair<WifiStatus, std::string> WifiApIface::getNameInternal() {
-    return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
-}
-
-std::pair<WifiStatus, IfaceType> WifiApIface::getTypeInternal() {
-    return {createWifiStatus(WifiStatusCode::SUCCESS), IfaceType::AP};
-}
-
-WifiStatus WifiApIface::setCountryCodeInternal(const std::array<int8_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<WifiStatus, std::vector<WifiChannelInMhz>>
-WifiApIface::getValidFrequenciesForBandInternal(V1_0::WifiBand band) {
-    static_assert(sizeof(WifiChannelInMhz) == sizeof(uint32_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_,
-            hidl_struct_util::convertHidlWifiBandToLegacy(band));
-    return {createWifiStatusFromLegacyError(legacy_status), valid_frequencies};
-}
-
-WifiStatus 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 createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-std::pair<WifiStatus, std::array<uint8_t, 6>> 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 {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), mac};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), mac};
-}
-
-WifiStatus WifiApIface::resetToFactoryMacAddressInternal() {
-    std::pair<WifiStatus, std::array<uint8_t, 6>> getMacResult;
-    if (instances_.size() == 2) {
-        for (auto const& intf : instances_) {
-            getMacResult = getFactoryMacAddressInternal(intf);
-            LOG(DEBUG) << "Reset MAC to factory MAC on " << intf;
-            if (getMacResult.first.code != WifiStatusCode::SUCCESS ||
-                !iface_util_.lock()->setMacAddress(intf, getMacResult.second)) {
-                return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-            }
-        }
-        // It needs to set mac address for bridged interface, otherwise the mac
-        // address of the bridged interface will be changed after one of the
-        // instance down. Thus we are generating a random MAC address for the
-        // bridged interface even if we got the request to reset the Factory
-        // MAC. Since the bridged interface is an internal interface for the
-        // operation of bpf and others networking operation.
-        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.first.code != WifiStatusCode::SUCCESS ||
-            !iface_util_.lock()->setMacAddress(ifname_, getMacResult.second)) {
-            return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-        }
-    }
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-std::pair<WifiStatus, std::vector<hidl_string>> WifiApIface::getBridgedInstancesInternal() {
-    std::vector<hidl_string> instances;
-    for (const auto& instance_name : instances_) {
-        instances.push_back(instance_name);
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), instances};
-}
-}  // namespace implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.6/default/wifi_ap_iface.h b/wifi/1.6/default/wifi_ap_iface.h
deleted file mode 100644
index d1c0642..0000000
--- a/wifi/1.6/default/wifi_ap_iface.h
+++ /dev/null
@@ -1,89 +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 WIFI_AP_IFACE_H_
-#define WIFI_AP_IFACE_H_
-
-#include <android-base/macros.h>
-#include <android/hardware/wifi/1.5/IWifiApIface.h>
-
-#include "wifi_iface_util.h"
-#include "wifi_legacy_hal.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-using namespace android::hardware::wifi::V1_0;
-
-/**
- * HIDL interface object used to control a AP Iface instance.
- */
-class WifiApIface : public V1_5::IWifiApIface {
-  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);
-
-    // HIDL methods exposed.
-    Return<void> getName(getName_cb hidl_status_cb) override;
-    Return<void> getType(getType_cb hidl_status_cb) override;
-    Return<void> setCountryCode(const hidl_array<int8_t, 2>& code,
-                                setCountryCode_cb hidl_status_cb) override;
-    Return<void> getValidFrequenciesForBand(V1_0::WifiBand band,
-                                            getValidFrequenciesForBand_cb hidl_status_cb) override;
-    Return<void> setMacAddress(const hidl_array<uint8_t, 6>& mac,
-                               setMacAddress_cb hidl_status_cb) override;
-    Return<void> getFactoryMacAddress(getFactoryMacAddress_cb hidl_status_cb) override;
-    Return<void> resetToFactoryMacAddress(resetToFactoryMacAddress_cb hidl_status_cb) override;
-
-    Return<void> getBridgedInstances(getBridgedInstances_cb hidl_status_cb) override;
-
-  private:
-    // Corresponding worker functions for the HIDL methods.
-    std::pair<WifiStatus, std::string> getNameInternal();
-    std::pair<WifiStatus, IfaceType> getTypeInternal();
-    WifiStatus setCountryCodeInternal(const std::array<int8_t, 2>& code);
-    std::pair<WifiStatus, std::vector<WifiChannelInMhz>> getValidFrequenciesForBandInternal(
-            V1_0::WifiBand band);
-    WifiStatus setMacAddressInternal(const std::array<uint8_t, 6>& mac);
-    std::pair<WifiStatus, std::array<uint8_t, 6>> getFactoryMacAddressInternal(
-            const std::string& ifaceName);
-    WifiStatus resetToFactoryMacAddressInternal();
-    std::pair<WifiStatus, std::vector<hidl_string>> 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 implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_AP_IFACE_H_
diff --git a/wifi/1.6/default/wifi_chip.cpp b/wifi/1.6/default/wifi_chip.cpp
deleted file mode 100644
index 920beb8..0000000
--- a/wifi/1.6/default/wifi_chip.cpp
+++ /dev/null
@@ -1,2062 +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.
- */
-
-#include <fcntl.h>
-
-#include <android-base/logging.h>
-#include <android-base/unique_fd.h>
-#include <cutils/properties.h>
-#include <net/if.h>
-#include <sys/stat.h>
-#include <sys/sysmacros.h>
-
-#include "hidl_return_util.h"
-#include "hidl_struct_util.h"
-#include "wifi_chip.h"
-#include "wifi_status_util.h"
-
-#define P2P_MGMT_DEVICE_PREFIX "p2p-dev-"
-
-namespace {
-using android::sp;
-using android::base::unique_fd;
-using android::hardware::hidl_string;
-using android::hardware::hidl_vec;
-using android::hardware::wifi::V1_0::ChipModeId;
-using android::hardware::wifi::V1_0::IfaceType;
-using android::hardware::wifi::V1_0::IWifiChip;
-
-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<sp<Iface>>& ifaces, sp<Iface> iface) {
-    iface->invalidate();
-    ifaces.erase(std::remove(ifaces.begin(), ifaces.end(), iface), ifaces.end());
-}
-
-template <typename Iface>
-void invalidateAndClearAll(std::vector<sp<Iface>>& ifaces) {
-    for (const auto& iface : ifaces) {
-        iface->invalidate();
-    }
-    ifaces.clear();
-}
-
-template <typename Iface>
-std::vector<hidl_string> getNames(std::vector<sp<Iface>>& ifaces) {
-    std::vector<hidl_string> names;
-    for (const auto& iface : ifaces) {
-        names.emplace_back(iface->getName());
-    }
-    return names;
-}
-
-template <typename Iface>
-sp<Iface> findUsingName(std::vector<sp<Iface>>& ifaces, const std::string& name) {
-    std::vector<hidl_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 conditions:
-// 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 android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-using hidl_return_util::validateAndCall;
-using hidl_return_util::validateAndCallWithLock;
-
-WifiChip::WifiChip(ChipId chip_id, bool is_primary,
-                   const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
-                   const std::weak_ptr<mode_controller::WifiModeController> mode_controller,
-                   const std::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);
-}
-
-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;
-}
-
-bool WifiChip::isValid() {
-    return is_valid_;
-}
-
-std::set<sp<V1_4::IWifiChipEventCallback>> WifiChip::getEventCallbacks() {
-    return event_cb_handler_.getCallbacks();
-}
-
-Return<void> WifiChip::getId(getId_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, &WifiChip::getIdInternal,
-                           hidl_status_cb);
-}
-
-// Deprecated support for this callback
-Return<void> WifiChip::registerEventCallback(const sp<V1_0::IWifiChipEventCallback>& event_callback,
-                                             registerEventCallback_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::registerEventCallbackInternal, hidl_status_cb,
-                           event_callback);
-}
-
-Return<void> WifiChip::getCapabilities(getCapabilities_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getCapabilitiesInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::getAvailableModes(getAvailableModes_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getAvailableModesInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::configureChip(ChipModeId mode_id, configureChip_cb hidl_status_cb) {
-    return validateAndCallWithLock(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                                   &WifiChip::configureChipInternal, hidl_status_cb, mode_id);
-}
-
-Return<void> WifiChip::getMode(getMode_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getModeInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::requestChipDebugInfo(requestChipDebugInfo_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::requestChipDebugInfoInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::requestDriverDebugDump(requestDriverDebugDump_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::requestDriverDebugDumpInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::requestFirmwareDebugDump(requestFirmwareDebugDump_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::requestFirmwareDebugDumpInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::createApIface(createApIface_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::createApIfaceInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::createBridgedApIface(createBridgedApIface_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::createBridgedApIfaceInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::getApIfaceNames(getApIfaceNames_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getApIfaceNamesInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::getApIface(const hidl_string& ifname, getApIface_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getApIfaceInternal, hidl_status_cb, ifname);
-}
-
-Return<void> WifiChip::removeApIface(const hidl_string& ifname, removeApIface_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::removeApIfaceInternal, hidl_status_cb, ifname);
-}
-
-Return<void> WifiChip::removeIfaceInstanceFromBridgedApIface(
-        const hidl_string& ifname, const hidl_string& ifInstanceName,
-        removeIfaceInstanceFromBridgedApIface_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::removeIfaceInstanceFromBridgedApIfaceInternal, hidl_status_cb,
-                           ifname, ifInstanceName);
-}
-
-Return<void> WifiChip::createNanIface(createNanIface_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::createNanIfaceInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::getNanIfaceNames(getNanIfaceNames_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getNanIfaceNamesInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::getNanIface(const hidl_string& ifname, getNanIface_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getNanIfaceInternal, hidl_status_cb, ifname);
-}
-
-Return<void> WifiChip::removeNanIface(const hidl_string& ifname, removeNanIface_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::removeNanIfaceInternal, hidl_status_cb, ifname);
-}
-
-Return<void> WifiChip::createP2pIface(createP2pIface_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::createP2pIfaceInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::getP2pIfaceNames(getP2pIfaceNames_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getP2pIfaceNamesInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::getP2pIface(const hidl_string& ifname, getP2pIface_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getP2pIfaceInternal, hidl_status_cb, ifname);
-}
-
-Return<void> WifiChip::removeP2pIface(const hidl_string& ifname, removeP2pIface_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::removeP2pIfaceInternal, hidl_status_cb, ifname);
-}
-
-Return<void> WifiChip::createStaIface(createStaIface_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::createStaIfaceInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::getStaIfaceNames(getStaIfaceNames_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getStaIfaceNamesInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::getStaIface(const hidl_string& ifname, getStaIface_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getStaIfaceInternal, hidl_status_cb, ifname);
-}
-
-Return<void> WifiChip::removeStaIface(const hidl_string& ifname, removeStaIface_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::removeStaIfaceInternal, hidl_status_cb, ifname);
-}
-
-Return<void> WifiChip::createRttController(const sp<IWifiIface>& bound_iface,
-                                           createRttController_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::createRttControllerInternal, hidl_status_cb, bound_iface);
-}
-
-Return<void> WifiChip::getDebugRingBuffersStatus(getDebugRingBuffersStatus_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getDebugRingBuffersStatusInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::startLoggingToDebugRingBuffer(
-        const hidl_string& ring_name, WifiDebugRingBufferVerboseLevel verbose_level,
-        uint32_t max_interval_in_sec, uint32_t min_data_size_in_bytes,
-        startLoggingToDebugRingBuffer_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::startLoggingToDebugRingBufferInternal, hidl_status_cb,
-                           ring_name, verbose_level, max_interval_in_sec, min_data_size_in_bytes);
-}
-
-Return<void> WifiChip::forceDumpToDebugRingBuffer(const hidl_string& ring_name,
-                                                  forceDumpToDebugRingBuffer_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::forceDumpToDebugRingBufferInternal, hidl_status_cb,
-                           ring_name);
-}
-
-Return<void> WifiChip::flushRingBufferToFile(flushRingBufferToFile_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::flushRingBufferToFileInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::stopLoggingToDebugRingBuffer(
-        stopLoggingToDebugRingBuffer_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::stopLoggingToDebugRingBufferInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::getDebugHostWakeReasonStats(getDebugHostWakeReasonStats_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getDebugHostWakeReasonStatsInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::enableDebugErrorAlerts(bool enable,
-                                              enableDebugErrorAlerts_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::enableDebugErrorAlertsInternal, hidl_status_cb, enable);
-}
-
-Return<void> WifiChip::selectTxPowerScenario(V1_1::IWifiChip::TxPowerScenario scenario,
-                                             selectTxPowerScenario_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::selectTxPowerScenarioInternal, hidl_status_cb, scenario);
-}
-
-Return<void> WifiChip::resetTxPowerScenario(resetTxPowerScenario_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::resetTxPowerScenarioInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::setLatencyMode(LatencyMode mode, setLatencyMode_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::setLatencyModeInternal, hidl_status_cb, mode);
-}
-
-Return<void> WifiChip::registerEventCallback_1_2(
-        const sp<V1_2::IWifiChipEventCallback>& event_callback,
-        registerEventCallback_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::registerEventCallbackInternal_1_2, hidl_status_cb,
-                           event_callback);
-}
-
-Return<void> WifiChip::selectTxPowerScenario_1_2(TxPowerScenario scenario,
-                                                 selectTxPowerScenario_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::selectTxPowerScenarioInternal_1_2, hidl_status_cb, scenario);
-}
-
-Return<void> WifiChip::getCapabilities_1_3(getCapabilities_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getCapabilitiesInternal_1_3, hidl_status_cb);
-}
-
-Return<void> WifiChip::getCapabilities_1_5(getCapabilities_1_5_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getCapabilitiesInternal_1_5, hidl_status_cb);
-}
-
-Return<void> WifiChip::debug(const hidl_handle& handle, const hidl_vec<hidl_string>&) {
-    if (handle != nullptr && handle->numFds >= 1) {
-        {
-            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.
-        int fd = handle->data[0];
-        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 occured in cpio function";
-        }
-        fsync(fd);
-    } else {
-        LOG(ERROR) << "File handle error";
-    }
-    return Void();
-}
-
-Return<void> WifiChip::createRttController_1_4(const sp<IWifiIface>& bound_iface,
-                                               createRttController_1_4_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::createRttControllerInternal_1_4, hidl_status_cb, bound_iface);
-}
-
-Return<void> WifiChip::registerEventCallback_1_4(
-        const sp<V1_4::IWifiChipEventCallback>& event_callback,
-        registerEventCallback_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::registerEventCallbackInternal_1_4, hidl_status_cb,
-                           event_callback);
-}
-
-Return<void> WifiChip::setMultiStaPrimaryConnection(
-        const hidl_string& ifname, setMultiStaPrimaryConnection_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::setMultiStaPrimaryConnectionInternal, hidl_status_cb, ifname);
-}
-
-Return<void> WifiChip::setMultiStaUseCase(MultiStaUseCase use_case,
-                                          setMultiStaUseCase_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::setMultiStaUseCaseInternal, hidl_status_cb, use_case);
-}
-
-Return<void> WifiChip::setCoexUnsafeChannels(const hidl_vec<CoexUnsafeChannel>& unsafeChannels,
-                                             hidl_bitfield<CoexRestriction> restrictions,
-                                             setCoexUnsafeChannels_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::setCoexUnsafeChannelsInternal, hidl_status_cb, unsafeChannels,
-                           restrictions);
-}
-
-Return<void> WifiChip::setCountryCode(const hidl_array<int8_t, 2>& code,
-                                      setCountryCode_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiChip::setCountryCodeInternal, hidl_status_cb, code);
-}
-
-Return<void> WifiChip::getUsableChannels(
-        WifiBand band, hidl_bitfield<V1_5::WifiIfaceMode> ifaceModeMask,
-        hidl_bitfield<V1_5::IWifiChip::UsableChannelFilter> filterMask,
-        getUsableChannels_cb _hidl_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getUsableChannelsInternal, _hidl_cb, band, ifaceModeMask,
-                           filterMask);
-}
-
-Return<void> WifiChip::triggerSubsystemRestart(triggerSubsystemRestart_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::triggerSubsystemRestartInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::createRttController_1_6(const sp<IWifiIface>& bound_iface,
-                                               createRttController_1_6_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::createRttControllerInternal_1_6, hidl_status_cb, bound_iface);
-}
-
-Return<void> WifiChip::getUsableChannels_1_6(
-        WifiBand band, hidl_bitfield<V1_5::WifiIfaceMode> ifaceModeMask,
-        hidl_bitfield<V1_6::IWifiChip::UsableChannelFilter> filterMask,
-        getUsableChannels_1_6_cb _hidl_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getUsableChannelsInternal_1_6, _hidl_cb, band, ifaceModeMask,
-                           filterMask);
-}
-
-Return<void> WifiChip::getSupportedRadioCombinationsMatrix(
-        getSupportedRadioCombinationsMatrix_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getSupportedRadioCombinationsMatrixInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::getAvailableModes_1_6(getAvailableModes_1_6_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getAvailableModesInternal_1_6, hidl_status_cb);
-}
-
-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, 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<WifiStatus, ChipId> WifiChip::getIdInternal() {
-    return {createWifiStatus(WifiStatusCode::SUCCESS), chip_id_};
-}
-
-WifiStatus WifiChip::registerEventCallbackInternal(
-        const sp<V1_0::IWifiChipEventCallback>& /* event_callback */) {
-    // Deprecated support for this callback.
-    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
-}
-
-std::pair<WifiStatus, uint32_t> WifiChip::getCapabilitiesInternal() {
-    // Deprecated support for this callback.
-    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), 0};
-}
-
-std::pair<WifiStatus, std::vector<V1_0::IWifiChip::ChipMode>>
-WifiChip::getAvailableModesInternal() {
-    // Deprecated support -- use getAvailableModes_1_6 for more granular concurrency combinations.
-    std::vector<V1_0::IWifiChip::ChipMode> modes_1_0 = {};
-    for (const auto& mode_1_6 : modes_) {
-        std::vector<V1_0::IWifiChip::ChipIfaceCombination> combos_1_0;
-        for (const auto& combo_1_6 : mode_1_6.availableCombinations) {
-            std::vector<V1_0::IWifiChip::ChipIfaceCombinationLimit> limits_1_0;
-            for (const auto& limit_1_6 : combo_1_6.limits) {
-                std::vector<IfaceType> types_1_0;
-                for (IfaceConcurrencyType type_1_6 : limit_1_6.types) {
-                    switch (type_1_6) {
-                        case IfaceConcurrencyType::STA:
-                            types_1_0.push_back(IfaceType::STA);
-                            break;
-                        case IfaceConcurrencyType::AP:
-                            types_1_0.push_back(IfaceType::AP);
-                            break;
-                        case IfaceConcurrencyType::AP_BRIDGED:
-                            // Ignore AP_BRIDGED
-                            break;
-                        case IfaceConcurrencyType::P2P:
-                            types_1_0.push_back(IfaceType::P2P);
-                            break;
-                        case IfaceConcurrencyType::NAN:
-                            types_1_0.push_back(IfaceType::NAN);
-                            break;
-                    }
-                }
-                if (types_1_0.empty()) {
-                    continue;
-                }
-                V1_0::IWifiChip::ChipIfaceCombinationLimit limit_1_0;
-                limit_1_0.types = hidl_vec(types_1_0);
-                limit_1_0.maxIfaces = limit_1_6.maxIfaces;
-                limits_1_0.push_back(limit_1_0);
-            }
-            if (limits_1_0.empty()) {
-                continue;
-            }
-            V1_0::IWifiChip::ChipIfaceCombination combo_1_0;
-            combo_1_0.limits = hidl_vec(limits_1_0);
-            combos_1_0.push_back(combo_1_0);
-        }
-        if (combos_1_0.empty()) {
-            continue;
-        }
-        V1_0::IWifiChip::ChipMode mode_1_0;
-        mode_1_0.id = mode_1_6.id;
-        mode_1_0.availableCombinations = hidl_vec(combos_1_0);
-        modes_1_0.push_back(mode_1_0);
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), modes_1_0};
-}
-
-WifiStatus WifiChip::configureChipInternal(
-        /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock, ChipModeId 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 createWifiStatus(WifiStatusCode::SUCCESS);
-    }
-    WifiStatus status = handleChipConfiguration(lock, mode_id);
-    if (status.code != WifiStatusCode::SUCCESS) {
-        for (const auto& callback : event_cb_handler_.getCallbacks()) {
-            if (!callback->onChipReconfigureFailure(status).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<WifiStatus, uint32_t> WifiChip::getModeInternal() {
-    if (!isValidModeId(current_mode_id_)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), current_mode_id_};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), current_mode_id_};
-}
-
-std::pair<WifiStatus, V1_4::IWifiChip::ChipDebugInfo> WifiChip::requestChipDebugInfoInternal() {
-    V1_4::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);
-        WifiStatus status =
-                createWifiStatusFromLegacyError(legacy_status, "failed to get driver version");
-        return {status, result};
-    }
-    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);
-        WifiStatus status =
-                createWifiStatusFromLegacyError(legacy_status, "failed to get firmware version");
-        return {status, result};
-    }
-    result.firmwareDescription = firmware_desc.c_str();
-
-    return {createWifiStatus(WifiStatusCode::SUCCESS), result};
-}
-
-std::pair<WifiStatus, std::vector<uint8_t>> 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 {createWifiStatusFromLegacyError(legacy_status), std::vector<uint8_t>()};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), driver_dump};
-}
-
-std::pair<WifiStatus, std::vector<uint8_t>> 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 {createWifiStatusFromLegacyError(legacy_status), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), firmware_dump};
-}
-
-WifiStatus WifiChip::createVirtualApInterface(const std::string& apVirtIf) {
-    legacy_hal::wifi_error legacy_status;
-    legacy_status = legacy_hal_.lock()->createVirtualInterface(
-            apVirtIf, hidl_struct_util::convertHidlIfaceTypeToLegacy(IfaceType::AP));
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        LOG(ERROR) << "Failed to add interface: " << apVirtIf << " "
-                   << legacyErrorToString(legacy_status);
-        return createWifiStatusFromLegacyError(legacy_status);
-    }
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-sp<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;
-        }
-    }
-    sp<WifiApIface> iface = new 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<WifiStatus, sp<V1_5::IWifiApIface>> WifiChip::createApIfaceInternal() {
-    if (!canCurrentModeSupportConcurrencyTypeWithCurrentTypes(IfaceConcurrencyType::AP)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
-    }
-    std::string ifname = allocateApIfaceName();
-    WifiStatus status = createVirtualApInterface(ifname);
-    if (status.code != WifiStatusCode::SUCCESS) {
-        return {status, {}};
-    }
-    sp<WifiApIface> iface = newWifiApIface(ifname);
-    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
-}
-
-std::pair<WifiStatus, sp<V1_5::IWifiApIface>> WifiChip::createBridgedApIfaceInternal() {
-    if (!canCurrentModeSupportConcurrencyTypeWithCurrentTypes(IfaceConcurrencyType::AP_BRIDGED)) {
-        return {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 {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
-    }
-    std::string br_ifname = kApBridgeIfacePrefix + ap_instances[0];
-    for (int i = 0; i < 2; i++) {
-        WifiStatus status = createVirtualApInterface(ap_instances[i]);
-        if (status.code != WifiStatusCode::SUCCESS) {
-            if (i != 0) {  // The failure happened when creating second virtual
-                           // iface.
-                legacy_hal_.lock()->deleteVirtualInterface(
-                        ap_instances.front());  // Remove the first virtual iface.
-            }
-            return {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();
-        deleteApIface(br_ifname);
-        return {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();
-            deleteApIface(br_ifname);
-            return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
-        }
-    }
-    sp<WifiApIface> iface = newWifiApIface(br_ifname);
-    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
-}
-
-std::pair<WifiStatus, std::vector<hidl_string>> WifiChip::getApIfaceNamesInternal() {
-    if (ap_ifaces_.empty()) {
-        return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(ap_ifaces_)};
-}
-
-std::pair<WifiStatus, sp<V1_5::IWifiApIface>> WifiChip::getApIfaceInternal(
-        const std::string& ifname) {
-    const auto iface = findUsingName(ap_ifaces_, ifname);
-    if (!iface.get()) {
-        return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
-}
-
-WifiStatus 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);
-    deleteApIface(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 createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus 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 createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-std::pair<WifiStatus, sp<V1_4::IWifiNanIface>> WifiChip::createNanIfaceInternal() {
-    if (!canCurrentModeSupportConcurrencyTypeWithCurrentTypes(IfaceConcurrencyType::NAN)) {
-        return {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;
-    }
-    sp<WifiNanIface> iface = new WifiNanIface(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, ifname).isOk()) {
-            LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
-        }
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
-}
-
-std::pair<WifiStatus, std::vector<hidl_string>> WifiChip::getNanIfaceNamesInternal() {
-    if (nan_ifaces_.empty()) {
-        return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(nan_ifaces_)};
-}
-
-std::pair<WifiStatus, sp<V1_4::IWifiNanIface>> WifiChip::getNanIfaceInternal(
-        const std::string& ifname) {
-    const auto iface = findUsingName(nan_ifaces_, ifname);
-    if (!iface.get()) {
-        return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
-}
-
-WifiStatus 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, ifname).isOk()) {
-            LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
-        }
-    }
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-std::pair<WifiStatus, sp<IWifiP2pIface>> WifiChip::createP2pIfaceInternal() {
-    if (!canCurrentModeSupportConcurrencyTypeWithCurrentTypes(IfaceConcurrencyType::P2P)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
-    }
-    std::string ifname = getPredefinedP2pIfaceName();
-    sp<WifiP2pIface> iface = new 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 {createWifiStatus(WifiStatusCode::SUCCESS), iface};
-}
-
-std::pair<WifiStatus, std::vector<hidl_string>> WifiChip::getP2pIfaceNamesInternal() {
-    if (p2p_ifaces_.empty()) {
-        return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(p2p_ifaces_)};
-}
-
-std::pair<WifiStatus, sp<IWifiP2pIface>> WifiChip::getP2pIfaceInternal(const std::string& ifname) {
-    const auto iface = findUsingName(p2p_ifaces_, ifname);
-    if (!iface.get()) {
-        return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
-}
-
-WifiStatus 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 createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-std::pair<WifiStatus, sp<V1_6::IWifiStaIface>> WifiChip::createStaIfaceInternal() {
-    if (!canCurrentModeSupportConcurrencyTypeWithCurrentTypes(IfaceConcurrencyType::STA)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
-    }
-    std::string ifname = allocateStaIfaceName();
-    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->createVirtualInterface(
-            ifname, hidl_struct_util::convertHidlIfaceTypeToLegacy(IfaceType::STA));
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        LOG(ERROR) << "Failed to add interface: " << ifname << " "
-                   << legacyErrorToString(legacy_status);
-        return {createWifiStatusFromLegacyError(legacy_status), {}};
-    }
-    sp<WifiStaIface> iface = new 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 {createWifiStatus(WifiStatusCode::SUCCESS), iface};
-}
-
-std::pair<WifiStatus, std::vector<hidl_string>> WifiChip::getStaIfaceNamesInternal() {
-    if (sta_ifaces_.empty()) {
-        return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(sta_ifaces_)};
-}
-
-std::pair<WifiStatus, sp<V1_6::IWifiStaIface>> WifiChip::getStaIfaceInternal(
-        const std::string& ifname) {
-    const auto iface = findUsingName(sta_ifaces_, ifname);
-    if (!iface.get()) {
-        return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
-}
-
-WifiStatus 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 createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-std::pair<WifiStatus, sp<V1_0::IWifiRttController>> WifiChip::createRttControllerInternal(
-        const sp<IWifiIface>& /*bound_iface*/) {
-    LOG(ERROR) << "createRttController is not supported on this HAL";
-    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
-}
-
-std::pair<WifiStatus, std::vector<WifiDebugRingBufferStatus>>
-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 {createWifiStatusFromLegacyError(legacy_status), {}};
-    }
-    std::vector<WifiDebugRingBufferStatus> hidl_ring_buffer_status_vec;
-    if (!hidl_struct_util::convertLegacyVectorOfDebugRingBufferStatusToHidl(
-                legacy_ring_buffer_status_vec, &hidl_ring_buffer_status_vec)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_ring_buffer_status_vec};
-}
-
-WifiStatus WifiChip::startLoggingToDebugRingBufferInternal(
-        const hidl_string& ring_name, WifiDebugRingBufferVerboseLevel verbose_level,
-        uint32_t max_interval_in_sec, uint32_t min_data_size_in_bytes) {
-    WifiStatus status = registerDebugRingBufferCallback();
-    if (status.code != WifiStatusCode::SUCCESS) {
-        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);
-}
-
-WifiStatus WifiChip::forceDumpToDebugRingBufferInternal(const hidl_string& ring_name) {
-    WifiStatus status = registerDebugRingBufferCallback();
-    if (status.code != WifiStatusCode::SUCCESS) {
-        return status;
-    }
-    legacy_hal::wifi_error legacy_status =
-            legacy_hal_.lock()->getRingBufferData(getFirstActiveWlanIfaceName(), ring_name);
-
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiChip::flushRingBufferToFileInternal() {
-    if (!writeRingbufferFilesInternal()) {
-        LOG(ERROR) << "Error writing files to flash";
-        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-    }
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus 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<WifiStatus, WifiDebugHostWakeReasonStats>
-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 {createWifiStatusFromLegacyError(legacy_status), {}};
-    }
-    WifiDebugHostWakeReasonStats hidl_stats;
-    if (!hidl_struct_util::convertLegacyWakeReasonStatsToHidl(legacy_stats, &hidl_stats)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_stats};
-}
-
-WifiStatus WifiChip::enableDebugErrorAlertsInternal(bool enable) {
-    legacy_hal::wifi_error legacy_status;
-    if (enable) {
-        android::wp<WifiChip> weak_ptr_this(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.promote();
-            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);
-}
-
-WifiStatus WifiChip::selectTxPowerScenarioInternal(V1_1::IWifiChip::TxPowerScenario scenario) {
-    auto legacy_status = legacy_hal_.lock()->selectTxPowerScenario(
-            getFirstActiveWlanIfaceName(),
-            hidl_struct_util::convertHidlTxPowerScenarioToLegacy(scenario));
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiChip::resetTxPowerScenarioInternal() {
-    auto legacy_status = legacy_hal_.lock()->resetTxPowerScenario(getFirstActiveWlanIfaceName());
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiChip::setLatencyModeInternal(LatencyMode mode) {
-    auto legacy_status = legacy_hal_.lock()->setLatencyMode(
-            getFirstActiveWlanIfaceName(), hidl_struct_util::convertHidlLatencyModeToLegacy(mode));
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiChip::registerEventCallbackInternal_1_2(
-        const sp<V1_2::IWifiChipEventCallback>& /* event_callback */) {
-    // Deprecated support for this callback.
-    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
-}
-
-WifiStatus WifiChip::selectTxPowerScenarioInternal_1_2(TxPowerScenario scenario) {
-    auto legacy_status = legacy_hal_.lock()->selectTxPowerScenario(
-            getFirstActiveWlanIfaceName(),
-            hidl_struct_util::convertHidlTxPowerScenarioToLegacy_1_2(scenario));
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, uint32_t> WifiChip::getCapabilitiesInternal_1_3() {
-    // Deprecated support for this callback.
-    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), 0};
-}
-
-std::pair<WifiStatus, uint32_t> WifiChip::getCapabilitiesInternal_1_5() {
-    legacy_hal::wifi_error legacy_status;
-    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 {createWifiStatusFromLegacyError(legacy_status), 0};
-    }
-    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 hidl_caps;
-    if (!hidl_struct_util::convertLegacyFeaturesToHidlChipCapabilities(
-                legacy_feature_set, legacy_logger_feature_set, &hidl_caps)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), 0};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
-}
-
-std::pair<WifiStatus, sp<V1_4::IWifiRttController>> WifiChip::createRttControllerInternal_1_4(
-        const sp<IWifiIface>& /*bound_iface*/) {
-    LOG(ERROR) << "createRttController_1_4 is not supported on this HAL";
-    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
-}
-
-WifiStatus WifiChip::registerEventCallbackInternal_1_4(
-        const sp<V1_4::IWifiChipEventCallback>& event_callback) {
-    if (!event_cb_handler_.addCallback(event_callback)) {
-        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-    }
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus WifiChip::setMultiStaPrimaryConnectionInternal(const std::string& ifname) {
-    auto legacy_status = legacy_hal_.lock()->multiStaSetPrimaryConnection(ifname);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiChip::setMultiStaUseCaseInternal(MultiStaUseCase use_case) {
-    auto legacy_status = legacy_hal_.lock()->multiStaSetUseCase(
-            hidl_struct_util::convertHidlMultiStaUseCaseToLegacy(use_case));
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiChip::setCoexUnsafeChannelsInternal(std::vector<CoexUnsafeChannel> unsafe_channels,
-                                                   uint32_t restrictions) {
-    std::vector<legacy_hal::wifi_coex_unsafe_channel> legacy_unsafe_channels;
-    if (!hidl_struct_util::convertHidlVectorOfCoexUnsafeChannelToLegacy(unsafe_channels,
-                                                                        &legacy_unsafe_channels)) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    uint32_t legacy_restrictions = 0;
-    if (restrictions & CoexRestriction::WIFI_DIRECT) {
-        legacy_restrictions |= legacy_hal::wifi_coex_restriction::WIFI_DIRECT;
-    }
-    if (restrictions & CoexRestriction::SOFTAP) {
-        legacy_restrictions |= legacy_hal::wifi_coex_restriction::SOFTAP;
-    }
-    if (restrictions & 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);
-}
-
-WifiStatus WifiChip::setCountryCodeInternal(const std::array<int8_t, 2>& code) {
-    auto legacy_status = legacy_hal_.lock()->setCountryCode(getFirstActiveWlanIfaceName(), code);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, std::vector<V1_5::WifiUsableChannel>> WifiChip::getUsableChannelsInternal(
-        WifiBand /*band*/, uint32_t /*ifaceModeMask*/, uint32_t /*filterMask*/) {
-    LOG(ERROR) << "getUsableChannels is not supported on this HAL";
-    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
-}
-
-WifiStatus WifiChip::triggerSubsystemRestartInternal() {
-    auto legacy_status = legacy_hal_.lock()->triggerSubsystemRestart();
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, sp<V1_6::IWifiRttController>> WifiChip::createRttControllerInternal_1_6(
-        const sp<IWifiIface>& bound_iface) {
-    if (sta_ifaces_.size() == 0 &&
-        !canCurrentModeSupportConcurrencyTypeWithCurrentTypes(IfaceConcurrencyType::STA)) {
-        LOG(ERROR) << "createRttControllerInternal_1_6: Chip cannot support STAs "
-                      "(and RTT by extension)";
-        return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
-    }
-    sp<WifiRttController> rtt =
-            new WifiRttController(getFirstActiveWlanIfaceName(), bound_iface, legacy_hal_);
-    rtt_controllers_.emplace_back(rtt);
-    return {createWifiStatus(WifiStatusCode::SUCCESS), rtt};
-}
-
-std::pair<WifiStatus, std::vector<V1_6::WifiUsableChannel>> WifiChip::getUsableChannelsInternal_1_6(
-        WifiBand band, uint32_t ifaceModeMask, uint32_t 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(
-            hidl_struct_util::convertHidlWifiBandToLegacyMacBand(band),
-            hidl_struct_util::convertHidlWifiIfaceModeToLegacy(ifaceModeMask),
-            hidl_struct_util::convertHidlUsableChannelFilterToLegacy(filterMask));
-
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        return {createWifiStatusFromLegacyError(legacy_status), {}};
-    }
-    std::vector<V1_6::WifiUsableChannel> hidl_usable_channels;
-    if (!hidl_struct_util::convertLegacyWifiUsableChannelsToHidl(legacy_usable_channels,
-                                                                 &hidl_usable_channels)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_usable_channels};
-}
-
-std::pair<WifiStatus, V1_6::WifiRadioCombinationMatrix>
-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 {createWifiStatusFromLegacyError(legacy_status), {}};
-    }
-
-    V1_6::WifiRadioCombinationMatrix hidl_matrix;
-    if (!hidl_struct_util::convertLegacyRadioCombinationsMatrixToHidl(legacy_matrix,
-                                                                      &hidl_matrix)) {
-        LOG(ERROR) << "Failed convertLegacyRadioCombinationsMatrixToHidl() ";
-        return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_matrix};
-}
-
-std::pair<WifiStatus, std::vector<V1_6::IWifiChip::ChipMode>>
-WifiChip::getAvailableModesInternal_1_6() {
-    return {createWifiStatus(WifiStatusCode::SUCCESS), modes_};
-}
-
-WifiStatus WifiChip::handleChipConfiguration(
-        /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock, ChipModeId 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.
-    WifiStatus status = registerRadioModeChangeCallback();
-    if (status.code != WifiStatusCode::SUCCESS) {
-        // This probably is not a critical failure?
-        LOG(ERROR) << "Failed to register radio mode change callback";
-    }
-    // Extract and save the version information into property.
-    std::pair<WifiStatus, V1_4::IWifiChip::ChipDebugInfo> version_info;
-    version_info = WifiChip::requestChipDebugInfoInternal();
-    if (WifiStatusCode::SUCCESS == version_info.first.code) {
-        property_set("vendor.wlan.firmware.version",
-                     version_info.second.firmwareDescription.c_str());
-        property_set("vendor.wlan.driver.version", version_info.second.driverDescription.c_str());
-    }
-
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus WifiChip::registerDebugRingBufferCallback() {
-    if (debug_ring_buffer_cb_registered_) {
-        return createWifiStatus(WifiStatusCode::SUCCESS);
-    }
-
-    android::wp<WifiChip> weak_ptr_this(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.promote();
-                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                    LOG(ERROR) << "Callback invoked on an invalid object";
-                    return;
-                }
-                WifiDebugRingBufferStatus hidl_status;
-                Ringbuffer::AppendStatus appendstatus;
-                if (!hidl_struct_util::convertLegacyDebugRingBufferStatusToHidl(status,
-                                                                                &hidl_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);
-}
-
-WifiStatus WifiChip::registerRadioModeChangeCallback() {
-    android::wp<WifiChip> weak_ptr_this(this);
-    const auto& on_radio_mode_change_callback =
-            [weak_ptr_this](const std::vector<legacy_hal::WifiMacInfo>& mac_infos) {
-                const auto shared_ptr_this = weak_ptr_this.promote();
-                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                    LOG(ERROR) << "Callback invoked on an invalid object";
-                    return;
-                }
-                std::vector<V1_4::IWifiChipEventCallback::RadioModeInfo> hidl_radio_mode_infos;
-                if (!hidl_struct_util::convertLegacyWifiMacInfosToHidl(mac_infos,
-                                                                       &hidl_radio_mode_infos)) {
-                    LOG(ERROR) << "Error converting wifi mac info";
-                    return;
-                }
-                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-                    if (!callback->onRadioModeChange_1_4(hidl_radio_mode_infos).isOk()) {
-                        LOG(ERROR) << "Failed to invoke onRadioModeChange_1_4"
-                                   << " callback on: " << toString(callback);
-                    }
-                }
-            };
-    legacy_hal::wifi_error legacy_status =
-            legacy_hal_.lock()->registerRadioModeChangeCallbackHandler(
-                    getFirstActiveWlanIfaceName(), on_radio_mode_change_callback);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::vector<V1_6::IWifiChip::ChipConcurrencyCombination>
-WifiChip::getCurrentModeConcurrencyCombinations() {
-    if (!isValidModeId(current_mode_id_)) {
-        LOG(ERROR) << "Chip not configured in a mode yet";
-        return {};
-    }
-    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 {};
-}
-
-// 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] = 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 V1_6::IWifiChip::ChipConcurrencyCombination& combination) {
-    uint32_t num_expanded_combos = 1;
-    for (const auto& limit : combination.limits) {
-        for (uint32_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,
-              IfaceConcurrencyType::P2P, IfaceConcurrencyType::STA}) {
-            expanded_combo[type] = 0;
-        }
-    }
-    uint32_t span = num_expanded_combos;
-    for (const auto& limit : combination.limits) {
-        for (uint32_t i = 0; i < limit.maxIfaces; i++) {
-            span /= limit.types.size();
-            for (uint32_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,
-          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,
-          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(ChipModeId 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::deleteApIface(const std::string& if_name) {
-    if (if_name.empty()) return;
-    // delete bridged interfaces if have
-    for (auto const& it : br_ifaces_ap_instances_) {
-        if (it.first == if_name) {
-            for (auto const& iface : it.second) {
-                iface_util_->removeIfaceFromBridge(if_name, iface);
-                legacy_hal_.lock()->deleteVirtualInterface(iface);
-            }
-            iface_util_->deleteBridge(if_name);
-            br_ifaces_ap_instances_.erase(if_name);
-            // ifname is bridged AP, return here.
-            return;
-        }
-    }
-
-    // No bridged AP case, delete AP iface
-    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->deleteVirtualInterface(if_name);
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        LOG(ERROR) << "Failed to remove interface: " << if_name << " "
-                   << legacyErrorToString(legacy_status);
-    }
-}
-
-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 implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.6/default/wifi_chip.h b/wifi/1.6/default/wifi_chip.h
deleted file mode 100644
index e8ddaa6..0000000
--- a/wifi/1.6/default/wifi_chip.h
+++ /dev/null
@@ -1,317 +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 WIFI_CHIP_H_
-#define WIFI_CHIP_H_
-
-// HACK: NAN is a macro defined in math.h, which can be included in various
-// headers. This wifi HAL uses an enum called NAN, which does not compile when
-// the macro is defined. Undefine NAN to work around it.
-#undef NAN
-
-#include <list>
-#include <map>
-#include <mutex>
-
-#include <android-base/macros.h>
-#include <android/hardware/wifi/1.6/IWifiChip.h>
-#include <android/hardware/wifi/1.6/IWifiRttController.h>
-#include <android/hardware/wifi/1.6/IWifiStaIface.h>
-
-#include "hidl_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 android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-using namespace android::hardware::wifi::V1_0;
-using V1_5::WifiBand;
-
-/**
- * HIDL 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 V1_6::IWifiChip {
-  public:
-    WifiChip(ChipId chip_id, bool is_primary,
-             const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
-             const std::weak_ptr<mode_controller::WifiModeController> mode_controller,
-             const std::shared_ptr<iface_util::WifiIfaceUtil> iface_util,
-             const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags,
-             const std::function<void(const std::string&)>& subsystemCallbackHandler);
-    // HIDL does not provide a built-in mechanism to let the server invalidate
-    // a HIDL interface object after creation. If any client process holds onto
-    // a reference to the object in their context, any method calls on that
-    // 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 it's 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 HIDL method implementations should check if the object is still
-    // marked valid before processing them.
-    void invalidate();
-    bool isValid();
-    std::set<sp<V1_4::IWifiChipEventCallback>> getEventCallbacks();
-
-    // HIDL methods exposed.
-    Return<void> getId(getId_cb hidl_status_cb) override;
-    // Deprecated support for this callback
-    Return<void> registerEventCallback(const sp<V1_0::IWifiChipEventCallback>& event_callback,
-                                       registerEventCallback_cb hidl_status_cb) override;
-    Return<void> getCapabilities(getCapabilities_cb hidl_status_cb) override;
-    Return<void> getAvailableModes(getAvailableModes_cb hidl_status_cb) override;
-    Return<void> configureChip(ChipModeId mode_id, configureChip_cb hidl_status_cb) override;
-    Return<void> getMode(getMode_cb hidl_status_cb) override;
-    Return<void> requestChipDebugInfo(requestChipDebugInfo_cb hidl_status_cb) override;
-    Return<void> requestDriverDebugDump(requestDriverDebugDump_cb hidl_status_cb) override;
-    Return<void> requestFirmwareDebugDump(requestFirmwareDebugDump_cb hidl_status_cb) override;
-    Return<void> createApIface(createApIface_cb hidl_status_cb) override;
-    Return<void> createBridgedApIface(createBridgedApIface_cb hidl_status_cb) override;
-    Return<void> getApIfaceNames(getApIfaceNames_cb hidl_status_cb) override;
-    Return<void> getApIface(const hidl_string& ifname, getApIface_cb hidl_status_cb) override;
-    Return<void> removeApIface(const hidl_string& ifname, removeApIface_cb hidl_status_cb) override;
-    Return<void> removeIfaceInstanceFromBridgedApIface(
-            const hidl_string& brIfaceName, const hidl_string& ifaceInstanceName,
-            removeIfaceInstanceFromBridgedApIface_cb hidl_status_cb) override;
-    Return<void> createNanIface(createNanIface_cb hidl_status_cb) override;
-    Return<void> getNanIfaceNames(getNanIfaceNames_cb hidl_status_cb) override;
-    Return<void> getNanIface(const hidl_string& ifname, getNanIface_cb hidl_status_cb) override;
-    Return<void> removeNanIface(const hidl_string& ifname,
-                                removeNanIface_cb hidl_status_cb) override;
-    Return<void> createP2pIface(createP2pIface_cb hidl_status_cb) override;
-    Return<void> getP2pIfaceNames(getP2pIfaceNames_cb hidl_status_cb) override;
-    Return<void> getP2pIface(const hidl_string& ifname, getP2pIface_cb hidl_status_cb) override;
-    Return<void> removeP2pIface(const hidl_string& ifname,
-                                removeP2pIface_cb hidl_status_cb) override;
-    Return<void> createStaIface(createStaIface_cb hidl_status_cb) override;
-    Return<void> getStaIfaceNames(getStaIfaceNames_cb hidl_status_cb) override;
-    Return<void> getStaIface(const hidl_string& ifname, getStaIface_cb hidl_status_cb) override;
-    Return<void> removeStaIface(const hidl_string& ifname,
-                                removeStaIface_cb hidl_status_cb) override;
-    Return<void> createRttController(const sp<IWifiIface>& bound_iface,
-                                     createRttController_cb hidl_status_cb) override;
-    Return<void> getDebugRingBuffersStatus(getDebugRingBuffersStatus_cb hidl_status_cb) override;
-    Return<void> startLoggingToDebugRingBuffer(
-            const hidl_string& ring_name, WifiDebugRingBufferVerboseLevel verbose_level,
-            uint32_t max_interval_in_sec, uint32_t min_data_size_in_bytes,
-            startLoggingToDebugRingBuffer_cb hidl_status_cb) override;
-    Return<void> forceDumpToDebugRingBuffer(const hidl_string& ring_name,
-                                            forceDumpToDebugRingBuffer_cb hidl_status_cb) override;
-    Return<void> flushRingBufferToFile(flushRingBufferToFile_cb hidl_status_cb) override;
-    Return<void> stopLoggingToDebugRingBuffer(
-            stopLoggingToDebugRingBuffer_cb hidl_status_cb) override;
-    Return<void> getDebugHostWakeReasonStats(
-            getDebugHostWakeReasonStats_cb hidl_status_cb) override;
-    Return<void> enableDebugErrorAlerts(bool enable,
-                                        enableDebugErrorAlerts_cb hidl_status_cb) override;
-    Return<void> selectTxPowerScenario(V1_1::IWifiChip::TxPowerScenario scenario,
-                                       selectTxPowerScenario_cb hidl_status_cb) override;
-    Return<void> resetTxPowerScenario(resetTxPowerScenario_cb hidl_status_cb) override;
-    Return<void> setLatencyMode(LatencyMode mode, setLatencyMode_cb hidl_status_cb) override;
-    Return<void> registerEventCallback_1_2(const sp<V1_2::IWifiChipEventCallback>& event_callback,
-                                           registerEventCallback_1_2_cb hidl_status_cb) override;
-    Return<void> selectTxPowerScenario_1_2(TxPowerScenario scenario,
-                                           selectTxPowerScenario_cb hidl_status_cb) override;
-    Return<void> getCapabilities_1_3(getCapabilities_cb hidl_status_cb) override;
-    Return<void> getCapabilities_1_5(getCapabilities_1_5_cb hidl_status_cb) override;
-    Return<void> debug(const hidl_handle& handle, const hidl_vec<hidl_string>& options) override;
-    Return<void> createRttController_1_4(const sp<IWifiIface>& bound_iface,
-                                         createRttController_1_4_cb hidl_status_cb) override;
-    Return<void> registerEventCallback_1_4(const sp<V1_4::IWifiChipEventCallback>& event_callback,
-                                           registerEventCallback_1_4_cb hidl_status_cb) override;
-    Return<void> setMultiStaPrimaryConnection(
-            const hidl_string& ifname, setMultiStaPrimaryConnection_cb hidl_status_cb) override;
-    Return<void> setMultiStaUseCase(MultiStaUseCase use_case,
-                                    setMultiStaUseCase_cb hidl_status_cb) override;
-    Return<void> setCoexUnsafeChannels(const hidl_vec<CoexUnsafeChannel>& unsafe_channels,
-                                       hidl_bitfield<IfaceType> restrictions,
-                                       setCoexUnsafeChannels_cb hidl_status_cb) override;
-    Return<void> setCountryCode(const hidl_array<int8_t, 2>& code,
-                                setCountryCode_cb _hidl_cb) override;
-    Return<void> getUsableChannels(WifiBand band, hidl_bitfield<V1_5::WifiIfaceMode> ifaceModeMask,
-                                   hidl_bitfield<V1_5::IWifiChip::UsableChannelFilter> filterMask,
-                                   getUsableChannels_cb _hidl_cb) override;
-    Return<void> triggerSubsystemRestart(triggerSubsystemRestart_cb hidl_status_cb) override;
-    Return<void> createRttController_1_6(const sp<IWifiIface>& bound_iface,
-                                         createRttController_1_6_cb hidl_status_cb) override;
-    Return<void> getUsableChannels_1_6(WifiBand band,
-                                       hidl_bitfield<V1_5::WifiIfaceMode> ifaceModeMask,
-                                       hidl_bitfield<UsableChannelFilter> filterMask,
-                                       getUsableChannels_1_6_cb _hidl_cb) override;
-    Return<void> getSupportedRadioCombinationsMatrix(
-            getSupportedRadioCombinationsMatrix_cb hidl_status_cb) override;
-    Return<void> getAvailableModes_1_6(getAvailableModes_1_6_cb hidl_status_cb) 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 HIDL methods.
-    std::pair<WifiStatus, ChipId> getIdInternal();
-    // Deprecated support for this callback
-    WifiStatus registerEventCallbackInternal(
-            const sp<V1_0::IWifiChipEventCallback>& event_callback);
-    std::pair<WifiStatus, uint32_t> getCapabilitiesInternal();
-    std::pair<WifiStatus, std::vector<V1_0::IWifiChip::ChipMode>> getAvailableModesInternal();
-    WifiStatus configureChipInternal(std::unique_lock<std::recursive_mutex>* lock,
-                                     ChipModeId mode_id);
-    std::pair<WifiStatus, uint32_t> getModeInternal();
-    std::pair<WifiStatus, IWifiChip::ChipDebugInfo> requestChipDebugInfoInternal();
-    std::pair<WifiStatus, std::vector<uint8_t>> requestDriverDebugDumpInternal();
-    std::pair<WifiStatus, std::vector<uint8_t>> requestFirmwareDebugDumpInternal();
-    sp<WifiApIface> newWifiApIface(std::string& ifname);
-    WifiStatus createVirtualApInterface(const std::string& apVirtIf);
-    std::pair<WifiStatus, sp<V1_5::IWifiApIface>> createApIfaceInternal();
-    std::pair<WifiStatus, sp<V1_5::IWifiApIface>> createBridgedApIfaceInternal();
-    std::pair<WifiStatus, std::vector<hidl_string>> getApIfaceNamesInternal();
-    std::pair<WifiStatus, sp<V1_5::IWifiApIface>> getApIfaceInternal(const std::string& ifname);
-    WifiStatus removeApIfaceInternal(const std::string& ifname);
-    WifiStatus removeIfaceInstanceFromBridgedApIfaceInternal(const std::string& brIfaceName,
-                                                             const std::string& ifInstanceName);
-    std::pair<WifiStatus, sp<V1_4::IWifiNanIface>> createNanIfaceInternal();
-    std::pair<WifiStatus, std::vector<hidl_string>> getNanIfaceNamesInternal();
-    std::pair<WifiStatus, sp<V1_4::IWifiNanIface>> getNanIfaceInternal(const std::string& ifname);
-    WifiStatus removeNanIfaceInternal(const std::string& ifname);
-    std::pair<WifiStatus, sp<IWifiP2pIface>> createP2pIfaceInternal();
-    std::pair<WifiStatus, std::vector<hidl_string>> getP2pIfaceNamesInternal();
-    std::pair<WifiStatus, sp<IWifiP2pIface>> getP2pIfaceInternal(const std::string& ifname);
-    WifiStatus removeP2pIfaceInternal(const std::string& ifname);
-    std::pair<WifiStatus, sp<V1_6::IWifiStaIface>> createStaIfaceInternal();
-    std::pair<WifiStatus, std::vector<hidl_string>> getStaIfaceNamesInternal();
-    std::pair<WifiStatus, sp<V1_6::IWifiStaIface>> getStaIfaceInternal(const std::string& ifname);
-    WifiStatus removeStaIfaceInternal(const std::string& ifname);
-    std::pair<WifiStatus, sp<V1_0::IWifiRttController>> createRttControllerInternal(
-            const sp<IWifiIface>& bound_iface);
-    std::pair<WifiStatus, std::vector<WifiDebugRingBufferStatus>>
-    getDebugRingBuffersStatusInternal();
-    WifiStatus startLoggingToDebugRingBufferInternal(const hidl_string& ring_name,
-                                                     WifiDebugRingBufferVerboseLevel verbose_level,
-                                                     uint32_t max_interval_in_sec,
-                                                     uint32_t min_data_size_in_bytes);
-    WifiStatus forceDumpToDebugRingBufferInternal(const hidl_string& ring_name);
-    WifiStatus flushRingBufferToFileInternal();
-    WifiStatus stopLoggingToDebugRingBufferInternal();
-    std::pair<WifiStatus, WifiDebugHostWakeReasonStats> getDebugHostWakeReasonStatsInternal();
-    WifiStatus enableDebugErrorAlertsInternal(bool enable);
-    WifiStatus selectTxPowerScenarioInternal(V1_1::IWifiChip::TxPowerScenario scenario);
-    WifiStatus resetTxPowerScenarioInternal();
-    WifiStatus setLatencyModeInternal(LatencyMode mode);
-    WifiStatus registerEventCallbackInternal_1_2(
-            const sp<V1_2::IWifiChipEventCallback>& event_callback);
-    WifiStatus selectTxPowerScenarioInternal_1_2(TxPowerScenario scenario);
-    std::pair<WifiStatus, uint32_t> getCapabilitiesInternal_1_3();
-    std::pair<WifiStatus, uint32_t> getCapabilitiesInternal_1_5();
-    std::pair<WifiStatus, sp<V1_4::IWifiRttController>> createRttControllerInternal_1_4(
-            const sp<IWifiIface>& bound_iface);
-    WifiStatus registerEventCallbackInternal_1_4(
-            const sp<V1_4::IWifiChipEventCallback>& event_callback);
-    WifiStatus setMultiStaPrimaryConnectionInternal(const std::string& ifname);
-    WifiStatus setMultiStaUseCaseInternal(MultiStaUseCase use_case);
-    WifiStatus setCoexUnsafeChannelsInternal(std::vector<CoexUnsafeChannel> unsafe_channels,
-                                             uint32_t restrictions);
-    WifiStatus setCountryCodeInternal(const std::array<int8_t, 2>& code);
-    std::pair<WifiStatus, std::vector<V1_5::WifiUsableChannel>> getUsableChannelsInternal(
-            WifiBand band, uint32_t ifaceModeMask, uint32_t filterMask);
-    WifiStatus handleChipConfiguration(std::unique_lock<std::recursive_mutex>* lock,
-                                       ChipModeId mode_id);
-    WifiStatus registerDebugRingBufferCallback();
-    WifiStatus registerRadioModeChangeCallback();
-    std::vector<V1_6::IWifiChip::ChipConcurrencyCombination>
-    getCurrentModeConcurrencyCombinations();
-    std::map<IfaceConcurrencyType, size_t> getCurrentConcurrencyCombination();
-    std::vector<std::map<IfaceConcurrencyType, size_t>> expandConcurrencyCombinations(
-            const V1_6::IWifiChip::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(ChipModeId 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 deleteApIface(const std::string& if_name);
-    bool findUsingNameFromBridgedApInstances(const std::string& name);
-    WifiStatus triggerSubsystemRestartInternal();
-    std::pair<WifiStatus, sp<V1_6::IWifiRttController>> createRttControllerInternal_1_6(
-            const sp<IWifiIface>& bound_iface);
-    std::pair<WifiStatus, std::vector<V1_6::WifiUsableChannel>> getUsableChannelsInternal_1_6(
-            WifiBand band, uint32_t ifaceModeMask, uint32_t filterMask);
-    std::pair<WifiStatus, WifiRadioCombinationMatrix> getSupportedRadioCombinationsMatrixInternal();
-    std::pair<WifiStatus, std::vector<V1_6::IWifiChip::ChipMode>> getAvailableModesInternal_1_6();
-
-    ChipId 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<sp<WifiApIface>> ap_ifaces_;
-    std::vector<sp<WifiNanIface>> nan_ifaces_;
-    std::vector<sp<WifiP2pIface>> p2p_ifaces_;
-    std::vector<sp<WifiStaIface>> sta_ifaces_;
-    std::vector<sp<WifiRttController>> rtt_controllers_;
-    std::map<std::string, Ringbuffer> ringbuffer_map_;
-    bool is_valid_;
-    // Members pertaining to chip configuration.
-    uint32_t current_mode_id_;
-    std::mutex lock_t;
-    std::vector<V1_6::IWifiChip::ChipMode> modes_;
-    // The legacy ring buffer callback API has only a global callback
-    // registration mechanism. Use this to check if we have already
-    // registered a callback.
-    bool debug_ring_buffer_cb_registered_;
-    hidl_callback_util::HidlCallbackHandler<V1_4::IWifiChipEventCallback> event_cb_handler_;
-
-    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 implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_CHIP_H_
diff --git a/wifi/1.6/default/wifi_feature_flags.cpp b/wifi/1.6/default/wifi_feature_flags.cpp
deleted file mode 100644
index e80a3cd..0000000
--- a/wifi/1.6/default/wifi_feature_flags.cpp
+++ /dev/null
@@ -1,247 +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.
- */
-
-#include <string>
-
-#include <android-base/logging.h>
-#include <cutils/properties.h>
-
-#include "wifi_feature_flags.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-namespace feature_flags {
-
-using V1_0::ChipModeId;
-using V1_0::IWifiChip;
-using V1_6::IfaceConcurrencyType;
-
-/* 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 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 ChipModeId kMainModeId = chip_mode_ids::kV3;
-#elif defined(WIFI_HIDL_FEATURE_DUAL_INTERFACE)
-// former V2 (fixed dual interface) setup expressed as V3
-constexpr ChipModeId 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 ChipModeId 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
-
-/**
- * Helper class to convert a collection of combination limits to a combination.
- *
- * The main point here is to simplify the syntax required by
- * WIFI_HAL_INTERFACE_COMBINATIONS.
- */
-struct ChipConcurrencyCombination
-    : public hidl_vec<V1_6::IWifiChip::ChipConcurrencyCombinationLimit> {
-    ChipConcurrencyCombination(
-            const std::initializer_list<V1_6::IWifiChip::ChipConcurrencyCombinationLimit> list)
-        : hidl_vec(list) {}
-
-    operator V1_6::IWifiChip::ChipConcurrencyCombination() const { return {*this}; }
-
-    static hidl_vec<V1_6::IWifiChip::ChipConcurrencyCombination> make_vec(
-            const std::initializer_list<ChipConcurrencyCombination> list) {
-        return hidl_vec<V1_6::IWifiChip::ChipConcurrencyCombination>(  //
-                std::begin(list), std::end(list));
-    }
-};
-
-#define STA IfaceConcurrencyType::STA
-#define AP IfaceConcurrencyType::AP
-#define AP_BRIDGED IfaceConcurrencyType::AP_BRIDGED
-#define P2P IfaceConcurrencyType::P2P
-#define NAN IfaceConcurrencyType::NAN
-static const std::vector<V1_6::IWifiChip::ChipMode> kChipModesPrimary{
-        {kMainModeId, ChipConcurrencyCombination::make_vec({WIFI_HAL_INTERFACE_COMBINATIONS})},
-#ifdef WIFI_HAL_INTERFACE_COMBINATIONS_AP
-        {chip_mode_ids::kV1Ap,
-         ChipConcurrencyCombination::make_vec({WIFI_HAL_INTERFACE_COMBINATIONS_AP})},
-#endif
-};
-
-static const std::vector<V1_6::IWifiChip::ChipMode> kChipModesSecondary{
-#ifdef WIFI_HAL_INTERFACE_COMBINATIONS_SECONDARY_CHIP
-        {chip_mode_ids::kV3,
-         ChipConcurrencyCombination::make_vec({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<V1_6::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, ChipConcurrencyCombination::make_vec(
-                                                {{{{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,
-                           ChipConcurrencyCombination::make_vec(
-                                   {{{{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,
-                           ChipConcurrencyCombination::make_vec(
-                                   {{{{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,
-                           ChipConcurrencyCombination::make_vec(
-                                   {{{{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,
-                           ChipConcurrencyCombination::make_vec(
-                                   {{{{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, ChipConcurrencyCombination::make_vec(
-                                                {{{{STA}, 1}, {{P2P, NAN, AP, AP_BRIDGED}, 1}},
-                                                 {{{STA}, 2}}})}}}};
-
-#undef STA
-#undef AP
-#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<V1_6::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<V1_6::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<V1_6::IWifiChip::ChipMode> WifiFeatureFlags::getChipModes(bool is_primary) {
-    return (is_primary) ? getChipModesForPrimary() : kChipModesSecondary;
-}
-
-}  // namespace feature_flags
-}  // namespace implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.6/default/wifi_feature_flags.h b/wifi/1.6/default/wifi_feature_flags.h
deleted file mode 100644
index 1635341..0000000
--- a/wifi/1.6/default/wifi_feature_flags.h
+++ /dev/null
@@ -1,58 +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 WIFI_FEATURE_FLAGS_H_
-#define WIFI_FEATURE_FLAGS_H_
-
-#include <android/hardware/wifi/1.6/IWifiChip.h>
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-namespace feature_flags {
-
-namespace chip_mode_ids {
-// These mode ID's should be unique (even across combo versions). Refer to
-// handleChipConfiguration() for it's usage.
-constexpr V1_0::ChipModeId kInvalid = UINT32_MAX;
-// Mode ID's for V1
-constexpr V1_0::ChipModeId kV1Sta = 0;
-constexpr V1_0::ChipModeId kV1Ap = 1;
-// Mode ID for V3
-constexpr V1_0::ChipModeId kV3 = 3;
-}  // namespace chip_mode_ids
-
-class WifiFeatureFlags {
-  public:
-    WifiFeatureFlags();
-    virtual ~WifiFeatureFlags() = default;
-
-    virtual std::vector<V1_6::IWifiChip::ChipMode> getChipModes(bool is_primary);
-
-  private:
-    std::vector<V1_6::IWifiChip::ChipMode> getChipModesForPrimary();
-};
-
-}  // namespace feature_flags
-}  // namespace implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_FEATURE_FLAGS_H_
diff --git a/wifi/1.6/default/wifi_iface_util.cpp b/wifi/1.6/default/wifi_iface_util.cpp
deleted file mode 100644
index d55e4f8..0000000
--- a/wifi/1.6/default/wifi_iface_util.cpp
+++ /dev/null
@@ -1,176 +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 <net/if.h>
-#include <cstddef>
-#include <iostream>
-#include <limits>
-#include <random>
-
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <private/android_filesystem_config.h>
-
-#undef NAN
-#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 android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-namespace iface_util {
-
-WifiIfaceUtil::WifiIfaceUtil(const std::weak_ptr<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 implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.6/default/wifi_iface_util.h b/wifi/1.6/default/wifi_iface_util.h
deleted file mode 100644
index c5db5de..0000000
--- a/wifi/1.6/default/wifi_iface_util.h
+++ /dev/null
@@ -1,87 +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.
- */
-
-#ifndef WIFI_IFACE_UTIL_H_
-#define WIFI_IFACE_UTIL_H_
-
-#include <wifi_system/interface_tool.h>
-
-#include <android/hardware/wifi/1.0/IWifi.h>
-
-#include "wifi_legacy_hal.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-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<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<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 implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_IFACE_UTIL_H_
diff --git a/wifi/1.6/default/wifi_legacy_hal.cpp b/wifi/1.6/default/wifi_legacy_hal.cpp
deleted file mode 100644
index c9bcdc5..0000000
--- a/wifi/1.6/default/wifi_legacy_hal.cpp
+++ /dev/null
@@ -1,1635 +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.
- */
-
-#include <array>
-#include <chrono>
-
-#include <android-base/logging.h>
-#include <cutils/properties.h>
-#include <net/if.h>
-
-#include "hidl_sync_util.h"
-#include "wifi_legacy_hal.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 android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-namespace legacy_hal {
-
-// Legacy HAL functions accept "C" style function pointers, so use global
-// functions to pass to the legacy HAL function and store the corresponding
-// std::function methods to be invoked.
-//
-// 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 = hidl_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 = hidl_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 = hidl_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 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 = hidl_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 = hidl_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 = hidl_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 = hidl_sync_util::acquireGlobalLock();
-    if (on_radio_mode_change_internal_callback) {
-        on_radio_mode_change_internal_callback(id, num_macs, mac_infos);
-    }
-}
-
-// Callback to be invoked to report subsystem restart
-std::function<void(const char*)> on_subsystem_restart_internal_callback;
-void onAsyncSubsystemRestart(const char* error) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_subsystem_restart_internal_callback) {
-        on_subsystem_restart_internal_callback(error);
-    }
-}
-
-// Callback to be invoked for rtt results results.
-std::function<void(wifi_request_id, unsigned num_results, wifi_rtt_result* rtt_results[])>
-        on_rtt_results_internal_callback;
-void onAsyncRttResults(wifi_request_id id, unsigned num_results, wifi_rtt_result* rtt_results[]) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_rtt_results_internal_callback) {
-        on_rtt_results_internal_callback(id, num_results, rtt_results);
-        on_rtt_results_internal_callback = nullptr;
-    }
-}
-
-// 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 onAysncNanNotifyResponse(transaction_id id, NanResponseMsg* msg) {
-    const auto lock = hidl_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 onAysncNanEventPublishReplied(NanPublishRepliedInd* /* event */) {
-    LOG(ERROR) << "onAysncNanEventPublishReplied triggered";
-}
-
-std::function<void(const NanPublishTerminatedInd&)> on_nan_event_publish_terminated_user_callback;
-void onAysncNanEventPublishTerminated(NanPublishTerminatedInd* event) {
-    const auto lock = hidl_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 onAysncNanEventMatch(NanMatchInd* event) {
-    const auto lock = hidl_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 onAysncNanEventMatchExpired(NanMatchExpiredInd* event) {
-    const auto lock = hidl_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 onAysncNanEventSubscribeTerminated(NanSubscribeTerminatedInd* event) {
-    const auto lock = hidl_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 onAysncNanEventFollowup(NanFollowupInd* event) {
-    const auto lock = hidl_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 onAysncNanEventDiscEngEvent(NanDiscEngEventInd* event) {
-    const auto lock = hidl_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 onAysncNanEventDisabled(NanDisabledInd* event) {
-    const auto lock = hidl_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 onAysncNanEventTca(NanTCAInd* event) {
-    const auto lock = hidl_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 onAysncNanEventBeaconSdfPayload(NanBeaconSdfPayloadInd* event) {
-    const auto lock = hidl_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 onAysncNanEventDataPathRequest(NanDataPathRequestInd* event) {
-    const auto lock = hidl_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 onAysncNanEventDataPathConfirm(NanDataPathConfirmInd* event) {
-    const auto lock = hidl_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 onAysncNanEventDataPathEnd(NanDataPathEndInd* event) {
-    const auto lock = hidl_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 onAysncNanEventTransmitFollowUp(NanTransmitFollowupInd* event) {
-    const auto lock = hidl_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 onAysncNanEventRangeRequest(NanRangeRequestInd* event) {
-    const auto lock = hidl_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 onAysncNanEventRangeReport(NanRangeReportInd* event) {
-    const auto lock = hidl_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 = hidl_sync_util::acquireGlobalLock();
-    if (on_nan_event_schedule_update_user_callback && event) {
-        on_nan_event_schedule_update_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 = hidl_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 = hidl_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 = hidl_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 = hidl_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 = hidl_sync_util::acquireGlobalLock();
-    if (on_chre_nan_rtt_internal_callback) {
-        on_chre_nan_rtt_internal_callback(state);
-    }
-}
-
-// End of the free-standing "C" style callbacks.
-
-WifiLegacyHal::WifiLegacyHal(const std::weak_ptr<wifi_system::InterfaceTool> iface_tool,
-                             const wifi_hal_fn& fn, bool is_primary)
-    : global_func_table_(fn),
-      global_handle_(nullptr),
-      awaiting_event_loop_termination_(false),
-      is_started_(false),
-      iface_tool_(iface_tool),
-      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);
-}
-
-std::pair<wifi_error, LinkLayerStats> WifiLegacyHal::getLinkLayerStats(
-        const std::string& iface_name) {
-    LinkLayerStats link_stats{};
-    LinkLayerStats* link_stats_ptr = &link_stats;
-
-    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;
-
-        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));
-        }
-    };
-
-    wifi_error status = global_func_table_.wifi_get_link_stats(0, getIfaceHandle(iface_name),
-                                                               {onSyncLinkLayerStatsResult});
-    on_link_layer_stats_result_internal_callback = nullptr;
-    return {status, link_stats};
-}
-
-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, 6> 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,
-                                                      uint32_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,
-                                                      uint32_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) {
-    if (on_rtt_results_internal_callback) {
-        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);
-    };
-
-    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});
-    if (status != WIFI_SUCCESS) {
-        on_rtt_results_internal_callback = nullptr;
-    }
-    return status;
-}
-
-wifi_error WifiLegacyHal::cancelRttRangeRequest(
-        const std::string& iface_name, wifi_request_id id,
-        const std::vector<std::array<uint8_t, 6>>& mac_addrs) {
-    if (!on_rtt_results_internal_callback) {
-        return WIFI_ERROR_NOT_AVAILABLE;
-    }
-    static_assert(sizeof(mac_addr) == sizeof(std::array<uint8_t, 6>), "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, 6>> 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) {
-        on_rtt_results_internal_callback = nullptr;
-    }
-    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_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),
-            {onAysncNanNotifyResponse, onAysncNanEventPublishReplied,
-             onAysncNanEventPublishTerminated, onAysncNanEventMatch, onAysncNanEventMatchExpired,
-             onAysncNanEventSubscribeTerminated, onAysncNanEventFollowup,
-             onAysncNanEventDiscEngEvent, onAysncNanEventDisabled, onAysncNanEventTca,
-             onAysncNanEventBeaconSdfPayload, onAysncNanEventDataPathRequest,
-             onAysncNanEventDataPathConfirm, onAysncNanEventDataPathEnd,
-             onAysncNanEventTransmitFollowUp, onAysncNanEventRangeRequest,
-             onAysncNanEventRangeReport, onAsyncNanEventScheduleUpdate});
-}
-
-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);
-}
-
-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,
-                                         std::array<int8_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 = hidl_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);
-}
-
-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_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;
-    on_rtt_results_internal_callback = nullptr;
-    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_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 implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.6/default/wifi_legacy_hal.h b/wifi/1.6/default/wifi_legacy_hal.h
deleted file mode 100644
index 2b923b4..0000000
--- a/wifi/1.6/default/wifi_legacy_hal.h
+++ /dev/null
@@ -1,730 +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 WIFI_LEGACY_HAL_H_
-#define WIFI_LEGACY_HAL_H_
-
-#include <condition_variable>
-#include <functional>
-#include <map>
-#include <thread>
-#include <vector>
-
-#include <hardware_legacy/wifi_hal.h>
-#include <wifi_system/interface_tool.h>
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-// This is in a separate namespace to prevent typename conflicts between
-// the legacy HAL types and the HIDL interface types.
-namespace legacy_hal {
-// Import all the types defined inside the legacy HAL header files into this
-// namespace.
-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_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_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_NDP_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 ::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 ::NanMatchAlg;
-using ::NanMatchExpiredInd;
-using ::NanMatchInd;
-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 ::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 ::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_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_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_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_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;
-};
-#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;
-};
-
-// 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, 6>, 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*>&)>;
-
-// 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;
-};
-
-/**
- * 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<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);
-    std::pair<wifi_error, LinkLayerStats> getLinkLayerStats(const std::string& iface_name);
-    // 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, uint32_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,
-                                           uint32_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);
-    wifi_error cancelRttRangeRequest(const std::string& iface_name, wifi_request_id id,
-                                     const std::vector<std::array<uint8_t, 6>>& 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 nanDataEnd(const std::string& iface_name, transaction_id id, uint32_t ndpInstanceId);
-    // AP functions.
-    wifi_error setCountryCode(const std::string& iface_name, std::array<int8_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);
-
-  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);
-
-    // 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<wifi_system::InterfaceTool> iface_tool_;
-    // flag to indicate if this HAL is for the primary chip. This is used
-    // in order to avoid some hard-coded behavior used with older HALs,
-    // such as bring wlan0 interface up/down on start/stop HAL.
-    // it may be removed once vendor HALs are updated.
-    bool is_primary_;
-};
-
-}  // namespace legacy_hal
-}  // namespace implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_LEGACY_HAL_H_
diff --git a/wifi/1.6/default/wifi_legacy_hal_factory.cpp b/wifi/1.6/default/wifi_legacy_hal_factory.cpp
deleted file mode 100644
index 147bf4d..0000000
--- a/wifi/1.6/default/wifi_legacy_hal_factory.cpp
+++ /dev/null
@@ -1,254 +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 <dirent.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <android-base/logging.h>
-#include <dlfcn.h>
-#include <libxml/parser.h>
-#include <libxml/tree.h>
-#include <libxml/xmlmemory.h>
-
-#include "wifi_legacy_hal_factory.h"
-#include "wifi_legacy_hal_stubs.h"
-
-namespace {
-static constexpr char kVendorHalsDescPath[] = "/vendor/etc/wifi/vendor_hals";
-static constexpr char kVendorHalsDescExt[] = ".xml";
-static constexpr uint32_t kVendorHalsDescVersion = 1;
-
-bool isDirectory(struct dirent* entryPtr) {
-    bool isDir = false;
-    if (entryPtr->d_type != DT_UNKNOWN && entryPtr->d_type != DT_LNK) {
-        isDir = (entryPtr->d_type == DT_DIR);
-    } else {
-        struct stat entryStat;
-        stat(entryPtr->d_name, &entryStat);
-        isDir = S_ISDIR(entryStat.st_mode);
-    }
-    return isDir;
-}
-
-bool isFileExtension(const char* name, const char* ext) {
-    if (name == NULL) return false;
-    if (ext == NULL) return false;
-
-    size_t extLen = strlen(ext);
-    size_t nameLen = strlen(name);
-
-    if (extLen > nameLen) return false;
-
-    if (strncmp(name + nameLen - extLen, ext, extLen) != 0) return false;
-
-    return true;
-}
-};  // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-namespace legacy_hal {
-
-WifiLegacyHalFactory::WifiLegacyHalFactory(
-        const std::weak_ptr<wifi_system::InterfaceTool> iface_tool)
-    : iface_tool_(iface_tool) {}
-
-std::vector<std::shared_ptr<WifiLegacyHal>> WifiLegacyHalFactory::getHals() {
-    if (legacy_hals_.empty()) {
-        if (!initVendorHalDescriptorFromLinked()) initVendorHalsDescriptorList();
-        for (auto& desc : descs_) {
-            std::shared_ptr<WifiLegacyHal> hal =
-                    std::make_shared<WifiLegacyHal>(iface_tool_, desc.fn, desc.primary);
-            legacy_hals_.push_back(hal);
-        }
-    }
-
-    return legacy_hals_;
-}
-
-bool WifiLegacyHalFactory::initVendorHalDescriptorFromLinked() {
-    wifi_hal_lib_desc desc;
-
-    if (!initLinkedHalFunctionTable(&desc.fn)) return false;
-
-    desc.primary = true;
-    desc.handle = NULL;
-    descs_.push_back(desc);
-    return true;
-}
-
-bool WifiLegacyHalFactory::initLinkedHalFunctionTable(wifi_hal_fn* hal_fn) {
-    init_wifi_vendor_hal_func_table_t initfn;
-
-    initfn = (init_wifi_vendor_hal_func_table_t)dlsym(RTLD_DEFAULT,
-                                                      "init_wifi_vendor_hal_func_table");
-    if (!initfn) {
-        LOG(INFO) << "no vendor HAL library linked, will try dynamic load";
-        return false;
-    }
-
-    if (!initHalFuncTableWithStubs(hal_fn)) {
-        LOG(ERROR) << "Can not initialize the basic function pointer table";
-        return false;
-    }
-
-    if (initfn(hal_fn) != WIFI_SUCCESS) {
-        LOG(ERROR) << "Can not initialize the vendor function pointer table";
-        return false;
-    }
-
-    return true;
-}
-
-/*
- * Overall structure of the HAL descriptor XML schema
- *
- * <?xml version="1.0" encoding="UTF-8"?>
- * <WifiVendorHal version="1">
- * <path>/vendor/lib64/libwifi-hal-qcom.so</path>
- * <primary>1</primary>
- * </WifiVendorHal>
- */
-void WifiLegacyHalFactory::initVendorHalsDescriptorList() {
-    xmlDocPtr xml;
-    xmlNodePtr node, cnode;
-    char* version;
-    std::string path;
-    xmlChar* value;
-    wifi_hal_lib_desc desc;
-
-    LOG(INFO) << "processing vendor HALs descriptions in " << kVendorHalsDescPath;
-    DIR* dirPtr = ::opendir(kVendorHalsDescPath);
-    if (dirPtr == NULL) {
-        LOG(ERROR) << "failed to open " << kVendorHalsDescPath;
-        return;
-    }
-    for (struct dirent* entryPtr = ::readdir(dirPtr); entryPtr != NULL;
-         entryPtr = ::readdir(dirPtr)) {
-        if (isDirectory(entryPtr)) continue;
-
-        if (!isFileExtension(entryPtr->d_name, kVendorHalsDescExt))
-            continue;  // only process .xml files
-
-        LOG(INFO) << "processing config file: " << entryPtr->d_name;
-
-        std::string fullPath(kVendorHalsDescPath);
-        fullPath.append("/");
-        fullPath.append(entryPtr->d_name);
-        xml = xmlReadFile(fullPath.c_str(), "UTF-8", XML_PARSE_RECOVER);
-        if (!xml) {
-            LOG(ERROR) << "failed to parse: " << entryPtr->d_name << " skipping...";
-            continue;
-        }
-        node = xmlDocGetRootElement(xml);
-        if (!node) {
-            LOG(ERROR) << "empty config file: " << entryPtr->d_name << " skipping...";
-            goto skip;
-        }
-        if (xmlStrcmp(node->name, BAD_CAST "WifiVendorHal")) {
-            LOG(ERROR) << "bad config, root element not WifiVendorHal: " << entryPtr->d_name
-                       << " skipping...";
-            goto skip;
-        }
-        version = (char*)xmlGetProp(node, BAD_CAST "version");
-        if (!version || strtoul(version, NULL, 0) != kVendorHalsDescVersion) {
-            LOG(ERROR) << "conf file: " << entryPtr->d_name
-                       << "must have version: " << kVendorHalsDescVersion << ", skipping...";
-            goto skip;
-        }
-        cnode = node->children;
-        path.clear();
-        desc.primary = false;
-        while (cnode) {
-            if (!xmlStrcmp(cnode->name, BAD_CAST "path")) {
-                value = xmlNodeListGetString(xml, cnode->children, 1);
-                if (value) path = (char*)value;
-                xmlFree(value);
-            } else if (!xmlStrcmp(cnode->name, BAD_CAST "primary")) {
-                value = xmlNodeListGetString(xml, cnode->children, 1);
-                desc.primary = !xmlStrcmp(value, BAD_CAST "1");
-                xmlFree(value);
-            }
-            cnode = cnode->next;
-        }
-        if (path.empty()) {
-            LOG(ERROR) << "hal library path not provided in: " << entryPtr->d_name
-                       << ", skipping...";
-            goto skip;
-        }
-        if (loadVendorHalLib(path, desc)) {
-            if (desc.primary)
-                descs_.insert(descs_.begin(), desc);
-            else
-                descs_.push_back(desc);
-        }
-    skip:
-        xmlFreeDoc(xml);
-    }
-    ::closedir(dirPtr);
-}
-
-bool WifiLegacyHalFactory::loadVendorHalLib(const std::string& path, wifi_hal_lib_desc& desc) {
-    void* h = dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL);
-    init_wifi_vendor_hal_func_table_t initfn;
-    wifi_error res;
-
-    if (!h) {
-        LOG(ERROR) << "failed to open vendor hal library: " << path;
-        return false;
-    }
-    initfn = (init_wifi_vendor_hal_func_table_t)dlsym(h, "init_wifi_vendor_hal_func_table");
-    if (!initfn) {
-        LOG(ERROR) << "init_wifi_vendor_hal_func_table not found in: " << path;
-        goto out_err;
-    }
-
-    if (!initHalFuncTableWithStubs(&desc.fn)) {
-        LOG(ERROR) << "Can not initialize the basic function pointer table";
-        goto out_err;
-    }
-    res = initfn(&desc.fn);
-    if (res != WIFI_SUCCESS) {
-        LOG(ERROR) << "failed to initialize the vendor func table in: " << path
-                   << " error: " << res;
-        goto out_err;
-    }
-
-    res = desc.fn.wifi_early_initialize();
-    // vendor HALs which do not implement early_initialize will return
-    // WIFI_ERROR_NOT_SUPPORTED, treat this as success.
-    if (res != WIFI_SUCCESS && res != WIFI_ERROR_NOT_SUPPORTED) {
-        LOG(ERROR) << "early initialization failed in: " << path << " error: " << res;
-        goto out_err;
-    }
-
-    desc.handle = h;
-    return true;
-out_err:
-    dlclose(h);
-    return false;
-}
-
-}  // namespace legacy_hal
-}  // namespace implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.6/default/wifi_legacy_hal_factory.h b/wifi/1.6/default/wifi_legacy_hal_factory.h
deleted file mode 100644
index 9f4423e..0000000
--- a/wifi/1.6/default/wifi_legacy_hal_factory.h
+++ /dev/null
@@ -1,66 +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.
- */
-
-#ifndef WIFI_LEGACY_HAL_FACTORY_H_
-#define WIFI_LEGACY_HAL_FACTORY_H_
-
-#include <wifi_system/interface_tool.h>
-
-#include "wifi_legacy_hal.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-// This is in a separate namespace to prevent typename conflicts between
-// the legacy HAL types and the HIDL interface types.
-namespace legacy_hal {
-/**
- * Class that creates WifiLegacyHal objects for vendor HALs in the system.
- */
-class WifiLegacyHalFactory {
-  public:
-    WifiLegacyHalFactory(const std::weak_ptr<wifi_system::InterfaceTool> iface_tool);
-    virtual ~WifiLegacyHalFactory() = default;
-
-    std::vector<std::shared_ptr<WifiLegacyHal>> getHals();
-
-  private:
-    typedef struct {
-        wifi_hal_fn fn;
-        bool primary;
-        void* handle;
-    } wifi_hal_lib_desc;
-
-    bool initVendorHalDescriptorFromLinked();
-    void initVendorHalsDescriptorList();
-    bool initLinkedHalFunctionTable(wifi_hal_fn* hal_fn);
-    bool loadVendorHalLib(const std::string& path, wifi_hal_lib_desc& desc);
-
-    std::weak_ptr<wifi_system::InterfaceTool> iface_tool_;
-    std::vector<wifi_hal_lib_desc> descs_;
-    std::vector<std::shared_ptr<WifiLegacyHal>> legacy_hals_;
-};
-
-}  // namespace legacy_hal
-}  // namespace implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_LEGACY_HAL_FACTORY_H_
diff --git a/wifi/1.6/default/wifi_legacy_hal_stubs.cpp b/wifi/1.6/default/wifi_legacy_hal_stubs.cpp
deleted file mode 100644
index b3bd373..0000000
--- a/wifi/1.6/default/wifi_legacy_hal_stubs.cpp
+++ /dev/null
@@ -1,177 +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.
- */
-
-#include "wifi_legacy_hal_stubs.h"
-
-// TODO: Remove these stubs from HalTool in libwifi-system.
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-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_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);
-    return true;
-}
-}  // namespace legacy_hal
-}  // namespace implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.6/default/wifi_legacy_hal_stubs.h b/wifi/1.6/default/wifi_legacy_hal_stubs.h
deleted file mode 100644
index c9a03bf..0000000
--- a/wifi/1.6/default/wifi_legacy_hal_stubs.h
+++ /dev/null
@@ -1,37 +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 WIFI_LEGACY_HAL_STUBS_H_
-#define WIFI_LEGACY_HAL_STUBS_H_
-
-#include <hardware_legacy/wifi_hal.h>
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-namespace legacy_hal {
-
-bool initHalFuncTableWithStubs(wifi_hal_fn* hal_fn);
-}  // namespace legacy_hal
-}  // namespace implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_LEGACY_HAL_STUBS_H_
diff --git a/wifi/1.6/default/wifi_mode_controller.cpp b/wifi/1.6/default/wifi_mode_controller.cpp
deleted file mode 100644
index 4b8ac7d..0000000
--- a/wifi/1.6/default/wifi_mode_controller.cpp
+++ /dev/null
@@ -1,89 +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.
- */
-
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <private/android_filesystem_config.h>
-
-#include "wifi_mode_controller.h"
-
-using android::hardware::wifi::V1_0::IfaceType;
-using android::wifi_hal::DriverTool;
-
-namespace {
-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:
-            // NAN is exposed in STA mode currently.
-            mode = DriverTool::kFirmwareModeSta;
-            break;
-        case IfaceType::STA:
-            mode = DriverTool::kFirmwareModeSta;
-            break;
-    }
-    return mode;
-}
-}  // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-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 implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.6/default/wifi_mode_controller.h b/wifi/1.6/default/wifi_mode_controller.h
deleted file mode 100644
index fee2b66..0000000
--- a/wifi/1.6/default/wifi_mode_controller.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef WIFI_MODE_CONTROLLER_H_
-#define WIFI_MODE_CONTROLLER_H_
-
-#include <wifi_hal/driver_tool.h>
-
-#include <android/hardware/wifi/1.0/IWifi.h>
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-namespace mode_controller {
-using namespace android::hardware::wifi::V1_0;
-
-/**
- * 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<wifi_hal::DriverTool> driver_tool_;
-};
-
-}  // namespace mode_controller
-}  // namespace implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_MODE_CONTROLLER_H_
diff --git a/wifi/1.6/default/wifi_nan_iface.cpp b/wifi/1.6/default/wifi_nan_iface.cpp
deleted file mode 100644
index ac2ebc9..0000000
--- a/wifi/1.6/default/wifi_nan_iface.cpp
+++ /dev/null
@@ -1,1016 +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.
- */
-
-#include <android-base/logging.h>
-
-#include "hidl_return_util.h"
-#include "hidl_struct_util.h"
-#include "wifi_nan_iface.h"
-#include "wifi_status_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-using hidl_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) {
-    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.
-            invalidate();
-            return;
-        }
-    }
-    // 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;
-    android::wp<WifiNanIface> weak_ptr_this(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.promote();
-        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-            LOG(ERROR) << "Callback invoked on an invalid object";
-            return;
-        }
-        WifiNanStatus wifiNanStatus;
-        if (!hidl_struct_util::convertLegacyNanResponseHeaderToHidl(msg, &wifiNanStatus)) {
-            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, wifiNanStatus).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, wifiNanStatus).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, wifiNanStatus,
-                                                              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, wifiNanStatus).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, wifiNanStatus).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, wifiNanStatus,
-                                         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, wifiNanStatus).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, wifiNanStatus).isOk()) {
-                        LOG(ERROR) << "Failed to invoke the callback";
-                    }
-                }
-                break;
-            }
-            case legacy_hal::NAN_GET_CAPABILITIES: {
-                V1_6::NanCapabilities hidl_struct;
-                if (!hidl_struct_util::convertLegacyNanCapabilitiesResponseToHidl(
-                            msg.body.nan_capabilities, &hidl_struct)) {
-                    LOG(ERROR) << "Failed to convert nan capabilities response";
-                    return;
-                }
-                for (const auto& callback : shared_ptr_this->getEventCallbacks_1_6()) {
-                    if (!callback->notifyCapabilitiesResponse_1_6(id, wifiNanStatus, hidl_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, wifiNanStatus).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, wifiNanStatus).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, wifiNanStatus,
-                                         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, wifiNanStatus)
-                                 .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, wifiNanStatus).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.promote();
-                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                    LOG(ERROR) << "Callback invoked on an invalid object";
-                    return;
-                }
-                NanClusterEventInd hidl_struct;
-                // event types defined identically - hence can be cast
-                hidl_struct.eventType = (NanClusterEventType)msg.event_type;
-                hidl_struct.addr = msg.data.mac_addr.addr;
-
-                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-                    if (!callback->eventClusterEvent(hidl_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.promote();
-        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-            LOG(ERROR) << "Callback invoked on an invalid object";
-            return;
-        }
-        WifiNanStatus status;
-        hidl_struct_util::convertToWifiNanStatus(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.promote();
-                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                    LOG(ERROR) << "Callback invoked on an invalid object";
-                    return;
-                }
-                WifiNanStatus status;
-                hidl_struct_util::convertToWifiNanStatus(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.promote();
-                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                    LOG(ERROR) << "Callback invoked on an invalid object";
-                    return;
-                }
-                WifiNanStatus status;
-                hidl_struct_util::convertToWifiNanStatus(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.promote();
-        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-            LOG(ERROR) << "Callback invoked on an invalid object";
-            return;
-        }
-        V1_6::NanMatchInd hidl_struct;
-        if (!hidl_struct_util::convertLegacyNanMatchIndToHidl(msg, &hidl_struct)) {
-            LOG(ERROR) << "Failed to convert nan capabilities response";
-            return;
-        }
-
-        for (const auto& callback : shared_ptr_this->getEventCallbacks_1_6()) {
-            if (!callback->eventMatch_1_6(hidl_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.promote();
-        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.promote();
-        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-            LOG(ERROR) << "Callback invoked on an invalid object";
-            return;
-        }
-        NanFollowupReceivedInd hidl_struct;
-        if (!hidl_struct_util::convertLegacyNanFollowupIndToHidl(msg, &hidl_struct)) {
-            LOG(ERROR) << "Failed to convert nan capabilities response";
-            return;
-        }
-
-        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-            if (!callback->eventFollowupReceived(hidl_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.promote();
-                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                    LOG(ERROR) << "Callback invoked on an invalid object";
-                    return;
-                }
-                WifiNanStatus status;
-                hidl_struct_util::convertToWifiNanStatus(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.promote();
-                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                    LOG(ERROR) << "Callback invoked on an invalid object";
-                    return;
-                }
-                NanDataPathRequestInd hidl_struct;
-                if (!hidl_struct_util::convertLegacyNanDataPathRequestIndToHidl(msg,
-                                                                                &hidl_struct)) {
-                    LOG(ERROR) << "Failed to convert nan capabilities response";
-                    return;
-                }
-
-                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-                    if (!callback->eventDataPathRequest(hidl_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.promote();
-                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                    LOG(ERROR) << "Callback invoked on an invalid object";
-                    return;
-                }
-                V1_6::NanDataPathConfirmInd hidl_struct;
-                if (!hidl_struct_util::convertLegacyNanDataPathConfirmIndToHidl(msg,
-                                                                                &hidl_struct)) {
-                    LOG(ERROR) << "Failed to convert nan capabilities response";
-                    return;
-                }
-
-                for (const auto& callback : shared_ptr_this->getEventCallbacks_1_6()) {
-                    if (!callback->eventDataPathConfirm_1_6(hidl_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.promote();
-                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_beacon_sdf_payload =
-            [weak_ptr_this](const legacy_hal::NanBeaconSdfPayloadInd& /* msg */) {
-                LOG(ERROR) << "on_event_beacon_sdf_payload - should not be called";
-            };
-
-    callback_handlers.on_event_range_request =
-            [weak_ptr_this](const legacy_hal::NanRangeRequestInd& /* msg */) {
-                LOG(ERROR) << "on_event_range_request - should not be called";
-            };
-
-    callback_handlers.on_event_range_report =
-            [weak_ptr_this](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.promote();
-                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                    LOG(ERROR) << "Callback invoked on an invalid object";
-                    return;
-                }
-                V1_6::NanDataPathScheduleUpdateInd hidl_struct;
-                if (!hidl_struct_util::convertLegacyNanDataPathScheduleUpdateIndToHidl(
-                            msg, &hidl_struct)) {
-                    LOG(ERROR) << "Failed to convert nan capabilities response";
-                    return;
-                }
-
-                for (const auto& callback : shared_ptr_this->getEventCallbacks_1_6()) {
-                    if (!callback->eventDataPathScheduleUpdate_1_6(hidl_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.promote();
-        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.
-        WifiNanStatus status = {NanStatusType::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::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();
-    event_cb_handler_1_2_.invalidate();
-    event_cb_handler_1_5_.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<sp<V1_0::IWifiNanIfaceEventCallback>> WifiNanIface::getEventCallbacks() {
-    return event_cb_handler_.getCallbacks();
-}
-
-std::set<sp<V1_2::IWifiNanIfaceEventCallback>> WifiNanIface::getEventCallbacks_1_2() {
-    return event_cb_handler_1_2_.getCallbacks();
-}
-
-std::set<sp<V1_5::IWifiNanIfaceEventCallback>> WifiNanIface::getEventCallbacks_1_5() {
-    return event_cb_handler_1_5_.getCallbacks();
-}
-
-std::set<sp<V1_6::IWifiNanIfaceEventCallback>> WifiNanIface::getEventCallbacks_1_6() {
-    return event_cb_handler_1_6_.getCallbacks();
-}
-
-Return<void> WifiNanIface::getName(getName_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::getNameInternal, hidl_status_cb);
-}
-
-Return<void> WifiNanIface::getType(getType_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::getTypeInternal, hidl_status_cb);
-}
-
-Return<void> WifiNanIface::registerEventCallback(
-        const sp<V1_0::IWifiNanIfaceEventCallback>& callback,
-        registerEventCallback_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::registerEventCallbackInternal, hidl_status_cb, callback);
-}
-
-Return<void> WifiNanIface::getCapabilitiesRequest(uint16_t cmd_id,
-                                                  getCapabilitiesRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::getCapabilitiesRequestInternal, hidl_status_cb, cmd_id);
-}
-
-Return<void> WifiNanIface::enableRequest(uint16_t cmd_id, const V1_0::NanEnableRequest& msg,
-                                         enableRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::enableRequestInternal, hidl_status_cb, cmd_id, msg);
-}
-
-Return<void> WifiNanIface::configRequest(uint16_t cmd_id, const V1_0::NanConfigRequest& msg,
-                                         configRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::configRequestInternal, hidl_status_cb, cmd_id, msg);
-}
-
-Return<void> WifiNanIface::disableRequest(uint16_t cmd_id, disableRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::disableRequestInternal, hidl_status_cb, cmd_id);
-}
-
-Return<void> WifiNanIface::startPublishRequest(uint16_t cmd_id, const V1_0::NanPublishRequest& msg,
-                                               startPublishRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::startPublishRequestInternal, hidl_status_cb, cmd_id, msg);
-}
-
-Return<void> WifiNanIface::stopPublishRequest(uint16_t cmd_id, uint8_t sessionId,
-                                              stopPublishRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::stopPublishRequestInternal, hidl_status_cb, cmd_id,
-                           sessionId);
-}
-
-Return<void> WifiNanIface::startSubscribeRequest(uint16_t cmd_id,
-                                                 const V1_0::NanSubscribeRequest& msg,
-                                                 startSubscribeRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::startSubscribeRequestInternal, hidl_status_cb, cmd_id,
-                           msg);
-}
-
-Return<void> WifiNanIface::stopSubscribeRequest(uint16_t cmd_id, uint8_t sessionId,
-                                                stopSubscribeRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::stopSubscribeRequestInternal, hidl_status_cb, cmd_id,
-                           sessionId);
-}
-
-Return<void> WifiNanIface::transmitFollowupRequest(uint16_t cmd_id,
-                                                   const NanTransmitFollowupRequest& msg,
-                                                   transmitFollowupRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::transmitFollowupRequestInternal, hidl_status_cb, cmd_id,
-                           msg);
-}
-
-Return<void> WifiNanIface::createDataInterfaceRequest(
-        uint16_t cmd_id, const hidl_string& iface_name,
-        createDataInterfaceRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::createDataInterfaceRequestInternal, hidl_status_cb,
-                           cmd_id, iface_name);
-}
-
-Return<void> WifiNanIface::deleteDataInterfaceRequest(
-        uint16_t cmd_id, const hidl_string& iface_name,
-        deleteDataInterfaceRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::deleteDataInterfaceRequestInternal, hidl_status_cb,
-                           cmd_id, iface_name);
-}
-
-Return<void> WifiNanIface::initiateDataPathRequest(uint16_t cmd_id,
-                                                   const V1_0::NanInitiateDataPathRequest& msg,
-                                                   initiateDataPathRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::initiateDataPathRequestInternal, hidl_status_cb, cmd_id,
-                           msg);
-}
-
-Return<void> WifiNanIface::respondToDataPathIndicationRequest(
-        uint16_t cmd_id, const V1_0::NanRespondToDataPathIndicationRequest& msg,
-        respondToDataPathIndicationRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::respondToDataPathIndicationRequestInternal,
-                           hidl_status_cb, cmd_id, msg);
-}
-
-Return<void> WifiNanIface::terminateDataPathRequest(uint16_t cmd_id, uint32_t ndpInstanceId,
-                                                    terminateDataPathRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::terminateDataPathRequestInternal, hidl_status_cb, cmd_id,
-                           ndpInstanceId);
-}
-
-Return<void> WifiNanIface::registerEventCallback_1_2(
-        const sp<V1_2::IWifiNanIfaceEventCallback>& callback,
-        registerEventCallback_1_2_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::registerEventCallback_1_2Internal, hidl_status_cb,
-                           callback);
-}
-
-Return<void> WifiNanIface::enableRequest_1_2(uint16_t cmd_id, const V1_0::NanEnableRequest& msg1,
-                                             const V1_2::NanConfigRequestSupplemental& msg2,
-                                             enableRequest_1_2_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::enableRequest_1_2Internal, hidl_status_cb, cmd_id, msg1,
-                           msg2);
-}
-
-Return<void> WifiNanIface::configRequest_1_2(uint16_t cmd_id, const V1_0::NanConfigRequest& msg1,
-                                             const V1_2::NanConfigRequestSupplemental& msg2,
-                                             configRequest_1_2_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::configRequest_1_2Internal, hidl_status_cb, cmd_id, msg1,
-                           msg2);
-}
-
-Return<void> WifiNanIface::enableRequest_1_4(uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
-                                             const V1_2::NanConfigRequestSupplemental& msg2,
-                                             enableRequest_1_4_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::enableRequest_1_4Internal, hidl_status_cb, cmd_id, msg1,
-                           msg2);
-}
-
-Return<void> WifiNanIface::configRequest_1_4(uint16_t cmd_id, const V1_4::NanConfigRequest& msg1,
-                                             const V1_2::NanConfigRequestSupplemental& msg2,
-                                             configRequest_1_4_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::configRequest_1_4Internal, hidl_status_cb, cmd_id, msg1,
-                           msg2);
-}
-
-Return<void> WifiNanIface::registerEventCallback_1_5(
-        const sp<V1_5::IWifiNanIfaceEventCallback>& callback,
-        registerEventCallback_1_5_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::registerEventCallback_1_5Internal, hidl_status_cb,
-                           callback);
-}
-
-Return<void> WifiNanIface::enableRequest_1_5(uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
-                                             const V1_5::NanConfigRequestSupplemental& msg2,
-                                             enableRequest_1_5_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::enableRequest_1_5Internal, hidl_status_cb, cmd_id, msg1,
-                           msg2);
-}
-
-Return<void> WifiNanIface::configRequest_1_5(uint16_t cmd_id, const V1_4::NanConfigRequest& msg1,
-                                             const V1_5::NanConfigRequestSupplemental& msg2,
-                                             configRequest_1_5_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::configRequest_1_5Internal, hidl_status_cb, cmd_id, msg1,
-                           msg2);
-}
-
-Return<void> WifiNanIface::getCapabilitiesRequest_1_5(
-        uint16_t cmd_id, getCapabilitiesRequest_1_5_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::getCapabilitiesRequest_1_5Internal, hidl_status_cb,
-                           cmd_id);
-}
-
-Return<void> WifiNanIface::enableRequest_1_6(uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
-                                             const V1_6::NanConfigRequestSupplemental& msg2,
-                                             enableRequest_1_5_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::enableRequest_1_6Internal, hidl_status_cb, cmd_id, msg1,
-                           msg2);
-}
-
-Return<void> WifiNanIface::configRequest_1_6(uint16_t cmd_id, const V1_4::NanConfigRequest& msg1,
-                                             const V1_6::NanConfigRequestSupplemental& msg2,
-                                             configRequest_1_5_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::configRequest_1_6Internal, hidl_status_cb, cmd_id, msg1,
-                           msg2);
-}
-
-Return<void> WifiNanIface::initiateDataPathRequest_1_6(uint16_t cmd_id,
-                                                       const V1_6::NanInitiateDataPathRequest& msg,
-                                                       initiateDataPathRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::initiateDataPathRequest_1_6Internal, hidl_status_cb,
-                           cmd_id, msg);
-}
-
-Return<void> WifiNanIface::respondToDataPathIndicationRequest_1_6(
-        uint16_t cmd_id, const V1_6::NanRespondToDataPathIndicationRequest& msg,
-        respondToDataPathIndicationRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::respondToDataPathIndicationRequest_1_6Internal,
-                           hidl_status_cb, cmd_id, msg);
-}
-
-Return<void> WifiNanIface::startPublishRequest_1_6(uint16_t cmd_id,
-                                                   const V1_6::NanPublishRequest& msg,
-                                                   startPublishRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::startPublishRequest_1_6Internal, hidl_status_cb, cmd_id,
-                           msg);
-}
-
-std::pair<WifiStatus, std::string> WifiNanIface::getNameInternal() {
-    return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
-}
-
-std::pair<WifiStatus, IfaceType> WifiNanIface::getTypeInternal() {
-    return {createWifiStatus(WifiStatusCode::SUCCESS), IfaceType::NAN};
-}
-
-Return<void> WifiNanIface::registerEventCallback_1_6(
-        const sp<V1_6::IWifiNanIfaceEventCallback>& callback,
-        registerEventCallback_1_6_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::registerEventCallback_1_6Internal, hidl_status_cb,
-                           callback);
-}
-
-WifiStatus WifiNanIface::registerEventCallbackInternal(
-        const sp<V1_0::IWifiNanIfaceEventCallback>& callback) {
-    if (!event_cb_handler_.addCallback(callback)) {
-        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-    }
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus WifiNanIface::getCapabilitiesRequestInternal(uint16_t /* cmd_id */) {
-    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
-}
-
-WifiStatus WifiNanIface::enableRequestInternal(uint16_t /* cmd_id */,
-                                               const V1_0::NanEnableRequest& /* msg */) {
-    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
-}
-
-WifiStatus WifiNanIface::configRequestInternal(uint16_t /* cmd_id */,
-                                               const V1_0::NanConfigRequest& /* msg */) {
-    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
-}
-
-WifiStatus WifiNanIface::disableRequestInternal(uint16_t cmd_id) {
-    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->nanDisableRequest(ifname_, cmd_id);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiNanIface::startPublishRequestInternal(uint16_t /* cmd_id */,
-                                                     const V1_0::NanPublishRequest& /* msg */) {
-    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
-}
-
-WifiStatus WifiNanIface::stopPublishRequestInternal(uint16_t cmd_id, uint8_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);
-}
-
-WifiStatus WifiNanIface::startSubscribeRequestInternal(uint16_t cmd_id,
-                                                       const V1_0::NanSubscribeRequest& msg) {
-    legacy_hal::NanSubscribeRequest legacy_msg;
-    if (!hidl_struct_util::convertHidlNanSubscribeRequestToLegacy(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);
-}
-
-WifiStatus WifiNanIface::stopSubscribeRequestInternal(uint16_t cmd_id, uint8_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);
-}
-
-WifiStatus WifiNanIface::transmitFollowupRequestInternal(uint16_t cmd_id,
-                                                         const NanTransmitFollowupRequest& msg) {
-    legacy_hal::NanTransmitFollowupRequest legacy_msg;
-    if (!hidl_struct_util::convertHidlNanTransmitFollowupRequestToLegacy(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);
-}
-
-WifiStatus WifiNanIface::createDataInterfaceRequestInternal(uint16_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);
-}
-WifiStatus WifiNanIface::deleteDataInterfaceRequestInternal(uint16_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);
-}
-WifiStatus WifiNanIface::initiateDataPathRequestInternal(
-        uint16_t cmd_id, const V1_0::NanInitiateDataPathRequest& msg) {
-    legacy_hal::NanDataPathInitiatorRequest legacy_msg;
-    if (!hidl_struct_util::convertHidlNanDataPathInitiatorRequestToLegacy(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);
-}
-WifiStatus WifiNanIface::respondToDataPathIndicationRequestInternal(
-        uint16_t cmd_id, const V1_0::NanRespondToDataPathIndicationRequest& msg) {
-    legacy_hal::NanDataPathIndicationResponse legacy_msg;
-    if (!hidl_struct_util::convertHidlNanDataPathIndicationResponseToLegacy(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);
-}
-WifiStatus WifiNanIface::terminateDataPathRequestInternal(uint16_t cmd_id, uint32_t ndpInstanceId) {
-    legacy_hal::wifi_error legacy_status =
-            legacy_hal_.lock()->nanDataEnd(ifname_, cmd_id, ndpInstanceId);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiNanIface::registerEventCallback_1_2Internal(
-        const sp<V1_2::IWifiNanIfaceEventCallback>& callback) {
-    sp<V1_0::IWifiNanIfaceEventCallback> callback_1_0 = callback;
-    if (!event_cb_handler_.addCallback(callback_1_0)) {
-        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-    }
-    if (!event_cb_handler_1_2_.addCallback(callback)) {
-        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-    }
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus WifiNanIface::enableRequest_1_2Internal(
-        uint16_t /* cmd_id */, const V1_0::NanEnableRequest& /* msg1 */,
-        const V1_2::NanConfigRequestSupplemental& /* msg2 */) {
-    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
-}
-
-WifiStatus WifiNanIface::configRequest_1_2Internal(
-        uint16_t /* cmd_id */, const V1_0::NanConfigRequest& /* msg1 */,
-        const V1_2::NanConfigRequestSupplemental& /* msg2 */) {
-    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
-}
-
-WifiStatus WifiNanIface::enableRequest_1_4Internal(
-        uint16_t /* cmd_id */, const V1_4::NanEnableRequest& /* msg1 */,
-        const V1_2::NanConfigRequestSupplemental& /* msg2 */) {
-    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
-}
-
-WifiStatus WifiNanIface::configRequest_1_4Internal(
-        uint16_t /* cmd_id */, const V1_4::NanConfigRequest& /* msg1 */,
-        const V1_2::NanConfigRequestSupplemental& /* msg2 */) {
-    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
-}
-
-WifiStatus WifiNanIface::registerEventCallback_1_5Internal(
-        const sp<V1_5::IWifiNanIfaceEventCallback>& callback) {
-    sp<V1_0::IWifiNanIfaceEventCallback> callback_1_0 = callback;
-    if (!event_cb_handler_.addCallback(callback_1_0)) {
-        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-    }
-    sp<V1_2::IWifiNanIfaceEventCallback> callback_1_2 = callback;
-    if (!event_cb_handler_1_2_.addCallback(callback_1_2)) {
-        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-    }
-    if (!event_cb_handler_1_5_.addCallback(callback)) {
-        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-    }
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus WifiNanIface::getCapabilitiesRequest_1_5Internal(uint16_t cmd_id) {
-    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->nanGetCapabilities(ifname_, cmd_id);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiNanIface::enableRequest_1_5Internal(
-        uint16_t /* cmd_id */, const V1_4::NanEnableRequest& /* msg1 */,
-        const V1_5::NanConfigRequestSupplemental& /* msg2 */) {
-    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
-}
-
-WifiStatus WifiNanIface::configRequest_1_5Internal(
-        uint16_t /* cmd_id */, const V1_4::NanConfigRequest& /* msg1 */,
-        const V1_5::NanConfigRequestSupplemental& /* msg2 */) {
-    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
-}
-
-WifiStatus WifiNanIface::enableRequest_1_6Internal(uint16_t cmd_id,
-                                                   const V1_4::NanEnableRequest& msg1,
-                                                   const V1_6::NanConfigRequestSupplemental& msg2) {
-    legacy_hal::NanEnableRequest legacy_msg;
-    if (!hidl_struct_util::convertHidlNanEnableRequest_1_6ToLegacy(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);
-}
-
-WifiStatus WifiNanIface::configRequest_1_6Internal(uint16_t cmd_id,
-                                                   const V1_4::NanConfigRequest& msg1,
-                                                   const V1_6::NanConfigRequestSupplemental& msg2) {
-    legacy_hal::NanConfigRequest legacy_msg;
-    if (!hidl_struct_util::convertHidlNanConfigRequest_1_6ToLegacy(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);
-}
-
-WifiStatus WifiNanIface::initiateDataPathRequest_1_6Internal(
-        uint16_t cmd_id, const V1_6::NanInitiateDataPathRequest& msg) {
-    legacy_hal::NanDataPathInitiatorRequest legacy_msg;
-    if (!hidl_struct_util::convertHidlNanDataPathInitiatorRequest_1_6ToLegacy(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);
-}
-
-WifiStatus WifiNanIface::respondToDataPathIndicationRequest_1_6Internal(
-        uint16_t cmd_id, const V1_6::NanRespondToDataPathIndicationRequest& msg) {
-    legacy_hal::NanDataPathIndicationResponse legacy_msg;
-    if (!hidl_struct_util::convertHidlNanDataPathIndicationResponse_1_6ToLegacy(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);
-}
-
-WifiStatus WifiNanIface::startPublishRequest_1_6Internal(uint16_t cmd_id,
-                                                         const V1_6::NanPublishRequest& msg) {
-    legacy_hal::NanPublishRequest legacy_msg;
-    if (!hidl_struct_util::convertHidlNanPublishRequestToLegacy(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);
-}
-
-WifiStatus WifiNanIface::registerEventCallback_1_6Internal(
-        const sp<V1_6::IWifiNanIfaceEventCallback>& callback) {
-    sp<V1_0::IWifiNanIfaceEventCallback> callback_1_0 = callback;
-    if (!event_cb_handler_.addCallback(callback_1_0)) {
-        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-    }
-    sp<V1_2::IWifiNanIfaceEventCallback> callback_1_2 = callback;
-    if (!event_cb_handler_1_2_.addCallback(callback_1_2)) {
-        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-    }
-    sp<V1_5::IWifiNanIfaceEventCallback> callback_1_5 = callback;
-    if (!event_cb_handler_1_5_.addCallback(callback_1_5)) {
-        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-    }
-    if (!event_cb_handler_1_6_.addCallback(callback)) {
-        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-    }
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-}  // namespace implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.6/default/wifi_nan_iface.h b/wifi/1.6/default/wifi_nan_iface.h
deleted file mode 100644
index 15bf572..0000000
--- a/wifi/1.6/default/wifi_nan_iface.h
+++ /dev/null
@@ -1,208 +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 WIFI_NAN_IFACE_H_
-#define WIFI_NAN_IFACE_H_
-
-#include <android-base/macros.h>
-#include <android/hardware/wifi/1.6/IWifiNanIface.h>
-#include <android/hardware/wifi/1.6/IWifiNanIfaceEventCallback.h>
-
-#include "hidl_callback_util.h"
-#include "wifi_iface_util.h"
-#include "wifi_legacy_hal.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-using namespace android::hardware::wifi::V1_0;
-using namespace android::hardware::wifi::V1_2;
-using namespace android::hardware::wifi::V1_4;
-using namespace android::hardware::wifi::V1_6;
-
-/**
- * HIDL interface object used to control a NAN Iface instance.
- */
-class WifiNanIface : public V1_6::IWifiNanIface {
-  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);
-    // Refer to |WifiChip::invalidate()|.
-    void invalidate();
-    bool isValid();
-    std::string getName();
-
-    // HIDL methods exposed.
-    Return<void> getName(getName_cb hidl_status_cb) override;
-    Return<void> getType(getType_cb hidl_status_cb) override;
-    Return<void> registerEventCallback(const sp<V1_0::IWifiNanIfaceEventCallback>& callback,
-                                       registerEventCallback_cb hidl_status_cb) override;
-    Return<void> getCapabilitiesRequest(uint16_t cmd_id,
-                                        getCapabilitiesRequest_cb hidl_status_cb) override;
-    Return<void> enableRequest(uint16_t cmd_id, const V1_0::NanEnableRequest& msg,
-                               enableRequest_cb hidl_status_cb) override;
-    Return<void> configRequest(uint16_t cmd_id, const V1_0::NanConfigRequest& msg,
-                               configRequest_cb hidl_status_cb) override;
-    Return<void> disableRequest(uint16_t cmd_id, disableRequest_cb hidl_status_cb) override;
-    Return<void> startPublishRequest(uint16_t cmd_id, const V1_0::NanPublishRequest& msg,
-                                     startPublishRequest_cb hidl_status_cb) override;
-    Return<void> stopPublishRequest(uint16_t cmd_id, uint8_t sessionId,
-                                    stopPublishRequest_cb hidl_status_cb) override;
-    Return<void> startSubscribeRequest(uint16_t cmd_id, const V1_0::NanSubscribeRequest& msg,
-                                       startSubscribeRequest_cb hidl_status_cb) override;
-    Return<void> stopSubscribeRequest(uint16_t cmd_id, uint8_t sessionId,
-                                      stopSubscribeRequest_cb hidl_status_cb) override;
-    Return<void> transmitFollowupRequest(uint16_t cmd_id, const NanTransmitFollowupRequest& msg,
-                                         transmitFollowupRequest_cb hidl_status_cb) override;
-    Return<void> createDataInterfaceRequest(uint16_t cmd_id, const hidl_string& iface_name,
-                                            createDataInterfaceRequest_cb hidl_status_cb) override;
-    Return<void> deleteDataInterfaceRequest(uint16_t cmd_id, const hidl_string& iface_name,
-                                            deleteDataInterfaceRequest_cb hidl_status_cb) override;
-    Return<void> initiateDataPathRequest(uint16_t cmd_id,
-                                         const V1_0::NanInitiateDataPathRequest& msg,
-                                         initiateDataPathRequest_cb hidl_status_cb) override;
-    Return<void> respondToDataPathIndicationRequest(
-            uint16_t cmd_id, const V1_0::NanRespondToDataPathIndicationRequest& msg,
-            respondToDataPathIndicationRequest_cb hidl_status_cb) override;
-    Return<void> terminateDataPathRequest(uint16_t cmd_id, uint32_t ndpInstanceId,
-                                          terminateDataPathRequest_cb hidl_status_cb) override;
-
-    Return<void> registerEventCallback_1_2(const sp<V1_2::IWifiNanIfaceEventCallback>& callback,
-                                           registerEventCallback_1_2_cb hidl_status_cb) override;
-    Return<void> enableRequest_1_2(uint16_t cmd_id, const V1_0::NanEnableRequest& msg1,
-                                   const V1_2::NanConfigRequestSupplemental& msg2,
-                                   enableRequest_1_2_cb hidl_status_cb) override;
-    Return<void> configRequest_1_2(uint16_t cmd_id, const V1_0::NanConfigRequest& msg1,
-                                   const V1_2::NanConfigRequestSupplemental& msg2,
-                                   configRequest_1_2_cb hidl_status_cb) override;
-    Return<void> enableRequest_1_4(uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
-                                   const V1_2::NanConfigRequestSupplemental& msg2,
-                                   enableRequest_1_4_cb hidl_status_cb) override;
-    Return<void> configRequest_1_4(uint16_t cmd_id, const V1_4::NanConfigRequest& msg1,
-                                   const V1_2::NanConfigRequestSupplemental& msg2,
-                                   configRequest_1_4_cb hidl_status_cb) override;
-    Return<void> registerEventCallback_1_5(const sp<V1_5::IWifiNanIfaceEventCallback>& callback,
-                                           registerEventCallback_1_5_cb hidl_status_cb) override;
-    Return<void> enableRequest_1_5(uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
-                                   const V1_5::NanConfigRequestSupplemental& msg2,
-                                   enableRequest_1_5_cb hidl_status_cb) override;
-    Return<void> configRequest_1_5(uint16_t cmd_id, const V1_4::NanConfigRequest& msg1,
-                                   const V1_5::NanConfigRequestSupplemental& msg2,
-                                   configRequest_1_5_cb hidl_status_cb) override;
-    Return<void> getCapabilitiesRequest_1_5(uint16_t cmd_id,
-                                            getCapabilitiesRequest_cb hidl_status_cb) override;
-    Return<void> registerEventCallback_1_6(const sp<V1_6::IWifiNanIfaceEventCallback>& callback,
-                                           registerEventCallback_1_6_cb hidl_status_cb) override;
-    Return<void> initiateDataPathRequest_1_6(
-            uint16_t cmd_id, const V1_6::NanInitiateDataPathRequest& msg,
-            initiateDataPathRequest_1_6_cb hidl_status_cb) override;
-    Return<void> respondToDataPathIndicationRequest_1_6(
-            uint16_t cmd_id, const V1_6::NanRespondToDataPathIndicationRequest& msg,
-            respondToDataPathIndicationRequest_1_6_cb hidl_status_cb) override;
-    Return<void> enableRequest_1_6(uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
-                                   const V1_6::NanConfigRequestSupplemental& msg2,
-                                   enableRequest_1_6_cb hidl_status_cb) override;
-    Return<void> configRequest_1_6(uint16_t cmd_id, const V1_4::NanConfigRequest& msg1,
-                                   const V1_6::NanConfigRequestSupplemental& msg2,
-                                   configRequest_1_6_cb hidl_status_cb) override;
-    Return<void> startPublishRequest_1_6(uint16_t cmd_id, const V1_6::NanPublishRequest& msg,
-                                         startPublishRequest_cb hidl_status_cb) override;
-
-  private:
-    // Corresponding worker functions for the HIDL methods.
-    std::pair<WifiStatus, std::string> getNameInternal();
-    std::pair<WifiStatus, IfaceType> getTypeInternal();
-    WifiStatus registerEventCallbackInternal(const sp<V1_0::IWifiNanIfaceEventCallback>& callback);
-    WifiStatus getCapabilitiesRequestInternal(uint16_t cmd_id);
-    WifiStatus enableRequestInternal(uint16_t cmd_id, const V1_0::NanEnableRequest& msg);
-    WifiStatus configRequestInternal(uint16_t cmd_id, const V1_0::NanConfigRequest& msg);
-    WifiStatus disableRequestInternal(uint16_t cmd_id);
-    WifiStatus startPublishRequestInternal(uint16_t cmd_id, const V1_0::NanPublishRequest& msg);
-    WifiStatus stopPublishRequestInternal(uint16_t cmd_id, uint8_t sessionId);
-    WifiStatus startSubscribeRequestInternal(uint16_t cmd_id, const V1_0::NanSubscribeRequest& msg);
-    WifiStatus stopSubscribeRequestInternal(uint16_t cmd_id, uint8_t sessionId);
-    WifiStatus transmitFollowupRequestInternal(uint16_t cmd_id,
-                                               const NanTransmitFollowupRequest& msg);
-    WifiStatus createDataInterfaceRequestInternal(uint16_t cmd_id, const std::string& iface_name);
-    WifiStatus deleteDataInterfaceRequestInternal(uint16_t cmd_id, const std::string& iface_name);
-    WifiStatus initiateDataPathRequestInternal(uint16_t cmd_id,
-                                               const V1_0::NanInitiateDataPathRequest& msg);
-    WifiStatus respondToDataPathIndicationRequestInternal(
-            uint16_t cmd_id, const V1_0::NanRespondToDataPathIndicationRequest& msg);
-    WifiStatus terminateDataPathRequestInternal(uint16_t cmd_id, uint32_t ndpInstanceId);
-
-    WifiStatus registerEventCallback_1_2Internal(
-            const sp<V1_2::IWifiNanIfaceEventCallback>& callback);
-    WifiStatus enableRequest_1_2Internal(uint16_t cmd_id, const V1_0::NanEnableRequest& msg1,
-                                         const V1_2::NanConfigRequestSupplemental& msg2);
-    WifiStatus configRequest_1_2Internal(uint16_t cmd_id, const V1_0::NanConfigRequest& msg,
-                                         const V1_2::NanConfigRequestSupplemental& msg2);
-    WifiStatus enableRequest_1_4Internal(uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
-                                         const V1_2::NanConfigRequestSupplemental& msg2);
-    WifiStatus configRequest_1_4Internal(uint16_t cmd_id, const V1_4::NanConfigRequest& msg,
-                                         const V1_2::NanConfigRequestSupplemental& msg2);
-    WifiStatus registerEventCallback_1_5Internal(
-            const sp<V1_5::IWifiNanIfaceEventCallback>& callback);
-    WifiStatus enableRequest_1_5Internal(uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
-                                         const V1_5::NanConfigRequestSupplemental& msg2);
-    WifiStatus configRequest_1_5Internal(uint16_t cmd_id, const V1_4::NanConfigRequest& msg,
-                                         const V1_5::NanConfigRequestSupplemental& msg2);
-    WifiStatus getCapabilitiesRequest_1_5Internal(uint16_t cmd_id);
-    WifiStatus registerEventCallback_1_6Internal(
-            const sp<V1_6::IWifiNanIfaceEventCallback>& callback);
-
-    WifiStatus enableRequest_1_6Internal(uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
-                                         const V1_6::NanConfigRequestSupplemental& msg2);
-    WifiStatus configRequest_1_6Internal(uint16_t cmd_id, const V1_4::NanConfigRequest& msg,
-                                         const V1_6::NanConfigRequestSupplemental& msg2);
-    WifiStatus startPublishRequest_1_6Internal(uint16_t cmd_id, const V1_6::NanPublishRequest& msg);
-    WifiStatus initiateDataPathRequest_1_6Internal(uint16_t cmd_id,
-                                                   const V1_6::NanInitiateDataPathRequest& msg);
-    WifiStatus respondToDataPathIndicationRequest_1_6Internal(
-            uint16_t cmd_id, const V1_6::NanRespondToDataPathIndicationRequest& msg);
-
-    // all 1_0 and descendant callbacks
-    std::set<sp<V1_0::IWifiNanIfaceEventCallback>> getEventCallbacks();
-    // all 1_2 and descendant callbacks
-    std::set<sp<V1_2::IWifiNanIfaceEventCallback>> getEventCallbacks_1_2();
-    // all 1_5 and descendant callbacks
-    std::set<sp<V1_5::IWifiNanIfaceEventCallback>> getEventCallbacks_1_5();
-    // all 1_6 and descendant callbacks
-    std::set<sp<V1_6::IWifiNanIfaceEventCallback>> getEventCallbacks_1_6();
-
-    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_;
-    hidl_callback_util::HidlCallbackHandler<V1_0::IWifiNanIfaceEventCallback> event_cb_handler_;
-    hidl_callback_util::HidlCallbackHandler<V1_2::IWifiNanIfaceEventCallback> event_cb_handler_1_2_;
-    hidl_callback_util::HidlCallbackHandler<V1_5::IWifiNanIfaceEventCallback> event_cb_handler_1_5_;
-    hidl_callback_util::HidlCallbackHandler<V1_6::IWifiNanIfaceEventCallback> event_cb_handler_1_6_;
-
-    DISALLOW_COPY_AND_ASSIGN(WifiNanIface);
-};
-
-}  // namespace implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_NAN_IFACE_H_
diff --git a/wifi/1.6/default/wifi_p2p_iface.cpp b/wifi/1.6/default/wifi_p2p_iface.cpp
deleted file mode 100644
index d4b1fca..0000000
--- a/wifi/1.6/default/wifi_p2p_iface.cpp
+++ /dev/null
@@ -1,69 +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.
- */
-
-#include <android-base/logging.h>
-
-#include "hidl_return_util.h"
-#include "wifi_p2p_iface.h"
-#include "wifi_status_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-using hidl_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_;
-}
-
-Return<void> WifiP2pIface::getName(getName_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiP2pIface::getNameInternal, hidl_status_cb);
-}
-
-Return<void> WifiP2pIface::getType(getType_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiP2pIface::getTypeInternal, hidl_status_cb);
-}
-
-std::pair<WifiStatus, std::string> WifiP2pIface::getNameInternal() {
-    return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
-}
-
-std::pair<WifiStatus, IfaceType> WifiP2pIface::getTypeInternal() {
-    return {createWifiStatus(WifiStatusCode::SUCCESS), IfaceType::P2P};
-}
-
-}  // namespace implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.6/default/wifi_p2p_iface.h b/wifi/1.6/default/wifi_p2p_iface.h
deleted file mode 100644
index 0089443..0000000
--- a/wifi/1.6/default/wifi_p2p_iface.h
+++ /dev/null
@@ -1,66 +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 WIFI_P2P_IFACE_H_
-#define WIFI_P2P_IFACE_H_
-
-#include <android-base/macros.h>
-#include <android/hardware/wifi/1.0/IWifiP2pIface.h>
-
-#include "wifi_legacy_hal.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-using namespace android::hardware::wifi::V1_0;
-
-/**
- * HIDL interface object used to control a P2P Iface instance.
- */
-class WifiP2pIface : public V1_0::IWifiP2pIface {
-  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();
-
-    // HIDL methods exposed.
-    Return<void> getName(getName_cb hidl_status_cb) override;
-    Return<void> getType(getType_cb hidl_status_cb) override;
-
-  private:
-    // Corresponding worker functions for the HIDL methods.
-    std::pair<WifiStatus, std::string> getNameInternal();
-    std::pair<WifiStatus, IfaceType> getTypeInternal();
-
-    std::string ifname_;
-    std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
-    bool is_valid_;
-
-    DISALLOW_COPY_AND_ASSIGN(WifiP2pIface);
-};
-
-}  // namespace implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_P2P_IFACE_H_
diff --git a/wifi/1.6/default/wifi_rtt_controller.cpp b/wifi/1.6/default/wifi_rtt_controller.cpp
deleted file mode 100644
index aa9ee2f..0000000
--- a/wifi/1.6/default/wifi_rtt_controller.cpp
+++ /dev/null
@@ -1,377 +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.
- */
-
-#include <android-base/logging.h>
-
-#include "hidl_return_util.h"
-#include "hidl_struct_util.h"
-#include "wifi_rtt_controller.h"
-#include "wifi_status_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-using hidl_return_util::validateAndCall;
-
-WifiRttController::WifiRttController(const std::string& iface_name,
-                                     const sp<IWifiIface>& 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) {}
-
-void WifiRttController::invalidate() {
-    legacy_hal_.reset();
-    event_callbacks_.clear();
-    is_valid_ = false;
-}
-
-bool WifiRttController::isValid() {
-    return is_valid_;
-}
-
-std::vector<sp<V1_6::IWifiRttControllerEventCallback>> WifiRttController::getEventCallbacks() {
-    return event_callbacks_;
-}
-
-std::string WifiRttController::getIfaceName() {
-    return ifname_;
-}
-
-Return<void> WifiRttController::getBoundIface(getBoundIface_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-                           &WifiRttController::getBoundIfaceInternal, hidl_status_cb);
-}
-
-Return<void> WifiRttController::registerEventCallback(
-        const sp<V1_0::IWifiRttControllerEventCallback>& callback,
-        registerEventCallback_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-                           &WifiRttController::registerEventCallbackInternal, hidl_status_cb,
-                           callback);
-}
-
-Return<void> WifiRttController::rangeRequest(uint32_t cmd_id,
-                                             const hidl_vec<V1_0::RttConfig>& rtt_configs,
-                                             rangeRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-                           &WifiRttController::rangeRequestInternal, hidl_status_cb, cmd_id,
-                           rtt_configs);
-}
-
-Return<void> WifiRttController::rangeCancel(uint32_t cmd_id,
-                                            const hidl_vec<hidl_array<uint8_t, 6>>& addrs,
-                                            rangeCancel_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-                           &WifiRttController::rangeCancelInternal, hidl_status_cb, cmd_id, addrs);
-}
-
-Return<void> WifiRttController::getCapabilities(getCapabilities_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-                           &WifiRttController::getCapabilitiesInternal, hidl_status_cb);
-}
-
-Return<void> WifiRttController::setLci(uint32_t cmd_id, const RttLciInformation& lci,
-                                       setLci_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-                           &WifiRttController::setLciInternal, hidl_status_cb, cmd_id, lci);
-}
-
-Return<void> WifiRttController::setLcr(uint32_t cmd_id, const RttLcrInformation& lcr,
-                                       setLcr_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-                           &WifiRttController::setLcrInternal, hidl_status_cb, cmd_id, lcr);
-}
-
-Return<void> WifiRttController::getResponderInfo(getResponderInfo_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-                           &WifiRttController::getResponderInfoInternal, hidl_status_cb);
-}
-
-Return<void> WifiRttController::enableResponder(uint32_t cmd_id,
-                                                const V1_0::WifiChannelInfo& channel_hint,
-                                                uint32_t max_duration_seconds,
-                                                const V1_0::RttResponder& info,
-                                                enableResponder_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-                           &WifiRttController::enableResponderInternal, hidl_status_cb, cmd_id,
-                           channel_hint, max_duration_seconds, info);
-}
-
-Return<void> WifiRttController::disableResponder(uint32_t cmd_id,
-                                                 disableResponder_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-                           &WifiRttController::disableResponderInternal, hidl_status_cb, cmd_id);
-}
-
-Return<void> WifiRttController::registerEventCallback_1_4(
-        const sp<V1_4::IWifiRttControllerEventCallback>& callback,
-        registerEventCallback_1_4_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-                           &WifiRttController::registerEventCallbackInternal_1_4, hidl_status_cb,
-                           callback);
-}
-
-Return<void> WifiRttController::rangeRequest_1_4(uint32_t cmd_id,
-                                                 const hidl_vec<V1_4::RttConfig>& rtt_configs,
-                                                 rangeRequest_1_4_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-                           &WifiRttController::rangeRequestInternal_1_4, hidl_status_cb, cmd_id,
-                           rtt_configs);
-}
-
-Return<void> WifiRttController::getCapabilities_1_4(getCapabilities_1_4_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-                           &WifiRttController::getCapabilitiesInternal_1_4, hidl_status_cb);
-}
-
-Return<void> WifiRttController::getResponderInfo_1_4(getResponderInfo_1_4_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-                           &WifiRttController::getResponderInfoInternal_1_4, hidl_status_cb);
-}
-
-Return<void> WifiRttController::enableResponder_1_4(uint32_t cmd_id,
-                                                    const V1_0::WifiChannelInfo& channel_hint,
-                                                    uint32_t max_duration_seconds,
-                                                    const V1_4::RttResponder& info,
-                                                    enableResponder_1_4_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-                           &WifiRttController::enableResponderInternal_1_4, hidl_status_cb, cmd_id,
-                           channel_hint, max_duration_seconds, info);
-}
-
-Return<void> WifiRttController::registerEventCallback_1_6(
-        const sp<V1_6::IWifiRttControllerEventCallback>& callback,
-        registerEventCallback_1_6_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-                           &WifiRttController::registerEventCallbackInternal_1_6, hidl_status_cb,
-                           callback);
-}
-
-Return<void> WifiRttController::rangeRequest_1_6(uint32_t cmd_id,
-                                                 const hidl_vec<V1_6::RttConfig>& rtt_configs,
-                                                 rangeRequest_1_6_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-                           &WifiRttController::rangeRequestInternal_1_6, hidl_status_cb, cmd_id,
-                           rtt_configs);
-}
-
-Return<void> WifiRttController::getCapabilities_1_6(getCapabilities_1_6_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-                           &WifiRttController::getCapabilitiesInternal_1_6, hidl_status_cb);
-}
-
-Return<void> WifiRttController::getResponderInfo_1_6(getResponderInfo_1_6_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-                           &WifiRttController::getResponderInfoInternal_1_6, hidl_status_cb);
-}
-
-Return<void> WifiRttController::enableResponder_1_6(uint32_t cmd_id,
-                                                    const V1_6::WifiChannelInfo& channel_hint,
-                                                    uint32_t max_duration_seconds,
-                                                    const V1_6::RttResponder& info,
-                                                    enableResponder_1_6_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-                           &WifiRttController::enableResponderInternal_1_6, hidl_status_cb, cmd_id,
-                           channel_hint, max_duration_seconds, info);
-}
-
-std::pair<WifiStatus, sp<IWifiIface>> WifiRttController::getBoundIfaceInternal() {
-    return {createWifiStatus(WifiStatusCode::SUCCESS), bound_iface_};
-}
-
-WifiStatus WifiRttController::registerEventCallbackInternal(
-        const sp<V1_0::IWifiRttControllerEventCallback>& /* callback */) {
-    // Deprecated support for this api
-    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
-}
-
-WifiStatus WifiRttController::rangeRequestInternal(
-        uint32_t /* cmd_id */, const std::vector<V1_0::RttConfig>& /* rtt_configs */) {
-    // Deprecated support for this api
-    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
-}
-
-WifiStatus WifiRttController::rangeCancelInternal(
-        uint32_t cmd_id, const std::vector<hidl_array<uint8_t, 6>>& addrs) {
-    std::vector<std::array<uint8_t, 6>> legacy_addrs;
-    for (const auto& addr : addrs) {
-        legacy_addrs.push_back(addr);
-    }
-    legacy_hal::wifi_error legacy_status =
-            legacy_hal_.lock()->cancelRttRangeRequest(ifname_, cmd_id, legacy_addrs);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, V1_0::RttCapabilities> WifiRttController::getCapabilitiesInternal() {
-    // Deprecated support for this api
-    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
-}
-
-WifiStatus WifiRttController::setLciInternal(uint32_t cmd_id, const RttLciInformation& lci) {
-    legacy_hal::wifi_lci_information legacy_lci;
-    if (!hidl_struct_util::convertHidlRttLciInformationToLegacy(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);
-}
-
-WifiStatus WifiRttController::setLcrInternal(uint32_t cmd_id, const RttLcrInformation& lcr) {
-    legacy_hal::wifi_lcr_information legacy_lcr;
-    if (!hidl_struct_util::convertHidlRttLcrInformationToLegacy(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<WifiStatus, V1_0::RttResponder> WifiRttController::getResponderInfoInternal() {
-    // Deprecated support for this api
-    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
-}
-
-WifiStatus WifiRttController::enableResponderInternal(
-        uint32_t /* cmd_id */, const V1_0::WifiChannelInfo& /* channel_hint */,
-        uint32_t /* max_duration_seconds */, const V1_0::RttResponder& /* info */) {
-    // Deprecated support for this api
-    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED)};
-}
-
-WifiStatus WifiRttController::disableResponderInternal(uint32_t cmd_id) {
-    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->disableRttResponder(ifname_, cmd_id);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiRttController::registerEventCallbackInternal_1_4(
-        const sp<V1_4::IWifiRttControllerEventCallback>& /* callback */) {
-    // Deprecated support for this api
-    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
-}
-
-WifiStatus WifiRttController::rangeRequestInternal_1_4(
-        uint32_t /* cmd_id */, const std::vector<V1_4::RttConfig>& /* rtt_configs */) {
-    // Deprecated support for this api
-    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
-}
-
-std::pair<WifiStatus, V1_4::RttCapabilities> WifiRttController::getCapabilitiesInternal_1_4() {
-    // Deprecated support for this api
-    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
-}
-
-std::pair<WifiStatus, V1_4::RttResponder> WifiRttController::getResponderInfoInternal_1_4() {
-    // Deprecated support for this api
-    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
-}
-
-WifiStatus WifiRttController::enableResponderInternal_1_4(
-        uint32_t /* cmd_id */, const V1_0::WifiChannelInfo& /* channel_hint */,
-        uint32_t /* max_duration_seconds */, const V1_4::RttResponder& /* info */) {
-    // Deprecated support for this api
-    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED)};
-}
-
-WifiStatus WifiRttController::registerEventCallbackInternal_1_6(
-        const sp<V1_6::IWifiRttControllerEventCallback>& callback) {
-    // TODO(b/31632518): remove the callback when the client is destroyed
-    event_callbacks_.emplace_back(callback);
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus WifiRttController::rangeRequestInternal_1_6(
-        uint32_t cmd_id, const std::vector<V1_6::RttConfig>& rtt_configs) {
-    std::vector<legacy_hal::wifi_rtt_config> legacy_configs;
-    if (!hidl_struct_util::convertHidlVectorOfRttConfigToLegacy(rtt_configs, &legacy_configs)) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    android::wp<WifiRttController> weak_ptr_this(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.promote();
-                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                    LOG(ERROR) << "Callback invoked on an invalid object";
-                    return;
-                }
-                std::vector<V1_6::RttResult> hidl_results;
-                if (!hidl_struct_util::convertLegacyVectorOfRttResultToHidl(results,
-                                                                            &hidl_results)) {
-                    LOG(ERROR) << "Failed to convert rtt results to HIDL structs";
-                    return;
-                }
-                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-                    if (!callback->onResults_1_6(id, hidl_results).isOk()) {
-                        LOG(ERROR) << "Failed to invoke the callback";
-                    }
-                }
-            };
-    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->startRttRangeRequest(
-            ifname_, cmd_id, legacy_configs, on_results_callback);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, V1_6::RttCapabilities> WifiRttController::getCapabilitiesInternal_1_6() {
-    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 {createWifiStatusFromLegacyError(legacy_status), {}};
-    }
-    V1_6::RttCapabilities hidl_caps;
-    if (!hidl_struct_util::convertLegacyRttCapabilitiesToHidl(legacy_caps, &hidl_caps)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
-}
-
-std::pair<WifiStatus, V1_6::RttResponder> WifiRttController::getResponderInfoInternal_1_6() {
-    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 {createWifiStatusFromLegacyError(legacy_status), {}};
-    }
-    V1_6::RttResponder hidl_responder;
-    if (!hidl_struct_util::convertLegacyRttResponderToHidl(legacy_responder, &hidl_responder)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_responder};
-}
-
-WifiStatus WifiRttController::enableResponderInternal_1_6(uint32_t cmd_id,
-                                                          const V1_6::WifiChannelInfo& channel_hint,
-                                                          uint32_t max_duration_seconds,
-                                                          const V1_6::RttResponder& info) {
-    legacy_hal::wifi_channel_info legacy_channel_info;
-    if (!hidl_struct_util::convertHidlWifiChannelInfoToLegacy(channel_hint, &legacy_channel_info)) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    legacy_hal::wifi_rtt_responder legacy_responder;
-    if (!hidl_struct_util::convertHidlRttResponderToLegacy(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);
-}
-}  // namespace implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.6/default/wifi_rtt_controller.h b/wifi/1.6/default/wifi_rtt_controller.h
deleted file mode 100644
index fd5f68b..0000000
--- a/wifi/1.6/default/wifi_rtt_controller.h
+++ /dev/null
@@ -1,138 +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 WIFI_RTT_CONTROLLER_H_
-#define WIFI_RTT_CONTROLLER_H_
-
-#include <android-base/macros.h>
-#include <android/hardware/wifi/1.0/IWifiIface.h>
-#include <android/hardware/wifi/1.6/IWifiRttController.h>
-#include <android/hardware/wifi/1.6/IWifiRttControllerEventCallback.h>
-
-#include "wifi_legacy_hal.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-
-/**
- * HIDL interface object used to control all RTT operations.
- */
-class WifiRttController : public V1_6::IWifiRttController {
-  public:
-    WifiRttController(const std::string& iface_name, const sp<IWifiIface>& bound_iface,
-                      const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
-    // Refer to |WifiChip::invalidate()|.
-    void invalidate();
-    bool isValid();
-    std::vector<sp<V1_6::IWifiRttControllerEventCallback>> getEventCallbacks();
-    std::string getIfaceName();
-
-    // HIDL methods exposed.
-    Return<void> getBoundIface(getBoundIface_cb hidl_status_cb) override;
-    Return<void> registerEventCallback(const sp<V1_0::IWifiRttControllerEventCallback>& callback,
-                                       registerEventCallback_cb hidl_status_cb) override;
-    Return<void> rangeRequest(uint32_t cmd_id, const hidl_vec<V1_0::RttConfig>& rtt_configs,
-                              rangeRequest_cb hidl_status_cb) override;
-    Return<void> rangeCancel(uint32_t cmd_id, const hidl_vec<hidl_array<uint8_t, 6>>& addrs,
-                             rangeCancel_cb hidl_status_cb) override;
-    Return<void> getCapabilities(getCapabilities_cb hidl_status_cb) override;
-    Return<void> setLci(uint32_t cmd_id, const RttLciInformation& lci,
-                        setLci_cb hidl_status_cb) override;
-    Return<void> setLcr(uint32_t cmd_id, const RttLcrInformation& lcr,
-                        setLcr_cb hidl_status_cb) override;
-    Return<void> getResponderInfo(getResponderInfo_cb hidl_status_cb) override;
-    Return<void> enableResponder(uint32_t cmd_id, const V1_0::WifiChannelInfo& channel_hint,
-                                 uint32_t max_duration_seconds, const V1_0::RttResponder& info,
-                                 enableResponder_cb hidl_status_cb) override;
-    Return<void> disableResponder(uint32_t cmd_id, disableResponder_cb hidl_status_cb) override;
-    Return<void> registerEventCallback_1_4(
-            const sp<V1_4::IWifiRttControllerEventCallback>& callback,
-            registerEventCallback_1_4_cb hidl_status_cb) override;
-    Return<void> rangeRequest_1_4(uint32_t cmd_id, const hidl_vec<V1_4::RttConfig>& rtt_configs,
-                                  rangeRequest_1_4_cb hidl_status_cb) override;
-    Return<void> getCapabilities_1_4(getCapabilities_1_4_cb hidl_status_cb) override;
-    Return<void> getResponderInfo_1_4(getResponderInfo_1_4_cb hidl_status_cb) override;
-    Return<void> enableResponder_1_4(uint32_t cmd_id, const V1_0::WifiChannelInfo& channel_hint,
-                                     uint32_t max_duration_seconds, const V1_4::RttResponder& info,
-                                     enableResponder_1_4_cb hidl_status_cb) override;
-    Return<void> registerEventCallback_1_6(
-            const sp<V1_6::IWifiRttControllerEventCallback>& callback,
-            registerEventCallback_1_6_cb hidl_status_cb) override;
-    Return<void> rangeRequest_1_6(uint32_t cmd_id, const hidl_vec<V1_6::RttConfig>& rtt_configs,
-                                  rangeRequest_1_6_cb hidl_status_cb) override;
-    Return<void> getCapabilities_1_6(getCapabilities_1_6_cb hidl_status_cb) override;
-    Return<void> getResponderInfo_1_6(getResponderInfo_1_6_cb hidl_status_cb) override;
-    Return<void> enableResponder_1_6(uint32_t cmd_id, const V1_6::WifiChannelInfo& channel_hint,
-                                     uint32_t max_duration_seconds, const V1_6::RttResponder& info,
-                                     enableResponder_1_6_cb hidl_status_cb) override;
-
-  private:
-    // Corresponding worker functions for the HIDL methods.
-    std::pair<WifiStatus, sp<IWifiIface>> getBoundIfaceInternal();
-    WifiStatus registerEventCallbackInternal(
-            const sp<V1_0::IWifiRttControllerEventCallback>& callback);
-    WifiStatus rangeRequestInternal(uint32_t cmd_id,
-                                    const std::vector<V1_0::RttConfig>& rtt_configs);
-    WifiStatus rangeCancelInternal(uint32_t cmd_id,
-                                   const std::vector<hidl_array<uint8_t, 6>>& addrs);
-    std::pair<WifiStatus, V1_0::RttCapabilities> getCapabilitiesInternal();
-    WifiStatus setLciInternal(uint32_t cmd_id, const RttLciInformation& lci);
-    WifiStatus setLcrInternal(uint32_t cmd_id, const RttLcrInformation& lcr);
-    std::pair<WifiStatus, V1_0::RttResponder> getResponderInfoInternal();
-    WifiStatus enableResponderInternal(uint32_t cmd_id, const V1_0::WifiChannelInfo& channel_hint,
-                                       uint32_t max_duration_seconds,
-                                       const V1_0::RttResponder& info);
-    WifiStatus disableResponderInternal(uint32_t cmd_id);
-    WifiStatus registerEventCallbackInternal_1_4(
-            const sp<V1_4::IWifiRttControllerEventCallback>& callback);
-    WifiStatus rangeRequestInternal_1_4(uint32_t cmd_id,
-                                        const std::vector<V1_4::RttConfig>& rtt_configs);
-    std::pair<WifiStatus, V1_4::RttCapabilities> getCapabilitiesInternal_1_4();
-    std::pair<WifiStatus, V1_4::RttResponder> getResponderInfoInternal_1_4();
-    WifiStatus enableResponderInternal_1_4(uint32_t cmd_id,
-                                           const V1_0::WifiChannelInfo& channel_hint,
-                                           uint32_t max_duration_seconds,
-                                           const V1_4::RttResponder& info);
-    WifiStatus registerEventCallbackInternal_1_6(
-            const sp<V1_6::IWifiRttControllerEventCallback>& callback);
-    WifiStatus rangeRequestInternal_1_6(uint32_t cmd_id,
-                                        const std::vector<V1_6::RttConfig>& rtt_configs);
-    std::pair<WifiStatus, V1_6::RttCapabilities> getCapabilitiesInternal_1_6();
-    std::pair<WifiStatus, V1_6::RttResponder> getResponderInfoInternal_1_6();
-    WifiStatus enableResponderInternal_1_6(uint32_t cmd_id,
-                                           const V1_6::WifiChannelInfo& channel_hint,
-                                           uint32_t max_duration_seconds,
-                                           const V1_6::RttResponder& info);
-
-    std::string ifname_;
-    sp<IWifiIface> bound_iface_;
-    std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
-    std::vector<sp<V1_6::IWifiRttControllerEventCallback>> event_callbacks_;
-    bool is_valid_;
-
-    DISALLOW_COPY_AND_ASSIGN(WifiRttController);
-};
-
-}  // namespace implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_RTT_CONTROLLER_H_
diff --git a/wifi/1.6/default/wifi_sta_iface.cpp b/wifi/1.6/default/wifi_sta_iface.cpp
deleted file mode 100644
index dd11839..0000000
--- a/wifi/1.6/default/wifi_sta_iface.cpp
+++ /dev/null
@@ -1,592 +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.
- */
-
-#include <android-base/logging.h>
-
-#include "hidl_return_util.h"
-#include "hidl_struct_util.h"
-#include "wifi_sta_iface.h"
-#include "wifi_status_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-using hidl_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.";
-    }
-}
-
-void WifiStaIface::invalidate() {
-    legacy_hal_.reset();
-    event_cb_handler_.invalidate();
-    is_valid_ = false;
-}
-
-bool WifiStaIface::isValid() {
-    return is_valid_;
-}
-
-std::string WifiStaIface::getName() {
-    return ifname_;
-}
-
-std::set<sp<IWifiStaIfaceEventCallback>> WifiStaIface::getEventCallbacks() {
-    return event_cb_handler_.getCallbacks();
-}
-
-Return<void> WifiStaIface::getName(getName_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::getNameInternal, hidl_status_cb);
-}
-
-Return<void> WifiStaIface::getType(getType_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::getTypeInternal, hidl_status_cb);
-}
-
-Return<void> WifiStaIface::registerEventCallback(const sp<IWifiStaIfaceEventCallback>& callback,
-                                                 registerEventCallback_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::registerEventCallbackInternal, hidl_status_cb, callback);
-}
-
-Return<void> WifiStaIface::getCapabilities(getCapabilities_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::getCapabilitiesInternal, hidl_status_cb);
-}
-
-Return<void> WifiStaIface::getApfPacketFilterCapabilities(
-        getApfPacketFilterCapabilities_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::getApfPacketFilterCapabilitiesInternal, hidl_status_cb);
-}
-
-Return<void> WifiStaIface::installApfPacketFilter(uint32_t cmd_id, const hidl_vec<uint8_t>& program,
-                                                  installApfPacketFilter_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::installApfPacketFilterInternal, hidl_status_cb, cmd_id,
-                           program);
-}
-
-Return<void> WifiStaIface::readApfPacketFilterData(readApfPacketFilterData_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::readApfPacketFilterDataInternal, hidl_status_cb);
-}
-
-Return<void> WifiStaIface::getBackgroundScanCapabilities(
-        getBackgroundScanCapabilities_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::getBackgroundScanCapabilitiesInternal, hidl_status_cb);
-}
-
-Return<void> WifiStaIface::getValidFrequenciesForBand(
-        V1_0::WifiBand band, getValidFrequenciesForBand_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::getValidFrequenciesForBandInternal, hidl_status_cb, band);
-}
-
-Return<void> WifiStaIface::startBackgroundScan(uint32_t cmd_id,
-                                               const StaBackgroundScanParameters& params,
-                                               startBackgroundScan_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::startBackgroundScanInternal, hidl_status_cb, cmd_id,
-                           params);
-}
-
-Return<void> WifiStaIface::stopBackgroundScan(uint32_t cmd_id,
-                                              stopBackgroundScan_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::stopBackgroundScanInternal, hidl_status_cb, cmd_id);
-}
-
-Return<void> WifiStaIface::enableLinkLayerStatsCollection(
-        bool debug, enableLinkLayerStatsCollection_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::enableLinkLayerStatsCollectionInternal, hidl_status_cb,
-                           debug);
-}
-
-Return<void> WifiStaIface::disableLinkLayerStatsCollection(
-        disableLinkLayerStatsCollection_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::disableLinkLayerStatsCollectionInternal, hidl_status_cb);
-}
-
-Return<void> WifiStaIface::getLinkLayerStats(getLinkLayerStats_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::getLinkLayerStatsInternal, hidl_status_cb);
-}
-
-Return<void> WifiStaIface::getLinkLayerStats_1_3(getLinkLayerStats_1_3_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::getLinkLayerStatsInternal_1_3, hidl_status_cb);
-}
-
-Return<void> WifiStaIface::getLinkLayerStats_1_5(getLinkLayerStats_1_5_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::getLinkLayerStatsInternal_1_5, hidl_status_cb);
-}
-
-Return<void> WifiStaIface::getLinkLayerStats_1_6(getLinkLayerStats_1_6_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::getLinkLayerStatsInternal_1_6, hidl_status_cb);
-}
-
-Return<void> WifiStaIface::startRssiMonitoring(uint32_t cmd_id, int32_t max_rssi, int32_t min_rssi,
-                                               startRssiMonitoring_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::startRssiMonitoringInternal, hidl_status_cb, cmd_id,
-                           max_rssi, min_rssi);
-}
-
-Return<void> WifiStaIface::stopRssiMonitoring(uint32_t cmd_id,
-                                              stopRssiMonitoring_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::stopRssiMonitoringInternal, hidl_status_cb, cmd_id);
-}
-
-Return<void> WifiStaIface::getRoamingCapabilities(getRoamingCapabilities_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::getRoamingCapabilitiesInternal, hidl_status_cb);
-}
-
-Return<void> WifiStaIface::configureRoaming(const StaRoamingConfig& config,
-                                            configureRoaming_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::configureRoamingInternal, hidl_status_cb, config);
-}
-
-Return<void> WifiStaIface::setRoamingState(StaRoamingState state,
-                                           setRoamingState_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::setRoamingStateInternal, hidl_status_cb, state);
-}
-
-Return<void> WifiStaIface::enableNdOffload(bool enable, enableNdOffload_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::enableNdOffloadInternal, hidl_status_cb, enable);
-}
-
-Return<void> WifiStaIface::startSendingKeepAlivePackets(
-        uint32_t cmd_id, const hidl_vec<uint8_t>& ip_packet_data, uint16_t ether_type,
-        const hidl_array<uint8_t, 6>& src_address, const hidl_array<uint8_t, 6>& dst_address,
-        uint32_t period_in_ms, startSendingKeepAlivePackets_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::startSendingKeepAlivePacketsInternal, hidl_status_cb,
-                           cmd_id, ip_packet_data, ether_type, src_address, dst_address,
-                           period_in_ms);
-}
-
-Return<void> WifiStaIface::stopSendingKeepAlivePackets(
-        uint32_t cmd_id, stopSendingKeepAlivePackets_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::stopSendingKeepAlivePacketsInternal, hidl_status_cb,
-                           cmd_id);
-}
-
-Return<void> WifiStaIface::setScanningMacOui(const hidl_array<uint8_t, 3>& oui,
-                                             setScanningMacOui_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::setScanningMacOuiInternal, hidl_status_cb, oui);
-}
-
-Return<void> WifiStaIface::startDebugPacketFateMonitoring(
-        startDebugPacketFateMonitoring_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::startDebugPacketFateMonitoringInternal, hidl_status_cb);
-}
-
-Return<void> WifiStaIface::getDebugTxPacketFates(getDebugTxPacketFates_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::getDebugTxPacketFatesInternal, hidl_status_cb);
-}
-
-Return<void> WifiStaIface::getDebugRxPacketFates(getDebugRxPacketFates_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::getDebugRxPacketFatesInternal, hidl_status_cb);
-}
-
-Return<void> WifiStaIface::setMacAddress(const hidl_array<uint8_t, 6>& mac,
-                                         setMacAddress_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::setMacAddressInternal, hidl_status_cb, mac);
-}
-
-Return<void> WifiStaIface::getFactoryMacAddress(getFactoryMacAddress_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::getFactoryMacAddressInternal, hidl_status_cb);
-}
-
-Return<void> WifiStaIface::setScanMode(bool enable, setScanMode_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::setScanModeInternal, hidl_status_cb, enable);
-}
-
-std::pair<WifiStatus, std::string> WifiStaIface::getNameInternal() {
-    return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
-}
-
-std::pair<WifiStatus, IfaceType> WifiStaIface::getTypeInternal() {
-    return {createWifiStatus(WifiStatusCode::SUCCESS), IfaceType::STA};
-}
-
-WifiStatus WifiStaIface::registerEventCallbackInternal(
-        const sp<IWifiStaIfaceEventCallback>& callback) {
-    if (!event_cb_handler_.addCallback(callback)) {
-        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-    }
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-std::pair<WifiStatus, uint32_t> 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 {createWifiStatusFromLegacyError(legacy_status), 0};
-    }
-    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 hidl_caps;
-    if (!hidl_struct_util::convertLegacyFeaturesToHidlStaCapabilities(
-                legacy_feature_set, legacy_logger_feature_set, &hidl_caps)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), 0};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
-}
-
-std::pair<WifiStatus, StaApfPacketFilterCapabilities>
-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 {createWifiStatusFromLegacyError(legacy_status), {}};
-    }
-    StaApfPacketFilterCapabilities hidl_caps;
-    if (!hidl_struct_util::convertLegacyApfCapabilitiesToHidl(legacy_caps, &hidl_caps)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
-}
-
-WifiStatus WifiStaIface::installApfPacketFilterInternal(uint32_t /* cmd_id */,
-                                                        const std::vector<uint8_t>& program) {
-    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->setPacketFilter(ifname_, program);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, std::vector<uint8_t>> WifiStaIface::readApfPacketFilterDataInternal() {
-    const std::pair<legacy_hal::wifi_error, std::vector<uint8_t>> legacy_status_and_data =
-            legacy_hal_.lock()->readApfPacketFilterData(ifname_);
-    return {createWifiStatusFromLegacyError(legacy_status_and_data.first),
-            std::move(legacy_status_and_data.second)};
-}
-
-std::pair<WifiStatus, StaBackgroundScanCapabilities>
-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 {createWifiStatusFromLegacyError(legacy_status), {}};
-    }
-    StaBackgroundScanCapabilities hidl_caps;
-    if (!hidl_struct_util::convertLegacyGscanCapabilitiesToHidl(legacy_caps, &hidl_caps)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
-}
-
-std::pair<WifiStatus, std::vector<WifiChannelInMhz>>
-WifiStaIface::getValidFrequenciesForBandInternal(V1_0::WifiBand band) {
-    static_assert(sizeof(WifiChannelInMhz) == sizeof(uint32_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_, hidl_struct_util::convertHidlWifiBandToLegacy(band));
-    return {createWifiStatusFromLegacyError(legacy_status), valid_frequencies};
-}
-
-WifiStatus WifiStaIface::startBackgroundScanInternal(uint32_t cmd_id,
-                                                     const StaBackgroundScanParameters& params) {
-    legacy_hal::wifi_scan_cmd_params legacy_params;
-    if (!hidl_struct_util::convertHidlGscanParamsToLegacy(params, &legacy_params)) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    android::wp<WifiStaIface> weak_ptr_this(this);
-    const auto& on_failure_callback = [weak_ptr_this](legacy_hal::wifi_request_id id) {
-        const auto shared_ptr_this = weak_ptr_this.promote();
-        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-            LOG(ERROR) << "Callback invoked on an invalid object";
-            return;
-        }
-        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.promote();
-                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                    LOG(ERROR) << "Callback invoked on an invalid object";
-                    return;
-                }
-                std::vector<StaScanData> hidl_scan_datas;
-                if (!hidl_struct_util::convertLegacyVectorOfCachedGscanResultsToHidl(
-                            results, &hidl_scan_datas)) {
-                    LOG(ERROR) << "Failed to convert scan results to HIDL structs";
-                    return;
-                }
-                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-                    if (!callback->onBackgroundScanResults(id, hidl_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.promote();
-        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-            LOG(ERROR) << "Callback invoked on an invalid object";
-            return;
-        }
-        StaScanResult hidl_scan_result;
-        if (!hidl_struct_util::convertLegacyGscanResultToHidl(*result, true, &hidl_scan_result)) {
-            LOG(ERROR) << "Failed to convert full scan results to HIDL structs";
-            return;
-        }
-        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-            if (!callback->onBackgroundFullScanResult(id, buckets_scanned, hidl_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);
-}
-
-WifiStatus WifiStaIface::stopBackgroundScanInternal(uint32_t cmd_id) {
-    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->stopGscan(ifname_, cmd_id);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::enableLinkLayerStatsCollectionInternal(bool debug) {
-    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->enableLinkLayerStats(ifname_, debug);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::disableLinkLayerStatsCollectionInternal() {
-    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->disableLinkLayerStats(ifname_);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, V1_0::StaLinkLayerStats> WifiStaIface::getLinkLayerStatsInternal() {
-    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
-}
-
-std::pair<WifiStatus, V1_3::StaLinkLayerStats> WifiStaIface::getLinkLayerStatsInternal_1_3() {
-    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
-}
-
-std::pair<WifiStatus, V1_5::StaLinkLayerStats> WifiStaIface::getLinkLayerStatsInternal_1_5() {
-    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
-}
-
-std::pair<WifiStatus, V1_6::StaLinkLayerStats> WifiStaIface::getLinkLayerStatsInternal_1_6() {
-    legacy_hal::wifi_error legacy_status;
-    legacy_hal::LinkLayerStats legacy_stats;
-    std::tie(legacy_status, legacy_stats) = legacy_hal_.lock()->getLinkLayerStats(ifname_);
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        return {createWifiStatusFromLegacyError(legacy_status), {}};
-    }
-    V1_6::StaLinkLayerStats hidl_stats;
-    if (!hidl_struct_util::convertLegacyLinkLayerStatsToHidl(legacy_stats, &hidl_stats)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_stats};
-}
-
-WifiStatus WifiStaIface::startRssiMonitoringInternal(uint32_t cmd_id, int32_t max_rssi,
-                                                     int32_t min_rssi) {
-    android::wp<WifiStaIface> weak_ptr_this(this);
-    const auto& on_threshold_breached_callback = [weak_ptr_this](legacy_hal::wifi_request_id id,
-                                                                 std::array<uint8_t, 6> bssid,
-                                                                 int8_t rssi) {
-        const auto shared_ptr_this = weak_ptr_this.promote();
-        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-            LOG(ERROR) << "Callback invoked on an invalid object";
-            return;
-        }
-        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);
-}
-
-WifiStatus WifiStaIface::stopRssiMonitoringInternal(uint32_t cmd_id) {
-    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->stopRssiMonitoring(ifname_, cmd_id);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, StaRoamingCapabilities> 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 {createWifiStatusFromLegacyError(legacy_status), {}};
-    }
-    StaRoamingCapabilities hidl_caps;
-    if (!hidl_struct_util::convertLegacyRoamingCapabilitiesToHidl(legacy_caps, &hidl_caps)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
-}
-
-WifiStatus WifiStaIface::configureRoamingInternal(const StaRoamingConfig& config) {
-    legacy_hal::wifi_roaming_config legacy_config;
-    if (!hidl_struct_util::convertHidlRoamingConfigToLegacy(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);
-}
-
-WifiStatus WifiStaIface::setRoamingStateInternal(StaRoamingState state) {
-    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->enableFirmwareRoaming(
-            ifname_, hidl_struct_util::convertHidlRoamingStateToLegacy(state));
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::enableNdOffloadInternal(bool enable) {
-    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->configureNdOffload(ifname_, enable);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::startSendingKeepAlivePacketsInternal(
-        uint32_t cmd_id, const std::vector<uint8_t>& ip_packet_data, uint16_t ether_type,
-        const std::array<uint8_t, 6>& src_address, const std::array<uint8_t, 6>& dst_address,
-        uint32_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);
-}
-
-WifiStatus WifiStaIface::stopSendingKeepAlivePacketsInternal(uint32_t cmd_id) {
-    legacy_hal::wifi_error legacy_status =
-            legacy_hal_.lock()->stopSendingOffloadedPacket(ifname_, cmd_id);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::setScanningMacOuiInternal(const std::array<uint8_t, 3>& /* oui */) {
-    // deprecated.
-    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
-}
-
-WifiStatus WifiStaIface::startDebugPacketFateMonitoringInternal() {
-    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->startPktFateMonitoring(ifname_);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, std::vector<WifiDebugTxPacketFateReport>>
-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 {createWifiStatusFromLegacyError(legacy_status), {}};
-    }
-    std::vector<WifiDebugTxPacketFateReport> hidl_fates;
-    if (!hidl_struct_util::convertLegacyVectorOfDebugTxPacketFateToHidl(legacy_fates,
-                                                                        &hidl_fates)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_fates};
-}
-
-std::pair<WifiStatus, std::vector<WifiDebugRxPacketFateReport>>
-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 {createWifiStatusFromLegacyError(legacy_status), {}};
-    }
-    std::vector<WifiDebugRxPacketFateReport> hidl_fates;
-    if (!hidl_struct_util::convertLegacyVectorOfDebugRxPacketFateToHidl(legacy_fates,
-                                                                        &hidl_fates)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_fates};
-}
-
-WifiStatus 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 createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-std::pair<WifiStatus, std::array<uint8_t, 6>> 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 {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), mac};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), mac};
-}
-
-WifiStatus 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);
-}
-
-}  // namespace implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.6/default/wifi_sta_iface.h b/wifi/1.6/default/wifi_sta_iface.h
deleted file mode 100644
index c01c50b..0000000
--- a/wifi/1.6/default/wifi_sta_iface.h
+++ /dev/null
@@ -1,157 +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 WIFI_STA_IFACE_H_
-#define WIFI_STA_IFACE_H_
-
-#include <android-base/macros.h>
-#include <android/hardware/wifi/1.0/IWifiStaIfaceEventCallback.h>
-#include <android/hardware/wifi/1.6/IWifiStaIface.h>
-
-#include "hidl_callback_util.h"
-#include "wifi_iface_util.h"
-#include "wifi_legacy_hal.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-using namespace android::hardware::wifi::V1_0;
-
-/**
- * HIDL interface object used to control a STA Iface instance.
- */
-class WifiStaIface : public V1_6::IWifiStaIface {
-  public:
-    WifiStaIface(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<sp<IWifiStaIfaceEventCallback>> getEventCallbacks();
-    std::string getName();
-
-    // HIDL methods exposed.
-    Return<void> getName(getName_cb hidl_status_cb) override;
-    Return<void> getType(getType_cb hidl_status_cb) override;
-    Return<void> registerEventCallback(const sp<IWifiStaIfaceEventCallback>& callback,
-                                       registerEventCallback_cb hidl_status_cb) override;
-    Return<void> getCapabilities(getCapabilities_cb hidl_status_cb) override;
-    Return<void> getApfPacketFilterCapabilities(
-            getApfPacketFilterCapabilities_cb hidl_status_cb) override;
-    Return<void> installApfPacketFilter(uint32_t cmd_id, const hidl_vec<uint8_t>& program,
-                                        installApfPacketFilter_cb hidl_status_cb) override;
-    Return<void> readApfPacketFilterData(readApfPacketFilterData_cb hidl_status_cb) override;
-    Return<void> getBackgroundScanCapabilities(
-            getBackgroundScanCapabilities_cb hidl_status_cb) override;
-    Return<void> getValidFrequenciesForBand(V1_0::WifiBand band,
-                                            getValidFrequenciesForBand_cb hidl_status_cb) override;
-    Return<void> startBackgroundScan(uint32_t cmd_id, const StaBackgroundScanParameters& params,
-                                     startBackgroundScan_cb hidl_status_cb) override;
-    Return<void> stopBackgroundScan(uint32_t cmd_id, stopBackgroundScan_cb hidl_status_cb) override;
-    Return<void> enableLinkLayerStatsCollection(
-            bool debug, enableLinkLayerStatsCollection_cb hidl_status_cb) override;
-    Return<void> disableLinkLayerStatsCollection(
-            disableLinkLayerStatsCollection_cb hidl_status_cb) override;
-    Return<void> getLinkLayerStats(getLinkLayerStats_cb hidl_status_cb) override;
-    Return<void> getLinkLayerStats_1_3(getLinkLayerStats_1_3_cb hidl_status_cb) override;
-    Return<void> getLinkLayerStats_1_5(getLinkLayerStats_1_5_cb hidl_status_cb) override;
-    Return<void> getLinkLayerStats_1_6(getLinkLayerStats_1_6_cb hidl_status_cb) override;
-    Return<void> startRssiMonitoring(uint32_t cmd_id, int32_t max_rssi, int32_t min_rssi,
-                                     startRssiMonitoring_cb hidl_status_cb) override;
-    Return<void> stopRssiMonitoring(uint32_t cmd_id, stopRssiMonitoring_cb hidl_status_cb) override;
-    Return<void> getRoamingCapabilities(getRoamingCapabilities_cb hidl_status_cb) override;
-    Return<void> configureRoaming(const StaRoamingConfig& config,
-                                  configureRoaming_cb hidl_status_cb) override;
-    Return<void> setRoamingState(StaRoamingState state, setRoamingState_cb hidl_status_cb) override;
-    Return<void> enableNdOffload(bool enable, enableNdOffload_cb hidl_status_cb) override;
-    Return<void> startSendingKeepAlivePackets(
-            uint32_t cmd_id, const hidl_vec<uint8_t>& ip_packet_data, uint16_t ether_type,
-            const hidl_array<uint8_t, 6>& src_address, const hidl_array<uint8_t, 6>& dst_address,
-            uint32_t period_in_ms, startSendingKeepAlivePackets_cb hidl_status_cb) override;
-    Return<void> stopSendingKeepAlivePackets(
-            uint32_t cmd_id, stopSendingKeepAlivePackets_cb hidl_status_cb) override;
-    Return<void> setScanningMacOui(const hidl_array<uint8_t, 3>& oui,
-                                   setScanningMacOui_cb hidl_status_cb) override;
-    Return<void> startDebugPacketFateMonitoring(
-            startDebugPacketFateMonitoring_cb hidl_status_cb) override;
-    Return<void> getDebugTxPacketFates(getDebugTxPacketFates_cb hidl_status_cb) override;
-    Return<void> getDebugRxPacketFates(getDebugRxPacketFates_cb hidl_status_cb) override;
-    Return<void> setMacAddress(const hidl_array<uint8_t, 6>& mac,
-                               setMacAddress_cb hidl_status_cb) override;
-    Return<void> getFactoryMacAddress(getFactoryMacAddress_cb hidl_status_cb) override;
-    Return<void> setScanMode(bool enable, setScanMode_cb hidl_status_cb) override;
-
-  private:
-    // Corresponding worker functions for the HIDL methods.
-    std::pair<WifiStatus, std::string> getNameInternal();
-    std::pair<WifiStatus, IfaceType> getTypeInternal();
-    WifiStatus registerEventCallbackInternal(const sp<IWifiStaIfaceEventCallback>& callback);
-    std::pair<WifiStatus, uint32_t> getCapabilitiesInternal();
-    std::pair<WifiStatus, StaApfPacketFilterCapabilities> getApfPacketFilterCapabilitiesInternal();
-    WifiStatus installApfPacketFilterInternal(uint32_t cmd_id, const std::vector<uint8_t>& program);
-    std::pair<WifiStatus, std::vector<uint8_t>> readApfPacketFilterDataInternal();
-    std::pair<WifiStatus, StaBackgroundScanCapabilities> getBackgroundScanCapabilitiesInternal();
-    std::pair<WifiStatus, std::vector<WifiChannelInMhz>> getValidFrequenciesForBandInternal(
-            V1_0::WifiBand band);
-    WifiStatus startBackgroundScanInternal(uint32_t cmd_id,
-                                           const StaBackgroundScanParameters& params);
-    WifiStatus stopBackgroundScanInternal(uint32_t cmd_id);
-    WifiStatus enableLinkLayerStatsCollectionInternal(bool debug);
-    WifiStatus disableLinkLayerStatsCollectionInternal();
-    std::pair<WifiStatus, V1_0::StaLinkLayerStats> getLinkLayerStatsInternal();
-    std::pair<WifiStatus, V1_3::StaLinkLayerStats> getLinkLayerStatsInternal_1_3();
-    std::pair<WifiStatus, V1_5::StaLinkLayerStats> getLinkLayerStatsInternal_1_5();
-    std::pair<WifiStatus, V1_6::StaLinkLayerStats> getLinkLayerStatsInternal_1_6();
-    WifiStatus startRssiMonitoringInternal(uint32_t cmd_id, int32_t max_rssi, int32_t min_rssi);
-    WifiStatus stopRssiMonitoringInternal(uint32_t cmd_id);
-    std::pair<WifiStatus, StaRoamingCapabilities> getRoamingCapabilitiesInternal();
-    WifiStatus configureRoamingInternal(const StaRoamingConfig& config);
-    WifiStatus setRoamingStateInternal(StaRoamingState state);
-    WifiStatus enableNdOffloadInternal(bool enable);
-    WifiStatus startSendingKeepAlivePacketsInternal(uint32_t cmd_id,
-                                                    const std::vector<uint8_t>& ip_packet_data,
-                                                    uint16_t ether_type,
-                                                    const std::array<uint8_t, 6>& src_address,
-                                                    const std::array<uint8_t, 6>& dst_address,
-                                                    uint32_t period_in_ms);
-    WifiStatus stopSendingKeepAlivePacketsInternal(uint32_t cmd_id);
-    WifiStatus setScanningMacOuiInternal(const std::array<uint8_t, 3>& oui);
-    WifiStatus startDebugPacketFateMonitoringInternal();
-    std::pair<WifiStatus, std::vector<WifiDebugTxPacketFateReport>> getDebugTxPacketFatesInternal();
-    std::pair<WifiStatus, std::vector<WifiDebugRxPacketFateReport>> getDebugRxPacketFatesInternal();
-    WifiStatus setMacAddressInternal(const std::array<uint8_t, 6>& mac);
-    std::pair<WifiStatus, std::array<uint8_t, 6>> getFactoryMacAddressInternal();
-    WifiStatus setScanModeInternal(bool enable);
-
-    std::string ifname_;
-    std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
-    std::weak_ptr<iface_util::WifiIfaceUtil> iface_util_;
-    bool is_valid_;
-    hidl_callback_util::HidlCallbackHandler<IWifiStaIfaceEventCallback> event_cb_handler_;
-
-    DISALLOW_COPY_AND_ASSIGN(WifiStaIface);
-};
-
-}  // namespace implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_STA_IFACE_H_
diff --git a/wifi/1.6/default/wifi_status_util.cpp b/wifi/1.6/default/wifi_status_util.cpp
deleted file mode 100644
index 3b18e53..0000000
--- a/wifi/1.6/default/wifi_status_util.cpp
+++ /dev/null
@@ -1,106 +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.
- */
-
-#include "wifi_status_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-
-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";
-    }
-}
-
-WifiStatus createWifiStatus(WifiStatusCode code, const std::string& description) {
-    return {code, description};
-}
-
-WifiStatus createWifiStatus(WifiStatusCode code) {
-    return createWifiStatus(code, "");
-}
-
-WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error, const std::string& desc) {
-    switch (error) {
-        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_NONE:
-            return createWifiStatus(WifiStatusCode::SUCCESS, desc);
-
-        case legacy_hal::WIFI_ERROR_UNKNOWN:
-            return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, "unknown");
-
-        default:
-            return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, "unknown error");
-    }
-}
-
-WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error) {
-    return createWifiStatusFromLegacyError(error, "");
-}
-
-}  // namespace implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.6/default/wifi_status_util.h b/wifi/1.6/default/wifi_status_util.h
deleted file mode 100644
index ea1c294..0000000
--- a/wifi/1.6/default/wifi_status_util.h
+++ /dev/null
@@ -1,44 +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 WIFI_STATUS_UTIL_H_
-#define WIFI_STATUS_UTIL_H_
-
-#include <android/hardware/wifi/1.4/IWifi.h>
-
-#include "wifi_legacy_hal.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_6 {
-namespace implementation {
-using namespace android::hardware::wifi::V1_0;
-
-std::string legacyErrorToString(legacy_hal::wifi_error error);
-WifiStatus createWifiStatus(WifiStatusCode code, const std::string& description);
-WifiStatus createWifiStatus(WifiStatusCode code);
-WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error,
-                                           const std::string& description);
-WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error);
-
-}  // namespace implementation
-}  // namespace V1_6
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_STATUS_UTIL_H_
diff --git a/wifi/1.6/vts/OWNERS b/wifi/1.6/vts/OWNERS
deleted file mode 100644
index 294fc82..0000000
--- a/wifi/1.6/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 33618
-include ../../1.0/vts/OWNERS
diff --git a/wifi/OWNERS b/wifi/OWNERS
new file mode 100644
index 0000000..c10bbab
--- /dev/null
+++ b/wifi/OWNERS
@@ -0,0 +1,10 @@
+# Bug component: 33618
+
+# Please assign all bugs related to /hardware/interfaces/wifi to the team alias:
+#
+#    android-wifi-team@google.com
+#
+# This will get them auto-assigned to the on-call triage engineer, ensuring quickest response.
+#
+arabawy@google.com
+etancohen@google.com
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..07612b6
--- /dev/null
+++ b/wifi/aidl/default/aidl_struct_util.cpp
@@ -0,0 +1,2775 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 convertLegacyLinkLayerStatsToAidl(const legacy_hal::LinkLayerStats& legacy_stats,
+                                       StaLinkLayerStats* aidl_stats) {
+    if (!aidl_stats) {
+        return false;
+    }
+    *aidl_stats = {};
+    // iface legacy_stats conversion.
+    aidl_stats->iface.beaconRx = legacy_stats.iface.beacon_rx;
+    aidl_stats->iface.avgRssiMgmt = legacy_stats.iface.rssi_mgmt;
+    aidl_stats->iface.wmeBePktStats.rxMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu;
+    aidl_stats->iface.wmeBePktStats.txMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu;
+    aidl_stats->iface.wmeBePktStats.lostMpdu =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost;
+    aidl_stats->iface.wmeBePktStats.retries = legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries;
+    aidl_stats->iface.wmeBeContentionTimeStats.contentionTimeMinInUsec =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_min;
+    aidl_stats->iface.wmeBeContentionTimeStats.contentionTimeMaxInUsec =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_max;
+    aidl_stats->iface.wmeBeContentionTimeStats.contentionTimeAvgInUsec =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_avg;
+    aidl_stats->iface.wmeBeContentionTimeStats.contentionNumSamples =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_num_samples;
+    aidl_stats->iface.wmeBkPktStats.rxMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu;
+    aidl_stats->iface.wmeBkPktStats.txMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu;
+    aidl_stats->iface.wmeBkPktStats.lostMpdu =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost;
+    aidl_stats->iface.wmeBkPktStats.retries = legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries;
+    aidl_stats->iface.wmeBkContentionTimeStats.contentionTimeMinInUsec =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_min;
+    aidl_stats->iface.wmeBkContentionTimeStats.contentionTimeMaxInUsec =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_max;
+    aidl_stats->iface.wmeBkContentionTimeStats.contentionTimeAvgInUsec =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_avg;
+    aidl_stats->iface.wmeBkContentionTimeStats.contentionNumSamples =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_num_samples;
+    aidl_stats->iface.wmeViPktStats.rxMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu;
+    aidl_stats->iface.wmeViPktStats.txMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu;
+    aidl_stats->iface.wmeViPktStats.lostMpdu =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost;
+    aidl_stats->iface.wmeViPktStats.retries = legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries;
+    aidl_stats->iface.wmeViContentionTimeStats.contentionTimeMinInUsec =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_min;
+    aidl_stats->iface.wmeViContentionTimeStats.contentionTimeMaxInUsec =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_max;
+    aidl_stats->iface.wmeViContentionTimeStats.contentionTimeAvgInUsec =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_avg;
+    aidl_stats->iface.wmeViContentionTimeStats.contentionNumSamples =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_num_samples;
+    aidl_stats->iface.wmeVoPktStats.rxMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu;
+    aidl_stats->iface.wmeVoPktStats.txMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu;
+    aidl_stats->iface.wmeVoPktStats.lostMpdu =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost;
+    aidl_stats->iface.wmeVoPktStats.retries = legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries;
+    aidl_stats->iface.wmeVoContentionTimeStats.contentionTimeMinInUsec =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_min;
+    aidl_stats->iface.wmeVoContentionTimeStats.contentionTimeMaxInUsec =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_max;
+    aidl_stats->iface.wmeVoContentionTimeStats.contentionTimeAvgInUsec =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_avg;
+    aidl_stats->iface.wmeVoContentionTimeStats.contentionNumSamples =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_num_samples;
+    aidl_stats->iface.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);
+    }
+    aidl_stats->iface.peers = aidl_peers_info_stats;
+    // 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);
+}
+
+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;
+    }
+    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 = 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;
+
+    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 = 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);
+    }
+
+    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 = 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;
+
+    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);
+    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;
+    };
+    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;
+    };
+    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_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;
+}
+
+}  // 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..4ebfc10
--- /dev/null
+++ b/wifi/aidl/default/aidl_struct_util.h
@@ -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.
+ */
+
+#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 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);
+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);
+}  // 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..4a69c24
--- /dev/null
+++ b/wifi/aidl/default/tests/aidl_struct_util_unit_tests.cpp
@@ -0,0 +1,485 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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";
+}  // 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, 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(legacy_stats.iface.beacon_rx, (uint32_t)converted.iface.beaconRx);
+    EXPECT_EQ(legacy_stats.iface.rssi_mgmt, converted.iface.avgRssiMgmt);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu,
+              converted.iface.wmeBePktStats.rxMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu,
+              converted.iface.wmeBePktStats.txMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost,
+              converted.iface.wmeBePktStats.lostMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries,
+              converted.iface.wmeBePktStats.retries);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_min,
+              (uint32_t)converted.iface.wmeBeContentionTimeStats.contentionTimeMinInUsec);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_max,
+              (uint32_t)converted.iface.wmeBeContentionTimeStats.contentionTimeMaxInUsec);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_avg,
+              (uint32_t)converted.iface.wmeBeContentionTimeStats.contentionTimeAvgInUsec);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_num_samples,
+              (uint32_t)converted.iface.wmeBeContentionTimeStats.contentionNumSamples);
+
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu,
+              converted.iface.wmeBkPktStats.rxMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu,
+              converted.iface.wmeBkPktStats.txMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost,
+              converted.iface.wmeBkPktStats.lostMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries,
+              converted.iface.wmeBkPktStats.retries);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_min,
+              (uint32_t)converted.iface.wmeBkContentionTimeStats.contentionTimeMinInUsec);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_max,
+              (uint32_t)converted.iface.wmeBkContentionTimeStats.contentionTimeMaxInUsec);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_avg,
+              (uint32_t)converted.iface.wmeBkContentionTimeStats.contentionTimeAvgInUsec);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_num_samples,
+              (uint32_t)converted.iface.wmeBkContentionTimeStats.contentionNumSamples);
+
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu,
+              converted.iface.wmeViPktStats.rxMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu,
+              converted.iface.wmeViPktStats.txMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost,
+              converted.iface.wmeViPktStats.lostMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries,
+              converted.iface.wmeViPktStats.retries);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_min,
+              (uint32_t)converted.iface.wmeViContentionTimeStats.contentionTimeMinInUsec);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_max,
+              (uint32_t)converted.iface.wmeViContentionTimeStats.contentionTimeMaxInUsec);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_avg,
+              (uint32_t)converted.iface.wmeViContentionTimeStats.contentionTimeAvgInUsec);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_num_samples,
+              (uint32_t)converted.iface.wmeViContentionTimeStats.contentionNumSamples);
+
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu,
+              converted.iface.wmeVoPktStats.rxMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu,
+              converted.iface.wmeVoPktStats.txMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost,
+              converted.iface.wmeVoPktStats.lostMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries,
+              converted.iface.wmeVoPktStats.retries);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_min,
+              (uint32_t)converted.iface.wmeVoContentionTimeStats.contentionTimeMinInUsec);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_max,
+              (uint32_t)converted.iface.wmeVoContentionTimeStats.contentionTimeMaxInUsec);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_avg,
+              (uint32_t)converted.iface.wmeVoContentionTimeStats.contentionTimeAvgInUsec);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_num_samples,
+              (uint32_t)converted.iface.wmeVoContentionTimeStats.contentionNumSamples);
+
+    EXPECT_EQ(legacy_stats.iface.info.time_slicing_duty_cycle_percent,
+              converted.iface.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.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.peers[i].staCount);
+        EXPECT_EQ(legacy_stats.peers[i].peer_info.bssload.chan_util,
+                  converted.iface.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.peers[i].rateStats[j].rateInfo.preamble);
+            EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rate.nss,
+                      (uint32_t)converted.iface.peers[i].rateStats[j].rateInfo.nss);
+            EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rate.bw,
+                      (uint32_t)converted.iface.peers[i].rateStats[j].rateInfo.bw);
+            EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rate.rateMcsIdx,
+                      (uint32_t)converted.iface.peers[i].rateStats[j].rateInfo.rateMcsIdx);
+            EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].tx_mpdu,
+                      (uint32_t)converted.iface.peers[i].rateStats[j].txMpdu);
+            EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rx_mpdu,
+                      (uint32_t)converted.iface.peers[i].rateStats[j].rxMpdu);
+            EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].mpdu_lost,
+                      (uint32_t)converted.iface.peers[i].rateStats[j].mpduLost);
+            EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].retries,
+                      (uint32_t)converted.iface.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);
+}
+
+}  // 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..d40801f
--- /dev/null
+++ b/wifi/aidl/default/tests/wifi_nan_iface_unit_tests.cpp
@@ -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.
+ */
+
+#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&));
+};
+
+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..076f351
--- /dev/null
+++ b/wifi/aidl/default/wifi_chip.cpp
@@ -0,0 +1,1910 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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);
+}
+
+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()};
+}
+
+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..59eaa4a
--- /dev/null
+++ b/wifi/aidl/default/wifi_chip.h
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+    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();
+    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..43e73ca
--- /dev/null
+++ b/wifi/aidl/default/wifi_legacy_hal.cpp
@@ -0,0 +1,1654 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 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;
+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);
+        on_rtt_results_internal_callback = nullptr;
+    }
+}
+
+// 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);
+    }
+}
+
+// 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);
+}
+
+std::pair<wifi_error, LinkLayerStats> WifiLegacyHal::getLinkLayerStats(
+        const std::string& iface_name) {
+    LinkLayerStats link_stats{};
+    LinkLayerStats* link_stats_ptr = &link_stats;
+
+    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;
+
+        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));
+        }
+    };
+
+    wifi_error status = global_func_table_.wifi_get_link_stats(0, getIfaceHandle(iface_name),
+                                                               {onSyncLinkLayerStatsResult});
+    on_link_layer_stats_result_internal_callback = nullptr;
+    return {status, link_stats};
+}
+
+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) {
+    if (on_rtt_results_internal_callback) {
+        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);
+    };
+
+    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});
+    if (status != WIFI_SUCCESS) {
+        on_rtt_results_internal_callback = nullptr;
+    }
+    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) {
+        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) {
+        on_rtt_results_internal_callback = nullptr;
+    }
+    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_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});
+}
+
+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);
+}
+
+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;
+}
+
+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_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;
+    on_rtt_results_internal_callback = nullptr;
+    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_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..cd8c0b1
--- /dev/null
+++ b/wifi/aidl/default/wifi_legacy_hal.h
@@ -0,0 +1,738 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 ::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_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_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_NDP_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 ::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 ::NanMatchAlg;
+using ::NanMatchExpiredInd;
+using ::NanMatchInd;
+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 ::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 ::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_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_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_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;
+};
+#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;
+};
+
+// 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*>&)>;
+
+// 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);
+    std::pair<wifi_error, LinkLayerStats> getLinkLayerStats(const std::string& iface_name);
+    // 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);
+    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 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);
+
+  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);
+
+    // 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..cff7f69
--- /dev/null
+++ b/wifi/aidl/default/wifi_legacy_hal_stubs.cpp
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_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);
+    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..9edef09
--- /dev/null
+++ b/wifi/aidl/default/wifi_nan_iface.cpp
@@ -0,0 +1,751 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_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_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);
+}
+
+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);
+}
+
+}  // 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..1018905
--- /dev/null
+++ b/wifi/aidl/default/wifi_nan_iface.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+  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);
+
+    // 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..856c3cd
--- /dev/null
+++ b/wifi/aidl/default/wifi_rtt_controller.cpp
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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";
+                    }
+                }
+            };
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->startRttRangeRequest(
+            ifname_, cmd_id, legacy_configs, on_results_callback);
+    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..ce90349
--- /dev/null
+++ b/wifi/aidl/default/wifi_sta_iface.cpp
@@ -0,0 +1,558 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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);
+}
+
+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;
+    std::tie(legacy_status, legacy_stats) = legacy_hal_.lock()->getLinkLayerStats(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {StaLinkLayerStats{}, createWifiStatusFromLegacyError(legacy_status)};
+    }
+    StaLinkLayerStats aidl_stats;
+    if (!aidl_struct_util::convertLegacyLinkLayerStatsToAidl(legacy_stats, &aidl_stats)) {
+        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);
+}
+
+}  // 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..8ac3470
--- /dev/null
+++ b/wifi/aidl/default/wifi_sta_iface.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+  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);
+
+    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..6722f36
--- /dev/null
+++ b/wifi/aidl/vts/functional/wifi_aidl_test_utils.cpp
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+}
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..ad16603
--- /dev/null
+++ b/wifi/aidl/vts/functional/wifi_aidl_test_utils.h
@@ -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.
+ */
+
+#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);
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..457d57a
--- /dev/null
+++ b/wifi/aidl/vts/functional/wifi_nan_iface_aidl_test.cpp
@@ -0,0 +1,627 @@
+/*
+ * 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::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::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,
+
+        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,
+    };
+
+    // 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 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();
+        }
+
+      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 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_;
+
+    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..ef7e274
--- /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.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
new file mode 100644
index 0000000..e1fefb9
--- /dev/null
+++ b/wifi/apex/Android.bp
@@ -0,0 +1,55 @@
+package {
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+apex_key {
+    name: "com.android.hardware.wifi.key",
+    public_key: "com.android.hardware.wifi.avbpubkey",
+    private_key: "com.android.hardware.wifi.pem",
+}
+
+android_app_certificate {
+    name: "com.android.hardware.wifi.certificate",
+    certificate: "com.android.hardware.wifi",
+}
+
+genrule {
+    name: "gen-android.hardware.wifi.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)",
+}
+
+prebuilt_etc {
+    name: "com.android.hardware.wifi.rc",
+    src: ":gen-android.hardware.wifi.rc",
+    installable: false,
+}
+
+prebuilt_etc {
+    name: "com.android.hardware.wifi.xml",
+    src: ":default-android.hardware.wifi-service.xml",
+    installable: false,
+}
+
+apex {
+    name: "com.android.hardware.wifi",
+    manifest: "apex_manifest.json",
+    key: "com.android.hardware.wifi.key",
+    certificate: ":com.android.hardware.wifi.certificate",
+    file_contexts: "file_contexts",
+    vintf_fragments: [":com.android.hardware.wifi.xml"],
+    use_vndk_as_stable: true,
+    updatable: false,
+    soc_specific: true,
+    binaries: [
+        "android.hardware.wifi-service",
+    ],
+    prebuilts: [
+        "com.android.hardware.wifi.rc",
+        "com.android.hardware.wifi.xml",
+    ],
+    overrides: [
+        "android.hardware.wifi-service",
+    ],
+}
diff --git a/wifi/apex/apex_manifest.json b/wifi/apex/apex_manifest.json
new file mode 100644
index 0000000..cab0814
--- /dev/null
+++ b/wifi/apex/apex_manifest.json
@@ -0,0 +1,4 @@
+{
+    "name": "com.android.hardware.wifi",
+    "version": 1
+}
diff --git a/wifi/apex/com.android.hardware.wifi.avbpubkey b/wifi/apex/com.android.hardware.wifi.avbpubkey
new file mode 100644
index 0000000..63fba77
--- /dev/null
+++ b/wifi/apex/com.android.hardware.wifi.avbpubkey
Binary files differ
diff --git a/wifi/apex/com.android.hardware.wifi.pem b/wifi/apex/com.android.hardware.wifi.pem
new file mode 100644
index 0000000..9e589ac
--- /dev/null
+++ b/wifi/apex/com.android.hardware.wifi.pem
@@ -0,0 +1,52 @@
+-----BEGIN PRIVATE KEY-----
+MIIJRAIBADANBgkqhkiG9w0BAQEFAASCCS4wggkqAgEAAoICAQCtT/vNnVVg2QVD
+eMdG+YZ8qYz/fbAQF9hnH8dE5RWHXzoYItBG7DSOuVT4T6POBVmFaVKlWDd7tDyw
+nFO3MmE2/FzhVSiBPwhMITa7UIERr3od3rWJ5g6oaTCOu4wa98L466Jp60f2fYSZ
+M9lGiKaDpLDSpxTU9hexjp7C4PfinnkYnlHBnrFXTmiO6f8AvOEwFFx73/rUNoe7
+F3TkGvjZDqHvE+pjz/nilkhXYuOl3zgSaeznJ9+TO5C/Z+Xr+zRhaJGI4v5Dkgmc
+jNy74+0hjwobXO3iWE44InQMvMh8zDKBx9l1oSsFoG3waj9ayqSYD7M74RX3PkUL
+QrhgAHZWi5iEnpu50xBzAqZB1ZDVkdZiKiGzweJ8OqltnVpvzlnW3rA3y3HtFyLm
+73C4ll9MdLaw266vBxgZfFOcjpphbbh9J9uGjOCJY1AxUzsqKygFD2CyOdb1jab3
+AC6VvRa+bLtv8fd2etp3atXv+Y9ACUX6zNK6Oa8Zktoo2Z//OLtcrk7xhgKKDkUF
+OPQrIjW9x0fdClDioIS+y7EHNUrfyRL7XPtUqGCszgz5jK2SMVGMpFaEtfbyNP1H
+BTGXdzcDP0RZdOOKTdBFgoRW5+6TH5CU9Nl4uevpxzwsTkXg0a+W1BGP+s9J7ssH
+rNPmHz+pbKZPDs/nxlpsKq+N+K8cCwIDAQABAoICAAJL943Lgnikl53DyXxGzUH0
+q0Itg7pK3prLQIRItubS2727JGB0O+QST650u7p8tql+clJvn1ib1FwQzkk0uTYV
+1RNFYiKIV89Od1+3GubFmQwxSd2Yd2RC9JpHoP0wgFx1HvNhY1RAaJPxLHVzVSWU
+dqVsAmoqErlPJwp1GcPejsNFQdcbh8Uc7GTMdA0p86AD/Q/FMZlDWbwgfPOS6e5S
+c9HrxSTqeijHDhFeZZ7qnN8dmT6c+CkG1o26zkC41QJfdOJIA8+YbVkuQrSYuilC
+MIOZUSu5ONwklL4geFWzDQ5MPDUDXEMYU6ymc817tv+u4ZSvEG/02sxh53iaOPc6
+C6im4nm6ZlRP9HzIvLAiRSbvwEb9cnLKgYpioSGXehDYg3zMPURwoqIxw+7IlIUh
+s+rhmCJV62PK1Z0nmo7m7S8r+z6j4G7aztGcbvdecocOJYOQB1VB8Zh4bNEIWp0a
+GDteG6aWXOCHoYRWAOluppDWa7Z+EgesU3Oj9Prn/ekUzzXx3V30zSTZYxRnQCO0
+vZIZ6hrlsNJcNrDpxmiWBaEOd4k5QI39pu6fDHc+UEEJMN+7eVk8d9QVA/LhrCjc
+JH1EVjtWosMUeMaMTpcmHTQKnEvmT2LO2fxGlF4JvjzDdVMloJrIP2LSQjovo2PX
+x9UXVu8Dt3kQRefZ42XxAoIBAQDkBoSYVajaFlyv9lW8oPmrQyzp93ite+TKVR8z
+PmcFQukjp5Gm8PGlGtGoH8aeE9Ev+R86aNPFy4n4ZJ7fmZYH1hxZ6dSc/56k6lLn
+uVKvTudYqwcRgBKuSZ8IDPFz3sHd+MnOBonDIri28fcBTDNv4LJP/6cAUoIOCCPm
+lQtJBfMNMDOXG4jv1Rv/1P5opGFATerRCubOxmeaFhZIDEjvN5WvLK5jmL7I8lX3
+X+gPiMHFWBQFmVTOHeVYEORDO5xFCOvHqCVB78b2xe1NkkrQ0CexpdflJVLE9IWt
+wWH43nhjxaK+eiBPrj37BliJvNaYfuxqcAj3p8c5KweFEtP7AoIBAQDCkx72K/Ja
+rFrrI0Avfo+3n6yoTMtMkiVhMuIKKPBJ2o4Opc/uixk+uLH5UH0X5GZsE51FAhUD
+L3bWMxV+vzVefWS8Iryo94ucvnfqhsN3KZXHDGoAuYv72jND8qPLKksM0dceMBfl
+aoyXSPAe8zAZeEx4iR2axgtnA0EbiXIaNVE/LF+WYdM74jvk/QtRzJ8IAAkSc5Rr
+GiTHeeP3nRnkjWjkmwKXYSJHcrEl26c/2ckeZORtblqxR9wMU5OgvJvMSzmOIpVH
+Y5lylZUOTuJCkApHFNKdRsawsSNKsy4yfY1byN/WkODb7le6Crt1gcwldMxDZAo9
+iB25FHq4zksxAoIBAQC+SBYkDO9PtnN4PycCto5B9VeokmN42bdthKT5nSxY/qIQ
+p8fquIvdzEiCdKnIxh69WrVNh6aZGyWySz0suDyzo1+bRH6w2LrpQcUXK9YtBroV
+ivrmBqsQF82G6U4f9BZxhifZLimN1g6wU7Bcu9r8lFQYX+1bXn66+N4EkAGP2VAe
+hEe45Dhccsjfrzzx06J4B81YzjEXAgf4VFAZpW7DeO4G9VE9OXyTsW49dSHwvJ1+
+ceabWX2kVtxIpiflVvwru6sNvGoC4PV2fmptXhPitqE5JHzJ8mBkjOx0t7hq9jMe
+hxEsxDrsYynDrWL65cNqFBhzJbTF/ZNJSHgI+1I7AoIBAQC7m0shJOJ61vCbA9Qh
+dzBvZn/9jn3/CHMOMxeLoEl/jEGokevZHzlqJn9D2n2jCdBPqOHc5dMIzT0R7xNs
+sERvJQx58ixh5r0wlt3cva++N9R4pdmXdVApuAvyGgQgIllWtQVr0AdaZs/EFsmf
+re/Uvw9MsThgQVBBNPwT5wSjjIEYHlrUDuKzPMFvWyUM6/Tyq8YTimmykvSfeUF7
+QHj0y/w1X9ixyTBaH5X64L10bTLkIXe2o87CXH0pTXRsaS73XhjSmTnCKaCMwPmF
+YD383BFs1AD3MITnXQSgQ//pIvGnbBmXMv38UOU5NpvlAw+pleJVoCHXjmTKTZq+
+kfohAoIBAQCrEecN8XEPjGdtY71rDYEwHGM6G4czHX0PNhlMjQos3aBVZ/YvVxPG
+pkXbms3GRXv4W92u7b2MwEKBPxcBepEdDZN9wSpe63bDFE6gpkipDhgj97JlLEUd
+s7h6oOoazdxmsRZyFho99SRQWrvyOiiKdLJCRZiqjUB4roOQmy7f9VAz6+OxyGV9
+XZigwW6bfUzMCmhx5Ss6zW8wZI+gINQh+2sDmiBiMQv14Ya5zlNYN+4/257Sk/jS
+o3QUDJITbReq/DNZ6UUzQS+AZ7ztc81rk5kRg0I33FZarRJ7TLAz+XmZZFoIOORz
+etEvMk8bJ4u7X89NWW/i2J+kQiDQg819
+-----END PRIVATE KEY-----
diff --git a/wifi/apex/com.android.hardware.wifi.pk8 b/wifi/apex/com.android.hardware.wifi.pk8
new file mode 100644
index 0000000..f4481bf
--- /dev/null
+++ b/wifi/apex/com.android.hardware.wifi.pk8
Binary files differ
diff --git a/wifi/apex/com.android.hardware.wifi.x509.pem b/wifi/apex/com.android.hardware.wifi.x509.pem
new file mode 100644
index 0000000..c942e71
--- /dev/null
+++ b/wifi/apex/com.android.hardware.wifi.x509.pem
@@ -0,0 +1,36 @@
+-----BEGIN CERTIFICATE-----
+MIIGOzCCBCOgAwIBAgIUIEueuBFEoCFmLyEvXDsKVuZeH0EwDQYJKoZIhvcNAQEL
+BQAwgasxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQH
+DA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYDVQQLDAdBbmRy
+b2lkMScwJQYDVQQDDB5jb20uYW5kcm9pZC5oYXJkd2FyZS53aWZpLmFwZXgxIjAg
+BgkqhkiG9w0BCQEWE2FuZHJvaWRAYW5kcm9pZC5jb20wIBcNMjIxMDA2MTY1MDQy
+WhgPNDc2MDA5MDExNjUwNDJaMIGrMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2Fs
+aWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEQMA4GA1UECgwHQW5kcm9p
+ZDEQMA4GA1UECwwHQW5kcm9pZDEnMCUGA1UEAwweY29tLmFuZHJvaWQuaGFyZHdh
+cmUud2lmaS5hcGV4MSIwIAYJKoZIhvcNAQkBFhNhbmRyb2lkQGFuZHJvaWQuY29t
+MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAo4N23iL0J42qG2lt4ysD
+t6XxAKdi4sTWB6ZjFWerBm11s3yLr1KBZV82z3j2o7+EOaWa/91Mgc+aoiGYUa1f
+IweugKTrnRmrzOvtq/Wp5PGqSxsmLPPvH3wyEB/CMgAn0pqDf0WyCWJ2kAlcCkmy
+qVNFupkGFyIE6gkoc+AmJGbSTquDlL07R/8XYDicqrcgeqy9ZaCJ5FLfmbnnRb2A
+vm4Un7e5dFz5+dPaOJXf4AOMUSPUd7fuBliGYFLzcZnYQbzMktXa4XnPuSlmerwy
+EwY767L2bjRjaSgPb0Js13gZ4S4ZHZe07AV7HPlt/EzbxV/jtMgHl4xn5p0WhVnK
+MPtLsO/e7FkDPAKpT02sgUK6pVKqgBGOWm27tmTB09lscMLQeVFqwpoFq2zMUrDn
+ipDFMWRBeLrEDKx41zF3gqdPmP+SMkQYJu4OATIXOndIeo7AN9iE+N6snHkckNyE
+saCwmnzyhVAbMn/epfIQZz3zcyljA9yfOpv5jctN4es+3i0htDnoNO9ij4M5fxuP
+jtNAP3EA61nKZ5+Js0/MMQKrfwCLogPl/4vCNuuGT2rhCkhq1CLYXmb9ghvVzcPe
+BOGXNDKdB+aUTxrQUOYlHf0cRDHdU6cchrz9+QhR7t9dlibtiyCZE34xgR3klmyz
+XJ3M1r/QRihjARH7exrrwiUCAwEAAaNTMFEwHQYDVR0OBBYEFGN9tMk+4SDk7twk
+MrLjM+nRxGDJMB8GA1UdIwQYMBaAFGN9tMk+4SDk7twkMrLjM+nRxGDJMA8GA1Ud
+EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIBAHoTfVBRG0rVE7gkV526gwR5
+/3mXyYA57lKJhZ21fu2qfTE6WYj4DsOTZKrPIAUFv/SnzZ6Rvv7W81XV5M/1m+5R
+/1wYvWwm3FBOvvt4VDUiel0Zfc9+nwynjz1seYdXU8fNIOzBcr9hutkYdRZDkNpc
+Zcl4NG04TzyedkQ/0SyHnygmq4ZY9OUEvrNaWBFHzw2SQhYvHh8jUrqpPvoJz0Px
+avKI8bOgXTJRJ+Pk7hjXDFQY/fbE0RGivorPMLs+XHaEIb+YPyXsX4OZwowG5KL8
+txyvUsH+qZToytdPk4LCuwYBobBlr+AAg7pxOtbDW1ITDhQ9n05UFK2iUwsJecgg
+VDA0K3GuCjmGVmkw7SFRYfToCyGWah8sQCUMCCcsof7gS+dMxuWeee+sRxRJcJY+
+xR2uySe8g4ohwNjQ0zLQv7PZOKQh91yEWxRXmhPYVpiVAjpSD2zH7Vd6CJ9xji//
+5S1UrxWwQ5igvu8v5veqNAW7uXGXADnxL69HVGTLm0XDIUUOAUIG8waiVkYUo3UU
+AzAFbF7ewYMKdg7ylUYcTaMRIsKYW/3/1t3NJv2z99W4V/p8e1kRCeWMPB5C+/Lo
+b/hSWj1NF9AJ30ukBndMh6bRprq+G5NLV6OaoCLp606CMdXdT8uw9lYCt7DbQHG9
+Hw3iw61svpUwcaWfN1hI
+-----END CERTIFICATE-----
diff --git a/wifi/apex/file_contexts b/wifi/apex/file_contexts
new file mode 100644
index 0000000..6368729
--- /dev/null
+++ b/wifi/apex/file_contexts
@@ -0,0 +1,3 @@
+(/.*)? 								u:object_r:vendor_file:s0
+/bin/hw/android\.hardware\.wifi-service			u:object_r:hal_wifi_default_exec:s0
+
diff --git a/wifi/hostapd/1.0/vts/OWNERS b/wifi/hostapd/1.0/vts/OWNERS
deleted file mode 100644
index 287152d..0000000
--- a/wifi/hostapd/1.0/vts/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 33618
-arabawy@google.com
-etancohen@google.com
diff --git a/wifi/hostapd/1.1/vts/OWNERS b/wifi/hostapd/1.1/vts/OWNERS
deleted file mode 100644
index 294fc82..0000000
--- a/wifi/hostapd/1.1/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 33618
-include ../../1.0/vts/OWNERS
diff --git a/wifi/hostapd/1.2/vts/OWNERS b/wifi/hostapd/1.2/vts/OWNERS
deleted file mode 100644
index 294fc82..0000000
--- a/wifi/hostapd/1.2/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 33618
-include ../../1.0/vts/OWNERS
diff --git a/wifi/hostapd/1.3/vts/OWNERS b/wifi/hostapd/1.3/vts/OWNERS
deleted file mode 100644
index 294fc82..0000000
--- a/wifi/hostapd/1.3/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 33618
-include ../../1.0/vts/OWNERS
diff --git a/wifi/hostapd/aidl/vts/OWNERS b/wifi/hostapd/aidl/vts/OWNERS
deleted file mode 100644
index 2a7a7b0..0000000
--- a/wifi/hostapd/aidl/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-etancohen@google.com
-lzye@google.com
diff --git a/wifi/hostapd/aidl/vts/functional/Android.bp b/wifi/hostapd/aidl/vts/functional/Android.bp
index e61d397..a9fdec8 100644
--- a/wifi/hostapd/aidl/vts/functional/Android.bp
+++ b/wifi/hostapd/aidl/vts/functional/Android.bp
@@ -20,20 +20,10 @@
         "libvndksupport",
     ],
     static_libs: [
+        "android.hardware.wifi-V1-ndk",
         "android.hardware.wifi.hostapd-V1-ndk",
-        "VtsHalWifiV1_0TargetTestUtil",
-        "VtsHalWifiV1_5TargetTestUtil",
-        "VtsHalWifiHostapdV1_0TargetTestUtil",
-        "android.hardware.wifi.hostapd@1.0",
-        "android.hardware.wifi.hostapd@1.1",
-        "android.hardware.wifi.hostapd@1.2",
-        "android.hardware.wifi.hostapd@1.3",
-        "android.hardware.wifi@1.0",
-        "android.hardware.wifi@1.1",
-        "android.hardware.wifi@1.2",
-        "android.hardware.wifi@1.3",
-        "android.hardware.wifi@1.4",
-        "android.hardware.wifi@1.5",
+        "libwifi-system-iface",
+        "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..65ffa7b 100644
--- a/wifi/hostapd/aidl/vts/functional/VtsHalHostapdTargetTest.cpp
+++ b/wifi/hostapd/aidl/vts/functional/VtsHalHostapdTargetTest.cpp
@@ -13,8 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#include <android/hardware/wifi/1.0/IWifi.h>
-#include <android/hardware/wifi/hostapd/1.3/IHostapd.h>
+#include <aidl/android/hardware/wifi/IWifi.h>
 
 #include <VtsCoreUtil.h>
 #include <aidl/Gtest.h>
@@ -24,12 +23,11 @@
 #include <android/binder_manager.h>
 #include <binder/IServiceManager.h>
 #include <binder/ProcessState.h>
-#include <hidl/ServiceManagement.h>
-#include <hostapd_hidl_call_util.h>
-#include <hostapd_hidl_test_utils.h>
-#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::IWifi;
+using aidl::android::hardware::wifi::IWifiApIface;
 using aidl::android::hardware::wifi::hostapd::BandMask;
 using aidl::android::hardware::wifi::hostapd::BnHostapdCallback;
 using aidl::android::hardware::wifi::hostapd::ChannelBandwidth;
@@ -44,6 +42,8 @@
 using android::ProcessState;
 
 namespace {
+const std::string kWifiInstanceNameStr = std::string() + IWifi::descriptor + "/default";
+const char* kWifiInstanceName = kWifiInstanceNameStr.c_str();
 const unsigned char kNwSsid[] = {'t', 'e', 's', 't', '1', '2', '3', '4', '5'};
 const std::string kPassphrase = "test12345";
 const std::string kInvalidMinPassphrase = "test";
@@ -75,17 +75,13 @@
             "/system/bin/cmd wifi get-softap-supported-features",
             "wifi_softap_wpa3_sae_supported");
         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];
+                "/system/bin/cmd wifi get-softap-supported-features",
+                "wifi_softap_bridged_ap_supported");
     }
 
     virtual void TearDown() override {
-        if (getWifi(wifiInstanceName) != nullptr) {
-            stopWifi(wifiInstanceName);
+        if (getWifi(kWifiInstanceName) != nullptr) {
+            stopWifiService(kWifiInstanceName);
         }
         hostapd->terminate();
         //  Wait 3 seconds to allow terminate to complete
@@ -93,24 +89,23 @@
     }
 
     std::shared_ptr<IHostapd> hostapd;
-    std::string wifiInstanceName;
     bool isAcsSupport;
     bool isWpa3SaeSupport;
     bool isBridgedSupport;
 
     std::string setupApIfaceAndGetName(bool isBridged) {
-        android::sp<::android::hardware::wifi::V1_0::IWifiApIface> wifi_ap_iface;
+        std::shared_ptr<IWifiApIface> wifi_ap_iface;
         if (isBridged) {
-            wifi_ap_iface = getBridgedWifiApIface_1_5(wifiInstanceName);
+            wifi_ap_iface = getBridgedWifiApIface(kWifiInstanceName);
         } else {
-            wifi_ap_iface = getWifiApIface_1_5(wifiInstanceName);
+            wifi_ap_iface = getWifiApIface(kWifiInstanceName);
         }
         EXPECT_NE(nullptr, wifi_ap_iface.get());
 
-        const auto& status_and_name = HIDL_INVOKE(wifi_ap_iface, getName);
-        EXPECT_EQ(android::hardware::wifi::V1_0::WifiStatusCode::SUCCESS,
-                  status_and_name.first.code);
-        return status_and_name.second;
+        std::string ap_iface_name;
+        auto status = wifi_ap_iface->getName(&ap_iface_name);
+        EXPECT_TRUE(status.isOk());
+        return ap_iface_name;
     }
 
     IfaceParams getIfaceParamsWithoutAcs(std::string iface_name) {
diff --git a/wifi/netlinkinterceptor/aidl/default/InterceptorRelay.cpp b/wifi/netlinkinterceptor/aidl/default/InterceptorRelay.cpp
index ded9122..e84a5cf 100644
--- a/wifi/netlinkinterceptor/aidl/default/InterceptorRelay.cpp
+++ b/wifi/netlinkinterceptor/aidl/default/InterceptorRelay.cpp
@@ -28,7 +28,7 @@
 using namespace std::chrono_literals;
 
 static constexpr std::chrono::milliseconds kPollTimeout = 300ms;
-static constexpr bool kSuperVerbose = true;
+static constexpr bool kSuperVerbose = false;
 
 InterceptorRelay::InterceptorRelay(uint32_t nlFamily, uint32_t clientNlPid,
                                    const std::string& clientName)
diff --git a/wifi/netlinkinterceptor/aidl/default/OWNERS b/wifi/netlinkinterceptor/aidl/default/OWNERS
deleted file mode 100644
index b738dac..0000000
--- a/wifi/netlinkinterceptor/aidl/default/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-chrisweir@google.com
-twasilczyk@google.com
diff --git a/wifi/netlinkinterceptor/libnlinterceptor/Android.bp b/wifi/netlinkinterceptor/libnlinterceptor/Android.bp
index 00cae32..671cd85 100644
--- a/wifi/netlinkinterceptor/libnlinterceptor/Android.bp
+++ b/wifi/netlinkinterceptor/libnlinterceptor/Android.bp
@@ -37,10 +37,8 @@
         "libutils",
     ],
     sanitize: {
-        address: true,
         undefined: true,
         all_undefined: true,
-        fuzzer: true,
         cfi: true,
         integer_overflow: true,
         scs: true,
diff --git a/wifi/netlinkinterceptor/vts/OWNERS b/wifi/netlinkinterceptor/vts/OWNERS
deleted file mode 100644
index b738dac..0000000
--- a/wifi/netlinkinterceptor/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-chrisweir@google.com
-twasilczyk@google.com
diff --git a/wifi/offload/1.0/vts/OWNERS b/wifi/offload/1.0/vts/OWNERS
deleted file mode 100644
index 287152d..0000000
--- a/wifi/offload/1.0/vts/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 33618
-arabawy@google.com
-etancohen@google.com
diff --git a/wifi/supplicant/1.0/vts/OWNERS b/wifi/supplicant/1.0/vts/OWNERS
deleted file mode 100644
index b16dc11..0000000
--- a/wifi/supplicant/1.0/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 33618
-include ../../1.3/vts/OWNERS
diff --git a/wifi/supplicant/1.1/vts/OWNERS b/wifi/supplicant/1.1/vts/OWNERS
deleted file mode 100644
index b16dc11..0000000
--- a/wifi/supplicant/1.1/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 33618
-include ../../1.3/vts/OWNERS
diff --git a/wifi/supplicant/1.2/vts/OWNERS b/wifi/supplicant/1.2/vts/OWNERS
deleted file mode 100644
index b16dc11..0000000
--- a/wifi/supplicant/1.2/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 33618
-include ../../1.3/vts/OWNERS
diff --git a/wifi/supplicant/1.4/vts/OWNERS b/wifi/supplicant/1.4/vts/OWNERS
deleted file mode 100644
index b16dc11..0000000
--- a/wifi/supplicant/1.4/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 33618
-include ../../1.3/vts/OWNERS
diff --git a/wifi/supplicant/OWNERS b/wifi/supplicant/OWNERS
deleted file mode 100644
index 7febd60..0000000
--- a/wifi/supplicant/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-# Bug component: 33618
-arabawy@google.com
-etancohen@google.com
-gbiren@google.com
-lzye@google.com
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl
index 8d9f498..da3ca52 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl
@@ -52,4 +52,5 @@
   oneway void onStaDeauthorized(in byte[] srcAddress, in byte[] p2pDeviceAddress);
   oneway void onGroupFrequencyChanged(in String groupIfname, in int frequency);
   oneway void onDeviceFoundWithVendorElements(in byte[] srcAddress, in byte[] p2pDeviceAddress, in byte[] primaryDeviceType, in String deviceName, in android.hardware.wifi.supplicant.WpsConfigMethods configMethods, in byte deviceCapabilities, in android.hardware.wifi.supplicant.P2pGroupCapabilityMask groupCapabilities, in byte[] wfdDeviceInfo, in byte[] wfdR2DeviceInfo, in byte[] vendorElemBytes);
+  oneway void onGroupStartedWithParams(in android.hardware.wifi.supplicant.P2pGroupStartedEventParams groupStartedEventParams);
 }
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..c7dd584 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
@@ -63,4 +63,5 @@
   oneway void onWpsEventSuccess();
   oneway void onQosPolicyReset();
   oneway void onQosPolicyRequest(in int qosPolicyRequestId, in android.hardware.wifi.supplicant.QosPolicyData[] qosPolicyData);
+  oneway void onStateChangedWithAkm(in android.hardware.wifi.supplicant.StaIfaceCallbackState newState, in byte[] bssid, in int id, in byte[] ssid, in boolean filsHlpSent, in android.hardware.wifi.supplicant.KeyMgmtMask keyMgmtMask);
 }
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 0b3cb81..0bdec34 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
@@ -127,6 +127,7 @@
   void setWepKey(in int keyIdx, in byte[] wepKey);
   void setWepTxKeyIdx(in int keyIdx);
   void setRoamingConsortiumSelection(in byte[] selectedRcoi);
+  void setMinimumTlsVersionEapPhase1Param(android.hardware.wifi.supplicant.TlsVersion tlsVersion);
   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/P2pGroupStartedEventParams.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pGroupStartedEventParams.aidl
new file mode 100644
index 0000000..19611a9
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pGroupStartedEventParams.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.wifi.supplicant;
+@VintfStability
+parcelable P2pGroupStartedEventParams {
+  String groupInterfaceName;
+  boolean isGroupOwner;
+  byte[] ssid;
+  int frequencyMHz;
+  byte[] psk;
+  String passphrase;
+  boolean isPersistent;
+  byte[] goDeviceAddress;
+  byte[] goInterfaceAddress;
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/TlsVersion.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/TlsVersion.aidl
new file mode 100644
index 0000000..22a374f
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/TlsVersion.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.supplicant;
+@Backing(type="int") @VintfStability
+enum TlsVersion {
+  TLS_V1_0 = 0,
+  TLS_V1_1 = 1,
+  TLS_V1_2 = 2,
+  TLS_V1_3 = 3,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpaDriverCapabilitiesMask.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpaDriverCapabilitiesMask.aidl
index 9a0a924..32e1510 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpaDriverCapabilitiesMask.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpaDriverCapabilitiesMask.aidl
@@ -39,4 +39,6 @@
   SAE_PK = 4,
   WFD_R2 = 8,
   TRUST_ON_FIRST_USE = 16,
+  SET_TLS_MINIMUM_VERSION = 32,
+  TLS_V1_3 = 64,
 }
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl
index 7c8c1f2..9d6fa67 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl
@@ -17,6 +17,7 @@
 package android.hardware.wifi.supplicant;
 
 import android.hardware.wifi.supplicant.P2pGroupCapabilityMask;
+import android.hardware.wifi.supplicant.P2pGroupStartedEventParams;
 import android.hardware.wifi.supplicant.P2pProvDiscStatusCode;
 import android.hardware.wifi.supplicant.P2pStatusCode;
 import android.hardware.wifi.supplicant.WpsConfigMethods;
@@ -243,4 +244,11 @@
             in byte[] primaryDeviceType, in String deviceName, in WpsConfigMethods configMethods,
             in byte deviceCapabilities, in P2pGroupCapabilityMask groupCapabilities,
             in byte[] wfdDeviceInfo, in byte[] wfdR2DeviceInfo, in byte[] vendorElemBytes);
+
+    /**
+     * Used to indicate the start of a P2P group, with some parameters describing the group.
+     *
+     * @param groupStartedEventParams Parameters describing the P2P group.
+     */
+    void onGroupStartedWithParams(in P2pGroupStartedEventParams groupStartedEventParams);
 }
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
index 0730a8c..c7961fa 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
@@ -27,6 +27,7 @@
 import android.hardware.wifi.supplicant.DppFailureCode;
 import android.hardware.wifi.supplicant.DppProgressCode;
 import android.hardware.wifi.supplicant.Hs20AnqpData;
+import android.hardware.wifi.supplicant.KeyMgmtMask;
 import android.hardware.wifi.supplicant.OsuMethod;
 import android.hardware.wifi.supplicant.QosPolicyData;
 import android.hardware.wifi.supplicant.StaIfaceCallbackState;
@@ -252,6 +253,8 @@
      * 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>
+     * This callback is deprecated from AIDL v2, newer HAL should call onStateChangedWithAkm().
      *
      * @param newState New State of the interface. This must be one of the |State|
      *        values above.
@@ -303,4 +306,27 @@
      * @param qosPolicyData QoS policies info requested by the AP.
      */
     void onQosPolicyRequest(in int qosPolicyRequestId, in QosPolicyData[] qosPolicyData);
+
+    /**
+     * Used to indicate a state change event on this particular iface. If this
+     * event is triggered by a particular network, the |id|,
+     * |ssid|, |bssid| parameters must indicate the parameters of the network/AP
+     * which caused this state transition.
+     *
+     * @param newState New State of the interface. This must be one of the
+     *        |StaIfaceCallbackState| values above.
+     * @param bssid 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.
+     * @param id 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.
+     * @param ssid 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.
+     * @param filsHlpSent Whether FILS HLP IEs were included in this association.
+     * @param keyMgmtMask current used key mgmt mask.
+     */
+    void onStateChangedWithAkm(in StaIfaceCallbackState newState, in byte[] bssid, in int id,
+            in byte[] ssid, in boolean filsHlpSent, in KeyMgmtMask keyMgmtMask);
 }
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl
index 267f1e8..44512a9 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl
@@ -31,6 +31,7 @@
 import android.hardware.wifi.supplicant.PairwiseCipherMask;
 import android.hardware.wifi.supplicant.ProtoMask;
 import android.hardware.wifi.supplicant.SaeH2eMode;
+import android.hardware.wifi.supplicant.TlsVersion;
 
 /**
  * Interface exposed by the supplicant for each station mode network
@@ -1118,4 +1119,16 @@
      *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
      */
     void setRoamingConsortiumSelection(in byte[] selectedRcoi);
+
+    /**
+     * Set the minimum TLS version for EAP phase1 param.
+     *
+     * @param tlsVersion the TLS version
+     *
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void setMinimumTlsVersionEapPhase1Param(TlsVersion tlsVersion);
 }
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pGroupStartedEventParams.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pGroupStartedEventParams.aidl
new file mode 100644
index 0000000..a04153a
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pGroupStartedEventParams.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.supplicant;
+
+/**
+ * Parameters passed as part of Wifi P2P group start event.
+ */
+@VintfStability
+parcelable P2pGroupStartedEventParams {
+    /** Interface name of the group (For ex: p2p-p2p0-1). */
+    String groupInterfaceName;
+
+    /** Whether this device is owner of the group. */
+    boolean isGroupOwner;
+
+    /** SSID of the group. */
+    byte[] ssid;
+
+    /** Frequency in MHz on which this group is created. */
+    int frequencyMHz;
+
+    /** PSK used to secure the group. */
+    byte[] psk;
+
+    /** PSK passphrase used to secure the group. */
+    String passphrase;
+
+    /** Whether this group is persisted or not. */
+    boolean isPersistent;
+
+    /** MAC Address of the owner of this group. */
+    byte[/* 6 */] goDeviceAddress;
+
+    /** MAC Address of the P2P interface of the owner of this group. */
+    byte[/* 6 */] goInterfaceAddress;
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/TlsVersion.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/TlsVersion.aidl
new file mode 100644
index 0000000..316e881
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/TlsVersion.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.wifi.supplicant;
+
+/**
+ * TlsVersion: TLS version.
+ */
+@VintfStability
+@Backing(type="int")
+enum TlsVersion {
+    TLS_V1_0,
+    TLS_V1_1,
+    TLS_V1_2,
+    TLS_V1_3,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WpaDriverCapabilitiesMask.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WpaDriverCapabilitiesMask.aidl
index 08006cf..a9434c4 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WpaDriverCapabilitiesMask.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WpaDriverCapabilitiesMask.aidl
@@ -42,4 +42,12 @@
      * Trust On First Use
      */
     TRUST_ON_FIRST_USE = 1 << 4,
+    /**
+     * TLS minimum version
+     */
+    SET_TLS_MINIMUM_VERSION = 1 << 5,
+    /**
+     * TLS V1.3
+     */
+    TLS_V1_3 = 1 << 6,
 }
diff --git a/wifi/supplicant/aidl/vts/functional/Android.bp b/wifi/supplicant/aidl/vts/functional/Android.bp
index 8e142ec..937fdc7 100644
--- a/wifi/supplicant/aidl/vts/functional/Android.bp
+++ b/wifi/supplicant/aidl/vts/functional/Android.bp
@@ -36,20 +36,11 @@
         "libvndksupport",
     ],
     static_libs: [
-        "android.hardware.wifi@1.0",
-        "android.hardware.wifi@1.1",
-        "android.hardware.wifi@1.2",
-        "android.hardware.wifi@1.3",
-        "android.hardware.wifi@1.4",
-        "android.hardware.wifi@1.5",
-        "android.hardware.wifi.supplicant@1.0",
-        "android.hardware.wifi.supplicant@1.1",
-        "android.hardware.wifi.supplicant-V1-ndk",
+        "android.hardware.wifi-V1-ndk",
+        "android.hardware.wifi.supplicant-V2-ndk",
         "libwifi-system",
         "libwifi-system-iface",
-        "VtsHalWifiV1_0TargetTestUtil",
-        "VtsHalWifiV1_5TargetTestUtil",
-        "VtsHalWifiSupplicantV1_0TargetTestUtil",
+        "VtsHalWifiTargetTestUtil",
     ],
     test_suites: [
         "general-tests",
@@ -70,20 +61,11 @@
         "libvndksupport",
     ],
     static_libs: [
-        "android.hardware.wifi@1.0",
-        "android.hardware.wifi@1.1",
-        "android.hardware.wifi@1.2",
-        "android.hardware.wifi@1.3",
-        "android.hardware.wifi@1.4",
-        "android.hardware.wifi@1.5",
-        "android.hardware.wifi.supplicant@1.0",
-        "android.hardware.wifi.supplicant@1.1",
-        "android.hardware.wifi.supplicant-V1-ndk",
+        "android.hardware.wifi-V1-ndk",
+        "android.hardware.wifi.supplicant-V2-ndk",
         "libwifi-system",
         "libwifi-system-iface",
-        "VtsHalWifiV1_0TargetTestUtil",
-        "VtsHalWifiV1_5TargetTestUtil",
-        "VtsHalWifiSupplicantV1_0TargetTestUtil",
+        "VtsHalWifiTargetTestUtil",
     ],
     test_suites: [
         "general-tests",
@@ -104,20 +86,11 @@
         "libvndksupport",
     ],
     static_libs: [
-        "android.hardware.wifi@1.0",
-        "android.hardware.wifi@1.1",
-        "android.hardware.wifi@1.2",
-        "android.hardware.wifi@1.3",
-        "android.hardware.wifi@1.4",
-        "android.hardware.wifi@1.5",
-        "android.hardware.wifi.supplicant@1.0",
-        "android.hardware.wifi.supplicant@1.1",
-        "android.hardware.wifi.supplicant-V1-ndk",
+        "android.hardware.wifi-V1-ndk",
+        "android.hardware.wifi.supplicant-V2-ndk",
         "libwifi-system",
         "libwifi-system-iface",
-        "VtsHalWifiV1_0TargetTestUtil",
-        "VtsHalWifiV1_5TargetTestUtil",
-        "VtsHalWifiSupplicantV1_0TargetTestUtil",
+        "VtsHalWifiTargetTestUtil",
     ],
     test_suites: [
         "general-tests",
diff --git a/wifi/supplicant/aidl/vts/functional/supplicant_p2p_iface_aidl_test.cpp b/wifi/supplicant/aidl/vts/functional/supplicant_p2p_iface_aidl_test.cpp
index b7984fa..ee0eff5 100644
--- a/wifi/supplicant/aidl/vts/functional/supplicant_p2p_iface_aidl_test.cpp
+++ b/wifi/supplicant/aidl/vts/functional/supplicant_p2p_iface_aidl_test.cpp
@@ -37,6 +37,7 @@
 using aidl::android::hardware::wifi::supplicant::MiracastMode;
 using aidl::android::hardware::wifi::supplicant::P2pFrameTypeMask;
 using aidl::android::hardware::wifi::supplicant::P2pGroupCapabilityMask;
+using aidl::android::hardware::wifi::supplicant::P2pGroupStartedEventParams;
 using aidl::android::hardware::wifi::supplicant::P2pProvDiscStatusCode;
 using aidl::android::hardware::wifi::supplicant::P2pStatusCode;
 using aidl::android::hardware::wifi::supplicant::SupplicantStatusCode;
@@ -177,6 +178,10 @@
             const std::vector<uint8_t>& /* vendorElemBytes */) override {
         return ndk::ScopedAStatus::ok();
     }
+    ::ndk::ScopedAStatus onGroupStartedWithParams(
+            const P2pGroupStartedEventParams& /* groupStartedEventParams */) override {
+        return ndk::ScopedAStatus::ok();
+    }
 };
 
 class SupplicantP2pIfaceAidlTest : public testing::TestWithParam<std::string> {
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..d57f539 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,13 @@
                                       QosPolicyData /* qosPolicyData */>&) override {
         return ndk::ScopedAStatus::ok();
     }
+    ::ndk::ScopedAStatus onStateChangedWithAkm(
+            ::aidl::android::hardware::wifi::supplicant::StaIfaceCallbackState /* newState */,
+            const std::vector<uint8_t>& /* bssid */, int32_t /* id */,
+            const std::vector<uint8_t>& /* ssid */, bool /* filsHlpSent */,
+            ::aidl::android::hardware::wifi::supplicant::KeyMgmtMask /* keyMgmtMask*/) 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 b3f70da..e5d976c 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
@@ -19,6 +19,7 @@
 #include <aidl/Vintf.h>
 #include <aidl/android/hardware/wifi/supplicant/BnSupplicant.h>
 #include <aidl/android/hardware/wifi/supplicant/BnSupplicantStaNetworkCallback.h>
+#include <aidl/android/hardware/wifi/supplicant/TlsVersion.h>
 #include <android/binder_manager.h>
 #include <android/binder_status.h>
 #include <binder/IServiceManager.h>
@@ -51,6 +52,7 @@
 using aidl::android::hardware::wifi::supplicant::PairwiseCipherMask;
 using aidl::android::hardware::wifi::supplicant::ProtoMask;
 using aidl::android::hardware::wifi::supplicant::SaeH2eMode;
+using aidl::android::hardware::wifi::supplicant::TlsVersion;
 using aidl::android::hardware::wifi::supplicant::TransitionDisableIndication;
 using aidl::android::hardware::wifi::supplicant::WpaDriverCapabilitiesMask;
 using android::ProcessState;
@@ -791,6 +793,13 @@
     EXPECT_TRUE(sta_network_->setRoamingConsortiumSelection(testSelection).isOk());
 }
 
+/*
+ * SetMinimumTlsVersionEapPhase1Param
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetMinimumTlsVersionEapPhase1Param) {
+    EXPECT_TRUE(sta_network_->setMinimumTlsVersionEapPhase1Param(TlsVersion::TLS_V1_3).isOk());
+}
+
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SupplicantStaNetworkAidlTest);
 INSTANTIATE_TEST_SUITE_P(Supplicant, SupplicantStaNetworkAidlTest,
                          testing::ValuesIn(android::getAidlHalInstanceNames(
diff --git a/wifi/supplicant/aidl/vts/functional/supplicant_test_utils.h b/wifi/supplicant/aidl/vts/functional/supplicant_test_utils.h
index 31042a2..740dc9f 100644
--- a/wifi/supplicant/aidl/vts/functional/supplicant_test_utils.h
+++ b/wifi/supplicant/aidl/vts/functional/supplicant_test_utils.h
@@ -14,16 +14,18 @@
  * limitations under the License.
  */
 
-#ifndef SUPPLICANT_TEST_UTILS_H
-#define SUPPLICANT_TEST_UTILS_H
+#pragma once
 
 #include <VtsCoreUtil.h>
+#include <aidl/android/hardware/wifi/IWifi.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 "wifi_aidl_test_utils.h"
+
+using aidl::android::hardware::wifi::IfaceConcurrencyType;
+using aidl::android::hardware::wifi::IWifi;
+using aidl::android::hardware::wifi::IWifiChip;
 using aidl::android::hardware::wifi::supplicant::IfaceInfo;
 using aidl::android::hardware::wifi::supplicant::ISupplicant;
 using aidl::android::hardware::wifi::supplicant::ISupplicantP2pIface;
@@ -31,6 +33,90 @@
 using aidl::android::hardware::wifi::supplicant::KeyMgmtMask;
 using android::wifi_system::SupplicantManager;
 
+const std::string kWifiInstanceName = std::string() + IWifi::descriptor + "/default";
+
+// 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) << "Supplicant not " << is_running ? "running" : "stopped";
+    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;
+}
+
 std::string getStaIfaceName() {
     std::array<char, PROPERTY_VALUE_MAX> buffer;
     property_get("wifi.interface", buffer.data(), "wlan0");
@@ -43,14 +129,6 @@
     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) {
     KeyMgmtMask caps;
@@ -68,17 +146,33 @@
 }
 
 void startSupplicant() {
-    initializeDriverAndFirmware(getWifiInstanceName());
+    initializeDriverAndFirmware(kWifiInstanceName);
     SupplicantManager supplicant_manager;
     ASSERT_TRUE(supplicant_manager.StartSupplicant());
     ASSERT_TRUE(supplicant_manager.IsSupplicantRunning());
 }
 
-// Wrapper around the implementation in supplicant_hidl_test_util.
-void stopSupplicantService() { stopSupplicant(getWifiInstanceName()); }
+void stopSupplicantService() {
+    SupplicantManager supplicant_manager;
+    ASSERT_TRUE(supplicant_manager.StopSupplicant());
+    deInitializeDriverAndFirmware(kWifiInstanceName);
+    ASSERT_FALSE(supplicant_manager.IsSupplicantRunning());
+}
+
+bool startWifiFramework() {
+    std::system("svc wifi enable");
+    std::system("cmd wifi set-scan-always-available enabled");
+    return waitForSupplicantStart();  // wait for wifi to start.
+}
+
+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(getWifiInstanceName()));
+    ASSERT_TRUE(stopWifiFramework(kWifiInstanceName));
     std::system("/system/bin/start");
     ASSERT_TRUE(waitForFrameworkReady());
     stopSupplicantService();
@@ -106,5 +200,3 @@
     }
     return supplicant;
 }
-
-#endif  // SUPPLICANT_TEST_UTILS_H
\ No newline at end of file