Merge "Revert "Radio HAL : Support N3IWF""
diff --git a/audio/aidl/Android.bp b/audio/aidl/Android.bp
index d6e6f50..4e50b7a 100644
--- a/audio/aidl/Android.bp
+++ b/audio/aidl/Android.bp
@@ -100,6 +100,7 @@
         "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",
@@ -147,11 +148,20 @@
     name: "android.hardware.audio.effect",
     vendor_available: true,
     srcs: [
+        "android/hardware/audio/effect/Capability.aidl",
+        "android/hardware/audio/effect/CommandId.aidl",
         "android/hardware/audio/effect/Descriptor.aidl",
+        "android/hardware/audio/effect/Equalizer.aidl",
+        "android/hardware/audio/effect/Flags.aidl",
         "android/hardware/audio/effect/IEffect.aidl",
         "android/hardware/audio/effect/IFactory.aidl",
+        "android/hardware/audio/effect/Parameter.aidl",
+        "android/hardware/audio/effect/Processing.aidl",
+        "android/hardware/audio/effect/State.aidl",
     ],
     imports: [
+        "android.hardware.common-V2",
+        "android.hardware.common.fmq-V1",
         "android.hardware.audio.common-V1",
         "android.media.audio.common.types-V2",
     ],
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/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/Capability.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Capability.aidl
new file mode 100644
index 0000000..11acf5e
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Capability.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.effect;
+@VintfStability
+union Capability {
+  android.hardware.audio.effect.Capability.VendorEffectCapability vendor;
+  android.hardware.audio.effect.Equalizer.Capability equalizer;
+  @VintfStability
+  parcelable VendorEffectCapability {
+    ParcelableHolder extension;
+  }
+}
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..4707011 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;
+    android.hardware.audio.effect.Flags flags;
   }
   @VintfStability
   parcelable Common {
     android.hardware.audio.effect.Descriptor.Identity id;
+    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/Equalizer.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Equalizer.aidl
new file mode 100644
index 0000000..f7af300
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Equalizer.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.audio.effect;
+@VintfStability
+union Equalizer {
+  android.hardware.audio.effect.Equalizer.VendorExtension vendor;
+  android.hardware.audio.effect.Equalizer.BandLevel[] bandLevels;
+  int preset;
+  @VintfStability
+  parcelable VendorExtension {
+    ParcelableHolder extension;
+  }
+  @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 level;
+  }
+  @VintfStability
+  parcelable BandFrequency {
+    int index;
+    int min;
+    int max;
+  }
+  @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/IEffect.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/IEffect.aidl
index 7f868ad..e5c96f5 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 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 fmqByteConsumed;
+    int fmqByteProduced;
+  }
+  @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<byte,android.hardware.common.fmq.SynchronizedReadWrite> inputDataMQ;
+    android.hardware.common.fmq.MQDescriptor<byte,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..a22c591 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
@@ -35,6 +35,7 @@
 @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.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/Parameter.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Parameter.aidl
new file mode 100644
index 0000000..547112a
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Parameter.aidl
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.AudioDeviceType device;
+  android.media.audio.common.AudioMode mode;
+  android.media.audio.common.AudioSource source;
+  android.hardware.audio.effect.Parameter.Volume volume;
+  boolean offload;
+  android.hardware.audio.effect.Parameter.VendorEffectParameter vendorEffect;
+  android.hardware.audio.effect.Parameter.Specific specific;
+  @VintfStability
+  union Id {
+    int commonTag;
+    int vendorTag;
+    android.hardware.audio.effect.Parameter.Specific.Id specificId;
+  }
+  @VintfStability
+  parcelable Common {
+    int session;
+    int ioHandle;
+    android.media.audio.common.AudioConfig input;
+    android.media.audio.common.AudioConfig output;
+  }
+  @VintfStability
+  parcelable Volume {
+    float left;
+    float right;
+  }
+  @VintfStability
+  parcelable VendorEffectParameter {
+    ParcelableHolder extension;
+  }
+  @VintfStability
+  union Specific {
+    android.hardware.audio.effect.Parameter.Specific.Id id;
+    android.hardware.audio.effect.Equalizer equalizer;
+    @VintfStability
+    union Id {
+      android.hardware.audio.effect.Equalizer.Tag equalizerTag = android.hardware.audio.effect.Equalizer.Tag.vendor;
+    }
+  }
+}
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/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/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/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/effect/Capability.aidl b/audio/aidl/android/hardware/audio/effect/Capability.aidl
new file mode 100644
index 0000000..e792f86
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/Capability.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.audio.effect;
+
+import android.hardware.audio.effect.Equalizer;
+
+/**
+ * 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.
+     */
+    @VintfStability
+    parcelable VendorEffectCapability {
+        ParcelableHolder extension;
+    }
+    VendorEffectCapability vendor;
+
+    /**
+     * Equalizer capability definition.
+     */
+    Equalizer.Capability equalizer;
+}
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..562c249 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;
+        /**
+         * Capability flags defined for the effect implementation.
+         */
+        Flags flags;
     }
 
-    // Common attributes of all effect implementation.
+    /**
+     * Common attributes of all effect implementation.
+     */
     @VintfStability
     parcelable Common {
         /**
          * Identity of effect implementation.
          */
         Identity id;
+        /**
+         * 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/Equalizer.aidl b/audio/aidl/android/hardware/audio/effect/Equalizer.aidl
new file mode 100644
index 0000000..7fe9bb2
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/Equalizer.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.audio.effect;
+
+import android.media.audio.common.AudioProfile;
+
+/**
+ * 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 {
+    /**
+     * Vendor Equalizer implementation definition for additional parameters.
+     */
+    @VintfStability
+    parcelable VendorExtension {
+        ParcelableHolder extension;
+    }
+    VendorExtension vendor;
+
+    /**
+     * 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.
+     */
+    @VintfStability
+    parcelable BandLevel {
+        int index;
+        int level;
+    }
+
+    /**
+     * Supported minimal and maximal frequency for each band.
+     */
+    @VintfStability
+    parcelable BandFrequency {
+        int index;
+        int min;
+        int max;
+    }
+
+    /**
+     * 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/IEffect.aidl b/audio/aidl/android/hardware/audio/effect/IEffect.aidl
index d7a9501..5dd390f 100644
--- a/audio/aidl/android/hardware/audio/effect/IEffect.aidl
+++ b/audio/aidl/android/hardware/audio/effect/IEffect.aidl
@@ -16,24 +16,76 @@
 
 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 bytes consumed by the effect instance.
+         */
+        int fmqByteConsumed;
+        /**
+         * The amount of bytes produced by the effect instance.
+         */
+        int fmqByteProduced;
+    }
+
     /**
-     * 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<byte, SynchronizedReadWrite> inputDataMQ;
+        /**
+         * Message queue for output data buffer.
+         */
+        MQDescriptor<byte, 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.
+     *
+     * @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 Parameter.Specific specific);
 
     /**
      * Called by the client to close the effect instance, processing thread should be destroyed and
@@ -45,7 +97,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 +114,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..e56c24f 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;
 
 /**
@@ -45,6 +46,16 @@
             in @nullable AudioUuid type, in @nullable AudioUuid implementation);
 
     /**
+     * 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
      * parameter).
      *
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..739c9ff
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/Parameter.aidl
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect;
+
+import android.hardware.audio.effect.Equalizer;
+import android.media.audio.common.AudioConfig;
+import android.media.audio.common.AudioDeviceType;
+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 for vendor.
+ *
+ * For all supported parameter, implementation MUST support both set and get.
+ */
+@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 {
+        /**
+         *  Common parameter tag.
+         */
+        int commonTag;
+        /**
+         * Vendor defined parameter tag.
+         */
+        int vendorTag;
+        /**
+         * Specific effect parameter tag.
+         */
+        Specific.Id specificId;
+    }
+
+    /**
+     * 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.
+     */
+    AudioDeviceType device;
+    /**
+     * 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 Volume {
+        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.
+     */
+    Volume volume;
+
+    /**
+     * Used by audio framework to delegate offload information to effect engine.
+     * Effect must implement setParameter(offload) if Flags.offloadSupported set to true.
+     */
+    boolean offload;
+
+    /**
+     * Parameters for vendor extension effect implementation usage.
+     */
+    @VintfStability
+    parcelable VendorEffectParameter {
+        ParcelableHolder extension;
+    }
+    VendorEffectParameter vendorEffect;
+
+    /**
+     * Parameters MUST be supported by a Specific type of effect.
+     */
+    @VintfStability
+    union Specific {
+        @VintfStability
+        union Id {
+            /**
+             * Equalizer.Tag to identify the parameters in Equalizer.
+             */
+            Equalizer.Tag equalizerTag = Equalizer.Tag.vendor;
+        }
+        Id id;
+
+        Equalizer equalizer;
+    }
+    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/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/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/default/Android.bp b/audio/aidl/default/Android.bp
index 53ed908..e64b90c 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 {
@@ -81,18 +84,23 @@
 cc_library_static {
     name: "libaudioeffectserviceexampleimpl",
     defaults: ["aidlaudioeffectservice_defaults"],
-    export_include_dirs: [
-        "include",
-        "include/equalizer-impl/",
-    ],
+    export_include_dirs: ["include"],
     srcs: [
         "EffectFactory.cpp",
     ],
+    header_libs: [
+        "libsystem_headers",
+    ],
     visibility: [
         ":__subpackages__",
     ],
 }
 
+filegroup {
+    name: "effectCommonFile",
+    srcs: ["EffectThread.cpp"],
+}
+
 cc_binary {
     name: "android.hardware.audio.effect.service-aidl.example",
     relative_install_path: "hw",
@@ -104,3 +112,10 @@
     ],
     srcs: ["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/EffectFactory.cpp b/audio/aidl/default/EffectFactory.cpp
index a9848fd..8e107a2 100644
--- a/audio/aidl/default/EffectFactory.cpp
+++ b/audio/aidl/default/EffectFactory.cpp
@@ -16,57 +16,167 @@
 
 #define LOG_TAG "AHAL_EffectFactory"
 #include <android-base/logging.h>
+#include <dlfcn.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.
+    std::function<void(void*)> dlClose = [](void* handle) -> void {
+        if (handle && dlclose(handle)) {
+            LOG(ERROR) << "dlclose failed " << dlerror();
+        }
+    };
+    // TODO: implement this with audio_effect.xml.
+    auto libHandle =
+            std::unique_ptr<void, decltype(dlClose)>{dlopen("libequalizer.so", RTLD_LAZY), dlClose};
+    if (!libHandle) {
+        LOG(ERROR) << __func__ << ": dlopen failed, err: " << dlerror();
+        return;
+    }
+
+    LOG(DEBUG) << __func__ << " dlopen uuid: " << EqualizerSwImplUUID.toString() << " handle "
+               << libHandle;
+    mEffectLibMap.insert({EqualizerSwImplUUID, std::make_pair(std::move(libHandle), nullptr)});
+
     Descriptor::Identity id;
     id.type = EqualizerTypeUUID;
     id.uuid = EqualizerSwImplUUID;
     mIdentityList.push_back(id);
 }
 
-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,
                                          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);
+                     return (!in_type_uuid.has_value() || in_type_uuid.value() == desc.type) &&
+                            (!in_impl_uuid.has_value() || in_impl_uuid.value() == desc.uuid);
                  });
     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();
+                struct effect_interface_s intf = {
+                        .createEffectFunc = (EffectCreateFunctor)dlsym(libHandle, "createEffect"),
+                        .destroyEffectFunc =
+                                (EffectDestroyFunctor)dlsym(libHandle, "destroyEffect")};
+                auto dlInterface = std::make_unique<struct effect_interface_s>(intf);
+                if (!dlInterface->createEffectFunc || !dlInterface->destroyEffectFunc) {
+                    LOG(ERROR) << __func__
+                               << ": create or destroy symbol not exist in library: " << libHandle
+                               << "!";
+                    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(&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__ << ": library doesn't exist";
+            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+        }
     } else {
-        LOG(ERROR) << __func__ << ": UUID "
-                   << " not supported";
+        LOG(ERROR) << __func__ << ": UUID not supported";
         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;
+}
+
 }  // namespace aidl::android::hardware::audio::effect
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/equalizer/Android.bp b/audio/aidl/default/equalizer/Android.bp
index b842149..2a2ddbc 100644
--- a/audio/aidl/default/equalizer/Android.bp
+++ b/audio/aidl/default/equalizer/Android.bp
@@ -27,17 +27,24 @@
     name: "libequalizer",
     vendor: true,
     shared_libs: [
+        "libaudioaidlcommon",
         "libbase",
-        "libbinder_ndk",
-        "libstagefright_foundation",
+        "android.hardware.common-V2-ndk",
     ],
     defaults: [
+        "aidlaudioservice_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",
+        ":effectCommonFile",
+    ],
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+        "-Wthread-safety",
     ],
     visibility: [
         "//hardware/interfaces/audio/aidl/default",
diff --git a/audio/aidl/default/equalizer/Equalizer.cpp b/audio/aidl/default/equalizer/Equalizer.cpp
index 8b157fa..43fa206 100644
--- a/audio/aidl/default/equalizer/Equalizer.cpp
+++ b/audio/aidl/default/equalizer/Equalizer.cpp
@@ -14,27 +14,309 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AHAL_Equalizer"
-#include <android-base/logging.h>
+#define LOG_TAG "AHAL_EqualizerSw"
+#include <Utils.h>
+#include <algorithm>
+#include <unordered_set>
 
-#include "Equalizer.h"
+#include <android-base/logging.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include "equalizer-impl/EqualizerSw.h"
+
+using android::hardware::audio::common::getFrameSizeInBytes;
 
 namespace aidl::android::hardware::audio::effect {
 
-ndk::ScopedAStatus Equalizer::open() {
+extern "C" binder_exception_t createEffect(std::shared_ptr<IEffect>* instanceSpp) {
+    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;
+}
+
+ndk::ScopedAStatus EqualizerSw::open(const Parameter::Common& common,
+                                     const Parameter::Specific& specific,
+                                     OpenEffectReturn* _aidl_return) {
+    LOG(DEBUG) << __func__;
+    if (mState != State::INIT) {
+        LOG(WARNING) << __func__ << " eq already open";
+        return ndk::ScopedAStatus::ok();
+    }
+
+    // Set essential parameters before create worker thread.
+    setCommonParameter(common);
+    setSpecificParameter(specific);
+
+    LOG(DEBUG) << " common: " << common.toString() << " specific " << specific.toString();
+
+    auto& input = common.input;
+    auto& output = common.output;
+    size_t inputFrameSize = getFrameSizeInBytes(input.base.format, input.base.channelMask);
+    size_t outputFrameSize = getFrameSizeInBytes(output.base.format, output.base.channelMask);
+    mContext = std::make_shared<EqualizerSwContext>(1, input.frameCount * inputFrameSize,
+                                                    output.frameCount * outputFrameSize);
+    if (!mContext) {
+        LOG(ERROR) << __func__ << " created EqualizerSwContext failed";
+        return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_UNSUPPORTED_OPERATION,
+                                                                "FailedToCreateFmq");
+    }
+    setContext(mContext);
+
+    // create the worker thread
+    if (RetCode::SUCCESS != createThread(LOG_TAG)) {
+        LOG(ERROR) << __func__ << " created worker thread failed";
+        mContext.reset();
+        return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_UNSUPPORTED_OPERATION,
+                                                                "FailedToCreateWorker");
+    }
+
+    _aidl_return->statusMQ = mContext->getStatusFmq()->dupeDesc();
+    _aidl_return->inputDataMQ = mContext->getInputDataFmq()->dupeDesc();
+    _aidl_return->outputDataMQ = mContext->getOutputDataFmq()->dupeDesc();
+    mState = State::IDLE;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EqualizerSw::close() {
+    if (mState == State::INIT) {
+        LOG(WARNING) << __func__ << " instance already closed";
+        return ndk::ScopedAStatus::ok();
+    } else if (mState == State::PROCESSING) {
+        LOG(ERROR) << __func__ << " instance still processing";
+        return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_STATE,
+                                                                "EqInstanceProcessing");
+    }
+
+    // stop the worker thread
+    mState = State::INIT;
+    destroyThread();
+    mContext.reset();
+
     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();
+ndk::ScopedAStatus EqualizerSw::getDescriptor(Descriptor* _aidl_return) {
+    LOG(DEBUG) << __func__ << mDesc.toString();
     *_aidl_return = mDesc;
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus EqualizerSw::command(CommandId in_commandId) {
+    LOG(DEBUG) << __func__ << ": receive command:" << toString(in_commandId);
+    if (mState == State::INIT) {
+        LOG(ERROR) << __func__ << ": instance not open yet";
+        return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_STATE,
+                                                                "CommandStateError");
+    }
+    switch (in_commandId) {
+        case CommandId::START:
+            // start processing.
+            mState = State::PROCESSING;
+            startThread();
+            LOG(DEBUG) << __func__ << " state: " << toString(mState);
+            return ndk::ScopedAStatus::ok();
+        case CommandId::STOP:
+            // stop processing.
+            mState = State::IDLE;
+            stopThread();
+            LOG(DEBUG) << __func__ << " state: " << toString(mState);
+            return ndk::ScopedAStatus::ok();
+        case CommandId::RESET:
+            // TODO: reset buffer status.
+            mState = State::IDLE;
+            stopThread();
+            LOG(DEBUG) << __func__ << " state: " << toString(mState);
+            return ndk::ScopedAStatus::ok();
+        default:
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "CommandIdNotSupported");
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EqualizerSw::setParameter(const Parameter& in_param) {
+    if (mState == State::INIT) {
+        LOG(ERROR) << __func__ << ": instance not open yet";
+        return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_STATE, "StateError");
+    }
+    LOG(DEBUG) << __func__ << " with: " << in_param.toString();
+    auto tag = in_param.getTag();
+    switch (tag) {
+        case Parameter::common: {
+            return setCommonParameter(in_param.get<Parameter::common>());
+        }
+        case Parameter::specific: {
+            return setSpecificParameter(in_param.get<Parameter::specific>());
+        }
+        default:
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "ParameterNotSupported");
+    }
+}
+
+ndk::ScopedAStatus EqualizerSw::getParameter(const Parameter::Id& in_paramId,
+                                             Parameter* _aidl_return) {
+    LOG(DEBUG) << __func__ << in_paramId.toString();
+    auto tag = in_paramId.getTag();
+    switch (tag) {
+        case Parameter::Id::commonTag: {
+            _aidl_return->set<Parameter::common>(mCommonParam);
+            LOG(DEBUG) << __func__ << " get: " << _aidl_return->toString();
+            return ndk::ScopedAStatus::ok();
+        }
+        case Parameter::Id::specificId: {
+            auto& id = in_paramId.get<Parameter::Id::specificId>();
+            Parameter::Specific specific;
+            ndk::ScopedAStatus status = getSpecificParameter(id, &specific);
+            if (!status.isOk()) {
+                LOG(ERROR) << __func__
+                           << " getSpecificParameter error: " << status.getDescription();
+                return status;
+            }
+            _aidl_return->set<Parameter::specific>(specific);
+            LOG(DEBUG) << __func__ << _aidl_return->toString();
+            return ndk::ScopedAStatus::ok();
+        }
+        case Parameter::Id::vendorTag: {
+            LOG(DEBUG) << __func__ << " noop for vendor tag now";
+            return ndk::ScopedAStatus::ok();
+        }
+    }
+    LOG(ERROR) << " unsupported tag: " << toString(tag);
+    return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                            "Parameter:IdNotSupported");
+}
+
+ndk::ScopedAStatus EqualizerSw::getState(State* _aidl_return) {
+    *_aidl_return = mState;
+    return ndk::ScopedAStatus::ok();
+}
+
+/// Private methods.
+ndk::ScopedAStatus EqualizerSw::setCommonParameter(const Parameter::Common& common) {
+    mCommonParam = common;
+    LOG(DEBUG) << __func__ << " set: " << mCommonParam.toString();
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EqualizerSw::setSpecificParameter(const Parameter::Specific& specific) {
+    if (Parameter::Specific::equalizer != specific.getTag()) {
+        LOG(ERROR) << " unsupported effect: " << specific.toString();
+        return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                "EffectNotSupported");
+    }
+
+    auto& eqParam = specific.get<Parameter::Specific::equalizer>();
+    auto tag = eqParam.getTag();
+    switch (tag) {
+        case Equalizer::bandLevels: {
+            auto& bandLevels = eqParam.get<Equalizer::bandLevels>();
+            const auto& [minItem, maxItem] = std::minmax_element(
+                    bandLevels.begin(), bandLevels.end(),
+                    [](const auto& a, const auto& b) { return a.index < b.index; });
+            if (bandLevels.size() >= NUM_OF_BANDS || minItem->index < 0 ||
+                maxItem->index >= NUM_OF_BANDS) {
+                LOG(ERROR) << " bandLevels " << bandLevels.size() << "minIndex " << minItem->index
+                           << "maxIndex " << maxItem->index << " illegal ";
+                return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                        "ExceedMaxBandNum");
+            }
+            mBandLevels = bandLevels;
+            return ndk::ScopedAStatus::ok();
+        }
+        case Equalizer::preset: {
+            int preset = eqParam.get<Equalizer::preset>();
+            if (preset < 0 || preset >= NUM_OF_PRESETS) {
+                LOG(ERROR) << " preset: " << preset << " invalid";
+                return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                        "ExceedMaxBandNum");
+            }
+            mPreset = preset;
+            LOG(DEBUG) << __func__ << " preset set to " << mPreset;
+            return ndk::ScopedAStatus::ok();
+        }
+        case Equalizer::vendor: {
+            LOG(DEBUG) << __func__ << " noop for vendor tag now";
+            return ndk::ScopedAStatus::ok();
+        }
+    }
+
+    LOG(ERROR) << __func__ << " unsupported eq param tag: " << toString(tag);
+    return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                            "ParamNotSupported");
+}
+
+ndk::ScopedAStatus EqualizerSw::getSpecificParameter(Parameter::Specific::Id id,
+                                                     Parameter::Specific* specific) {
+    Equalizer eqParam;
+    auto tag = id.getTag();
+    if (tag != Parameter::Specific::Id::equalizerTag) {
+        LOG(ERROR) << " invalid tag: " << toString(tag);
+        return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                "UnsupportedTag");
+    }
+    auto eqTag = id.get<Parameter::Specific::Id::equalizerTag>();
+    switch (eqTag) {
+        case Equalizer::bandLevels: {
+            eqParam.set<Equalizer::bandLevels>(mBandLevels);
+            specific->set<Parameter::Specific::equalizer>(eqParam);
+            return ndk::ScopedAStatus::ok();
+        }
+        case Equalizer::preset: {
+            eqParam.set<Equalizer::preset>(mPreset);
+            LOG(DEBUG) << __func__ << " preset " << mPreset;
+            specific->set<Parameter::Specific::equalizer>(eqParam);
+            return ndk::ScopedAStatus::ok();
+        }
+        case Equalizer::vendor: {
+            LOG(DEBUG) << __func__ << " noop for vendor tag now";
+            return ndk::ScopedAStatus::ok();
+        }
+    }
+    LOG(ERROR) << __func__ << " unsupported eq param: " << toString(eqTag);
+    return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                            "ParamNotSupported");
+}
+
+void EqualizerSw::cleanUp() {
+    if (State::PROCESSING == mState) {
+        command(CommandId::STOP);
+    }
+    if (State::INIT != mState) {
+        close();
+    }
+}
+
+IEffect::Status EqualizerSw::status(binder_status_t status, size_t consumed, size_t produced) {
+    IEffect::Status ret;
+    ret.status = status;
+    ret.fmqByteConsumed = consumed;
+    ret.fmqByteProduced = produced;
+    return ret;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status EqualizerSw::effectProcessImpl() {
+    // TODO: get data buffer and process.
+    return status(STATUS_OK, mContext->availableToRead(), mContext->availableToWrite());
+}
+
 }  // 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/effect-impl/EffectContext.h b/audio/aidl/default/include/effect-impl/EffectContext.h
new file mode 100644
index 0000000..36492ec
--- /dev/null
+++ b/audio/aidl/default/include/effect-impl/EffectContext.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 <cstdint>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include <aidl/android/hardware/audio/effect/BnEffect.h>
+#include <fmq/AidlMessageQueue.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<
+            int8_t, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
+            DataMQ;
+
+    EffectContext(size_t statusDepth, size_t inBufferSize, size_t outBufferSize) {
+        mStatusMQ = std::make_shared<StatusMQ>(statusDepth, true /*configureEventFlagWord*/);
+        mInputMQ = std::make_shared<DataMQ>(inBufferSize);
+        mOutputMQ = std::make_shared<DataMQ>(outBufferSize);
+
+        if (!mStatusMQ->isValid() || !mInputMQ->isValid() || !mOutputMQ->isValid()) {
+            LOG(ERROR) << __func__ << " created invalid FMQ";
+        }
+        mWorkBuffer.reserve(std::max(inBufferSize, outBufferSize));
+    };
+
+    std::shared_ptr<StatusMQ> getStatusFmq() { return mStatusMQ; };
+    std::shared_ptr<DataMQ> getInputDataFmq() { return mInputMQ; };
+    std::shared_ptr<DataMQ> getOutputDataFmq() { return mOutputMQ; };
+
+    int8_t* getWorkBuffer() { return static_cast<int8_t*>(mWorkBuffer.data()); };
+    // TODO: update with actual available size
+    size_t availableToRead() { return mWorkBuffer.capacity(); };
+    size_t availableToWrite() { return mWorkBuffer.capacity(); };
+
+  private:
+    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<int8_t> mWorkBuffer;
+};
+}  // 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..46cfc0c
--- /dev/null
+++ b/audio/aidl/default/include/effect-impl/EffectTypes.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 <ostream>
+#include <string>
+
+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 */
+};
+
+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";
+    }
+
+    return out << "EnumError: " << code;
+}
+
+}  // 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..48b7137
--- /dev/null
+++ b/audio/aidl/default/include/effect-impl/EffectUUID.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.
+ */
+
+#pragma once
+#include <aidl/android/media/audio/common/AudioUuid.h>
+
+namespace aidl::android::hardware::audio::effect {
+
+using ::aidl::android::media::audio::common::AudioUuid;
+
+// Null UUID
+static const AudioUuid EffectNullUuid = {static_cast<int32_t>(0xec7178ec),
+                                         0xe5e1,
+                                         0x4432,
+                                         0xa3f4,
+                                         {0x46, 0x57, 0xe6, 0x79, 0x52, 0x10}};
+
+// Zero UUID
+static const AudioUuid EffectZeroUuid = {
+        static_cast<int32_t>(0x0), 0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
+
+// Equalizer type UUID.
+static const AudioUuid EqualizerTypeUUID = {static_cast<int32_t>(0x0bed4300),
+                                            0xddd6,
+                                            0x11db,
+                                            0x8f34,
+                                            {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+
+// Equalizer implementation UUID.
+static const AudioUuid EqualizerSwImplUUID = {static_cast<int32_t>(0x0bed4300),
+                                              0x847d,
+                                              0x11df,
+                                              0xbb17,
+                                              {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+
+// Visualizer type UUID.
+static const AudioUuid VisualizerTypeUUID = {static_cast<int32_t>(0x1d4033c0),
+                                             0x8557,
+                                             0x11df,
+                                             0x9f2d,
+                                             {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+
+}  // 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..0fe69ff
--- /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 {
+        if (!mContext) {
+            LOG(ERROR) << __func__ << " invalid context!";
+            return;
+        }
+        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 readSize = inputMQ->availableToRead(), writeSize = outputMQ->availableToWrite();
+        if (readSize && writeSize) {
+            LOG(DEBUG) << __func__ << " available to read " << readSize << " available to write "
+                       << writeSize;
+            auto buffer = mContext->getWorkBuffer();
+            inputMQ->read(buffer, readSize);
+            IEffect::Status status = effectProcessImpl();
+            writeSize = std::min((int32_t)writeSize, status.fmqByteProduced);
+            outputMQ->write(buffer, writeSize);
+            statusMQ->writeBlocking(&status, 1);
+            LOG(DEBUG) << __func__ << " done processing, effect consumed " << status.fmqByteConsumed
+                       << " produced " << status.fmqByteProduced;
+        } else {
+            // TODO: maybe add some sleep here to avoid busy waiting
+        }
+    }
+
+    // must implement by each effect implementation
+    virtual IEffect::Status effectProcessImpl() = 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/EffectFactory.h b/audio/aidl/default/include/effectFactory-impl/EffectFactory.h
index 8da5525..6195d8a 100644
--- a/audio/aidl/default/include/effectFactory-impl/EffectFactory.h
+++ b/audio/aidl/default/include/effectFactory-impl/EffectFactory.h
@@ -16,6 +16,8 @@
 
 #pragma once
 
+#include <any>
+#include <map>
 #include <optional>
 #include <vector>
 
@@ -41,6 +43,16 @@
             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 +75,26 @@
             override;
 
   private:
+    ~Factory();
     // List of effect descriptors supported by the devices.
     std::vector<Descriptor::Identity> mIdentityList;
+
+    typedef binder_exception_t (*EffectCreateFunctor)(std::shared_ptr<IEffect>*);
+    typedef binder_exception_t (*EffectDestroyFunctor)(const std::shared_ptr<IEffect>&);
+    struct effect_interface_s {
+        EffectCreateFunctor createEffectFunc;
+        EffectDestroyFunctor destroyEffectFunc;
+    };
+
+    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_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();
 };
 }  // 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/equalizer-impl/EqualizerSw.h b/audio/aidl/default/include/equalizer-impl/EqualizerSw.h
new file mode 100644
index 0000000..aa3a727
--- /dev/null
+++ b/audio/aidl/default/include/equalizer-impl/EqualizerSw.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/EffectContext.h"
+#include "effect-impl/EffectTypes.h"
+#include "effect-impl/EffectUUID.h"
+#include "effect-impl/EffectWorker.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+class EqualizerSwContext : public EffectContext {
+  public:
+    EqualizerSwContext(int statusDepth, int inBufferSize, int outBufferSize)
+        : EffectContext(statusDepth, inBufferSize, outBufferSize) {
+        LOG(DEBUG) << __func__;
+    }
+
+  private:
+    // Add equalizer specific context for processing here
+};
+
+class EqualizerSw : public BnEffect, EffectWorker {
+  public:
+    EqualizerSw() {
+        Equalizer::Capability eqCap = {.bandFrequencies = mBandFrequency, .presets = mPresets};
+        mDesc.capability.set<Capability::equalizer>(eqCap);
+        LOG(DEBUG) << __func__;
+    };
+    ~EqualizerSw() {
+        cleanUp();
+        LOG(DEBUG) << __func__;
+    };
+    ndk::ScopedAStatus open(const Parameter::Common& common, const Parameter::Specific& specific,
+                            OpenEffectReturn* _aidl_return) override;
+    ndk::ScopedAStatus close() override;
+    ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
+
+    ndk::ScopedAStatus getState(State* _aidl_return) override;
+    ndk::ScopedAStatus command(CommandId in_commandId) override;
+    ndk::ScopedAStatus setParameter(const Parameter& in_param) override;
+    ndk::ScopedAStatus getParameter(const Parameter::Id& in_paramId,
+                                    Parameter* _aidl_return) override;
+
+    IEffect::Status effectProcessImpl() override;
+
+  private:
+    // Effect descriptor.
+    Descriptor mDesc = {.common = {.id = {.type = EqualizerTypeUUID, .uuid = EqualizerSwImplUUID}}};
+
+    // Parameters.
+    Parameter::Common mCommonParam;
+    Equalizer mEqualizerParam;  // TODO: the equalizer parameter needs to update
+
+    // Instance state INIT by default.
+    State mState = State::INIT;
+
+    int mPreset = PRESET_CUSTOM;  // the current preset
+    const std::vector<Equalizer::BandFrequency> mBandFrequency = {{0, 30000, 120000},
+                                                                  {1, 120001, 460000},
+                                                                  {2, 460001, 1800000},
+                                                                  {3, 1800001, 7000000},
+                                                                  {4, 7000001, 20000000}};
+    // preset band level
+    std::vector<Equalizer::BandLevel> mBandLevels = {{0, 3}, {1, 0}, {2, 0}, {3, 0}, {4, 3}};
+    // 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"}};
+    static const int NUM_OF_BANDS = 5;
+    static const int NUM_OF_PRESETS = 10;
+    static const int PRESET_CUSTOM = -1;
+
+    // Equalizer worker context
+    std::shared_ptr<EqualizerSwContext> mContext;
+
+    ndk::ScopedAStatus setCommonParameter(const Parameter::Common& common_param);
+    ndk::ScopedAStatus setSpecificParameter(const Parameter::Specific& specific);
+    ndk::ScopedAStatus getSpecificParameter(Parameter::Specific::Id id,
+                                            Parameter::Specific* specific);
+
+    void cleanUp();
+
+    IEffect::Status status(binder_status_t status, size_t consumed, size_t produced);
+};
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/vts/Android.bp b/audio/aidl/vts/Android.bp
index 6ea7cef..8de1d79 100644
--- a/audio/aidl/vts/Android.bp
+++ b/audio/aidl/vts/Android.bp
@@ -43,8 +43,40 @@
 }
 
 cc_test {
+    name: "VtsHalAudioEffectFactoryTargetTest",
+    defaults: [
+        "latest_android_media_audio_common_types_ndk_static",
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: [
+        "VtsHalAudioEffectFactoryTargetTest.cpp",
+    ],
+    shared_libs: [
+        "libbinder_ndk",
+    ],
+    static_libs: [
+        "android.hardware.audio.effect-V1-ndk",
+        "android.hardware.common-V2-ndk",
+        "android.hardware.common.fmq-V1-ndk",
+    ],
+    header_libs: ["libaudioaidl_headers"],
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+        "-Wthread-safety",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
+
+cc_test {
     name: "VtsHalAudioEffectTargetTest",
     defaults: [
+        "latest_android_hardware_audio_common_ndk_static",
         "latest_android_media_audio_common_types_ndk_static",
         "VtsHalTargetTestDefaults",
         "use_libaidlvintf_gtest_helper_static",
@@ -54,10 +86,49 @@
     ],
     shared_libs: [
         "libbinder_ndk",
+        "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",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
+
+cc_test {
+    name: "VtsHalEqualizerTargetTest",
+    defaults: [
+        "latest_android_hardware_audio_common_ndk_static",
+        "latest_android_media_audio_common_types_ndk_static",
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: [
+        "VtsHalEqualizerTargetTest.cpp",
+    ],
+    shared_libs: [
+        "libbinder_ndk",
+        "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",
diff --git a/audio/aidl/vts/EffectFactoryHelper.h b/audio/aidl/vts/EffectFactoryHelper.h
new file mode 100644
index 0000000..63efae0
--- /dev/null
+++ b/audio/aidl/vts/EffectFactoryHelper.h
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#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::EffectNullUuid;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::Processing;
+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);
+        ClearEffectMap();
+    }
+
+    void QueryEffects(const std::optional<AudioUuid>& in_type,
+                      const std::optional<AudioUuid>& in_instance,
+                      std::vector<Descriptor::Identity>* _aidl_return) {
+        ASSERT_NE(mEffectFactory, nullptr);
+        EXPECT_IS_OK(mEffectFactory->queryEffects(in_type, in_instance, _aidl_return));
+        mIds = *_aidl_return;
+    }
+
+    void QueryProcessing(const std::optional<Processing::Type>& in_type,
+                         std::vector<Processing>* _aidl_return) {
+        ASSERT_NE(mEffectFactory, nullptr);
+        EXPECT_IS_OK(mEffectFactory->queryProcessing(in_type, _aidl_return));
+        // only update the whole list if no filter applied
+        if (!in_type.has_value()) {
+            mProcesses = *_aidl_return;
+        }
+    }
+
+    void CreateEffects() {
+        for (const auto& id : mIds) {
+            std::shared_ptr<IEffect> effect;
+            EXPECT_IS_OK(mEffectFactory->createEffect(id.uuid, &effect));
+            EXPECT_NE(effect, nullptr) << id.toString();
+            if (effect) {
+                mEffectIdMap[effect] = id;
+            }
+        }
+    }
+
+    void QueryAndCreateEffects(const AudioUuid& type = EffectNullUuid) {
+        std::vector<Descriptor::Identity> ids;
+        ASSERT_NE(mEffectFactory, nullptr);
+
+        if (type == EffectNullUuid) {
+            EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, &ids));
+        } else {
+            EXPECT_IS_OK(mEffectFactory->queryEffects(type, std::nullopt, &ids));
+        }
+        for (const auto& id : ids) {
+            ASSERT_EQ(id.type, type);
+            std::shared_ptr<IEffect> effect;
+            EXPECT_IS_OK(mEffectFactory->createEffect(id.uuid, &effect));
+            EXPECT_NE(effect, nullptr) << id.toString();
+            if (effect) {
+                mEffectIdMap[effect] = id;
+            }
+        }
+    }
+
+    void CreateEffectsAndExpect(
+            const std::vector<std::pair<Descriptor::Identity, binder_exception_t>>& uuid_status) {
+        ASSERT_NE(mEffectFactory, nullptr);
+        for (const auto& it : uuid_status) {
+            std::shared_ptr<IEffect> effect;
+            auto status = mEffectFactory->createEffect(it.first.uuid, &effect);
+            EXPECT_STATUS(it.second, status);
+            if (effect) {
+                mEffectIdMap[effect] = it.first;
+            }
+        }
+    }
+
+    void DestroyEffectAndExpect(std::shared_ptr<IEffect>& instance, binder_exception_t exception) {
+        ASSERT_NE(mEffectFactory, nullptr);
+        auto status = mEffectFactory->destroyEffect(instance);
+        EXPECT_STATUS(exception, status);
+    }
+
+    void QueryAndCreateAllEffects() {
+        ASSERT_NE(mEffectFactory, nullptr);
+        EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, &mCompleteIds));
+        for (const auto& id : mCompleteIds) {
+            std::shared_ptr<IEffect> effect;
+            EXPECT_IS_OK(mEffectFactory->createEffect(id.uuid, &effect));
+            EXPECT_NE(effect, nullptr) << id.toString();
+            mEffectIdMap[effect] = id;
+        }
+    }
+
+    void DestroyEffects(const binder_exception_t expected = EX_NONE, const int remaining = 0) {
+        ASSERT_NE(mEffectFactory, nullptr);
+
+        for (auto it = mEffectIdMap.begin(); it != mEffectIdMap.end();) {
+            auto erased = it++;
+            auto status = mEffectFactory->destroyEffect(erased->first);
+            EXPECT_STATUS(expected, status);
+            if (status.isOk()) {
+                mEffectIdMap.erase(erased);
+            }
+        }
+        EXPECT_EQ((unsigned int)remaining, mEffectIdMap.size());
+    }
+
+    std::shared_ptr<IFactory> GetFactory() { return mEffectFactory; }
+    const std::vector<Descriptor::Identity>& GetEffectIds() { return mIds; }
+    const std::vector<Descriptor::Identity>& GetCompleteEffectIdList() const {
+        return mCompleteIds;
+    }
+    const std::map<std::shared_ptr<IEffect>, Descriptor::Identity>& GetEffectMap() const {
+        return mEffectIdMap;
+    }
+    void ClearEffectMap() { mEffectIdMap.clear(); }
+
+  private:
+    std::shared_ptr<IFactory> mEffectFactory;
+    std::string mServiceName;
+    AudioHalBinderServiceUtil binderUtil;
+    std::vector<Descriptor::Identity> mIds;
+    std::vector<Descriptor::Identity> mCompleteIds;
+    std::vector<Processing> mProcesses;
+
+    std::map<std::shared_ptr<IEffect>, Descriptor::Identity> mEffectIdMap;
+};
diff --git a/audio/aidl/vts/EffectHelper.h b/audio/aidl/vts/EffectHelper.h
new file mode 100644
index 0000000..c58ed13
--- /dev/null
+++ b/audio/aidl/vts/EffectHelper.h
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <aidl/android/hardware/audio/effect/IEffect.h>
+#include <aidl/android/hardware/audio/effect/IFactory.h>
+#include <aidl/android/media/audio/common/AudioChannelLayout.h>
+#include <aidl/android/media/audio/common/AudioDeviceType.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::EffectNullUuid;
+using aidl::android::hardware::audio::effect::EffectZeroUuid;
+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::AudioDeviceType;
+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 DefaultFormat = {
+        .type = AudioFormatType::PCM, .pcm = PcmType::INT_16_BIT, .encoding = ""};
+
+class EffectHelper {
+  public:
+    explicit EffectHelper(const std::string& name) : mFactoryHelper(EffectFactoryHelper(name)) {
+        mFactoryHelper.ConnectToFactoryService();
+    }
+
+    void OpenEffects(const AudioUuid& type = EffectNullUuid) {
+        auto open = [&](const std::shared_ptr<IEffect>& effect) {
+            IEffect::OpenEffectReturn ret;
+            EXPECT_IS_OK(effect->open(mCommon, mSpecific, &ret));
+            EffectParam params;
+            params.statusMQ = std::make_unique<StatusMQ>(ret.statusMQ);
+            params.inputMQ = std::make_unique<DataMQ>(ret.inputDataMQ);
+            params.outputMQ = std::make_unique<DataMQ>(ret.outputDataMQ);
+            mEffectParams.push_back(std::move(params));
+        };
+        EXPECT_NO_FATAL_FAILURE(ForEachEffect(open, type));
+    }
+
+    void CloseEffects(const binder_status_t status = EX_NONE) {
+        auto close = [&](const std::shared_ptr<IEffect>& effect) {
+            EXPECT_STATUS(status, effect->close());
+        };
+
+        EXPECT_NO_FATAL_FAILURE(ForEachEffect(close));
+    }
+
+    void CreateEffects(const int n = 1) {
+        for (int i = 0; i < n; i++) {
+            ASSERT_NO_FATAL_FAILURE(mFactoryHelper.QueryAndCreateAllEffects());
+        }
+    }
+
+    void CreateEffectsWithUUID(const AudioUuid& type = EffectNullUuid) {
+        ASSERT_NO_FATAL_FAILURE(mFactoryHelper.QueryAndCreateEffects(type));
+    }
+
+    void QueryEffects() { ASSERT_NO_FATAL_FAILURE(mFactoryHelper.QueryAndCreateAllEffects()); }
+
+    void DestroyEffects(const binder_status_t status = EX_NONE, const int remaining = 0) {
+        ASSERT_NO_FATAL_FAILURE(mFactoryHelper.DestroyEffects(status, remaining));
+        mEffectDescriptors.clear();
+    }
+
+    void GetEffectDescriptors() {
+        auto get = [&](const std::shared_ptr<IEffect>& effect) {
+            Descriptor desc;
+            EXPECT_IS_OK(effect->getDescriptor(&desc));
+            mEffectDescriptors.push_back(std::move(desc));
+        };
+        EXPECT_NO_FATAL_FAILURE(ForEachEffect(get));
+    }
+
+    void CommandEffects(CommandId command) {
+        auto close = [&](const std::shared_ptr<IEffect>& effect) {
+            EXPECT_IS_OK(effect->command(command));
+        };
+        EXPECT_NO_FATAL_FAILURE(ForEachEffect(close));
+    }
+
+    void CommandEffectsExpectStatus(CommandId command, const binder_status_t status) {
+        auto func = [&](const std::shared_ptr<IEffect>& effect) {
+            EXPECT_STATUS(status, effect->command(command));
+        };
+        EXPECT_NO_FATAL_FAILURE(ForEachEffect(func));
+    }
+
+    void ExpectState(State expected) {
+        auto get = [&](const std::shared_ptr<IEffect>& effect) {
+            State state = State::INIT;
+            EXPECT_IS_OK(effect->getState(&state));
+            EXPECT_EQ(expected, state);
+        };
+        EXPECT_NO_FATAL_FAILURE(ForEachEffect(get));
+    }
+
+    void SetParameter() {
+        auto func = [&](const std::shared_ptr<IEffect>& effect) {
+            Parameter param;
+            param.set<Parameter::common>(mCommon);
+            EXPECT_IS_OK(effect->setParameter(param));
+        };
+        EXPECT_NO_FATAL_FAILURE(ForEachEffect(func));
+    }
+
+    void VerifyParameters() {
+        auto func = [&](const std::shared_ptr<IEffect>& effect) {
+            Parameter paramCommonGet = Parameter(), paramCommonExpect = Parameter();
+            Parameter::Id id;
+            id.set<Parameter::Id::commonTag>(0);
+            paramCommonExpect.set<Parameter::common>(mCommon);
+            EXPECT_IS_OK(effect->getParameter(id, &paramCommonGet));
+            EXPECT_EQ(paramCommonExpect, paramCommonGet)
+                    << paramCommonExpect.toString() << " vs " << paramCommonGet.toString();
+        };
+        EXPECT_NO_FATAL_FAILURE(ForEachEffect(func));
+    }
+
+    void QueryEffects(const std::optional<AudioUuid>& in_type,
+                      const std::optional<AudioUuid>& in_instance,
+                      std::vector<Descriptor::Identity>* _aidl_return) {
+        mFactoryHelper.QueryEffects(in_type, in_instance, _aidl_return);
+    }
+
+    template <typename Functor>
+    void ForEachEffect(Functor functor, const std::optional<AudioUuid>& type = EffectNullUuid) {
+        auto effectMap = mFactoryHelper.GetEffectMap();
+        for (const auto& it : effectMap) {
+            SCOPED_TRACE(it.second.toString());
+            if (type != EffectNullUuid && it.second.type != type) continue;
+            functor(it.first);
+        }
+    }
+
+    template <typename Functor>
+    void ForEachDescriptor(Functor functor) {
+        for (size_t i = 0; i < mEffectDescriptors.size(); i++) {
+            SCOPED_TRACE(mEffectDescriptors[i].toString());
+            functor(i, mEffectDescriptors[i]);
+        }
+    }
+
+    static const size_t mWriteMQSize = 0x400;
+
+    enum class IO : char { INPUT = 0, OUTPUT = 1, INOUT = 2 };
+
+    void initParamCommonFormat(IO io = IO::INOUT,
+                               const AudioFormatDescription& format = DefaultFormat) {
+        if (io == IO::INPUT || io == IO::INOUT) {
+            mCommon.input.base.format = format;
+        }
+        if (io == IO::OUTPUT || io == IO::INOUT) {
+            mCommon.output.base.format = format;
+        }
+    }
+
+    void initParamCommonSampleRate(IO io = IO::INOUT, const int& sampleRate = 48000) {
+        if (io == IO::INPUT || io == IO::INOUT) {
+            mCommon.input.base.sampleRate = sampleRate;
+        }
+        if (io == IO::OUTPUT || io == IO::INOUT) {
+            mCommon.output.base.sampleRate = sampleRate;
+        }
+    }
+
+    void initParamCommonFrameCount(IO io = IO::INOUT, const long& frameCount = 48000) {
+        if (io == IO::INPUT || io == IO::INOUT) {
+            mCommon.input.frameCount = frameCount;
+        }
+        if (io == IO::OUTPUT || io == IO::INOUT) {
+            mCommon.output.frameCount = frameCount;
+        }
+    }
+    void initParamCommon(int session = -1, int ioHandle = -1, int iSampleRate = 48000,
+                         int oSampleRate = 48000, long iFrameCount = 0x100,
+                         long oFrameCount = 0x100) {
+        mCommon.session = session;
+        mCommon.ioHandle = ioHandle;
+
+        auto& input = mCommon.input;
+        auto& output = mCommon.output;
+        input.base.sampleRate = iSampleRate;
+        input.base.channelMask = mInputChannelLayout;
+        input.frameCount = iFrameCount;
+        output.base.sampleRate = oSampleRate;
+        output.base.channelMask = mOutputChannelLayout;
+        output.frameCount = oFrameCount;
+        inputFrameSize = android::hardware::audio::common::getFrameSizeInBytes(
+                input.base.format, input.base.channelMask);
+        outputFrameSize = android::hardware::audio::common::getFrameSizeInBytes(
+                output.base.format, output.base.channelMask);
+    }
+
+    void setSpecific(Parameter::Specific& specific) { mSpecific = specific; }
+
+    // usually this function only call once.
+    void PrepareInputData(size_t s = mWriteMQSize) {
+        size_t maxInputSize = s;
+        for (auto& it : mEffectParams) {
+            auto& mq = it.inputMQ;
+            EXPECT_NE(nullptr, mq);
+            EXPECT_TRUE(mq->isValid());
+            const size_t bytesToWrite = mq->availableToWrite();
+            EXPECT_EQ(inputFrameSize * mCommon.input.frameCount, bytesToWrite);
+            EXPECT_NE(0UL, bytesToWrite);
+            EXPECT_TRUE(s <= bytesToWrite);
+            maxInputSize = std::max(maxInputSize, bytesToWrite);
+        }
+        mInputBuffer.resize(maxInputSize);
+        std::fill(mInputBuffer.begin(), mInputBuffer.end(), 0x5a);
+    }
+
+    void writeToFmq(size_t s = mWriteMQSize) {
+        for (auto& it : mEffectParams) {
+            auto& mq = it.inputMQ;
+            EXPECT_NE(nullptr, mq);
+            const size_t bytesToWrite = mq->availableToWrite();
+            EXPECT_NE(0Ul, bytesToWrite);
+            EXPECT_TRUE(s <= bytesToWrite);
+            EXPECT_TRUE(mq->write(mInputBuffer.data(), s));
+        }
+    }
+
+    void readFromFmq(size_t expectSize = mWriteMQSize) {
+        for (auto& it : mEffectParams) {
+            IEffect::Status status{};
+            auto& statusMq = it.statusMQ;
+            EXPECT_NE(nullptr, statusMq);
+            EXPECT_TRUE(statusMq->readBlocking(&status, 1));
+            EXPECT_EQ(STATUS_OK, status.status);
+            EXPECT_EQ(expectSize, (unsigned)status.fmqByteProduced);
+
+            auto& outputMq = it.outputMQ;
+            EXPECT_NE(nullptr, outputMq);
+            EXPECT_EQ(expectSize, outputMq->availableToRead());
+        }
+    }
+
+    void setInputChannelLayout(AudioChannelLayout input) { mInputChannelLayout = input; }
+    void setOutputChannelLayout(AudioChannelLayout output) { mOutputChannelLayout = output; }
+    const std::vector<Descriptor::Identity>& GetCompleteEffectIdList() const {
+        return mFactoryHelper.GetCompleteEffectIdList();
+    }
+    const std::vector<Descriptor>& getDescriptorVec() const { return mEffectDescriptors; }
+
+  private:
+    EffectFactoryHelper mFactoryHelper;
+
+    AudioChannelLayout mInputChannelLayout =
+            AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
+                    AudioChannelLayout::LAYOUT_STEREO);
+    AudioChannelLayout mOutputChannelLayout =
+            AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
+                    AudioChannelLayout::LAYOUT_STEREO);
+
+    Parameter::Common mCommon;
+    Parameter::Specific mSpecific;
+
+    size_t inputFrameSize, outputFrameSize;
+    std::vector<int8_t> mInputBuffer;  // reuse same buffer for all effects testing
+
+    typedef ::android::AidlMessageQueue<
+            IEffect::Status, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
+            StatusMQ;
+    typedef ::android::AidlMessageQueue<
+            int8_t, ::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;
+    };
+    std::vector<EffectParam> mEffectParams;
+    std::vector<Descriptor> mEffectDescriptors;
+};
diff --git a/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp b/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp
new file mode 100644
index 0000000..da8ca37
--- /dev/null
+++ b/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <memory>
+#include <string>
+#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::EffectNullUuid;
+using aidl::android::hardware::audio::effect::EffectZeroUuid;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::Processing;
+using aidl::android::media::audio::common::AudioUuid;
+
+/// 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());
+
+    const Descriptor::Identity nullDesc = {.uuid = EffectNullUuid};
+    const Descriptor::Identity zeroDesc = {.uuid = EffectZeroUuid};
+};
+
+TEST_P(EffectFactoryTest, SetupAndTearDown) {
+    // Intentionally empty test body.
+}
+
+TEST_P(EffectFactoryTest, CanBeRestarted) {
+    ASSERT_NO_FATAL_FAILURE(mFactory.RestartFactoryService());
+}
+
+TEST_P(EffectFactoryTest, QueriedDescriptorList) {
+    std::vector<Descriptor::Identity> descriptors;
+    mFactory.QueryEffects(std::nullopt, std::nullopt, &descriptors);
+    EXPECT_NE(descriptors.size(), 0UL);
+}
+
+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, EffectNullUuid);
+        EXPECT_NE(desc.uuid, EffectNullUuid);
+    }
+}
+
+TEST_P(EffectFactoryTest, QueriedDescriptorNotExistType) {
+    std::vector<Descriptor::Identity> descriptors;
+    mFactory.QueryEffects(EffectNullUuid, std::nullopt, &descriptors);
+    EXPECT_EQ(descriptors.size(), 0UL);
+}
+
+TEST_P(EffectFactoryTest, QueriedDescriptorNotExistInstance) {
+    std::vector<Descriptor::Identity> descriptors;
+    mFactory.QueryEffects(std::nullopt, EffectNullUuid, &descriptors);
+    EXPECT_EQ(descriptors.size(), 0UL);
+}
+
+TEST_P(EffectFactoryTest, CreateAndDestroyOnce) {
+    std::vector<Descriptor::Identity> descriptors;
+    mFactory.QueryEffects(std::nullopt, std::nullopt, &descriptors);
+    auto numIds = mFactory.GetEffectIds().size();
+    EXPECT_NE(numIds, 0UL);
+
+    auto& effectMap = mFactory.GetEffectMap();
+    EXPECT_EQ(effectMap.size(), 0UL);
+    mFactory.CreateEffects();
+    EXPECT_EQ(effectMap.size(), numIds);
+    mFactory.DestroyEffects();
+    EXPECT_EQ(effectMap.size(), 0UL);
+}
+
+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);
+
+    auto& effectMap = mFactory.GetEffectMap();
+    EXPECT_EQ(effectMap.size(), 0UL);
+    mFactory.CreateEffects();
+    EXPECT_EQ(effectMap.size(), numIds);
+    mFactory.DestroyEffects();
+    EXPECT_EQ(effectMap.size(), 0UL);
+
+    // Create and destroy again
+    mFactory.CreateEffects();
+    EXPECT_EQ(effectMap.size(), numIds);
+    mFactory.DestroyEffects();
+    EXPECT_EQ(effectMap.size(), 0UL);
+}
+
+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);
+
+    auto& effectMap = mFactory.GetEffectMap();
+    EXPECT_EQ(effectMap.size(), 0UL);
+    mFactory.CreateEffects();
+    EXPECT_EQ(effectMap.size(), numIds);
+    // Create effect instances of same implementation
+    mFactory.CreateEffects();
+    EXPECT_EQ(effectMap.size(), 2 * numIds);
+
+    mFactory.CreateEffects();
+    EXPECT_EQ(effectMap.size(), 3 * numIds);
+
+    mFactory.DestroyEffects();
+    EXPECT_EQ(effectMap.size(), 0UL);
+}
+
+// Expect EX_ILLEGAL_ARGUMENT when create with invalid UUID.
+TEST_P(EffectFactoryTest, CreateWithInvalidUuid) {
+    std::vector<std::pair<Descriptor::Identity, binder_status_t>> descriptors;
+    descriptors.push_back(std::make_pair(nullDesc, EX_ILLEGAL_ARGUMENT));
+    descriptors.push_back(std::make_pair(zeroDesc, EX_ILLEGAL_ARGUMENT));
+
+    auto& effectMap = mFactory.GetEffectMap();
+    mFactory.CreateEffectsAndExpect(descriptors);
+    EXPECT_EQ(effectMap.size(), 0UL);
+}
+
+// Expect EX_ILLEGAL_ARGUMENT when destroy null interface.
+TEST_P(EffectFactoryTest, DestroyWithInvalidInterface) {
+    std::shared_ptr<IEffect> spDummyEffect(nullptr);
+
+    mFactory.DestroyEffectAndExpect(spDummyEffect, EX_ILLEGAL_ARGUMENT);
+}
+
+TEST_P(EffectFactoryTest, CreateAndRemoveReference) {
+    std::vector<Descriptor::Identity> descriptors;
+    mFactory.QueryEffects(std::nullopt, std::nullopt, &descriptors);
+    auto numIds = mFactory.GetEffectIds().size();
+    EXPECT_NE(numIds, 0UL);
+
+    auto& effectMap = mFactory.GetEffectMap();
+    EXPECT_EQ(effectMap.size(), 0UL);
+    mFactory.CreateEffects();
+    EXPECT_EQ(effectMap.size(), numIds);
+    // remove all reference
+    mFactory.ClearEffectMap();
+    EXPECT_EQ(effectMap.size(), 0UL);
+}
+
+TEST_P(EffectFactoryTest, CreateRemoveReferenceAndCreateDestroy) {
+    std::vector<Descriptor::Identity> descriptors;
+    mFactory.QueryEffects(std::nullopt, std::nullopt, &descriptors);
+    auto numIds = mFactory.GetEffectIds().size();
+    EXPECT_NE(numIds, 0UL);
+
+    auto& effectMap = mFactory.GetEffectMap();
+    EXPECT_EQ(effectMap.size(), 0UL);
+    mFactory.CreateEffects();
+    EXPECT_EQ(effectMap.size(), numIds);
+    // remove all reference
+    mFactory.ClearEffectMap();
+    EXPECT_EQ(effectMap.size(), 0UL);
+
+    // Create and destroy again
+    mFactory.CreateEffects();
+    EXPECT_EQ(effectMap.size(), numIds);
+    mFactory.DestroyEffects();
+    EXPECT_EQ(effectMap.size(), 0UL);
+}
+
+TEST_P(EffectFactoryTest, CreateRestartAndCreateDestroy) {
+    std::vector<Descriptor::Identity> descriptors;
+    mFactory.QueryEffects(std::nullopt, std::nullopt, &descriptors);
+    auto numIds = mFactory.GetEffectIds().size();
+    auto& effectMap = mFactory.GetEffectMap();
+    mFactory.CreateEffects();
+    EXPECT_EQ(effectMap.size(), numIds);
+    ASSERT_NO_FATAL_FAILURE(mFactory.RestartFactoryService());
+
+    mFactory.CreateEffects();
+    EXPECT_EQ(effectMap.size(), numIds);
+    mFactory.DestroyEffects();
+    EXPECT_EQ(effectMap.size(), 0UL);
+}
+
+TEST_P(EffectFactoryTest, QueryProcess) {
+    std::vector<Processing> processing;
+    mFactory.QueryProcessing(std::nullopt, &processing);
+    // TODO: verify the number of process in example implementation after audio_effects.xml migrated
+}
+
+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..7ed1f01 100644
--- a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
@@ -14,14 +14,14 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "VtsHalAudioEffectTargetTest"
+
 #include <memory>
 #include <string>
 #include <unordered_map>
 #include <unordered_set>
 #include <vector>
 
-#define LOG_TAG "VtsHalAudioEffect"
-
 #include <aidl/Gtest.h>
 #include <aidl/Vintf.h>
 #include <android-base/logging.h>
@@ -30,272 +30,91 @@
 #include <android/binder_manager.h>
 #include <android/binder_process.h>
 
+#include <Utils.h>
+#include <aidl/android/hardware/audio/effect/IEffect.h>
 #include <aidl/android/hardware/audio/effect/IFactory.h>
+#include <aidl/android/media/audio/common/AudioDeviceType.h>
 
 #include "AudioHalBinderServiceUtil.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;
+using aidl::android::media::audio::common::AudioDeviceType;
 
-class EffectFactoryHelper {
+class AudioEffectTest : public testing::TestWithParam<std::string>, public EffectHelper {
   public:
-    explicit EffectFactoryHelper(const std::string& name) : mServiceName(name) {}
+    AudioEffectTest() : EffectHelper(GetParam()) {}
 
-    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);
-    }
-
-    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;
-};
-
-/// 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) {
-    // Intentionally empty test body.
-}
-
-TEST_P(EffectFactoryTest, CanBeRestarted) {
-    ASSERT_NO_FATAL_FAILURE(mFactory.RestartFactoryService());
-}
-
-TEST_P(EffectFactoryTest, QueriedDescriptorList) {
-    std::vector<Descriptor::Identity> descriptors;
-    mFactory.QueryEffects(std::nullopt, std::nullopt, &descriptors);
-    EXPECT_NE(descriptors.size(), 0UL);
-}
-
-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(EffectFactoryTest, QueriedDescriptorNotExistType) {
-    std::vector<Descriptor::Identity> descriptors;
-    mFactory.QueryEffects(nullUuid, std::nullopt, &descriptors);
-    EXPECT_EQ(descriptors.size(), 0UL);
-}
-
-TEST_P(EffectFactoryTest, QueriedDescriptorNotExistInstance) {
-    std::vector<Descriptor::Identity> descriptors;
-    mFactory.QueryEffects(std::nullopt, nullUuid, &descriptors);
-    EXPECT_EQ(descriptors.size(), 0UL);
-}
-
-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(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);
-}
-
-INSTANTIATE_TEST_SUITE_P(EffectFactoryTest, EffectFactoryTest,
-                         testing::ValuesIn(android::getAidlHalInstanceNames(IFactory::descriptor)),
-                         android::PrintInstanceNameToString);
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EffectFactoryTest);
-
-/// 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());
+        CreateEffects();
+        initParamCommonFormat();
+        initParamCommon();
+        // initParamSpecific();
     }
 
     void TearDown() override {
         CloseEffects();
-        ASSERT_NO_FATAL_FAILURE(mFactory.DestroyEffects());
+        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());
+TEST_P(AudioEffectTest, OpenEffectTest) {
+    OpenEffects();
 }
 
-TEST_P(AudioEffect, OpenAndCloseEffect) {
-    EXPECT_NO_FATAL_FAILURE(OpenEffects());
-    EXPECT_NO_FATAL_FAILURE(CloseEffects());
+TEST_P(AudioEffectTest, OpenAndCloseEffect) {
+    OpenEffects();
+    CloseEffects();
 }
 
-TEST_P(AudioEffect, CloseUnopenedEffectTest) {
-    EXPECT_NO_FATAL_FAILURE(CloseEffects());
+TEST_P(AudioEffectTest, CloseUnopenedEffectTest) {
+    CloseEffects();
 }
 
-TEST_P(AudioEffect, DoubleOpenCloseEffects) {
-    EXPECT_NO_FATAL_FAILURE(OpenEffects());
-    EXPECT_NO_FATAL_FAILURE(CloseEffects());
-    EXPECT_NO_FATAL_FAILURE(OpenEffects());
-    EXPECT_NO_FATAL_FAILURE(CloseEffects());
+TEST_P(AudioEffectTest, DoubleOpenCloseEffects) {
+    OpenEffects();
+    CloseEffects();
+    OpenEffects();
+    CloseEffects();
 
-    EXPECT_NO_FATAL_FAILURE(OpenEffects());
-    EXPECT_NO_FATAL_FAILURE(OpenEffects());
-    EXPECT_NO_FATAL_FAILURE(CloseEffects());
+    OpenEffects();
+    OpenEffects();
+    CloseEffects();
 
-    EXPECT_NO_FATAL_FAILURE(OpenEffects());
-    EXPECT_NO_FATAL_FAILURE(CloseEffects());
-    EXPECT_NO_FATAL_FAILURE(CloseEffects());
+    OpenEffects();
+    CloseEffects();
+    CloseEffects();
 }
 
-TEST_P(AudioEffect, GetDescriptors) {
-    EXPECT_NO_FATAL_FAILURE(GetEffectDescriptors());
+TEST_P(AudioEffectTest, GetDescriptors) {
+    GetEffectDescriptors();
 }
 
-TEST_P(AudioEffect, DescriptorIdExistAndUnique) {
+TEST_P(AudioEffectTest, 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);
+        QueryEffects(desc.common.id.type, desc.common.id.uuid, &idList);
         EXPECT_EQ(idList.size(), 1UL);
     };
-    EXPECT_NO_FATAL_FAILURE(ForEachEffect(checker));
+    ForEachEffect(checker);
 
     // Check unique with a set
     auto stringHash = [](const Descriptor::Identity& id) {
         return std::hash<std::string>()(id.toString());
     };
-    auto vec = mFactory.GetCompleteEffectIdList();
+    auto vec = GetCompleteEffectIdList();
     std::unordered_set<Descriptor::Identity, decltype(stringHash)> idSet(0, stringHash);
     for (auto it : vec) {
         EXPECT_EQ(idSet.count(it), 0UL);
@@ -303,14 +122,237 @@
     }
 }
 
-INSTANTIATE_TEST_SUITE_P(AudioEffectTest, AudioEffect,
+/// State testing.
+// An effect instance is in INIT state by default after it was created.
+TEST_P(AudioEffectTest, InitStateAfterCreation) {
+    ExpectState(State::INIT);
+}
+
+// An effect instance transfer to INIT state after it was open successfully with IEffect.open().
+TEST_P(AudioEffectTest, IdleStateAfterOpen) {
+    OpenEffects();
+    ExpectState(State::IDLE);
+    CloseEffects();
+}
+
+// An effect instance is in PROCESSING state after it receive an START command.
+TEST_P(AudioEffectTest, ProcessingStateAfterStart) {
+    OpenEffects();
+    CommandEffects(CommandId::START);
+    ExpectState(State::PROCESSING);
+    CommandEffects(CommandId::STOP);
+    CloseEffects();
+}
+
+// An effect instance transfer to IDLE state after Command.Id.STOP in PROCESSING state.
+TEST_P(AudioEffectTest, IdleStateAfterStop) {
+    OpenEffects();
+    CommandEffects(CommandId::START);
+    ExpectState(State::PROCESSING);
+    CommandEffects(CommandId::STOP);
+    ExpectState(State::IDLE);
+    CloseEffects();
+}
+
+// An effect instance transfer to IDLE state after Command.Id.RESET in PROCESSING state.
+TEST_P(AudioEffectTest, IdleStateAfterReset) {
+    OpenEffects();
+    CommandEffects(CommandId::START);
+    ExpectState(State::PROCESSING);
+    CommandEffects(CommandId::RESET);
+    ExpectState(State::IDLE);
+    CloseEffects();
+}
+
+// An effect instance transfer to INIT if instance receive a close() call.
+TEST_P(AudioEffectTest, InitStateAfterClose) {
+    OpenEffects();
+    CommandEffects(CommandId::START);
+    ExpectState(State::PROCESSING);
+    CommandEffects(CommandId::STOP);
+    ExpectState(State::IDLE);
+    CloseEffects();
+    ExpectState(State::INIT);
+}
+
+// An effect instance shouldn't accept any command before open.
+TEST_P(AudioEffectTest, NoCommandAcceptedBeforeOpen) {
+    ExpectState(State::INIT);
+    CommandEffectsExpectStatus(CommandId::START, EX_ILLEGAL_STATE);
+    CommandEffectsExpectStatus(CommandId::STOP, EX_ILLEGAL_STATE);
+    CommandEffectsExpectStatus(CommandId::RESET, EX_ILLEGAL_STATE);
+    ExpectState(State::INIT);
+}
+
+// No-op when receive STOP command in IDLE state.
+TEST_P(AudioEffectTest, StopCommandInIdleStateNoOp) {
+    ExpectState(State::INIT);
+    OpenEffects();
+    ExpectState(State::IDLE);
+    CommandEffects(CommandId::STOP);
+    ExpectState(State::IDLE);
+    CloseEffects();
+}
+
+// No-op when receive STOP command in IDLE state.
+TEST_P(AudioEffectTest, ResetCommandInIdleStateNoOp) {
+    ExpectState(State::INIT);
+    OpenEffects();
+    ExpectState(State::IDLE);
+    CommandEffects(CommandId::RESET);
+    ExpectState(State::IDLE);
+    CloseEffects();
+}
+
+// Repeat START and STOP command.
+TEST_P(AudioEffectTest, RepeatStartAndStop) {
+    OpenEffects();
+    CommandEffects(CommandId::START);
+    ExpectState(State::PROCESSING);
+    CommandEffects(CommandId::STOP);
+    ExpectState(State::IDLE);
+    CommandEffects(CommandId::START);
+    ExpectState(State::PROCESSING);
+    CommandEffects(CommandId::STOP);
+    ExpectState(State::IDLE);
+    CloseEffects();
+}
+
+// Repeat START and RESET command.
+TEST_P(AudioEffectTest, RepeatStartAndReset) {
+    OpenEffects();
+    CommandEffects(CommandId::START);
+    ExpectState(State::PROCESSING);
+    CommandEffects(CommandId::RESET);
+    ExpectState(State::IDLE);
+    CommandEffects(CommandId::START);
+    ExpectState(State::PROCESSING);
+    CommandEffects(CommandId::RESET);
+    ExpectState(State::IDLE);
+    CloseEffects();
+}
+
+// Repeat START and STOP command, try to close at PROCESSING state.
+TEST_P(AudioEffectTest, CloseProcessingStateEffects) {
+    OpenEffects();
+    CommandEffects(CommandId::START);
+    ExpectState(State::PROCESSING);
+    CommandEffects(CommandId::STOP);
+    ExpectState(State::IDLE);
+    CommandEffects(CommandId::START);
+    ExpectState(State::PROCESSING);
+    CloseEffects(EX_ILLEGAL_STATE);
+    // cleanup
+    CommandEffects(CommandId::STOP);
+    ExpectState(State::IDLE);
+}
+
+// Expect EX_ILLEGAL_STATE if the effect instance is not in a proper state to be destroyed.
+TEST_P(AudioEffectTest, DestroyOpenEffects) {
+    // cleanup all effects.
+    CloseEffects();
+    DestroyEffects();
+
+    // open effects, destroy without close, expect to get EX_ILLEGAL_STATE status.
+    CreateEffects();
+    OpenEffects();
+    DestroyEffects(EX_ILLEGAL_STATE, 1);
+    CloseEffects();
+}
+
+/// Parameter testing.
+// Verify parameters pass in open can be successfully get.
+TEST_P(AudioEffectTest, VerifyParametersAfterOpen) {
+    OpenEffects();
+    VerifyParameters();
+    CloseEffects();
+}
+
+// Verify parameters pass in set can be successfully get.
+TEST_P(AudioEffectTest, SetAndGetParameter) {
+    OpenEffects();
+    VerifyParameters();
+    initParamCommon(1 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */,
+                    44100 /* oSampleRate */);
+    SetParameter();
+    VerifyParameters();
+    CloseEffects();
+}
+
+// Verify parameters pass in set can be successfully get.
+TEST_P(AudioEffectTest, SetAndGetParameterInProcessing) {
+    OpenEffects();
+    VerifyParameters();
+    CommandEffects(CommandId::START);
+    ExpectState(State::PROCESSING);
+    initParamCommon(1 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */,
+                    44100 /* oSampleRate */);
+    SetParameter();
+    VerifyParameters();
+    CommandEffects(CommandId::STOP);
+    ExpectState(State::IDLE);
+    CloseEffects();
+}
+
+// Parameters kept after reset.
+TEST_P(AudioEffectTest, ResetAndVerifyParameter) {
+    OpenEffects();
+    VerifyParameters();
+    CommandEffects(CommandId::START);
+    ExpectState(State::PROCESSING);
+    initParamCommon(1 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */,
+                    44100 /* oSampleRate */);
+    SetParameter();
+    VerifyParameters();
+    CommandEffects(CommandId::RESET);
+    ExpectState(State::IDLE);
+    VerifyParameters();
+    CloseEffects();
+}
+
+// Multiple instances of same implementation running.
+TEST_P(AudioEffectTest, MultipleInstancesRunning) {
+    CreateEffects(3);
+    ExpectState(State::INIT);
+    OpenEffects();
+    ExpectState(State::IDLE);
+    CommandEffects(CommandId::START);
+    ExpectState(State::PROCESSING);
+    initParamCommon(1 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */,
+                    44100 /* oSampleRate */);
+    SetParameter();
+    VerifyParameters();
+    CommandEffects(CommandId::STOP);
+    ExpectState(State::IDLE);
+    VerifyParameters();
+    CloseEffects();
+}
+
+// Send data to effects and expect it to consume by check statusMQ.
+TEST_P(AudioEffectTest, ExpectEffectsToConsumeDataInMQ) {
+    OpenEffects();
+    PrepareInputData(mWriteMQSize);
+
+    CommandEffects(CommandId::START);
+    writeToFmq(mWriteMQSize);
+    readFromFmq(mWriteMQSize);
+
+    ExpectState(State::PROCESSING);
+    CommandEffects(CommandId::STOP);
+    // cleanup
+    CommandEffects(CommandId::STOP);
+    ExpectState(State::IDLE);
+    CloseEffects();
+}
+
+INSTANTIATE_TEST_SUITE_P(AudioEffectTestTest, AudioEffectTest,
                          testing::ValuesIn(android::getAidlHalInstanceNames(IFactory::descriptor)),
                          android::PrintInstanceNameToString);
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioEffect);
+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..3b9699b
--- /dev/null
+++ b/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <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 <aidl/android/media/audio/common/AudioChannelLayout.h>
+#include <aidl/android/media/audio/common/AudioDeviceType.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::EffectNullUuid;
+using aidl::android::hardware::audio::effect::Equalizer;
+using aidl::android::hardware::audio::effect::EqualizerTypeUUID;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::Parameter;
+
+/**
+ * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
+ * VtsAudioEfectTargetTest.
+ */
+using EqualizerParamTestParam = std::tuple<int, int, int>;
+
+class EqualizerParamTest : public ::testing::TestWithParam<EqualizerParamTestParam>,
+                           public EffectHelper {
+  public:
+    EqualizerParamTest()
+        : EffectHelper(android::getAidlHalInstanceNames(IFactory::descriptor)[0]),
+          mParamPresetIndex(std::get<0 /* kPresetIndexRange */>(GetParam())),
+          mParamBandIndex(std::get<1 /* kBandIndexRange */>(GetParam())),
+          mParamBandLevel(std::get<2 /* kBandLevelRange */>(GetParam())) {}
+
+    void SetUp() override {
+        CreateEffectsWithUUID(EqualizerTypeUUID);
+        initParamCommonFormat();
+        initParamCommon();
+        initParamSpecific();
+        OpenEffects(EqualizerTypeUUID);
+        SCOPED_TRACE(testing::Message() << "preset: " << mParamPresetIndex << " bandIdx "
+                                        << mParamBandIndex << " level " << mParamBandLevel);
+    }
+
+    void TearDown() override {
+        CloseEffects();
+        DestroyEffects();
+        CleanUp();
+    }
+
+    const int mParamPresetIndex;
+    const int mParamBandIndex;
+    const int mParamBandLevel;
+
+    void SetAndGetEqualizerParameters() {
+        auto functor = [&](const std::shared_ptr<IEffect>& effect) {
+            for (auto& it : mTags) {
+                auto& tag = it.first;
+                auto& eq = it.second;
+
+                // validate parameter
+                Descriptor desc;
+                ASSERT_STATUS(EX_NONE, effect->getDescriptor(&desc));
+                const bool valid = isTagInRange(it.first, it.second, desc);
+                const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
+
+                // set
+                Parameter expectParam;
+                Parameter::Specific specific;
+                specific.set<Parameter::Specific::equalizer>(*eq.get());
+                expectParam.set<Parameter::specific>(specific);
+                EXPECT_STATUS(expected, effect->setParameter(expectParam))
+                        << expectParam.toString();
+
+                // get
+                if (expected == EX_NONE) {
+                    Parameter getParam;
+                    Parameter::Specific::Id id;
+                    id.set<Parameter::Specific::Id::equalizerTag>(tag);
+                    // if set success, then get should match
+                    EXPECT_STATUS(expected, effect->getParameter(id, &getParam));
+                    EXPECT_EQ(expectParam, getParam) << "\n"
+                                                     << expectParam.toString() << "\n"
+                                                     << getParam.toString();
+                }
+            }
+        };
+        EXPECT_NO_FATAL_FAILURE(ForEachEffect(functor));
+    }
+
+    void addPresetParam(int preset) {
+        Equalizer eq;
+        eq.set<Equalizer::preset>(preset);
+        mTags.push_back({Equalizer::preset, std::make_unique<Equalizer>(std::move(eq))});
+    }
+
+    void addBandLevelsParam(std::vector<Equalizer::BandLevel>& bandLevels) {
+        Equalizer eq;
+        eq.set<Equalizer::bandLevels>(bandLevels);
+        mTags.push_back({Equalizer::bandLevels, std::make_unique<Equalizer>(std::move(eq))});
+    }
+
+    bool isTagInRange(const Equalizer::Tag& tag, const std::unique_ptr<Equalizer>& eq,
+                      const Descriptor& desc) const {
+        std::cout << "xxx" << toString(tag) << " " << desc.toString();
+        const Equalizer::Capability& eqCap = desc.capability.get<Capability::equalizer>();
+        switch (tag) {
+            case Equalizer::preset: {
+                int index = eq->get<Equalizer::preset>();
+                return isPresetIndexInRange(eqCap, index);
+            }
+            case Equalizer::bandLevels: {
+                auto& bandLevel = eq->get<Equalizer::bandLevels>();
+                return isBandIndexInRange(eqCap, bandLevel);
+            }
+            default:
+                return false;
+        }
+        return false;
+    }
+
+    bool isPresetIndexInRange(const Equalizer::Capability& cap, int idx) 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 idx >= min->index && idx <= max->index;
+    }
+
+    bool isBandIndexInRange(const Equalizer::Capability& cap,
+                            const std::vector<Equalizer::BandLevel>& bandLevel) const {
+        for (auto& it : bandLevel) {
+            if (!isBandIndexInRange(cap, it.index)) return false;
+        }
+        return true;
+    }
+
+    bool isBandIndexInRange(const Equalizer::Capability& cap, int idx) 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 idx >= min->index && idx <= max->index;
+    }
+
+  private:
+    Equalizer::VendorExtension mVendorExtension;
+    std::vector<std::pair<Equalizer::Tag, std::unique_ptr<Equalizer>>> mTags;
+
+    bool validCapabilityTag(Capability& cap) { return cap.getTag() == Capability::equalizer; }
+
+    void initParamSpecific() {
+        Equalizer eq;
+        eq.set<Equalizer::preset>(0);
+        Parameter::Specific specific;
+        specific.set<Parameter::Specific::equalizer>(eq);
+        setSpecific(specific);
+    }
+
+    void CleanUp() { mTags.clear(); }
+};
+
+TEST_P(EqualizerParamTest, SetAndGetPreset) {
+    EXPECT_NO_FATAL_FAILURE(addPresetParam(mParamPresetIndex));
+    SetAndGetEqualizerParameters();
+}
+
+TEST_P(EqualizerParamTest, SetAndGetSingleBand) {
+    Equalizer::BandLevel bandLevel = {mParamBandIndex, mParamBandLevel};
+    std::vector<Equalizer::BandLevel> bandLevels;
+    bandLevels.push_back(bandLevel);
+    EXPECT_NO_FATAL_FAILURE(addBandLevelsParam(bandLevels));
+    SetAndGetEqualizerParameters();
+}
+
+/**
+ Testing preset index range with [-10, 10], assuming the min/max preset index 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.
+ */
+constexpr std::pair<int, int> kPresetIndexRange = {-1, 10};  // valid range [0, 9]
+constexpr std::pair<int, int> kBandIndexRange = {-1, 5};     // valid range [0, 4]
+constexpr std::pair<int, int> kBandLevelRange = {-5, 5};     // needs update with implementation
+
+INSTANTIATE_TEST_SUITE_P(
+        EqualizerTest, EqualizerParamTest,
+        ::testing::Combine(testing::Range(kPresetIndexRange.first, kPresetIndexRange.second),
+                           testing::Range(kBandIndexRange.first, kBandIndexRange.second),
+                           testing::Range(kBandLevelRange.first, kBandLevelRange.second)));
+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/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/remoteaccess/impl/default/client/Android.bp b/automotive/remoteaccess/hal/default/Android.bp
similarity index 64%
rename from automotive/remoteaccess/impl/default/client/Android.bp
rename to automotive/remoteaccess/hal/default/Android.bp
index 6327637..a2bf86c 100644
--- a/automotive/remoteaccess/impl/default/client/Android.bp
+++ b/automotive/remoteaccess/hal/default/Android.bp
@@ -29,28 +29,61 @@
         "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_library {
-    name: "RemoteAccessService",
-    vendor: true,
-    local_include_dirs: ["include"],
-    export_include_dirs: ["include"],
-    srcs: [
-        "src/RemoteAccessService.cpp",
-    ],
+cc_fuzz {
+    name: "android.hardware.automotive.remoteaccess@V1-default-service.aidl_fuzzer",
+    srcs: ["fuzzer/fuzzer.cpp"],
     whole_static_libs: [
-        "android.hardware.automotive.remoteaccess-V1-ndk",
-        "wakeup_client_protos",
+        "RemoteAccessService",
+    ],
+    static_libs: [
+        "libgtest",
+        "libgmock",
     ],
     shared_libs: [
         "libbase",
@@ -60,7 +93,17 @@
         "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/impl/default/client/include/RemoteAccessService.h b/automotive/remoteaccess/hal/default/include/RemoteAccessService.h
similarity index 71%
rename from automotive/remoteaccess/impl/default/client/include/RemoteAccessService.h
rename to automotive/remoteaccess/hal/default/include/RemoteAccessService.h
index 806440a..74c2af4 100644
--- a/automotive/remoteaccess/impl/default/client/include/RemoteAccessService.h
+++ b/automotive/remoteaccess/hal/default/include/RemoteAccessService.h
@@ -16,10 +16,14 @@
 
 #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>
@@ -30,6 +34,27 @@
 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:
@@ -51,10 +76,14 @@
     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;
@@ -69,12 +98,16 @@
     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
diff --git a/automotive/remoteaccess/impl/default/proto/Android.bp b/automotive/remoteaccess/hal/default/proto/Android.bp
similarity index 97%
rename from automotive/remoteaccess/impl/default/proto/Android.bp
rename to automotive/remoteaccess/hal/default/proto/Android.bp
index 31b9d0e..3e0dba1 100644
--- a/automotive/remoteaccess/impl/default/proto/Android.bp
+++ b/automotive/remoteaccess/hal/default/proto/Android.bp
@@ -35,7 +35,6 @@
         "wakeup_client.pb.h",
         "wakeup_client.grpc.pb.h",
     ],
-    vendor: true,
 }
 
 genrule {
@@ -52,12 +51,11 @@
         "wakeup_client.pb.cc",
         "wakeup_client.grpc.pb.cc",
     ],
-    vendor: true,
 }
 
 cc_library_static {
     name: "wakeup_client_protos",
-    vendor: true,
+    vendor_available: true,
     host_supported: true,
     include_dirs: [
         "external/protobuf/src",
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/impl/default/client/src/RemoteAccessImpl.cpp b/automotive/remoteaccess/hal/default/src/RemoteAccessImpl.cpp
similarity index 70%
rename from automotive/remoteaccess/impl/default/client/src/RemoteAccessImpl.cpp
rename to automotive/remoteaccess/hal/default/src/RemoteAccessImpl.cpp
index 7431898..8720c2f 100644
--- a/automotive/remoteaccess/impl/default/client/src/RemoteAccessImpl.cpp
+++ b/automotive/remoteaccess/hal/default/src/RemoteAccessImpl.cpp
@@ -20,27 +20,35 @@
 
 #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...");
 
-    // TODO(b/241483300): Create GrpcClientStub here.
+#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>(nullptr);
+            android::hardware::automotive::remoteaccess::RemoteAccessService>(clientStub.get());
 
-    binder_exception_t err = AServiceManager_addService(
-            service->asBinder().get(), "android.hardware.automotive.remote.IRemoteAccess/default");
+    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);
-        return 1;
+        exit(1);
     }
 
     if (!ABinderProcess_setThreadPoolMaxThreadCount(1)) {
         ALOGE("%s", "failed to set thread pool max thread count");
-        return 1;
+        exit(1);
     }
     ABinderProcess_startThreadPool();
 
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/impl/default/test/Android.bp b/automotive/remoteaccess/hal/default/test/Android.bp
similarity index 94%
rename from automotive/remoteaccess/impl/default/test/Android.bp
rename to automotive/remoteaccess/hal/default/test/Android.bp
index e92440f..227175a 100644
--- a/automotive/remoteaccess/impl/default/test/Android.bp
+++ b/automotive/remoteaccess/hal/default/test/Android.bp
@@ -24,6 +24,7 @@
         "RemoteAccessService",
     ],
     shared_libs: [
+        "libbase",
         "libbinder_ndk",
         "liblog",
         "libutils",
@@ -36,6 +37,9 @@
         "libgtest",
         "libgmock",
     ],
+    defaults: [
+        "vhalclient_defaults",
+    ],
     cflags: [
         "-Wno-unused-parameter",
     ],
diff --git a/automotive/remoteaccess/impl/default/test/RemoteAccessServiceUnitTest.cpp b/automotive/remoteaccess/hal/default/test/RemoteAccessServiceUnitTest.cpp
similarity index 78%
rename from automotive/remoteaccess/impl/default/test/RemoteAccessServiceUnitTest.cpp
rename to automotive/remoteaccess/hal/default/test/RemoteAccessServiceUnitTest.cpp
index 11523f6..8c4fa08 100644
--- a/automotive/remoteaccess/impl/default/test/RemoteAccessServiceUnitTest.cpp
+++ b/automotive/remoteaccess/hal/default/test/RemoteAccessServiceUnitTest.cpp
@@ -16,8 +16,11 @@
 
 #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>
@@ -30,10 +33,20 @@
 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;
@@ -49,6 +62,10 @@
 using ::testing::Return;
 using ::testing::SetArgPointee;
 
+constexpr char kTestVin[] = "test_VIN";
+
+}  // namespace
+
 class MockGrpcClientStub : public WakeupClient::StubInterface {
   public:
     MOCK_METHOD(ClientReaderInterface<GetRemoteTasksResponse>*, GetRemoteTasksRaw,
@@ -73,6 +90,62 @@
                  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,
@@ -114,10 +187,13 @@
 
     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;
-    MockClientReader<GetRemoteTasksResponse>* mMockTaskReader;
 };
 
 TEST_F(RemoteAccessServiceUnitTest, TestGetWakeupServiceName) {
@@ -282,6 +358,15 @@
     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
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/test_grpc_server/README.md b/automotive/remoteaccess/test_grpc_server/README.md
new file mode 100644
index 0000000..deea764
--- /dev/null
+++ b/automotive/remoteaccess/test_grpc_server/README.md
@@ -0,0 +1,7 @@
+# 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. This
+reference server also implements wakeup_client_debug.proto which is the
+debugging interface. It is recommended that the actual implementation also
+implements this test interface for easier end-to-end testing.
diff --git a/automotive/remoteaccess/impl/default/test/Android.bp b/automotive/remoteaccess/test_grpc_server/impl/Android.bp
similarity index 60%
copy from automotive/remoteaccess/impl/default/test/Android.bp
copy to automotive/remoteaccess/test_grpc_server/impl/Android.bp
index e92440f..8aab2e3 100644
--- a/automotive/remoteaccess/impl/default/test/Android.bp
+++ b/automotive/remoteaccess/test_grpc_server/impl/Android.bp
@@ -13,31 +13,31 @@
 // limitations under the License.
 
 package {
-    default_applicable_licenses: ["Android-Apache-2.0"],
+    // 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: "RemoteAccessServiceUnitTest",
+cc_binary {
+    name: "TestWakeupClientServer",
     vendor: true,
-    srcs: ["*.cpp"],
-    whole_static_libs: [
-        "RemoteAccessService",
-    ],
+    srcs: ["src/*.cpp"],
+    local_include_dirs: ["include"],
     shared_libs: [
-        "libbinder_ndk",
+        "libbase",
         "liblog",
         "libutils",
         "libgrpc++",
         "libprotobuf-cpp-full",
     ],
-    // libgrpc++.so is installed as root, require root to access it.
-    require_root: true,
-    static_libs: [
-        "libgtest",
-        "libgmock",
+    whole_static_libs: [
+        "wakeup_client_protos",
     ],
     cflags: [
         "-Wno-unused-parameter",
+        "-DGRPC_SERVICE_ADDRESS=\"localhost:50051\"",
     ],
-    test_suites: ["device-tests"],
 }
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..61c1ad3
--- /dev/null
+++ b/automotive/remoteaccess/test_grpc_server/impl/include/TestWakeupClientServiceImpl.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.
+ */
+
+#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();
+
+  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;
+    std::mutex mLock;
+    bool mServerStopped GUARDED_BY(mLock);
+
+    // Thread-safe. For test impl only.
+    FakeTaskGenerator mFakeTaskGenerator;
+    // Thread-sfae.
+    TaskQueue mTaskQueue;
+
+    void fakeTaskGenerateLoop();
+};
+
+}  // 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..2cdf68b
--- /dev/null
+++ b/automotive/remoteaccess/test_grpc_server/impl/src/TestWakeupClientServiceImpl.cpp
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <android-base/stringprintf.h>
+#include <inttypes.h>
+#include <utils/Log.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();
+}
+
+void TaskQueue::checkForTestTimeoutLoop() {
+    Looper::setForThread(mLooper);
+
+    while (true) {
+        {
+            std::unique_lock<std::mutex> lock(mLock);
+            if (mStopped) {
+                ALOGW("The TestWakeupClientServiceImpl is stopping, "
+                      "exiting checkForTestTimeoutLoop");
+                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.
+        ALOGW("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());
+        ALOGI("Sleeping for %d seconds until next task", 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) {
+    ALOGD("GetRemoteTasks called");
+    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.
+                ALOGW("Failed to deliver remote task to remote access HAL");
+                // 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) {
+    return Status::OK;
+}
+
+}  // 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..bb03e70
--- /dev/null
+++ b/automotive/remoteaccess/test_grpc_server/impl/src/main.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 <string>
+
+#include "TestWakeupClientServiceImpl.h"
+
+#include <grpc/grpc.h>
+#include <grpcpp/security/server_credentials.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+#include <utils/Log.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());
+    ALOGI("Test Remote Access GRPC Server listening on %s", serverAddress.c_str());
+    server->Wait();
+}
+
+int main(int argc, char** argv) {
+    RunServer();
+    return 0;
+}
diff --git a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
index 68a1f26..651c9dc 100644
--- a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
+++ b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
@@ -56,43 +56,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);
@@ -104,12 +119,31 @@
                                              const std::future<void>& cancel) {
     BEGIN_OP(FingerprintHalProperties::operation_authenticate_latency().value_or(DEFAULT_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;
+    }
+
+    int i = 0;
     do {
         if (FingerprintHalProperties::operation_authenticate_fails().value_or(false)) {
             LOG(ERROR) << "Fail: operation_authenticate_fails";
-            cb->onError(Error::VENDOR, 0 /* vendorError */);
+            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,20 +160,25 @@
             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 */);
+        return;
+    } else {
+        LOG(ERROR) << "Fail: fingerprint not enrolled";
+        cb->onAuthenticationFailed();
+    }
 }
 
 void FakeFingerprintEngine::detectInteractionImpl(ISessionCallback* cb,
@@ -147,17 +186,42 @@
     BEGIN_OP(FingerprintHalProperties::operation_detect_interaction_latency().value_or(
             DEFAULT_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 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;
     }
 
-    if (shouldCancel(cancel)) {
-        LOG(ERROR) << "Fail: cancel";
-        cb->onError(Error::CANCELED, 0 /* vendorCode */);
-        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();
@@ -211,24 +275,37 @@
 
 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();
 }
@@ -286,4 +363,96 @@
     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;
+}
+
+std::vector<std::vector<int32_t>> FakeFingerprintEngine::parseEnrollmentCapture(
+        const std::string& str) {
+    std::vector<int32_t> defaultAcquiredInfo = {(int32_t)AcquiredInfo::GOOD};
+    std::vector<std::vector<int32_t>> res;
+    int i = 0, N = str.length();
+    std::size_t found = 0;
+    bool aborted = true;
+
+    while (found != std::string::npos) {
+        std::string durationStr, acquiredStr;
+        found = str.find_first_of("-,", i);
+        if (found == std::string::npos) {
+            if (N - i < 1) break;
+            durationStr = str.substr(i, N - i);
+        } else {
+            durationStr = str.substr(i, found - i);
+            if (str[found] == '-') {
+                found = str.find_first_of('[', found + 1);
+                if (found == std::string::npos) break;
+                i = found + 1;
+                found = str.find_first_of(']', found + 1);
+                if (found == std::string::npos) break;
+                acquiredStr = str.substr(i, found - i);
+                found = str.find_first_of(',', found + 1);
+            }
+        }
+        std::vector<int32_t> duration{0};
+        if (!ParseInt(durationStr, &duration[0])) break;
+        res.push_back(duration);
+        if (!acquiredStr.empty()) {
+            std::vector<int32_t> acquiredInfo = parseIntSequence(acquiredStr);
+            if (acquiredInfo.empty()) break;
+            res.push_back(acquiredInfo);
+        } else
+            res.push_back(defaultAcquiredInfo);
+
+        i = found + 1;
+        if (found == std::string::npos || found == N - 1) aborted = false;
+    }
+
+    if (aborted) {
+        LOG(ERROR) << "Failed to parse enrollment captures:" + str;
+        res.clear();
+    }
+
+    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;
+}
+
 }  // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/Fingerprint.cpp b/biometrics/fingerprint/aidl/default/Fingerprint.cpp
index 922781c..74e7caf 100644
--- a/biometrics/fingerprint/aidl/default/Fingerprint.cpp
+++ b/biometrics/fingerprint/aidl/default/Fingerprint.cpp
@@ -65,8 +65,18 @@
             {SW_COMPONENT_ID, "" /* hardwareVersion */, "" /* firmwareVersion */,
              "" /* serialNumber */, SW_VERSION}};
 
-    common::CommonProps commonProps = {SENSOR_ID, SENSOR_STRENGTH, MAX_ENROLLMENTS_PER_USER,
-                                       componentInfo};
+    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 = {sensorId, (common::SensorStrength)sensorStrength,
+                                       maxEnrollments, componentInfo};
 
     SensorLocation sensorLocation = mEngine->getSensorLocation();
 
@@ -75,8 +85,10 @@
     *out = {{commonProps,
              mSensorType,
              {sensorLocation},
-             SUPPORTS_NAVIGATION_GESTURES,
-             false /* supportsDetectInteraction */}};
+             navigationGuesture,
+             detectInteraction,
+             displayTouch,
+             controlIllumination}};
     return ndk::ScopedAStatus::ok();
 }
 
diff --git a/biometrics/fingerprint/aidl/default/README.md b/biometrics/fingerprint/aidl/default/README.md
index bb6bb48..ad471f7 100644
--- a/biometrics/fingerprint/aidl/default/README.md
+++ b/biometrics/fingerprint/aidl/default/README.md
@@ -65,7 +65,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,7 +74,52 @@
 $ 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
+
+## View HAL State
 
 To view all the properties of the HAL (see `fingerprint.sysprop` file for the API):
 
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..fa21663 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
@@ -5,7 +5,7 @@
     api_name: "authenticator_id"
     type: Long
     access: ReadWrite
-    prop_name: "vendor.fingerprint.virtual.authenticator_id"
+    prop_name: "persist.vendor.fingerprint.virtual.authenticator_id"
   }
   prop {
     api_name: "challenge"
@@ -14,6 +14,21 @@
     prop_name: "vendor.fingerprint.virtual.challenge"
   }
   prop {
+    api_name: "control_illumination"
+    access: ReadWrite
+    prop_name: "persist.vendor.fingerprint.virtual.udfps.control_illumination"
+  }
+  prop {
+    api_name: "detect_interaction"
+    access: ReadWrite
+    prop_name: "persist.vendor.fingerprint.virtual.detect_interaction"
+  }
+  prop {
+    api_name: "display_touch"
+    access: ReadWrite
+    prop_name: "persist.vendor.fingerprint.virtual.udfps.display_touch"
+  }
+  prop {
     api_name: "enrollment_hit"
     type: Integer
     access: ReadWrite
@@ -28,7 +43,18 @@
   prop {
     api_name: "lockout"
     access: ReadWrite
-    prop_name: "vendor.fingerprint.virtual.lockout"
+    prop_name: "persist.vendor.fingerprint.virtual.lockout"
+  }
+  prop {
+    api_name: "max_enrollments"
+    type: Integer
+    access: ReadWrite
+    prop_name: "persist.vendor.fingerprint.virtual.max_enrollments"
+  }
+  prop {
+    api_name: "navigation_guesture"
+    access: ReadWrite
+    prop_name: "persist.vendor.fingerprint.virtual.navigation_guesture"
   }
   prop {
     api_name: "next_enrollment"
@@ -37,12 +63,24 @@
     prop_name: "vendor.fingerprint.virtual.next_enrollment"
   }
   prop {
+    api_name: "operation_authenticate_acquired"
+    type: String
+    access: ReadWrite
+    prop_name: "vendor.fingerprint.virtual.operation_authenticate_acquired"
+  }
+  prop {
     api_name: "operation_authenticate_duration"
     type: Integer
     access: ReadWrite
     prop_name: "vendor.fingerprint.virtual.operation_authenticate_duration"
   }
   prop {
+    api_name: "operation_authenticate_error"
+    type: Integer
+    access: ReadWrite
+    prop_name: "vendor.fingerprint.virtual.operation_authenticate_error"
+  }
+  prop {
     api_name: "operation_authenticate_fails"
     access: ReadWrite
     prop_name: "vendor.fingerprint.virtual.operation_authenticate_fails"
@@ -54,9 +92,22 @@
     prop_name: "vendor.fingerprint.virtual.operation_authenticate_latency"
   }
   prop {
-    api_name: "operation_detect_interaction_fails"
+    api_name: "operation_detect_interaction_acquired"
+    type: String
     access: ReadWrite
-    prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_fails"
+    prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_acquired"
+  }
+  prop {
+    api_name: "operation_detect_interaction_duration"
+    type: Integer
+    access: ReadWrite
+    prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_duration"
+  }
+  prop {
+    api_name: "operation_detect_interaction_error"
+    type: Integer
+    access: ReadWrite
+    prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_error"
   }
   prop {
     api_name: "operation_detect_interaction_latency"
@@ -65,9 +116,10 @@
     prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_latency"
   }
   prop {
-    api_name: "operation_enroll_fails"
+    api_name: "operation_enroll_error"
+    type: Integer
     access: ReadWrite
-    prop_name: "vendor.fingerprint.virtual.operation_enroll_fails"
+    prop_name: "vendor.fingerprint.virtual.operation_enroll_error"
   }
   prop {
     api_name: "operation_enroll_latency"
@@ -76,12 +128,24 @@
     prop_name: "vendor.fingerprint.virtual.operation_enroll_latency"
   }
   prop {
+    api_name: "sensor_id"
+    type: Integer
+    access: ReadWrite
+    prop_name: "persist.vendor.fingerprint.virtual.sensor_id"
+  }
+  prop {
     api_name: "sensor_location"
     type: String
     access: ReadWrite
     prop_name: "persist.vendor.fingerprint.virtual.sensor_location"
   }
   prop {
+    api_name: "sensor_strength"
+    type: Integer
+    access: ReadWrite
+    prop_name: "persist.vendor.fingerprint.virtual.sensor_strength"
+  }
+  prop {
     api_name: "type"
     type: String
     access: ReadWrite
diff --git a/biometrics/fingerprint/aidl/default/fingerprint.sysprop b/biometrics/fingerprint/aidl/default/fingerprint.sysprop
index 85e93b0..9b8fada 100644
--- a/biometrics/fingerprint/aidl/default/fingerprint.sysprop
+++ b/biometrics/fingerprint/aidl/default/fingerprint.sysprop
@@ -32,8 +32,12 @@
     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"
@@ -45,7 +49,7 @@
 
 # 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
     access: ReadWrite
@@ -63,7 +67,7 @@
 
 # if locked out
 prop {
-    prop_name: "vendor.fingerprint.virtual.lockout"
+    prop_name: "persist.vendor.fingerprint.virtual.lockout"
     type: Boolean
     scope: Public
     access: ReadWrite
@@ -79,22 +83,26 @@
     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
+    prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_error"
+    type: Integer
     scope: Public
     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
+    prop_name: "vendor.fingerprint.virtual.operation_enroll_error"
+    type: Integer
     scope: Public
     access: ReadWrite
-    api_name: "operation_enroll_fails"
+    api_name: "operation_enroll_error"
 }
 
 # add a latency to authentication operations
@@ -134,6 +142,15 @@
     api_name: "operation_authenticate_duration"
 }
 
+# insert error for authenticate operations
+prop {
+    prop_name: "vendor.fingerprint.virtual.operation_authenticate_error"
+    type: Integer
+    scope: Public
+    access: ReadWrite
+    api_name: "operation_authenticate_error"
+}
+
 # sensor location
 #    <x>:<y>:<radius> in pixel
 prop {
@@ -143,3 +160,99 @@
     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: Public
+    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: Public
+    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: Public
+    access: ReadWrite
+    api_name: "operation_detect_interaction_acquired"
+}
+
+# sensor id (default: 5)
+prop {
+    prop_name: "persist.vendor.fingerprint.virtual.sensor_id"
+    type: Integer
+    scope: Public
+    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: Public
+    access: ReadWrite
+    api_name: "sensor_strength"
+}
+
+# max enrollments per user (default: 5)
+#
+prop {
+    prop_name: "persist.vendor.fingerprint.virtual.max_enrollments"
+    type: Integer
+    scope: Public
+    access: ReadWrite
+    api_name: "max_enrollments"
+}
+
+# whether support navigation guestures (default: false)
+prop {
+    prop_name: "persist.vendor.fingerprint.virtual.navigation_guesture"
+    type: Boolean
+    scope: Public
+    access: ReadWrite
+    api_name: "navigation_guesture"
+}
+
+# whether support detect interaction (default: false)
+prop {
+    prop_name: "persist.vendor.fingerprint.virtual.detect_interaction"
+    type: Boolean
+    scope: Public
+    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: Public
+    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: Public
+    access: ReadWrite
+    api_name: "control_illumination"
+}
diff --git a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
index d7df818..22b1744 100644
--- a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
+++ b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
@@ -59,7 +59,17 @@
 
     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);
+
     std::mt19937 mRandom;
+
+  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);
 };
 
 }  // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp b/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp
index 8696d26..32d01f4 100644
--- a/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp
+++ b/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp
@@ -38,8 +38,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 +63,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 +98,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,6 +110,9 @@
     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 {
@@ -116,6 +124,12 @@
         mCallback = ndk::SharedRefBase::make<TestSessionCallback>();
     }
 
+    void TearDown() override {
+        FingerprintHalProperties::operation_authenticate_error(0);
+        FingerprintHalProperties::operation_detect_interaction_error(0);
+        FingerprintHalProperties::operation_authenticate_acquired("");
+    }
+
     FakeFingerprintEngine mEngine;
     std::shared_ptr<TestSessionCallback> mCallback;
     std::promise<void> mCancel;
@@ -135,11 +149,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 +178,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 +206,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 +244,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 +251,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,11 +262,41 @@
     ASSERT_NE(mCallback->mError, Error::UNKNOWN);
 }
 
+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::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) {
@@ -261,6 +322,26 @@
     ASSERT_EQ(0, mCallback->mInteractionDetectedCount);
 }
 
+TEST_F(FakeFingerprintEngineTest, InteractionDetectError) {
+    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::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 +371,76 @@
     }
 }
 
+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);
+    }
+}
+
 }  // 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..7c0021f 100644
--- a/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineUdfpsTest.cpp
+++ b/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineUdfpsTest.cpp
@@ -47,14 +47,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,8 +62,14 @@
     ASSERT_TRUE(sc.sensorLocationY == 200);
     ASSERT_TRUE(sc.sensorRadius == 30);
     ASSERT_TRUE(sc.display == "screen1");
+}
 
-    loc = "100";
+TEST_F(FakeFingerprintEngineUdfpsTest, getSensorLocationBad) {
+    FingerprintHalProperties::sensor_location("");
+    SensorLocation sc = mEngine.getSensorLocation();
+    ASSERT_TRUE(isDefaultLocation(sc));
+
+    auto loc = "100";
     FingerprintHalProperties::sensor_location(loc);
     sc = mEngine.getSensorLocation();
     ASSERT_TRUE(isDefaultLocation(sc));
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/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/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index a20d15d..ee61dfc 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -166,14 +166,6 @@
             <regex-instance>.*</regex-instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="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>
@@ -190,9 +182,9 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="aidl" optional="true">
         <name>android.hardware.confirmationui</name>
-        <version>1.0</version>
+        <version>1</version>
         <interface>
             <name>IConfirmationUI</name>
             <instance>default</instance>
@@ -238,7 +230,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>
@@ -305,7 +297,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 +344,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 +353,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,18 +377,6 @@
             <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>
-        <interface>
-            <name>IOmx</name>
-            <instance>default</instance>
-        </interface>
-        <interface>
-            <name>IOmxStore</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.memtrack</name>
         <version>1</version>
@@ -600,22 +580,28 @@
             <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="aidl" optional="true">
+        <name>android.hardware.tv.hdmi</name>
+        <interface>
+            <name>IHdmi</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.tv.input</name>
         <version>1.0</version>
diff --git a/compatibility_matrices/exclude/fcm_exclude.cpp b/compatibility_matrices/exclude/fcm_exclude.cpp
index 6de9d03..cb77c7b 100644
--- a/compatibility_matrices/exclude/fcm_exclude.cpp
+++ b/compatibility_matrices/exclude/fcm_exclude.cpp
@@ -68,6 +68,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/audio/aidl/default/include/visualizer-impl/Visualizer.h b/confirmationui/aidl/android/hardware/confirmationui/UIOption.aidl
similarity index 60%
copy from audio/aidl/default/include/visualizer-impl/Visualizer.h
copy to confirmationui/aidl/android/hardware/confirmationui/UIOption.aidl
index 4b82dd0..b242c53 100644
--- a/audio/aidl/default/include/visualizer-impl/Visualizer.h
+++ b/confirmationui/aidl/android/hardware/confirmationui/UIOption.aidl
@@ -14,18 +14,20 @@
  * limitations under the License.
  */
 
-#pragma once
+package android.hardware.confirmationui;
 
-#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
+/**
+ * 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/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/audio/aidl/default/include/visualizer-impl/Visualizer.h b/fastboot/aidl/android/hardware/fastboot/FileSystemType.aidl
similarity index 60%
copy from audio/aidl/default/include/visualizer-impl/Visualizer.h
copy to fastboot/aidl/android/hardware/fastboot/FileSystemType.aidl
index 4b82dd0..b4027ec 100644
--- a/audio/aidl/default/include/visualizer-impl/Visualizer.h
+++ b/fastboot/aidl/android/hardware/fastboot/FileSystemType.aidl
@@ -14,18 +14,21 @@
  * limitations under the License.
  */
 
-#pragma once
+package android.hardware.fastboot;
 
-#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
+@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..5cd4542
--- /dev/null
+++ b/fastboot/aidl/default/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"],
+}
+
+cc_library {
+    name: "android.hardware.fastboot-impl-mock",
+    recovery: true,
+    srcs: [
+        "Fastboot.cpp",
+    ],
+    relative_install_path: "hw",
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "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/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/IGnssCallback.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssCallback.aidl
index 48c88f5..fd07a6e 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;
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..2b2592b 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;
 
@@ -308,4 +309,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/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..8a4d186 100644
--- a/gnss/aidl/default/Gnss.cpp
+++ b/gnss/aidl/default/Gnss.cpp
@@ -74,7 +74,21 @@
     if (!status.isOk()) {
         ALOGE("%s: Unable to invoke callback.gnssSetSystemInfoCb", __func__);
     }
-
+    GnssSignalType signalType1 = {
+            .constellation = GnssConstellationType::GPS,
+            .carrierFrequencyHz = 1.59975e+09,
+            .codeType = GnssSignalType::CODE_TYPE_C,
+    };
+    GnssSignalType signalType2 = {
+            .constellation = GnssConstellationType::GLONASS,
+            .carrierFrequencyHz = 1.59975e+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/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/gnss_hal_test.cpp b/gnss/aidl/vts/gnss_hal_test.cpp
index 0e1218e..91cd917 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) {
diff --git a/gnss/aidl/vts/gnss_hal_test.h b/gnss/aidl/vts/gnss_hal_test.h
index 645fc82..c49c1b9 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);
diff --git a/gnss/aidl/vts/gnss_hal_test_cases.cpp b/gnss/aidl/vts/gnss_hal_test_cases.cpp
index 3696233..f1a9894 100644
--- a/gnss/aidl/vts/gnss_hal_test_cases.cpp
+++ b/gnss/aidl/vts/gnss_hal_test_cases.cpp
@@ -1494,3 +1494,32 @@
         assertMeanAndStdev(locationIntervalMs, deltas);
     }
 }
+
+TEST_P(GnssHalTest, TestGnssMeasurementSetCallback) {
+    if (aidl_gnss_hal_->getInterfaceVersion() <= 2) {
+        return;
+    }
+
+    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, /* timeoutSeconds= */ 10, deltas);
+
+    // setCallback at 1s interval and wait for 5 measurements
+    startMeasurementWithInterval(1000, iGnssMeasurement, callback);
+    collectMeasurementIntervals(callback, /* numEvents= */ 5, /* timeoutSeconds= */ 10, deltas);
+
+    // verify the measurements were received at 1Hz
+    assertMeanAndStdev(1000, deltas);
+
+    status = iGnssMeasurement->close();
+    ASSERT_TRUE(status.isOk());
+}
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/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..b17643e 100644
--- a/graphics/Android.bp
+++ b/graphics/Android.bp
@@ -47,13 +47,13 @@
 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/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/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/audio/aidl/default/include/visualizer-impl/Visualizer.h b/graphics/composer/aidl/android/hardware/graphics/composer3/SupportedBufferCombinations.aidl
similarity index 60%
copy from audio/aidl/default/include/visualizer-impl/Visualizer.h
copy to graphics/composer/aidl/android/hardware/graphics/composer3/SupportedBufferCombinations.aidl
index 4b82dd0..41f8817 100644
--- a/audio/aidl/default/include/visualizer-impl/Visualizer.h
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/SupportedBufferCombinations.aidl
@@ -1,4 +1,4 @@
-/*
+/**
  * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,18 +14,12 @@
  * limitations under the License.
  */
 
-#pragma once
+package android.hardware.graphics.composer3;
 
-#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
+@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/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..6358b85 100644
--- a/graphics/composer/aidl/vts/VtsComposerClient.h
+++ b/graphics/composer/aidl/vts/VtsComposerClient.h
@@ -172,6 +172,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_TargetTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
index 93b646f..78dce63 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>
@@ -808,6 +809,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());
 
diff --git a/identity/aidl/Android.bp b/identity/aidl/Android.bp
index 57451ed..a33d43c 100644
--- a/identity/aidl/Android.bp
+++ b/identity/aidl/Android.bp
@@ -14,7 +14,7 @@
         "android/hardware/identity/*.aidl",
     ],
     imports: [
-        "android.hardware.keymaster",
+        "android.hardware.keymaster-V3",
         "android.hardware.security.keymint",
     ],
     stability: "vintf",
@@ -66,20 +66,20 @@
 cc_defaults {
     name: "identity_use_latest_hal_aidl_ndk_static",
     static_libs: [
-        "android.hardware.identity-V4-ndk",
+        "android.hardware.identity-V5-ndk",
     ],
 }
 
 cc_defaults {
     name: "identity_use_latest_hal_aidl_ndk_shared",
     shared_libs: [
-        "android.hardware.identity-V4-ndk",
+        "android.hardware.identity-V5-ndk",
     ],
 }
 
 cc_defaults {
     name: "identity_use_latest_hal_aidl_cpp_static",
     static_libs: [
-        "android.hardware.identity-V4-cpp",
+        "android.hardware.identity-V5-cpp",
     ],
 }
diff --git a/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/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/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/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..aa95be4
--- /dev/null
+++ b/power/aidl/default/PowerHintSession.cpp
@@ -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.
+ */
+
+#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();
+}
+
+}  // 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..6a7627a
--- /dev/null
+++ b/power/aidl/default/PowerHintSession.h
@@ -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.
+ */
+
+#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;
+};
+
+}  // 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..e51f756 100644
--- a/power/aidl/vts/VtsHalPowerTargetTest.cpp
+++ b/power/aidl/vts/VtsHalPowerTargetTest.cpp
@@ -92,6 +92,14 @@
         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;
+
 inline bool isUnknownOrUnsupported(const ndk::ScopedAStatus& status) {
     return status.getStatus() == STATUS_UNKNOWN_TRANSACTION ||
            status.getExceptionCode() == EX_UNSUPPORTED_OPERATION;
@@ -103,9 +111,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 +173,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 +185,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 +201,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 +216,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());
@@ -226,14 +245,13 @@
 // 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/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/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/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/RKP_CHANGELOG.md b/security/keymint/RKP_CHANGELOG.md
index dfcc938..243fc26 100644
--- a/security/keymint/RKP_CHANGELOG.md
+++ b/security/keymint/RKP_CHANGELOG.md
@@ -21,13 +21,13 @@
 ## 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
+    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.
 
diff --git a/security/keymint/aidl/Android.bp b/security/keymint/aidl/Android.bp
index 96d44a7..6efff2f 100644
--- a/security/keymint/aidl/Android.bp
+++ b/security/keymint/aidl/Android.bp
@@ -52,21 +52,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 +76,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/android/hardware/security/keymint/DeviceInfo.aidl b/security/keymint/aidl/android/hardware/security/keymint/DeviceInfo.aidl
index 6954d65..f0af619 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/DeviceInfo.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/DeviceInfo.aidl
@@ -49,7 +49,6 @@
      *         "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
index c2acbed..86c1717 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
@@ -29,7 +29,7 @@
  * 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).
+ * 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
@@ -79,9 +79,9 @@
  * 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.
+ * 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
  * ==================
@@ -151,7 +151,8 @@
 
     /**
      * 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.
+     * 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
@@ -170,7 +171,7 @@
      *        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
+     * @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
@@ -197,7 +198,7 @@
      *                 -2 : bstr                      ; Ed25519 public key
      *            }
      *
-     *            SignatureKeyP256 = {
+     *            SignatureKeyP256 = {                ; COSE_Key
      *                 1 : 2,                         ; Key type : EC2
      *                 3 : AlgorithmES256,            ; Algorithm
      *                 -1 : 1,                        ; Curve: P256
@@ -227,7 +228,7 @@
      *                2 : bstr             ; KID : EEK ID
      *                3 : -25,             ; Algorithm : ECDH-ES + HKDF-256
      *                -1 : 4,              ; Curve : X25519
-     *                -2 : bstr            ; Ed25519 public key
+     *                -2 : bstr            ; X25519 public key
      *            }
      *
      *            EekP256 = {              ; COSE_Key
@@ -246,8 +247,8 @@
      *                payload: bstr .cbor EekX25519 / .cbor EekP256
      *            ]
      *
-     *            AlgorithmES256 = -7
-     *            AlgorithmEdDSA = -8
+     *            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.
@@ -256,7 +257,7 @@
      *        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
+     *        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.
      *
@@ -270,7 +271,7 @@
      * @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:
+     * @return The MAC of KeysToSign in the CertificateRequest structure. Specifically, it contains:
      *
      *            HMAC-256(EK_mac, .cbor KeysToMacStructure)
      *
@@ -314,38 +315,50 @@
      *
      * @return the following CBOR Certificate Signing Request (Csr) serialized into a byte array:
      *
-     * Csr = [
-     *    version: 3,              ; The CDDL Schema version.
-     *    UdsCerts,
-     *    DiceCertChain,
-     *    SignedData
-     * ]
+     * Csr = AuthenticatedMessage<CsrPayload>
      *
-     * ; 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
+     * CsrPayload = [                      ; CBOR Array defining the payload for Csr
+     *     version: 1,                     ; The CsrPayload CDDL Schema version.
+     *     CertificateType,                ; The type of certificate being requested.
      *     DeviceInfo,                     ; Defined in DeviceInfo.aidl
      *     challenge: bstr .size (32..64), ; Provided by the method parameters
      *     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.
      *
+     * AuthenticatedMessage<T> = [
+     *    version: 3,              ; The AuthenticatedMessage CDDL Schema version.
+     *    UdsCerts,
+     *    DiceCertChain,
+     *    SignedData<T>,
+     * ]
+     *
+     * ; COSE_Sign1 (untagged)
+     * SignedData<T> = [
+     *     protected: bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 },
+     *     unprotected: {},
+     *     payload: bstr .cbor T / nil,
+     *     signature: bstr         ; PureEd25519(CDI_Leaf_Priv, bstr .cbor SignedDataSigStruct<T>) /
+     *                             ; ECDSA(CDI_Leaf_Priv, bstr .cbor SignedDataSigStruct<T>)
+     * ]
+     *
+     * ; Sig_structure for SignedData
+     * SignedDataSigStruct<T> = [
+     *     context: "Signature1",
+     *     protected: bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 },
+     *     external_aad: bstr .size 0,
+     *     payload: bstr .cbor T
+     * ]
+     *
      * ; 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
@@ -365,7 +378,7 @@
      *                              ; intermediate certificates between Root and Leaf.
      * ]
      *
-     * ; A bstr containing a DER-encoded X.509 certificate (RSA, NIST P-curve, or edDSA)
+     * ; 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.
@@ -378,8 +391,8 @@
      *                                      ; 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
+     * ; 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
@@ -408,8 +421,8 @@
      *     -4670551 : bstr,                         ; Mode
      * }
      *
-     * ; Each entry in the Dcc is a DiceChainEntryPayload signed by the key from the previous entry
-     * ; in the Dcc array.
+     * ; 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: {},
diff --git a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
index e1f65fe..4f361bb 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;
     }
 
@@ -261,7 +266,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 +289,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 +344,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 +369,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 +382,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 +660,131 @@
 
 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.
+ */
+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 firstBcc = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge_);
+    ASSERT_TRUE(firstBcc) << firstBcc.message();
+
+    status = provisionable_->generateCertificateRequestV2(keysToSign_, challenge_, &csr);
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+    auto secondBcc = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge_);
+    ASSERT_TRUE(secondBcc) << secondBcc.message();
+
+    ASSERT_EQ(firstBcc->size(), secondBcc->size());
+    for (auto i = 0; i < firstBcc->size(); i++) {
+        ASSERT_EQ(firstBcc->at(i).pubKey, secondBcc->at(i).pubKey);
+    }
+}
+
+/**
+ * Generate a non-empty certificate request with multiple keys.
+ */
+TEST_P(CertificateRequestV2Test, NonEmptyRequestMultipleKeys) {
+    // TODO(b/254137722): define a minimum number of keys that must be supported.
+    generateKeys(false /* testMode */, 5 /* 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/support/include/remote_prov/remote_prov_utils.h b/security/keymint/support/include/remote_prov/remote_prov_utils.h
index 9ea20ac..6871e1b 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,19 @@
         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::vector<BccEntryData>> 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::vector<BccEntryData>> 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..f7ab3ac 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.
@@ -527,22 +530,27 @@
     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 +587,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 +742,264 @@
                                /*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<cppbor::Array> parseAndValidateCsrPayload(const cppbor::Array& keysToSign,
+                                                   const std::vector<uint8_t>& csrPayload,
+                                                   IRemotelyProvisionedComponent* provisionable,
+                                                   const std::vector<uint8_t>& challenge,
+                                                   bool isFactory) {
+    auto [parsedCsrPayload, _, errMsg] = cppbor::parse(csrPayload);
+    if (!parsedCsrPayload) {
+        return errMsg;
+    }
+    if (!parsedCsrPayload->asArray()) {
+        return "CSR payload is not a CBOR array.";
+    }
+    if (parsedCsrPayload->asArray()->size() != 5U) {
+        return "CSR payload must contain version, certificate type, device info, challenge, keys. "
+               "However, the parsed CSR payload has " +
+               std::to_string(parsedCsrPayload->asArray()->size()) + " entries.";
+    }
+
+    auto& signedVersion = parsedCsrPayload->asArray()->get(0);
+    auto& signedCertificateType = parsedCsrPayload->asArray()->get(1);
+    auto& signedDeviceInfo = parsedCsrPayload->asArray()->get(2);
+    auto& signedChallenge = parsedCsrPayload->asArray()->get(3);
+    auto& signedKeys = parsedCsrPayload->asArray()->get(4);
+
+    if (!signedVersion || !signedVersion->asUint() || signedVersion->asUint()->value() != 1U) {
+        return "CSR payload version must be an unsigned integer and must be equal to 1.";
+    }
+    if (!signedCertificateType || !signedCertificateType->asTstr()) {
+        // 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 || !signedDeviceInfo->asMap()) {
+        return "Device info must be an Map.";
+    }
+    if (!signedChallenge || !signedChallenge->asBstr()) {
+        return "Challenge must be a Bstr.";
+    }
+    if (!signedKeys || !signedKeys->asArray()) {
+        return "Keys must be an Array.";
+    }
+
+    auto result = parseAndValidateDeviceInfo(signedDeviceInfo->asMap()->encode(), provisionable,
+                                             isFactory);
+    if (!result) {
+        return result.message();
+    }
+
+    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->asBstr() != challengeBstr) {
+        return "Signed challenge does not match."
+               "\n  Actual: " +
+               cppbor::prettyPrint(signedChallenge->asBstr(), 64 /* maxBStrSize */) +
+               "\nExpected: " + cppbor::prettyPrint(&challengeBstr, 64 /* maxBStrSize */);
+    }
+
+    if (signedKeys->asArray()->encode() != keysToSign.encode()) {
+        return "Signed keys do not match.";
+    }
+
+    return std::move(*parsedCsrPayload->asArray());
+}
+
+ErrMsgOr<std::vector<BccEntryData>> verifyCsr(const cppbor::Array& keysToSign,
+                                              const std::vector<uint8_t>& csr,
+                                              IRemotelyProvisionedComponent* provisionable,
+                                              const std::vector<uint8_t>& challenge,
+                                              bool isFactory) {
+    auto [parsedCsr, _, csrErrMsg] = cppbor::parse(csr);
+    if (!parsedCsr) {
+        return csrErrMsg;
+    }
+    if (!parsedCsr->asArray()) {
+        return "CSR is not a CBOR array.";
+    }
+    if (parsedCsr->asArray()->size() != 4U) {
+        return "CSR must contain version, UDS certificates, DICE chain, and signed data. "
+               "However, the parsed CSR has " +
+               std::to_string(parsedCsr->asArray()->size()) + " entries.";
+    }
+
+    auto& version = parsedCsr->asArray()->get(0);
+    auto& udsCerts = parsedCsr->asArray()->get(1);
+    auto& diceCertChain = parsedCsr->asArray()->get(2);
+    auto& signedData = parsedCsr->asArray()->get(3);
+
+    if (!version || !version->asUint() || version->asUint()->value() != 3U) {
+        return "Version must be an unsigned integer and must be equal to 3.";
+    }
+    if (!udsCerts || !udsCerts->asMap()) {
+        return "UdsCerts must be an Map.";
+    }
+    if (!diceCertChain || !diceCertChain->asArray()) {
+        return "DiceCertChain must be an Array.";
+    }
+    if (!signedData || !signedData->asArray()) {
+        return "SignedData must be an Array.";
+    }
+
+    RpcHardwareInfo info;
+    provisionable->getHardwareInfo(&info);
+    if (version->asUint()->value() != info.versionNumber) {
+        return "CSR version (" + std::to_string(version->asUint()->value()) +
+               ") does not match the remotely provisioned component version (" +
+               std::to_string(info.versionNumber) + ").";
+    }
+
+    // DICE chain is [ pubkey, + DiceChainEntry ]. Its format is the same as BCC from RKP v1-2.
+    auto diceContents = validateBcc(diceCertChain->asArray());
+    if (!diceContents) {
+        return diceContents.message() + "\n" + prettyPrint(diceCertChain.get());
+    }
+    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->asMap(), udsPub);
+    if (!error.empty()) {
+        return error;
+    }
+
+    auto csrPayload = verifyAndParseCoseSign1(signedData->asArray(), udsPub, {} /* aad */);
+    if (!csrPayload) {
+        return csrPayload.message();
+    }
+
+    auto parsedCsrPayload = parseAndValidateCsrPayload(keysToSign, *csrPayload, provisionable,
+                                                       challenge, isFactory);
+    if (!parsedCsrPayload) {
+        return parsedCsrPayload.message();
+    }
+
+    return *diceContents;
+}
+
+ErrMsgOr<std::vector<BccEntryData>> 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::vector<BccEntryData>> 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/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/audio/aidl/default/include/visualizer-impl/Visualizer.h b/thermal/aidl/android/hardware/thermal/CoolingType.aidl
similarity index 60%
copy from audio/aidl/default/include/visualizer-impl/Visualizer.h
copy to thermal/aidl/android/hardware/thermal/CoolingType.aidl
index 4b82dd0..1b430d2 100644
--- a/audio/aidl/default/include/visualizer-impl/Visualizer.h
+++ b/thermal/aidl/android/hardware/thermal/CoolingType.aidl
@@ -14,18 +14,23 @@
  * limitations under the License.
  */
 
-#pragma once
+package android.hardware.thermal;
 
-#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
+/**
+ * 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/audio/aidl/default/include/visualizer-impl/Visualizer.h b/tv/cec/aidl/android/hardware/tv/cec/AbortReason.aidl
similarity index 60%
copy from audio/aidl/default/include/visualizer-impl/Visualizer.h
copy to tv/cec/aidl/android/hardware/tv/cec/AbortReason.aidl
index 4b82dd0..3ae23ec 100644
--- a/audio/aidl/default/include/visualizer-impl/Visualizer.h
+++ b/tv/cec/aidl/android/hardware/tv/cec/AbortReason.aidl
@@ -14,18 +14,18 @@
  * limitations under the License.
  */
 
-#pragma once
+package android.hardware.tv.cec;
 
-#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
+/**
+ * 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/audio/aidl/default/include/visualizer-impl/Visualizer.h b/tv/cec/aidl/android/hardware/tv/cec/CecDeviceType.aidl
similarity index 60%
rename from audio/aidl/default/include/visualizer-impl/Visualizer.h
rename to tv/cec/aidl/android/hardware/tv/cec/CecDeviceType.aidl
index 4b82dd0..16dfbec 100644
--- a/audio/aidl/default/include/visualizer-impl/Visualizer.h
+++ b/tv/cec/aidl/android/hardware/tv/cec/CecDeviceType.aidl
@@ -14,18 +14,15 @@
  * limitations under the License.
  */
 
-#pragma once
+package android.hardware.tv.cec;
 
-#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
+@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/audio/aidl/default/include/visualizer-impl/Visualizer.h b/tv/cec/aidl/android/hardware/tv/cec/IHdmiCecCallback.aidl
similarity index 60%
copy from audio/aidl/default/include/visualizer-impl/Visualizer.h
copy to tv/cec/aidl/android/hardware/tv/cec/IHdmiCecCallback.aidl
index 4b82dd0..4934a64 100644
--- a/audio/aidl/default/include/visualizer-impl/Visualizer.h
+++ b/tv/cec/aidl/android/hardware/tv/cec/IHdmiCecCallback.aidl
@@ -14,18 +14,18 @@
  * limitations under the License.
  */
 
-#pragma once
+package android.hardware.tv.cec;
 
-#include <cstdlib>
+import android.hardware.tv.cec.CecMessage;
 
-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
+/**
+ * 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/audio/aidl/default/include/visualizer-impl/Visualizer.h b/tv/cec/aidl/android/hardware/tv/cec/Result.aidl
similarity index 60%
copy from audio/aidl/default/include/visualizer-impl/Visualizer.h
copy to tv/cec/aidl/android/hardware/tv/cec/Result.aidl
index 4b82dd0..3184c46 100644
--- a/audio/aidl/default/include/visualizer-impl/Visualizer.h
+++ b/tv/cec/aidl/android/hardware/tv/cec/Result.aidl
@@ -14,18 +14,15 @@
  * limitations under the License.
  */
 
-#pragma once
+package android.hardware.tv.cec;
 
-#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
+@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/audio/aidl/default/include/visualizer-impl/Visualizer.h b/tv/cec/aidl/android/hardware/tv/cec/SendMessageResult.aidl
similarity index 60%
copy from audio/aidl/default/include/visualizer-impl/Visualizer.h
copy to tv/cec/aidl/android/hardware/tv/cec/SendMessageResult.aidl
index 4b82dd0..8cb98bc 100644
--- a/audio/aidl/default/include/visualizer-impl/Visualizer.h
+++ b/tv/cec/aidl/android/hardware/tv/cec/SendMessageResult.aidl
@@ -14,18 +14,16 @@
  * limitations under the License.
  */
 
-#pragma once
+package android.hardware.tv.cec;
 
-#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
+/**
+ * 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..a5e3a2a
--- /dev/null
+++ b/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/HdmiPortInfo.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.tv.hdmi;
+@VintfStability
+parcelable HdmiPortInfo {
+  android.hardware.tv.hdmi.HdmiPortType type;
+  int portId;
+  boolean cecSupported;
+  boolean arcSupported;
+  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..1d6f27d
--- /dev/null
+++ b/tv/hdmi/aidl/android/hardware/tv/hdmi/HdmiPortInfo.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.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;
+    // 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/audio/aidl/default/include/visualizer-impl/Visualizer.h b/tv/hdmi/aidl/android/hardware/tv/hdmi/HdmiPortType.aidl
similarity index 60%
copy from audio/aidl/default/include/visualizer-impl/Visualizer.h
copy to tv/hdmi/aidl/android/hardware/tv/hdmi/HdmiPortType.aidl
index 4b82dd0..59c0d42 100644
--- a/audio/aidl/default/include/visualizer-impl/Visualizer.h
+++ b/tv/hdmi/aidl/android/hardware/tv/hdmi/HdmiPortType.aidl
@@ -14,18 +14,14 @@
  * limitations under the License.
  */
 
-#pragma once
+package android.hardware.tv.hdmi;
 
-#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
+/**
+ * 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/audio/aidl/default/include/visualizer-impl/Visualizer.h b/tv/hdmi/aidl/android/hardware/tv/hdmi/IHdmiCallback.aidl
similarity index 60%
copy from audio/aidl/default/include/visualizer-impl/Visualizer.h
copy to tv/hdmi/aidl/android/hardware/tv/hdmi/IHdmiCallback.aidl
index 4b82dd0..51275b0 100644
--- a/audio/aidl/default/include/visualizer-impl/Visualizer.h
+++ b/tv/hdmi/aidl/android/hardware/tv/hdmi/IHdmiCallback.aidl
@@ -14,18 +14,16 @@
  * limitations under the License.
  */
 
-#pragma once
+package android.hardware.tv.hdmi;
 
-#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
+/**
+ * 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..0cf5118
--- /dev/null
+++ b/tv/hdmi/aidl/default/HdmiMock.cpp
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "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,
+                     .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/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/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/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/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/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.6/default/Android.bp b/wifi/1.6/default/Android.bp
index a132dee..0f98e71 100644
--- a/wifi/1.6/default/Android.bp
+++ b/wifi/1.6/default/Android.bp
@@ -226,3 +226,13 @@
         "libwifi-system-iface",
     ],
 }
+
+filegroup {
+    name: "default-android.hardware.wifi@1.0-service.rc",
+    srcs: ["android.hardware.wifi@1.0-service.rc"],
+}
+
+filegroup {
+    name: "default-android.hardware.wifi@1.0-service.xml",
+    srcs: ["android.hardware.wifi@1.0-service.xml"],
+}
diff --git a/wifi/apex/Android.bp b/wifi/apex/Android.bp
new file mode 100644
index 0000000..0afb96b
--- /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@1.0-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@1.0-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@1.0-service",
+    ],
+    prebuilts: [
+        "com.android.hardware.wifi.rc",
+        "com.android.hardware.wifi.xml",
+    ],
+    overrides: [
+        "android.hardware.wifi@1.0-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..812d51d
--- /dev/null
+++ b/wifi/apex/file_contexts
@@ -0,0 +1,3 @@
+(/.*)? 								u:object_r:vendor_file:s0
+/bin/hw/android\.hardware\.wifi@1.0-service			u:object_r:hal_wifi_default_exec:s0
+
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,