[automerger skipped] Merge "Rename mDNS offload feature name" into android14-tests-dev am: 486de7bc69 am: 1d9000b29a am: 502d320cb3 am: f4869af4a4 -s ours

am skip reason: Merged-In I57d8f955c3f5d39814f36b662fee8d045c8c5150 with SHA-1 aee7ba0345 is already in history

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

Change-Id: I9b95b5b14ceee2eb72ce508641d287f516282b62
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/.gitignore b/.gitignore
index 1d74e21..6c7f477 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,4 @@
 .vscode/
+
+# Vim temporary files
+**/*.swp
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 1eca2a1..2e9d9ab 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -85,3 +85,4 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/init/android.hardware.cas@1.1*)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/vintf/manifest/android.hardware.cas@1.1*)
 $(call add-clean-step, rm -rf $(OUT_DIR)/soong/.intermediates/hardware/interfaces/wifi/1.4/android.hardware.wifi@1.4-adapter_genc++/)
+$(call add-clean-step, rm -rf $(OUT_DIR)/soong/.intermediates/hardware/interfaces/automotive/vehicle/aidl/android.hardware.automotive.vehicle-V2-ndk-source/)
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 2116e21..de7aa35 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -10,3 +10,4 @@
 aosp_hook_confirmationui = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} confirmationui
 aosp_hook_gatekeeper = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} gatekeeper
 aosp_hook_keymaster = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} keymaster
+generate_vehicle_property_enums = ${REPO_ROOT}/hardware/interfaces/automotive/vehicle/tools/generate_annotation_enums.py --android_build_top ${REPO_ROOT} --preupload_files ${PREUPLOAD_FILES} --check_only
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 25246d8..92cafbd 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -11,6 +11,9 @@
     },
     {
       "name": "VtsHalTvInputV1_0TargetTest"
+    },
+    {
+      "name": "CtsStrictJavaPackagesTestCases"
     }
   ],
   "auto-presubmit": [
diff --git a/apexkey/Android.bp b/apexkey/Android.bp
new file mode 100644
index 0000000..e74717a
--- /dev/null
+++ b/apexkey/Android.bp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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"],
+}
+
+apex_key {
+    name: "com.android.hardware.key",
+    public_key: "com.android.hardware.avbpubkey",
+    private_key: "com.android.hardware.pem",
+}
+
+android_app_certificate {
+    name: "com.android.hardware.certificate",
+    certificate: "com.android.hardware",
+}
diff --git a/apexkey/OWNERS b/apexkey/OWNERS
new file mode 100644
index 0000000..38765f9
--- /dev/null
+++ b/apexkey/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 296524155
+
+jooyung@google.com
diff --git a/apexkey/com.android.hardware.avbpubkey b/apexkey/com.android.hardware.avbpubkey
new file mode 100644
index 0000000..12f0370
--- /dev/null
+++ b/apexkey/com.android.hardware.avbpubkey
Binary files differ
diff --git a/apexkey/com.android.hardware.pem b/apexkey/com.android.hardware.pem
new file mode 100644
index 0000000..4d2882b
--- /dev/null
+++ b/apexkey/com.android.hardware.pem
@@ -0,0 +1,52 @@
+-----BEGIN PRIVATE KEY-----
+MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQCmirL5vFcGDqg9
+JqKZwRqzPr76t8aqJSu+UOdnlmqBLmUBaeun2KwRsZiLku933m5MNv+CPnVQW7ij
+z0lv0z/qB8SXN+KAgSqRdIjL1ySQgp8ygKHu+GcvbMFj9pVuqufwSrEOY9Un1RRY
+InDDj88c/aNbCw64d1QVedgUIs5KDDLjOzkcrrbH+Th26r2YjhlRKQXCZT5jW1fY
+2gJg5LPeuM4fI63ESxFyRTY/V8E3LbAuTYKBSrHRbec22oCkL/pUilJBe2r8aNyp
+ACWEJB96uWdKmIYDCdj6r6SNzHM3S4X+l1C9/Gi9UNK8nuIAI3v2qW07S2RABAWX
+vKfE8rIKAdFmajGlHKfRe6IL9ka1/rsM1xgDr2/FgEsyRgrfJvlvvMb7ampMgTKu
+Az/hv4siSaDD2E3JrRyh3nNxTCuIABla7/jGmNz6vIdwTRJsa2RIEezkeMiUy+jp
+VyeYsWIEBmQwZ5+k6YbdrKTULaay3UJ6/YXEQY9Sbg0JL/7sjQWILwnrtab3/jsn
+iWsr59Qsaf+q3PnrWPCXT/KC8DwKi/2zSWfCX8MHreqaoozjfWXeD87lnBAhukBS
+984xWEmStJGFQG29J4sF4NmgO1I8GPqQRtoB6ghme11U2EX0vIqrDNccX12ohqgh
+CfwMXX64WV5fWscmSLZin5xK+AN+/wIDAQABAoICABLDnda1ebic/ielqrxYHYIE
+l8/31NJmzb7rrqblM6rKZ2b5YCvRJdH4iI9xRrnivdqod7FdCCq9qtgKCuQmkRT1
+Oxkumr6PzxQEZUVSQDRoAzfVdmlOY5HcVw3EQqHtb6SLRdexN9r9DwW/G6VtFpDV
+owom/Mmb6EVjLQ1XvpZpOXKQwaaRqNZvJgV//Uyq9f9G9/cnIRhguk0cgxgXrIxz
+lgW8J1/udVDCq5IHeSWWaDtPUFzw5YgLMfnkNIpLPZE45HusRCmcRwBjm9Z/m2xg
+Z1roRHEjMudL0uaHGpQoVjiRI+/D+Kkb6iKGZEBPvy/TdxMvM2RjD55BC0YNcjGv
+kXTMLwj2ke824rUPJJOYN8bJFIpOYblMcbDrxYVlDZetKOMc6EJw90xaj4za2IMS
+vWDxZx1WQPcn+B/nUvrMMOTN6MkNYKR97lmxBYP6TeCiUUytZiCF72cvvpYcdhE9
+zzOES5kVakSE8NnLTH9xAjrpAguxI9gqxeyLALhz/Rb46fgWwnhcBdqmPtez/IHb
+BgF81SSobSaBlzLcnRyrjwBRWA21DP8U/ApUkmHR/Lm1BJejzxf1hj35Hp9XUwdC
+JK7aoVnjuko/l5TPn0Bvm4pcBArG0AUL75GlRgDJTVCDZbLFR/2JZlnZ9optvN6E
+vniu3HwBRHDHn0K1DqIBAoIBAQDpdBJtyizIlZ5p6k1f0wWE/B2riPzPwv/a+ygD
+GOtzWsukyZjWHXVPjx2XY3bwlbusiqhJE1OcF+oymHTtSSv3VsqMmo2VDIj8d21T
+ycpBvV7+mcehGk6o6lGTJAiPc1wVMajmM0Co2LQb4hRvf2p8dW6+RRn5c3o288B5
+e45zpbq9+l9PMpgrmOBU3m652JmGK8JqQKeKKT96kZQVf/U3ArMif+jW2piAZnmG
+CS00el0K0RtZe/iKrFftoD27ai9GNZx/Z1p55x+9vUD15LiQ/MK0Bk/f9b24zE98
+6T07KAGPB5gXWlSs2yEk4Waufjw3JSYXs18kEoMklTA0IGGhAoIBAQC2oEwGQZI0
+oR1oL7P76FyMNjtp2T2wYnOcnGeKjp4vxZWTZNRfNUmzGqSamVE1ZPhj721sAImS
+mk1pUJbglkpP6aMDNXzA6Z50PuXfhF5+dXBrLftT1tcNo/8/ysd/iKsi1C6hWZ9L
+YYt/7uR8wazeG65jahsOKEfCrNyDBQzyoSft1qfVTvYzxUVmJRQr5S7H0c9jPTwg
+Qj+/RQsDOspsJrBC5+H0tLPkvZDdZCYvdBzVWFL7npHd0fy53TmT6kEjDwwAiE8W
+VggvzkhHOnprAiwq36nlpGo3um5Ona98dXWZ4rfELEdSUOiWCz2Gzz7IL+H8uhen
+iXQAtlAlMVyfAoIBAQDDGmlobgW9YSVyWQlvIxnCyT02pZa7P7m6VhpbdFEaJ/B3
+eLANibMH2ZCee9bkPA8LpRn9cHR4yJfGzxkxUey3mkZO+b+HqGE3tcudsdAh3tTs
+LLLk1eqVSrcAJKYu1PdJEyaXtI++TNVBVFFF2ZOyDiaOR4vsqPCjylS6cmNcDU6j
+BQLwWlVIYkxhQUACe53avumNCRm74rsVgWLkEPtrjQsOsx1xqmC3Nm0rcrHf4L+v
+kZCs2Wme42fcxQWygoydvaJb65F2vY0OcoM+vXbuXP+PmpLYljSHo+BugTLWJJog
+4fTe13RavgvWGbZJ8F/8qkRKnHLP39TQFwqhFcrhAoIBAQCZYipX+syUHVl4ftA4
+2+CW9pmR/h5cvWOCfq5L5hqf3uAQqlfgGv5qSg9DtU9KfCJOtPH/CriBA83OjRwb
+Rr7lPUJnWI4N7GjkE0u4HhHLPlGMA1OaB9AZKcsgxewmhh/OIc2EQKSUiDnE2lzX
+F0dcSH2AC8brbhNPQyX1eNF2GrpRfL77XdVUh/QQpUW61EMlGmeHXw/XvCyUNaXZ
+MZB/o0LY/q59eyO4EyrPduTHaEsrOIKByJ2UY2BSrqZEQDQzANlAvTtHdDxuAmAc
+StY0d9+mprGoKR347kDlEHUqH/EErTFQtyuzzDZ8hrZHOlrtgaHZRGbHlJ90Vasc
+gcfbAoIBAEIR0dtmd38dC7r0h0SZ7ORIvm9F8JRs+wKdWjiPfWLK3trR/jxRx6Eh
+xrrJEoRCeUmT6rc0TwUkzow5ApcEY338KmsqKVbm3iGfPpvZFEO44vBrg3280QBM
+PerIrEfidflUAE9QXNoBpvvnh2KXIOsvyN2MeY2SAyebPJQJtWzJkP35Y8fOtZkJ
+VtIhYj2wvFuobl7iuxKJG0cn4xL3OLysc03oX7Al2qA42hUCy7UMsTT6ZAPWd49+
+3gOFrqmaV3Hu5KY2HaX6Yly5ohhQWSkSL1kZMo9Uq6tTM+2HFzFU6sveFbWW/XQc
+rWnazDdd1WkHT6+nzA/NX24OzPjiUk0=
+-----END PRIVATE KEY-----
diff --git a/apexkey/com.android.hardware.pk8 b/apexkey/com.android.hardware.pk8
new file mode 100644
index 0000000..97007d2
--- /dev/null
+++ b/apexkey/com.android.hardware.pk8
Binary files differ
diff --git a/apexkey/com.android.hardware.x509.pem b/apexkey/com.android.hardware.x509.pem
new file mode 100644
index 0000000..2728a23
--- /dev/null
+++ b/apexkey/com.android.hardware.x509.pem
@@ -0,0 +1,34 @@
+-----BEGIN CERTIFICATE-----
+MIIF6TCCA9ECFDAU6pJXjblHA/w9a354h2QUOharMA0GCSqGSIb3DQEBCwUAMIGv
+MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91
+bnRhaW4gVmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UECwwHQW5kcm9pZDEi
+MCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTErMCkGA1UEAwwiY29t
+LmFuZHJvaWQuaGFyZHdhcmUudGhyZWFkbmV0d29yazAgFw0yMzA4MjQwNjE4MTZa
+GA80NzYxMDcyMDA2MTgxNlowga8xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxp
+Zm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lk
+MRAwDgYDVQQLDAdBbmRyb2lkMSIwIAYJKoZIhvcNAQkBFhNhbmRyb2lkQGFuZHJv
+aWQuY29tMSswKQYDVQQDDCJjb20uYW5kcm9pZC5oYXJkd2FyZS50aHJlYWRuZXR3
+b3JrMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA5eMXZfeadUJiqZ0b
+kbXYSbzjd1opoeAVk/+LxGyBLLPy2z2EAeuUBx8HYEJhyPOyUrs3ohP6OvAtE8O4
+JeEbGBzqOymusKbve8ght7tDjUuTYsbBsKQWw1Gu/UUK7x3lc6zD+wDTK/5NUoTA
+I/5lI8Q4+NHCI1jb/uBRGSlzSO+k2A2oVUPdyaWWgGhLeEiXKo+Xy6XXduhFK1wc
+iSCgVyuQkZnbrJrGCGS1LD1MavsfBTthD3jfuOq+YqMjGjdi6xVPG3fZnwwdVNzW
+mSFwWwHif56ZAtxyZVtQOAksTqwAwGrUjhn70rw5eLBQjXIL1061cLrOZ4XlRSZj
+kHB8mwr6OQOw7isMORO0h+NNJ+5POa5V9rGylqk/hn1vzcTX62YUZy1N6b3rfGc2
+p9LA6STjvoXLeCFaSIc+LfTiHOamkg7LuLlsQ/AIoXeuaLyWAgg4ls2U8IG1Mdkz
+BClX5vMG/At6yZqHiCIbCU8V8VSCz7Rtuu+C/87G5Pwb/G1r4FHXr9x7d0qj4rWV
+u9MhdzvZWoTTnEzDA+DWPQM/ILkGdkSj0g4yC8GR/F5p7xWQ0vqyMyM/ii1KzWVs
+ZJFUxzpGX99C0mfjT2hezHzfEyisPec39PFbdxzC756yP1Le8I5qjMbjl+XeFjxO
+REoC0nDFgHEI7C5RunT1osKmpDUCAwEAATANBgkqhkiG9w0BAQsFAAOCAgEA3HPY
++nHGFE9aFQbEsjvotuxguLMKmrgQ44yGBTr9349MPvnxGDdz1HPWs/m456k9HQxt
+1YWV+xr56NS37UDVMkqS7hzCkJe/LdMT51qvUS+hPHLzSuZNKuFAaCOb8WDa7tGQ
+MuvISlb6T7G512fUdFDRjFjnIXDLTYANzoxI3cqs2N2xQNxsL8uIJ79RWlPm2Upz
+Y5Ad55kv3EygWgirvZnSNo27E/Tt4Bo9KS0HsYXVHgWK9zHHtup1vDOntJ8bX16C
+rP7e8SELanPbUtyIUDcf14P3EFztUYBZIXO2HUSsoOTX3+Hd592h7EsnGDdlWSLU
+oreaRWCAMh4TKI/eP+1N35b8zmPMHaG+WsWjdDPrs6oNpr2MMA4U8AHGW2d6QY0N
+xZ/VhhbjbHMgmmB3Q2LXZZufbSEBawBfuFjhodfmKSgTjNCTYXtTiT/pL2w0PqEM
+v4UxrGD0uFQafFKuxQfL2LYG5tg46daRrT3BoIqLKoseTuykzW4z08NuurwsLvmy
+t7njqMxlf/tN9o+d3D3lWHQpiDJ8kC/TjgKBj7iQTCOJeShutxyR2F3R+3+kUXpP
+w7O4QfoqZDca1qtJRtew2tpmOb1hFkj/QzRi5WRx/oM/Cm0yMttYIA+4vCJeDOja
+gngrtH3jmEwMME71HDyXHlcCIIt95odXoBSBKgk=
+-----END CERTIFICATE-----
diff --git a/atrace/1.0/vts/functional/OWNERS b/atrace/1.0/vts/functional/OWNERS
deleted file mode 100644
index 31043aa..0000000
--- a/atrace/1.0/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 837454
-wvw@google.com
diff --git a/atrace/OWNERS b/atrace/OWNERS
new file mode 100644
index 0000000..d76ffa6
--- /dev/null
+++ b/atrace/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 837454
+
+wvw@google.com
diff --git a/audio/aidl/Android.bp b/audio/aidl/Android.bp
index 5a009fe..89d186c 100644
--- a/audio/aidl/Android.bp
+++ b/audio/aidl/Android.bp
@@ -34,6 +34,7 @@
     name: "android.hardware.audio.common",
     defaults: [
         "android.hardware.audio_defaults",
+        "latest_android_media_audio_common_types_import_interface",
     ],
     srcs: [
         "android/hardware/audio/common/AudioOffloadMetadata.aidl",
@@ -42,10 +43,7 @@
         "android/hardware/audio/common/SinkMetadata.aidl",
         "android/hardware/audio/common/SourceMetadata.aidl",
     ],
-    frozen: true,
-    imports: [
-        "android.media.audio.common.types-V2",
-    ],
+    frozen: false,
     backend: {
         cpp: {
             enabled: true,
@@ -83,7 +81,7 @@
 }
 
 // Note: This should always be one version ahead of the last frozen version
-latest_android_hardware_audio_common = "android.hardware.audio.common-V2"
+latest_android_hardware_audio_common = "android.hardware.audio.common-V3"
 
 // Modules that depend on android.hardware.audio.common directly can include
 // the following cc_defaults to avoid explicitly managing dependency versions
@@ -109,10 +107,21 @@
     ],
 }
 
+aidl_interface_defaults {
+    name: "latest_android_hardware_audio_common_import_interface",
+    imports: [
+        latest_android_hardware_audio_common,
+    ],
+}
+
 aidl_interface {
     name: "android.hardware.audio.core",
     defaults: [
         "android.hardware.audio_defaults",
+        "latest_android_hardware_audio_common_import_interface",
+        "latest_android_hardware_audio_core_sounddose_import_interface",
+        "latest_android_hardware_audio_effect_import_interface",
+        "latest_android_media_audio_common_types_import_interface",
     ],
     srcs: [
         "android/hardware/audio/core/AudioPatch.aidl",
@@ -137,10 +146,6 @@
     imports: [
         "android.hardware.common-V2",
         "android.hardware.common.fmq-V1",
-        "android.hardware.audio.common-V2",
-        "android.hardware.audio.core.sounddose-V1",
-        "android.hardware.audio.effect-V1",
-        "android.media.audio.common.types-V2",
     ],
     backend: {
         // The C++ backend is disabled transitively due to use of FMQ.
@@ -167,11 +172,11 @@
         // IMPORTANT: Update latest_android_hardware_audio_core every time you
         // add the latest frozen version to versions_with_info
     ],
-    frozen: true,
+    frozen: false,
 }
 
 // Note: This should always be one version ahead of the last frozen version
-latest_android_hardware_audio_core = "android.hardware.audio.core-V1"
+latest_android_hardware_audio_core = "android.hardware.audio.core-V2"
 
 // Modules that depend on android.hardware.audio.core directly can include
 // the following cc_defaults to avoid explicitly managing dependency versions
@@ -190,18 +195,23 @@
     ],
 }
 
+aidl_interface_defaults {
+    name: "latest_android_hardware_audio_core_import_interface",
+    imports: [
+        latest_android_hardware_audio_core,
+    ],
+}
+
 // Used for the standalone sounddose HAL
 aidl_interface {
     name: "android.hardware.audio.core.sounddose",
     defaults: [
         "android.hardware.audio_defaults",
+        "latest_android_media_audio_common_types_import_interface",
     ],
     srcs: [
         "android/hardware/audio/core/sounddose/ISoundDose.aidl",
     ],
-    imports: [
-        "android.media.audio.common.types-V2",
-    ],
     backend: {
         // The C++ backend is disabled transitively due to use of FMQ by the core HAL.
         cpp: {
@@ -220,11 +230,11 @@
         // IMPORTANT: Update latest_android_hardware_audio_core_sounddose every time you
         // add the latest frozen version to versions_with_info
     ],
-    frozen: true,
+    frozen: false,
 }
 
 // Note: This should always be one version ahead of the last frozen version
-latest_android_hardware_audio_core_sounddose = "android.hardware.audio.core.sounddose-V1"
+latest_android_hardware_audio_core_sounddose = "android.hardware.audio.core.sounddose-V2"
 
 // Modules that depend on android.hardware.audio.core.sounddose directly can include
 // the following cc_defaults to avoid explicitly managing dependency versions
@@ -237,16 +247,32 @@
 }
 
 cc_defaults {
+    name: "latest_android_hardware_audio_core_sounddose_ndk_export_shared_lib_header",
+    export_shared_lib_headers: [
+        latest_android_hardware_audio_core_sounddose + "-ndk",
+    ],
+}
+
+cc_defaults {
     name: "latest_android_hardware_audio_core_sounddose_ndk_static",
     static_libs: [
         latest_android_hardware_audio_core_sounddose + "-ndk",
     ],
 }
 
+aidl_interface_defaults {
+    name: "latest_android_hardware_audio_core_sounddose_import_interface",
+    imports: [
+        latest_android_hardware_audio_core_sounddose,
+    ],
+}
+
 aidl_interface {
     name: "android.hardware.audio.effect",
     defaults: [
         "android.hardware.audio_defaults",
+        "latest_android_hardware_audio_common_import_interface",
+        "latest_android_media_audio_common_types_import_interface",
     ],
     srcs: [
         "android/hardware/audio/effect/AcousticEchoCanceler.aidl",
@@ -271,6 +297,7 @@
         "android/hardware/audio/effect/PresetReverb.aidl",
         "android/hardware/audio/effect/Processing.aidl",
         "android/hardware/audio/effect/Range.aidl",
+        "android/hardware/audio/effect/Spatializer.aidl",
         "android/hardware/audio/effect/State.aidl",
         "android/hardware/audio/effect/VendorExtension.aidl",
         "android/hardware/audio/effect/Virtualizer.aidl",
@@ -280,8 +307,6 @@
     imports: [
         "android.hardware.common-V2",
         "android.hardware.common.fmq-V1",
-        "android.hardware.audio.common-V2",
-        "android.media.audio.common.types-V2",
     ],
     backend: {
         // The C++ backend is disabled transitively due to use of FMQ.
@@ -303,11 +328,11 @@
             ],
         },
     ],
-    frozen: true,
+    frozen: false,
 
 }
 
-latest_android_hardware_audio_effect = "android.hardware.audio.effect-V1"
+latest_android_hardware_audio_effect = "android.hardware.audio.effect-V2"
 
 cc_defaults {
     name: "latest_android_hardware_audio_effect_ndk_shared",
@@ -322,3 +347,10 @@
         latest_android_hardware_audio_effect + "-ndk",
     ],
 }
+
+aidl_interface_defaults {
+    name: "latest_android_hardware_audio_effect_import_interface",
+    imports: [
+        latest_android_hardware_audio_effect,
+    ],
+}
diff --git a/audio/aidl/TEST_MAPPING b/audio/aidl/TEST_MAPPING
index 12bce0b..b5fcd86 100644
--- a/audio/aidl/TEST_MAPPING
+++ b/audio/aidl/TEST_MAPPING
@@ -4,9 +4,6 @@
       "name": "VtsHalAudioCoreTargetTest"
     },
     {
-      "name": "VtsHalAudioCoreConfigTargetTest"
-    },
-    {
       "name": "audio_policy_config_xml_converter_tests"
     },
     {
@@ -54,5 +51,33 @@
     {
       "name": "VtsHalNSTargetTest"
     }
+  ],
+  "postsubmit": [
+    {
+      "name": "VtsHalSpatializerTargetTest"
+    },
+    {
+      "name": "audiorecord_tests"
+    },
+    {
+      "name": "audioeffect_tests"
+    },
+    {
+      "name": "audiorouting_tests"
+    },
+    {
+      "name": "trackplayerbase_tests"
+    },
+    {
+      "name": "audiosystem_tests"
+    },
+    {
+      "name": "CtsVirtualDevicesTestCases",
+      "options" : [
+        {
+          "include-filter": "android.virtualdevice.cts.VirtualAudioTest"
+        }
+      ]
+    }
   ]
 }
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IModule.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IModule.aidl
index e14e9c0..07a85f8 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IModule.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IModule.aidl
@@ -74,6 +74,7 @@
   boolean supportsVariableLatency();
   int getAAudioMixerBurstCount();
   int getAAudioHardwareBurstMinUsec();
+  void prepareToDisconnectExternalDevice(int portId);
   const int DEFAULT_AAUDIO_MIXER_BURST_COUNT = 2;
   const int DEFAULT_AAUDIO_HARDWARE_BURST_MIN_DURATION_US = 1000;
   @VintfStability
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
index bcbf870..046c220 100644
--- 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
@@ -43,6 +43,8 @@
   boolean audioModeIndication;
   boolean audioSourceIndication;
   boolean bypass;
+  boolean sinkMetadataIndication;
+  boolean sourceMetadataIndication;
   @Backing(type="byte") @VintfStability
   enum Type {
     INSERT = 0,
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 8c196e7..a1b00be 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
@@ -41,6 +41,7 @@
   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);
+  android.hardware.audio.effect.IEffect.OpenEffectReturn reopen();
   @FixedSize @VintfStability
   parcelable Status {
     int status;
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Parameter.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Parameter.aidl
index 0422bd9..ff33c42 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Parameter.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Parameter.aidl
@@ -41,6 +41,8 @@
   boolean offload;
   android.hardware.audio.effect.Parameter.VolumeStereo volumeStereo;
   android.hardware.audio.effect.Parameter.Specific specific;
+  android.hardware.audio.common.SinkMetadata sinkMetadata;
+  android.hardware.audio.common.SourceMetadata sourceMetadata;
   @VintfStability
   union Id {
     android.hardware.audio.effect.VendorExtension vendorEffectTag;
@@ -60,6 +62,7 @@
     android.hardware.audio.effect.Visualizer.Id visualizerTag;
     android.hardware.audio.effect.Volume.Id volumeTag;
     android.hardware.audio.effect.Parameter.Tag commonTag;
+    android.hardware.audio.effect.Spatializer.Id spatializerTag;
   }
   @VintfStability
   parcelable Common {
@@ -91,5 +94,6 @@
     android.hardware.audio.effect.Virtualizer virtualizer;
     android.hardware.audio.effect.Visualizer visualizer;
     android.hardware.audio.effect.Volume volume;
+    android.hardware.audio.effect.Spatializer spatializer;
   }
 }
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Range.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Range.aidl
index 93edc5e..40ee6b5 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Range.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Range.aidl
@@ -50,6 +50,7 @@
   android.hardware.audio.effect.Range.VirtualizerRange[] virtualizer;
   android.hardware.audio.effect.Range.VisualizerRange[] visualizer;
   android.hardware.audio.effect.Range.VolumeRange[] volume;
+  android.hardware.audio.effect.Range.SpatializerRange[] spatializer;
   @VintfStability
   parcelable AcousticEchoCancelerRange {
     android.hardware.audio.effect.AcousticEchoCanceler min;
@@ -111,6 +112,11 @@
     android.hardware.audio.effect.PresetReverb max;
   }
   @VintfStability
+  parcelable SpatializerRange {
+    android.hardware.audio.effect.Spatializer min;
+    android.hardware.audio.effect.Spatializer max;
+  }
+  @VintfStability
   parcelable VendorExtensionRange {
     android.hardware.audio.effect.VendorExtension min;
     android.hardware.audio.effect.VendorExtension max;
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Spatializer.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Spatializer.aidl
new file mode 100644
index 0000000..98ecee0
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Spatializer.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible 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 Spatializer {
+  android.hardware.audio.effect.VendorExtension vendor;
+  android.media.audio.common.AudioChannelLayout[] supportedChannelLayout;
+  android.media.audio.common.Spatialization.Level spatializationLevel;
+  android.media.audio.common.Spatialization.Mode spatializationMode;
+  int headTrackingSensorId;
+  android.media.audio.common.HeadTracking.Mode headTrackingMode;
+  android.media.audio.common.HeadTracking.ConnectionMode headTrackingConnectionMode;
+  android.media.audio.common.HeadTracking.SensorData headTrackingSensorData;
+  @VintfStability
+  union Id {
+    android.hardware.audio.effect.VendorExtension vendorExtensionTag;
+    android.hardware.audio.effect.Spatializer.Tag commonTag;
+  }
+}
diff --git a/audio/aidl/android/hardware/audio/core/IModule.aidl b/audio/aidl/android/hardware/audio/core/IModule.aidl
index e736c32..3c5f7f6 100644
--- a/audio/aidl/android/hardware/audio/core/IModule.aidl
+++ b/audio/aidl/android/hardware/audio/core/IModule.aidl
@@ -206,8 +206,10 @@
      * after successful connection of an external device.
      *
      * Handling of a disconnect is done in a reverse order:
-     *  1. Reset port configuration using the 'resetAudioPortConfig' method.
-     *  2. Release the connected device port by calling the 'disconnectExternalDevice'
+     *  1. Notify the HAL module to prepare for device disconnection using
+     *     'prepareToDisconnectExternalDevice' method.
+     *  2. Reset port configuration using the 'resetAudioPortConfig' method.
+     *  3. Release the connected device port by calling the 'disconnectExternalDevice'
      *     method. This also removes the audio routes associated with this
      *     device port.
      *
@@ -234,11 +236,15 @@
      * instance previously instantiated using the 'connectExternalDevice'
      * method.
      *
-     * The framework will call this method before closing streams and resetting
-     * patches. This call can be used by the HAL module to prepare itself to
-     * device disconnection. If the HAL module indicates an error after the first
-     * call, the framework will call this method once again after closing associated
-     * streams and patches.
+     * On AIDL HAL v1, the framework will call this method before closing streams
+     * and resetting patches. This call can be used by the HAL module to prepare
+     * itself to device disconnection. If the HAL module indicates an error after
+     * the first call, the framework will call this method once again after closing
+     * associated streams and patches.
+     *
+     * On AIDL HAL v2 and later, the framework will call 'prepareToDisconnectExternalDevice'
+     * method to notify the HAL module to prepare itself for device disconnection. The
+     * framework will only call this method after closing associated streams and patches.
      *
      * @throws EX_ILLEGAL_ARGUMENT In the following cases:
      *                             - If the port can not be found by the ID.
@@ -912,4 +918,23 @@
      * @throw EX_UNSUPPORTED_OPERATION If the module does not support aaudio MMAP.
      */
     int getAAudioHardwareBurstMinUsec();
+
+    /**
+     * Notify the HAL module to prepare for disconnecting an external device.
+     *
+     * This method is used to inform the HAL module that 'disconnectExternalDevice' will be
+     * called soon. The HAL module can rely on this method to abort active data operations
+     * early. The 'portId' must be of a connected device Port instance previously instantiated
+     * using 'connectExternalDevice' method. 'disconnectExternalDevice' method will be called
+     * soon after this method with the same 'portId'.
+     *
+     * Note: This method is called after the external device is disconnected. The system does
+     * not try to predict the disconnection event.
+     *
+     * @param portId The ID of the audio port corresponding to the disconnected device
+     * @throws EX_ILLEGAL_ARGUMENT In the following cases:
+     *                             - If the port can not be found by the ID.
+     *                             - If this is not a connected device port.
+     */
+    void prepareToDisconnectExternalDevice(int portId);
 }
diff --git a/audio/aidl/android/hardware/audio/effect/Flags.aidl b/audio/aidl/android/hardware/audio/effect/Flags.aidl
index 28685c3..70668a3 100644
--- a/audio/aidl/android/hardware/audio/effect/Flags.aidl
+++ b/audio/aidl/android/hardware/audio/effect/Flags.aidl
@@ -144,4 +144,18 @@
      * Set to true if the effect instance bypass audio data (no processing).
      */
     boolean bypass;
+
+    /**
+     * Effect instance sets this flag to true if it requires record AudioTrack metadata update. In
+     * this case the framework must call IEffect.setParameter to notify effect instance when there
+     * is a change in sinkMetadata.
+     */
+    boolean sinkMetadataIndication;
+
+    /**
+     * Effect instance sets this flag to true if it requires playback AudioTrack metadata update. In
+     * this case the framework must call IEffect.setParameter to notify effect instance when there
+     * is a change in sourceMetadata.
+     */
+    boolean sourceMetadataIndication;
 }
diff --git a/audio/aidl/android/hardware/audio/effect/IEffect.aidl b/audio/aidl/android/hardware/audio/effect/IEffect.aidl
index 6097f34..266adec 100644
--- a/audio/aidl/android/hardware/audio/effect/IEffect.aidl
+++ b/audio/aidl/android/hardware/audio/effect/IEffect.aidl
@@ -54,7 +54,16 @@
     }
 
     /**
-     * Return data structure of IEffect.open() interface.
+     * Return data structure of the IEffect.open() and IEffect.reopen() method.
+     *
+     * Contains Fast Message Queues (FMQs) for effect processing status and input/output data.
+     * The status FMQ remains valid and unchanged after opening, while input/output data FMQs can be
+     * modified with changes in input/output AudioConfig. If reallocation of data FMQ is necessary,
+     * the effect instance must release the existing data FMQs to signal the need to the audio
+     * framework.
+     * When the audio framework encounters a valid status FMQ and invalid input/output data FMQs,
+     * it must invoke the IEffect.reopen() method to request the effect instance to reallocate
+     * the FMQ and return to the audio framework.
      */
     @VintfStability
     parcelable OpenEffectReturn {
@@ -97,7 +106,7 @@
      * client responsibility to make sure all parameter/buffer is correct if client wants to reopen
      * a closed instance.
      *
-     * Effect instance close interface should always succeed unless:
+     * Effect instance close method should always succeed unless:
      * 1. The effect instance is not in a proper state to be closed, for example it's still in
      * State::PROCESSING state.
      * 2. There is system/hardware related failure when close.
@@ -154,8 +163,8 @@
     /**
      * 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.
+     * This method 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().
      *
@@ -165,4 +174,24 @@
      * @throws EX_ILLEGAL_ARGUMENT if the effect instance receive unsupported parameter tag.
      */
     Parameter getParameter(in Parameter.Id paramId);
+
+    /**
+     * Reopen the effect instance, keeping all previous parameters unchanged, and reallocate only
+     * the Fast Message Queues (FMQs) allocated during the open time as needed.
+     *
+     * When the audio framework encounters a valid status FMQ and invalid data FMQ(s), it calls
+     * this method to reopen the effect and request the latest data FMQ.
+     * Upon receiving this call, if the effect instance's data FMQ(s) is invalid, it must reallocate
+     * the necessary data FMQ(s) and return them to the audio framework. All previous parameters and
+     * states keep unchanged.
+     * Once the audio framework successfully completes the call, it must validate the returned FMQs,
+     * deprecate all old FMQs, and exclusively use the FMQs returned from this method.
+     *
+     * @return The reallocated data FMQ and the original status FMQ.
+     *
+     * @throws EX_ILLEGAL_STATE if the effect instance is not in a proper state  to reallocate FMQ.
+     * This may occur if the effect instance has already been closed or if there is no need to
+     * update any data FMQ.
+     */
+    OpenEffectReturn reopen();
 }
diff --git a/audio/aidl/android/hardware/audio/effect/Parameter.aidl b/audio/aidl/android/hardware/audio/effect/Parameter.aidl
index 0954055..6fd9161 100644
--- a/audio/aidl/android/hardware/audio/effect/Parameter.aidl
+++ b/audio/aidl/android/hardware/audio/effect/Parameter.aidl
@@ -16,6 +16,8 @@
 
 package android.hardware.audio.effect;
 
+import android.hardware.audio.common.SinkMetadata;
+import android.hardware.audio.common.SourceMetadata;
 import android.hardware.audio.effect.AcousticEchoCanceler;
 import android.hardware.audio.effect.AutomaticGainControlV1;
 import android.hardware.audio.effect.AutomaticGainControlV2;
@@ -28,6 +30,7 @@
 import android.hardware.audio.effect.LoudnessEnhancer;
 import android.hardware.audio.effect.NoiseSuppression;
 import android.hardware.audio.effect.PresetReverb;
+import android.hardware.audio.effect.Spatializer;
 import android.hardware.audio.effect.VendorExtension;
 import android.hardware.audio.effect.Virtualizer;
 import android.hardware.audio.effect.Visualizer;
@@ -103,6 +106,11 @@
          * directly.
          */
         Parameter.Tag commonTag;
+
+        /**
+         * Parameter tag defined for Spatializer parameters.
+         */
+        Spatializer.Id spatializerTag;
     }
 
     /**
@@ -189,6 +197,23 @@
         Virtualizer virtualizer;
         Visualizer visualizer;
         Volume volume;
+        Spatializer spatializer;
     }
     Specific specific;
+
+    /**
+     * SinkMetadata defines the metadata of record AudioTracks which the effect instance associate
+     * with.
+     * The effect engine is required to set Flags.sinkMetadataIndication to true if it wants to
+     * receive sinkMetadata update from the audio framework.
+     */
+    SinkMetadata sinkMetadata;
+
+    /**
+     * SourceMetadata defines the metadata of playback AudioTracks which the effect instance
+     * associate with.
+     * The effect engine is required to set Flags.sourceMetadataIndication to true if it wants to
+     * receive sourceMetadata update from the audio framework.
+     */
+    SourceMetadata sourceMetadata;
 }
diff --git a/audio/aidl/android/hardware/audio/effect/Range.aidl b/audio/aidl/android/hardware/audio/effect/Range.aidl
index 567320a..e5acb68 100644
--- a/audio/aidl/android/hardware/audio/effect/Range.aidl
+++ b/audio/aidl/android/hardware/audio/effect/Range.aidl
@@ -28,6 +28,7 @@
 import android.hardware.audio.effect.LoudnessEnhancer;
 import android.hardware.audio.effect.NoiseSuppression;
 import android.hardware.audio.effect.PresetReverb;
+import android.hardware.audio.effect.Spatializer;
 import android.hardware.audio.effect.VendorExtension;
 import android.hardware.audio.effect.Virtualizer;
 import android.hardware.audio.effect.Visualizer;
@@ -169,6 +170,12 @@
     }
 
     @VintfStability
+    parcelable SpatializerRange {
+        Spatializer min;
+        Spatializer max;
+    }
+
+    @VintfStability
     parcelable VendorExtensionRange {
         VendorExtension min;
         VendorExtension max;
@@ -217,4 +224,5 @@
     VirtualizerRange[] virtualizer;
     VisualizerRange[] visualizer;
     VolumeRange[] volume;
+    SpatializerRange[] spatializer;
 }
diff --git a/audio/aidl/android/hardware/audio/effect/Spatializer.aidl b/audio/aidl/android/hardware/audio/effect/Spatializer.aidl
new file mode 100644
index 0000000..71e3ffe
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/Spatializer.aidl
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect;
+
+import android.hardware.audio.effect.VendorExtension;
+import android.media.audio.common.AudioChannelLayout;
+import android.media.audio.common.HeadTracking;
+import android.media.audio.common.Spatialization;
+
+/**
+ * Union representing parameters for audio spatialization effects.
+ *
+ * Sound spatialization simulates sounds around the listener as if they were emanating from virtual
+ * positions based on the original recording.
+ * For more details, refer to the documentation:
+ * https://developer.android.com/reference/android/media/Spatializer.
+ *
+ * android.hardware.audio.effect.Spatializer specifies parameters for the implementation of audio
+ * spatialization effects.
+ *
+ * A Spatializer implementation must report its supported parameter ranges using Capability.Range.
+ * spatializer.
+ */
+@VintfStability
+union Spatializer {
+    /**
+     * Parameter tag to identify the parameters for getParameter().
+     */
+    @VintfStability
+    union Id {
+        VendorExtension vendorExtensionTag;
+        Spatializer.Tag commonTag;
+    }
+
+    /**
+     * Vendor extension implementation for additional parameters.
+     */
+    VendorExtension vendor;
+
+    /**
+     * List of supported input channel layouts.
+     */
+    AudioChannelLayout[] supportedChannelLayout;
+
+    /**
+     * Level of spatialization.
+     */
+    Spatialization.Level spatializationLevel;
+
+    /**
+     * Spatialization mode, Binaural or Transaural for example.
+     */
+    Spatialization.Mode spatializationMode;
+
+    /**
+     * Identifies the head tracking sensor using its unique sensor ID.
+     * The value corresponds to android.hardware.sensors.SensorInfo.sensorHandle.
+     */
+    int headTrackingSensorId;
+
+    /**
+     * Head tracking mode for spatialization.
+     */
+    HeadTracking.Mode headTrackingMode;
+
+    /**
+     * Head tracking sensor connection mode for spatialization.
+     */
+    HeadTracking.ConnectionMode headTrackingConnectionMode;
+
+    /**
+     * Headtracking sensor data.
+     */
+    HeadTracking.SensorData headTrackingSensorData;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/state.gv b/audio/aidl/android/hardware/audio/effect/state.gv
index ce369ba..22c70c8 100644
--- a/audio/aidl/android/hardware/audio/effect/state.gv
+++ b/audio/aidl/android/hardware/audio/effect/state.gv
@@ -31,6 +31,8 @@
     IDLE -> INIT[label = "IEffect.close()"];
 
     INIT -> INIT[label = "IEffect.getState\nIEffect.getDescriptor"];
-    IDLE -> IDLE[label = "IEffect.getParameter\nIEffect.setParameter\nIEffect.getDescriptor\nIEffect.command(RESET)"];
-    PROCESSING -> PROCESSING[label = "IEffect.getParameter\nIEffect.setParameter\nIEffect.getDescriptor"];
+    IDLE -> IDLE[label = "IEffect.getParameter\nIEffect.setParameter\nIEffect.getDescriptor\nIEffect.command(RESET)\nIEffect.reopen"];
+    PROCESSING
+            -> PROCESSING
+                    [label = "IEffect.getParameter\nIEffect.setParameter\nIEffect.getDescriptor\nIEffect.reopen"];
 }
diff --git a/audio/aidl/common/Android.bp b/audio/aidl/common/Android.bp
index 4c6a74e..85ece3b 100644
--- a/audio/aidl/common/Android.bp
+++ b/audio/aidl/common/Android.bp
@@ -45,8 +45,8 @@
     name: "libaudioaidlranges",
     host_supported: true,
     vendor_available: true,
-    static_libs: [
-        "android.hardware.audio.effect-V1-ndk",
+    defaults: [
+        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     export_include_dirs: ["include"],
     header_libs: ["libaudioaidl_headers"],
@@ -59,8 +59,10 @@
     name: "libaudioaidlcommon_test",
     host_supported: true,
     vendor_available: true,
+    defaults: [
+        "latest_android_media_audio_common_types_ndk_static",
+    ],
     static_libs: [
-        "android.media.audio.common.types-V1-ndk",
         "libaudioaidlcommon",
     ],
     shared_libs: [
diff --git a/audio/aidl/common/include/Utils.h b/audio/aidl/common/include/Utils.h
index 3b08de7..ef312d5 100644
--- a/audio/aidl/common/include/Utils.h
+++ b/audio/aidl/common/include/Utils.h
@@ -174,4 +174,12 @@
     return result;
 }
 
+constexpr int32_t frameCountFromDurationUs(long durationUs, int32_t sampleRateHz) {
+    return (static_cast<long long>(durationUs) * sampleRateHz) / 1000000LL;
+}
+
+constexpr int32_t frameCountFromDurationMs(int32_t durationMs, int32_t sampleRateHz) {
+    return frameCountFromDurationUs(durationMs * 1000, sampleRateHz);
+}
+
 }  // namespace aidl::android::hardware::audio::common
diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp
index bb8d76f..e65ee77 100644
--- a/audio/aidl/default/Android.bp
+++ b/audio/aidl/default/Android.bp
@@ -12,6 +12,7 @@
     vendor: true,
     shared_libs: [
         "libalsautilsv2",
+        "libaudio_aidl_conversion_common_ndk",
         "libaudioaidlcommon",
         "libaudioutils",
         "libbase",
@@ -19,6 +20,8 @@
         "libcutils",
         "libfmq",
         "libnbaio_mono",
+        "liblog",
+        "libmedia_helper",
         "libstagefright_foundation",
         "libtinyalsav2",
         "libutils",
@@ -31,28 +34,8 @@
         "libaudioaidl_headers",
         "libxsdc-utils",
     ],
-}
-
-cc_library {
-    name: "libaudioservicesounddoseimpl",
-    vendor: true,
-    defaults: [
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_core_sounddose_ndk_shared",
-        "latest_android_hardware_audio_sounddose_ndk_shared",
-    ],
-    export_include_dirs: ["include"],
-    srcs: [
-        "SoundDose.cpp",
-    ],
-    shared_libs: [
-        "libbase",
-        "libbinder_ndk",
-        "libcutils",
-        "libutils",
-    ],
-    visibility: [
-        "//hardware/interfaces/audio/aidl/sounddose/default",
+    cflags: [
+        "-DBACKEND_NDK",
     ],
 }
 
@@ -63,6 +46,7 @@
         "latest_android_media_audio_common_types_ndk_shared",
         "latest_android_hardware_audio_core_ndk_shared",
         "latest_android_hardware_audio_core_sounddose_ndk_shared",
+        "latest_android_hardware_bluetooth_audio_ndk_shared",
     ],
     export_include_dirs: ["include"],
     srcs: [
@@ -78,6 +62,7 @@
         "Stream.cpp",
         "StreamSwitcher.cpp",
         "Telephony.cpp",
+        "XsdcConversion.cpp",
         "alsa/Mixer.cpp",
         "alsa/ModuleAlsa.cpp",
         "alsa/StreamAlsa.cpp",
@@ -109,10 +94,13 @@
         "audio_policy_engine_configuration_aidl_default",
     ],
     shared_libs: [
-        "android.hardware.bluetooth.audio-V3-ndk",
+        "android.hardware.bluetooth.audio-impl",
         "libaudio_aidl_conversion_common_ndk",
+        "libaudioutils",
         "libbluetooth_audio_session_aidl",
+        "liblog",
         "libmedia_helper",
+        "libmediautils_vendor",
         "libstagefright_foundation",
     ],
     export_shared_lib_headers: [
@@ -130,21 +118,21 @@
 cc_binary {
     name: "android.hardware.audio.service-aidl.example",
     relative_install_path: "hw",
-    init_rc: ["android.hardware.audio.service-aidl.example.rc"],
-    vintf_fragments: ["android.hardware.audio.service-aidl.xml"],
     defaults: [
         "aidlaudioservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
         "latest_android_hardware_audio_core_sounddose_ndk_shared",
         "latest_android_hardware_audio_core_ndk_shared",
+        "latest_android_hardware_bluetooth_audio_ndk_shared",
+        "latest_android_media_audio_common_types_ndk_shared",
     ],
     static_libs: [
         "libaudioserviceexampleimpl",
     ],
     shared_libs: [
-        "android.hardware.bluetooth.audio-V3-ndk",
+        "android.hardware.bluetooth.audio-impl",
         "libaudio_aidl_conversion_common_ndk",
         "libbluetooth_audio_session_aidl",
+        "liblog",
         "libmedia_helper",
         "libstagefright_foundation",
     ],
@@ -156,6 +144,7 @@
         "-Wthread-safety",
         "-DBACKEND_NDK",
     ],
+    installable: false, //installed in apex com.android.hardware.audio
 }
 
 cc_test {
@@ -172,6 +161,7 @@
         "libbase",
         "libbinder_ndk",
         "libcutils",
+        "libfmq",
         "libmedia_helper",
         "libstagefright_foundation",
         "libutils",
@@ -184,9 +174,11 @@
     ],
     generated_sources: [
         "audio_policy_configuration_aidl_default",
+        "audio_policy_engine_configuration_aidl_default",
     ],
     generated_headers: [
         "audio_policy_configuration_aidl_default",
+        "audio_policy_engine_configuration_aidl_default",
     ],
     srcs: [
         "AudioPolicyConfigXmlConverter.cpp",
@@ -211,6 +203,7 @@
     vendor: true,
     shared_libs: [
         "libaudioaidlcommon",
+        "libaudioutils",
         "libbase",
         "libbinder_ndk",
         "libcutils",
@@ -236,6 +229,7 @@
 filegroup {
     name: "effectCommonFile",
     srcs: [
+        "EffectContext.cpp",
         "EffectThread.cpp",
         "EffectImpl.cpp",
     ],
@@ -244,10 +238,9 @@
 cc_binary {
     name: "android.hardware.audio.effect.service-aidl.example",
     relative_install_path: "hw",
-    init_rc: ["android.hardware.audio.effect.service-aidl.example.rc"],
-    vintf_fragments: ["android.hardware.audio.effect.service-aidl.xml"],
     defaults: ["aidlaudioeffectservice_defaults"],
     shared_libs: [
+        "libapexsupport",
         "libtinyxml2",
     ],
     srcs: [
@@ -255,6 +248,7 @@
         "EffectFactory.cpp",
         "EffectMain.cpp",
     ],
+    installable: false, //installed in apex com.android.hardware.audio.effect
 }
 
 cc_library_headers {
@@ -263,3 +257,22 @@
     vendor_available: true,
     host_supported: true,
 }
+
+prebuilt_etc {
+    name: "android.hardware.audio.service-aidl.example.rc",
+    src: "android.hardware.audio.service-aidl.example.rc",
+    installable: false,
+}
+
+prebuilt_etc {
+    name: "android.hardware.audio.service-aidl.xml",
+    src: "android.hardware.audio.service-aidl.xml",
+    sub_dir: "vintf",
+    installable: false,
+}
+
+prebuilt_etc {
+    name: "audio_effects_config.xml",
+    src: "audio_effects_config.xml",
+    installable: false,
+}
diff --git a/audio/aidl/default/AudioPolicyConfigXmlConverter.cpp b/audio/aidl/default/AudioPolicyConfigXmlConverter.cpp
index 7452c8e..2f1282a 100644
--- a/audio/aidl/default/AudioPolicyConfigXmlConverter.cpp
+++ b/audio/aidl/default/AudioPolicyConfigXmlConverter.cpp
@@ -30,6 +30,7 @@
 
 #include "core-impl/AidlConversionXsdc.h"
 #include "core-impl/AudioPolicyConfigXmlConverter.h"
+#include "core-impl/XsdcConversion.h"
 
 using aidl::android::media::audio::common::AudioFormatDescription;
 using aidl::android::media::audio::common::AudioHalEngineConfig;
@@ -37,60 +38,39 @@
 using aidl::android::media::audio::common::AudioHalVolumeGroup;
 using aidl::android::media::audio::common::AudioStreamType;
 
-namespace xsd = android::audio::policy::configuration;
+namespace ap_xsd = android::audio::policy::configuration;
 
 namespace aidl::android::hardware::audio::core::internal {
 
 static const int kDefaultVolumeIndexMin = 0;
 static const int kDefaultVolumeIndexMax = 100;
 static const int KVolumeIndexDeferredToAudioService = -1;
-/**
- * Valid curve points take the form "<index>,<attenuationMb>", where the index
- * must be in the range [0,100]. kInvalidCurvePointIndex is used to indicate
- * that a point was formatted incorrectly (e.g. if a vendor accidentally typed a
- * '.' instead of a ',' in their XML) -- using such a curve point will result in
- * failed VTS tests.
- */
-static const int8_t kInvalidCurvePointIndex = -1;
 
-AudioHalVolumeCurve::CurvePoint AudioPolicyConfigXmlConverter::convertCurvePointToAidl(
-        const std::string& xsdcCurvePoint) {
-    AudioHalVolumeCurve::CurvePoint aidlCurvePoint{};
-    if (sscanf(xsdcCurvePoint.c_str(), "%" SCNd8 ",%d", &aidlCurvePoint.index,
-               &aidlCurvePoint.attenuationMb) != 2) {
-        aidlCurvePoint.index = kInvalidCurvePointIndex;
-    }
-    return aidlCurvePoint;
-}
-
-AudioHalVolumeCurve AudioPolicyConfigXmlConverter::convertVolumeCurveToAidl(
-        const xsd::Volume& xsdcVolumeCurve) {
+ConversionResult<AudioHalVolumeCurve> AudioPolicyConfigXmlConverter::convertVolumeCurveToAidl(
+        const ap_xsd::Volume& xsdcVolumeCurve) {
     AudioHalVolumeCurve aidlVolumeCurve;
     aidlVolumeCurve.deviceCategory =
             static_cast<AudioHalVolumeCurve::DeviceCategory>(xsdcVolumeCurve.getDeviceCategory());
     if (xsdcVolumeCurve.hasRef()) {
         if (mVolumesReferenceMap.empty()) {
-            mVolumesReferenceMap = generateReferenceMap<xsd::Volumes, xsd::Reference>(
+            mVolumesReferenceMap = generateReferenceMap<ap_xsd::Volumes, ap_xsd::Reference>(
                     getXsdcConfig()->getVolumes());
         }
-        aidlVolumeCurve.curvePoints =
-                convertCollectionToAidlUnchecked<std::string, AudioHalVolumeCurve::CurvePoint>(
+        aidlVolumeCurve.curvePoints = VALUE_OR_FATAL(
+                (convertCollectionToAidl<std::string, AudioHalVolumeCurve::CurvePoint>(
                         mVolumesReferenceMap.at(xsdcVolumeCurve.getRef()).getPoint(),
-                        std::bind(&AudioPolicyConfigXmlConverter::convertCurvePointToAidl, this,
-                                  std::placeholders::_1));
+                        &convertCurvePointToAidl)));
     } else {
-        aidlVolumeCurve.curvePoints =
-                convertCollectionToAidlUnchecked<std::string, AudioHalVolumeCurve::CurvePoint>(
-                        xsdcVolumeCurve.getPoint(),
-                        std::bind(&AudioPolicyConfigXmlConverter::convertCurvePointToAidl, this,
-                                  std::placeholders::_1));
+        aidlVolumeCurve.curvePoints = VALUE_OR_FATAL(
+                (convertCollectionToAidl<std::string, AudioHalVolumeCurve::CurvePoint>(
+                        xsdcVolumeCurve.getPoint(), &convertCurvePointToAidl)));
     }
     return aidlVolumeCurve;
 }
 
-void AudioPolicyConfigXmlConverter::mapStreamToVolumeCurve(const xsd::Volume& xsdcVolumeCurve) {
+void AudioPolicyConfigXmlConverter::mapStreamToVolumeCurve(const ap_xsd::Volume& xsdcVolumeCurve) {
     mStreamToVolumeCurvesMap[xsdcVolumeCurve.getStream()].push_back(
-            convertVolumeCurveToAidl(xsdcVolumeCurve));
+            VALUE_OR_FATAL(convertVolumeCurveToAidl(xsdcVolumeCurve)));
 }
 
 const SurroundSoundConfig& AudioPolicyConfigXmlConverter::getSurroundSoundConfig() {
@@ -109,6 +89,11 @@
     return aidlSurroundSoundConfig;
 }
 
+std::unique_ptr<AudioPolicyConfigXmlConverter::ModuleConfigs>
+AudioPolicyConfigXmlConverter::releaseModuleConfigs() {
+    return std::move(mModuleConfigurations);
+}
+
 const AudioHalEngineConfig& AudioPolicyConfigXmlConverter::getAidlEngineConfig() {
     if (mAidlEngineConfig.volumeGroups.empty() && getXsdcConfig() &&
         getXsdcConfig()->hasVolumes()) {
@@ -160,8 +145,8 @@
 
 void AudioPolicyConfigXmlConverter::mapStreamsToVolumeCurves() {
     if (getXsdcConfig()->hasVolumes()) {
-        for (const xsd::Volumes& xsdcWrapperType : getXsdcConfig()->getVolumes()) {
-            for (const xsd::Volume& xsdcVolume : xsdcWrapperType.getVolume()) {
+        for (const ap_xsd::Volumes& xsdcWrapperType : getXsdcConfig()->getVolumes()) {
+            for (const ap_xsd::Volume& xsdcVolume : xsdcWrapperType.getVolume()) {
                 mapStreamToVolumeCurve(xsdcVolume);
             }
         }
@@ -171,7 +156,7 @@
 void AudioPolicyConfigXmlConverter::addVolumeGroupstoEngineConfig() {
     for (const auto& [xsdcStream, volumeCurves] : mStreamToVolumeCurvesMap) {
         AudioHalVolumeGroup volumeGroup;
-        volumeGroup.name = xsd::toString(xsdcStream);
+        volumeGroup.name = ap_xsd::toString(xsdcStream);
         if (static_cast<int>(xsdcStream) >= AUDIO_STREAM_PUBLIC_CNT) {
             volumeGroup.minIndex = kDefaultVolumeIndexMin;
             volumeGroup.maxIndex = kDefaultVolumeIndexMax;
@@ -190,4 +175,24 @@
         addVolumeGroupstoEngineConfig();
     }
 }
+
+void AudioPolicyConfigXmlConverter::init() {
+    if (!getXsdcConfig()->hasModules()) return;
+    for (const ap_xsd::Modules& xsdcModulesType : getXsdcConfig()->getModules()) {
+        if (!xsdcModulesType.has_module()) continue;
+        for (const ap_xsd::Modules::Module& xsdcModule : xsdcModulesType.get_module()) {
+            // 'primary' in the XML schema used by HIDL is equivalent to 'default' module.
+            const std::string name =
+                    xsdcModule.getName() != "primary" ? xsdcModule.getName() : "default";
+            if (name != "r_submix") {
+                mModuleConfigurations->emplace_back(
+                        name, VALUE_OR_FATAL(convertModuleConfigToAidl(xsdcModule)));
+            } else {
+                // See the note on the 'getRSubmixConfiguration' function.
+                mModuleConfigurations->emplace_back(name, nullptr);
+            }
+        }
+    }
+}
+
 }  // namespace aidl::android::hardware::audio::core::internal
diff --git a/audio/aidl/default/Configuration.cpp b/audio/aidl/default/Configuration.cpp
index b9f1131..2a8e58f 100644
--- a/audio/aidl/default/Configuration.cpp
+++ b/audio/aidl/default/Configuration.cpp
@@ -41,8 +41,8 @@
 using aidl::android::media::audio::common::AudioPortMixExt;
 using aidl::android::media::audio::common::AudioProfile;
 using aidl::android::media::audio::common::Int;
-using aidl::android::media::audio::common::MicrophoneInfo;
 using aidl::android::media::audio::common::PcmType;
+using Configuration = aidl::android::hardware::audio::core::Module::Configuration;
 
 namespace aidl::android::hardware::audio::core::internal {
 
@@ -105,15 +105,11 @@
     return port;
 }
 
-static AudioPortConfig createPortConfig(int32_t id, int32_t portId, PcmType pcmType, int32_t layout,
-                                        int32_t sampleRate, int32_t flags, bool isInput,
-                                        const AudioPortExt& ext) {
+static AudioPortConfig createDynamicPortConfig(int32_t id, int32_t portId, int32_t flags,
+                                               bool isInput, const AudioPortExt& ext) {
     AudioPortConfig config;
     config.id = id;
     config.portId = portId;
-    config.sampleRate = Int{.value = sampleRate};
-    config.channelMask = AudioChannelLayout::make<AudioChannelLayout::layoutMask>(layout);
-    config.format = AudioFormatDescription{.type = AudioFormatType::PCM, .pcm = pcmType};
     config.gain = AudioGainConfig();
     config.flags = isInput ? AudioIoFlags::make<AudioIoFlags::Tag::input>(flags)
                            : AudioIoFlags::make<AudioIoFlags::Tag::output>(flags);
@@ -121,6 +117,16 @@
     return config;
 }
 
+static AudioPortConfig createPortConfig(int32_t id, int32_t portId, PcmType pcmType, int32_t layout,
+                                        int32_t sampleRate, int32_t flags, bool isInput,
+                                        const AudioPortExt& ext) {
+    AudioPortConfig config = createDynamicPortConfig(id, portId, flags, isInput, ext);
+    config.sampleRate = Int{.value = sampleRate};
+    config.channelMask = AudioChannelLayout::make<AudioChannelLayout::layoutMask>(layout);
+    config.format = AudioFormatDescription{.type = AudioFormatType::PCM, .pcm = pcmType};
+    return config;
+}
+
 static AudioRoute createRoute(const std::vector<AudioPort>& sources, const AudioPort& sink) {
     AudioRoute route;
     route.sinkPortId = sink.id;
@@ -129,6 +135,22 @@
     return route;
 }
 
+std::vector<AudioProfile> getStandard16And24BitPcmAudioProfiles() {
+    auto createStdPcmAudioProfile = [](const PcmType& pcmType) {
+        return AudioProfile{
+                .format = AudioFormatDescription{.type = AudioFormatType::PCM, .pcm = pcmType},
+                .channelMasks = {AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
+                                         AudioChannelLayout::LAYOUT_MONO),
+                                 AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
+                                         AudioChannelLayout::LAYOUT_STEREO)},
+                .sampleRates = {8000, 11025, 16000, 32000, 44100, 48000}};
+    };
+    return {
+            createStdPcmAudioProfile(PcmType::INT_16_BIT),
+            createStdPcmAudioProfile(PcmType::INT_24_BIT),
+    };
+}
+
 // Primary (default) configuration:
 //
 // Device ports:
@@ -147,8 +169,7 @@
 //  * "primary output", PRIMARY, 1 max open, 1 max active stream
 //    - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
 //  * "primary input", 1 max open, 1 max active stream
-//    - profile PCM 16-bit; MONO, STEREO;
-//        8000, 11025, 16000, 32000, 44100, 48000
+//    - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
 //  * "telephony_tx", 1 max open, 1 max active stream
 //    - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
 //  * "telephony_rx", 1 max open, 1 max active stream
@@ -164,11 +185,11 @@
 //  "FM Tuner" -> "fm_tuner"
 //
 // Initial port configs:
-//  * "Speaker" device port: PCM 16-bit; STEREO; 48000
-//  * "Built-In Mic" device port: PCM 16-bit; MONO; 48000
-//  * "Telephony Tx" device port: PCM 16-bit; MONO; 48000
-//  * "Telephony Rx" device port: PCM 16-bit; MONO; 48000
-//  * "FM Tuner" device port: PCM 16-bit; STEREO; 48000
+//  * "Speaker" device port: dynamic configuration
+//  * "Built-In Mic" device port: dynamic configuration
+//  * "Telephony Tx" device port: dynamic configuration
+//  * "Telephony Rx" device port: dynamic configuration
+//  * "FM Tuner" device port: dynamic configuration
 //
 std::unique_ptr<Configuration> getPrimaryConfiguration() {
     static const Configuration configuration = []() {
@@ -186,9 +207,8 @@
                                            1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE));
         c.ports.push_back(speakerOutDevice);
         c.initialConfigs.push_back(
-                createPortConfig(speakerOutDevice.id, speakerOutDevice.id, PcmType::INT_16_BIT,
-                                 AudioChannelLayout::LAYOUT_STEREO, 48000, 0, false,
-                                 createDeviceExt(AudioDeviceType::OUT_SPEAKER, 0)));
+                createDynamicPortConfig(speakerOutDevice.id, speakerOutDevice.id, 0, false,
+                                        createDeviceExt(AudioDeviceType::OUT_SPEAKER, 0)));
 
         AudioPort micInDevice =
                 createPort(c.nextPortId++, "Built-In Mic", 0, true,
@@ -196,35 +216,31 @@
                                            1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE));
         c.ports.push_back(micInDevice);
         c.initialConfigs.push_back(
-                createPortConfig(micInDevice.id, micInDevice.id, PcmType::INT_16_BIT,
-                                 AudioChannelLayout::LAYOUT_MONO, 48000, 0, true,
-                                 createDeviceExt(AudioDeviceType::IN_MICROPHONE, 0)));
+                createDynamicPortConfig(micInDevice.id, micInDevice.id, 0, true,
+                                        createDeviceExt(AudioDeviceType::IN_MICROPHONE, 0)));
 
         AudioPort telephonyTxOutDevice =
                 createPort(c.nextPortId++, "Telephony Tx", 0, false,
                            createDeviceExt(AudioDeviceType::OUT_TELEPHONY_TX, 0));
         c.ports.push_back(telephonyTxOutDevice);
         c.initialConfigs.push_back(
-                createPortConfig(telephonyTxOutDevice.id, telephonyTxOutDevice.id,
-                                 PcmType::INT_16_BIT, AudioChannelLayout::LAYOUT_MONO, 48000, 0,
-                                 false, createDeviceExt(AudioDeviceType::OUT_TELEPHONY_TX, 0)));
+                createDynamicPortConfig(telephonyTxOutDevice.id, telephonyTxOutDevice.id, 0, false,
+                                        createDeviceExt(AudioDeviceType::OUT_TELEPHONY_TX, 0)));
 
         AudioPort telephonyRxInDevice =
                 createPort(c.nextPortId++, "Telephony Rx", 0, true,
                            createDeviceExt(AudioDeviceType::IN_TELEPHONY_RX, 0));
         c.ports.push_back(telephonyRxInDevice);
         c.initialConfigs.push_back(
-                createPortConfig(telephonyRxInDevice.id, telephonyRxInDevice.id,
-                                 PcmType::INT_16_BIT, AudioChannelLayout::LAYOUT_MONO, 48000, 0,
-                                 true, createDeviceExt(AudioDeviceType::IN_TELEPHONY_RX, 0)));
+                createDynamicPortConfig(telephonyRxInDevice.id, telephonyRxInDevice.id, 0, true,
+                                        createDeviceExt(AudioDeviceType::IN_TELEPHONY_RX, 0)));
 
         AudioPort fmTunerInDevice = createPort(c.nextPortId++, "FM Tuner", 0, true,
                                                createDeviceExt(AudioDeviceType::IN_FM_TUNER, 0));
         c.ports.push_back(fmTunerInDevice);
         c.initialConfigs.push_back(
-                createPortConfig(fmTunerInDevice.id, fmTunerInDevice.id, PcmType::INT_16_BIT,
-                                 AudioChannelLayout::LAYOUT_STEREO, 48000, 0, true,
-                                 createDeviceExt(AudioDeviceType::IN_FM_TUNER, 0)));
+                createDynamicPortConfig(fmTunerInDevice.id, fmTunerInDevice.id, 0, true,
+                                        createDeviceExt(AudioDeviceType::IN_FM_TUNER, 0)));
 
         // Mix ports
 
@@ -237,7 +253,7 @@
         c.ports.push_back(primaryOutMix);
 
         AudioPort primaryInMix =
-                createPort(c.nextPortId++, "primary input", 0, true, createPortMixExt(0, 0));
+                createPort(c.nextPortId++, "primary input", 0, true, createPortMixExt(0, 1));
         primaryInMix.profiles.push_back(
                 createProfile(PcmType::INT_16_BIT,
                               {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
@@ -252,14 +268,14 @@
         c.ports.push_back(telephonyTxOutMix);
 
         AudioPort telephonyRxInMix =
-                createPort(c.nextPortId++, "telephony_rx", 0, true, createPortMixExt(1, 1));
+                createPort(c.nextPortId++, "telephony_rx", 0, true, createPortMixExt(0, 1));
         telephonyRxInMix.profiles.insert(telephonyRxInMix.profiles.begin(),
                                          standardPcmAudioProfiles.begin(),
                                          standardPcmAudioProfiles.end());
         c.ports.push_back(telephonyRxInMix);
 
         AudioPort fmTunerInMix =
-                createPort(c.nextPortId++, "fm_tuner", 0, true, createPortMixExt(1, 1));
+                createPort(c.nextPortId++, "fm_tuner", 0, true, createPortMixExt(0, 1));
         fmTunerInMix.profiles.insert(fmTunerInMix.profiles.begin(),
                                      standardPcmAudioProfiles.begin(),
                                      standardPcmAudioProfiles.end());
@@ -273,18 +289,28 @@
 
         c.portConfigs.insert(c.portConfigs.end(), c.initialConfigs.begin(), c.initialConfigs.end());
 
-        MicrophoneInfo mic;
-        mic.id = "mic";
-        mic.device = micInDevice.ext.get<AudioPortExt::Tag::device>().device;
-        mic.group = 0;
-        mic.indexInTheGroup = 0;
-        c.microphones = std::vector<MicrophoneInfo>{mic};
-
         return c;
     }();
     return std::make_unique<Configuration>(configuration);
 }
 
+// Note: When transitioning to loading of XML configs, either keep the configuration
+// of the remote submix sources from this static configuration, or update the XML
+// config to match it. There are several reasons for that:
+//   1. The "Remote Submix In" device is listed in the XML config as "attached",
+//      however in the AIDL scheme its device type has a "virtual" connection.
+//   2. The canonical r_submix configuration only lists 'STEREO' and '48000',
+//      however the framework attempts to open streams for other sample rates
+//      as well. The legacy r_submix implementation allowed that, but libaudiohal@aidl
+//      will not find a mix port to use. Because of that, list all sample rates that
+//      the legacy implementation allowed (note that mono was not allowed, the framework
+//      is expected to upmix mono tracks into stereo if needed).
+//   3. The legacy implementation had a hard limit on the number of routes (10),
+//      and this is checked indirectly by AudioPlaybackCaptureTest#testPlaybackCaptureDoS
+//      CTS test. Instead of hardcoding the number of routes, we can use
+//      "maxOpen/ActiveStreamCount" to enforce a similar limit. However, the canonical
+//      XML file lacks this specification.
+//
 // Remote Submix configuration:
 //
 // Device ports:
@@ -294,16 +320,10 @@
 //    - no profiles specified
 //
 // Mix ports:
-//  * "r_submix output", unlimited max open, unlimited max active stream
-//    - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
-//    - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
-//    - profile PCM 32-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
-//    - profile PCM 32-bit float; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
-//  * "r_submix input", unlimited max open, unlimited max active stream
-//    - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
-//    - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
-//    - profile PCM 32-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
-//    - profile PCM 32-bit float; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
+//  * "r_submix output", maximum 10 opened streams, maximum 10 active streams
+//    - profile PCM 16-bit; STEREO; 8000, 11025, 16000, 32000, 44100, 48000
+//  * "r_submix input", maximum 10 opened streams, maximum 10 active streams
+//    - profile PCM 16-bit; STEREO; 8000, 11025, 16000, 32000, 44100, 48000
 //
 // Routes:
 //  "r_submix output" -> "Remote Submix Out"
@@ -312,18 +332,8 @@
 std::unique_ptr<Configuration> getRSubmixConfiguration() {
     static const Configuration configuration = []() {
         Configuration c;
-        const std::vector<AudioProfile> standardPcmAudioProfiles{
-                createProfile(PcmType::FLOAT_32_BIT,
-                              {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
-                              {8000, 11025, 16000, 32000, 44100, 48000}),
-                createProfile(PcmType::INT_32_BIT,
-                              {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
-                              {8000, 11025, 16000, 32000, 44100, 48000}),
-                createProfile(PcmType::INT_24_BIT,
-                              {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
-                              {8000, 11025, 16000, 32000, 44100, 48000}),
-                createProfile(PcmType::INT_16_BIT,
-                              {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
+        const std::vector<AudioProfile> remoteSubmixPcmAudioProfiles{
+                createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO},
                               {8000, 11025, 16000, 32000, 44100, 48000})};
 
         // Device ports
@@ -333,25 +343,25 @@
                            createDeviceExt(AudioDeviceType::OUT_SUBMIX, 0,
                                            AudioDeviceDescription::CONNECTION_VIRTUAL));
         c.ports.push_back(rsubmixOutDevice);
-        c.connectedProfiles[rsubmixOutDevice.id] = standardPcmAudioProfiles;
+        c.connectedProfiles[rsubmixOutDevice.id] = remoteSubmixPcmAudioProfiles;
 
         AudioPort rsubmixInDevice =
                 createPort(c.nextPortId++, "Remote Submix In", 0, true,
                            createDeviceExt(AudioDeviceType::IN_SUBMIX, 0,
                                            AudioDeviceDescription::CONNECTION_VIRTUAL));
         c.ports.push_back(rsubmixInDevice);
-        c.connectedProfiles[rsubmixInDevice.id] = standardPcmAudioProfiles;
+        c.connectedProfiles[rsubmixInDevice.id] = remoteSubmixPcmAudioProfiles;
 
         // Mix ports
 
         AudioPort rsubmixOutMix =
-                createPort(c.nextPortId++, "r_submix output", 0, false, createPortMixExt(0, 0));
-        rsubmixOutMix.profiles = standardPcmAudioProfiles;
+                createPort(c.nextPortId++, "r_submix output", 0, false, createPortMixExt(10, 10));
+        rsubmixOutMix.profiles = remoteSubmixPcmAudioProfiles;
         c.ports.push_back(rsubmixOutMix);
 
         AudioPort rsubmixInMix =
-                createPort(c.nextPortId++, "r_submix input", 0, true, createPortMixExt(0, 0));
-        rsubmixInMix.profiles = standardPcmAudioProfiles;
+                createPort(c.nextPortId++, "r_submix input", 0, true, createPortMixExt(10, 10));
+        rsubmixInMix.profiles = remoteSubmixPcmAudioProfiles;
         c.ports.push_back(rsubmixInMix);
 
         c.routes.push_back(createRoute({rsubmixOutMix}, rsubmixOutDevice));
@@ -385,7 +395,7 @@
 //  * "usb_device output" -> "USB Headset Out"
 //  * "USB Device In", "USB Headset In" -> "usb_device input"
 //
-// Profiles for device port connected state:
+// Profiles for device port connected state (when simulating connections):
 //  * "USB Device Out", "USB Headset Out":
 //    - profile PCM 16-bit; MONO, STEREO, INDEX_MASK_1, INDEX_MASK_2; 44100, 48000
 //    - profile PCM 24-bit; MONO, STEREO, INDEX_MASK_1, INDEX_MASK_2; 44100, 48000
@@ -442,7 +452,7 @@
         c.ports.push_back(usbDeviceOutMix);
 
         AudioPort usbDeviceInMix =
-                createPort(c.nextPortId++, "usb_device input", 0, true, createPortMixExt(1, 1));
+                createPort(c.nextPortId++, "usb_device input", 0, true, createPortMixExt(0, 1));
         c.ports.push_back(usbDeviceInMix);
 
         c.routes.push_back(createRoute({usbDeviceOutMix}, usbOutDevice));
@@ -462,9 +472,9 @@
 //  * "Test In", IN_AFE_PROXY
 //    - no profiles specified
 //  * "Wired Headset", OUT_HEADSET
-//    - profile PCM 24-bit; STEREO; 48000
+//    - no profiles specified
 //  * "Wired Headset Mic", IN_HEADSET
-//    - profile PCM 24-bit; MONO; 48000
+//    - no profiles specified
 //
 // Mix ports:
 //  * "test output", 1 max open, 1 max active stream
@@ -487,6 +497,10 @@
 //  * "Test Out" device port: PCM 24-bit; STEREO; 48000
 //  * "Test In" device port: PCM 24-bit; MONO; 48000
 //
+// Profiles for device port connected state (when simulating connections):
+//  * "Wired Headset": dynamic profiles
+//  * "Wired Headset Mic": dynamic profiles
+//
 std::unique_ptr<Configuration> getStubConfiguration() {
     static const Configuration configuration = []() {
         Configuration c;
@@ -505,8 +519,6 @@
                 createPort(c.nextPortId++, "Wired Headset", 0, false,
                            createDeviceExt(AudioDeviceType::OUT_HEADSET, 0,
                                            AudioDeviceDescription::CONNECTION_ANALOG));
-        headsetOutDevice.profiles.push_back(
-                createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
         c.ports.push_back(headsetOutDevice);
 
         AudioPort testInDevice = createPort(c.nextPortId++, "Test In", 0, true,
@@ -521,8 +533,6 @@
                 createPort(c.nextPortId++, "Wired Headset Mic", 0, true,
                            createDeviceExt(AudioDeviceType::IN_HEADSET, 0,
                                            AudioDeviceDescription::CONNECTION_ANALOG));
-        headsetInDevice.profiles.push_back(
-                createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_MONO}, {48000}));
         c.ports.push_back(headsetInDevice);
 
         // Mix ports
@@ -554,24 +564,24 @@
                               {44100, 48000}));
         c.ports.push_back(compressedOffloadOutMix);
 
-        AudioPort testInMIx =
+        AudioPort testInMix =
                 createPort(c.nextPortId++, "test input", 0, true, createPortMixExt(2, 2));
-        testInMIx.profiles.push_back(
+        testInMix.profiles.push_back(
                 createProfile(PcmType::INT_16_BIT,
                               {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO,
                                AudioChannelLayout::LAYOUT_FRONT_BACK},
                               {8000, 11025, 16000, 22050, 32000, 44100, 48000}));
-        testInMIx.profiles.push_back(
+        testInMix.profiles.push_back(
                 createProfile(PcmType::INT_24_BIT,
                               {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO,
                                AudioChannelLayout::LAYOUT_FRONT_BACK},
                               {8000, 11025, 16000, 22050, 32000, 44100, 48000}));
-        c.ports.push_back(testInMIx);
+        c.ports.push_back(testInMix);
 
         c.routes.push_back(
                 createRoute({testOutMix, testFastOutMix, compressedOffloadOutMix}, testOutDevice));
         c.routes.push_back(createRoute({testOutMix}, headsetOutDevice));
-        c.routes.push_back(createRoute({testInDevice, headsetInDevice}, testInMIx));
+        c.routes.push_back(createRoute({testInDevice, headsetInDevice}, testInMix));
 
         c.portConfigs.insert(c.portConfigs.end(), c.initialConfigs.begin(), c.initialConfigs.end());
 
@@ -604,11 +614,19 @@
 //  "a2dp output" -> "BT A2DP Speaker"
 //  "hearing aid output" -> "BT Hearing Aid Out"
 //
+// Profiles for device port connected state (when simulating connections):
+//  * "BT A2DP Out", "BT A2DP Headphones", "BT A2DP Speaker":
+//    - profile PCM 16-bit; STEREO; 44100, 48000, 88200, 96000
+//  * "BT Hearing Aid Out":
+//    - profile PCM 16-bit; STEREO; 16000, 24000
+//
 std::unique_ptr<Configuration> getBluetoothConfiguration() {
     static const Configuration configuration = []() {
         const std::vector<AudioProfile> standardPcmAudioProfiles = {
                 createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO},
                               {44100, 48000, 88200, 96000})};
+        const std::vector<AudioProfile> hearingAidAudioProfiles = {createProfile(
+                PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {16000, 24000})};
         Configuration c;
 
         // Device ports
@@ -646,8 +664,7 @@
                            createDeviceExt(AudioDeviceType::OUT_HEARING_AID, 0,
                                            AudioDeviceDescription::CONNECTION_WIRELESS));
         c.ports.push_back(btOutHearingAid);
-        c.connectedProfiles[btOutHearingAid.id] = std::vector<AudioProfile>(
-                {createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {16000})});
+        c.connectedProfiles[btOutHearingAid.id] = hearingAidAudioProfiles;
 
         // Mix ports
         AudioPort btOutMix =
@@ -656,8 +673,7 @@
 
         AudioPort btHearingOutMix =
                 createPort(c.nextPortId++, "hearing aid output", 0, false, createPortMixExt(1, 1));
-        btHearingOutMix.profiles.push_back(createProfile(
-                PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {16000, 24000}));
+        btHearingOutMix.profiles = hearingAidAudioProfiles;
         c.ports.push_back(btHearingOutMix);
 
         c.routes.push_back(createRoute({btOutMix}, btOutDevice));
@@ -670,4 +686,19 @@
     return std::make_unique<Configuration>(configuration);
 }
 
+std::unique_ptr<Module::Configuration> getConfiguration(Module::Type moduleType) {
+    switch (moduleType) {
+        case Module::Type::DEFAULT:
+            return getPrimaryConfiguration();
+        case Module::Type::R_SUBMIX:
+            return getRSubmixConfiguration();
+        case Module::Type::STUB:
+            return getStubConfiguration();
+        case Module::Type::USB:
+            return getUsbConfiguration();
+        case Module::Type::BLUETOOTH:
+            return getBluetoothConfiguration();
+    }
+}
+
 }  // namespace aidl::android::hardware::audio::core::internal
diff --git a/audio/aidl/default/EffectConfig.cpp b/audio/aidl/default/EffectConfig.cpp
index 730c0bf..1cc4897 100644
--- a/audio/aidl/default/EffectConfig.cpp
+++ b/audio/aidl/default/EffectConfig.cpp
@@ -24,6 +24,10 @@
 
 #include "effectFactory-impl/EffectConfig.h"
 
+#ifdef __ANDROID_APEX__
+#include <android/apexsupport.h>
+#endif
+
 using aidl::android::media::audio::common::AudioSource;
 using aidl::android::media::audio::common::AudioStreamType;
 using aidl::android::media::audio::common::AudioUuid;
@@ -89,6 +93,24 @@
 }
 
 bool EffectConfig::resolveLibrary(const std::string& path, std::string* resolvedPath) {
+    if (__builtin_available(android AAPEXSUPPORT_API, *)) {
+        AApexInfo *apexInfo;
+        if (AApexInfo_create(&apexInfo) == AAPEXINFO_OK) {
+            std::string apexName(AApexInfo_getName(apexInfo));
+            AApexInfo_destroy(apexInfo);
+            std::string candidatePath("/apex/");
+            candidatePath.append(apexName).append(kEffectLibApexPath).append(path);
+            LOG(DEBUG) << __func__ << " effect lib path " << candidatePath;
+            if (access(candidatePath.c_str(), R_OK) == 0) {
+                *resolvedPath = std::move(candidatePath);
+                return true;
+            }
+        }
+    } else {
+        LOG(DEBUG) << __func__ << " libapexsupport is not supported";
+    }
+
+    // If audio effects libs are not in vendor apex, locate them in kEffectLibPath
     for (auto* libraryDirectory : kEffectLibPath) {
         std::string candidatePath = std::string(libraryDirectory) + '/' + path;
         if (access(candidatePath.c_str(), R_OK) == 0) {
@@ -196,16 +218,16 @@
     // see list of audio sources in audio_source_t:
     // system/media/audio/include/system/audio_effects/audio_effects_conf.h
     static const std::map<const std::string, AudioSource> sAudioSourceTable = {
-            {MIC_SRC_TAG, AudioSource::VOICE_CALL},
-            {VOICE_UL_SRC_TAG, AudioSource::VOICE_CALL},
-            {VOICE_DL_SRC_TAG, AudioSource::VOICE_CALL},
+            {MIC_SRC_TAG, AudioSource::MIC},
+            {VOICE_UL_SRC_TAG, AudioSource::VOICE_UPLINK},
+            {VOICE_DL_SRC_TAG, AudioSource::VOICE_DOWNLINK},
             {VOICE_CALL_SRC_TAG, AudioSource::VOICE_CALL},
-            {CAMCORDER_SRC_TAG, AudioSource::VOICE_CALL},
-            {VOICE_REC_SRC_TAG, AudioSource::VOICE_CALL},
-            {VOICE_COMM_SRC_TAG, AudioSource::VOICE_CALL},
-            {REMOTE_SUBMIX_SRC_TAG, AudioSource::VOICE_CALL},
-            {UNPROCESSED_SRC_TAG, AudioSource::VOICE_CALL},
-            {VOICE_PERFORMANCE_SRC_TAG, AudioSource::VOICE_CALL}};
+            {CAMCORDER_SRC_TAG, AudioSource::CAMCORDER},
+            {VOICE_REC_SRC_TAG, AudioSource::VOICE_RECOGNITION},
+            {VOICE_COMM_SRC_TAG, AudioSource::VOICE_COMMUNICATION},
+            {REMOTE_SUBMIX_SRC_TAG, AudioSource::REMOTE_SUBMIX},
+            {UNPROCESSED_SRC_TAG, AudioSource::UNPROCESSED},
+            {VOICE_PERFORMANCE_SRC_TAG, AudioSource::VOICE_PERFORMANCE}};
 
     if (typeTag == Processing::Type::streamType) {
         auto typeIter = sAudioStreamTypeTable.find(type);
diff --git a/audio/aidl/default/EffectContext.cpp b/audio/aidl/default/EffectContext.cpp
new file mode 100644
index 0000000..2e12918
--- /dev/null
+++ b/audio/aidl/default/EffectContext.cpp
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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>
+#define LOG_TAG "AHAL_EffectContext"
+#include "effect-impl/EffectContext.h"
+#include "include/effect-impl/EffectTypes.h"
+
+using aidl::android::hardware::audio::common::getChannelCount;
+using aidl::android::hardware::audio::common::getFrameSizeInBytes;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::media::audio::common::PcmType;
+using ::android::hardware::EventFlag;
+
+namespace aidl::android::hardware::audio::effect {
+
+EffectContext::EffectContext(size_t statusDepth, const Parameter::Common& common) {
+    LOG_ALWAYS_FATAL_IF(RetCode::SUCCESS != setCommon(common), "illegalCommonParameter");
+
+    // in/outBuffer size in float (FMQ data format defined for DataMQ)
+    size_t inBufferSizeInFloat = common.input.frameCount * mInputFrameSize / sizeof(float);
+    size_t outBufferSizeInFloat = common.output.frameCount * mOutputFrameSize / sizeof(float);
+
+    // only status FMQ use the EventFlag
+    mStatusMQ = std::make_shared<StatusMQ>(statusDepth, true /*configureEventFlagWord*/);
+    mInputMQ = std::make_shared<DataMQ>(inBufferSizeInFloat);
+    mOutputMQ = std::make_shared<DataMQ>(outBufferSizeInFloat);
+
+    if (!mStatusMQ->isValid() || !mInputMQ->isValid() || !mOutputMQ->isValid()) {
+        LOG(ERROR) << __func__ << " created invalid FMQ";
+    }
+
+    ::android::status_t status =
+            EventFlag::createEventFlag(mStatusMQ->getEventFlagWord(), &mEfGroup);
+    LOG_ALWAYS_FATAL_IF(status != ::android::OK || !mEfGroup, " create EventFlagGroup failed ");
+    mWorkBuffer.reserve(std::max(inBufferSizeInFloat, outBufferSizeInFloat));
+}
+
+// reset buffer status by abandon input data in FMQ
+void EffectContext::resetBuffer() {
+    auto buffer = static_cast<float*>(mWorkBuffer.data());
+    std::vector<IEffect::Status> status(mStatusMQ->availableToRead());
+    if (mInputMQ) {
+        mInputMQ->read(buffer, mInputMQ->availableToRead());
+    }
+}
+
+void EffectContext::dupeFmqWithReopen(IEffect::OpenEffectReturn* effectRet) {
+    if (!mInputMQ) {
+        mInputMQ = std::make_shared<DataMQ>(mCommon.input.frameCount * mInputFrameSize /
+                                            sizeof(float));
+    }
+    if (!mOutputMQ) {
+        mOutputMQ = std::make_shared<DataMQ>(mCommon.output.frameCount * mOutputFrameSize /
+                                             sizeof(float));
+    }
+    dupeFmq(effectRet);
+}
+
+void EffectContext::dupeFmq(IEffect::OpenEffectReturn* effectRet) {
+    if (effectRet) {
+        effectRet->statusMQ = mStatusMQ->dupeDesc();
+        effectRet->inputDataMQ = mInputMQ->dupeDesc();
+        effectRet->outputDataMQ = mOutputMQ->dupeDesc();
+    }
+}
+
+float* EffectContext::getWorkBuffer() {
+    return static_cast<float*>(mWorkBuffer.data());
+}
+
+std::shared_ptr<EffectContext::StatusMQ> EffectContext::getStatusFmq() const {
+    return mStatusMQ;
+}
+
+std::shared_ptr<EffectContext::DataMQ> EffectContext::getInputDataFmq() const {
+    return mInputMQ;
+}
+
+std::shared_ptr<EffectContext::DataMQ> EffectContext::getOutputDataFmq() const {
+    return mOutputMQ;
+}
+
+size_t EffectContext::getInputFrameSize() const {
+    return mInputFrameSize;
+}
+
+size_t EffectContext::getOutputFrameSize() const {
+    return mOutputFrameSize;
+}
+
+int EffectContext::getSessionId() const {
+    return mCommon.session;
+}
+
+int EffectContext::getIoHandle() const {
+    return mCommon.ioHandle;
+}
+
+RetCode EffectContext::setOutputDevice(
+        const std::vector<aidl::android::media::audio::common::AudioDeviceDescription>& device) {
+    mOutputDevice = device;
+    return RetCode::SUCCESS;
+}
+
+std::vector<aidl::android::media::audio::common::AudioDeviceDescription>
+EffectContext::getOutputDevice() {
+    return mOutputDevice;
+}
+
+RetCode EffectContext::setAudioMode(const aidl::android::media::audio::common::AudioMode& mode) {
+    mMode = mode;
+    return RetCode::SUCCESS;
+}
+aidl::android::media::audio::common::AudioMode EffectContext::getAudioMode() {
+    return mMode;
+}
+
+RetCode EffectContext::setAudioSource(
+        const aidl::android::media::audio::common::AudioSource& source) {
+    mSource = source;
+    return RetCode::SUCCESS;
+}
+
+aidl::android::media::audio::common::AudioSource EffectContext::getAudioSource() {
+    return mSource;
+}
+
+RetCode EffectContext::setVolumeStereo(const Parameter::VolumeStereo& volumeStereo) {
+    mVolumeStereo = volumeStereo;
+    return RetCode::SUCCESS;
+}
+
+Parameter::VolumeStereo EffectContext::getVolumeStereo() {
+    return mVolumeStereo;
+}
+
+RetCode EffectContext::setCommon(const Parameter::Common& common) {
+    LOG(VERBOSE) << __func__ << common.toString();
+    auto& input = common.input;
+    auto& output = common.output;
+
+    if (input.base.format.pcm != aidl::android::media::audio::common::PcmType::FLOAT_32_BIT ||
+        output.base.format.pcm != aidl::android::media::audio::common::PcmType::FLOAT_32_BIT) {
+        LOG(ERROR) << __func__ << " illegal IO, input "
+                   << ::android::internal::ToString(input.base.format) << ", output "
+                   << ::android::internal::ToString(output.base.format);
+        return RetCode::ERROR_ILLEGAL_PARAMETER;
+    }
+
+    if (auto ret = updateIOFrameSize(common); ret != RetCode::SUCCESS) {
+        return ret;
+    }
+
+    mInputChannelCount = getChannelCount(input.base.channelMask);
+    mOutputChannelCount = getChannelCount(output.base.channelMask);
+    if (mInputChannelCount == 0 || mOutputChannelCount == 0) {
+        LOG(ERROR) << __func__ << " illegal channel count input " << mInputChannelCount
+                   << ", output " << mOutputChannelCount;
+        return RetCode::ERROR_ILLEGAL_PARAMETER;
+    }
+
+    mCommon = common;
+    return RetCode::SUCCESS;
+}
+
+Parameter::Common EffectContext::getCommon() {
+    LOG(VERBOSE) << __func__ << mCommon.toString();
+    return mCommon;
+}
+
+EventFlag* EffectContext::getStatusEventFlag() {
+    return mEfGroup;
+}
+
+RetCode EffectContext::updateIOFrameSize(const Parameter::Common& common) {
+    const auto iFrameSize = ::aidl::android::hardware::audio::common::getFrameSizeInBytes(
+            common.input.base.format, common.input.base.channelMask);
+    const auto oFrameSize = ::aidl::android::hardware::audio::common::getFrameSizeInBytes(
+            common.output.base.format, common.output.base.channelMask);
+
+    bool needUpdateMq = false;
+    if (mInputMQ &&
+        (mInputFrameSize != iFrameSize || mCommon.input.frameCount != common.input.frameCount)) {
+        mInputMQ.reset();
+        needUpdateMq = true;
+    }
+    if (mOutputMQ &&
+        (mOutputFrameSize != oFrameSize || mCommon.output.frameCount != common.output.frameCount)) {
+        mOutputMQ.reset();
+        needUpdateMq = true;
+    }
+    mInputFrameSize = iFrameSize;
+    mOutputFrameSize = oFrameSize;
+    if (needUpdateMq) {
+        return notifyDataMqUpdate();
+    }
+    return RetCode::SUCCESS;
+}
+
+RetCode EffectContext::notifyDataMqUpdate() {
+    if (!mEfGroup) {
+        LOG(ERROR) << __func__ << ": invalid EventFlag group";
+        return RetCode::ERROR_EVENT_FLAG_ERROR;
+    }
+
+    if (const auto ret = mEfGroup->wake(kEventFlagDataMqUpdate); ret != ::android::OK) {
+        LOG(ERROR) << __func__ << ": wake failure with ret " << ret;
+        return RetCode::ERROR_EVENT_FLAG_ERROR;
+    }
+    LOG(DEBUG) << __func__ << " : signal client for reopen";
+    return RetCode::SUCCESS;
+}
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/EffectImpl.cpp b/audio/aidl/default/EffectImpl.cpp
index c81c731..b76269a 100644
--- a/audio/aidl/default/EffectImpl.cpp
+++ b/audio/aidl/default/EffectImpl.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <memory>
 #define LOG_TAG "AHAL_EffectImpl"
 #include "effect-impl/EffectImpl.h"
 #include "effect-impl/EffectTypes.h"
@@ -22,6 +23,7 @@
 using aidl::android::hardware::audio::effect::IEffect;
 using aidl::android::hardware::audio::effect::State;
 using aidl::android::media::audio::common::PcmType;
+using ::android::hardware::EventFlag;
 
 extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
     State state;
@@ -45,40 +47,62 @@
     RETURN_IF(common.input.base.format.pcm != common.output.base.format.pcm ||
                       common.input.base.format.pcm != PcmType::FLOAT_32_BIT,
               EX_ILLEGAL_ARGUMENT, "dataMustBe32BitsFloat");
+    std::lock_guard lg(mImplMutex);
     RETURN_OK_IF(mState != State::INIT);
-    auto context = createContext(common);
-    RETURN_IF(!context, EX_NULL_POINTER, "createContextFailed");
+    mImplContext = createContext(common);
+    RETURN_IF(!mImplContext, EX_NULL_POINTER, "nullContext");
+    mEventFlag = mImplContext->getStatusEventFlag();
 
     if (specific.has_value()) {
         RETURN_IF_ASTATUS_NOT_OK(setParameterSpecific(specific.value()), "setSpecParamErr");
     }
 
     mState = State::IDLE;
-    context->dupeFmq(ret);
-    RETURN_IF(createThread(context, getEffectName()) != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
+    mImplContext->dupeFmq(ret);
+    RETURN_IF(createThread(getEffectName()) != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
               "FailedToCreateWorker");
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus EffectImpl::close() {
-    RETURN_OK_IF(mState == State::INIT);
-    RETURN_IF(mState == State::PROCESSING, EX_ILLEGAL_STATE, "closeAtProcessing");
+ndk::ScopedAStatus EffectImpl::reopen(OpenEffectReturn* ret) {
+    std::lock_guard lg(mImplMutex);
+    RETURN_IF(mState == State::INIT, EX_ILLEGAL_STATE, "alreadyClosed");
 
+    // TODO: b/302036943 add reopen implementation
+    RETURN_IF(!mImplContext, EX_NULL_POINTER, "nullContext");
+    mImplContext->dupeFmqWithReopen(ret);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EffectImpl::close() {
+    {
+        std::lock_guard lg(mImplMutex);
+        RETURN_OK_IF(mState == State::INIT);
+        RETURN_IF(mState == State::PROCESSING, EX_ILLEGAL_STATE, "closeAtProcessing");
+        mState = State::INIT;
+    }
+
+    RETURN_IF(notifyEventFlag(kEventFlagNotEmpty) != RetCode::SUCCESS, EX_ILLEGAL_STATE,
+              "notifyEventFlagFailed");
     // stop the worker thread, ignore the return code
     RETURN_IF(destroyThread() != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
               "FailedToDestroyWorker");
-    mState = State::INIT;
-    RETURN_IF(releaseContext() != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
-              "FailedToCreateWorker");
+
+    {
+        std::lock_guard lg(mImplMutex);
+        releaseContext();
+        mImplContext.reset();
+    }
 
     LOG(DEBUG) << getEffectName() << __func__;
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus EffectImpl::setParameter(const Parameter& param) {
+    std::lock_guard lg(mImplMutex);
     LOG(VERBOSE) << getEffectName() << __func__ << " with: " << param.toString();
 
-    const auto tag = param.getTag();
+    const auto& tag = param.getTag();
     switch (tag) {
         case Parameter::common:
         case Parameter::deviceDescription:
@@ -100,8 +124,8 @@
 }
 
 ndk::ScopedAStatus EffectImpl::getParameter(const Parameter::Id& id, Parameter* param) {
-    auto tag = id.getTag();
-    switch (tag) {
+    std::lock_guard lg(mImplMutex);
+    switch (id.getTag()) {
         case Parameter::Id::commonTag: {
             RETURN_IF_ASTATUS_NOT_OK(getParameterCommon(id.get<Parameter::Id::commonTag>(), param),
                                      "CommonParamNotSupported");
@@ -121,30 +145,30 @@
 }
 
 ndk::ScopedAStatus EffectImpl::setParameterCommon(const Parameter& param) {
-    auto context = getContext();
-    RETURN_IF(!context, EX_NULL_POINTER, "nullContext");
+    RETURN_IF(!mImplContext, EX_NULL_POINTER, "nullContext");
 
-    auto tag = param.getTag();
+    const auto& tag = param.getTag();
     switch (tag) {
         case Parameter::common:
-            RETURN_IF(context->setCommon(param.get<Parameter::common>()) != RetCode::SUCCESS,
+            RETURN_IF(mImplContext->setCommon(param.get<Parameter::common>()) != RetCode::SUCCESS,
                       EX_ILLEGAL_ARGUMENT, "setCommFailed");
             break;
         case Parameter::deviceDescription:
-            RETURN_IF(context->setOutputDevice(param.get<Parameter::deviceDescription>()) !=
+            RETURN_IF(mImplContext->setOutputDevice(param.get<Parameter::deviceDescription>()) !=
                               RetCode::SUCCESS,
                       EX_ILLEGAL_ARGUMENT, "setDeviceFailed");
             break;
         case Parameter::mode:
-            RETURN_IF(context->setAudioMode(param.get<Parameter::mode>()) != RetCode::SUCCESS,
+            RETURN_IF(mImplContext->setAudioMode(param.get<Parameter::mode>()) != RetCode::SUCCESS,
                       EX_ILLEGAL_ARGUMENT, "setModeFailed");
             break;
         case Parameter::source:
-            RETURN_IF(context->setAudioSource(param.get<Parameter::source>()) != RetCode::SUCCESS,
+            RETURN_IF(mImplContext->setAudioSource(param.get<Parameter::source>()) !=
+                              RetCode::SUCCESS,
                       EX_ILLEGAL_ARGUMENT, "setSourceFailed");
             break;
         case Parameter::volumeStereo:
-            RETURN_IF(context->setVolumeStereo(param.get<Parameter::volumeStereo>()) !=
+            RETURN_IF(mImplContext->setVolumeStereo(param.get<Parameter::volumeStereo>()) !=
                               RetCode::SUCCESS,
                       EX_ILLEGAL_ARGUMENT, "setVolumeStereoFailed");
             break;
@@ -159,28 +183,27 @@
 }
 
 ndk::ScopedAStatus EffectImpl::getParameterCommon(const Parameter::Tag& tag, Parameter* param) {
-    auto context = getContext();
-    RETURN_IF(!context, EX_NULL_POINTER, "nullContext");
+    RETURN_IF(!mImplContext, EX_NULL_POINTER, "nullContext");
 
     switch (tag) {
         case Parameter::common: {
-            param->set<Parameter::common>(context->getCommon());
+            param->set<Parameter::common>(mImplContext->getCommon());
             break;
         }
         case Parameter::deviceDescription: {
-            param->set<Parameter::deviceDescription>(context->getOutputDevice());
+            param->set<Parameter::deviceDescription>(mImplContext->getOutputDevice());
             break;
         }
         case Parameter::mode: {
-            param->set<Parameter::mode>(context->getAudioMode());
+            param->set<Parameter::mode>(mImplContext->getAudioMode());
             break;
         }
         case Parameter::source: {
-            param->set<Parameter::source>(context->getAudioSource());
+            param->set<Parameter::source>(mImplContext->getAudioSource());
             break;
         }
         case Parameter::volumeStereo: {
-            param->set<Parameter::volumeStereo>(context->getVolumeStereo());
+            param->set<Parameter::volumeStereo>(mImplContext->getVolumeStereo());
             break;
         }
         default: {
@@ -192,30 +215,34 @@
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus EffectImpl::getState(State* state) {
+ndk::ScopedAStatus EffectImpl::getState(State* state) NO_THREAD_SAFETY_ANALYSIS {
     *state = mState;
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus EffectImpl::command(CommandId command) {
-    RETURN_IF(mState == State::INIT, EX_ILLEGAL_STATE, "CommandStateError");
+    std::lock_guard lg(mImplMutex);
+    RETURN_IF(mState == State::INIT, EX_ILLEGAL_STATE, "instanceNotOpen");
     LOG(DEBUG) << getEffectName() << __func__ << ": receive command: " << toString(command)
                << " at state " << toString(mState);
 
     switch (command) {
         case CommandId::START:
-            RETURN_IF(mState == State::INIT, EX_ILLEGAL_STATE, "instanceNotOpen");
             RETURN_OK_IF(mState == State::PROCESSING);
             RETURN_IF_ASTATUS_NOT_OK(commandImpl(command), "commandImplFailed");
-            startThread();
             mState = State::PROCESSING;
+            RETURN_IF(notifyEventFlag(kEventFlagNotEmpty) != RetCode::SUCCESS, EX_ILLEGAL_STATE,
+                      "notifyEventFlagFailed");
+            startThread();
             break;
         case CommandId::STOP:
         case CommandId::RESET:
             RETURN_OK_IF(mState == State::IDLE);
+            mState = State::IDLE;
+            RETURN_IF(notifyEventFlag(kEventFlagNotEmpty) != RetCode::SUCCESS, EX_ILLEGAL_STATE,
+                      "notifyEventFlagFailed");
             stopThread();
             RETURN_IF_ASTATUS_NOT_OK(commandImpl(command), "commandImplFailed");
-            mState = State::IDLE;
             break;
         default:
             LOG(ERROR) << getEffectName() << __func__ << " instance still processing";
@@ -227,19 +254,41 @@
 }
 
 ndk::ScopedAStatus EffectImpl::commandImpl(CommandId command) {
-    auto context = getContext();
-    RETURN_IF(!context, EX_NULL_POINTER, "nullContext");
+    RETURN_IF(!mImplContext, EX_NULL_POINTER, "nullContext");
     if (command == CommandId::RESET) {
-        context->resetBuffer();
+        mImplContext->resetBuffer();
     }
     return ndk::ScopedAStatus::ok();
 }
 
+std::shared_ptr<EffectContext> EffectImpl::createContext(const Parameter::Common& common) {
+    return std::make_shared<EffectContext>(1 /* statusMqDepth */, common);
+}
+
+RetCode EffectImpl::releaseContext() {
+    if (mImplContext) {
+        mImplContext.reset();
+    }
+    return RetCode::SUCCESS;
+}
+
 void EffectImpl::cleanUp() {
     command(CommandId::STOP);
     close();
 }
 
+RetCode EffectImpl::notifyEventFlag(uint32_t flag) {
+    if (!mEventFlag) {
+        LOG(ERROR) << getEffectName() << __func__ << ": StatusEventFlag invalid";
+        return RetCode::ERROR_EVENT_FLAG_ERROR;
+    }
+    if (const auto ret = mEventFlag->wake(flag); ret != ::android::OK) {
+        LOG(ERROR) << getEffectName() << __func__ << ": wake failure with ret " << ret;
+        return RetCode::ERROR_EVENT_FLAG_ERROR;
+    }
+    return RetCode::SUCCESS;
+}
+
 IEffect::Status EffectImpl::status(binder_status_t status, size_t consumed, size_t produced) {
     IEffect::Status ret;
     ret.status = status;
@@ -248,6 +297,48 @@
     return ret;
 }
 
+void EffectImpl::process() {
+    /**
+     * wait for the EventFlag without lock, it's ok because the mEfGroup pointer will not change
+     * in the life cycle of workerThread (threadLoop).
+     */
+    uint32_t efState = 0;
+    if (!mEventFlag ||
+        ::android::OK != mEventFlag->wait(kEventFlagNotEmpty, &efState, 0 /* no timeout */,
+                                          true /* retry */) ||
+        !(efState & kEventFlagNotEmpty)) {
+        LOG(ERROR) << getEffectName() << __func__ << ": StatusEventFlag - " << mEventFlag
+                   << " efState - " << std::hex << efState;
+        return;
+    }
+
+    {
+        std::lock_guard lg(mImplMutex);
+        if (mState != State::PROCESSING) {
+            LOG(DEBUG) << getEffectName() << " skip process in state: " << toString(mState);
+            return;
+        }
+        RETURN_VALUE_IF(!mImplContext, void(), "nullContext");
+        auto statusMQ = mImplContext->getStatusFmq();
+        auto inputMQ = mImplContext->getInputDataFmq();
+        auto outputMQ = mImplContext->getOutputDataFmq();
+        auto buffer = mImplContext->getWorkBuffer();
+        if (!inputMQ || !outputMQ) {
+            return;
+        }
+
+        auto processSamples = inputMQ->availableToRead();
+        if (processSamples) {
+            inputMQ->read(buffer, processSamples);
+            IEffect::Status status = effectProcessImpl(buffer, buffer, processSamples);
+            outputMQ->write(buffer, status.fmqProduced);
+            statusMQ->writeBlocking(&status, 1);
+            LOG(VERBOSE) << getEffectName() << __func__ << ": done processing, effect consumed "
+                         << status.fmqConsumed << " produced " << status.fmqProduced;
+        }
+    }
+}
+
 // A placeholder processing implementation to copy samples from input to output
 IEffect::Status EffectImpl::effectProcessImpl(float* in, float* out, int samples) {
     for (int i = 0; i < samples; i++) {
diff --git a/audio/aidl/default/EffectMain.cpp b/audio/aidl/default/EffectMain.cpp
index ca81204..ac178b6 100644
--- a/audio/aidl/default/EffectMain.cpp
+++ b/audio/aidl/default/EffectMain.cpp
@@ -21,15 +21,39 @@
 #include <android/binder_process.h>
 #include <system/audio_config.h>
 
+#ifdef __ANDROID_APEX__
+#include <android/apexsupport.h>
+#endif
+
 /** Default name of effect configuration file. */
 static const char* kDefaultConfigName = "audio_effects_config.xml";
 
+static inline std::string config_file_path() {
+    if (__builtin_available(android AAPEXSUPPORT_API, *)) {
+        AApexInfo *apexInfo;
+        if (AApexInfo_create(&apexInfo) == AAPEXINFO_OK) {
+            std::string apexName(AApexInfo_getName(apexInfo));
+            AApexInfo_destroy(apexInfo);
+            std::string candidatePath("/apex/");
+            candidatePath.append(apexName).append("/etc/").append(kDefaultConfigName);
+            LOG(DEBUG) << __func__ << " effect lib path " << candidatePath;
+            if (access(candidatePath.c_str(), R_OK) == 0) {
+                return std::move(candidatePath);
+            }
+        }
+    } else {
+        LOG(DEBUG) << __func__ << " libapexsupport is not supported";
+    }
+    LOG(DEBUG) << __func__ << ": Unable to resolve config file path in APEX";
+    return android::audio_find_readable_configuration_file(kDefaultConfigName);
+}
+
 int main() {
     // This is a debug implementation, always enable debug logging.
     android::base::SetMinimumLogSeverity(::android::base::DEBUG);
     ABinderProcess_setThreadPoolMaxThreadCount(0);
 
-    auto configFile = android::audio_find_readable_configuration_file(kDefaultConfigName);
+    auto configFile = config_file_path();
     if (configFile == "") {
         LOG(ERROR) << __func__ << ": config file " << kDefaultConfigName << " not found!";
         return EXIT_FAILURE;
diff --git a/audio/aidl/default/EffectThread.cpp b/audio/aidl/default/EffectThread.cpp
index 47ba9f4..fdd4803 100644
--- a/audio/aidl/default/EffectThread.cpp
+++ b/audio/aidl/default/EffectThread.cpp
@@ -25,8 +25,6 @@
 #include "effect-impl/EffectThread.h"
 #include "effect-impl/EffectTypes.h"
 
-using ::android::hardware::EventFlag;
-
 namespace aidl::android::hardware::audio::effect {
 
 EffectThread::EffectThread() {
@@ -38,31 +36,18 @@
     LOG(DEBUG) << __func__ << " done";
 }
 
-RetCode EffectThread::createThread(std::shared_ptr<EffectContext> context, const std::string& name,
-                                   int priority) {
+RetCode EffectThread::createThread(const std::string& name, int priority) {
     if (mThread.joinable()) {
         LOG(WARNING) << mName << __func__ << " thread already created, no-op";
         return RetCode::SUCCESS;
     }
+
     mName = name;
     mPriority = priority;
     {
         std::lock_guard lg(mThreadMutex);
         mStop = true;
         mExit = false;
-        mThreadContext = std::move(context);
-        auto statusMQ = mThreadContext->getStatusFmq();
-        EventFlag* efGroup = nullptr;
-        ::android::status_t status =
-                EventFlag::createEventFlag(statusMQ->getEventFlagWord(), &efGroup);
-        if (status != ::android::OK || !efGroup) {
-            LOG(ERROR) << mName << __func__ << " create EventFlagGroup failed " << status
-                       << " efGroup " << efGroup;
-            return RetCode::ERROR_THREAD;
-        }
-        mEfGroup.reset(efGroup);
-        // kickoff and wait for commands (CommandId::START/STOP) or IEffect.close from client
-        mEfGroup->wake(kEventFlagNotEmpty);
     }
 
     mThread = std::thread(&EffectThread::threadLoop, this);
@@ -75,16 +60,12 @@
         std::lock_guard lg(mThreadMutex);
         mStop = mExit = true;
     }
-    mCv.notify_one();
 
+    mCv.notify_one();
     if (mThread.joinable()) {
         mThread.join();
     }
 
-    {
-        std::lock_guard lg(mThreadMutex);
-        mThreadContext.reset();
-    }
     LOG(DEBUG) << mName << __func__;
     return RetCode::SUCCESS;
 }
@@ -96,7 +77,6 @@
         mCv.notify_one();
     }
 
-    mEfGroup->wake(kEventFlagNotEmpty);
     LOG(DEBUG) << mName << __func__;
     return RetCode::SUCCESS;
 }
@@ -108,7 +88,6 @@
         mCv.notify_one();
     }
 
-    mEfGroup->wake(kEventFlagNotEmpty);
     LOG(DEBUG) << mName << __func__;
     return RetCode::SUCCESS;
 }
@@ -117,13 +96,6 @@
     pthread_setname_np(pthread_self(), mName.substr(0, kMaxTaskNameLen - 1).c_str());
     setpriority(PRIO_PROCESS, 0, mPriority);
     while (true) {
-        /**
-         * wait for the EventFlag without lock, it's ok because the mEfGroup pointer will not change
-         * in the life cycle of workerThread (threadLoop).
-         */
-        uint32_t efState = 0;
-        mEfGroup->wait(kEventFlagNotEmpty, &efState);
-
         {
             std::unique_lock l(mThreadMutex);
             ::android::base::ScopedLockAssertion lock_assertion(mThreadMutex);
@@ -132,27 +104,8 @@
                 LOG(INFO) << __func__ << " EXIT!";
                 return;
             }
-            process_l();
         }
-    }
-}
-
-void EffectThread::process_l() {
-    RETURN_VALUE_IF(!mThreadContext, void(), "nullContext");
-
-    auto statusMQ = mThreadContext->getStatusFmq();
-    auto inputMQ = mThreadContext->getInputDataFmq();
-    auto outputMQ = mThreadContext->getOutputDataFmq();
-    auto buffer = mThreadContext->getWorkBuffer();
-
-    auto processSamples = inputMQ->availableToRead();
-    if (processSamples) {
-        inputMQ->read(buffer, processSamples);
-        IEffect::Status status = effectProcessImpl(buffer, buffer, processSamples);
-        outputMQ->write(buffer, status.fmqProduced);
-        statusMQ->writeBlocking(&status, 1);
-        LOG(VERBOSE) << mName << __func__ << ": done processing, effect consumed "
-                     << status.fmqConsumed << " produced " << status.fmqProduced;
+        process();
     }
 }
 
diff --git a/audio/aidl/default/EngineConfigXmlConverter.cpp b/audio/aidl/default/EngineConfigXmlConverter.cpp
index 96b555c..631cdce 100644
--- a/audio/aidl/default/EngineConfigXmlConverter.cpp
+++ b/audio/aidl/default/EngineConfigXmlConverter.cpp
@@ -20,11 +20,14 @@
 #include <functional>
 #include <unordered_map>
 
+#define LOG_TAG "AHAL_Config"
 #include <aidl/android/media/audio/common/AudioFlag.h>
 #include <aidl/android/media/audio/common/AudioHalEngineConfig.h>
 #include <aidl/android/media/audio/common/AudioProductStrategyType.h>
+#include <android-base/logging.h>
 
 #include "core-impl/EngineConfigXmlConverter.h"
+#include "core-impl/XsdcConversion.h"
 
 using aidl::android::media::audio::common::AudioAttributes;
 using aidl::android::media::audio::common::AudioContentType;
@@ -40,20 +43,13 @@
 using aidl::android::media::audio::common::AudioSource;
 using aidl::android::media::audio::common::AudioStreamType;
 using aidl::android::media::audio::common::AudioUsage;
+using ::android::BAD_VALUE;
+using ::android::base::unexpected;
 
-namespace xsd = android::audio::policy::engine::configuration;
+namespace eng_xsd = android::audio::policy::engine::configuration;
 
 namespace aidl::android::hardware::audio::core::internal {
 
-/**
- * Valid curve points take the form "<index>,<attenuationMb>", where the index
- * must be in the range [0,100]. kInvalidCurvePointIndex is used to indicate
- * that a point was formatted incorrectly (e.g. if a vendor accidentally typed a
- * '.' instead of a ',' in their XML)-- using such a curve point will result in
- * failed VTS tests.
- */
-static const int8_t kInvalidCurvePointIndex = -1;
-
 void EngineConfigXmlConverter::initProductStrategyMap() {
 #define STRATEGY_ENTRY(name) {"STRATEGY_" #name, static_cast<int>(AudioProductStrategyType::name)}
 
@@ -68,7 +64,7 @@
 #undef STRATEGY_ENTRY
 }
 
-int EngineConfigXmlConverter::convertProductStrategyNameToAidl(
+ConversionResult<int> EngineConfigXmlConverter::convertProductStrategyNameToAidl(
         const std::string& xsdcProductStrategyName) {
     const auto [it, success] = mProductStrategyMap.insert(
             std::make_pair(xsdcProductStrategyName, mNextVendorStrategy));
@@ -85,12 +81,12 @@
             (attributes.tags.empty()));
 }
 
-AudioAttributes EngineConfigXmlConverter::convertAudioAttributesToAidl(
-        const xsd::AttributesType& xsdcAudioAttributes) {
+ConversionResult<AudioAttributes> EngineConfigXmlConverter::convertAudioAttributesToAidl(
+        const eng_xsd::AttributesType& xsdcAudioAttributes) {
     if (xsdcAudioAttributes.hasAttributesRef()) {
         if (mAttributesReferenceMap.empty()) {
             mAttributesReferenceMap =
-                    generateReferenceMap<xsd::AttributesRef, xsd::AttributesRefType>(
+                    generateReferenceMap<eng_xsd::AttributesRef, eng_xsd::AttributesRefType>(
                             getXsdcConfig()->getAttributesRef());
         }
         return convertAudioAttributesToAidl(
@@ -111,16 +107,16 @@
                 static_cast<AudioSource>(xsdcAudioAttributes.getFirstSource()->getValue());
     }
     if (xsdcAudioAttributes.hasFlags()) {
-        std::vector<xsd::FlagType> xsdcFlagTypeVec =
+        std::vector<eng_xsd::FlagType> xsdcFlagTypeVec =
                 xsdcAudioAttributes.getFirstFlags()->getValue();
-        for (const xsd::FlagType& xsdcFlagType : xsdcFlagTypeVec) {
-            if (xsdcFlagType != xsd::FlagType::AUDIO_FLAG_NONE) {
+        for (const eng_xsd::FlagType& xsdcFlagType : xsdcFlagTypeVec) {
+            if (xsdcFlagType != eng_xsd::FlagType::AUDIO_FLAG_NONE) {
                 aidlAudioAttributes.flags |= 1 << (static_cast<int>(xsdcFlagType) - 1);
             }
         }
     }
     if (xsdcAudioAttributes.hasBundle()) {
-        const xsd::BundleType* xsdcBundle = xsdcAudioAttributes.getFirstBundle();
+        const eng_xsd::BundleType* xsdcBundle = xsdcAudioAttributes.getFirstBundle();
         aidlAudioAttributes.tags[0] = xsdcBundle->getKey() + "=" + xsdcBundle->getValue();
     }
     if (isDefaultAudioAttributes(aidlAudioAttributes)) {
@@ -129,53 +125,54 @@
     return aidlAudioAttributes;
 }
 
-AudioHalAttributesGroup EngineConfigXmlConverter::convertAttributesGroupToAidl(
-        const xsd::AttributesGroup& xsdcAttributesGroup) {
+ConversionResult<AudioHalAttributesGroup> EngineConfigXmlConverter::convertAttributesGroupToAidl(
+        const eng_xsd::AttributesGroup& xsdcAttributesGroup) {
     AudioHalAttributesGroup aidlAttributesGroup;
     static const int kStreamTypeEnumOffset =
-            static_cast<int>(xsd::Stream::AUDIO_STREAM_VOICE_CALL) -
+            static_cast<int>(eng_xsd::Stream::AUDIO_STREAM_VOICE_CALL) -
             static_cast<int>(AudioStreamType::VOICE_CALL);
     aidlAttributesGroup.streamType = static_cast<AudioStreamType>(
             static_cast<int>(xsdcAttributesGroup.getStreamType()) - kStreamTypeEnumOffset);
     aidlAttributesGroup.volumeGroupName = xsdcAttributesGroup.getVolumeGroup();
     if (xsdcAttributesGroup.hasAttributes_optional()) {
         aidlAttributesGroup.attributes =
-                convertCollectionToAidlUnchecked<xsd::AttributesType, AudioAttributes>(
+                VALUE_OR_FATAL((convertCollectionToAidl<eng_xsd::AttributesType, AudioAttributes>(
                         xsdcAttributesGroup.getAttributes_optional(),
                         std::bind(&EngineConfigXmlConverter::convertAudioAttributesToAidl, this,
-                                  std::placeholders::_1));
+                                  std::placeholders::_1))));
     } else if (xsdcAttributesGroup.hasContentType_optional() ||
                xsdcAttributesGroup.hasUsage_optional() ||
                xsdcAttributesGroup.hasSource_optional() ||
                xsdcAttributesGroup.hasFlags_optional() ||
                xsdcAttributesGroup.hasBundle_optional()) {
-        aidlAttributesGroup.attributes.push_back(convertAudioAttributesToAidl(xsd::AttributesType(
-                xsdcAttributesGroup.getContentType_optional(),
-                xsdcAttributesGroup.getUsage_optional(), xsdcAttributesGroup.getSource_optional(),
-                xsdcAttributesGroup.getFlags_optional(), xsdcAttributesGroup.getBundle_optional(),
-                std::nullopt)));
+        aidlAttributesGroup.attributes.push_back(VALUE_OR_FATAL(convertAudioAttributesToAidl(
+                eng_xsd::AttributesType(xsdcAttributesGroup.getContentType_optional(),
+                                        xsdcAttributesGroup.getUsage_optional(),
+                                        xsdcAttributesGroup.getSource_optional(),
+                                        xsdcAttributesGroup.getFlags_optional(),
+                                        xsdcAttributesGroup.getBundle_optional(), std::nullopt))));
 
     } else {
-        // do nothing;
-        // TODO: check if this is valid or if we should treat as an error.
-        // Currently, attributes are not mandatory in schema, but an AttributesGroup
-        // without attributes does not make much sense.
+        LOG(ERROR) << __func__ << " Review Audio Policy config: no audio attributes provided for "
+                   << aidlAttributesGroup.toString();
+        return unexpected(BAD_VALUE);
     }
     return aidlAttributesGroup;
 }
 
-AudioHalProductStrategy EngineConfigXmlConverter::convertProductStrategyToAidl(
-        const xsd::ProductStrategies::ProductStrategy& xsdcProductStrategy) {
+ConversionResult<AudioHalProductStrategy> EngineConfigXmlConverter::convertProductStrategyToAidl(
+        const eng_xsd::ProductStrategies::ProductStrategy& xsdcProductStrategy) {
     AudioHalProductStrategy aidlProductStrategy;
 
-    aidlProductStrategy.id = convertProductStrategyNameToAidl(xsdcProductStrategy.getName());
+    aidlProductStrategy.id =
+            VALUE_OR_FATAL(convertProductStrategyNameToAidl(xsdcProductStrategy.getName()));
 
     if (xsdcProductStrategy.hasAttributesGroup()) {
-        aidlProductStrategy.attributesGroups =
-                convertCollectionToAidlUnchecked<xsd::AttributesGroup, AudioHalAttributesGroup>(
+        aidlProductStrategy.attributesGroups = VALUE_OR_FATAL(
+                (convertCollectionToAidl<eng_xsd::AttributesGroup, AudioHalAttributesGroup>(
                         xsdcProductStrategy.getAttributesGroup(),
                         std::bind(&EngineConfigXmlConverter::convertAttributesGroupToAidl, this,
-                                  std::placeholders::_1));
+                                  std::placeholders::_1))));
     }
     if ((mDefaultProductStrategyId != std::nullopt) && (mDefaultProductStrategyId.value() == -1)) {
         mDefaultProductStrategyId = aidlProductStrategy.id;
@@ -183,82 +180,42 @@
     return aidlProductStrategy;
 }
 
-AudioHalVolumeCurve::CurvePoint EngineConfigXmlConverter::convertCurvePointToAidl(
-        const std::string& xsdcCurvePoint) {
-    AudioHalVolumeCurve::CurvePoint aidlCurvePoint{};
-    if (sscanf(xsdcCurvePoint.c_str(), "%" SCNd8 ",%d", &aidlCurvePoint.index,
-               &aidlCurvePoint.attenuationMb) != 2) {
-        aidlCurvePoint.index = kInvalidCurvePointIndex;
-    }
-    return aidlCurvePoint;
-}
-
-AudioHalVolumeCurve EngineConfigXmlConverter::convertVolumeCurveToAidl(
-        const xsd::Volume& xsdcVolumeCurve) {
+ConversionResult<AudioHalVolumeCurve> EngineConfigXmlConverter::convertVolumeCurveToAidl(
+        const eng_xsd::Volume& xsdcVolumeCurve) {
     AudioHalVolumeCurve aidlVolumeCurve;
     aidlVolumeCurve.deviceCategory =
             static_cast<AudioHalVolumeCurve::DeviceCategory>(xsdcVolumeCurve.getDeviceCategory());
     if (xsdcVolumeCurve.hasRef()) {
         if (mVolumesReferenceMap.empty()) {
-            mVolumesReferenceMap = generateReferenceMap<xsd::VolumesType, xsd::VolumeRef>(
+            mVolumesReferenceMap = generateReferenceMap<eng_xsd::VolumesType, eng_xsd::VolumeRef>(
                     getXsdcConfig()->getVolumes());
         }
-        aidlVolumeCurve.curvePoints =
-                convertCollectionToAidlUnchecked<std::string, AudioHalVolumeCurve::CurvePoint>(
+        aidlVolumeCurve.curvePoints = VALUE_OR_FATAL(
+                (convertCollectionToAidl<std::string, AudioHalVolumeCurve::CurvePoint>(
                         mVolumesReferenceMap.at(xsdcVolumeCurve.getRef()).getPoint(),
-                        std::bind(&EngineConfigXmlConverter::convertCurvePointToAidl, this,
-                                  std::placeholders::_1));
+                        &convertCurvePointToAidl)));
     } else {
-        aidlVolumeCurve.curvePoints =
-                convertCollectionToAidlUnchecked<std::string, AudioHalVolumeCurve::CurvePoint>(
-                        xsdcVolumeCurve.getPoint(),
-                        std::bind(&EngineConfigXmlConverter::convertCurvePointToAidl, this,
-                                  std::placeholders::_1));
+        aidlVolumeCurve.curvePoints = VALUE_OR_FATAL(
+                (convertCollectionToAidl<std::string, AudioHalVolumeCurve::CurvePoint>(
+                        xsdcVolumeCurve.getPoint(), &convertCurvePointToAidl)));
     }
     return aidlVolumeCurve;
 }
 
-AudioHalVolumeGroup EngineConfigXmlConverter::convertVolumeGroupToAidl(
-        const xsd::VolumeGroupsType::VolumeGroup& xsdcVolumeGroup) {
+ConversionResult<AudioHalVolumeGroup> EngineConfigXmlConverter::convertVolumeGroupToAidl(
+        const eng_xsd::VolumeGroupsType::VolumeGroup& xsdcVolumeGroup) {
     AudioHalVolumeGroup aidlVolumeGroup;
     aidlVolumeGroup.name = xsdcVolumeGroup.getName();
     aidlVolumeGroup.minIndex = xsdcVolumeGroup.getIndexMin();
     aidlVolumeGroup.maxIndex = xsdcVolumeGroup.getIndexMax();
     aidlVolumeGroup.volumeCurves =
-            convertCollectionToAidlUnchecked<xsd::Volume, AudioHalVolumeCurve>(
+            VALUE_OR_FATAL((convertCollectionToAidl<eng_xsd::Volume, AudioHalVolumeCurve>(
                     xsdcVolumeGroup.getVolume(),
                     std::bind(&EngineConfigXmlConverter::convertVolumeCurveToAidl, this,
-                              std::placeholders::_1));
+                              std::placeholders::_1))));
     return aidlVolumeGroup;
 }
 
-AudioHalCapCriterion EngineConfigXmlConverter::convertCapCriterionToAidl(
-        const xsd::CriterionType& xsdcCriterion) {
-    AudioHalCapCriterion aidlCapCriterion;
-    aidlCapCriterion.name = xsdcCriterion.getName();
-    aidlCapCriterion.criterionTypeName = xsdcCriterion.getType();
-    aidlCapCriterion.defaultLiteralValue = xsdcCriterion.get_default();
-    return aidlCapCriterion;
-}
-
-std::string EngineConfigXmlConverter::convertCriterionTypeValueToAidl(
-        const xsd::ValueType& xsdcCriterionTypeValue) {
-    return xsdcCriterionTypeValue.getLiteral();
-}
-
-AudioHalCapCriterionType EngineConfigXmlConverter::convertCapCriterionTypeToAidl(
-        const xsd::CriterionTypeType& xsdcCriterionType) {
-    AudioHalCapCriterionType aidlCapCriterionType;
-    aidlCapCriterionType.name = xsdcCriterionType.getName();
-    aidlCapCriterionType.isInclusive = !(static_cast<bool>(xsdcCriterionType.getType()));
-    aidlCapCriterionType.values =
-            convertWrappedCollectionToAidlUnchecked<xsd::ValuesType, xsd::ValueType, std::string>(
-                    xsdcCriterionType.getValues(), &xsd::ValuesType::getValue,
-                    std::bind(&EngineConfigXmlConverter::convertCriterionTypeValueToAidl, this,
-                              std::placeholders::_1));
-    return aidlCapCriterionType;
-}
-
 AudioHalEngineConfig& EngineConfigXmlConverter::getAidlEngineConfig() {
     return mAidlEngineConfig;
 }
@@ -266,39 +223,42 @@
 void EngineConfigXmlConverter::init() {
     initProductStrategyMap();
     if (getXsdcConfig()->hasProductStrategies()) {
-        mAidlEngineConfig.productStrategies =
-                convertWrappedCollectionToAidlUnchecked<xsd::ProductStrategies,
-                                                        xsd::ProductStrategies::ProductStrategy,
-                                                        AudioHalProductStrategy>(
+        mAidlEngineConfig.productStrategies = VALUE_OR_FATAL(
+                (convertWrappedCollectionToAidl<eng_xsd::ProductStrategies,
+                                                eng_xsd::ProductStrategies::ProductStrategy,
+                                                AudioHalProductStrategy>(
                         getXsdcConfig()->getProductStrategies(),
-                        &xsd::ProductStrategies::getProductStrategy,
+                        &eng_xsd::ProductStrategies::getProductStrategy,
                         std::bind(&EngineConfigXmlConverter::convertProductStrategyToAidl, this,
-                                  std::placeholders::_1));
+                                  std::placeholders::_1))));
         if (mDefaultProductStrategyId) {
             mAidlEngineConfig.defaultProductStrategyId = mDefaultProductStrategyId.value();
         }
     }
     if (getXsdcConfig()->hasVolumeGroups()) {
-        mAidlEngineConfig.volumeGroups = convertWrappedCollectionToAidlUnchecked<
-                xsd::VolumeGroupsType, xsd::VolumeGroupsType::VolumeGroup, AudioHalVolumeGroup>(
-                getXsdcConfig()->getVolumeGroups(), &xsd::VolumeGroupsType::getVolumeGroup,
-                std::bind(&EngineConfigXmlConverter::convertVolumeGroupToAidl, this,
-                          std::placeholders::_1));
+        mAidlEngineConfig.volumeGroups = VALUE_OR_FATAL(
+                (convertWrappedCollectionToAidl<eng_xsd::VolumeGroupsType,
+                                                eng_xsd::VolumeGroupsType::VolumeGroup,
+                                                AudioHalVolumeGroup>(
+                        getXsdcConfig()->getVolumeGroups(),
+                        &eng_xsd::VolumeGroupsType::getVolumeGroup,
+                        std::bind(&EngineConfigXmlConverter::convertVolumeGroupToAidl, this,
+                                  std::placeholders::_1))));
     }
     if (getXsdcConfig()->hasCriteria() && getXsdcConfig()->hasCriterion_types()) {
         AudioHalEngineConfig::CapSpecificConfig capSpecificConfig;
-        capSpecificConfig.criteria =
-                convertWrappedCollectionToAidlUnchecked<xsd::CriteriaType, xsd::CriterionType,
-                                                        AudioHalCapCriterion>(
-                        getXsdcConfig()->getCriteria(), &xsd::CriteriaType::getCriterion,
-                        std::bind(&EngineConfigXmlConverter::convertCapCriterionToAidl, this,
-                                  std::placeholders::_1));
-        capSpecificConfig.criterionTypes = convertWrappedCollectionToAidlUnchecked<
-                xsd::CriterionTypesType, xsd::CriterionTypeType, AudioHalCapCriterionType>(
-                getXsdcConfig()->getCriterion_types(), &xsd::CriterionTypesType::getCriterion_type,
-                std::bind(&EngineConfigXmlConverter::convertCapCriterionTypeToAidl, this,
-                          std::placeholders::_1));
-        mAidlEngineConfig.capSpecificConfig = capSpecificConfig;
+        capSpecificConfig.criteria = VALUE_OR_FATAL(
+                (convertWrappedCollectionToAidl<eng_xsd::CriteriaType, eng_xsd::CriterionType,
+                                                AudioHalCapCriterion>(
+                        getXsdcConfig()->getCriteria(), &eng_xsd::CriteriaType::getCriterion,
+                        &convertCapCriterionToAidl)));
+        capSpecificConfig.criterionTypes =
+                VALUE_OR_FATAL((convertWrappedCollectionToAidl<eng_xsd::CriterionTypesType,
+                                                               eng_xsd::CriterionTypeType,
+                                                               AudioHalCapCriterionType>(
+                        getXsdcConfig()->getCriterion_types(),
+                        &eng_xsd::CriterionTypesType::getCriterion_type,
+                        &convertCapCriterionTypeToAidl)));
     }
 }
 }  // namespace aidl::android::hardware::audio::core::internal
diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp
index b7761bf..94aa4dc 100644
--- a/audio/aidl/default/Module.cpp
+++ b/audio/aidl/default/Module.cpp
@@ -18,13 +18,13 @@
 #include <set>
 
 #define LOG_TAG "AHAL_Module"
-#include <Utils.h>
 #include <aidl/android/media/audio/common/AudioInputFlags.h>
 #include <aidl/android/media/audio/common/AudioOutputFlags.h>
 #include <android-base/logging.h>
 #include <android/binder_ibinder_platform.h>
 #include <error/expected_utils.h>
 
+#include "core-impl/Configuration.h"
 #include "core-impl/Module.h"
 #include "core-impl/ModuleBluetooth.h"
 #include "core-impl/ModulePrimary.h"
@@ -34,6 +34,7 @@
 #include "core-impl/SoundDose.h"
 #include "core-impl/utils.h"
 
+using aidl::android::hardware::audio::common::frameCountFromDurationMs;
 using aidl::android::hardware::audio::common::getFrameSizeInBytes;
 using aidl::android::hardware::audio::common::isBitPositionFlagSet;
 using aidl::android::hardware::audio::common::isValidAudioMode;
@@ -42,6 +43,7 @@
 using aidl::android::hardware::audio::core::sounddose::ISoundDose;
 using aidl::android::media::audio::common::AudioChannelLayout;
 using aidl::android::media::audio::common::AudioDevice;
+using aidl::android::media::audio::common::AudioDeviceType;
 using aidl::android::media::audio::common::AudioFormatDescription;
 using aidl::android::media::audio::common::AudioFormatType;
 using aidl::android::media::audio::common::AudioInputFlags;
@@ -65,32 +67,30 @@
 
 namespace {
 
-bool generateDefaultPortConfig(const AudioPort& port, AudioPortConfig* config) {
-    *config = {};
-    config->portId = port.id;
-    if (port.profiles.empty()) {
-        LOG(ERROR) << __func__ << ": port " << port.id << " has no profiles";
-        return false;
-    }
-    const auto& profile = port.profiles.begin();
-    config->format = profile->format;
-    if (profile->channelMasks.empty()) {
-        LOG(ERROR) << __func__ << ": the first profile in port " << port.id
-                   << " has no channel masks";
-        return false;
-    }
-    config->channelMask = *profile->channelMasks.begin();
-    if (profile->sampleRates.empty()) {
-        LOG(ERROR) << __func__ << ": the first profile in port " << port.id
-                   << " has no sample rates";
-        return false;
-    }
-    Int sampleRate;
-    sampleRate.value = *profile->sampleRates.begin();
-    config->sampleRate = sampleRate;
-    config->flags = port.flags;
-    config->ext = port.ext;
-    return true;
+inline bool hasDynamicChannelMasks(const std::vector<AudioChannelLayout>& channelMasks) {
+    return channelMasks.empty() ||
+           std::all_of(channelMasks.begin(), channelMasks.end(),
+                       [](const auto& channelMask) { return channelMask == AudioChannelLayout{}; });
+}
+
+inline bool hasDynamicFormat(const AudioFormatDescription& format) {
+    return format == AudioFormatDescription{};
+}
+
+inline bool hasDynamicSampleRates(const std::vector<int32_t>& sampleRates) {
+    return sampleRates.empty() ||
+           std::all_of(sampleRates.begin(), sampleRates.end(),
+                       [](const auto& sampleRate) { return sampleRate == 0; });
+}
+
+inline bool isDynamicProfile(const AudioProfile& profile) {
+    return hasDynamicFormat(profile.format) || hasDynamicChannelMasks(profile.channelMasks) ||
+           hasDynamicSampleRates(profile.sampleRates);
+}
+
+bool hasDynamicProfilesOnly(const std::vector<AudioProfile>& profiles) {
+    if (profiles.empty()) return true;
+    return std::all_of(profiles.begin(), profiles.end(), isDynamicProfile);
 }
 
 bool findAudioProfile(const AudioPort& port, const AudioFormatDescription& format,
@@ -108,21 +108,36 @@
 }  // namespace
 
 // static
-std::shared_ptr<Module> Module::createInstance(Type type) {
+std::shared_ptr<Module> Module::createInstance(Type type, std::unique_ptr<Configuration>&& config) {
     switch (type) {
         case Type::DEFAULT:
-            return ndk::SharedRefBase::make<ModulePrimary>();
+            return ndk::SharedRefBase::make<ModulePrimary>(std::move(config));
         case Type::R_SUBMIX:
-            return ndk::SharedRefBase::make<ModuleRemoteSubmix>();
+            return ndk::SharedRefBase::make<ModuleRemoteSubmix>(std::move(config));
         case Type::STUB:
-            return ndk::SharedRefBase::make<ModuleStub>();
+            return ndk::SharedRefBase::make<ModuleStub>(std::move(config));
         case Type::USB:
-            return ndk::SharedRefBase::make<ModuleUsb>();
+            return ndk::SharedRefBase::make<ModuleUsb>(std::move(config));
         case Type::BLUETOOTH:
-            return ndk::SharedRefBase::make<ModuleBluetooth>();
+            return ndk::SharedRefBase::make<ModuleBluetooth>(std::move(config));
     }
 }
 
+// static
+std::optional<Module::Type> Module::typeFromString(const std::string& type) {
+    if (type == "default")
+        return Module::Type::DEFAULT;
+    else if (type == "r_submix")
+        return Module::Type::R_SUBMIX;
+    else if (type == "stub")
+        return Module::Type::STUB;
+    else if (type == "usb")
+        return Module::Type::USB;
+    else if (type == "bluetooth")
+        return Module::Type::BLUETOOTH;
+    return {};
+}
+
 std::ostream& operator<<(std::ostream& os, Module::Type t) {
     switch (t) {
         case Module::Type::DEFAULT:
@@ -144,6 +159,11 @@
     return os;
 }
 
+Module::Module(Type type, std::unique_ptr<Configuration>&& config)
+    : mType(type), mConfig(std::move(config)) {
+    populateConnectedProfiles();
+}
+
 void Module::cleanUpPatch(int32_t patchId) {
     erase_all_values(mPatches, std::set<int32_t>{patchId});
 }
@@ -156,15 +176,18 @@
         LOG(ERROR) << __func__ << ": non-positive buffer size " << in_bufferSizeFrames;
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
-    if (in_bufferSizeFrames < kMinimumStreamBufferSizeFrames) {
-        LOG(ERROR) << __func__ << ": insufficient buffer size " << in_bufferSizeFrames
-                   << ", must be at least " << kMinimumStreamBufferSizeFrames;
-        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
-    }
     auto& configs = getConfig().portConfigs;
     auto portConfigIt = findById<AudioPortConfig>(configs, in_portConfigId);
+    const int32_t nominalLatencyMs = getNominalLatencyMs(*portConfigIt);
     // Since this is a private method, it is assumed that
     // validity of the portConfigId has already been checked.
+    const int32_t minimumStreamBufferSizeFrames =
+            calculateBufferSizeFrames(nominalLatencyMs, portConfigIt->sampleRate.value().value);
+    if (in_bufferSizeFrames < minimumStreamBufferSizeFrames) {
+        LOG(ERROR) << __func__ << ": insufficient buffer size " << in_bufferSizeFrames
+                   << ", must be at least " << minimumStreamBufferSizeFrames;
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
     const size_t frameSize =
             getFrameSizeInBytes(portConfigIt->format.value(), portConfigIt->channelMask.value());
     if (frameSize == 0) {
@@ -189,14 +212,19 @@
         StreamContext::DebugParameters params{mDebug.streamTransientStateDelayMs,
                                               mVendorDebug.forceTransientBurst,
                                               mVendorDebug.forceSynchronousDrain};
+        std::shared_ptr<ISoundDose> soundDose;
+        if (!getSoundDose(&soundDose).isOk()) {
+            LOG(ERROR) << __func__ << ": could not create sound dose instance";
+            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+        }
         StreamContext temp(
                 std::make_unique<StreamContext::CommandMQ>(1, true /*configureEventFlagWord*/),
                 std::make_unique<StreamContext::ReplyMQ>(1, true /*configureEventFlagWord*/),
-                portConfigIt->portId, portConfigIt->format.value(),
-                portConfigIt->channelMask.value(), portConfigIt->sampleRate.value().value, flags,
+                portConfigIt->format.value(), portConfigIt->channelMask.value(),
+                portConfigIt->sampleRate.value().value, flags, nominalLatencyMs,
                 portConfigIt->ext.get<AudioPortExt::mix>().handle,
                 std::make_unique<StreamContext::DataMQ>(frameSize * in_bufferSizeFrames),
-                asyncCallback, outEventCallback, params);
+                asyncCallback, outEventCallback, mSoundDose.getInstance(), params);
         if (temp.isValid()) {
             *out_context = std::move(temp);
         } else {
@@ -279,6 +307,45 @@
     return ndk::ScopedAStatus::ok();
 }
 
+bool Module::generateDefaultPortConfig(const AudioPort& port, AudioPortConfig* config) {
+    const bool allowDynamicConfig = port.ext.getTag() == AudioPortExt::device;
+    for (const auto& profile : port.profiles) {
+        if (isDynamicProfile(profile)) continue;
+        config->format = profile.format;
+        config->channelMask = *profile.channelMasks.begin();
+        config->sampleRate = Int{.value = *profile.sampleRates.begin()};
+        config->flags = port.flags;
+        config->ext = port.ext;
+        return true;
+    }
+    if (allowDynamicConfig) {
+        config->format = AudioFormatDescription{};
+        config->channelMask = AudioChannelLayout{};
+        config->sampleRate = Int{.value = 0};
+        config->flags = port.flags;
+        config->ext = port.ext;
+        return true;
+    }
+    LOG(ERROR) << __func__ << ": port " << port.id << " only has dynamic profiles";
+    return false;
+}
+
+void Module::populateConnectedProfiles() {
+    Configuration& config = getConfig();
+    for (const AudioPort& port : config.ports) {
+        if (port.ext.getTag() == AudioPortExt::device) {
+            if (auto devicePort = port.ext.get<AudioPortExt::device>();
+                !devicePort.device.type.connection.empty() && port.profiles.empty()) {
+                if (auto connIt = config.connectedProfiles.find(port.id);
+                    connIt == config.connectedProfiles.end()) {
+                    config.connectedProfiles.emplace(
+                            port.id, internal::getStandard16And24BitPcmAudioProfiles());
+                }
+            }
+        }
+    }
+}
+
 template <typename C>
 std::set<int32_t> Module::portIdsFromPortConfigIds(C portConfigIds) {
     std::set<int32_t> result;
@@ -292,35 +359,53 @@
     return result;
 }
 
-std::unique_ptr<internal::Configuration> Module::initializeConfig() {
-    std::unique_ptr<internal::Configuration> config;
-    switch (getType()) {
-        case Type::DEFAULT:
-            config = std::move(internal::getPrimaryConfiguration());
-            break;
-        case Type::R_SUBMIX:
-            config = std::move(internal::getRSubmixConfiguration());
-            break;
-        case Type::STUB:
-            config = std::move(internal::getStubConfiguration());
-            break;
-        case Type::USB:
-            config = std::move(internal::getUsbConfiguration());
-            break;
-        case Type::BLUETOOTH:
-            config = std::move(internal::getBluetoothConfiguration());
-            break;
-    }
-    return config;
+std::unique_ptr<Module::Configuration> Module::initializeConfig() {
+    return internal::getConfiguration(getType());
 }
 
-internal::Configuration& Module::getConfig() {
+int32_t Module::getNominalLatencyMs(const AudioPortConfig&) {
+    // Arbitrary value. Implementations must override this method to provide their actual latency.
+    static constexpr int32_t kLatencyMs = 5;
+    return kLatencyMs;
+}
+
+std::vector<AudioRoute*> Module::getAudioRoutesForAudioPortImpl(int32_t portId) {
+    std::vector<AudioRoute*> result;
+    auto& routes = getConfig().routes;
+    for (auto& r : routes) {
+        const auto& srcs = r.sourcePortIds;
+        if (r.sinkPortId == portId || std::find(srcs.begin(), srcs.end(), portId) != srcs.end()) {
+            result.push_back(&r);
+        }
+    }
+    return result;
+}
+
+Module::Configuration& Module::getConfig() {
     if (!mConfig) {
         mConfig = std::move(initializeConfig());
     }
     return *mConfig;
 }
 
+std::set<int32_t> Module::getRoutableAudioPortIds(int32_t portId,
+                                                  std::vector<AudioRoute*>* routes) {
+    std::vector<AudioRoute*> routesStorage;
+    if (routes == nullptr) {
+        routesStorage = getAudioRoutesForAudioPortImpl(portId);
+        routes = &routesStorage;
+    }
+    std::set<int32_t> result;
+    for (AudioRoute* r : *routes) {
+        if (r->sinkPortId == portId) {
+            result.insert(r->sourcePortIds.begin(), r->sourcePortIds.end());
+        } else {
+            result.insert(r->sinkPortId);
+        }
+    }
+    return result;
+}
+
 void Module::registerPatch(const AudioPatch& patch) {
     auto& configs = getConfig().portConfigs;
     auto do_insert = [&](const std::vector<int32_t>& portConfigIds) {
@@ -340,21 +425,43 @@
 
 ndk::ScopedAStatus Module::updateStreamsConnectedState(const AudioPatch& oldPatch,
                                                        const AudioPatch& newPatch) {
-    // Streams from the old patch need to be disconnected, streams from the new
-    // patch need to be connected. If the stream belongs to both patches, no need
-    // to update it.
+    // Notify streams about the new set of devices they are connected to.
     auto maybeFailure = ndk::ScopedAStatus::ok();
-    std::set<int32_t> idsToDisconnect, idsToConnect, idsToDisconnectOnFailure;
-    idsToDisconnect.insert(oldPatch.sourcePortConfigIds.begin(),
-                           oldPatch.sourcePortConfigIds.end());
-    idsToDisconnect.insert(oldPatch.sinkPortConfigIds.begin(), oldPatch.sinkPortConfigIds.end());
-    idsToConnect.insert(newPatch.sourcePortConfigIds.begin(), newPatch.sourcePortConfigIds.end());
-    idsToConnect.insert(newPatch.sinkPortConfigIds.begin(), newPatch.sinkPortConfigIds.end());
-    std::for_each(idsToDisconnect.begin(), idsToDisconnect.end(), [&](const auto& portConfigId) {
-        if (idsToConnect.count(portConfigId) == 0 && mStreams.count(portConfigId) != 0) {
-            if (auto status = mStreams.setStreamConnectedDevices(portConfigId, {}); status.isOk()) {
+    using Connections =
+            std::map<int32_t /*mixPortConfigId*/, std::set<int32_t /*devicePortConfigId*/>>;
+    Connections oldConnections, newConnections;
+    auto fillConnectionsHelper = [&](Connections& connections,
+                                     const std::vector<int32_t>& mixPortCfgIds,
+                                     const std::vector<int32_t>& devicePortCfgIds) {
+        for (int32_t mixPortCfgId : mixPortCfgIds) {
+            connections[mixPortCfgId].insert(devicePortCfgIds.begin(), devicePortCfgIds.end());
+        }
+    };
+    auto fillConnections = [&](Connections& connections, const AudioPatch& patch) {
+        if (std::find_if(patch.sourcePortConfigIds.begin(), patch.sourcePortConfigIds.end(),
+                         [&](int32_t portConfigId) { return mStreams.count(portConfigId) > 0; }) !=
+            patch.sourcePortConfigIds.end()) {
+            // Sources are mix ports.
+            fillConnectionsHelper(connections, patch.sourcePortConfigIds, patch.sinkPortConfigIds);
+        } else if (std::find_if(patch.sinkPortConfigIds.begin(), patch.sinkPortConfigIds.end(),
+                                [&](int32_t portConfigId) {
+                                    return mStreams.count(portConfigId) > 0;
+                                }) != patch.sinkPortConfigIds.end()) {
+            // Sources are device ports.
+            fillConnectionsHelper(connections, patch.sinkPortConfigIds, patch.sourcePortConfigIds);
+        }  // Otherwise, there are no streams to notify.
+    };
+    fillConnections(oldConnections, oldPatch);
+    fillConnections(newConnections, newPatch);
+
+    std::for_each(oldConnections.begin(), oldConnections.end(), [&](const auto& connectionPair) {
+        const int32_t mixPortConfigId = connectionPair.first;
+        if (auto it = newConnections.find(mixPortConfigId);
+            it == newConnections.end() || it->second != connectionPair.second) {
+            if (auto status = mStreams.setStreamConnectedDevices(mixPortConfigId, {});
+                status.isOk()) {
                 LOG(DEBUG) << "updateStreamsConnectedState: The stream on port config id "
-                           << portConfigId << " has been disconnected";
+                           << mixPortConfigId << " has been disconnected";
             } else {
                 // Disconnection is tricky to roll back, just register a failure.
                 maybeFailure = std::move(status);
@@ -362,23 +469,26 @@
         }
     });
     if (!maybeFailure.isOk()) return maybeFailure;
-    std::for_each(idsToConnect.begin(), idsToConnect.end(), [&](const auto& portConfigId) {
-        if (idsToDisconnect.count(portConfigId) == 0 && mStreams.count(portConfigId) != 0) {
-            const auto connectedDevices = findConnectedDevices(portConfigId);
+    std::set<int32_t> idsToDisconnectOnFailure;
+    std::for_each(newConnections.begin(), newConnections.end(), [&](const auto& connectionPair) {
+        const int32_t mixPortConfigId = connectionPair.first;
+        if (auto it = oldConnections.find(mixPortConfigId);
+            it == oldConnections.end() || it->second != connectionPair.second) {
+            const auto connectedDevices = findConnectedDevices(mixPortConfigId);
             if (connectedDevices.empty()) {
                 // This is important as workers use the vector size to derive the connection status.
                 LOG(FATAL) << "updateStreamsConnectedState: No connected devices found for port "
                               "config id "
-                           << portConfigId;
+                           << mixPortConfigId;
             }
-            if (auto status = mStreams.setStreamConnectedDevices(portConfigId, connectedDevices);
+            if (auto status = mStreams.setStreamConnectedDevices(mixPortConfigId, connectedDevices);
                 status.isOk()) {
                 LOG(DEBUG) << "updateStreamsConnectedState: The stream on port config id "
-                           << portConfigId << " has been connected to: "
+                           << mixPortConfigId << " has been connected to: "
                            << ::android::internal::ToString(connectedDevices);
             } else {
                 maybeFailure = std::move(status);
-                idsToDisconnectOnFailure.insert(portConfigId);
+                idsToDisconnectOnFailure.insert(mixPortConfigId);
             }
         }
     });
@@ -485,74 +595,100 @@
         }
     }
 
-    if (connectedPort.profiles.empty()) {
-        if (!mDebug.simulateDeviceConnections) {
-            RETURN_STATUS_IF_ERROR(populateConnectedDevicePort(&connectedPort));
-        } else {
-            auto& connectedProfiles = getConfig().connectedProfiles;
-            if (auto connectedProfilesIt = connectedProfiles.find(templateId);
-                connectedProfilesIt != connectedProfiles.end()) {
-                connectedPort.profiles = connectedProfilesIt->second;
-            }
+    // Two main cases are considered with regard to the profiles of the connected device port:
+    //
+    //  1. If the template device port has dynamic profiles, and at least one routable mix
+    //     port also has dynamic profiles, it means that after connecting the device, the
+    //     connected device port must have profiles populated with actual capabilities of
+    //     the connected device, and dynamic of routable mix ports will be filled
+    //     according to these capabilities. An example of this case is connection of an
+    //     HDMI or USB device. For USB handled by ADSP, there can be mix ports with static
+    //     profiles, and one dedicated mix port for "hi-fi" playback. The latter is left with
+    //     dynamic profiles so that they can be populated with actual capabilities of
+    //     the connected device.
+    //
+    //  2. If the template device port has dynamic profiles, while all routable mix ports
+    //     have static profiles, it means that after connecting the device, the connected
+    //     device port can be left with dynamic profiles, and profiles of mix ports are
+    //     left untouched. An example of this case is connection of an analog wired
+    //     headset, it should be treated in the same way as a speaker.
+    //
+    //  Yet another possible case is when both the template device port and all routable
+    //  mix ports have static profiles. This is allowed and handled correctly, however, it
+    //  is not very practical, since these profiles are likely duplicates of each other.
+
+    std::vector<AudioRoute*> routesToMixPorts = getAudioRoutesForAudioPortImpl(templateId);
+    std::set<int32_t> routableMixPortIds = getRoutableAudioPortIds(templateId, &routesToMixPorts);
+    const int32_t nextPortId = getConfig().nextPortId++;
+    if (!mDebug.simulateDeviceConnections) {
+        // Even if the device port has static profiles, the HAL module might need to update
+        // them, or abort the connection process.
+        RETURN_STATUS_IF_ERROR(populateConnectedDevicePort(&connectedPort, nextPortId));
+    } else if (hasDynamicProfilesOnly(connectedPort.profiles)) {
+        auto& connectedProfiles = getConfig().connectedProfiles;
+        if (auto connectedProfilesIt = connectedProfiles.find(templateId);
+            connectedProfilesIt != connectedProfiles.end()) {
+            connectedPort.profiles = connectedProfilesIt->second;
         }
-        if (connectedPort.profiles.empty()) {
-            LOG(ERROR) << __func__
-                       << ": profiles of a connected port still empty after connecting external "
-                          "device "
-                       << connectedPort.toString();
+    }
+    if (hasDynamicProfilesOnly(connectedPort.profiles)) {
+        // Possible case 2. Check if all routable mix ports have static profiles.
+        if (auto dynamicMixPortIt = std::find_if(ports.begin(), ports.end(),
+                                                 [&routableMixPortIds](const auto& p) {
+                                                     return routableMixPortIds.count(p.id) > 0 &&
+                                                            hasDynamicProfilesOnly(p.profiles);
+                                                 });
+            dynamicMixPortIt != ports.end()) {
+            LOG(ERROR) << __func__ << ": connected port only has dynamic profiles after connecting "
+                       << "external device " << connectedPort.toString() << ", and there exist "
+                       << "a routable mix port with dynamic profiles: "
+                       << dynamicMixPortIt->toString();
             return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
         }
     }
 
-    for (auto profile : connectedPort.profiles) {
-        if (profile.channelMasks.empty()) {
-            LOG(ERROR) << __func__ << ": the profile " << profile.name << " has no channel masks";
-            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
-        }
-        if (profile.sampleRates.empty()) {
-            LOG(ERROR) << __func__ << ": the profile " << profile.name << " has no sample rates";
-            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
-        }
-    }
-
-    connectedPort.id = ++getConfig().nextPortId;
+    connectedPort.id = nextPortId;
     auto [connectedPortsIt, _] =
-            mConnectedDevicePorts.insert(std::pair(connectedPort.id, std::vector<int32_t>()));
+            mConnectedDevicePorts.insert(std::pair(connectedPort.id, std::set<int32_t>()));
     LOG(DEBUG) << __func__ << ": template port " << templateId << " external device connected, "
                << "connected port ID " << connectedPort.id;
     ports.push_back(connectedPort);
     onExternalDeviceConnectionChanged(connectedPort, true /*connected*/);
 
-    std::vector<int32_t> routablePortIds;
+    // For routes where the template port is a source, add the connected port to sources,
+    // otherwise, create a new route by copying from the route for the template port.
     std::vector<AudioRoute> newRoutes;
-    auto& routes = getConfig().routes;
-    for (auto& r : routes) {
-        if (r.sinkPortId == templateId) {
-            AudioRoute newRoute;
-            newRoute.sourcePortIds = r.sourcePortIds;
-            newRoute.sinkPortId = connectedPort.id;
-            newRoute.isExclusive = r.isExclusive;
-            newRoutes.push_back(std::move(newRoute));
-            routablePortIds.insert(routablePortIds.end(), r.sourcePortIds.begin(),
-                                   r.sourcePortIds.end());
+    for (AudioRoute* r : routesToMixPorts) {
+        if (r->sinkPortId == templateId) {
+            newRoutes.push_back(AudioRoute{.sourcePortIds = r->sourcePortIds,
+                                           .sinkPortId = connectedPort.id,
+                                           .isExclusive = r->isExclusive});
         } else {
-            auto& srcs = r.sourcePortIds;
-            if (std::find(srcs.begin(), srcs.end(), templateId) != srcs.end()) {
-                srcs.push_back(connectedPort.id);
-                routablePortIds.push_back(r.sinkPortId);
-            }
+            r->sourcePortIds.push_back(connectedPort.id);
         }
     }
+    auto& routes = getConfig().routes;
     routes.insert(routes.end(), newRoutes.begin(), newRoutes.end());
 
-    // Note: this is a simplistic approach assuming that a mix port can only be populated
-    // from a single device port. Implementing support for stuffing dynamic profiles with a superset
-    // of all profiles from all routable dynamic device ports would be more involved.
-    for (const auto mixPortId : routablePortIds) {
-        auto portsIt = findById<AudioPort>(ports, mixPortId);
-        if (portsIt != ports.end() && portsIt->profiles.empty()) {
-            portsIt->profiles = connectedPort.profiles;
-            connectedPortsIt->second.push_back(portsIt->id);
+    if (!hasDynamicProfilesOnly(connectedPort.profiles) && !routableMixPortIds.empty()) {
+        // Note: this is a simplistic approach assuming that a mix port can only be populated
+        // from a single device port. Implementing support for stuffing dynamic profiles with
+        // a superset of all profiles from all routable dynamic device ports would be more involved.
+        for (auto& port : ports) {
+            if (routableMixPortIds.count(port.id) == 0) continue;
+            if (hasDynamicProfilesOnly(port.profiles)) {
+                port.profiles = connectedPort.profiles;
+                connectedPortsIt->second.insert(port.id);
+            } else {
+                // Check if profiles are not all dynamic because they were populated by
+                // a previous connection. Otherwise, it means that they are actually static.
+                for (const auto& cp : mConnectedDevicePorts) {
+                    if (cp.second.count(port.id) > 0) {
+                        connectedPortsIt->second.insert(port.id);
+                        break;
+                    }
+                }
+            }
         }
     }
     *_aidl_return = std::move(connectedPort);
@@ -607,13 +743,42 @@
         }
     }
 
-    for (const auto mixPortId : connectedPortsIt->second) {
+    // Clear profiles for mix ports that are not connected to any other ports.
+    std::set<int32_t> mixPortsToClear = std::move(connectedPortsIt->second);
+    mConnectedDevicePorts.erase(connectedPortsIt);
+    for (const auto& connectedPort : mConnectedDevicePorts) {
+        for (int32_t mixPortId : connectedPort.second) {
+            mixPortsToClear.erase(mixPortId);
+        }
+    }
+    for (int32_t mixPortId : mixPortsToClear) {
         auto mixPortIt = findById<AudioPort>(ports, mixPortId);
         if (mixPortIt != ports.end()) {
             mixPortIt->profiles = {};
         }
     }
-    mConnectedDevicePorts.erase(connectedPortsIt);
+
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::prepareToDisconnectExternalDevice(int32_t in_portId) {
+    auto& ports = getConfig().ports;
+    auto portIt = findById<AudioPort>(ports, in_portId);
+    if (portIt == ports.end()) {
+        LOG(ERROR) << __func__ << ": port id " << in_portId << " not found";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+    if (portIt->ext.getTag() != AudioPortExt::Tag::device) {
+        LOG(ERROR) << __func__ << ": port id " << in_portId << " is not a device port";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+    auto connectedPortsIt = mConnectedDevicePorts.find(in_portId);
+    if (connectedPortsIt == mConnectedDevicePorts.end()) {
+        LOG(ERROR) << __func__ << ": port id " << in_portId << " is not a connected device port";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+
+    onPrepareToDisconnectExternalDevice(*portIt);
 
     return ndk::ScopedAStatus::ok();
 }
@@ -661,13 +826,9 @@
         LOG(ERROR) << __func__ << ": port id " << in_portId << " not found";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
-    auto& routes = getConfig().routes;
-    std::copy_if(routes.begin(), routes.end(), std::back_inserter(*_aidl_return),
-                 [&](const auto& r) {
-                     const auto& srcs = r.sourcePortIds;
-                     return r.sinkPortId == in_portId ||
-                            std::find(srcs.begin(), srcs.end(), in_portId) != srcs.end();
-                 });
+    std::vector<AudioRoute*> routes = getAudioRoutesForAudioPortImpl(in_portId);
+    std::transform(routes.begin(), routes.end(), std::back_inserter(*_aidl_return),
+                   [](auto rptr) { return *rptr; });
     return ndk::ScopedAStatus::ok();
 }
 
@@ -688,7 +849,7 @@
     context.fillDescriptor(&_aidl_return->desc);
     std::shared_ptr<StreamIn> stream;
     RETURN_STATUS_IF_ERROR(createInputStream(std::move(context), in_args.sinkMetadata,
-                                             mConfig->microphones, &stream));
+                                             getMicrophoneInfos(), &stream));
     StreamWrapper streamWrapper(stream);
     if (auto patchIt = mPatches.find(in_args.portConfigId); patchIt != mPatches.end()) {
         RETURN_STATUS_IF_ERROR(
@@ -835,17 +996,28 @@
             return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
         }
     }
+    // Find the highest sample rate among mix port configs.
+    std::map<int32_t, AudioPortConfig*> sampleRates;
+    std::vector<AudioPortConfig*>& mixPortConfigs =
+            sources[0]->ext.getTag() == AudioPortExt::mix ? sources : sinks;
+    for (auto mix : mixPortConfigs) {
+        sampleRates.emplace(mix->sampleRate.value().value, mix);
+    }
     *_aidl_return = in_requested;
-    _aidl_return->minimumStreamBufferSizeFrames = kMinimumStreamBufferSizeFrames;
+    auto maxSampleRateIt = std::max_element(sampleRates.begin(), sampleRates.end());
+    const int32_t latencyMs = getNominalLatencyMs(*(maxSampleRateIt->second));
+    _aidl_return->minimumStreamBufferSizeFrames =
+            calculateBufferSizeFrames(latencyMs, maxSampleRateIt->first);
     _aidl_return->latenciesMs.clear();
     _aidl_return->latenciesMs.insert(_aidl_return->latenciesMs.end(),
-                                     _aidl_return->sinkPortConfigIds.size(), kLatencyMs);
+                                     _aidl_return->sinkPortConfigIds.size(), latencyMs);
     AudioPatch oldPatch{};
     if (existing == patches.end()) {
         _aidl_return->id = getConfig().nextPatchId++;
         patches.push_back(*_aidl_return);
     } else {
         oldPatch = *existing;
+        *existing = *_aidl_return;
     }
     patchesBackup = mPatches;
     registerPatch(*_aidl_return);
@@ -866,6 +1038,18 @@
 
 ndk::ScopedAStatus Module::setAudioPortConfig(const AudioPortConfig& in_requested,
                                               AudioPortConfig* out_suggested, bool* _aidl_return) {
+    auto generate = [this](const AudioPort& port, AudioPortConfig* config) {
+        return generateDefaultPortConfig(port, config);
+    };
+    return setAudioPortConfigImpl(in_requested, generate, out_suggested, _aidl_return);
+}
+
+ndk::ScopedAStatus Module::setAudioPortConfigImpl(
+        const AudioPortConfig& in_requested,
+        const std::function<bool(const ::aidl::android::media::audio::common::AudioPort& port,
+                                 ::aidl::android::media::audio::common::AudioPortConfig* config)>&
+                fillPortConfig,
+        AudioPortConfig* out_suggested, bool* applied) {
     LOG(DEBUG) << __func__ << ": requested " << in_requested.toString();
     auto& configs = getConfig().portConfigs;
     auto existing = configs.end();
@@ -880,20 +1064,22 @@
 
     const int portId = existing != configs.end() ? existing->portId : in_requested.portId;
     if (portId == 0) {
-        LOG(ERROR) << __func__ << ": input port config does not specify portId";
+        LOG(ERROR) << __func__ << ": requested port config does not specify portId";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
     auto& ports = getConfig().ports;
     auto portIt = findById<AudioPort>(ports, portId);
     if (portIt == ports.end()) {
-        LOG(ERROR) << __func__ << ": input port config points to non-existent portId " << portId;
+        LOG(ERROR) << __func__ << ": requested port config points to non-existent portId "
+                   << portId;
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
     if (existing != configs.end()) {
         *out_suggested = *existing;
     } else {
         AudioPortConfig newConfig;
-        if (generateDefaultPortConfig(*portIt, &newConfig)) {
+        newConfig.portId = portIt->id;
+        if (fillPortConfig(*portIt, &newConfig)) {
             *out_suggested = newConfig;
         } else {
             LOG(ERROR) << __func__ << ": unable generate a default config for port " << portId;
@@ -904,6 +1090,10 @@
     // or a new generated config. Now attempt to update it according to the specified
     // fields of 'in_requested'.
 
+    // Device ports with only dynamic profiles are used for devices that are connected via ADSP,
+    // which takes care of their actual configuration automatically.
+    const bool allowDynamicConfig = portIt->ext.getTag() == AudioPortExt::device &&
+                                    hasDynamicProfilesOnly(portIt->profiles);
     bool requestedIsValid = true, requestedIsFullySpecified = true;
 
     AudioIoFlags portFlags = portIt->flags;
@@ -921,17 +1111,19 @@
     AudioProfile portProfile;
     if (in_requested.format.has_value()) {
         const auto& format = in_requested.format.value();
-        if (findAudioProfile(*portIt, format, &portProfile)) {
+        if ((format == AudioFormatDescription{} && allowDynamicConfig) ||
+            findAudioProfile(*portIt, format, &portProfile)) {
             out_suggested->format = format;
         } else {
             LOG(WARNING) << __func__ << ": requested format " << format.toString()
-                         << " is not found in port's " << portId << " profiles";
+                         << " is not found in the profiles of port " << portId;
             requestedIsValid = false;
         }
     } else {
         requestedIsFullySpecified = false;
     }
-    if (!findAudioProfile(*portIt, out_suggested->format.value(), &portProfile)) {
+    if (!(out_suggested->format.value() == AudioFormatDescription{} && allowDynamicConfig) &&
+        !findAudioProfile(*portIt, out_suggested->format.value(), &portProfile)) {
         LOG(ERROR) << __func__ << ": port " << portId << " does not support format "
                    << out_suggested->format.value().toString() << " anymore";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
@@ -939,8 +1131,9 @@
 
     if (in_requested.channelMask.has_value()) {
         const auto& channelMask = in_requested.channelMask.value();
-        if (find(portProfile.channelMasks.begin(), portProfile.channelMasks.end(), channelMask) !=
-            portProfile.channelMasks.end()) {
+        if ((channelMask == AudioChannelLayout{} && allowDynamicConfig) ||
+            find(portProfile.channelMasks.begin(), portProfile.channelMasks.end(), channelMask) !=
+                    portProfile.channelMasks.end()) {
             out_suggested->channelMask = channelMask;
         } else {
             LOG(WARNING) << __func__ << ": requested channel mask " << channelMask.toString()
@@ -954,7 +1147,8 @@
 
     if (in_requested.sampleRate.has_value()) {
         const auto& sampleRate = in_requested.sampleRate.value();
-        if (find(portProfile.sampleRates.begin(), portProfile.sampleRates.end(),
+        if ((sampleRate.value == 0 && allowDynamicConfig) ||
+            find(portProfile.sampleRates.begin(), portProfile.sampleRates.end(),
                  sampleRate.value) != portProfile.sampleRates.end()) {
             out_suggested->sampleRate = sampleRate;
         } else {
@@ -990,17 +1184,17 @@
     if (existing == configs.end() && requestedIsValid && requestedIsFullySpecified) {
         out_suggested->id = getConfig().nextPortId++;
         configs.push_back(*out_suggested);
-        *_aidl_return = true;
+        *applied = true;
         LOG(DEBUG) << __func__ << ": created new port config " << out_suggested->toString();
     } else if (existing != configs.end() && requestedIsValid) {
         *existing = *out_suggested;
-        *_aidl_return = true;
+        *applied = true;
         LOG(DEBUG) << __func__ << ": updated port config " << out_suggested->toString();
     } else {
         LOG(DEBUG) << __func__ << ": not applied; existing config ? " << (existing != configs.end())
                    << "; requested is valid? " << requestedIsValid << ", fully specified? "
                    << requestedIsFullySpecified;
-        *_aidl_return = false;
+        *applied = false;
     }
     return ndk::ScopedAStatus::ok();
 }
@@ -1071,7 +1265,7 @@
         // Reset master mute if it failed.
         onMasterMuteChanged(mMasterMute);
     }
-    return std::move(result);
+    return result;
 }
 
 ndk::ScopedAStatus Module::getMasterVolume(float* _aidl_return) {
@@ -1093,7 +1287,7 @@
                        << "), error=" << result;
             onMasterVolumeChanged(mMasterVolume);
         }
-        return std::move(result);
+        return result;
     }
     LOG(ERROR) << __func__ << ": invalid master volume value: " << in_volume;
     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
@@ -1112,7 +1306,7 @@
 }
 
 ndk::ScopedAStatus Module::getMicrophones(std::vector<MicrophoneInfo>* _aidl_return) {
-    *_aidl_return = getConfig().microphones;
+    *_aidl_return = getMicrophoneInfos();
     LOG(DEBUG) << __func__ << ": returning " << ::android::internal::ToString(*_aidl_return);
     return ndk::ScopedAStatus::ok();
 }
@@ -1258,6 +1452,12 @@
             mmapSources.insert(port.id);
         }
     }
+    if (mmapSources.empty() && mmapSinks.empty()) {
+        AudioMMapPolicyInfo never;
+        never.mmapPolicy = AudioMMapPolicy::NEVER;
+        _aidl_return->push_back(never);
+        return ndk::ScopedAStatus::ok();
+    }
     for (const auto& route : getConfig().routes) {
         if (mmapSinks.count(route.sinkPortId) != 0) {
             // The sink is a mix port, add the sources if they are device ports.
@@ -1346,7 +1546,18 @@
     return mIsMmapSupported.value();
 }
 
-ndk::ScopedAStatus Module::populateConnectedDevicePort(AudioPort* audioPort __unused) {
+ndk::ScopedAStatus Module::populateConnectedDevicePort(AudioPort* audioPort, int32_t) {
+    if (audioPort->ext.getTag() != AudioPortExt::device) {
+        LOG(ERROR) << __func__ << ": not a device port: " << audioPort->toString();
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+    const auto& devicePort = audioPort->ext.get<AudioPortExt::device>();
+    if (!devicePort.device.type.connection.empty()) {
+        LOG(ERROR) << __func__
+                   << ": module implementation must override 'populateConnectedDevicePort' "
+                   << "to handle connection of external devices.";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
     LOG(VERBOSE) << __func__ << ": do nothing and return ok";
     return ndk::ScopedAStatus::ok();
 }
@@ -1364,6 +1575,11 @@
     LOG(DEBUG) << __func__ << ": do nothing and return";
 }
 
+void Module::onPrepareToDisconnectExternalDevice(
+        const ::aidl::android::media::audio::common::AudioPort& audioPort __unused) {
+    LOG(DEBUG) << __func__ << ": do nothing and return";
+}
+
 ndk::ScopedAStatus Module::onMasterMuteChanged(bool mute __unused) {
     LOG(VERBOSE) << __func__ << ": do nothing and return ok";
     return ndk::ScopedAStatus::ok();
@@ -1374,9 +1590,27 @@
     return ndk::ScopedAStatus::ok();
 }
 
-Module::BtProfileHandles Module::getBtProfileManagerHandles() {
-    return std::make_tuple(std::weak_ptr<IBluetooth>(), std::weak_ptr<IBluetoothA2dp>(),
-                           std::weak_ptr<IBluetoothLe>());
+std::vector<MicrophoneInfo> Module::getMicrophoneInfos() {
+    std::vector<MicrophoneInfo> result;
+    Configuration& config = getConfig();
+    for (const AudioPort& port : config.ports) {
+        if (port.ext.getTag() == AudioPortExt::Tag::device) {
+            const AudioDeviceType deviceType =
+                    port.ext.get<AudioPortExt::Tag::device>().device.type.type;
+            if (deviceType == AudioDeviceType::IN_MICROPHONE ||
+                deviceType == AudioDeviceType::IN_MICROPHONE_BACK) {
+                // Placeholder values. Vendor implementations must populate MicrophoneInfo
+                // accordingly based on their physical microphone parameters.
+                result.push_back(MicrophoneInfo{
+                        .id = port.name,
+                        .device = port.ext.get<AudioPortExt::Tag::device>().device,
+                        .group = 0,
+                        .indexInTheGroup = 0,
+                });
+            }
+        }
+    }
+    return result;
 }
 
 ndk::ScopedAStatus Module::bluetoothParametersUpdated() {
diff --git a/audio/aidl/default/ModulePrimary.cpp b/audio/aidl/default/ModulePrimary.cpp
index 9919c7f..3da6d48 100644
--- a/audio/aidl/default/ModulePrimary.cpp
+++ b/audio/aidl/default/ModulePrimary.cpp
@@ -58,4 +58,12 @@
                                                   offloadInfo);
 }
 
+int32_t ModulePrimary::getNominalLatencyMs(const AudioPortConfig&) {
+    // 85 ms is chosen considering 4096 frames @ 48 kHz. This is the value which allows
+    // the virtual Android device implementation to pass CTS. Hardware implementations
+    // should have significantly lower latency.
+    static constexpr int32_t kLatencyMs = 85;
+    return kLatencyMs;
+}
+
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/SoundDose.cpp b/audio/aidl/default/SoundDose.cpp
index f12ce5d..6c3a067 100644
--- a/audio/aidl/default/SoundDose.cpp
+++ b/audio/aidl/default/SoundDose.cpp
@@ -18,7 +18,15 @@
 
 #include "core-impl/SoundDose.h"
 
+#include <aidl/android/hardware/audio/core/sounddose/ISoundDose.h>
 #include <android-base/logging.h>
+#include <media/AidlConversionCppNdk.h>
+#include <utils/Timers.h>
+
+using aidl::android::hardware::audio::core::sounddose::ISoundDose;
+using aidl::android::media::audio::common::AudioDevice;
+using aidl::android::media::audio::common::AudioDeviceDescription;
+using aidl::android::media::audio::common::AudioFormatDescription;
 
 namespace aidl::android::hardware::audio::core::sounddose {
 
@@ -28,11 +36,16 @@
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
 
+    ::android::audio_utils::lock_guard l(mMutex);
     mRs2Value = in_rs2ValueDbA;
+    if (mMelProcessor != nullptr) {
+        mMelProcessor->setOutputRs2UpperBound(in_rs2ValueDbA);
+    }
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus SoundDose::getOutputRs2UpperBound(float* _aidl_return) {
+    ::android::audio_utils::lock_guard l(mMutex);
     *_aidl_return = mRs2Value;
     LOG(DEBUG) << __func__ << ": returning " << *_aidl_return;
     return ndk::ScopedAStatus::ok();
@@ -44,6 +57,8 @@
         LOG(ERROR) << __func__ << ": Callback is nullptr";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
+
+    ::android::audio_utils::lock_guard l(mCbMutex);
     if (mCallback != nullptr) {
         LOG(ERROR) << __func__ << ": Sound dose callback was already registered";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
@@ -51,7 +66,82 @@
 
     mCallback = in_callback;
     LOG(DEBUG) << __func__ << ": Registered sound dose callback ";
+
     return ndk::ScopedAStatus::ok();
 }
 
+void SoundDose::setAudioDevice(const AudioDevice& audioDevice) {
+    ::android::audio_utils::lock_guard l(mCbMutex);
+    mAudioDevice = audioDevice;
+}
+
+void SoundDose::startDataProcessor(uint32_t sampleRate, uint32_t channelCount,
+                                   const AudioFormatDescription& aidlFormat) {
+    ::android::audio_utils::lock_guard l(mMutex);
+    const auto result = aidl2legacy_AudioFormatDescription_audio_format_t(aidlFormat);
+    const audio_format_t format = result.value_or(AUDIO_FORMAT_INVALID);
+
+    if (mMelProcessor == nullptr) {
+        // we don't have the deviceId concept on the vendor side so just pass 0
+        mMelProcessor = ::android::sp<::android::audio_utils::MelProcessor>::make(
+                sampleRate, channelCount, format, mMelCallback, /*deviceId=*/0, mRs2Value);
+    } else {
+        mMelProcessor->updateAudioFormat(sampleRate, channelCount, format);
+    }
+}
+
+void SoundDose::process(const void* buffer, size_t bytes) {
+    ::android::audio_utils::lock_guard l(mMutex);
+    if (mMelProcessor != nullptr) {
+        mMelProcessor->process(buffer, bytes);
+    }
+}
+
+void SoundDose::onNewMelValues(const std::vector<float>& mels, size_t offset, size_t length,
+                               audio_port_handle_t deviceId __attribute__((__unused__))) const {
+    ::android::audio_utils::lock_guard l(mCbMutex);
+    if (!mAudioDevice.has_value()) {
+        LOG(WARNING) << __func__ << ": New mel values without a registered device";
+        return;
+    }
+    if (mCallback == nullptr) {
+        LOG(ERROR) << __func__ << ": New mel values without a registered callback";
+        return;
+    }
+
+    ISoundDose::IHalSoundDoseCallback::MelRecord melRecord;
+    melRecord.timestamp = nanoseconds_to_seconds(systemTime());
+    melRecord.melValues = std::vector<float>(mels.begin() + offset, mels.begin() + offset + length);
+
+    mCallback->onNewMelValues(melRecord, mAudioDevice.value());
+}
+
+void SoundDose::MelCallback::onNewMelValues(const std::vector<float>& mels, size_t offset,
+                                            size_t length,
+                                            audio_port_handle_t deviceId
+                                            __attribute__((__unused__)),
+                                            bool attenuated __attribute__((__unused__))) const {
+    mSoundDose.onNewMelValues(mels, offset, length, deviceId);
+}
+
+void SoundDose::onMomentaryExposure(float currentMel, audio_port_handle_t deviceId
+                                    __attribute__((__unused__))) const {
+    ::android::audio_utils::lock_guard l(mCbMutex);
+    if (!mAudioDevice.has_value()) {
+        LOG(WARNING) << __func__ << ": Momentary exposure without a registered device";
+        return;
+    }
+    if (mCallback == nullptr) {
+        LOG(ERROR) << __func__ << ": Momentary exposure without a registered callback";
+        return;
+    }
+
+    mCallback->onMomentaryExposureWarning(currentMel, mAudioDevice.value());
+}
+
+void SoundDose::MelCallback::onMomentaryExposure(float currentMel, audio_port_handle_t deviceId
+                                                 __attribute__((__unused__))) const {
+    mSoundDose.onMomentaryExposure(currentMel, deviceId);
+}
+
 }  // namespace aidl::android::hardware::audio::core::sounddose
diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp
index f7298c0..cf0870e 100644
--- a/audio/aidl/default/Stream.cpp
+++ b/audio/aidl/default/Stream.cpp
@@ -90,6 +90,14 @@
     return true;
 }
 
+void StreamContext::startStreamDataProcessor() {
+    auto streamDataProcessor = mStreamDataProcessor.lock();
+    if (streamDataProcessor != nullptr) {
+        streamDataProcessor->startDataProcessor(mSampleRate, getChannelCount(mChannelLayout),
+                                                mFormat);
+    }
+}
+
 void StreamContext::reset() {
     mCommandMQ.reset();
     mReplyMQ.reset();
@@ -130,7 +138,7 @@
     reply->status = STATUS_OK;
     if (isConnected) {
         reply->observable.frames = mContext->getFrameCount();
-        reply->observable.timeNs = ::android::elapsedRealtimeNano();
+        reply->observable.timeNs = ::android::uptimeNanos();
         if (auto status = mDriver->refinePosition(&reply->observable); status == ::android::OK) {
             return;
         }
@@ -172,17 +180,20 @@
     StreamDescriptor::Reply reply{};
     reply.status = STATUS_BAD_VALUE;
     switch (command.getTag()) {
-        case Tag::halReservedExit:
-            if (const int32_t cookie = command.get<Tag::halReservedExit>();
-                cookie == (mContext->getInternalCommandCookie() ^ getTid())) {
+        case Tag::halReservedExit: {
+            const int32_t cookie = command.get<Tag::halReservedExit>();
+            if (cookie == (mContext->getInternalCommandCookie() ^ getTid())) {
                 mDriver->shutdown();
                 setClosed();
-                // This is an internal command, no need to reply.
-                return Status::EXIT;
             } else {
                 LOG(WARNING) << __func__ << ": EXIT command has a bad cookie: " << cookie;
             }
-            break;
+            if (cookie != 0) {  // This is an internal command, no need to reply.
+                return Status::EXIT;
+            } else {
+                break;
+            }
+        }
         case Tag::getStatus:
             populateReply(&reply, mIsConnected);
             break;
@@ -307,7 +318,7 @@
     const size_t frameSize = mContext->getFrameSize();
     size_t actualFrameCount = 0;
     bool fatal = false;
-    int32_t latency = Module::kLatencyMs;
+    int32_t latency = mContext->getNominalLatencyMs();
     if (isConnected) {
         if (::android::status_t status = mDriver->transfer(mDataBuffer.get(), byteCount / frameSize,
                                                            &actualFrameCount, &latency);
@@ -392,17 +403,20 @@
     reply.status = STATUS_BAD_VALUE;
     using Tag = StreamDescriptor::Command::Tag;
     switch (command.getTag()) {
-        case Tag::halReservedExit:
-            if (const int32_t cookie = command.get<Tag::halReservedExit>();
-                cookie == (mContext->getInternalCommandCookie() ^ getTid())) {
+        case Tag::halReservedExit: {
+            const int32_t cookie = command.get<Tag::halReservedExit>();
+            if (cookie == (mContext->getInternalCommandCookie() ^ getTid())) {
                 mDriver->shutdown();
                 setClosed();
-                // This is an internal command, no need to reply.
-                return Status::EXIT;
             } else {
                 LOG(WARNING) << __func__ << ": EXIT command has a bad cookie: " << cookie;
             }
-            break;
+            if (cookie != 0) {  // This is an internal command, no need to reply.
+                return Status::EXIT;
+            } else {
+                break;
+            }
+        }
         case Tag::getStatus:
             populateReply(&reply, mIsConnected);
             break;
@@ -573,8 +587,8 @@
     const size_t readByteCount = dataMQ->availableToRead();
     const size_t frameSize = mContext->getFrameSize();
     bool fatal = false;
-    int32_t latency = Module::kLatencyMs;
-    if (bool success = readByteCount > 0 ? dataMQ->read(&mDataBuffer[0], readByteCount) : true) {
+    int32_t latency = mContext->getNominalLatencyMs();
+    if (readByteCount > 0 ? dataMQ->read(&mDataBuffer[0], readByteCount) : true) {
         const bool isConnected = mIsConnected;
         LOG(VERBOSE) << __func__ << ": reading of " << readByteCount << " bytes from data MQ"
                      << " succeeded; connected? " << isConnected;
@@ -593,6 +607,10 @@
                 fatal = true;
                 LOG(ERROR) << __func__ << ": write failed: " << status;
             }
+            auto streamDataProcessor = mContext->getStreamDataProcessor().lock();
+            if (streamDataProcessor != nullptr) {
+                streamDataProcessor->process(mDataBuffer.get(), actualFrameCount * frameSize);
+            }
         } else {
             if (mContext->getAsyncCallback() == nullptr) {
                 usleep(3000);  // Simulate blocking transfer delay.
@@ -836,7 +854,7 @@
 }
 
 StreamInHwGainHelper::StreamInHwGainHelper(const StreamContext* context)
-    : mChannelCount(getChannelCount(context->getChannelLayout())) {}
+    : mChannelCount(getChannelCount(context->getChannelLayout())), mHwGains(mChannelCount, 0.0f) {}
 
 ndk::ScopedAStatus StreamInHwGainHelper::getHwGainImpl(std::vector<float>* _aidl_return) {
     *_aidl_return = mHwGains;
@@ -967,7 +985,8 @@
 }
 
 StreamOutHwVolumeHelper::StreamOutHwVolumeHelper(const StreamContext* context)
-    : mChannelCount(getChannelCount(context->getChannelLayout())) {}
+    : mChannelCount(getChannelCount(context->getChannelLayout())),
+      mHwVolumes(mChannelCount, 0.0f) {}
 
 ndk::ScopedAStatus StreamOutHwVolumeHelper::getHwVolumeImpl(std::vector<float>* _aidl_return) {
     *_aidl_return = mHwVolumes;
diff --git a/audio/aidl/default/Telephony.cpp b/audio/aidl/default/Telephony.cpp
index bf05a8d..d9da39f 100644
--- a/audio/aidl/default/Telephony.cpp
+++ b/audio/aidl/default/Telephony.cpp
@@ -16,9 +16,9 @@
 
 #define LOG_TAG "AHAL_Telephony"
 #include <android-base/logging.h>
+#include <android/binder_to_string.h>
 
 #include <Utils.h>
-#include <android/binder_to_string.h>
 
 #include "core-impl/Telephony.h"
 
diff --git a/audio/aidl/default/XsdcConversion.cpp b/audio/aidl/default/XsdcConversion.cpp
new file mode 100644
index 0000000..1720949
--- /dev/null
+++ b/audio/aidl/default/XsdcConversion.cpp
@@ -0,0 +1,452 @@
+#include <inttypes.h>
+
+#include <unordered_set>
+
+#define LOG_TAG "AHAL_Config"
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+
+#include <aidl/android/media/audio/common/AudioPort.h>
+#include <aidl/android/media/audio/common/AudioPortConfig.h>
+#include <media/AidlConversionCppNdk.h>
+#include <media/TypeConverter.h>
+
+#include "core-impl/XmlConverter.h"
+#include "core-impl/XsdcConversion.h"
+
+using aidl::android::media::audio::common::AudioChannelLayout;
+using aidl::android::media::audio::common::AudioDevice;
+using aidl::android::media::audio::common::AudioDeviceAddress;
+using aidl::android::media::audio::common::AudioDeviceDescription;
+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::AudioGain;
+using aidl::android::media::audio::common::AudioHalCapCriterion;
+using aidl::android::media::audio::common::AudioHalCapCriterionType;
+using aidl::android::media::audio::common::AudioHalVolumeCurve;
+using aidl::android::media::audio::common::AudioIoFlags;
+using aidl::android::media::audio::common::AudioPort;
+using aidl::android::media::audio::common::AudioPortConfig;
+using aidl::android::media::audio::common::AudioPortDeviceExt;
+using aidl::android::media::audio::common::AudioPortExt;
+using aidl::android::media::audio::common::AudioPortMixExt;
+using aidl::android::media::audio::common::AudioProfile;
+using ::android::BAD_VALUE;
+using ::android::base::unexpected;
+
+namespace ap_xsd = android::audio::policy::configuration;
+namespace eng_xsd = android::audio::policy::engine::configuration;
+
+namespace aidl::android::hardware::audio::core::internal {
+
+inline ConversionResult<std::string> assertNonEmpty(const std::string& s) {
+    if (s.empty()) {
+        LOG(ERROR) << __func__ << " Review Audio Policy config: "
+                   << " empty string is not valid.";
+        return unexpected(BAD_VALUE);
+    }
+    return s;
+}
+
+#define NON_EMPTY_STRING_OR_FATAL(s) VALUE_OR_FATAL(assertNonEmpty(s))
+
+ConversionResult<AudioFormatDescription> convertAudioFormatToAidl(const std::string& xsdcFormat) {
+    audio_format_t legacyFormat = ::android::formatFromString(xsdcFormat, AUDIO_FORMAT_DEFAULT);
+    ConversionResult<AudioFormatDescription> result =
+            legacy2aidl_audio_format_t_AudioFormatDescription(legacyFormat);
+    if ((legacyFormat == AUDIO_FORMAT_DEFAULT && xsdcFormat.compare("AUDIO_FORMAT_DEFAULT") != 0) ||
+        !result.ok()) {
+        LOG(ERROR) << __func__ << " Review Audio Policy config: " << xsdcFormat
+                   << " is not a valid audio format.";
+        return unexpected(BAD_VALUE);
+    }
+    return result;
+}
+
+std::unordered_set<std::string> getAttachedDevices(const ap_xsd::Modules::Module& moduleConfig) {
+    std::unordered_set<std::string> attachedDeviceSet;
+    if (moduleConfig.hasAttachedDevices()) {
+        for (const ap_xsd::AttachedDevices& attachedDevices : moduleConfig.getAttachedDevices()) {
+            if (attachedDevices.hasItem()) {
+                attachedDeviceSet.insert(attachedDevices.getItem().begin(),
+                                         attachedDevices.getItem().end());
+            }
+        }
+    }
+    return attachedDeviceSet;
+}
+
+ConversionResult<AudioDeviceDescription> convertDeviceTypeToAidl(const std::string& xType) {
+    audio_devices_t legacyDeviceType = AUDIO_DEVICE_NONE;
+    ::android::DeviceConverter::fromString(xType, legacyDeviceType);
+    ConversionResult<AudioDeviceDescription> result =
+            legacy2aidl_audio_devices_t_AudioDeviceDescription(legacyDeviceType);
+    if ((legacyDeviceType == AUDIO_DEVICE_NONE) || !result.ok()) {
+        LOG(ERROR) << __func__ << " Review Audio Policy config: " << xType
+                   << " is not a valid device type.";
+        return unexpected(BAD_VALUE);
+    }
+    return result;
+}
+
+ConversionResult<AudioDevice> createAudioDevice(
+        const ap_xsd::DevicePorts::DevicePort& xDevicePort) {
+    AudioDevice device = {
+            .type = VALUE_OR_FATAL(convertDeviceTypeToAidl(xDevicePort.getType())),
+            .address = xDevicePort.hasAddress()
+                               ? AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>(
+                                         xDevicePort.getAddress())
+                               : AudioDeviceAddress{}};
+    if (device.type.type == AudioDeviceType::IN_MICROPHONE && device.type.connection.empty()) {
+        device.address = "bottom";
+    } else if (device.type.type == AudioDeviceType::IN_MICROPHONE_BACK &&
+               device.type.connection.empty()) {
+        device.address = "back";
+    }
+    return device;
+}
+
+ConversionResult<AudioPortExt> createAudioPortExt(
+        const ap_xsd::DevicePorts::DevicePort& xDevicePort,
+        const std::string& xDefaultOutputDevice) {
+    AudioPortDeviceExt deviceExt = {
+            .device = VALUE_OR_FATAL(createAudioDevice(xDevicePort)),
+            .flags = (xDevicePort.getTagName() == xDefaultOutputDevice)
+                             ? 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE
+                             : 0,
+            .encodedFormats =
+                    xDevicePort.hasEncodedFormats()
+                            ? VALUE_OR_FATAL(
+                                      (convertCollectionToAidl<std::string, AudioFormatDescription>(
+                                              xDevicePort.getEncodedFormats(),
+                                              &convertAudioFormatToAidl)))
+                            : std::vector<AudioFormatDescription>{},
+    };
+    return AudioPortExt::make<AudioPortExt::Tag::device>(deviceExt);
+}
+
+ConversionResult<AudioPortExt> createAudioPortExt(const ap_xsd::MixPorts::MixPort& xMixPort) {
+    AudioPortMixExt mixExt = {
+            .maxOpenStreamCount =
+                    xMixPort.hasMaxOpenCount() ? static_cast<int>(xMixPort.getMaxOpenCount()) : 0,
+            .maxActiveStreamCount = xMixPort.hasMaxActiveCount()
+                                            ? static_cast<int>(xMixPort.getMaxActiveCount())
+                                            : 1,
+            .recommendedMuteDurationMs =
+                    xMixPort.hasRecommendedMuteDurationMs()
+                            ? static_cast<int>(xMixPort.getRecommendedMuteDurationMs())
+                            : 0};
+    return AudioPortExt::make<AudioPortExt::Tag::mix>(mixExt);
+}
+
+ConversionResult<int> convertGainModeToAidl(const std::vector<ap_xsd::AudioGainMode>& gainModeVec) {
+    int gainModeMask = 0;
+    for (const ap_xsd::AudioGainMode& gainMode : gainModeVec) {
+        audio_gain_mode_t legacyGainMode;
+        if (::android::GainModeConverter::fromString(ap_xsd::toString(gainMode), legacyGainMode)) {
+            gainModeMask |= static_cast<int>(legacyGainMode);
+        }
+    }
+    return gainModeMask;
+}
+
+ConversionResult<AudioChannelLayout> convertChannelMaskToAidl(
+        const ap_xsd::AudioChannelMask& xChannelMask) {
+    std::string xChannelMaskLiteral = ap_xsd::toString(xChannelMask);
+    audio_channel_mask_t legacyChannelMask = ::android::channelMaskFromString(xChannelMaskLiteral);
+    ConversionResult<AudioChannelLayout> result =
+            legacy2aidl_audio_channel_mask_t_AudioChannelLayout(
+                    legacyChannelMask,
+                    /* isInput= */ xChannelMaskLiteral.find("AUDIO_CHANNEL_IN_") == 0);
+    if ((legacyChannelMask == AUDIO_CHANNEL_INVALID) || !result.ok()) {
+        LOG(ERROR) << __func__ << " Review Audio Policy config: " << xChannelMaskLiteral
+                   << " is not a valid audio channel mask.";
+        return unexpected(BAD_VALUE);
+    }
+    return result;
+}
+
+ConversionResult<AudioGain> convertGainToAidl(const ap_xsd::Gains::Gain& xGain) {
+    return AudioGain{
+            .mode = VALUE_OR_FATAL(convertGainModeToAidl(xGain.getMode())),
+            .channelMask =
+                    xGain.hasChannel_mask()
+                            ? VALUE_OR_FATAL(convertChannelMaskToAidl(xGain.getChannel_mask()))
+                            : AudioChannelLayout{},
+            .minValue = xGain.hasMinValueMB() ? xGain.getMinValueMB() : 0,
+            .maxValue = xGain.hasMaxValueMB() ? xGain.getMaxValueMB() : 0,
+            .defaultValue = xGain.hasDefaultValueMB() ? xGain.getDefaultValueMB() : 0,
+            .stepValue = xGain.hasStepValueMB() ? xGain.getStepValueMB() : 0,
+            .minRampMs = xGain.hasMinRampMs() ? xGain.getMinRampMs() : 0,
+            .maxRampMs = xGain.hasMaxRampMs() ? xGain.getMaxRampMs() : 0,
+            .useForVolume = xGain.hasUseForVolume() ? xGain.getUseForVolume() : false,
+    };
+}
+
+ConversionResult<AudioProfile> convertAudioProfileToAidl(const ap_xsd::Profile& xProfile) {
+    return AudioProfile{
+            .format = xProfile.hasFormat()
+                              ? VALUE_OR_FATAL(convertAudioFormatToAidl(xProfile.getFormat()))
+                              : AudioFormatDescription{},
+            .channelMasks =
+                    xProfile.hasChannelMasks()
+                            ? VALUE_OR_FATAL((convertCollectionToAidl<ap_xsd::AudioChannelMask,
+                                                                      AudioChannelLayout>(
+                                      xProfile.getChannelMasks(), &convertChannelMaskToAidl)))
+                            : std::vector<AudioChannelLayout>{},
+            .sampleRates = xProfile.hasSamplingRates()
+                                   ? VALUE_OR_FATAL((convertCollectionToAidl<int64_t, int>(
+                                             xProfile.getSamplingRates(),
+                                             [](const int64_t x) -> int { return x; })))
+                                   : std::vector<int>{}};
+}
+
+ConversionResult<AudioIoFlags> convertIoFlagsToAidl(
+        const std::vector<ap_xsd::AudioInOutFlag>& flags, const ap_xsd::Role role,
+        bool flagsForMixPort) {
+    int legacyFlagMask = 0;
+    if ((role == ap_xsd::Role::sink && flagsForMixPort) ||
+        (role == ap_xsd::Role::source && !flagsForMixPort)) {
+        for (const ap_xsd::AudioInOutFlag& flag : flags) {
+            audio_input_flags_t legacyFlag;
+            if (::android::InputFlagConverter::fromString(ap_xsd::toString(flag), legacyFlag)) {
+                legacyFlagMask |= static_cast<int>(legacyFlag);
+            }
+        }
+        return AudioIoFlags::make<AudioIoFlags::Tag::input>(
+                VALUE_OR_FATAL(legacy2aidl_audio_input_flags_t_int32_t_mask(
+                        static_cast<audio_input_flags_t>(legacyFlagMask))));
+    } else {
+        for (const ap_xsd::AudioInOutFlag& flag : flags) {
+            audio_output_flags_t legacyFlag;
+            if (::android::OutputFlagConverter::fromString(ap_xsd::toString(flag), legacyFlag)) {
+                legacyFlagMask |= static_cast<int>(legacyFlag);
+            }
+        }
+        return AudioIoFlags::make<AudioIoFlags::Tag::output>(
+                VALUE_OR_FATAL(legacy2aidl_audio_output_flags_t_int32_t_mask(
+                        static_cast<audio_output_flags_t>(legacyFlagMask))));
+    }
+}
+
+ConversionResult<AudioPort> convertDevicePortToAidl(
+        const ap_xsd::DevicePorts::DevicePort& xDevicePort, const std::string& xDefaultOutputDevice,
+        int32_t& nextPortId) {
+    return AudioPort{
+            .id = nextPortId++,
+            .name = NON_EMPTY_STRING_OR_FATAL(xDevicePort.getTagName()),
+            .profiles = VALUE_OR_FATAL((convertCollectionToAidl<ap_xsd::Profile, AudioProfile>(
+                    xDevicePort.getProfile(), convertAudioProfileToAidl))),
+            .flags = VALUE_OR_FATAL(convertIoFlagsToAidl({}, xDevicePort.getRole(), false)),
+            .gains = VALUE_OR_FATAL(
+                    (convertWrappedCollectionToAidl<ap_xsd::Gains, ap_xsd::Gains::Gain, AudioGain>(
+                            xDevicePort.getGains(), &ap_xsd::Gains::getGain, convertGainToAidl))),
+
+            .ext = VALUE_OR_FATAL(createAudioPortExt(xDevicePort, xDefaultOutputDevice))};
+}
+
+ConversionResult<std::vector<AudioPort>> convertDevicePortsInModuleToAidl(
+        const ap_xsd::Modules::Module& xModuleConfig, int32_t& nextPortId) {
+    std::vector<AudioPort> audioPortVec;
+    std::vector<ap_xsd::DevicePorts> xDevicePortsVec = xModuleConfig.getDevicePorts();
+    if (xDevicePortsVec.size() > 1) {
+        LOG(ERROR) << __func__ << "Having multiple '<devicePorts>' elements is not allowed, found: "
+                   << xDevicePortsVec.size();
+        return unexpected(BAD_VALUE);
+    }
+    if (!xDevicePortsVec.empty()) {
+        const std::string xDefaultOutputDevice = xModuleConfig.hasDefaultOutputDevice()
+                                                         ? xModuleConfig.getDefaultOutputDevice()
+                                                         : "";
+        audioPortVec.reserve(xDevicePortsVec[0].getDevicePort().size());
+        for (const ap_xsd::DevicePorts& xDevicePortsType : xDevicePortsVec) {
+            for (const ap_xsd::DevicePorts::DevicePort& xDevicePort :
+                 xDevicePortsType.getDevicePort()) {
+                audioPortVec.push_back(VALUE_OR_FATAL(
+                        convertDevicePortToAidl(xDevicePort, xDefaultOutputDevice, nextPortId)));
+            }
+        }
+    }
+    const std::unordered_set<std::string> xAttachedDeviceSet = getAttachedDevices(xModuleConfig);
+    for (const auto& port : audioPortVec) {
+        const auto& devicePort = port.ext.get<AudioPortExt::device>();
+        if (xAttachedDeviceSet.count(port.name) != devicePort.device.type.connection.empty()) {
+            LOG(ERROR) << __func__ << ": Review Audio Policy config: <attachedDevices> "
+                       << "list is incorrect or devicePort \"" << port.name
+                       << "\" type= " << devicePort.device.type.toString() << " is incorrect.";
+            return unexpected(BAD_VALUE);
+        }
+    }
+    return audioPortVec;
+}
+
+ConversionResult<AudioPort> convertMixPortToAidl(const ap_xsd::MixPorts::MixPort& xMixPort,
+                                                 int32_t& nextPortId) {
+    return AudioPort{
+            .id = nextPortId++,
+            .name = NON_EMPTY_STRING_OR_FATAL(xMixPort.getName()),
+            .profiles = VALUE_OR_FATAL((convertCollectionToAidl<ap_xsd::Profile, AudioProfile>(
+                    xMixPort.getProfile(), convertAudioProfileToAidl))),
+            .flags = xMixPort.hasFlags()
+                             ? VALUE_OR_FATAL(convertIoFlagsToAidl(xMixPort.getFlags(),
+                                                                   xMixPort.getRole(), true))
+                             : VALUE_OR_FATAL(convertIoFlagsToAidl({}, xMixPort.getRole(), true)),
+            .gains = VALUE_OR_FATAL(
+                    (convertWrappedCollectionToAidl<ap_xsd::Gains, ap_xsd::Gains::Gain, AudioGain>(
+                            xMixPort.getGains(), &ap_xsd::Gains::getGain, &convertGainToAidl))),
+            .ext = VALUE_OR_FATAL(createAudioPortExt(xMixPort)),
+    };
+}
+
+ConversionResult<std::vector<AudioPort>> convertMixPortsInModuleToAidl(
+        const ap_xsd::Modules::Module& xModuleConfig, int32_t& nextPortId) {
+    std::vector<AudioPort> audioPortVec;
+    std::vector<ap_xsd::MixPorts> xMixPortsVec = xModuleConfig.getMixPorts();
+    if (xMixPortsVec.size() > 1) {
+        LOG(ERROR) << __func__ << "Having multiple '<mixPorts>' elements is not allowed, found: "
+                   << xMixPortsVec.size();
+        return unexpected(BAD_VALUE);
+    }
+    if (!xMixPortsVec.empty()) {
+        audioPortVec.reserve(xMixPortsVec[0].getMixPort().size());
+        for (const ap_xsd::MixPorts& xMixPortsType : xMixPortsVec) {
+            for (const ap_xsd::MixPorts::MixPort& xMixPort : xMixPortsType.getMixPort()) {
+                audioPortVec.push_back(VALUE_OR_FATAL(convertMixPortToAidl(xMixPort, nextPortId)));
+            }
+        }
+    }
+    return audioPortVec;
+}
+
+ConversionResult<int32_t> getSinkPortId(const ap_xsd::Routes::Route& xRoute,
+                                        const std::unordered_map<std::string, int32_t>& portMap) {
+    auto portMapIter = portMap.find(xRoute.getSink());
+    if (portMapIter == portMap.end()) {
+        LOG(ERROR) << __func__ << " Review Audio Policy config: audio route"
+                   << "has sink: " << xRoute.getSink()
+                   << " which is neither a device port nor mix port.";
+        return unexpected(BAD_VALUE);
+    }
+    return portMapIter->second;
+}
+
+ConversionResult<std::vector<int32_t>> getSourcePortIds(
+        const ap_xsd::Routes::Route& xRoute,
+        const std::unordered_map<std::string, int32_t>& portMap) {
+    std::vector<int32_t> sourcePortIds;
+    for (const std::string& rawSource : ::android::base::Split(xRoute.getSources(), ",")) {
+        const std::string source = ::android::base::Trim(rawSource);
+        auto portMapIter = portMap.find(source);
+        if (portMapIter == portMap.end()) {
+            LOG(ERROR) << __func__ << " Review Audio Policy config: audio route"
+                       << "has source \"" << source
+                       << "\" which is neither a device port nor mix port.";
+            return unexpected(BAD_VALUE);
+        }
+        sourcePortIds.push_back(portMapIter->second);
+    }
+    return sourcePortIds;
+}
+
+ConversionResult<AudioRoute> convertRouteToAidl(const ap_xsd::Routes::Route& xRoute,
+                                                const std::vector<AudioPort>& aidlAudioPorts) {
+    std::unordered_map<std::string, int32_t> portMap;
+    for (const AudioPort& port : aidlAudioPorts) {
+        portMap.insert({port.name, port.id});
+    }
+    return AudioRoute{.sourcePortIds = VALUE_OR_FATAL(getSourcePortIds(xRoute, portMap)),
+                      .sinkPortId = VALUE_OR_FATAL(getSinkPortId(xRoute, portMap)),
+                      .isExclusive = (xRoute.getType() == ap_xsd::MixType::mux)};
+}
+
+ConversionResult<std::vector<AudioRoute>> convertRoutesInModuleToAidl(
+        const ap_xsd::Modules::Module& xModuleConfig,
+        const std::vector<AudioPort>& aidlAudioPorts) {
+    std::vector<AudioRoute> audioRouteVec;
+    std::vector<ap_xsd::Routes> xRoutesVec = xModuleConfig.getRoutes();
+    if (!xRoutesVec.empty()) {
+        /*
+         * xRoutesVec likely only contains one element; that is, it's
+         * likely that all ap_xsd::Routes::MixPort types that we need to convert
+         * are inside of xRoutesVec[0].
+         */
+        audioRouteVec.reserve(xRoutesVec[0].getRoute().size());
+        for (const ap_xsd::Routes& xRoutesType : xRoutesVec) {
+            for (const ap_xsd::Routes::Route& xRoute : xRoutesType.getRoute()) {
+                audioRouteVec.push_back(VALUE_OR_FATAL(convertRouteToAidl(xRoute, aidlAudioPorts)));
+            }
+        }
+    }
+    return audioRouteVec;
+}
+
+ConversionResult<std::unique_ptr<Module::Configuration>> convertModuleConfigToAidl(
+        const ap_xsd::Modules::Module& xModuleConfig) {
+    auto result = std::make_unique<Module::Configuration>();
+    auto& aidlModuleConfig = *result;
+    std::vector<AudioPort> devicePorts = VALUE_OR_FATAL(
+            convertDevicePortsInModuleToAidl(xModuleConfig, aidlModuleConfig.nextPortId));
+
+    // The XML config does not specify the default input device.
+    // Assign the first attached input device as the default.
+    for (auto& port : devicePorts) {
+        if (port.flags.getTag() != AudioIoFlags::input) continue;
+        auto& deviceExt = port.ext.get<AudioPortExt::device>();
+        if (!deviceExt.device.type.connection.empty()) continue;
+        deviceExt.flags |= 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE;
+        break;
+    }
+
+    std::vector<AudioPort> mixPorts = VALUE_OR_FATAL(
+            convertMixPortsInModuleToAidl(xModuleConfig, aidlModuleConfig.nextPortId));
+    aidlModuleConfig.ports.reserve(devicePorts.size() + mixPorts.size());
+    aidlModuleConfig.ports.insert(aidlModuleConfig.ports.end(), devicePorts.begin(),
+                                  devicePorts.end());
+    aidlModuleConfig.ports.insert(aidlModuleConfig.ports.end(), mixPorts.begin(), mixPorts.end());
+
+    aidlModuleConfig.routes =
+            VALUE_OR_FATAL(convertRoutesInModuleToAidl(xModuleConfig, aidlModuleConfig.ports));
+    return result;
+}
+
+ConversionResult<AudioHalCapCriterion> convertCapCriterionToAidl(
+        const eng_xsd::CriterionType& xsdcCriterion) {
+    AudioHalCapCriterion aidlCapCriterion;
+    aidlCapCriterion.name = xsdcCriterion.getName();
+    aidlCapCriterion.criterionTypeName = xsdcCriterion.getType();
+    aidlCapCriterion.defaultLiteralValue = xsdcCriterion.get_default();
+    return aidlCapCriterion;
+}
+
+ConversionResult<std::string> convertCriterionTypeValueToAidl(
+        const eng_xsd::ValueType& xsdcCriterionTypeValue) {
+    return xsdcCriterionTypeValue.getLiteral();
+}
+
+ConversionResult<AudioHalCapCriterionType> convertCapCriterionTypeToAidl(
+        const eng_xsd::CriterionTypeType& xsdcCriterionType) {
+    AudioHalCapCriterionType aidlCapCriterionType;
+    aidlCapCriterionType.name = xsdcCriterionType.getName();
+    aidlCapCriterionType.isInclusive = !(static_cast<bool>(xsdcCriterionType.getType()));
+    aidlCapCriterionType.values = VALUE_OR_RETURN(
+            (convertWrappedCollectionToAidl<eng_xsd::ValuesType, eng_xsd::ValueType, std::string>(
+                    xsdcCriterionType.getValues(), &eng_xsd::ValuesType::getValue,
+                    &convertCriterionTypeValueToAidl)));
+    return aidlCapCriterionType;
+}
+
+ConversionResult<AudioHalVolumeCurve::CurvePoint> convertCurvePointToAidl(
+        const std::string& xsdcCurvePoint) {
+    AudioHalVolumeCurve::CurvePoint aidlCurvePoint{};
+    if ((sscanf(xsdcCurvePoint.c_str(), "%" SCNd8 ",%d", &aidlCurvePoint.index,
+                &aidlCurvePoint.attenuationMb) != 2) ||
+        (aidlCurvePoint.index < AudioHalVolumeCurve::CurvePoint::MIN_INDEX) ||
+        (aidlCurvePoint.index > AudioHalVolumeCurve::CurvePoint::MAX_INDEX)) {
+        LOG(ERROR) << __func__ << " Review Audio Policy config: volume curve point:"
+                   << "\"" << xsdcCurvePoint << "\" is invalid";
+        return unexpected(BAD_VALUE);
+    }
+    return aidlCurvePoint;
+}
+}  // namespace aidl::android::hardware::audio::core::internal
diff --git a/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.cpp b/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.cpp
index 63a014a..be0927c 100644
--- a/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.cpp
+++ b/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.cpp
@@ -74,9 +74,9 @@
         .common = {.id = {.type = getEffectTypeUuidAcousticEchoCanceler(),
                           .uuid = getEffectImplUuidAcousticEchoCancelerSw(),
                           .proxy = std::nullopt},
-                   .flags = {.type = Flags::Type::INSERT,
+                   .flags = {.type = Flags::Type::PRE_PROC,
                              .insert = Flags::Insert::FIRST,
-                             .volume = Flags::Volume::CTRL},
+                             .volume = Flags::Volume::NONE},
                    .name = AcousticEchoCancelerSw::kEffectName,
                    .implementor = "The Android Open Source Project"},
         .capability = AcousticEchoCancelerSw::kCapability};
@@ -168,10 +168,6 @@
     return mContext;
 }
 
-std::shared_ptr<EffectContext> AcousticEchoCancelerSw::getContext() {
-    return mContext;
-}
-
 RetCode AcousticEchoCancelerSw::releaseContext() {
     if (mContext) {
         mContext.reset();
diff --git a/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.h b/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.h
index 73cf42b..95738f8 100644
--- a/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.h
+++ b/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.h
@@ -52,21 +52,23 @@
     }
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
-    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
-    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
-                                            Parameter::Specific* specific) override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+            REQUIRES(mImplMutex) override;
 
-    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
-    std::shared_ptr<EffectContext> getContext() override;
-    RetCode releaseContext() override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+            REQUIRES(mImplMutex) override;
+    RetCode releaseContext() REQUIRES(mImplMutex) override;
 
     std::string getEffectName() override { return kEffectName; };
     IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
 
   private:
     static const std::vector<Range::AcousticEchoCancelerRange> kRanges;
-    std::shared_ptr<AcousticEchoCancelerSwContext> mContext;
+    std::shared_ptr<AcousticEchoCancelerSwContext> mContext GUARDED_BY(mImplMutex);
     ndk::ScopedAStatus getParameterAcousticEchoCanceler(const AcousticEchoCanceler::Tag& tag,
-                                                        Parameter::Specific* specific);
+                                                        Parameter::Specific* specific)
+            REQUIRES(mImplMutex);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/acousticEchoCanceler/Android.bp b/audio/aidl/default/acousticEchoCanceler/Android.bp
index bfb7212..d0404cd 100644
--- a/audio/aidl/default/acousticEchoCanceler/Android.bp
+++ b/audio/aidl/default/acousticEchoCanceler/Android.bp
@@ -27,8 +27,6 @@
     name: "libaecsw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "AcousticEchoCancelerSw.cpp",
@@ -36,6 +34,6 @@
     ],
     relative_install_path: "soundfx",
     visibility: [
-        "//hardware/interfaces/audio/aidl/default",
+        "//hardware/interfaces/audio/aidl/default:__subpackages__",
     ],
 }
diff --git a/audio/aidl/default/alsa/Mixer.cpp b/audio/aidl/default/alsa/Mixer.cpp
index 126c033..e72502b 100644
--- a/audio/aidl/default/alsa/Mixer.cpp
+++ b/audio/aidl/default/alsa/Mixer.cpp
@@ -20,9 +20,24 @@
 #define LOG_TAG "AHAL_AlsaMixer"
 #include <android-base/logging.h>
 #include <android/binder_status.h>
+#include <error/expected_utils.h>
 
 #include "Mixer.h"
 
+namespace ndk {
+
+// This enables use of 'error/expected_utils' for ScopedAStatus.
+
+inline bool errorIsOk(const ScopedAStatus& s) {
+    return s.isOk();
+}
+
+inline std::string errorToString(const ScopedAStatus& s) {
+    return s.getDescription();
+}
+
+}  // namespace ndk
+
 namespace aidl::android::hardware::audio::core::alsa {
 
 // static
@@ -93,6 +108,36 @@
     }
 }
 
+ndk::ScopedAStatus Mixer::getMasterMute(bool* muted) {
+    return getMixerControlMute(MASTER_SWITCH, muted);
+}
+
+ndk::ScopedAStatus Mixer::getMasterVolume(float* volume) {
+    return getMixerControlVolume(MASTER_VOLUME, volume);
+}
+
+ndk::ScopedAStatus Mixer::getMicGain(float* gain) {
+    return getMixerControlVolume(MIC_GAIN, gain);
+}
+
+ndk::ScopedAStatus Mixer::getMicMute(bool* muted) {
+    return getMixerControlMute(MIC_SWITCH, muted);
+}
+
+ndk::ScopedAStatus Mixer::getVolumes(std::vector<float>* volumes) {
+    struct mixer_ctl* mctl;
+    RETURN_STATUS_IF_ERROR(findControl(Mixer::HW_VOLUME, &mctl));
+    std::vector<int> percents;
+    std::lock_guard l(mMixerAccess);
+    if (int err = getMixerControlPercent(mctl, &percents); err != 0) {
+        LOG(ERROR) << __func__ << ": failed to get volume, err=" << err;
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    std::transform(percents.begin(), percents.end(), std::back_inserter(*volumes),
+                   [](int percent) -> float { return std::clamp(percent / 100.0f, 0.0f, 1.0f); });
+    return ndk::ScopedAStatus::ok();
+}
+
 ndk::ScopedAStatus Mixer::setMasterMute(bool muted) {
     return setMixerControlMute(MASTER_SWITCH, muted);
 }
@@ -110,35 +155,70 @@
 }
 
 ndk::ScopedAStatus Mixer::setVolumes(const std::vector<float>& volumes) {
-    if (!isValid()) {
-        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
-    }
-    auto it = mMixerControls.find(Mixer::HW_VOLUME);
-    if (it == mMixerControls.end()) {
-        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
-    }
+    struct mixer_ctl* mctl;
+    RETURN_STATUS_IF_ERROR(findControl(Mixer::HW_VOLUME, &mctl));
     std::vector<int> percents;
     std::transform(
             volumes.begin(), volumes.end(), std::back_inserter(percents),
             [](float volume) -> int { return std::floor(std::clamp(volume, 0.0f, 1.0f) * 100); });
     std::lock_guard l(mMixerAccess);
-    if (int err = setMixerControlPercent(it->second, percents); err != 0) {
+    if (int err = setMixerControlPercent(mctl, percents); err != 0) {
         LOG(ERROR) << __func__ << ": failed to set volume, err=" << err;
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
     }
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Mixer::setMixerControlMute(Mixer::Control ctl, bool muted) {
+ndk::ScopedAStatus Mixer::findControl(Control ctl, struct mixer_ctl** result) {
     if (!isValid()) {
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
     }
-    auto it = mMixerControls.find(ctl);
-    if (it == mMixerControls.end()) {
-        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    if (auto it = mMixerControls.find(ctl); it != mMixerControls.end()) {
+        *result = it->second;
+        return ndk::ScopedAStatus::ok();
     }
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus Mixer::getMixerControlMute(Control ctl, bool* muted) {
+    struct mixer_ctl* mctl;
+    RETURN_STATUS_IF_ERROR(findControl(ctl, &mctl));
     std::lock_guard l(mMixerAccess);
-    if (int err = setMixerControlValue(it->second, muted ? 0 : 1); err != 0) {
+    std::vector<int> mutedValues;
+    if (int err = getMixerControlValues(mctl, &mutedValues); err != 0) {
+        LOG(ERROR) << __func__ << ": failed to get " << ctl << ", err=" << err;
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    if (mutedValues.empty()) {
+        LOG(ERROR) << __func__ << ": got no values for " << ctl;
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    *muted = mutedValues[0] != 0;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Mixer::getMixerControlVolume(Control ctl, float* volume) {
+    struct mixer_ctl* mctl;
+    RETURN_STATUS_IF_ERROR(findControl(ctl, &mctl));
+    std::lock_guard l(mMixerAccess);
+    std::vector<int> percents;
+    if (int err = getMixerControlPercent(mctl, &percents); err != 0) {
+        LOG(ERROR) << __func__ << ": failed to get " << ctl << ", err=" << err;
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    if (percents.empty()) {
+        LOG(ERROR) << __func__ << ": got no values for " << ctl;
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    *volume = std::clamp(percents[0] / 100.0f, 0.0f, 1.0f);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Mixer::setMixerControlMute(Control ctl, bool muted) {
+    struct mixer_ctl* mctl;
+    RETURN_STATUS_IF_ERROR(findControl(ctl, &mctl));
+    std::lock_guard l(mMixerAccess);
+    if (int err = setMixerControlValue(mctl, muted ? 0 : 1); err != 0) {
         LOG(ERROR) << __func__ << ": failed to set " << ctl << " to " << muted << ", err=" << err;
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
     }
@@ -146,54 +226,72 @@
 }
 
 ndk::ScopedAStatus Mixer::setMixerControlVolume(Control ctl, float volume) {
-    if (!isValid()) {
-        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
-    }
-    auto it = mMixerControls.find(ctl);
-    if (it == mMixerControls.end()) {
-        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
-    }
+    struct mixer_ctl* mctl;
+    RETURN_STATUS_IF_ERROR(findControl(ctl, &mctl));
     volume = std::clamp(volume, 0.0f, 1.0f);
     std::lock_guard l(mMixerAccess);
-    if (int err = setMixerControlPercent(it->second, std::floor(volume * 100)); err != 0) {
+    if (int err = setMixerControlPercent(mctl, std::floor(volume * 100)); err != 0) {
         LOG(ERROR) << __func__ << ": failed to set " << ctl << " to " << volume << ", err=" << err;
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
     }
     return ndk::ScopedAStatus::ok();
 }
 
+int Mixer::getMixerControlPercent(struct mixer_ctl* ctl, std::vector<int>* percents) {
+    const unsigned int n = mixer_ctl_get_num_values(ctl);
+    percents->resize(n);
+    for (unsigned int id = 0; id < n; id++) {
+        if (int valueOrError = mixer_ctl_get_percent(ctl, id); valueOrError >= 0) {
+            (*percents)[id] = valueOrError;
+        } else {
+            return valueOrError;
+        }
+    }
+    return 0;
+}
+
+int Mixer::getMixerControlValues(struct mixer_ctl* ctl, std::vector<int>* values) {
+    const unsigned int n = mixer_ctl_get_num_values(ctl);
+    values->resize(n);
+    for (unsigned int id = 0; id < n; id++) {
+        if (int valueOrError = mixer_ctl_get_value(ctl, id); valueOrError >= 0) {
+            (*values)[id] = valueOrError;
+        } else {
+            return valueOrError;
+        }
+    }
+    return 0;
+}
+
 int Mixer::setMixerControlPercent(struct mixer_ctl* ctl, int percent) {
-    int ret = 0;
     const unsigned int n = mixer_ctl_get_num_values(ctl);
     for (unsigned int id = 0; id < n; id++) {
         if (int error = mixer_ctl_set_percent(ctl, id, percent); error != 0) {
-            ret = error;
+            return error;
         }
     }
-    return ret;
+    return 0;
 }
 
 int Mixer::setMixerControlPercent(struct mixer_ctl* ctl, const std::vector<int>& percents) {
-    int ret = 0;
     const unsigned int n = mixer_ctl_get_num_values(ctl);
     for (unsigned int id = 0; id < n; id++) {
         if (int error = mixer_ctl_set_percent(ctl, id, id < percents.size() ? percents[id] : 0);
             error != 0) {
-            ret = error;
+            return error;
         }
     }
-    return ret;
+    return 0;
 }
 
 int Mixer::setMixerControlValue(struct mixer_ctl* ctl, int value) {
-    int ret = 0;
     const unsigned int n = mixer_ctl_get_num_values(ctl);
     for (unsigned int id = 0; id < n; id++) {
         if (int error = mixer_ctl_set_value(ctl, id, value); error != 0) {
-            ret = error;
+            return error;
         }
     }
-    return ret;
+    return 0;
 }
 
 }  // namespace aidl::android::hardware::audio::core::alsa
diff --git a/audio/aidl/default/alsa/Mixer.h b/audio/aidl/default/alsa/Mixer.h
index 8fba1e0..41f19a8 100644
--- a/audio/aidl/default/alsa/Mixer.h
+++ b/audio/aidl/default/alsa/Mixer.h
@@ -39,6 +39,11 @@
 
     bool isValid() const { return mMixer != nullptr; }
 
+    ndk::ScopedAStatus getMasterMute(bool* muted);
+    ndk::ScopedAStatus getMasterVolume(float* volume);
+    ndk::ScopedAStatus getMicGain(float* gain);
+    ndk::ScopedAStatus getMicMute(bool* muted);
+    ndk::ScopedAStatus getVolumes(std::vector<float>* volumes);
     ndk::ScopedAStatus setMasterMute(bool muted);
     ndk::ScopedAStatus setMasterVolume(float volume);
     ndk::ScopedAStatus setMicGain(float gain);
@@ -60,9 +65,16 @@
     static const std::map<Control, std::vector<ControlNamesAndExpectedCtlType>> kPossibleControls;
     static Controls initializeMixerControls(struct mixer* mixer);
 
+    ndk::ScopedAStatus findControl(Control ctl, struct mixer_ctl** result);
+    ndk::ScopedAStatus getMixerControlMute(Control ctl, bool* muted);
+    ndk::ScopedAStatus getMixerControlVolume(Control ctl, float* volume);
     ndk::ScopedAStatus setMixerControlMute(Control ctl, bool muted);
     ndk::ScopedAStatus setMixerControlVolume(Control ctl, float volume);
 
+    int getMixerControlPercent(struct mixer_ctl* ctl, std::vector<int>* percents)
+            REQUIRES(mMixerAccess);
+    int getMixerControlValues(struct mixer_ctl* ctl, std::vector<int>* values)
+            REQUIRES(mMixerAccess);
     int setMixerControlPercent(struct mixer_ctl* ctl, int percent) REQUIRES(mMixerAccess);
     int setMixerControlPercent(struct mixer_ctl* ctl, const std::vector<int>& percents)
             REQUIRES(mMixerAccess);
diff --git a/audio/aidl/default/alsa/ModuleAlsa.cpp b/audio/aidl/default/alsa/ModuleAlsa.cpp
index 8e75d56..9a2cce7 100644
--- a/audio/aidl/default/alsa/ModuleAlsa.cpp
+++ b/audio/aidl/default/alsa/ModuleAlsa.cpp
@@ -34,18 +34,19 @@
 
 namespace aidl::android::hardware::audio::core {
 
-ndk::ScopedAStatus ModuleAlsa::populateConnectedDevicePort(AudioPort* audioPort) {
+ndk::ScopedAStatus ModuleAlsa::populateConnectedDevicePort(AudioPort* audioPort, int32_t) {
     auto deviceProfile = alsa::getDeviceProfile(*audioPort);
     if (!deviceProfile.has_value()) {
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
-    auto profile = alsa::readAlsaDeviceInfo(*deviceProfile);
-    if (!profile.has_value()) {
+    auto proxy = alsa::readAlsaDeviceInfo(*deviceProfile);
+    if (proxy.get() == nullptr) {
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
     }
 
-    std::vector<AudioChannelLayout> channels = alsa::getChannelMasksFromProfile(&profile.value());
-    std::vector<int> sampleRates = alsa::getSampleRatesFromProfile(&profile.value());
+    alsa_device_profile* profile = proxy.getProfile();
+    std::vector<AudioChannelLayout> channels = alsa::getChannelMasksFromProfile(profile);
+    std::vector<int> sampleRates = alsa::getSampleRatesFromProfile(profile);
 
     for (size_t i = 0; i < std::min(MAX_PROFILE_FORMATS, AUDIO_PORT_MAX_AUDIO_PROFILES) &&
                        profile->formats[i] != PCM_FORMAT_INVALID;
diff --git a/audio/aidl/default/alsa/StreamAlsa.cpp b/audio/aidl/default/alsa/StreamAlsa.cpp
index 0605d6f..e57d538 100644
--- a/audio/aidl/default/alsa/StreamAlsa.cpp
+++ b/audio/aidl/default/alsa/StreamAlsa.cpp
@@ -83,7 +83,7 @@
             proxy = alsa::openProxyForAttachedDevice(
                     device, const_cast<struct pcm_config*>(&mConfig.value()), mBufferSizeFrames);
         }
-        if (!proxy) {
+        if (proxy.get() == nullptr) {
             return ::android::NO_INIT;
         }
         alsaDeviceProxies.push_back(std::move(proxy));
@@ -119,7 +119,7 @@
 
 ::android::status_t StreamAlsa::refinePosition(StreamDescriptor::Position* position) {
     if (mAlsaDeviceProxies.empty()) {
-        LOG(FATAL) << __func__ << ": no opened devices";
+        LOG(WARNING) << __func__ << ": no opened devices";
         return ::android::NO_INIT;
     }
     // Since the proxy can only count transferred frames since its creation,
diff --git a/audio/aidl/default/alsa/Utils.cpp b/audio/aidl/default/alsa/Utils.cpp
index 9dcd024..c08836c 100644
--- a/audio/aidl/default/alsa/Utils.cpp
+++ b/audio/aidl/default/alsa/Utils.cpp
@@ -37,6 +37,23 @@
 
 namespace aidl::android::hardware::audio::core::alsa {
 
+DeviceProxy::DeviceProxy() : mProfile(nullptr), mProxy(nullptr, alsaProxyDeleter) {}
+
+DeviceProxy::DeviceProxy(const DeviceProfile& deviceProfile)
+    : mProfile(new alsa_device_profile), mProxy(new alsa_device_proxy, alsaProxyDeleter) {
+    profile_init(mProfile.get(), deviceProfile.direction);
+    mProfile->card = deviceProfile.card;
+    mProfile->device = deviceProfile.device;
+    memset(mProxy.get(), 0, sizeof(alsa_device_proxy));
+}
+
+void DeviceProxy::alsaProxyDeleter(alsa_device_proxy* proxy) {
+    if (proxy != nullptr) {
+        proxy_close(proxy);
+        delete proxy;
+    }
+}
+
 namespace {
 
 using AudioChannelCountToMaskMap = std::map<unsigned int, AudioChannelLayout>;
@@ -261,39 +278,24 @@
     return sampleRates;
 }
 
-DeviceProxy makeDeviceProxy() {
-    DeviceProxy proxy(new alsa_device_proxy, [](alsa_device_proxy* proxy) {
-        if (proxy != nullptr) {
-            proxy_close(proxy);
-            delete proxy;
-        }
-    });
-    memset(proxy.get(), 0, sizeof(alsa_device_proxy));
-    return proxy;
-}
-
 DeviceProxy openProxyForAttachedDevice(const DeviceProfile& deviceProfile,
                                        struct pcm_config* pcmConfig, size_t bufferFrameCount) {
     if (deviceProfile.isExternal) {
         LOG(FATAL) << __func__ << ": called for an external device, address=" << deviceProfile;
     }
-    alsa_device_profile profile;
-    profile_init(&profile, deviceProfile.direction);
-    profile.card = deviceProfile.card;
-    profile.device = deviceProfile.device;
-    if (!profile_fill_builtin_device_info(&profile, pcmConfig, bufferFrameCount)) {
+    DeviceProxy proxy(deviceProfile);
+    if (!profile_fill_builtin_device_info(proxy.getProfile(), pcmConfig, bufferFrameCount)) {
         LOG(FATAL) << __func__ << ": failed to init for built-in device, address=" << deviceProfile;
     }
-    auto proxy = makeDeviceProxy();
-    if (int err = proxy_prepare_from_default_config(proxy.get(), &profile); err != 0) {
+    if (int err = proxy_prepare_from_default_config(proxy.get(), proxy.getProfile()); err != 0) {
         LOG(FATAL) << __func__ << ": fail to prepare for device address=" << deviceProfile
                    << " error=" << err;
-        return nullptr;
+        return DeviceProxy();
     }
     if (int err = proxy_open(proxy.get()); err != 0) {
         LOG(ERROR) << __func__ << ": failed to open device, address=" << deviceProfile
                    << " error=" << err;
-        return nullptr;
+        return DeviceProxy();
     }
     return proxy;
 }
@@ -303,42 +305,36 @@
     if (!deviceProfile.isExternal) {
         LOG(FATAL) << __func__ << ": called for an attached device, address=" << deviceProfile;
     }
-    auto profile = readAlsaDeviceInfo(deviceProfile);
-    if (!profile.has_value()) {
-        LOG(ERROR) << __func__ << ": unable to read device info, device address=" << deviceProfile;
-        return nullptr;
+    auto proxy = readAlsaDeviceInfo(deviceProfile);
+    if (proxy.get() == nullptr) {
+        return proxy;
     }
-    auto proxy = makeDeviceProxy();
-    if (int err = proxy_prepare(proxy.get(), &profile.value(), pcmConfig, requireExactMatch);
+    if (int err = proxy_prepare(proxy.get(), proxy.getProfile(), pcmConfig, requireExactMatch);
         err != 0) {
         LOG(ERROR) << __func__ << ": fail to prepare for device address=" << deviceProfile
                    << " error=" << err;
-        return nullptr;
+        return DeviceProxy();
     }
     if (int err = proxy_open(proxy.get()); err != 0) {
         LOG(ERROR) << __func__ << ": failed to open device, address=" << deviceProfile
                    << " error=" << err;
-        return nullptr;
+        return DeviceProxy();
     }
     return proxy;
 }
 
-std::optional<alsa_device_profile> readAlsaDeviceInfo(const DeviceProfile& deviceProfile) {
-    alsa_device_profile profile;
-    profile_init(&profile, deviceProfile.direction);
-    profile.card = deviceProfile.card;
-    profile.device = deviceProfile.device;
-    if (!profile_read_device_info(&profile)) {
-        LOG(ERROR) << __func__ << ": failed to read device info, card=" << profile.card
-                   << ", device=" << profile.device;
-        return std::nullopt;
+DeviceProxy readAlsaDeviceInfo(const DeviceProfile& deviceProfile) {
+    DeviceProxy proxy(deviceProfile);
+    if (!profile_read_device_info(proxy.getProfile())) {
+        LOG(ERROR) << __func__ << ": unable to read device info, device address=" << deviceProfile;
+        return DeviceProxy();
     }
-    return profile;
+    return proxy;
 }
 
 void resetTransferredFrames(DeviceProxy& proxy, uint64_t frames) {
-    if (proxy != nullptr) {
-        proxy->transferred = frames;
+    if (proxy.get() != nullptr) {
+        proxy.get()->transferred = frames;
     }
 }
 
diff --git a/audio/aidl/default/alsa/Utils.h b/audio/aidl/default/alsa/Utils.h
index 37414b3..980f685 100644
--- a/audio/aidl/default/alsa/Utils.h
+++ b/audio/aidl/default/alsa/Utils.h
@@ -43,8 +43,21 @@
     bool isExternal;
 };
 std::ostream& operator<<(std::ostream& os, const DeviceProfile& device);
-using DeviceProxyDeleter = std::function<void(alsa_device_proxy*)>;
-using DeviceProxy = std::unique_ptr<alsa_device_proxy, DeviceProxyDeleter>;
+
+class DeviceProxy {
+  public:
+    DeviceProxy();  // Constructs a "null" proxy.
+    explicit DeviceProxy(const DeviceProfile& deviceProfile);
+    alsa_device_profile* getProfile() { return mProfile.get(); }
+    alsa_device_proxy* get() { return mProxy.get(); }
+
+  private:
+    static void alsaProxyDeleter(alsa_device_proxy* proxy);
+    using AlsaProxy = std::unique_ptr<alsa_device_proxy, decltype(alsaProxyDeleter)*>;
+
+    std::unique_ptr<alsa_device_profile> mProfile;
+    AlsaProxy mProxy;
+};
 
 ::aidl::android::media::audio::common::AudioChannelLayout getChannelLayoutMaskFromChannelCount(
         unsigned int channelCount, int isInput);
@@ -60,12 +73,11 @@
         const ::aidl::android::media::audio::common::AudioPort& audioPort);
 std::optional<struct pcm_config> getPcmConfig(const StreamContext& context, bool isInput);
 std::vector<int> getSampleRatesFromProfile(const alsa_device_profile* profile);
-DeviceProxy makeDeviceProxy();
 DeviceProxy openProxyForAttachedDevice(const DeviceProfile& deviceProfile,
                                        struct pcm_config* pcmConfig, size_t bufferFrameCount);
 DeviceProxy openProxyForExternalDevice(const DeviceProfile& deviceProfile,
                                        struct pcm_config* pcmConfig, bool requireExactMatch);
-std::optional<alsa_device_profile> readAlsaDeviceInfo(const DeviceProfile& deviceProfile);
+DeviceProxy readAlsaDeviceInfo(const DeviceProfile& deviceProfile);
 void resetTransferredFrames(DeviceProxy& proxy, uint64_t frames);
 
 ::aidl::android::media::audio::common::AudioFormatDescription
diff --git a/audio/aidl/default/android.hardware.audio.effect.service-aidl.example.rc b/audio/aidl/default/android.hardware.audio.effect.service-aidl.example.rc
deleted file mode 100644
index 5f859a1..0000000
--- a/audio/aidl/default/android.hardware.audio.effect.service-aidl.example.rc
+++ /dev/null
@@ -1,11 +0,0 @@
-service vendor.audio-effect-hal-aidl /vendor/bin/hw/android.hardware.audio.effect.service-aidl.example
-    class hal
-    user audioserver
-    # media gid needed for /dev/fm (radio) and for /data/misc/media (tee)
-    group audio media
-    capabilities BLOCK_SUSPEND
-    # setting RLIMIT_RTPRIO allows binder RT priority inheritance
-    rlimit rtprio 10 10
-    ioprio rt 4
-    task_profiles ProcessCapacityHigh HighPerformance
-    onrestart restart audioserver
diff --git a/audio/aidl/default/android.hardware.audio.effect.service-aidl.xml b/audio/aidl/default/android.hardware.audio.effect.service-aidl.xml
deleted file mode 100644
index fdc53a3..0000000
--- a/audio/aidl/default/android.hardware.audio.effect.service-aidl.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<manifest version="1.0" type="device">
-  <hal format="aidl">
-    <name>android.hardware.audio.effect</name>
-    <version>1</version>
-    <fqname>IFactory/default</fqname>
-  </hal>
-</manifest>
diff --git a/audio/aidl/default/android.hardware.audio.service-aidl.example.rc b/audio/aidl/default/android.hardware.audio.service-aidl.example.rc
index 757976f..c3e19ba 100644
--- a/audio/aidl/default/android.hardware.audio.service-aidl.example.rc
+++ b/audio/aidl/default/android.hardware.audio.service-aidl.example.rc
@@ -1,4 +1,5 @@
-service vendor.audio-hal-aidl /vendor/bin/hw/android.hardware.audio.service-aidl.example
+
+service vendor.audio-hal-aidl /apex/com.android.hardware.audio/bin/hw/android.hardware.audio.service-aidl.example
     class hal
     user audioserver
     # media gid needed for /dev/fm (radio) and for /data/misc/media (tee)
@@ -9,3 +10,15 @@
     ioprio rt 4
     task_profiles ProcessCapacityHigh HighPerformance
     onrestart restart audioserver
+
+service vendor.audio-effect-hal-aidl /apex/com.android.hardware.audio/bin/hw/android.hardware.audio.effect.service-aidl.example
+    class hal
+    user audioserver
+    # media gid needed for /dev/fm (radio) and for /data/misc/media (tee)
+    group audio media
+    capabilities BLOCK_SUSPEND
+    # setting RLIMIT_RTPRIO allows binder RT priority inheritance
+    rlimit rtprio 10 10
+    ioprio rt 4
+    task_profiles ProcessCapacityHigh HighPerformance
+    onrestart restart audioserver
\ No newline at end of file
diff --git a/audio/aidl/default/android.hardware.audio.service-aidl.xml b/audio/aidl/default/android.hardware.audio.service-aidl.xml
index 9db6061..5278e4f 100644
--- a/audio/aidl/default/android.hardware.audio.service-aidl.xml
+++ b/audio/aidl/default/android.hardware.audio.service-aidl.xml
@@ -1,16 +1,27 @@
 <manifest version="1.0" type="device">
   <hal format="aidl">
     <name>android.hardware.audio.core</name>
-    <version>1</version>
+    <version>2</version>
     <fqname>IModule/default</fqname>
   </hal>
   <hal format="aidl">
     <name>android.hardware.audio.core</name>
-    <version>1</version>
+    <version>2</version>
     <fqname>IModule/r_submix</fqname>
   </hal>
   <hal format="aidl">
     <name>android.hardware.audio.core</name>
+    <version>2</version>
+    <fqname>IModule/bluetooth</fqname>
+  </hal>
+  <hal format="aidl">
+    <name>android.hardware.audio.core</name>
+    <version>2</version>
+    <fqname>IConfig/default</fqname>
+  </hal>
+  <!-- Uncomment when these modules present in the configuration
+  <hal format="aidl">
+    <name>android.hardware.audio.core</name>
     <version>1</version>
     <fqname>IModule/stub</fqname>
   </hal>
@@ -19,14 +30,10 @@
     <version>1</version>
     <fqname>IModule/usb</fqname>
   </hal>
+  -->
   <hal format="aidl">
-    <name>android.hardware.audio.core</name>
-    <version>1</version>
-    <fqname>IModule/bluetooth</fqname>
-  </hal>
-  <hal format="aidl">
-    <name>android.hardware.audio.core</name>
-    <version>1</version>
-    <fqname>IConfig/default</fqname>
+    <name>android.hardware.audio.effect</name>
+    <version>2</version>
+    <fqname>IFactory/default</fqname>
   </hal>
 </manifest>
diff --git a/audio/aidl/default/apex/com.android.hardware.audio/Android.bp b/audio/aidl/default/apex/com.android.hardware.audio/Android.bp
new file mode 100644
index 0000000..da84412
--- /dev/null
+++ b/audio/aidl/default/apex/com.android.hardware.audio/Android.bp
@@ -0,0 +1,49 @@
+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"],
+}
+
+apex {
+    name: "com.android.hardware.audio",
+    manifest: "manifest.json",
+    file_contexts: "file_contexts",
+    key: "com.android.hardware.key",
+    certificate: ":com.android.hardware.certificate",
+    updatable: false,
+    vendor: true,
+
+    binaries: [
+        "android.hardware.audio.service-aidl.example",
+        "android.hardware.audio.effect.service-aidl.example",
+    ],
+    native_shared_libs: [
+        "libaecsw",
+        "libagc1sw",
+        "libagc2sw",
+        "libbassboostsw",
+        "libbundleaidl",
+        "libdownmixaidl",
+        "libdynamicsprocessingaidl",
+        "libenvreverbsw",
+        "libequalizersw",
+        "libextensioneffect",
+        "libhapticgeneratoraidl",
+        "libloudnessenhanceraidl",
+        "libnssw",
+        "libpreprocessingaidl",
+        "libpresetreverbsw",
+        "libreverbaidl",
+        "libvirtualizersw",
+        "libvisualizeraidl",
+        "libvolumesw",
+    ],
+    prebuilts: [
+        "android.hardware.audio.service-aidl.example.rc",
+        "android.hardware.audio.service-aidl.xml",
+        "audio_effects_config.xml",
+    ],
+}
diff --git a/audio/aidl/default/apex/com.android.hardware.audio/file_contexts b/audio/aidl/default/apex/com.android.hardware.audio/file_contexts
new file mode 100644
index 0000000..41a6ada
--- /dev/null
+++ b/audio/aidl/default/apex/com.android.hardware.audio/file_contexts
@@ -0,0 +1,4 @@
+(/.*)?                                                              u:object_r:vendor_file:s0
+/etc(/.*)?                                                          u:object_r:vendor_configs_file:s0
+/bin/hw/android\.hardware\.audio\.service-aidl\.example             u:object_r:hal_audio_default_exec:s0
+/bin/hw/android\.hardware\.audio\.effect\.service-aidl\.example     u:object_r:hal_audio_default_exec:s0
\ No newline at end of file
diff --git a/audio/aidl/default/apex/com.android.hardware.audio/manifest.json b/audio/aidl/default/apex/com.android.hardware.audio/manifest.json
new file mode 100644
index 0000000..42a2368
--- /dev/null
+++ b/audio/aidl/default/apex/com.android.hardware.audio/manifest.json
@@ -0,0 +1,4 @@
+{
+    "name": "com.android.hardware.audio",
+    "version": 1
+}
diff --git a/audio/aidl/default/audio_effects_config.xml b/audio/aidl/default/audio_effects_config.xml
index 00de797..827ff80 100644
--- a/audio/aidl/default/audio_effects_config.xml
+++ b/audio/aidl/default/audio_effects_config.xml
@@ -47,6 +47,7 @@
         <library name="visualizer" path="libvisualizeraidl.so"/>
         <library name="volumesw" path="libvolumesw.so"/>
         <library name="extensioneffect" path="libextensioneffect.so"/>
+        <library name="spatializersw" path="libspatializersw.so"/>
     </libraries>
 
     <!-- list of effects to load.
@@ -96,8 +97,9 @@
             <libsw library="bundle" uuid="ce772f20-847d-11df-bb17-0002a5d5c51b"/>
         </effectProxy>
         <effect name="extension_effect" library="extensioneffect" uuid="fa81dd00-588b-11ed-9b6a-0242ac120002" type="fa81de0e-588b-11ed-9b6a-0242ac120002"/>
-        <effect name="acoustic_echo_canceler" library="aecsw" uuid="bb392ec0-8d4d-11e0-a896-0002a5d5c51b"/>
-        <effect name="noise_suppression" library="nssw" uuid="c06c8400-8e06-11e0-9cb6-0002a5d5c51b"/>
+        <effect name="acoustic_echo_canceler" library="pre_processing" uuid="bb392ec0-8d4d-11e0-a896-0002a5d5c51b"/>
+        <effect name="noise_suppression" library="pre_processing" uuid="c06c8400-8e06-11e0-9cb6-0002a5d5c51b"/>
+        <effect name="spatializer" library="spatializersw" uuid="fa81a880-588b-11ed-9b6a-0242ac120002"/>
     </effects>
 
     <preprocess>
diff --git a/audio/aidl/default/automaticGainControlV1/Android.bp b/audio/aidl/default/automaticGainControlV1/Android.bp
index 4ae8e63..7b753eb 100644
--- a/audio/aidl/default/automaticGainControlV1/Android.bp
+++ b/audio/aidl/default/automaticGainControlV1/Android.bp
@@ -27,8 +27,6 @@
     name: "libagc1sw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "AutomaticGainControlV1Sw.cpp",
@@ -36,6 +34,6 @@
     ],
     relative_install_path: "soundfx",
     visibility: [
-        "//hardware/interfaces/audio/aidl/default",
+        "//hardware/interfaces/audio/aidl/default:__subpackages__",
     ],
 }
diff --git a/audio/aidl/default/automaticGainControlV1/AutomaticGainControlV1Sw.cpp b/audio/aidl/default/automaticGainControlV1/AutomaticGainControlV1Sw.cpp
index ce10ae1..d865b7e 100644
--- a/audio/aidl/default/automaticGainControlV1/AutomaticGainControlV1Sw.cpp
+++ b/audio/aidl/default/automaticGainControlV1/AutomaticGainControlV1Sw.cpp
@@ -177,10 +177,6 @@
     return mContext;
 }
 
-std::shared_ptr<EffectContext> AutomaticGainControlV1Sw::getContext() {
-    return mContext;
-}
-
 RetCode AutomaticGainControlV1Sw::releaseContext() {
     if (mContext) {
         mContext.reset();
diff --git a/audio/aidl/default/automaticGainControlV1/AutomaticGainControlV1Sw.h b/audio/aidl/default/automaticGainControlV1/AutomaticGainControlV1Sw.h
index 7d2a69f..76b91ae 100644
--- a/audio/aidl/default/automaticGainControlV1/AutomaticGainControlV1Sw.h
+++ b/audio/aidl/default/automaticGainControlV1/AutomaticGainControlV1Sw.h
@@ -53,21 +53,24 @@
     }
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
-    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
-    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
-                                            Parameter::Specific* specific) override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+            REQUIRES(mImplMutex) override;
 
-    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
-    std::shared_ptr<EffectContext> getContext() override;
-    RetCode releaseContext() override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+            REQUIRES(mImplMutex) override;
+    RetCode releaseContext() REQUIRES(mImplMutex) override;
 
     std::string getEffectName() override { return kEffectName; };
-    IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+    IEffect::Status effectProcessImpl(float* in, float* out, int samples)
+            REQUIRES(mImplMutex) override;
 
   private:
     static const std::vector<Range::AutomaticGainControlV1Range> kRanges;
-    std::shared_ptr<AutomaticGainControlV1SwContext> mContext;
+    std::shared_ptr<AutomaticGainControlV1SwContext> mContext GUARDED_BY(mImplMutex);
     ndk::ScopedAStatus getParameterAutomaticGainControlV1(const AutomaticGainControlV1::Tag& tag,
-                                                          Parameter::Specific* specific);
+                                                          Parameter::Specific* specific)
+            REQUIRES(mImplMutex);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/automaticGainControlV2/Android.bp b/audio/aidl/default/automaticGainControlV2/Android.bp
index 631cf58..ea05152 100644
--- a/audio/aidl/default/automaticGainControlV2/Android.bp
+++ b/audio/aidl/default/automaticGainControlV2/Android.bp
@@ -27,8 +27,6 @@
     name: "libagc2sw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "AutomaticGainControlV2Sw.cpp",
@@ -36,6 +34,6 @@
     ],
     relative_install_path: "soundfx",
     visibility: [
-        "//hardware/interfaces/audio/aidl/default",
+        "//hardware/interfaces/audio/aidl/default:__subpackages__",
     ],
 }
diff --git a/audio/aidl/default/automaticGainControlV2/AutomaticGainControlV2Sw.cpp b/audio/aidl/default/automaticGainControlV2/AutomaticGainControlV2Sw.cpp
index 1e336ac..3ff6e38 100644
--- a/audio/aidl/default/automaticGainControlV2/AutomaticGainControlV2Sw.cpp
+++ b/audio/aidl/default/automaticGainControlV2/AutomaticGainControlV2Sw.cpp
@@ -180,10 +180,6 @@
     return mContext;
 }
 
-std::shared_ptr<EffectContext> AutomaticGainControlV2Sw::getContext() {
-    return mContext;
-}
-
 RetCode AutomaticGainControlV2Sw::releaseContext() {
     if (mContext) {
         mContext.reset();
diff --git a/audio/aidl/default/automaticGainControlV2/AutomaticGainControlV2Sw.h b/audio/aidl/default/automaticGainControlV2/AutomaticGainControlV2Sw.h
index 9aa60ea..863d470 100644
--- a/audio/aidl/default/automaticGainControlV2/AutomaticGainControlV2Sw.h
+++ b/audio/aidl/default/automaticGainControlV2/AutomaticGainControlV2Sw.h
@@ -59,21 +59,24 @@
     }
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
-    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
-    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
-                                            Parameter::Specific* specific) override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+            REQUIRES(mImplMutex) override;
 
-    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
-    std::shared_ptr<EffectContext> getContext() override;
-    RetCode releaseContext() override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+            REQUIRES(mImplMutex) override;
+    RetCode releaseContext() REQUIRES(mImplMutex) override;
 
     std::string getEffectName() override { return kEffectName; };
-    IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+    IEffect::Status effectProcessImpl(float* in, float* out, int samples)
+            REQUIRES(mImplMutex) override;
 
   private:
     static const std::vector<Range::AutomaticGainControlV2Range> kRanges;
-    std::shared_ptr<AutomaticGainControlV2SwContext> mContext;
+    std::shared_ptr<AutomaticGainControlV2SwContext> mContext GUARDED_BY(mImplMutex);
     ndk::ScopedAStatus getParameterAutomaticGainControlV2(const AutomaticGainControlV2::Tag& tag,
-                                                          Parameter::Specific* specific);
+                                                          Parameter::Specific* specific)
+            REQUIRES(mImplMutex);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/bassboost/Android.bp b/audio/aidl/default/bassboost/Android.bp
index 82b2f20..8f53eae 100644
--- a/audio/aidl/default/bassboost/Android.bp
+++ b/audio/aidl/default/bassboost/Android.bp
@@ -27,8 +27,6 @@
     name: "libbassboostsw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "BassBoostSw.cpp",
@@ -36,6 +34,6 @@
     ],
     relative_install_path: "soundfx",
     visibility: [
-        "//hardware/interfaces/audio/aidl/default",
+        "//hardware/interfaces/audio/aidl/default:__subpackages__",
     ],
 }
diff --git a/audio/aidl/default/bassboost/BassBoostSw.cpp b/audio/aidl/default/bassboost/BassBoostSw.cpp
index 6072d89..60adc30 100644
--- a/audio/aidl/default/bassboost/BassBoostSw.cpp
+++ b/audio/aidl/default/bassboost/BassBoostSw.cpp
@@ -151,10 +151,6 @@
     return mContext;
 }
 
-std::shared_ptr<EffectContext> BassBoostSw::getContext() {
-    return mContext;
-}
-
 RetCode BassBoostSw::releaseContext() {
     if (mContext) {
         mContext.reset();
diff --git a/audio/aidl/default/bassboost/BassBoostSw.h b/audio/aidl/default/bassboost/BassBoostSw.h
index 1132472..901e455 100644
--- a/audio/aidl/default/bassboost/BassBoostSw.h
+++ b/audio/aidl/default/bassboost/BassBoostSw.h
@@ -51,21 +51,23 @@
     }
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
-    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
-    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
-                                            Parameter::Specific* specific) override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+            REQUIRES(mImplMutex) override;
 
-    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
-    std::shared_ptr<EffectContext> getContext() override;
-    RetCode releaseContext() override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+            REQUIRES(mImplMutex) override;
+    RetCode releaseContext() REQUIRES(mImplMutex) override;
 
     std::string getEffectName() override { return kEffectName; };
-    IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+    IEffect::Status effectProcessImpl(float* in, float* out, int samples)
+            REQUIRES(mImplMutex) override;
 
   private:
     static const std::vector<Range::BassBoostRange> kRanges;
-    std::shared_ptr<BassBoostSwContext> mContext;
+    std::shared_ptr<BassBoostSwContext> mContext GUARDED_BY(mImplMutex);
     ndk::ScopedAStatus getParameterBassBoost(const BassBoost::Tag& tag,
-                                             Parameter::Specific* specific);
+                                             Parameter::Specific* specific) REQUIRES(mImplMutex);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/bluetooth/DevicePortProxy.cpp b/audio/aidl/default/bluetooth/DevicePortProxy.cpp
index 12e204a..d772c20 100644
--- a/audio/aidl/default/bluetooth/DevicePortProxy.cpp
+++ b/audio/aidl/default/bluetooth/DevicePortProxy.cpp
@@ -14,16 +14,30 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AHAL_BluetoothPortProxy"
+#define LOG_TAG "AHAL_BluetoothAudioPort"
 
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
 #include <audio_utils/primitives.h>
-#include <inttypes.h>
 #include <log/log.h>
 
+#include "BluetoothAudioSessionControl.h"
 #include "core-impl/DevicePortProxy.h"
 
+using aidl::android::hardware::audio::common::SinkMetadata;
+using aidl::android::hardware::audio::common::SourceMetadata;
+using aidl::android::hardware::bluetooth::audio::AudioConfiguration;
+using aidl::android::hardware::bluetooth::audio::BluetoothAudioSessionControl;
+using aidl::android::hardware::bluetooth::audio::BluetoothAudioStatus;
+using aidl::android::hardware::bluetooth::audio::ChannelMode;
+using aidl::android::hardware::bluetooth::audio::PcmConfiguration;
+using aidl::android::hardware::bluetooth::audio::PortStatusCallbacks;
+using aidl::android::hardware::bluetooth::audio::PresentationPosition;
+using aidl::android::hardware::bluetooth::audio::SessionType;
+using aidl::android::media::audio::common::AudioDeviceDescription;
+using aidl::android::media::audio::common::AudioDeviceType;
+using android::base::StringPrintf;
+
 namespace android::bluetooth::audio::aidl {
 
 namespace {
@@ -33,20 +47,6 @@
 
 }  // namespace
 
-using ::aidl::android::hardware::audio::common::SinkMetadata;
-using ::aidl::android::hardware::audio::common::SourceMetadata;
-using ::aidl::android::hardware::bluetooth::audio::AudioConfiguration;
-using ::aidl::android::hardware::bluetooth::audio::BluetoothAudioSessionControl;
-using ::aidl::android::hardware::bluetooth::audio::BluetoothAudioStatus;
-using ::aidl::android::hardware::bluetooth::audio::ChannelMode;
-using ::aidl::android::hardware::bluetooth::audio::PcmConfiguration;
-using ::aidl::android::hardware::bluetooth::audio::PortStatusCallbacks;
-using ::aidl::android::hardware::bluetooth::audio::PresentationPosition;
-using ::aidl::android::hardware::bluetooth::audio::SessionType;
-using ::aidl::android::media::audio::common::AudioDeviceDescription;
-using ::aidl::android::media::audio::common::AudioDeviceType;
-using ::android::base::StringPrintf;
-
 std::ostream& operator<<(std::ostream& os, const BluetoothStreamState& state) {
     switch (state) {
         case BluetoothStreamState::DISABLED:
@@ -254,12 +254,7 @@
     return (mCookie != ::aidl::android::hardware::bluetooth::audio::kObserversCookieUndefined);
 }
 
-bool BluetoothAudioPortAidl::getPreferredDataIntervalUs(size_t* interval_us) const {
-    if (!interval_us) {
-        LOG(ERROR) << __func__ << ": bad input arg";
-        return false;
-    }
-
+bool BluetoothAudioPortAidl::getPreferredDataIntervalUs(size_t& interval_us) const {
     if (!inUse()) {
         LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use";
         return false;
@@ -272,16 +267,11 @@
         return false;
     }
 
-    *interval_us = hal_audio_cfg.get<AudioConfiguration::pcmConfig>().dataIntervalUs;
+    interval_us = hal_audio_cfg.get<AudioConfiguration::pcmConfig>().dataIntervalUs;
     return true;
 }
 
-bool BluetoothAudioPortAidl::loadAudioConfig(PcmConfiguration* audio_cfg) const {
-    if (!audio_cfg) {
-        LOG(ERROR) << __func__ << ": bad input arg";
-        return false;
-    }
-
+bool BluetoothAudioPortAidl::loadAudioConfig(PcmConfiguration& audio_cfg) {
     if (!inUse()) {
         LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use";
         return false;
@@ -293,15 +283,26 @@
         LOG(ERROR) << __func__ << ": unsupported audio cfg tag";
         return false;
     }
-    *audio_cfg = hal_audio_cfg.get<AudioConfiguration::pcmConfig>();
+    audio_cfg = hal_audio_cfg.get<AudioConfiguration::pcmConfig>();
     LOG(VERBOSE) << __func__ << debugMessage() << ", state*=" << getState() << ", PcmConfig=["
-                 << audio_cfg->toString() << "]";
-    if (audio_cfg->channelMode == ChannelMode::UNKNOWN) {
+                 << audio_cfg.toString() << "]";
+    if (audio_cfg.channelMode == ChannelMode::UNKNOWN) {
         return false;
     }
     return true;
 }
 
+bool BluetoothAudioPortAidlOut::loadAudioConfig(PcmConfiguration& audio_cfg) {
+    if (!BluetoothAudioPortAidl::loadAudioConfig(audio_cfg)) return false;
+    // WAR to support Mono / 16 bits per sample as the Bluetooth stack requires
+    if (audio_cfg.channelMode == ChannelMode::MONO && audio_cfg.bitsPerSample == 16) {
+        mIsStereoToMono = true;
+        audio_cfg.channelMode = ChannelMode::STEREO;
+        LOG(INFO) << __func__ << ": force channels = to be AUDIO_CHANNEL_OUT_STEREO";
+    }
+    return true;
+}
+
 bool BluetoothAudioPortAidl::standby() {
     if (!inUse()) {
         LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use";
@@ -435,7 +436,7 @@
                 retval = condWaitState(BluetoothStreamState::SUSPENDING);
             } else {
                 LOG(ERROR) << __func__ << debugMessage() << ", state=" << getState()
-                           << " Hal fails";
+                           << " failure to suspend stream";
             }
         }
     }
diff --git a/audio/aidl/default/bluetooth/ModuleBluetooth.cpp b/audio/aidl/default/bluetooth/ModuleBluetooth.cpp
index bfe7ca0..9084b30 100644
--- a/audio/aidl/default/bluetooth/ModuleBluetooth.cpp
+++ b/audio/aidl/default/bluetooth/ModuleBluetooth.cpp
@@ -18,42 +18,112 @@
 
 #include <android-base/logging.h>
 
+#include "BluetoothAudioSession.h"
 #include "core-impl/ModuleBluetooth.h"
 #include "core-impl/StreamBluetooth.h"
 
-namespace aidl::android::hardware::audio::core {
-
 using aidl::android::hardware::audio::common::SinkMetadata;
 using aidl::android::hardware::audio::common::SourceMetadata;
+using aidl::android::hardware::bluetooth::audio::ChannelMode;
+using aidl::android::hardware::bluetooth::audio::PcmConfiguration;
+using aidl::android::media::audio::common::AudioChannelLayout;
+using aidl::android::media::audio::common::AudioConfigBase;
+using aidl::android::media::audio::common::AudioDeviceDescription;
+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::AudioIoFlags;
 using aidl::android::media::audio::common::AudioOffloadInfo;
+using aidl::android::media::audio::common::AudioPort;
+using aidl::android::media::audio::common::AudioPortConfig;
+using aidl::android::media::audio::common::AudioPortExt;
+using aidl::android::media::audio::common::AudioProfile;
+using aidl::android::media::audio::common::Int;
 using aidl::android::media::audio::common::MicrophoneInfo;
+using aidl::android::media::audio::common::PcmType;
+using android::bluetooth::audio::aidl::BluetoothAudioPortAidl;
+using android::bluetooth::audio::aidl::BluetoothAudioPortAidlIn;
+using android::bluetooth::audio::aidl::BluetoothAudioPortAidlOut;
+
+// TODO(b/312265159) bluetooth audio should be in its own process
+// Remove this and the shared_libs when that happens
+extern "C" binder_status_t createIBluetoothAudioProviderFactory();
+
+namespace aidl::android::hardware::audio::core {
+
+namespace {
+
+PcmType pcmTypeFromBitsPerSample(int8_t bitsPerSample) {
+    if (bitsPerSample == 8)
+        return PcmType::UINT_8_BIT;
+    else if (bitsPerSample == 16)
+        return PcmType::INT_16_BIT;
+    else if (bitsPerSample == 24)
+        return PcmType::INT_24_BIT;
+    else if (bitsPerSample == 32)
+        return PcmType::INT_32_BIT;
+    ALOGE("Unsupported bitsPerSample: %d", bitsPerSample);
+    return PcmType::DEFAULT;
+}
+
+AudioChannelLayout channelLayoutFromChannelMode(ChannelMode mode) {
+    if (mode == ChannelMode::MONO) {
+        return AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
+                AudioChannelLayout::LAYOUT_MONO);
+    } else if (mode == ChannelMode::STEREO || mode == ChannelMode::DUALMONO) {
+        return AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
+                AudioChannelLayout::LAYOUT_STEREO);
+    }
+    ALOGE("Unsupported channel mode: %s", toString(mode).c_str());
+    return AudioChannelLayout{};
+}
+
+}  // namespace
+
+ModuleBluetooth::ModuleBluetooth(std::unique_ptr<Module::Configuration>&& config)
+    : Module(Type::BLUETOOTH, std::move(config)) {
+    // TODO(b/312265159) bluetooth audio should be in its own process
+    // Remove this and the shared_libs when that happens
+    binder_status_t status = createIBluetoothAudioProviderFactory();
+    if (status != STATUS_OK) {
+        LOG(ERROR) << "Failed to create bluetooth audio provider factory. Status: "
+                   << ::android::statusToString(status);
+    }
+}
 
 ndk::ScopedAStatus ModuleBluetooth::getBluetoothA2dp(
         std::shared_ptr<IBluetoothA2dp>* _aidl_return) {
-    if (!mBluetoothA2dp) {
-        auto handle = ndk::SharedRefBase::make<BluetoothA2dp>();
-        handle->registerHandler(std::bind(&ModuleBluetooth::bluetoothParametersUpdated, this));
-        mBluetoothA2dp = handle;
-    }
-    *_aidl_return = mBluetoothA2dp.getInstance();
+    *_aidl_return = getBtA2dp().getInstance();
     LOG(DEBUG) << __func__ << ": returning instance of IBluetoothA2dp: " << _aidl_return->get();
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus ModuleBluetooth::getBluetoothLe(std::shared_ptr<IBluetoothLe>* _aidl_return) {
+    *_aidl_return = getBtLe().getInstance();
+    LOG(DEBUG) << __func__ << ": returning instance of IBluetoothLe: " << _aidl_return->get();
+    return ndk::ScopedAStatus::ok();
+}
+
+ChildInterface<BluetoothA2dp>& ModuleBluetooth::getBtA2dp() {
+    if (!mBluetoothA2dp) {
+        auto handle = ndk::SharedRefBase::make<BluetoothA2dp>();
+        handle->registerHandler(std::bind(&ModuleBluetooth::bluetoothParametersUpdated, this));
+        mBluetoothA2dp = handle;
+    }
+    return mBluetoothA2dp;
+}
+
+ChildInterface<BluetoothLe>& ModuleBluetooth::getBtLe() {
     if (!mBluetoothLe) {
         auto handle = ndk::SharedRefBase::make<BluetoothLe>();
         handle->registerHandler(std::bind(&ModuleBluetooth::bluetoothParametersUpdated, this));
         mBluetoothLe = handle;
     }
-    *_aidl_return = mBluetoothLe.getInstance();
-    LOG(DEBUG) << __func__ << ": returning instance of IBluetoothLe: " << _aidl_return->get();
-    return ndk::ScopedAStatus::ok();
+    return mBluetoothLe;
 }
 
-Module::BtProfileHandles ModuleBluetooth::getBtProfileManagerHandles() {
-    return std::make_tuple(std::weak_ptr<IBluetooth>(), mBluetoothA2dp.getInstance(),
-                           mBluetoothLe.getInstance());
+ModuleBluetooth::BtProfileHandles ModuleBluetooth::getBtProfileManagerHandles() {
+    return std::make_tuple(std::weak_ptr<IBluetooth>(), getBtA2dp().getPtr(), getBtLe().getPtr());
 }
 
 ndk::ScopedAStatus ModuleBluetooth::getMicMute(bool* _aidl_return __unused) {
@@ -66,18 +136,130 @@
     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
 }
 
+ndk::ScopedAStatus ModuleBluetooth::setAudioPortConfig(const AudioPortConfig& in_requested,
+                                                       AudioPortConfig* out_suggested,
+                                                       bool* _aidl_return) {
+    auto fillConfig = [this](const AudioPort& port, AudioPortConfig* config) {
+        if (port.ext.getTag() == AudioPortExt::device) {
+            CachedProxy proxy;
+            auto status = findOrCreateProxy(port, proxy);
+            if (status.isOk()) {
+                const auto& pcmConfig = proxy.pcmConfig;
+                LOG(DEBUG) << "setAudioPortConfig: suggesting port config from "
+                           << pcmConfig.toString();
+                const auto pcmType = pcmTypeFromBitsPerSample(pcmConfig.bitsPerSample);
+                const auto channelMask = channelLayoutFromChannelMode(pcmConfig.channelMode);
+                if (pcmType != PcmType::DEFAULT && channelMask != AudioChannelLayout{}) {
+                    config->format =
+                            AudioFormatDescription{.type = AudioFormatType::PCM, .pcm = pcmType};
+                    config->channelMask = channelMask;
+                    config->sampleRate = Int{.value = pcmConfig.sampleRateHz};
+                    config->flags = port.flags;
+                    config->ext = port.ext;
+                    return true;
+                }
+            }
+        }
+        return generateDefaultPortConfig(port, config);
+    };
+    return Module::setAudioPortConfigImpl(in_requested, fillConfig, out_suggested, _aidl_return);
+}
+
+ndk::ScopedAStatus ModuleBluetooth::checkAudioPatchEndpointsMatch(
+        const std::vector<AudioPortConfig*>& sources, const std::vector<AudioPortConfig*>& sinks) {
+    // Both sources and sinks must be non-empty, this is guaranteed by 'setAudioPatch'.
+    const bool isInput = sources[0]->ext.getTag() == AudioPortExt::device;
+    const int32_t devicePortId = isInput ? sources[0]->portId : sinks[0]->portId;
+    const auto proxyIt = mProxies.find(devicePortId);
+    if (proxyIt == mProxies.end()) return ndk::ScopedAStatus::ok();
+    const auto& pcmConfig = proxyIt->second.pcmConfig;
+    const AudioPortConfig* mixPortConfig = isInput ? sinks[0] : sources[0];
+    if (!StreamBluetooth::checkConfigParams(
+                pcmConfig, AudioConfigBase{.sampleRate = mixPortConfig->sampleRate->value,
+                                           .channelMask = *(mixPortConfig->channelMask),
+                                           .format = *(mixPortConfig->format)})) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    }
+    if (int32_t handle = mixPortConfig->ext.get<AudioPortExt::mix>().handle; handle > 0) {
+        mConnections.insert(std::pair(handle, devicePortId));
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+void ModuleBluetooth::onExternalDeviceConnectionChanged(const AudioPort& audioPort,
+                                                        bool connected) {
+    if (!connected) mProxies.erase(audioPort.id);
+}
+
 ndk::ScopedAStatus ModuleBluetooth::createInputStream(
         StreamContext&& context, const SinkMetadata& sinkMetadata,
         const std::vector<MicrophoneInfo>& microphones, std::shared_ptr<StreamIn>* result) {
+    CachedProxy proxy;
+    RETURN_STATUS_IF_ERROR(fetchAndCheckProxy(context, proxy));
     return createStreamInstance<StreamInBluetooth>(result, std::move(context), sinkMetadata,
-                                                   microphones, getBtProfileManagerHandles());
+                                                   microphones, getBtProfileManagerHandles(),
+                                                   proxy.ptr, proxy.pcmConfig);
 }
 
 ndk::ScopedAStatus ModuleBluetooth::createOutputStream(
         StreamContext&& context, const SourceMetadata& sourceMetadata,
         const std::optional<AudioOffloadInfo>& offloadInfo, std::shared_ptr<StreamOut>* result) {
+    CachedProxy proxy;
+    RETURN_STATUS_IF_ERROR(fetchAndCheckProxy(context, proxy));
     return createStreamInstance<StreamOutBluetooth>(result, std::move(context), sourceMetadata,
-                                                    offloadInfo, getBtProfileManagerHandles());
+                                                    offloadInfo, getBtProfileManagerHandles(),
+                                                    proxy.ptr, proxy.pcmConfig);
+}
+
+ndk::ScopedAStatus ModuleBluetooth::populateConnectedDevicePort(AudioPort* audioPort,
+                                                                int32_t nextPortId) {
+    if (audioPort->ext.getTag() != AudioPortExt::device) {
+        LOG(ERROR) << __func__ << ": not a device port: " << audioPort->toString();
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+    if (!::aidl::android::hardware::bluetooth::audio::BluetoothAudioSession::IsAidlAvailable()) {
+        LOG(ERROR) << __func__ << ": IBluetoothAudioProviderFactory AIDL service not available";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    const auto& devicePort = audioPort->ext.get<AudioPortExt::device>();
+    const auto& description = devicePort.device.type;
+    // This method must return an error when the device can not be connected.
+    if (description.connection == AudioDeviceDescription::CONNECTION_BT_A2DP) {
+        bool isA2dpEnabled = false;
+        if (!!mBluetoothA2dp) {
+            RETURN_STATUS_IF_ERROR((*mBluetoothA2dp).isEnabled(&isA2dpEnabled));
+        }
+        LOG(DEBUG) << __func__ << ": isA2dpEnabled: " << isA2dpEnabled;
+        if (!isA2dpEnabled) return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    } else if (description.connection == AudioDeviceDescription::CONNECTION_BT_LE) {
+        bool isLeEnabled = false;
+        if (!!mBluetoothLe) {
+            RETURN_STATUS_IF_ERROR((*mBluetoothLe).isEnabled(&isLeEnabled));
+        }
+        LOG(DEBUG) << __func__ << ": isLeEnabled: " << isLeEnabled;
+        if (!isLeEnabled) return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    } else if (description.connection == AudioDeviceDescription::CONNECTION_WIRELESS &&
+               description.type == AudioDeviceType::OUT_HEARING_AID) {
+        // Hearing aids can use a number of profiles, no single switch exists.
+    } else {
+        LOG(ERROR) << __func__ << ": unsupported device type: " << audioPort->toString();
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+    CachedProxy proxy;
+    RETURN_STATUS_IF_ERROR(createProxy(*audioPort, nextPortId, proxy));
+    // Since the device is already connected and configured by the BT stack, provide
+    // the current configuration instead of all possible profiles.
+    const auto& pcmConfig = proxy.pcmConfig;
+    audioPort->profiles.clear();
+    audioPort->profiles.push_back(
+            AudioProfile{.format = AudioFormatDescription{.type = AudioFormatType::PCM,
+                                                          .pcm = pcmTypeFromBitsPerSample(
+                                                                  pcmConfig.bitsPerSample)},
+                         .channelMasks = std::vector<AudioChannelLayout>(
+                                 {channelLayoutFromChannelMode(pcmConfig.channelMode)}),
+                         .sampleRates = std::vector<int>({pcmConfig.sampleRateHz})});
+    LOG(DEBUG) << __func__ << ": " << audioPort->toString();
+    return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus ModuleBluetooth::onMasterMuteChanged(bool) {
@@ -90,4 +272,77 @@
     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
 }
 
+int32_t ModuleBluetooth::getNominalLatencyMs(const AudioPortConfig& portConfig) {
+    const auto connectionsIt = mConnections.find(portConfig.ext.get<AudioPortExt::mix>().handle);
+    if (connectionsIt != mConnections.end()) {
+        const auto proxyIt = mProxies.find(connectionsIt->second);
+        if (proxyIt != mProxies.end()) {
+            auto proxy = proxyIt->second.ptr;
+            size_t dataIntervalUs = 0;
+            if (!proxy->getPreferredDataIntervalUs(dataIntervalUs)) {
+                LOG(WARNING) << __func__ << ": could not fetch preferred data interval";
+            }
+            const bool isInput = portConfig.flags->getTag() == AudioIoFlags::input;
+            return isInput ? StreamInBluetooth::getNominalLatencyMs(dataIntervalUs)
+                           : StreamOutBluetooth::getNominalLatencyMs(dataIntervalUs);
+        }
+    }
+    LOG(ERROR) << __func__ << ": no connection or proxy found for " << portConfig.toString();
+    return Module::getNominalLatencyMs(portConfig);
+}
+
+ndk::ScopedAStatus ModuleBluetooth::createProxy(const AudioPort& audioPort, int32_t instancePortId,
+                                                CachedProxy& proxy) {
+    const bool isInput = audioPort.flags.getTag() == AudioIoFlags::input;
+    proxy.ptr = isInput ? std::shared_ptr<BluetoothAudioPortAidl>(
+                                  std::make_shared<BluetoothAudioPortAidlIn>())
+                        : std::shared_ptr<BluetoothAudioPortAidl>(
+                                  std::make_shared<BluetoothAudioPortAidlOut>());
+    const auto& devicePort = audioPort.ext.get<AudioPortExt::device>();
+    if (const auto device = devicePort.device.type; !proxy.ptr->registerPort(device)) {
+        LOG(ERROR) << __func__ << ": failed to register BT port for " << device.toString();
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    if (!proxy.ptr->loadAudioConfig(proxy.pcmConfig)) {
+        LOG(ERROR) << __func__ << ": state=" << proxy.ptr->getState()
+                   << ", failed to load audio config";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    mProxies.insert(std::pair(instancePortId, proxy));
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ModuleBluetooth::fetchAndCheckProxy(const StreamContext& context,
+                                                       CachedProxy& proxy) {
+    const auto connectionsIt = mConnections.find(context.getMixPortHandle());
+    if (connectionsIt != mConnections.end()) {
+        const auto proxyIt = mProxies.find(connectionsIt->second);
+        if (proxyIt != mProxies.end()) {
+            proxy = proxyIt->second;
+            mProxies.erase(proxyIt);
+        }
+        mConnections.erase(connectionsIt);
+    }
+    if (proxy.ptr != nullptr) {
+        if (!StreamBluetooth::checkConfigParams(
+                    proxy.pcmConfig, AudioConfigBase{.sampleRate = context.getSampleRate(),
+                                                     .channelMask = context.getChannelLayout(),
+                                                     .format = context.getFormat()})) {
+            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+        }
+    }
+    // Not having a proxy is OK, it may happen in VTS tests when streams are opened on unconnected
+    // mix ports.
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ModuleBluetooth::findOrCreateProxy(const AudioPort& audioPort,
+                                                      CachedProxy& proxy) {
+    if (auto proxyIt = mProxies.find(audioPort.id); proxyIt != mProxies.end()) {
+        proxy = proxyIt->second;
+        return ndk::ScopedAStatus::ok();
+    }
+    return createProxy(audioPort, audioPort.id, proxy);
+}
+
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/bluetooth/StreamBluetooth.cpp b/audio/aidl/default/bluetooth/StreamBluetooth.cpp
index 91a33c2..a73af1b 100644
--- a/audio/aidl/default/bluetooth/StreamBluetooth.cpp
+++ b/audio/aidl/default/bluetooth/StreamBluetooth.cpp
@@ -14,88 +14,69 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AHAL_StreamBluetooth"
+#include <algorithm>
 
+#define LOG_TAG "AHAL_StreamBluetooth"
 #include <Utils.h>
 #include <android-base/logging.h>
 #include <audio_utils/clock.h>
 
-#include "BluetoothAudioSessionControl.h"
+#include "BluetoothAudioSession.h"
 #include "core-impl/StreamBluetooth.h"
 
-namespace aidl::android::hardware::audio::core {
+using aidl::android::hardware::audio::common::frameCountFromDurationUs;
+using aidl::android::hardware::audio::common::SinkMetadata;
+using aidl::android::hardware::audio::common::SourceMetadata;
+using aidl::android::hardware::audio::core::VendorParameter;
+using aidl::android::hardware::bluetooth::audio::ChannelMode;
+using aidl::android::hardware::bluetooth::audio::PcmConfiguration;
+using aidl::android::hardware::bluetooth::audio::PresentationPosition;
+using aidl::android::media::audio::common::AudioChannelLayout;
+using aidl::android::media::audio::common::AudioConfigBase;
+using aidl::android::media::audio::common::AudioDevice;
+using aidl::android::media::audio::common::AudioDeviceAddress;
+using aidl::android::media::audio::common::AudioFormatDescription;
+using aidl::android::media::audio::common::AudioFormatType;
+using aidl::android::media::audio::common::AudioOffloadInfo;
+using aidl::android::media::audio::common::MicrophoneDynamicInfo;
+using aidl::android::media::audio::common::MicrophoneInfo;
+using android::bluetooth::audio::aidl::BluetoothAudioPortAidl;
+using android::bluetooth::audio::aidl::BluetoothAudioPortAidlIn;
+using android::bluetooth::audio::aidl::BluetoothAudioPortAidlOut;
+using android::bluetooth::audio::aidl::BluetoothStreamState;
 
-using ::aidl::android::hardware::audio::common::SinkMetadata;
-using ::aidl::android::hardware::audio::common::SourceMetadata;
-using ::aidl::android::hardware::audio::core::VendorParameter;
-using ::aidl::android::hardware::bluetooth::audio::ChannelMode;
-using ::aidl::android::hardware::bluetooth::audio::PcmConfiguration;
-using ::aidl::android::hardware::bluetooth::audio::PresentationPosition;
-using ::aidl::android::media::audio::common::AudioChannelLayout;
-using ::aidl::android::media::audio::common::AudioDevice;
-using ::aidl::android::media::audio::common::AudioDeviceAddress;
-using ::aidl::android::media::audio::common::AudioFormatDescription;
-using ::aidl::android::media::audio::common::AudioFormatType;
-using ::aidl::android::media::audio::common::AudioOffloadInfo;
-using ::aidl::android::media::audio::common::MicrophoneDynamicInfo;
-using ::aidl::android::media::audio::common::MicrophoneInfo;
-using ::android::bluetooth::audio::aidl::BluetoothAudioPortAidl;
-using ::android::bluetooth::audio::aidl::BluetoothAudioPortAidlIn;
-using ::android::bluetooth::audio::aidl::BluetoothAudioPortAidlOut;
-using ::android::bluetooth::audio::aidl::BluetoothStreamState;
+namespace aidl::android::hardware::audio::core {
 
 constexpr int kBluetoothDefaultInputBufferMs = 20;
 constexpr int kBluetoothDefaultOutputBufferMs = 10;
 // constexpr int kBluetoothSpatializerOutputBufferMs = 10;
+constexpr int kBluetoothDefaultRemoteDelayMs = 200;
 
-size_t getFrameCount(uint64_t durationUs, uint32_t sampleRate) {
-    return (durationUs * sampleRate) / 1000000;
-}
-
-// pcm configuration params are not really used by the module
 StreamBluetooth::StreamBluetooth(StreamContext* context, const Metadata& metadata,
-                                 Module::BtProfileHandles&& btHandles)
+                                 ModuleBluetooth::BtProfileHandles&& btHandles,
+                                 const std::shared_ptr<BluetoothAudioPortAidl>& btDeviceProxy,
+                                 const PcmConfiguration& pcmConfig)
     : StreamCommonImpl(context, metadata),
-      mSampleRate(getContext().getSampleRate()),
-      mChannelLayout(getContext().getChannelLayout()),
-      mFormat(getContext().getFormat()),
       mFrameSizeBytes(getContext().getFrameSize()),
       mIsInput(isInput(metadata)),
-      mBluetoothA2dp(std::move(std::get<Module::BtInterface::BTA2DP>(btHandles))),
-      mBluetoothLe(std::move(std::get<Module::BtInterface::BTLE>(btHandles))) {
-    mPreferredDataIntervalUs =
-            mIsInput ? kBluetoothDefaultInputBufferMs : kBluetoothDefaultOutputBufferMs;
-    mPreferredFrameCount = getFrameCount(mPreferredDataIntervalUs, mSampleRate);
-    mIsInitialized = false;
-    mIsReadyToClose = false;
-}
+      mBluetoothA2dp(std::move(std::get<ModuleBluetooth::BtInterface::BTA2DP>(btHandles))),
+      mBluetoothLe(std::move(std::get<ModuleBluetooth::BtInterface::BTLE>(btHandles))),
+      mPreferredDataIntervalUs(pcmConfig.dataIntervalUs != 0
+                                       ? pcmConfig.dataIntervalUs
+                                       : (mIsInput ? kBluetoothDefaultInputBufferMs
+                                                   : kBluetoothDefaultOutputBufferMs) *
+                                                 1000),
+      mPreferredFrameCount(
+              frameCountFromDurationUs(mPreferredDataIntervalUs, pcmConfig.sampleRateHz)),
+      mBtDeviceProxy(btDeviceProxy) {}
 
 ::android::status_t StreamBluetooth::init() {
-    return ::android::OK;  // defering this till we get AudioDeviceDescription
-}
-
-const StreamCommonInterface::ConnectedDevices& StreamBluetooth::getConnectedDevices() const {
     std::lock_guard guard(mLock);
-    return StreamCommonImpl::getConnectedDevices();
-}
-
-ndk::ScopedAStatus StreamBluetooth::setConnectedDevices(
-        const std::vector<AudioDevice>& connectedDevices) {
-    if (mIsInput && connectedDevices.size() > 1) {
-        LOG(ERROR) << __func__ << ": wrong device size(" << connectedDevices.size()
-                   << ") for input stream";
-        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    if (mBtDeviceProxy == nullptr) {
+        // This is a normal situation in VTS tests.
+        LOG(INFO) << __func__ << ": no BT HAL proxy, stream is non-functional";
     }
-    for (const auto& connectedDevice : connectedDevices) {
-        if (connectedDevice.address.getTag() != AudioDeviceAddress::mac) {
-            LOG(ERROR) << __func__ << ": bad device address" << connectedDevice.address.toString();
-            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
-        }
-    }
-    std::lock_guard guard(mLock);
-    RETURN_STATUS_IF_ERROR(StreamCommonImpl::setConnectedDevices(connectedDevices));
-    mIsInitialized = false;  // updated connected device list, need initialization
-    return ndk::ScopedAStatus::ok();
+    return ::android::OK;
 }
 
 ::android::status_t StreamBluetooth::drain(StreamDescriptor::DrainMode) {
@@ -115,167 +96,111 @@
 ::android::status_t StreamBluetooth::transfer(void* buffer, size_t frameCount,
                                               size_t* actualFrameCount, int32_t* latencyMs) {
     std::lock_guard guard(mLock);
-    if (!mIsInitialized || mIsReadyToClose) {
-        // 'setConnectedDevices' has been called or stream is ready to close, so no transfers
+    if (mBtDeviceProxy == nullptr || mBtDeviceProxy->getState() == BluetoothStreamState::DISABLED) {
         *actualFrameCount = 0;
         *latencyMs = StreamDescriptor::LATENCY_UNKNOWN;
         return ::android::OK;
     }
     *actualFrameCount = 0;
     *latencyMs = 0;
-    for (auto proxy : mBtDeviceProxies) {
-        if (!proxy->start()) {
-            LOG(ERROR) << __func__ << ": state = " << proxy->getState() << " failed to start ";
-            return -EIO;
-        }
-        const size_t fc = std::min(frameCount, mPreferredFrameCount);
-        const size_t bytesToTransfer = fc * mFrameSizeBytes;
-        if (mIsInput) {
-            const size_t totalRead = proxy->readData(buffer, bytesToTransfer);
-            *actualFrameCount = std::max(*actualFrameCount, totalRead / mFrameSizeBytes);
-        } else {
-            const size_t totalWrite = proxy->writeData(buffer, bytesToTransfer);
-            *actualFrameCount = std::max(*actualFrameCount, totalWrite / mFrameSizeBytes);
-        }
-        PresentationPosition presentation_position;
-        if (!proxy->getPresentationPosition(presentation_position)) {
-            LOG(ERROR) << __func__ << ": getPresentationPosition returned error ";
-            return ::android::UNKNOWN_ERROR;
-        }
-        *latencyMs =
-                std::max(*latencyMs, (int32_t)(presentation_position.remoteDeviceAudioDelayNanos /
-                                               NANOS_PER_MILLISECOND));
+    if (!mBtDeviceProxy->start()) {
+        LOG(ERROR) << __func__ << ": state= " << mBtDeviceProxy->getState() << " failed to start";
+        return -EIO;
     }
+    const size_t fc = std::min(frameCount, mPreferredFrameCount);
+    const size_t bytesToTransfer = fc * mFrameSizeBytes;
+    if (mIsInput) {
+        const size_t totalRead = mBtDeviceProxy->readData(buffer, bytesToTransfer);
+        *actualFrameCount = std::max(*actualFrameCount, totalRead / mFrameSizeBytes);
+    } else {
+        const size_t totalWrite = mBtDeviceProxy->writeData(buffer, bytesToTransfer);
+        *actualFrameCount = std::max(*actualFrameCount, totalWrite / mFrameSizeBytes);
+    }
+    PresentationPosition presentation_position;
+    if (!mBtDeviceProxy->getPresentationPosition(presentation_position)) {
+        presentation_position.remoteDeviceAudioDelayNanos =
+                kBluetoothDefaultRemoteDelayMs * NANOS_PER_MILLISECOND;
+        LOG(WARNING) << __func__ << ": getPresentationPosition failed, latency info is unavailable";
+    }
+    // TODO(b/317117580): incorporate logic from
+    //                    packages/modules/Bluetooth/system/audio_bluetooth_hw/stream_apis.cc
+    //                    out_calculate_feeding_delay_ms / in_calculate_starving_delay_ms
+    *latencyMs = std::max(*latencyMs, (int32_t)(presentation_position.remoteDeviceAudioDelayNanos /
+                                                NANOS_PER_MILLISECOND));
     return ::android::OK;
 }
 
-::android::status_t StreamBluetooth::initialize() {
-    if (!::aidl::android::hardware::bluetooth::audio::BluetoothAudioSession::IsAidlAvailable()) {
-        LOG(ERROR) << __func__ << ": IBluetoothAudioProviderFactory service not available";
-        return ::android::UNKNOWN_ERROR;
-    }
-    if (StreamCommonImpl::getConnectedDevices().empty()) {
-        LOG(ERROR) << __func__ << ", has no connected devices";
-        return ::android::NO_INIT;
-    }
-    // unregister older proxies (if any)
-    for (auto proxy : mBtDeviceProxies) {
-        proxy->stop();
-        proxy->unregisterPort();
-    }
-    mBtDeviceProxies.clear();
-    for (auto it = StreamCommonImpl::getConnectedDevices().begin();
-         it != StreamCommonImpl::getConnectedDevices().end(); ++it) {
-        std::shared_ptr<BluetoothAudioPortAidl> proxy =
-                mIsInput ? std::shared_ptr<BluetoothAudioPortAidl>(
-                                   std::make_shared<BluetoothAudioPortAidlIn>())
-                         : std::shared_ptr<BluetoothAudioPortAidl>(
-                                   std::make_shared<BluetoothAudioPortAidlOut>());
-        if (proxy->registerPort(it->type)) {
-            LOG(ERROR) << __func__ << ": cannot init HAL";
-            return ::android::UNKNOWN_ERROR;
-        }
-        PcmConfiguration config;
-        if (!proxy->loadAudioConfig(&config)) {
-            LOG(ERROR) << __func__ << ": state=" << proxy->getState()
-                       << " failed to get audio config";
-            return ::android::UNKNOWN_ERROR;
-        }
-        // TODO: Ensure minimum duration for spatialized output?
-        // WAR to support Mono / 16 bits per sample as the Bluetooth stack required
-        if (!mIsInput && config.channelMode == ChannelMode::MONO && config.bitsPerSample == 16) {
-            proxy->forcePcmStereoToMono(true);
-            config.channelMode = ChannelMode::STEREO;
-            LOG(INFO) << __func__ << ": force channels = to be AUDIO_CHANNEL_OUT_STEREO";
-        }
-        if (!checkConfigParams(config)) {
-            LOG(ERROR) << __func__ << " checkConfigParams failed";
-            return ::android::UNKNOWN_ERROR;
-        }
-        mBtDeviceProxies.push_back(std::move(proxy));
-    }
-    mIsInitialized = true;
-    return ::android::OK;
-}
-
-bool StreamBluetooth::checkConfigParams(
-        ::aidl::android::hardware::bluetooth::audio::PcmConfiguration& config) {
-    if ((int)mSampleRate != config.sampleRateHz) {
-        LOG(ERROR) << __func__ << ": Sample Rate mismatch, stream val = " << mSampleRate
-                   << " hal val = " << config.sampleRateHz;
+// static
+bool StreamBluetooth::checkConfigParams(const PcmConfiguration& pcmConfig,
+                                        const AudioConfigBase& config) {
+    if ((int)config.sampleRate != pcmConfig.sampleRateHz) {
+        LOG(ERROR) << __func__ << ": sample rate mismatch, stream value=" << config.sampleRate
+                   << ", BT HAL value=" << pcmConfig.sampleRateHz;
         return false;
     }
-    auto channelCount = aidl::android::hardware::audio::common::getChannelCount(mChannelLayout);
-    if ((config.channelMode == ChannelMode::MONO && channelCount != 1) ||
-        (config.channelMode == ChannelMode::STEREO && channelCount != 2)) {
-        LOG(ERROR) << __func__ << ": Channel count mismatch, stream val = " << channelCount
-                   << " hal val = " << toString(config.channelMode);
+    const auto channelCount =
+            aidl::android::hardware::audio::common::getChannelCount(config.channelMask);
+    if ((pcmConfig.channelMode == ChannelMode::MONO && channelCount != 1) ||
+        (pcmConfig.channelMode == ChannelMode::STEREO && channelCount != 2)) {
+        LOG(ERROR) << __func__ << ": Channel count mismatch, stream value=" << channelCount
+                   << ", BT HAL value=" << toString(pcmConfig.channelMode);
         return false;
     }
-    if (mFormat.type != AudioFormatType::PCM) {
-        LOG(ERROR) << __func__ << ": unexpected format type "
-                   << aidl::android::media::audio::common::toString(mFormat.type);
+    if (config.format.type != AudioFormatType::PCM) {
+        LOG(ERROR) << __func__
+                   << ": unexpected stream format type: " << toString(config.format.type);
         return false;
     }
-    int8_t bps = aidl::android::hardware::audio::common::getPcmSampleSizeInBytes(mFormat.pcm) * 8;
-    if (bps != config.bitsPerSample) {
-        LOG(ERROR) << __func__ << ": bits per sample mismatch, stream val = " << bps
-                   << " hal val = " << config.bitsPerSample;
+    const int8_t bitsPerSample =
+            aidl::android::hardware::audio::common::getPcmSampleSizeInBytes(config.format.pcm) * 8;
+    if (bitsPerSample != pcmConfig.bitsPerSample) {
+        LOG(ERROR) << __func__ << ": bits per sample mismatch, stream value=" << bitsPerSample
+                   << ", BT HAL value=" << pcmConfig.bitsPerSample;
         return false;
     }
-    if (config.dataIntervalUs > 0) {
-        mPreferredDataIntervalUs =
-                std::min((int32_t)mPreferredDataIntervalUs, config.dataIntervalUs);
-        mPreferredFrameCount = getFrameCount(mPreferredDataIntervalUs, mSampleRate);
-    }
     return true;
 }
 
 ndk::ScopedAStatus StreamBluetooth::prepareToClose() {
     std::lock_guard guard(mLock);
-    mIsReadyToClose = true;
+    if (mBtDeviceProxy != nullptr) {
+        if (mBtDeviceProxy->getState() != BluetoothStreamState::DISABLED) {
+            mBtDeviceProxy->stop();
+        }
+    }
     return ndk::ScopedAStatus::ok();
 }
 
 ::android::status_t StreamBluetooth::standby() {
     std::lock_guard guard(mLock);
-    if (!mIsInitialized) {
-        if (auto status = initialize(); status != ::android::OK) return status;
-    }
-    for (auto proxy : mBtDeviceProxies) {
-        if (!proxy->suspend()) {
-            LOG(ERROR) << __func__ << ": state = " << proxy->getState() << " failed to stand by ";
-            return -EIO;
-        }
-    }
+    if (mBtDeviceProxy != nullptr) mBtDeviceProxy->suspend();
     return ::android::OK;
 }
 
 ::android::status_t StreamBluetooth::start() {
     std::lock_guard guard(mLock);
-    if (!mIsInitialized) return initialize();
+    if (mBtDeviceProxy != nullptr) mBtDeviceProxy->start();
     return ::android::OK;
 }
 
 void StreamBluetooth::shutdown() {
     std::lock_guard guard(mLock);
-    for (auto proxy : mBtDeviceProxies) {
-        proxy->stop();
-        proxy->unregisterPort();
+    if (mBtDeviceProxy != nullptr) {
+        mBtDeviceProxy->stop();
+        mBtDeviceProxy = nullptr;
     }
-    mBtDeviceProxies.clear();
 }
 
 ndk::ScopedAStatus StreamBluetooth::updateMetadataCommon(const Metadata& metadata) {
     std::lock_guard guard(mLock);
-    if (!mIsInitialized) return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    if (mBtDeviceProxy == nullptr) {
+        return ndk::ScopedAStatus::ok();
+    }
     bool isOk = true;
     if (isInput(metadata)) {
-        isOk = mBtDeviceProxies[0]->updateSinkMetadata(std::get<SinkMetadata>(metadata));
+        isOk = mBtDeviceProxy->updateSinkMetadata(std::get<SinkMetadata>(metadata));
     } else {
-        for (auto proxy : mBtDeviceProxies) {
-            if (!proxy->updateSourceMetadata(std::get<SourceMetadata>(metadata))) isOk = false;
-        }
+        isOk = mBtDeviceProxy->updateSourceMetadata(std::get<SourceMetadata>(metadata));
     }
     return isOk ? ndk::ScopedAStatus::ok()
                 : ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
@@ -283,7 +208,6 @@
 
 ndk::ScopedAStatus StreamBluetooth::bluetoothParametersUpdated() {
     if (mIsInput) {
-        LOG(WARNING) << __func__ << ": not handled";
         return ndk::ScopedAStatus::ok();
     }
     auto applyParam = [](const std::shared_ptr<BluetoothAudioPortAidl>& proxy,
@@ -300,15 +224,10 @@
     bool hasLeParam, enableLe;
     auto btLe = mBluetoothLe.lock();
     hasLeParam = btLe != nullptr && btLe->isEnabled(&enableLe).isOk();
-    std::unique_lock lock(mLock);
-    ::android::base::ScopedLockAssertion lock_assertion(mLock);
-    if (!mIsInitialized) {
-        LOG(WARNING) << __func__ << ": init not done";
-        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
-    }
-    for (auto proxy : mBtDeviceProxies) {
-        if ((hasA2dpParam && proxy->isA2dp() && !applyParam(proxy, enableA2dp)) ||
-            (hasLeParam && proxy->isLeAudio() && !applyParam(proxy, enableLe))) {
+    std::lock_guard guard(mLock);
+    if (mBtDeviceProxy != nullptr) {
+        if ((hasA2dpParam && mBtDeviceProxy->isA2dp() && !applyParam(mBtDeviceProxy, enableA2dp)) ||
+            (hasLeParam && mBtDeviceProxy->isLeAudio() && !applyParam(mBtDeviceProxy, enableLe))) {
             LOG(DEBUG) << __func__ << ": applyParam failed";
             return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
         }
@@ -316,11 +235,20 @@
     return ndk::ScopedAStatus::ok();
 }
 
+// static
+int32_t StreamInBluetooth::getNominalLatencyMs(size_t dataIntervalUs) {
+    if (dataIntervalUs == 0) dataIntervalUs = kBluetoothDefaultInputBufferMs * 1000LL;
+    return dataIntervalUs / 1000LL;
+}
+
 StreamInBluetooth::StreamInBluetooth(StreamContext&& context, const SinkMetadata& sinkMetadata,
                                      const std::vector<MicrophoneInfo>& microphones,
-                                     Module::BtProfileHandles&& btProfileHandles)
+                                     ModuleBluetooth::BtProfileHandles&& btProfileHandles,
+                                     const std::shared_ptr<BluetoothAudioPortAidl>& btDeviceProxy,
+                                     const PcmConfiguration& pcmConfig)
     : StreamIn(std::move(context), microphones),
-      StreamBluetooth(&mContextInstance, sinkMetadata, std::move(btProfileHandles)) {}
+      StreamBluetooth(&mContextInstance, sinkMetadata, std::move(btProfileHandles), btDeviceProxy,
+                      pcmConfig) {}
 
 ndk::ScopedAStatus StreamInBluetooth::getActiveMicrophones(
         std::vector<MicrophoneDynamicInfo>* _aidl_return __unused) {
@@ -328,11 +256,20 @@
     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
 }
 
+// static
+int32_t StreamOutBluetooth::getNominalLatencyMs(size_t dataIntervalUs) {
+    if (dataIntervalUs == 0) dataIntervalUs = kBluetoothDefaultOutputBufferMs * 1000LL;
+    return dataIntervalUs / 1000LL;
+}
+
 StreamOutBluetooth::StreamOutBluetooth(StreamContext&& context,
                                        const SourceMetadata& sourceMetadata,
                                        const std::optional<AudioOffloadInfo>& offloadInfo,
-                                       Module::BtProfileHandles&& btProfileHandles)
+                                       ModuleBluetooth::BtProfileHandles&& btProfileHandles,
+                                       const std::shared_ptr<BluetoothAudioPortAidl>& btDeviceProxy,
+                                       const PcmConfiguration& pcmConfig)
     : StreamOut(std::move(context), offloadInfo),
-      StreamBluetooth(&mContextInstance, sourceMetadata, std::move(btProfileHandles)) {}
+      StreamBluetooth(&mContextInstance, sourceMetadata, std::move(btProfileHandles), btDeviceProxy,
+                      pcmConfig) {}
 
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/config/audioPolicy/api/current.txt b/audio/aidl/default/config/audioPolicy/api/current.txt
index e2bc833..3547f54 100644
--- a/audio/aidl/default/config/audioPolicy/api/current.txt
+++ b/audio/aidl/default/config/audioPolicy/api/current.txt
@@ -85,16 +85,6 @@
     enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_TRI_BACK;
   }
 
-  public enum AudioContentType {
-    method @NonNull public String getRawName();
-    enum_constant public static final android.audio.policy.configuration.AudioContentType AUDIO_CONTENT_TYPE_MOVIE;
-    enum_constant public static final android.audio.policy.configuration.AudioContentType AUDIO_CONTENT_TYPE_MUSIC;
-    enum_constant public static final android.audio.policy.configuration.AudioContentType AUDIO_CONTENT_TYPE_SONIFICATION;
-    enum_constant public static final android.audio.policy.configuration.AudioContentType AUDIO_CONTENT_TYPE_SPEECH;
-    enum_constant public static final android.audio.policy.configuration.AudioContentType AUDIO_CONTENT_TYPE_ULTRASOUND;
-    enum_constant public static final android.audio.policy.configuration.AudioContentType AUDIO_CONTENT_TYPE_UNKNOWN;
-  }
-
   public enum AudioDevice {
     method @NonNull public String getRawName();
     enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_AMBIENT;
@@ -168,13 +158,6 @@
     enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_WIRED_HEADSET;
   }
 
-  public enum AudioEncapsulationType {
-    method @NonNull public String getRawName();
-    enum_constant public static final android.audio.policy.configuration.AudioEncapsulationType AUDIO_ENCAPSULATION_TYPE_IEC61937;
-    enum_constant public static final android.audio.policy.configuration.AudioEncapsulationType AUDIO_ENCAPSULATION_TYPE_NONE;
-    enum_constant public static final android.audio.policy.configuration.AudioEncapsulationType AUDIO_ENCAPSULATION_TYPE_PCM;
-  }
-
   public enum AudioFormat {
     method @NonNull public String getRawName();
     enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC;
@@ -359,29 +342,6 @@
     enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_VOICE_CALL;
   }
 
-  public enum AudioUsage {
-    method @NonNull public String getRawName();
-    enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_ALARM;
-    enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_ANNOUNCEMENT;
-    enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY;
-    enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
-    enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_ASSISTANCE_SONIFICATION;
-    enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_ASSISTANT;
-    enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_CALL_ASSISTANT;
-    enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_EMERGENCY;
-    enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_GAME;
-    enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_MEDIA;
-    enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_NOTIFICATION;
-    enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_NOTIFICATION_EVENT;
-    enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE;
-    enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_SAFETY;
-    enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_UNKNOWN;
-    enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_VEHICLE_STATUS;
-    enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_VIRTUAL_SOURCE;
-    enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_VOICE_COMMUNICATION;
-    enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING;
-  }
-
   public enum DeviceCategory {
     method @NonNull public String getRawName();
     enum_constant public static final android.audio.policy.configuration.DeviceCategory DEVICE_CATEGORY_EARPIECE;
@@ -435,7 +395,6 @@
     method @Nullable public int getMinRampMs();
     method @Nullable public int getMinValueMB();
     method @Nullable public java.util.List<android.audio.policy.configuration.AudioGainMode> getMode();
-    method @Nullable public String getName();
     method @Nullable public int getStepValueMB();
     method @Nullable public boolean getUseForVolume();
     method public void setChannel_mask(@Nullable android.audio.policy.configuration.AudioChannelMask);
@@ -445,7 +404,6 @@
     method public void setMinRampMs(@Nullable int);
     method public void setMinValueMB(@Nullable int);
     method public void setMode(@Nullable java.util.List<android.audio.policy.configuration.AudioGainMode>);
-    method public void setName(@Nullable String);
     method public void setStepValueMB(@Nullable int);
     method public void setUseForVolume(@Nullable boolean);
   }
@@ -478,7 +436,6 @@
     method @Nullable public long getMaxActiveCount();
     method @Nullable public long getMaxOpenCount();
     method @Nullable public String getName();
-    method @Nullable public java.util.List<android.audio.policy.configuration.AudioUsage> getPreferredUsage();
     method @Nullable public java.util.List<android.audio.policy.configuration.Profile> getProfile();
     method @Nullable public long getRecommendedMuteDurationMs();
     method @Nullable public android.audio.policy.configuration.Role getRole();
@@ -487,7 +444,6 @@
     method public void setMaxActiveCount(@Nullable long);
     method public void setMaxOpenCount(@Nullable long);
     method public void setName(@Nullable String);
-    method public void setPreferredUsage(@Nullable java.util.List<android.audio.policy.configuration.AudioUsage>);
     method public void setRecommendedMuteDurationMs(@Nullable long);
     method public void setRole(@Nullable android.audio.policy.configuration.Role);
   }
@@ -524,14 +480,10 @@
   public class Profile {
     ctor public Profile();
     method @Nullable public java.util.List<android.audio.policy.configuration.AudioChannelMask> getChannelMasks();
-    method @Nullable public android.audio.policy.configuration.AudioEncapsulationType getEncapsulationType();
     method @Nullable public String getFormat();
-    method @Nullable public String getName();
     method @Nullable public java.util.List<java.math.BigInteger> getSamplingRates();
     method public void setChannelMasks(@Nullable java.util.List<android.audio.policy.configuration.AudioChannelMask>);
-    method public void setEncapsulationType(@Nullable android.audio.policy.configuration.AudioEncapsulationType);
     method public void setFormat(@Nullable String);
-    method public void setName(@Nullable String);
     method public void setSamplingRates(@Nullable java.util.List<java.math.BigInteger>);
   }
 
diff --git a/audio/aidl/default/config/audioPolicy/audio_policy_configuration.xsd b/audio/aidl/default/config/audioPolicy/audio_policy_configuration.xsd
index 9a3a447..d93f697 100644
--- a/audio/aidl/default/config/audioPolicy/audio_policy_configuration.xsd
+++ b/audio/aidl/default/config/audioPolicy/audio_policy_configuration.xsd
@@ -217,20 +217,6 @@
                     <xs:attribute name="flags" type="audioInOutFlags"/>
                     <xs:attribute name="maxOpenCount" type="xs:unsignedInt"/>
                     <xs:attribute name="maxActiveCount" type="xs:unsignedInt"/>
-                    <xs:attribute name="preferredUsage" type="audioUsageList">
-                        <xs:annotation>
-                            <xs:documentation xml:lang="en">
-                                When choosing the mixPort of an audio track, the audioPolicy
-                                first considers the mixPorts with a preferredUsage including
-                                the track AudioUsage preferred .
-                                If non support the track format, the other mixPorts are considered.
-                                Eg: a <mixPort preferredUsage="AUDIO_USAGE_MEDIA" /> will receive
-                                    the audio of all apps playing with a MEDIA usage.
-                                    It may receive audio from ALARM if there are no audio compatible
-                                    <mixPort preferredUsage="AUDIO_USAGE_ALARM" />.
-                             </xs:documentation>
-                        </xs:annotation>
-                    </xs:attribute>
                     <xs:attribute name="recommendedMuteDurationMs" type="xs:unsignedInt"/>
                 </xs:complexType>
                 <xs:unique name="mixPortProfileUniqueness">
@@ -434,56 +420,6 @@
     <xs:simpleType name="extendableAudioFormat">
         <xs:union memberTypes="audioFormat vendorExtension"/>
     </xs:simpleType>
-    <xs:simpleType name="audioUsage">
-        <xs:annotation>
-            <xs:documentation xml:lang="en">
-                Audio usage specifies the intended use case for the sound being played.
-                Please consult frameworks/base/media/java/android/media/AudioAttributes.java
-                for the description of each value.
-            </xs:documentation>
-        </xs:annotation>
-        <xs:restriction base="xs:string">
-            <xs:enumeration value="AUDIO_USAGE_UNKNOWN" />
-            <xs:enumeration value="AUDIO_USAGE_MEDIA" />
-            <xs:enumeration value="AUDIO_USAGE_VOICE_COMMUNICATION" />
-            <xs:enumeration value="AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING" />
-            <xs:enumeration value="AUDIO_USAGE_ALARM" />
-            <xs:enumeration value="AUDIO_USAGE_NOTIFICATION" />
-            <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE" />
-            <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_EVENT" />
-            <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY" />
-            <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE" />
-            <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_SONIFICATION" />
-            <xs:enumeration value="AUDIO_USAGE_GAME" />
-            <xs:enumeration value="AUDIO_USAGE_VIRTUAL_SOURCE" />
-            <xs:enumeration value="AUDIO_USAGE_ASSISTANT" />
-            <xs:enumeration value="AUDIO_USAGE_CALL_ASSISTANT" />
-            <xs:enumeration value="AUDIO_USAGE_EMERGENCY" />
-            <xs:enumeration value="AUDIO_USAGE_SAFETY" />
-            <xs:enumeration value="AUDIO_USAGE_VEHICLE_STATUS" />
-            <xs:enumeration value="AUDIO_USAGE_ANNOUNCEMENT" />
-        </xs:restriction>
-    </xs:simpleType>
-    <xs:simpleType name="audioUsageList">
-        <xs:list itemType="audioUsage"/>
-    </xs:simpleType>
-    <xs:simpleType name="audioContentType">
-        <xs:annotation>
-            <xs:documentation xml:lang="en">
-                Audio content type expresses the general category of the content.
-                Please consult frameworks/base/media/java/android/media/AudioAttributes.java
-                for the description of each value.
-            </xs:documentation>
-        </xs:annotation>
-        <xs:restriction base="xs:string">
-            <xs:enumeration value="AUDIO_CONTENT_TYPE_UNKNOWN"/>
-            <xs:enumeration value="AUDIO_CONTENT_TYPE_SPEECH"/>
-            <xs:enumeration value="AUDIO_CONTENT_TYPE_MUSIC"/>
-            <xs:enumeration value="AUDIO_CONTENT_TYPE_MOVIE"/>
-            <xs:enumeration value="AUDIO_CONTENT_TYPE_SONIFICATION"/>
-            <xs:enumeration value="AUDIO_CONTENT_TYPE_ULTRASOUND"/>
-        </xs:restriction>
-    </xs:simpleType>
     <xs:simpleType name="samplingRates">
         <xs:list itemType="xs:nonNegativeInteger" />
     </xs:simpleType>
@@ -579,19 +515,10 @@
     <xs:simpleType name="channelMasks">
         <xs:list itemType="audioChannelMask" />
     </xs:simpleType>
-    <xs:simpleType name="audioEncapsulationType">
-        <xs:restriction base="xs:string">
-            <xs:enumeration value="AUDIO_ENCAPSULATION_TYPE_NONE"/>
-            <xs:enumeration value="AUDIO_ENCAPSULATION_TYPE_IEC61937"/>
-            <xs:enumeration value="AUDIO_ENCAPSULATION_TYPE_PCM"/>
-        </xs:restriction>
-    </xs:simpleType>
     <xs:complexType name="profile">
-        <xs:attribute name="name" type="xs:token" use="optional"/>
         <xs:attribute name="format" type="extendableAudioFormat" use="optional"/>
         <xs:attribute name="samplingRates" type="samplingRates" use="optional"/>
         <xs:attribute name="channelMasks" type="channelMasks" use="optional"/>
-        <xs:attribute name="encapsulationType" type="audioEncapsulationType" use="optional"/>
     </xs:complexType>
     <xs:simpleType name="audioGainMode">
         <xs:restriction base="xs:string">
@@ -612,7 +539,6 @@
         <xs:sequence>
             <xs:element name="gain" minOccurs="0" maxOccurs="unbounded">
                 <xs:complexType>
-                    <xs:attribute name="name" type="xs:token" use="required"/>
                     <xs:attribute name="mode" type="audioGainModeMask" use="required"/>
                     <xs:attribute name="channel_mask" type="audioChannelMask" use="optional"/>
                     <xs:attribute name="minValueMB" type="xs:int" use="optional"/>
diff --git a/audio/aidl/default/downmix/Android.bp b/audio/aidl/default/downmix/Android.bp
index 6d15cdb..8657283 100644
--- a/audio/aidl/default/downmix/Android.bp
+++ b/audio/aidl/default/downmix/Android.bp
@@ -27,8 +27,6 @@
     name: "libdownmixsw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "DownmixSw.cpp",
diff --git a/audio/aidl/default/downmix/DownmixSw.cpp b/audio/aidl/default/downmix/DownmixSw.cpp
index ce5fe20..19ab2e8 100644
--- a/audio/aidl/default/downmix/DownmixSw.cpp
+++ b/audio/aidl/default/downmix/DownmixSw.cpp
@@ -144,10 +144,6 @@
     return mContext;
 }
 
-std::shared_ptr<EffectContext> DownmixSw::getContext() {
-    return mContext;
-}
-
 RetCode DownmixSw::releaseContext() {
     if (mContext) {
         mContext.reset();
diff --git a/audio/aidl/default/downmix/DownmixSw.h b/audio/aidl/default/downmix/DownmixSw.h
index 3f8a09b..1a9f0f0 100644
--- a/audio/aidl/default/downmix/DownmixSw.h
+++ b/audio/aidl/default/downmix/DownmixSw.h
@@ -55,20 +55,23 @@
     }
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
-    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
-    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
-                                            Parameter::Specific* specific) override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+            REQUIRES(mImplMutex) override;
 
-    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
-    std::shared_ptr<EffectContext> getContext() override;
-    RetCode releaseContext() override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+            REQUIRES(mImplMutex) override;
+    RetCode releaseContext() REQUIRES(mImplMutex) override;
 
     std::string getEffectName() override { return kEffectName; };
-    IEffect::Status effectProcessImpl(float* in, float* out, int sample) override;
+    IEffect::Status effectProcessImpl(float* in, float* out, int sample)
+            REQUIRES(mImplMutex) override;
 
   private:
-    std::shared_ptr<DownmixSwContext> mContext;
+    std::shared_ptr<DownmixSwContext> mContext GUARDED_BY(mImplMutex);
 
-    ndk::ScopedAStatus getParameterDownmix(const Downmix::Tag& tag, Parameter::Specific* specific);
+    ndk::ScopedAStatus getParameterDownmix(const Downmix::Tag& tag, Parameter::Specific* specific)
+            REQUIRES(mImplMutex);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/dynamicProcessing/Android.bp b/audio/aidl/default/dynamicProcessing/Android.bp
index 1c0312d..c0a648d 100644
--- a/audio/aidl/default/dynamicProcessing/Android.bp
+++ b/audio/aidl/default/dynamicProcessing/Android.bp
@@ -27,8 +27,6 @@
     name: "libdynamicsprocessingsw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "DynamicsProcessingSw.cpp",
diff --git a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp
index ed6cfa0..36face1 100644
--- a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp
+++ b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp
@@ -93,7 +93,7 @@
         .common = {.id = {.type = getEffectTypeUuidDynamicsProcessing(),
                           .uuid = getEffectImplUuidDynamicsProcessingSw(),
                           .proxy = std::nullopt},
-                   .flags = {.type = Flags::Type::INSERT,
+                   .flags = {.type = Flags::Type::POST_PROC,
                              .insert = Flags::Insert::FIRST,
                              .volume = Flags::Volume::CTRL},
                    .name = DynamicsProcessingSw::kEffectName,
@@ -260,10 +260,6 @@
     return mContext;
 }
 
-std::shared_ptr<EffectContext> DynamicsProcessingSw::getContext() {
-    return mContext;
-}
-
 RetCode DynamicsProcessingSw::releaseContext() {
     if (mContext) {
         mContext.reset();
@@ -282,6 +278,9 @@
 }
 
 RetCode DynamicsProcessingSwContext::setCommon(const Parameter::Common& common) {
+    if (auto ret = updateIOFrameSize(common); ret != RetCode::SUCCESS) {
+        return ret;
+    }
     mCommon = common;
     mChannelCount = ::aidl::android::hardware::audio::common::getChannelCount(
             common.input.base.channelMask);
diff --git a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h
index 641cf71..98edca0 100644
--- a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h
+++ b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h
@@ -113,15 +113,17 @@
     }
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
-    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
-    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
-                                            Parameter::Specific* specific) override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+            REQUIRES(mImplMutex) override;
 
-    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
-    std::shared_ptr<EffectContext> getContext() override;
-    RetCode releaseContext() override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+            REQUIRES(mImplMutex) override;
+    RetCode releaseContext() REQUIRES(mImplMutex) override;
 
-    IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+    IEffect::Status effectProcessImpl(float* in, float* out, int samples)
+            REQUIRES(mImplMutex) override;
     std::string getEffectName() override { return kEffectName; };
 
   private:
@@ -130,9 +132,10 @@
     static const Range::DynamicsProcessingRange kPreEqBandRange;
     static const Range::DynamicsProcessingRange kPostEqBandRange;
     static const std::vector<Range::DynamicsProcessingRange> kRanges;
-    std::shared_ptr<DynamicsProcessingSwContext> mContext;
+    std::shared_ptr<DynamicsProcessingSwContext> mContext GUARDED_BY(mImplMutex);
     ndk::ScopedAStatus getParameterDynamicsProcessing(const DynamicsProcessing::Tag& tag,
-                                                      Parameter::Specific* specific);
+                                                      Parameter::Specific* specific)
+            REQUIRES(mImplMutex);
 
 };  // DynamicsProcessingSw
 
diff --git a/audio/aidl/default/envReverb/Android.bp b/audio/aidl/default/envReverb/Android.bp
index dd4219a..23495f1 100644
--- a/audio/aidl/default/envReverb/Android.bp
+++ b/audio/aidl/default/envReverb/Android.bp
@@ -27,8 +27,6 @@
     name: "libenvreverbsw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "EnvReverbSw.cpp",
@@ -36,6 +34,6 @@
     ],
     relative_install_path: "soundfx",
     visibility: [
-        "//hardware/interfaces/audio/aidl/default",
+        "//hardware/interfaces/audio/aidl/default:__subpackages__",
     ],
 }
diff --git a/audio/aidl/default/envReverb/EnvReverbSw.cpp b/audio/aidl/default/envReverb/EnvReverbSw.cpp
index 73975c6..7937a6a 100644
--- a/audio/aidl/default/envReverb/EnvReverbSw.cpp
+++ b/audio/aidl/default/envReverb/EnvReverbSw.cpp
@@ -267,10 +267,6 @@
     return mContext;
 }
 
-std::shared_ptr<EffectContext> EnvReverbSw::getContext() {
-    return mContext;
-}
-
 RetCode EnvReverbSw::releaseContext() {
     if (mContext) {
         mContext.reset();
diff --git a/audio/aidl/default/envReverb/EnvReverbSw.h b/audio/aidl/default/envReverb/EnvReverbSw.h
index 5e31e2f..367462b 100644
--- a/audio/aidl/default/envReverb/EnvReverbSw.h
+++ b/audio/aidl/default/envReverb/EnvReverbSw.h
@@ -100,21 +100,23 @@
     }
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
-    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
-    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
-                                            Parameter::Specific* specific) override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+            REQUIRES(mImplMutex) override;
 
-    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
-    std::shared_ptr<EffectContext> getContext() override;
-    RetCode releaseContext() override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+            REQUIRES(mImplMutex) override;
+    RetCode releaseContext() REQUIRES(mImplMutex) override;
 
     IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
     std::string getEffectName() override { return kEffectName; }
 
   private:
     static const std::vector<Range::EnvironmentalReverbRange> kRanges;
-    std::shared_ptr<EnvReverbSwContext> mContext;
+    std::shared_ptr<EnvReverbSwContext> mContext GUARDED_BY(mImplMutex);
     ndk::ScopedAStatus getParameterEnvironmentalReverb(const EnvironmentalReverb::Tag& tag,
-                                                       Parameter::Specific* specific);
+                                                       Parameter::Specific* specific)
+            REQUIRES(mImplMutex);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/equalizer/Android.bp b/audio/aidl/default/equalizer/Android.bp
index 3610563..1d29d40 100644
--- a/audio/aidl/default/equalizer/Android.bp
+++ b/audio/aidl/default/equalizer/Android.bp
@@ -27,8 +27,6 @@
     name: "libequalizersw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "EqualizerSw.cpp",
@@ -36,6 +34,6 @@
     ],
     relative_install_path: "soundfx",
     visibility: [
-        "//hardware/interfaces/audio/aidl/default",
+        "//hardware/interfaces/audio/aidl/default:__subpackages__",
     ],
 }
diff --git a/audio/aidl/default/equalizer/EqualizerSw.cpp b/audio/aidl/default/equalizer/EqualizerSw.cpp
index b2add31..640b3ba 100644
--- a/audio/aidl/default/equalizer/EqualizerSw.cpp
+++ b/audio/aidl/default/equalizer/EqualizerSw.cpp
@@ -198,10 +198,6 @@
     return mContext;
 }
 
-std::shared_ptr<EffectContext> EqualizerSw::getContext() {
-    return mContext;
-}
-
 RetCode EqualizerSw::releaseContext() {
     if (mContext) {
         mContext.reset();
diff --git a/audio/aidl/default/equalizer/EqualizerSw.h b/audio/aidl/default/equalizer/EqualizerSw.h
index 56af3b5..caaa129 100644
--- a/audio/aidl/default/equalizer/EqualizerSw.h
+++ b/audio/aidl/default/equalizer/EqualizerSw.h
@@ -97,15 +97,17 @@
     }
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
-    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
-    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
-                                            Parameter::Specific* specific) override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+            REQUIRES(mImplMutex) override;
 
-    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
-    std::shared_ptr<EffectContext> getContext() override;
-    RetCode releaseContext() override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+            REQUIRES(mImplMutex) override;
+    RetCode releaseContext() REQUIRES(mImplMutex) override;
 
-    IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+    IEffect::Status effectProcessImpl(float* in, float* out, int samples)
+            REQUIRES(mImplMutex) override;
     std::string getEffectName() override { return kEffectName; }
 
   private:
@@ -113,7 +115,7 @@
     static const std::vector<Equalizer::Preset> kPresets;
     static const std::vector<Range::EqualizerRange> kRanges;
     ndk::ScopedAStatus getParameterEqualizer(const Equalizer::Tag& tag,
-                                             Parameter::Specific* specific);
+                                             Parameter::Specific* specific) REQUIRES(mImplMutex);
     std::shared_ptr<EqualizerSwContext> mContext;
 };
 
diff --git a/audio/aidl/default/extension/Android.bp b/audio/aidl/default/extension/Android.bp
index 4e5d352..2b21e3e 100644
--- a/audio/aidl/default/extension/Android.bp
+++ b/audio/aidl/default/extension/Android.bp
@@ -27,8 +27,6 @@
     name: "libextensioneffect",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "ExtensionEffect.cpp",
@@ -36,6 +34,6 @@
     ],
     relative_install_path: "soundfx",
     visibility: [
-        "//hardware/interfaces/audio/aidl/default",
+        "//hardware/interfaces/audio/aidl/default:__subpackages__",
     ],
 }
diff --git a/audio/aidl/default/extension/ExtensionEffect.cpp b/audio/aidl/default/extension/ExtensionEffect.cpp
index 4a4d71b6..11916c8 100644
--- a/audio/aidl/default/extension/ExtensionEffect.cpp
+++ b/audio/aidl/default/extension/ExtensionEffect.cpp
@@ -123,10 +123,6 @@
     return mContext;
 }
 
-std::shared_ptr<EffectContext> ExtensionEffect::getContext() {
-    return mContext;
-}
-
 RetCode ExtensionEffect::releaseContext() {
     if (mContext) {
         mContext.reset();
diff --git a/audio/aidl/default/extension/ExtensionEffect.h b/audio/aidl/default/extension/ExtensionEffect.h
index e7a068b..b560860 100644
--- a/audio/aidl/default/extension/ExtensionEffect.h
+++ b/audio/aidl/default/extension/ExtensionEffect.h
@@ -54,18 +54,20 @@
     }
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
-    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
-    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
-                                            Parameter::Specific* specific) override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+            REQUIRES(mImplMutex) override;
 
-    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
-    std::shared_ptr<EffectContext> getContext() override;
-    RetCode releaseContext() override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+            REQUIRES(mImplMutex) override;
+    RetCode releaseContext() REQUIRES(mImplMutex) override;
 
     std::string getEffectName() override { return kEffectName; };
-    IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+    IEffect::Status effectProcessImpl(float* in, float* out, int samples)
+            REQUIRES(mImplMutex) override;
 
   private:
-    std::shared_ptr<ExtensionEffectContext> mContext;
+    std::shared_ptr<ExtensionEffectContext> mContext GUARDED_BY(mImplMutex);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/hapticGenerator/Android.bp b/audio/aidl/default/hapticGenerator/Android.bp
index 0df9a94..8fb9a3d 100644
--- a/audio/aidl/default/hapticGenerator/Android.bp
+++ b/audio/aidl/default/hapticGenerator/Android.bp
@@ -27,8 +27,6 @@
     name: "libhapticgeneratorsw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "HapticGeneratorSw.cpp",
diff --git a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp
index 27cdac8..7469ab9 100644
--- a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp
+++ b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp
@@ -158,10 +158,6 @@
     return mContext;
 }
 
-std::shared_ptr<EffectContext> HapticGeneratorSw::getContext() {
-    return mContext;
-}
-
 RetCode HapticGeneratorSw::releaseContext() {
     if (mContext) {
         mContext.reset();
diff --git a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h
index 3bbe41a..47f3848 100644
--- a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h
+++ b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h
@@ -67,21 +67,24 @@
     }
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
-    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
-    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
-                                            Parameter::Specific* specific) override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+            REQUIRES(mImplMutex) override;
 
-    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
-    std::shared_ptr<EffectContext> getContext() override;
-    RetCode releaseContext() override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+            REQUIRES(mImplMutex) override;
+    RetCode releaseContext() REQUIRES(mImplMutex) override;
 
-    IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+    IEffect::Status effectProcessImpl(float* in, float* out, int samples)
+            REQUIRES(mImplMutex) override;
     std::string getEffectName() override { return kEffectName; }
 
   private:
-    std::shared_ptr<HapticGeneratorSwContext> mContext;
+    std::shared_ptr<HapticGeneratorSwContext> mContext GUARDED_BY(mImplMutex);
 
     ndk::ScopedAStatus getParameterHapticGenerator(const HapticGenerator::Tag& tag,
-                                                   Parameter::Specific* specific);
+                                                   Parameter::Specific* specific)
+            REQUIRES(mImplMutex);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/core-impl/AudioPolicyConfigXmlConverter.h b/audio/aidl/default/include/core-impl/AudioPolicyConfigXmlConverter.h
index 090d585..bff4b4a 100644
--- a/audio/aidl/default/include/core-impl/AudioPolicyConfigXmlConverter.h
+++ b/audio/aidl/default/include/core-impl/AudioPolicyConfigXmlConverter.h
@@ -16,27 +16,42 @@
 
 #pragma once
 
+#include <memory>
+#include <optional>
 #include <string>
+#include <unordered_map>
+#include <utility>
+#include <vector>
 
 #include <aidl/android/hardware/audio/core/SurroundSoundConfig.h>
 #include <aidl/android/media/audio/common/AudioHalEngineConfig.h>
 #include <android_audio_policy_configuration.h>
 #include <android_audio_policy_configuration_enums.h>
+#include <media/AidlConversionUtil.h>
 
+#include "core-impl/Module.h"
 #include "core-impl/XmlConverter.h"
 
 namespace aidl::android::hardware::audio::core::internal {
 
 class AudioPolicyConfigXmlConverter {
   public:
+    using ModuleConfiguration = std::pair<std::string, std::unique_ptr<Module::Configuration>>;
+    using ModuleConfigs = std::vector<ModuleConfiguration>;
+
     explicit AudioPolicyConfigXmlConverter(const std::string& configFilePath)
-        : mConverter(configFilePath, &::android::audio::policy::configuration::read) {}
+        : mConverter(configFilePath, &::android::audio::policy::configuration::read) {
+        if (mConverter.getXsdcConfig()) {
+            init();
+        }
+    }
 
     std::string getError() const { return mConverter.getError(); }
     ::android::status_t getStatus() const { return mConverter.getStatus(); }
 
     const ::aidl::android::media::audio::common::AudioHalEngineConfig& getAidlEngineConfig();
     const SurroundSoundConfig& getSurroundSoundConfig();
+    std::unique_ptr<ModuleConfigs> releaseModuleConfigs();
 
     // Public for testing purposes.
     static const SurroundSoundConfig& getDefaultSurroundSoundConfig();
@@ -47,13 +62,13 @@
         return mConverter.getXsdcConfig();
     }
     void addVolumeGroupstoEngineConfig();
+    void init();
     void mapStreamToVolumeCurve(
             const ::android::audio::policy::configuration::Volume& xsdcVolumeCurve);
     void mapStreamsToVolumeCurves();
     void parseVolumes();
-    ::aidl::android::media::audio::common::AudioHalVolumeCurve::CurvePoint convertCurvePointToAidl(
-            const std::string& xsdcCurvePoint);
-    ::aidl::android::media::audio::common::AudioHalVolumeCurve convertVolumeCurveToAidl(
+    ConversionResult<::aidl::android::media::audio::common::AudioHalVolumeCurve>
+    convertVolumeCurveToAidl(
             const ::android::audio::policy::configuration::Volume& xsdcVolumeCurve);
 
     ::aidl::android::media::audio::common::AudioHalEngineConfig mAidlEngineConfig;
@@ -63,6 +78,7 @@
     std::unordered_map<::android::audio::policy::configuration::AudioStreamType,
                        std::vector<::aidl::android::media::audio::common::AudioHalVolumeCurve>>
             mStreamToVolumeCurvesMap;
+    std::unique_ptr<ModuleConfigs> mModuleConfigurations = std::make_unique<ModuleConfigs>();
 };
 
 }  // namespace aidl::android::hardware::audio::core::internal
diff --git a/audio/aidl/default/include/core-impl/Bluetooth.h b/audio/aidl/default/include/core-impl/Bluetooth.h
index 44899bc..002cb19 100644
--- a/audio/aidl/default/include/core-impl/Bluetooth.h
+++ b/audio/aidl/default/include/core-impl/Bluetooth.h
@@ -46,9 +46,9 @@
 class BluetoothA2dp : public BnBluetoothA2dp, public ParamChangeHandler {
   public:
     BluetoothA2dp() = default;
+    ndk::ScopedAStatus isEnabled(bool* _aidl_return) override;
 
   private:
-    ndk::ScopedAStatus isEnabled(bool* _aidl_return) override;
     ndk::ScopedAStatus setEnabled(bool in_enabled) override;
     ndk::ScopedAStatus supportsOffloadReconfiguration(bool* _aidl_return) override;
     ndk::ScopedAStatus reconfigureOffload(
@@ -61,9 +61,9 @@
 class BluetoothLe : public BnBluetoothLe, public ParamChangeHandler {
   public:
     BluetoothLe() = default;
+    ndk::ScopedAStatus isEnabled(bool* _aidl_return) override;
 
   private:
-    ndk::ScopedAStatus isEnabled(bool* _aidl_return) override;
     ndk::ScopedAStatus setEnabled(bool in_enabled) override;
     ndk::ScopedAStatus supportsOffloadReconfiguration(bool* _aidl_return) override;
     ndk::ScopedAStatus reconfigureOffload(
diff --git a/audio/aidl/default/include/core-impl/ChildInterface.h b/audio/aidl/default/include/core-impl/ChildInterface.h
index 2421b59..f5f1855 100644
--- a/audio/aidl/default/include/core-impl/ChildInterface.h
+++ b/audio/aidl/default/include/core-impl/ChildInterface.h
@@ -40,14 +40,19 @@
     explicit operator bool() const { return !!this->first; }
     C& operator*() const { return *(this->first); }
     C* operator->() const { return this->first; }
+    std::shared_ptr<C> getPtr() { return this->first; }
     // Use 'getInstance' when returning the interface instance.
     std::shared_ptr<C> getInstance() {
+        (void)getBinder();
+        return this->first;
+    }
+    AIBinder* getBinder() {
         if (this->second.get() == nullptr) {
             this->second = this->first->asBinder();
             AIBinder_setMinSchedulerPolicy(this->second.get(), SCHED_NORMAL,
                                            ANDROID_PRIORITY_AUDIO);
         }
-        return this->first;
+        return this->second.get();
     }
 };
 
diff --git a/audio/aidl/default/include/core-impl/Config.h b/audio/aidl/default/include/core-impl/Config.h
index 96a6cb9..63d4b3d 100644
--- a/audio/aidl/default/include/core-impl/Config.h
+++ b/audio/aidl/default/include/core-impl/Config.h
@@ -26,11 +26,16 @@
 static const std::string kEngineConfigFileName = "audio_policy_engine_configuration.xml";
 
 class Config : public BnConfig {
+  public:
+    explicit Config(internal::AudioPolicyConfigXmlConverter& apConverter)
+        : mAudioPolicyConverter(apConverter) {}
+
+  private:
     ndk::ScopedAStatus getSurroundSoundConfig(SurroundSoundConfig* _aidl_return) override;
     ndk::ScopedAStatus getEngineConfig(
             aidl::android::media::audio::common::AudioHalEngineConfig* _aidl_return) override;
-    internal::AudioPolicyConfigXmlConverter mAudioPolicyConverter{
-            ::android::audio_get_audio_policy_config_file()};
+
+    internal::AudioPolicyConfigXmlConverter& mAudioPolicyConverter;
     internal::EngineConfigXmlConverter mEngConfigConverter{
             ::android::audio_find_readable_configuration_file(kEngineConfigFileName.c_str())};
 };
diff --git a/audio/aidl/default/include/core-impl/Configuration.h b/audio/aidl/default/include/core-impl/Configuration.h
index 6277c38..a56c8c9 100644
--- a/audio/aidl/default/include/core-impl/Configuration.h
+++ b/audio/aidl/default/include/core-impl/Configuration.h
@@ -16,37 +16,14 @@
 
 #pragma once
 
-#include <map>
 #include <memory>
-#include <vector>
 
-#include <aidl/android/hardware/audio/core/AudioPatch.h>
-#include <aidl/android/hardware/audio/core/AudioRoute.h>
-#include <aidl/android/media/audio/common/AudioPort.h>
-#include <aidl/android/media/audio/common/AudioPortConfig.h>
-#include <aidl/android/media/audio/common/MicrophoneInfo.h>
+#include "Module.h"
 
 namespace aidl::android::hardware::audio::core::internal {
 
-struct Configuration {
-    std::vector<::aidl::android::media::audio::common::MicrophoneInfo> microphones;
-    std::vector<::aidl::android::media::audio::common::AudioPort> ports;
-    std::vector<::aidl::android::media::audio::common::AudioPortConfig> portConfigs;
-    std::vector<::aidl::android::media::audio::common::AudioPortConfig> initialConfigs;
-    // Port id -> List of profiles to use when the device port state is set to 'connected'
-    // in connection simulation mode.
-    std::map<int32_t, std::vector<::aidl::android::media::audio::common::AudioProfile>>
-            connectedProfiles;
-    std::vector<AudioRoute> routes;
-    std::vector<AudioPatch> patches;
-    int32_t nextPortId = 1;
-    int32_t nextPatchId = 1;
-};
-
-std::unique_ptr<Configuration> getPrimaryConfiguration();
-std::unique_ptr<Configuration> getRSubmixConfiguration();
-std::unique_ptr<Configuration> getStubConfiguration();
-std::unique_ptr<Configuration> getUsbConfiguration();
-std::unique_ptr<Configuration> getBluetoothConfiguration();
+std::unique_ptr<Module::Configuration> getConfiguration(Module::Type moduleType);
+std::vector<aidl::android::media::audio::common::AudioProfile>
+getStandard16And24BitPcmAudioProfiles();
 
 }  // namespace aidl::android::hardware::audio::core::internal
diff --git a/audio/aidl/default/include/core-impl/DevicePortProxy.h b/audio/aidl/default/include/core-impl/DevicePortProxy.h
index 13b8c91..ccb23bb 100644
--- a/audio/aidl/default/include/core-impl/DevicePortProxy.h
+++ b/audio/aidl/default/include/core-impl/DevicePortProxy.h
@@ -25,11 +25,10 @@
 #include <aidl/android/hardware/audio/common/SourceMetadata.h>
 #include <aidl/android/hardware/bluetooth/audio/BluetoothAudioStatus.h>
 #include <aidl/android/hardware/bluetooth/audio/PcmConfiguration.h>
+#include <aidl/android/hardware/bluetooth/audio/PresentationPosition.h>
 #include <aidl/android/hardware/bluetooth/audio/SessionType.h>
 #include <aidl/android/media/audio/common/AudioDeviceDescription.h>
 
-#include "BluetoothAudioSessionControl.h"
-
 namespace android::bluetooth::audio::aidl {
 
 enum class BluetoothStreamState : uint8_t {
@@ -74,12 +73,7 @@
      * Bluetooth stack
      */
     virtual bool loadAudioConfig(
-            ::aidl::android::hardware::bluetooth::audio::PcmConfiguration*) const = 0;
-
-    /**
-     * WAR to support Mono mode / 16 bits per sample
-     */
-    virtual void forcePcmStereoToMono(bool) = 0;
+            ::aidl::android::hardware::bluetooth::audio::PcmConfiguration&) = 0;
 
     /**
      * When the Audio framework / HAL wants to change the stream state, it invokes
@@ -146,7 +140,7 @@
 
     virtual bool isLeAudio() const = 0;
 
-    virtual bool getPreferredDataIntervalUs(size_t*) const = 0;
+    virtual bool getPreferredDataIntervalUs(size_t&) const = 0;
 
     virtual size_t writeData(const void*, size_t) const { return 0; }
 
@@ -163,10 +157,8 @@
 
     void unregisterPort() override;
 
-    bool loadAudioConfig(::aidl::android::hardware::bluetooth::audio::PcmConfiguration* audio_cfg)
-            const override;
-
-    void forcePcmStereoToMono(bool force) override { mIsStereoToMono = force; }
+    bool loadAudioConfig(
+            ::aidl::android::hardware::bluetooth::audio::PcmConfiguration& audio_cfg) override;
 
     bool standby() override;
     bool start() override;
@@ -194,7 +186,7 @@
 
     bool isLeAudio() const override;
 
-    bool getPreferredDataIntervalUs(size_t* interval_us) const override;
+    bool getPreferredDataIntervalUs(size_t& interval_us) const override;
 
   protected:
     uint16_t mCookie;
@@ -229,6 +221,9 @@
 
 class BluetoothAudioPortAidlOut : public BluetoothAudioPortAidl {
   public:
+    bool loadAudioConfig(
+            ::aidl::android::hardware::bluetooth::audio::PcmConfiguration& audio_cfg) override;
+
     // The audio data path to the Bluetooth stack (Software encoding)
     size_t writeData(const void* buffer, size_t bytes) const override;
 };
@@ -239,4 +234,4 @@
     size_t readData(void* buffer, size_t bytes) const override;
 };
 
-}  // namespace android::bluetooth::audio::aidl
\ No newline at end of file
+}  // namespace android::bluetooth::audio::aidl
diff --git a/audio/aidl/default/include/core-impl/EngineConfigXmlConverter.h b/audio/aidl/default/include/core-impl/EngineConfigXmlConverter.h
index b34441d..22ac8cb 100644
--- a/audio/aidl/default/include/core-impl/EngineConfigXmlConverter.h
+++ b/audio/aidl/default/include/core-impl/EngineConfigXmlConverter.h
@@ -19,10 +19,9 @@
 #include <string>
 #include <unordered_map>
 
-#include <utils/Errors.h>
-
 #include <android_audio_policy_engine_configuration.h>
 #include <android_audio_policy_engine_configuration_enums.h>
+#include <media/AidlConversionUtil.h>
 
 #include "core-impl/XmlConverter.h"
 
@@ -49,29 +48,24 @@
     }
     void init();
     void initProductStrategyMap();
-    ::aidl::android::media::audio::common::AudioAttributes convertAudioAttributesToAidl(
+    ConversionResult<::aidl::android::media::audio::common::AudioAttributes>
+    convertAudioAttributesToAidl(
             const ::android::audio::policy::engine::configuration::AttributesType&
                     xsdcAudioAttributes);
-    ::aidl::android::media::audio::common::AudioHalAttributesGroup convertAttributesGroupToAidl(
+    ConversionResult<::aidl::android::media::audio::common::AudioHalAttributesGroup>
+    convertAttributesGroupToAidl(
             const ::android::audio::policy::engine::configuration::AttributesGroup&
                     xsdcAttributesGroup);
-    ::aidl::android::media::audio::common::AudioHalCapCriterion convertCapCriterionToAidl(
-            const ::android::audio::policy::engine::configuration::CriterionType& xsdcCriterion);
-    ::aidl::android::media::audio::common::AudioHalCapCriterionType convertCapCriterionTypeToAidl(
-            const ::android::audio::policy::engine::configuration::CriterionTypeType&
-                    xsdcCriterionType);
-    std::string convertCriterionTypeValueToAidl(
-            const ::android::audio::policy::engine::configuration::ValueType&
-                    xsdcCriterionTypeValue);
-    ::aidl::android::media::audio::common::AudioHalVolumeCurve::CurvePoint convertCurvePointToAidl(
-            const std::string& xsdcCurvePoint);
-    ::aidl::android::media::audio::common::AudioHalProductStrategy convertProductStrategyToAidl(
-            const ::android::audio::policy::engine::configuration::ProductStrategies::
-                    ProductStrategy& xsdcProductStrategy);
-    int convertProductStrategyNameToAidl(const std::string& xsdcProductStrategyName);
-    ::aidl::android::media::audio::common::AudioHalVolumeCurve convertVolumeCurveToAidl(
+    ConversionResult<::aidl::android::media::audio::common::AudioHalProductStrategy>
+    convertProductStrategyToAidl(const ::android::audio::policy::engine::configuration::
+                                         ProductStrategies::ProductStrategy& xsdcProductStrategy);
+    ConversionResult<int> convertProductStrategyNameToAidl(
+            const std::string& xsdcProductStrategyName);
+    ConversionResult<::aidl::android::media::audio::common::AudioHalVolumeCurve>
+    convertVolumeCurveToAidl(
             const ::android::audio::policy::engine::configuration::Volume& xsdcVolumeCurve);
-    ::aidl::android::media::audio::common::AudioHalVolumeGroup convertVolumeGroupToAidl(
+    ConversionResult<::aidl::android::media::audio::common::AudioHalVolumeGroup>
+    convertVolumeGroupToAidl(
             const ::android::audio::policy::engine::configuration::VolumeGroupsType::VolumeGroup&
                     xsdcVolumeGroup);
 
diff --git a/audio/aidl/default/include/core-impl/Module.h b/audio/aidl/default/include/core-impl/Module.h
index fb3eef2..ce71d70 100644
--- a/audio/aidl/default/include/core-impl/Module.h
+++ b/audio/aidl/default/include/core-impl/Module.h
@@ -16,33 +16,46 @@
 
 #pragma once
 
+#include <functional>
 #include <iostream>
 #include <map>
 #include <memory>
+#include <optional>
 #include <set>
 
+#include <Utils.h>
 #include <aidl/android/hardware/audio/core/BnModule.h>
 
 #include "core-impl/ChildInterface.h"
-#include "core-impl/Configuration.h"
 #include "core-impl/Stream.h"
 
 namespace aidl::android::hardware::audio::core {
 
 class Module : public BnModule {
   public:
-    // This value is used for all AudioPatches and reported by all streams.
-    static constexpr int32_t kLatencyMs = 10;
+    struct Configuration {
+        std::vector<::aidl::android::media::audio::common::AudioPort> ports;
+        std::vector<::aidl::android::media::audio::common::AudioPortConfig> portConfigs;
+        std::vector<::aidl::android::media::audio::common::AudioPortConfig> initialConfigs;
+        // Port id -> List of profiles to use when the device port state is set to 'connected'
+        // in connection simulation mode.
+        std::map<int32_t, std::vector<::aidl::android::media::audio::common::AudioProfile>>
+                connectedProfiles;
+        std::vector<AudioRoute> routes;
+        std::vector<AudioPatch> patches;
+        int32_t nextPortId = 1;
+        int32_t nextPatchId = 1;
+    };
     enum Type : int { DEFAULT, R_SUBMIX, STUB, USB, BLUETOOTH };
-    enum BtInterface : int { BTCONF, BTA2DP, BTLE };
 
-    static std::shared_ptr<Module> createInstance(Type type);
+    static std::shared_ptr<Module> createInstance(Type type) {
+        return createInstance(type, std::make_unique<Configuration>());
+    }
+    static std::shared_ptr<Module> createInstance(Type type,
+                                                  std::unique_ptr<Configuration>&& config);
+    static std::optional<Type> typeFromString(const std::string& type);
 
-    explicit Module(Type type) : mType(type) {}
-
-    typedef std::tuple<std::weak_ptr<IBluetooth>, std::weak_ptr<IBluetoothA2dp>,
-                       std::weak_ptr<IBluetoothLe>>
-            BtProfileHandles;
+    Module(Type type, std::unique_ptr<Configuration>&& config);
 
   protected:
     // The vendor extension done via inheritance can override interface methods and augment
@@ -58,6 +71,7 @@
             const ::aidl::android::media::audio::common::AudioPort& in_templateIdAndAdditionalData,
             ::aidl::android::media::audio::common::AudioPort* _aidl_return) override;
     ndk::ScopedAStatus disconnectExternalDevice(int32_t in_portId) override;
+    ndk::ScopedAStatus prepareToDisconnectExternalDevice(int32_t in_portId) override;
     ndk::ScopedAStatus getAudioPatches(std::vector<AudioPatch>* _aidl_return) override;
     ndk::ScopedAStatus getAudioPort(
             int32_t in_portId,
@@ -127,8 +141,6 @@
     ndk::ScopedAStatus getAAudioMixerBurstCount(int32_t* _aidl_return) override;
     ndk::ScopedAStatus getAAudioHardwareBurstMinUsec(int32_t* _aidl_return) override;
 
-    // This value is used for all AudioPatches.
-    static constexpr int32_t kMinimumStreamBufferSizeFrames = 256;
     // The maximum stream buffer size is 1 GiB = 2 ** 30 bytes;
     static constexpr int32_t kMaximumStreamBufferSizeBytes = 1 << 30;
 
@@ -142,13 +154,13 @@
     // ids of device ports created at runtime via 'connectExternalDevice'.
     // Also stores a list of ids of mix ports with dynamic profiles that were populated from
     // the connected port. This list can be empty, thus an int->int multimap can't be used.
-    using ConnectedDevicePorts = std::map<int32_t, std::vector<int32_t>>;
+    using ConnectedDevicePorts = std::map<int32_t, std::set<int32_t>>;
     // Maps port ids and port config ids to patch ids.
     // Multimap because both ports and configs can be used by multiple patches.
     using Patches = std::multimap<int32_t, int32_t>;
 
     const Type mType;
-    std::unique_ptr<internal::Configuration> mConfig;
+    std::unique_ptr<Configuration> mConfig;
     ModuleDebug mDebug;
     VendorDebug mVendorDebug;
     ConnectedDevicePorts mConnectedDevicePorts;
@@ -157,7 +169,7 @@
     bool mMicMute = false;
     bool mMasterMute = false;
     float mMasterVolume = 1.0f;
-    ChildInterface<sounddose::ISoundDose> mSoundDose;
+    ChildInterface<sounddose::SoundDose> mSoundDose;
     std::optional<bool> mIsMmapSupported;
 
   protected:
@@ -177,7 +189,7 @@
     // If the module is unable to populate the connected device port correctly, the returned error
     // code must correspond to the errors of `IModule.connectedExternalDevice` method.
     virtual ndk::ScopedAStatus populateConnectedDevicePort(
-            ::aidl::android::media::audio::common::AudioPort* audioPort);
+            ::aidl::android::media::audio::common::AudioPort* audioPort, int32_t nextPortId);
     // If the module finds that the patch endpoints configurations are not matched, the returned
     // error code must correspond to the errors of `IModule.setAudioPatch` method.
     virtual ndk::ScopedAStatus checkAudioPatchEndpointsMatch(
@@ -185,11 +197,26 @@
             const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sinks);
     virtual void onExternalDeviceConnectionChanged(
             const ::aidl::android::media::audio::common::AudioPort& audioPort, bool connected);
+    virtual void onPrepareToDisconnectExternalDevice(
+            const ::aidl::android::media::audio::common::AudioPort& audioPort);
     virtual ndk::ScopedAStatus onMasterMuteChanged(bool mute);
     virtual ndk::ScopedAStatus onMasterVolumeChanged(float volume);
-    virtual std::unique_ptr<internal::Configuration> initializeConfig();
+    virtual std::vector<::aidl::android::media::audio::common::MicrophoneInfo> getMicrophoneInfos();
+    virtual std::unique_ptr<Configuration> initializeConfig();
+    virtual int32_t getNominalLatencyMs(
+            const ::aidl::android::media::audio::common::AudioPortConfig& portConfig);
 
     // Utility and helper functions accessible to subclasses.
+    static int32_t calculateBufferSizeFrames(int32_t latencyMs, int32_t sampleRateHz) {
+        const int32_t rawSizeFrames =
+                aidl::android::hardware::audio::common::frameCountFromDurationMs(latencyMs,
+                                                                                 sampleRateHz);
+        if (latencyMs >= 5) return rawSizeFrames;
+        int32_t powerOf2 = 1;
+        while (powerOf2 < rawSizeFrames) powerOf2 <<= 1;
+        return powerOf2;
+    }
+
     ndk::ScopedAStatus bluetoothParametersUpdated();
     void cleanUpPatch(int32_t patchId);
     ndk::ScopedAStatus createStreamContext(
@@ -202,19 +229,32 @@
     std::set<int32_t> findConnectedPortConfigIds(int32_t portConfigId);
     ndk::ScopedAStatus findPortIdForNewStream(
             int32_t in_portConfigId, ::aidl::android::media::audio::common::AudioPort** port);
-    virtual BtProfileHandles getBtProfileManagerHandles();
-    internal::Configuration& getConfig();
+    // Note: does not assign an ID to the config.
+    bool generateDefaultPortConfig(const ::aidl::android::media::audio::common::AudioPort& port,
+                                   ::aidl::android::media::audio::common::AudioPortConfig* config);
+    std::vector<AudioRoute*> getAudioRoutesForAudioPortImpl(int32_t portId);
+    Configuration& getConfig();
     const ConnectedDevicePorts& getConnectedDevicePorts() const { return mConnectedDevicePorts; }
     bool getMasterMute() const { return mMasterMute; }
     bool getMasterVolume() const { return mMasterVolume; }
     bool getMicMute() const { return mMicMute; }
+    const ModuleDebug& getModuleDebug() const { return mDebug; }
     const Patches& getPatches() const { return mPatches; }
+    std::set<int32_t> getRoutableAudioPortIds(int32_t portId,
+                                              std::vector<AudioRoute*>* routes = nullptr);
     const Streams& getStreams() const { return mStreams; }
     Type getType() const { return mType; }
     bool isMmapSupported();
+    void populateConnectedProfiles();
     template <typename C>
     std::set<int32_t> portIdsFromPortConfigIds(C portConfigIds);
     void registerPatch(const AudioPatch& patch);
+    ndk::ScopedAStatus setAudioPortConfigImpl(
+            const ::aidl::android::media::audio::common::AudioPortConfig& in_requested,
+            const std::function<bool(const ::aidl::android::media::audio::common::AudioPort& port,
+                                     ::aidl::android::media::audio::common::AudioPortConfig*
+                                             config)>& fillPortConfig,
+            ::aidl::android::media::audio::common::AudioPortConfig* out_suggested, bool* applied);
     ndk::ScopedAStatus updateStreamsConnectedState(const AudioPatch& oldPatch,
                                                    const AudioPatch& newPatch);
 };
diff --git a/audio/aidl/default/include/core-impl/ModuleAlsa.h b/audio/aidl/default/include/core-impl/ModuleAlsa.h
index 5815961..3392b41 100644
--- a/audio/aidl/default/include/core-impl/ModuleAlsa.h
+++ b/audio/aidl/default/include/core-impl/ModuleAlsa.h
@@ -27,12 +27,14 @@
 // provide necessary overrides for all interface methods omitted here.
 class ModuleAlsa : public Module {
   public:
-    explicit ModuleAlsa(Module::Type type) : Module(type) {}
+    ModuleAlsa(Type type, std::unique_ptr<Configuration>&& config)
+        : Module(type, std::move(config)) {}
 
   protected:
     // Extension methods of 'Module'.
     ndk::ScopedAStatus populateConnectedDevicePort(
-            ::aidl::android::media::audio::common::AudioPort* audioPort) override;
+            ::aidl::android::media::audio::common::AudioPort* audioPort,
+            int32_t nextPortId) override;
 };
 
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/ModuleBluetooth.h b/audio/aidl/default/include/core-impl/ModuleBluetooth.h
index 68b4e6b..9451411 100644
--- a/audio/aidl/default/include/core-impl/ModuleBluetooth.h
+++ b/audio/aidl/default/include/core-impl/ModuleBluetooth.h
@@ -16,23 +16,49 @@
 
 #pragma once
 
+#include <map>
+
 #include "core-impl/Bluetooth.h"
+#include "core-impl/DevicePortProxy.h"
 #include "core-impl/Module.h"
 
 namespace aidl::android::hardware::audio::core {
 
 class ModuleBluetooth final : public Module {
   public:
-    ModuleBluetooth() : Module(Type::BLUETOOTH) {}
+    enum BtInterface : int { BTSCO, BTA2DP, BTLE };
+    typedef std::tuple<std::weak_ptr<IBluetooth>, std::weak_ptr<IBluetoothA2dp>,
+                       std::weak_ptr<IBluetoothLe>>
+            BtProfileHandles;
+
+    ModuleBluetooth(std::unique_ptr<Configuration>&& config);
 
   private:
-    BtProfileHandles getBtProfileManagerHandles() override;
+    struct CachedProxy {
+        std::shared_ptr<::android::bluetooth::audio::aidl::BluetoothAudioPortAidl> ptr;
+        ::aidl::android::hardware::bluetooth::audio::PcmConfiguration pcmConfig;
+    };
+
+    ChildInterface<BluetoothA2dp>& getBtA2dp();
+    ChildInterface<BluetoothLe>& getBtLe();
+    BtProfileHandles getBtProfileManagerHandles();
 
     ndk::ScopedAStatus getBluetoothA2dp(std::shared_ptr<IBluetoothA2dp>* _aidl_return) override;
     ndk::ScopedAStatus getBluetoothLe(std::shared_ptr<IBluetoothLe>* _aidl_return) override;
     ndk::ScopedAStatus getMicMute(bool* _aidl_return) override;
     ndk::ScopedAStatus setMicMute(bool in_mute) override;
 
+    ndk::ScopedAStatus setAudioPortConfig(
+            const ::aidl::android::media::audio::common::AudioPortConfig& in_requested,
+            ::aidl::android::media::audio::common::AudioPortConfig* out_suggested,
+            bool* _aidl_return) override;
+
+    ndk::ScopedAStatus checkAudioPatchEndpointsMatch(
+            const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sources,
+            const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sinks)
+            override;
+    void onExternalDeviceConnectionChanged(
+            const ::aidl::android::media::audio::common::AudioPort& audioPort, bool connected);
     ndk::ScopedAStatus createInputStream(
             StreamContext&& context,
             const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
@@ -44,11 +70,25 @@
             const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
                     offloadInfo,
             std::shared_ptr<StreamOut>* result) override;
+    ndk::ScopedAStatus populateConnectedDevicePort(
+            ::aidl::android::media::audio::common::AudioPort* audioPort,
+            int32_t nextPortId) override;
     ndk::ScopedAStatus onMasterMuteChanged(bool mute) override;
     ndk::ScopedAStatus onMasterVolumeChanged(float volume) override;
+    int32_t getNominalLatencyMs(
+            const ::aidl::android::media::audio::common::AudioPortConfig& portConfig) override;
 
-    ChildInterface<IBluetoothA2dp> mBluetoothA2dp;
-    ChildInterface<IBluetoothLe> mBluetoothLe;
+    ndk::ScopedAStatus createProxy(
+            const ::aidl::android::media::audio::common::AudioPort& audioPort,
+            int32_t instancePortId, CachedProxy& proxy);
+    ndk::ScopedAStatus fetchAndCheckProxy(const StreamContext& context, CachedProxy& proxy);
+    ndk::ScopedAStatus findOrCreateProxy(
+            const ::aidl::android::media::audio::common::AudioPort& audioPort, CachedProxy& proxy);
+
+    ChildInterface<BluetoothA2dp> mBluetoothA2dp;
+    ChildInterface<BluetoothLe> mBluetoothLe;
+    std::map<int32_t /*instantiated device port ID*/, CachedProxy> mProxies;
+    std::map<int32_t /*mix port handle*/, int32_t /*instantiated device port ID*/> mConnections;
 };
 
-}  // namespace aidl::android::hardware::audio::core
\ No newline at end of file
+}  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/ModulePrimary.h b/audio/aidl/default/include/core-impl/ModulePrimary.h
index 6264237..82c8a03 100644
--- a/audio/aidl/default/include/core-impl/ModulePrimary.h
+++ b/audio/aidl/default/include/core-impl/ModulePrimary.h
@@ -22,7 +22,8 @@
 
 class ModulePrimary final : public Module {
   public:
-    ModulePrimary() : Module(Type::DEFAULT) {}
+    ModulePrimary(std::unique_ptr<Configuration>&& config)
+        : Module(Type::DEFAULT, std::move(config)) {}
 
   protected:
     ndk::ScopedAStatus getTelephony(std::shared_ptr<ITelephony>* _aidl_return) override;
@@ -38,6 +39,8 @@
             const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
                     offloadInfo,
             std::shared_ptr<StreamOut>* result) override;
+    int32_t getNominalLatencyMs(
+            const ::aidl::android::media::audio::common::AudioPortConfig& portConfig) override;
 
   private:
     ChildInterface<ITelephony> mTelephony;
diff --git a/audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h b/audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h
index c4bf7b9..9d8c027 100644
--- a/audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h
+++ b/audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h
@@ -22,12 +22,17 @@
 
 class ModuleRemoteSubmix : public Module {
   public:
-    ModuleRemoteSubmix() : Module(Type::R_SUBMIX) {}
+    ModuleRemoteSubmix(std::unique_ptr<Configuration>&& config)
+        : Module(Type::R_SUBMIX, std::move(config)) {}
 
   private:
     // IModule interfaces
     ndk::ScopedAStatus getMicMute(bool* _aidl_return) override;
     ndk::ScopedAStatus setMicMute(bool in_mute) override;
+    ndk::ScopedAStatus setAudioPortConfig(
+            const ::aidl::android::media::audio::common::AudioPortConfig& in_requested,
+            ::aidl::android::media::audio::common::AudioPortConfig* out_suggested,
+            bool* _aidl_return) override;
 
     // Module interfaces
     ndk::ScopedAStatus createInputStream(
@@ -42,13 +47,17 @@
                     offloadInfo,
             std::shared_ptr<StreamOut>* result) override;
     ndk::ScopedAStatus populateConnectedDevicePort(
-            ::aidl::android::media::audio::common::AudioPort* audioPort) override;
+            ::aidl::android::media::audio::common::AudioPort* audioPort,
+            int32_t nextPortId) override;
     ndk::ScopedAStatus checkAudioPatchEndpointsMatch(
             const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sources,
             const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sinks)
             override;
     ndk::ScopedAStatus onMasterMuteChanged(bool mute) override;
     ndk::ScopedAStatus onMasterVolumeChanged(float volume) override;
+    int32_t getNominalLatencyMs(
+            const ::aidl::android::media::audio::common::AudioPortConfig& portConfig) override;
+    binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
 };
 
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/ModuleStub.h b/audio/aidl/default/include/core-impl/ModuleStub.h
index 4f77161..e9b7db4 100644
--- a/audio/aidl/default/include/core-impl/ModuleStub.h
+++ b/audio/aidl/default/include/core-impl/ModuleStub.h
@@ -22,7 +22,7 @@
 
 class ModuleStub final : public Module {
   public:
-    ModuleStub() : Module(Type::STUB) {}
+    ModuleStub(std::unique_ptr<Configuration>&& config) : Module(Type::STUB, std::move(config)) {}
 
   protected:
     ndk::ScopedAStatus getBluetooth(std::shared_ptr<IBluetooth>* _aidl_return) override;
diff --git a/audio/aidl/default/include/core-impl/ModuleUsb.h b/audio/aidl/default/include/core-impl/ModuleUsb.h
index a296b8c..d9ac4f0 100644
--- a/audio/aidl/default/include/core-impl/ModuleUsb.h
+++ b/audio/aidl/default/include/core-impl/ModuleUsb.h
@@ -22,7 +22,7 @@
 
 class ModuleUsb final : public ModuleAlsa {
   public:
-    ModuleUsb() : ModuleAlsa(Type::USB) {}
+    ModuleUsb(std::unique_ptr<Configuration>&& config) : ModuleAlsa(Type::USB, std::move(config)) {}
 
   private:
     // IModule interfaces
@@ -44,7 +44,8 @@
                     offloadInfo,
             std::shared_ptr<StreamOut>* result) override;
     ndk::ScopedAStatus populateConnectedDevicePort(
-            ::aidl::android::media::audio::common::AudioPort* audioPort) override;
+            ::aidl::android::media::audio::common::AudioPort* audioPort,
+            int32_t nextPortId) override;
     ndk::ScopedAStatus checkAudioPatchEndpointsMatch(
             const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sources,
             const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sinks)
diff --git a/audio/aidl/default/include/core-impl/SoundDose.h b/audio/aidl/default/include/core-impl/SoundDose.h
index 2a069d9..f58e541 100644
--- a/audio/aidl/default/include/core-impl/SoundDose.h
+++ b/audio/aidl/default/include/core-impl/SoundDose.h
@@ -20,23 +20,68 @@
 
 #include <aidl/android/hardware/audio/core/sounddose/BnSoundDose.h>
 #include <aidl/android/media/audio/common/AudioDevice.h>
-
-using aidl::android::media::audio::common::AudioDevice;
+#include <aidl/android/media/audio/common/AudioFormatDescription.h>
+#include <audio_utils/MelProcessor.h>
+#include <audio_utils/mutex.h>
 
 namespace aidl::android::hardware::audio::core::sounddose {
 
-class SoundDose : public BnSoundDose {
+// Interface used for processing the data received by a stream.
+class StreamDataProcessorInterface {
   public:
-    SoundDose() : mRs2Value(DEFAULT_MAX_RS2){};
+    virtual ~StreamDataProcessorInterface() = default;
 
+    virtual void startDataProcessor(
+            uint32_t samplerate, uint32_t channelCount,
+            const ::aidl::android::media::audio::common::AudioFormatDescription& format) = 0;
+    virtual void setAudioDevice(
+            const ::aidl::android::media::audio::common::AudioDevice& audioDevice) = 0;
+    virtual void process(const void* buffer, size_t size) = 0;
+};
+
+class SoundDose final : public BnSoundDose, public StreamDataProcessorInterface {
+  public:
+    SoundDose() : mMelCallback(::android::sp<MelCallback>::make(this)){};
+
+    // -------------------------------------- BnSoundDose ------------------------------------------
     ndk::ScopedAStatus setOutputRs2UpperBound(float in_rs2ValueDbA) override;
     ndk::ScopedAStatus getOutputRs2UpperBound(float* _aidl_return) override;
     ndk::ScopedAStatus registerSoundDoseCallback(
             const std::shared_ptr<ISoundDose::IHalSoundDoseCallback>& in_callback) override;
 
+    // ----------------------------- StreamDataProcessorInterface ----------------------------------
+    void setAudioDevice(
+            const ::aidl::android::media::audio::common::AudioDevice& audioDevice) override;
+    void startDataProcessor(
+            uint32_t samplerate, uint32_t channelCount,
+            const ::aidl::android::media::audio::common::AudioFormatDescription& format) override;
+    void process(const void* buffer, size_t size) override;
+
   private:
-    std::shared_ptr<ISoundDose::IHalSoundDoseCallback> mCallback;
-    float mRs2Value;
+    class MelCallback : public ::android::audio_utils::MelProcessor::MelCallback {
+      public:
+        explicit MelCallback(SoundDose* soundDose) : mSoundDose(*soundDose) {}
+
+        // ------------------------------------ MelCallback ----------------------------------------
+        void onNewMelValues(const std::vector<float>& mels, size_t offset, size_t length,
+                            audio_port_handle_t deviceId, bool attenuated) const override;
+        void onMomentaryExposure(float currentMel, audio_port_handle_t deviceId) const override;
+
+        SoundDose& mSoundDose;  // must outlive MelCallback, not owning
+    };
+
+    void onNewMelValues(const std::vector<float>& mels, size_t offset, size_t length,
+                        audio_port_handle_t deviceId) const;
+    void onMomentaryExposure(float currentMel, audio_port_handle_t deviceId) const;
+
+    mutable ::android::audio_utils::mutex mCbMutex;
+    std::shared_ptr<ISoundDose::IHalSoundDoseCallback> mCallback GUARDED_BY(mCbMutex);
+    std::optional<::aidl::android::media::audio::common::AudioDevice> mAudioDevice
+            GUARDED_BY(mCbMutex);
+    mutable ::android::audio_utils::mutex mMutex;
+    float mRs2Value GUARDED_BY(mMutex) = DEFAULT_MAX_RS2;
+    ::android::sp<::android::audio_utils::MelProcessor> mMelProcessor GUARDED_BY(mMutex);
+    ::android::sp<MelCallback> mMelCallback GUARDED_BY(mMutex);
 };
 
 }  // namespace aidl::android::hardware::audio::core::sounddose
diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h
index 88fddec..21e63f9 100644
--- a/audio/aidl/default/include/core-impl/Stream.h
+++ b/audio/aidl/default/include/core-impl/Stream.h
@@ -44,6 +44,7 @@
 #include <utils/Errors.h>
 
 #include "core-impl/ChildInterface.h"
+#include "core-impl/SoundDose.h"
 #include "core-impl/utils.h"
 
 namespace aidl::android::hardware::audio::core {
@@ -80,59 +81,28 @@
 
     StreamContext() = default;
     StreamContext(std::unique_ptr<CommandMQ> commandMQ, std::unique_ptr<ReplyMQ> replyMQ,
-                  int portId,
                   const ::aidl::android::media::audio::common::AudioFormatDescription& format,
                   const ::aidl::android::media::audio::common::AudioChannelLayout& channelLayout,
                   int sampleRate, const ::aidl::android::media::audio::common::AudioIoFlags& flags,
-                  int32_t mixPortHandle, std::unique_ptr<DataMQ> dataMQ,
+                  int32_t nominalLatencyMs, int32_t mixPortHandle, std::unique_ptr<DataMQ> dataMQ,
                   std::shared_ptr<IStreamCallback> asyncCallback,
                   std::shared_ptr<IStreamOutEventCallback> outEventCallback,
+                  std::weak_ptr<sounddose::StreamDataProcessorInterface> streamDataProcessor,
                   DebugParameters debugParameters)
         : mCommandMQ(std::move(commandMQ)),
-          mInternalCommandCookie(std::rand()),
+          mInternalCommandCookie(std::rand() | 1 /* make sure it's not 0 */),
           mReplyMQ(std::move(replyMQ)),
-          mPortId(portId),
           mFormat(format),
           mChannelLayout(channelLayout),
           mSampleRate(sampleRate),
           mFlags(flags),
+          mNominalLatencyMs(nominalLatencyMs),
           mMixPortHandle(mixPortHandle),
           mDataMQ(std::move(dataMQ)),
           mAsyncCallback(asyncCallback),
           mOutEventCallback(outEventCallback),
+          mStreamDataProcessor(streamDataProcessor),
           mDebugParameters(debugParameters) {}
-    StreamContext(StreamContext&& other)
-        : mCommandMQ(std::move(other.mCommandMQ)),
-          mInternalCommandCookie(other.mInternalCommandCookie),
-          mReplyMQ(std::move(other.mReplyMQ)),
-          mPortId(other.mPortId),
-          mFormat(other.mFormat),
-          mChannelLayout(other.mChannelLayout),
-          mSampleRate(other.mSampleRate),
-          mFlags(std::move(other.mFlags)),
-          mMixPortHandle(other.mMixPortHandle),
-          mDataMQ(std::move(other.mDataMQ)),
-          mAsyncCallback(std::move(other.mAsyncCallback)),
-          mOutEventCallback(std::move(other.mOutEventCallback)),
-          mDebugParameters(std::move(other.mDebugParameters)),
-          mFrameCount(other.mFrameCount) {}
-    StreamContext& operator=(StreamContext&& other) {
-        mCommandMQ = std::move(other.mCommandMQ);
-        mInternalCommandCookie = other.mInternalCommandCookie;
-        mReplyMQ = std::move(other.mReplyMQ);
-        mPortId = std::move(other.mPortId);
-        mFormat = std::move(other.mFormat);
-        mChannelLayout = std::move(other.mChannelLayout);
-        mSampleRate = other.mSampleRate;
-        mFlags = std::move(other.mFlags);
-        mMixPortHandle = other.mMixPortHandle;
-        mDataMQ = std::move(other.mDataMQ);
-        mAsyncCallback = std::move(other.mAsyncCallback);
-        mOutEventCallback = std::move(other.mOutEventCallback);
-        mDebugParameters = std::move(other.mDebugParameters);
-        mFrameCount = other.mFrameCount;
-        return *this;
-    }
 
     void fillDescriptor(StreamDescriptor* desc);
     std::shared_ptr<IStreamCallback> getAsyncCallback() const { return mAsyncCallback; }
@@ -151,10 +121,14 @@
     size_t getFrameSize() const;
     int getInternalCommandCookie() const { return mInternalCommandCookie; }
     int32_t getMixPortHandle() const { return mMixPortHandle; }
+    int32_t getNominalLatencyMs() const { return mNominalLatencyMs; }
     std::shared_ptr<IStreamOutEventCallback> getOutEventCallback() const {
         return mOutEventCallback;
     }
-    int getPortId() const { return mPortId; }
+    std::weak_ptr<sounddose::StreamDataProcessorInterface> getStreamDataProcessor() const {
+        return mStreamDataProcessor;
+    }
+    void startStreamDataProcessor();
     ReplyMQ* getReplyMQ() const { return mReplyMQ.get(); }
     int getTransientStateDelayMs() const { return mDebugParameters.transientStateDelayMs; }
     int getSampleRate() const { return mSampleRate; }
@@ -167,18 +141,20 @@
     long getFrameCount() const { return mFrameCount; }
 
   private:
+    // Fields are non const to allow move assignment.
     std::unique_ptr<CommandMQ> mCommandMQ;
     int mInternalCommandCookie;  // The value used to confirm that the command was posted internally
     std::unique_ptr<ReplyMQ> mReplyMQ;
-    int mPortId;
     ::aidl::android::media::audio::common::AudioFormatDescription mFormat;
     ::aidl::android::media::audio::common::AudioChannelLayout mChannelLayout;
     int mSampleRate;
     ::aidl::android::media::audio::common::AudioIoFlags mFlags;
+    int32_t mNominalLatencyMs;
     int32_t mMixPortHandle;
     std::unique_ptr<DataMQ> mDataMQ;
     std::shared_ptr<IStreamCallback> mAsyncCallback;
     std::shared_ptr<IStreamOutEventCallback> mOutEventCallback;  // Only used by output streams
+    std::weak_ptr<sounddose::StreamDataProcessorInterface> mStreamDataProcessor;
     DebugParameters mDebugParameters;
     long mFrameCount = 0;
 };
diff --git a/audio/aidl/default/include/core-impl/StreamBluetooth.h b/audio/aidl/default/include/core-impl/StreamBluetooth.h
index c2f8c1d..35c3183 100644
--- a/audio/aidl/default/include/core-impl/StreamBluetooth.h
+++ b/audio/aidl/default/include/core-impl/StreamBluetooth.h
@@ -24,15 +24,23 @@
 #include <aidl/android/hardware/audio/core/IBluetoothLe.h>
 
 #include "core-impl/DevicePortProxy.h"
-#include "core-impl/Module.h"
+#include "core-impl/ModuleBluetooth.h"
 #include "core-impl/Stream.h"
 
 namespace aidl::android::hardware::audio::core {
 
 class StreamBluetooth : public StreamCommonImpl {
   public:
-    StreamBluetooth(StreamContext* context, const Metadata& metadata,
-                    Module::BtProfileHandles&& btHandles);
+    static bool checkConfigParams(
+            const ::aidl::android::hardware::bluetooth::audio::PcmConfiguration& pcmConfig,
+            const ::aidl::android::media::audio::common::AudioConfigBase& config);
+
+    StreamBluetooth(
+            StreamContext* context, const Metadata& metadata,
+            ModuleBluetooth::BtProfileHandles&& btHandles,
+            const std::shared_ptr<::android::bluetooth::audio::aidl::BluetoothAudioPortAidl>&
+                    btDeviceProxy,
+            const ::aidl::android::hardware::bluetooth::audio::PcmConfiguration& pcmConfig);
     // Methods of 'DriverInterface'.
     ::android::status_t init() override;
     ::android::status_t drain(StreamDescriptor::DrainMode) override;
@@ -47,40 +55,35 @@
     // Overridden methods of 'StreamCommonImpl', called on a Binder thread.
     ndk::ScopedAStatus updateMetadataCommon(const Metadata& metadata) override;
     ndk::ScopedAStatus prepareToClose() override;
-    const ConnectedDevices& getConnectedDevices() const override;
-    ndk::ScopedAStatus setConnectedDevices(const ConnectedDevices& devices) override;
     ndk::ScopedAStatus bluetoothParametersUpdated() override;
 
   private:
-    // Audio Pcm Config
-    const uint32_t mSampleRate;
-    const ::aidl::android::media::audio::common::AudioChannelLayout mChannelLayout;
-    const ::aidl::android::media::audio::common::AudioFormatDescription mFormat;
     const size_t mFrameSizeBytes;
     const bool mIsInput;
     const std::weak_ptr<IBluetoothA2dp> mBluetoothA2dp;
     const std::weak_ptr<IBluetoothLe> mBluetoothLe;
-    size_t mPreferredDataIntervalUs;
-    size_t mPreferredFrameCount;
-
+    const size_t mPreferredDataIntervalUs;
+    const size_t mPreferredFrameCount;
     mutable std::mutex mLock;
-    bool mIsInitialized GUARDED_BY(mLock);
-    bool mIsReadyToClose GUARDED_BY(mLock);
-    std::vector<std::shared_ptr<::android::bluetooth::audio::aidl::BluetoothAudioPortAidl>>
-            mBtDeviceProxies GUARDED_BY(mLock);
-
-    ::android::status_t initialize() REQUIRES(mLock);
-    bool checkConfigParams(::aidl::android::hardware::bluetooth::audio::PcmConfiguration& config);
+    // The lock is also used to serialize calls to the proxy.
+    std::shared_ptr<::android::bluetooth::audio::aidl::BluetoothAudioPortAidl> mBtDeviceProxy
+            GUARDED_BY(mLock);  // proxy may be null if the stream is not connected to a device
 };
 
 class StreamInBluetooth final : public StreamIn, public StreamBluetooth {
   public:
     friend class ndk::SharedRefBase;
+
+    static int32_t getNominalLatencyMs(size_t dataIntervalUs);
+
     StreamInBluetooth(
             StreamContext&& context,
             const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
             const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones,
-            Module::BtProfileHandles&& btHandles);
+            ModuleBluetooth::BtProfileHandles&& btHandles,
+            const std::shared_ptr<::android::bluetooth::audio::aidl::BluetoothAudioPortAidl>&
+                    btDeviceProxy,
+            const ::aidl::android::hardware::bluetooth::audio::PcmConfiguration& pcmConfig);
 
   private:
     void onClose(StreamDescriptor::State) override { defaultOnClose(); }
@@ -92,12 +95,18 @@
 class StreamOutBluetooth final : public StreamOut, public StreamBluetooth {
   public:
     friend class ndk::SharedRefBase;
+
+    static int32_t getNominalLatencyMs(size_t dataIntervalUs);
+
     StreamOutBluetooth(
             StreamContext&& context,
             const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
             const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
                     offloadInfo,
-            Module::BtProfileHandles&& btHandles);
+            ModuleBluetooth::BtProfileHandles&& btHandles,
+            const std::shared_ptr<::android::bluetooth::audio::aidl::BluetoothAudioPortAidl>&
+                    btDeviceProxy,
+            const ::aidl::android::hardware::bluetooth::audio::PcmConfiguration& pcmConfig);
 
   private:
     void onClose(StreamDescriptor::State) override { defaultOnClose(); }
diff --git a/audio/aidl/default/include/core-impl/StreamPrimary.h b/audio/aidl/default/include/core-impl/StreamPrimary.h
index b3ddd0b..8d5c57d 100644
--- a/audio/aidl/default/include/core-impl/StreamPrimary.h
+++ b/audio/aidl/default/include/core-impl/StreamPrimary.h
@@ -27,10 +27,18 @@
   public:
     StreamPrimary(StreamContext* context, const Metadata& metadata);
 
+    ::android::status_t start() override;
+    ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
+                                 int32_t* latencyMs) override;
+    ::android::status_t refinePosition(StreamDescriptor::Position* position) override;
+
   protected:
     std::vector<alsa::DeviceProfile> getDeviceProfiles() override;
 
-    const bool mIsInput;
+    const bool mIsAsynchronous;
+    int64_t mStartTimeNs = 0;
+    long mFramesSinceStart = 0;
+    bool mSkipNextTransfer = false;
 };
 
 class StreamInPrimary final : public StreamIn, public StreamSwitcher, public StreamInHwGainHelper {
@@ -79,6 +87,10 @@
 
     ndk::ScopedAStatus getHwVolume(std::vector<float>* _aidl_return) override;
     ndk::ScopedAStatus setHwVolume(const std::vector<float>& in_channelVolumes) override;
+
+    ndk::ScopedAStatus setConnectedDevices(
+            const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices)
+            override;
 };
 
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h b/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h
index 94404a1..b2cdc28 100644
--- a/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h
+++ b/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h
@@ -16,7 +16,6 @@
 
 #pragma once
 
-#include <mutex>
 #include <vector>
 
 #include "core-impl/Stream.h"
@@ -46,7 +45,7 @@
     ndk::ScopedAStatus prepareToClose() override;
 
   private:
-    size_t getPipeSizeInFrames();
+    long getDelayInUsForFrameCount(size_t frameCount);
     size_t getStreamPipeSizeInFrames();
     ::android::status_t outWrite(void* buffer, size_t frameCount, size_t* actualFrameCount);
     ::android::status_t inRead(void* buffer, size_t frameCount, size_t* actualFrameCount);
@@ -56,13 +55,6 @@
     r_submix::AudioConfig mStreamConfig;
     std::shared_ptr<r_submix::SubmixRoute> mCurrentRoute = nullptr;
 
-    // Mutex lock to protect vector of submix routes, each of these submix routes have their mutex
-    // locks and none of the mutex locks should be taken together.
-    static std::mutex sSubmixRoutesLock;
-    static std::map<::aidl::android::media::audio::common::AudioDeviceAddress,
-                    std::shared_ptr<r_submix::SubmixRoute>>
-            sSubmixRoutes GUARDED_BY(sSubmixRoutesLock);
-
     // limit for number of read error log entries to avoid spamming the logs
     static constexpr int kMaxReadErrorLogs = 5;
     // The duration of kMaxReadFailureAttempts * READ_ATTEMPT_SLEEP_MS must be strictly inferior
@@ -71,6 +63,11 @@
     static constexpr int kMaxReadFailureAttempts = 3;
     // 5ms between two read attempts when pipe is empty
     static constexpr int kReadAttemptSleepUs = 5000;
+
+    int64_t mStartTimeNs = 0;
+    long mFramesSinceStart = 0;
+    int mReadErrorCount = 0;
+    int mReadFailureCount = 0;
 };
 
 class StreamInRemoteSubmix final : public StreamIn, public StreamSwitcher {
diff --git a/audio/aidl/default/include/core-impl/XmlConverter.h b/audio/aidl/default/include/core-impl/XmlConverter.h
index 383ea24..68e6b8e 100644
--- a/audio/aidl/default/include/core-impl/XmlConverter.h
+++ b/audio/aidl/default/include/core-impl/XmlConverter.h
@@ -22,7 +22,6 @@
 
 #include <media/AidlConversionUtil.h>
 #include <system/audio_config.h>
-#include <utils/Errors.h>
 
 namespace aidl::android::hardware::audio::core::internal {
 
@@ -85,10 +84,10 @@
  *     </Modules>
  */
 template <typename W, typename X, typename A>
-std::vector<A> convertWrappedCollectionToAidlUnchecked(
+static ConversionResult<std::vector<A>> convertWrappedCollectionToAidl(
         const std::vector<W>& xsdcWrapperTypeVec,
         std::function<const std::vector<X>&(const W&)> getInnerTypeVec,
-        std::function<A(const X&)> convertToAidl) {
+        std::function<ConversionResult<A>(const X&)> convertToAidl) {
     std::vector<A> resultAidlTypeVec;
     if (!xsdcWrapperTypeVec.empty()) {
         /*
@@ -98,21 +97,23 @@
          */
         resultAidlTypeVec.reserve(getInnerTypeVec(xsdcWrapperTypeVec[0]).size());
         for (const W& xsdcWrapperType : xsdcWrapperTypeVec) {
-            std::transform(getInnerTypeVec(xsdcWrapperType).begin(),
-                           getInnerTypeVec(xsdcWrapperType).end(),
-                           std::back_inserter(resultAidlTypeVec), convertToAidl);
+            for (const X& xsdcType : getInnerTypeVec(xsdcWrapperType)) {
+                resultAidlTypeVec.push_back(VALUE_OR_FATAL(convertToAidl(xsdcType)));
+            }
         }
     }
     return resultAidlTypeVec;
 }
 
 template <typename X, typename A>
-std::vector<A> convertCollectionToAidlUnchecked(const std::vector<X>& xsdcTypeVec,
-                                                std::function<A(const X&)> itemConversion) {
+static ConversionResult<std::vector<A>> convertCollectionToAidl(
+        const std::vector<X>& xsdcTypeVec,
+        std::function<ConversionResult<A>(const X&)> convertToAidl) {
     std::vector<A> resultAidlTypeVec;
     resultAidlTypeVec.reserve(xsdcTypeVec.size());
-    std::transform(xsdcTypeVec.begin(), xsdcTypeVec.end(), std::back_inserter(resultAidlTypeVec),
-                   itemConversion);
+    for (const X& xsdcType : xsdcTypeVec) {
+        resultAidlTypeVec.push_back(VALUE_OR_FATAL(convertToAidl(xsdcType)));
+    }
     return resultAidlTypeVec;
 }
 
diff --git a/audio/aidl/default/include/core-impl/XsdcConversion.h b/audio/aidl/default/include/core-impl/XsdcConversion.h
new file mode 100644
index 0000000..30dc8b6
--- /dev/null
+++ b/audio/aidl/default/include/core-impl/XsdcConversion.h
@@ -0,0 +1,29 @@
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+
+#include <aidl/android/media/audio/common/AudioHalCapCriterion.h>
+#include <aidl/android/media/audio/common/AudioHalCapCriterionType.h>
+#include <aidl/android/media/audio/common/AudioHalVolumeCurve.h>
+#include <aidl/android/media/audio/common/AudioPort.h>
+#include <android_audio_policy_configuration.h>
+#include <android_audio_policy_configuration_enums.h>
+#include <android_audio_policy_engine_configuration.h>
+#include <media/AidlConversionUtil.h>
+
+#include "core-impl/Module.h"
+
+namespace aidl::android::hardware::audio::core::internal {
+
+ConversionResult<::aidl::android::media::audio::common::AudioHalCapCriterion>
+convertCapCriterionToAidl(
+        const ::android::audio::policy::engine::configuration::CriterionType& xsdcCriterion);
+ConversionResult<::aidl::android::media::audio::common::AudioHalCapCriterionType>
+convertCapCriterionTypeToAidl(
+        const ::android::audio::policy::engine::configuration::CriterionTypeType&
+                xsdcCriterionType);
+ConversionResult<::aidl::android::media::audio::common::AudioHalVolumeCurve::CurvePoint>
+convertCurvePointToAidl(const std::string& xsdcCurvePoint);
+ConversionResult<std::unique_ptr<Module::Configuration>> convertModuleConfigToAidl(
+        const ::android::audio::policy::configuration::Modules::Module& moduleConfig);
+}  // namespace aidl::android::hardware::audio::core::internal
diff --git a/audio/aidl/default/include/effect-impl/EffectContext.h b/audio/aidl/default/include/effect-impl/EffectContext.h
index 698e7a5..24f3b5d 100644
--- a/audio/aidl/default/include/effect-impl/EffectContext.h
+++ b/audio/aidl/default/include/effect-impl/EffectContext.h
@@ -21,6 +21,7 @@
 #include <Utils.h>
 #include <android-base/logging.h>
 #include <fmq/AidlMessageQueue.h>
+#include <fmq/EventFlag.h>
 
 #include <aidl/android/hardware/audio/effect/BnEffect.h>
 #include "EffectTypes.h"
@@ -36,119 +37,73 @@
             float, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
             DataMQ;
 
-    EffectContext(size_t statusDepth, const Parameter::Common& common) {
-        auto& input = common.input;
-        auto& output = common.output;
-
-        LOG_ALWAYS_FATAL_IF(
-                input.base.format.pcm != aidl::android::media::audio::common::PcmType::FLOAT_32_BIT,
-                "inputFormatNotFloat");
-        LOG_ALWAYS_FATAL_IF(output.base.format.pcm !=
-                                    aidl::android::media::audio::common::PcmType::FLOAT_32_BIT,
-                            "outputFormatNotFloat");
-        mInputFrameSize = ::aidl::android::hardware::audio::common::getFrameSizeInBytes(
-                input.base.format, input.base.channelMask);
-        mOutputFrameSize = ::aidl::android::hardware::audio::common::getFrameSizeInBytes(
-                output.base.format, output.base.channelMask);
-        // in/outBuffer size in float (FMQ data format defined for DataMQ)
-        size_t inBufferSizeInFloat = input.frameCount * mInputFrameSize / sizeof(float);
-        size_t outBufferSizeInFloat = output.frameCount * mOutputFrameSize / sizeof(float);
-
-        // only status FMQ use the EventFlag
-        mStatusMQ = std::make_shared<StatusMQ>(statusDepth, true /*configureEventFlagWord*/);
-        mInputMQ = std::make_shared<DataMQ>(inBufferSizeInFloat);
-        mOutputMQ = std::make_shared<DataMQ>(outBufferSizeInFloat);
-
-        if (!mStatusMQ->isValid() || !mInputMQ->isValid() || !mOutputMQ->isValid()) {
-            LOG(ERROR) << __func__ << " created invalid FMQ";
+    EffectContext(size_t statusDepth, const Parameter::Common& common);
+    virtual ~EffectContext() {
+        if (mEfGroup) {
+            ::android::hardware::EventFlag::deleteEventFlag(&mEfGroup);
         }
-        mWorkBuffer.reserve(std::max(inBufferSizeInFloat, outBufferSizeInFloat));
-        mCommon = common;
     }
-    virtual ~EffectContext() {}
 
-    std::shared_ptr<StatusMQ> getStatusFmq() { return mStatusMQ; }
-    std::shared_ptr<DataMQ> getInputDataFmq() { return mInputMQ; }
-    std::shared_ptr<DataMQ> getOutputDataFmq() { return mOutputMQ; }
+    std::shared_ptr<StatusMQ> getStatusFmq() const;
+    std::shared_ptr<DataMQ> getInputDataFmq() const;
+    std::shared_ptr<DataMQ> getOutputDataFmq() const;
 
-    float* getWorkBuffer() { return static_cast<float*>(mWorkBuffer.data()); }
+    float* getWorkBuffer();
 
     // reset buffer status by abandon input data in FMQ
-    void resetBuffer() {
-        auto buffer = static_cast<float*>(mWorkBuffer.data());
-        std::vector<IEffect::Status> status(mStatusMQ->availableToRead());
-        mInputMQ->read(buffer, mInputMQ->availableToRead());
-    }
+    void resetBuffer();
+    void dupeFmq(IEffect::OpenEffectReturn* effectRet);
+    size_t getInputFrameSize() const;
+    size_t getOutputFrameSize() const;
+    int getSessionId() const;
+    int getIoHandle() const;
 
-    void dupeFmq(IEffect::OpenEffectReturn* effectRet) {
-        if (effectRet) {
-            effectRet->statusMQ = mStatusMQ->dupeDesc();
-            effectRet->inputDataMQ = mInputMQ->dupeDesc();
-            effectRet->outputDataMQ = mOutputMQ->dupeDesc();
-        }
-    }
-    size_t getInputFrameSize() { return mInputFrameSize; }
-    size_t getOutputFrameSize() { return mOutputFrameSize; }
-    int getSessionId() { return mCommon.session; }
-    int getIoHandle() { return mCommon.ioHandle; }
+    virtual void dupeFmqWithReopen(IEffect::OpenEffectReturn* effectRet);
 
     virtual RetCode setOutputDevice(
-            const std::vector<aidl::android::media::audio::common::AudioDeviceDescription>&
-                    device) {
-        mOutputDevice = device;
-        return RetCode::SUCCESS;
-    }
+            const std::vector<aidl::android::media::audio::common::AudioDeviceDescription>& device);
 
     virtual std::vector<aidl::android::media::audio::common::AudioDeviceDescription>
-    getOutputDevice() {
-        return mOutputDevice;
-    }
+    getOutputDevice();
 
-    virtual RetCode setAudioMode(const aidl::android::media::audio::common::AudioMode& mode) {
-        mMode = mode;
-        return RetCode::SUCCESS;
-    }
-    virtual aidl::android::media::audio::common::AudioMode getAudioMode() { return mMode; }
+    virtual RetCode setAudioMode(const aidl::android::media::audio::common::AudioMode& mode);
+    virtual aidl::android::media::audio::common::AudioMode getAudioMode();
 
-    virtual RetCode setAudioSource(const aidl::android::media::audio::common::AudioSource& source) {
-        mSource = source;
-        return RetCode::SUCCESS;
-    }
-    virtual aidl::android::media::audio::common::AudioSource getAudioSource() { return mSource; }
+    virtual RetCode setAudioSource(const aidl::android::media::audio::common::AudioSource& source);
+    virtual aidl::android::media::audio::common::AudioSource getAudioSource();
 
-    virtual RetCode setVolumeStereo(const Parameter::VolumeStereo& volumeStereo) {
-        mVolumeStereo = volumeStereo;
-        return RetCode::SUCCESS;
-    }
-    virtual Parameter::VolumeStereo getVolumeStereo() { return mVolumeStereo; }
+    virtual RetCode setVolumeStereo(const Parameter::VolumeStereo& volumeStereo);
+    virtual Parameter::VolumeStereo getVolumeStereo();
 
-    virtual RetCode setCommon(const Parameter::Common& common) {
-        mCommon = common;
-        LOG(VERBOSE) << __func__ << mCommon.toString();
-        return RetCode::SUCCESS;
-    }
-    virtual Parameter::Common getCommon() {
-        LOG(VERBOSE) << __func__ << mCommon.toString();
-        return mCommon;
-    }
+    virtual RetCode setCommon(const Parameter::Common& common);
+    virtual Parameter::Common getCommon();
+
+    virtual ::android::hardware::EventFlag* getStatusEventFlag();
 
   protected:
-    // common parameters
     size_t mInputFrameSize;
     size_t mOutputFrameSize;
-    Parameter::Common mCommon;
-    std::vector<aidl::android::media::audio::common::AudioDeviceDescription> mOutputDevice;
-    aidl::android::media::audio::common::AudioMode mMode;
-    aidl::android::media::audio::common::AudioSource mSource;
-    Parameter::VolumeStereo mVolumeStereo;
+    size_t mInputChannelCount;
+    size_t mOutputChannelCount;
+    Parameter::Common mCommon = {};
+    std::vector<aidl::android::media::audio::common::AudioDeviceDescription> mOutputDevice = {};
+    aidl::android::media::audio::common::AudioMode mMode =
+            aidl::android::media::audio::common::AudioMode::SYS_RESERVED_INVALID;
+    aidl::android::media::audio::common::AudioSource mSource =
+            aidl::android::media::audio::common::AudioSource::SYS_RESERVED_INVALID;
+    Parameter::VolumeStereo mVolumeStereo = {};
+    RetCode updateIOFrameSize(const Parameter::Common& common);
+    RetCode notifyDataMqUpdate();
 
   private:
     // fmq and buffers
     std::shared_ptr<StatusMQ> mStatusMQ;
     std::shared_ptr<DataMQ> mInputMQ;
     std::shared_ptr<DataMQ> mOutputMQ;
-    // TODO handle effect process input and output
+    // std::shared_ptr<IEffect::OpenEffectReturn> mRet;
     // work buffer set by effect instances, the access and update are in same thread
     std::vector<float> mWorkBuffer;
+
+    ::android::hardware::EventFlag* mEfGroup;
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/effect-impl/EffectImpl.h b/audio/aidl/default/include/effect-impl/EffectImpl.h
index e7d081f..21f6502 100644
--- a/audio/aidl/default/include/effect-impl/EffectImpl.h
+++ b/audio/aidl/default/include/effect-impl/EffectImpl.h
@@ -43,38 +43,60 @@
                                     OpenEffectReturn* ret) override;
     virtual ndk::ScopedAStatus close() override;
     virtual ndk::ScopedAStatus command(CommandId id) override;
+    virtual ndk::ScopedAStatus reopen(OpenEffectReturn* ret) override;
 
     virtual ndk::ScopedAStatus getState(State* state) override;
     virtual ndk::ScopedAStatus setParameter(const Parameter& param) override;
     virtual ndk::ScopedAStatus getParameter(const Parameter::Id& id, Parameter* param) override;
 
-    virtual ndk::ScopedAStatus setParameterCommon(const Parameter& param);
-    virtual ndk::ScopedAStatus getParameterCommon(const Parameter::Tag& tag, Parameter* param);
+    virtual ndk::ScopedAStatus setParameterCommon(const Parameter& param) REQUIRES(mImplMutex);
+    virtual ndk::ScopedAStatus getParameterCommon(const Parameter::Tag& tag, Parameter* param)
+            REQUIRES(mImplMutex);
 
     /* Methods MUST be implemented by each effect instances */
     virtual ndk::ScopedAStatus getDescriptor(Descriptor* desc) = 0;
-    virtual ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) = 0;
+    virtual ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex) = 0;
     virtual ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
-                                                    Parameter::Specific* specific) = 0;
+                                                    Parameter::Specific* specific)
+            REQUIRES(mImplMutex) = 0;
 
     virtual std::string getEffectName() = 0;
-    virtual IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+    virtual std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+            REQUIRES(mImplMutex);
+    virtual RetCode releaseContext() REQUIRES(mImplMutex) = 0;
 
     /**
-     * Effect context methods must be implemented by each effect.
-     * Each effect can derive from EffectContext and define its own context, but must upcast to
-     * EffectContext for EffectImpl to use.
+     * @brief effectProcessImpl is running in worker thread which created in EffectThread.
+     *
+     * EffectThread will make sure effectProcessImpl only be called after startThread() successful
+     * and before stopThread() successful.
+     *
+     * effectProcessImpl implementation must not call any EffectThread interface, otherwise it will
+     * cause deadlock.
+     *
+     * @param in address of input float buffer.
+     * @param out address of output float buffer.
+     * @param samples number of samples to process.
+     * @return IEffect::Status
      */
-    virtual std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) = 0;
-    virtual std::shared_ptr<EffectContext> getContext() = 0;
-    virtual RetCode releaseContext() = 0;
+    virtual IEffect::Status effectProcessImpl(float* in, float* out, int samples) = 0;
+
+    /**
+     * process() get data from data MQs, and call effectProcessImpl() for effect data processing.
+     * Its important for the implementation to use mImplMutex for context synchronization.
+     */
+    void process() override;
 
   protected:
-    State mState = State::INIT;
+    State mState GUARDED_BY(mImplMutex) = State::INIT;
 
     IEffect::Status status(binder_status_t status, size_t consumed, size_t produced);
     void cleanUp();
 
+    std::mutex mImplMutex;
+    std::shared_ptr<EffectContext> mImplContext GUARDED_BY(mImplMutex);
+
     /**
      * Optional CommandId handling methods for effects to override.
      * For CommandId::START, EffectImpl call commandImpl before starting the EffectThread
@@ -82,6 +104,9 @@
      * For CommandId::STOP and CommandId::RESET, EffectImpl call commandImpl after stop the
      * EffectThread processing.
      */
-    virtual ndk::ScopedAStatus commandImpl(CommandId id);
+    virtual ndk::ScopedAStatus commandImpl(CommandId id) REQUIRES(mImplMutex);
+
+    RetCode notifyEventFlag(uint32_t flag);
+    ::android::hardware::EventFlag* mEventFlag;
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/effect-impl/EffectThread.h b/audio/aidl/default/include/effect-impl/EffectThread.h
index ae51ef7..3dbb0e6 100644
--- a/audio/aidl/default/include/effect-impl/EffectThread.h
+++ b/audio/aidl/default/include/effect-impl/EffectThread.h
@@ -36,8 +36,7 @@
     virtual ~EffectThread();
 
     // called by effect implementation.
-    RetCode createThread(std::shared_ptr<EffectContext> context, const std::string& name,
-                         int priority = ANDROID_PRIORITY_URGENT_AUDIO);
+    RetCode createThread(const std::string& name, int priority = ANDROID_PRIORITY_URGENT_AUDIO);
     RetCode destroyThread();
     RetCode startThread();
     RetCode stopThread();
@@ -46,32 +45,11 @@
     void threadLoop();
 
     /**
-     * @brief effectProcessImpl is running in worker thread which created in EffectThread.
-     *
-     * Effect implementation should think about concurrency in the implementation if necessary.
-     * Parameter setting usually implemented in context (derived from EffectContext), and some
-     * parameter maybe used in the processing, then effect implementation should consider using a
-     * mutex to protect these parameter.
-     *
-     * EffectThread will make sure effectProcessImpl only be called after startThread() successful
-     * and before stopThread() successful.
-     *
-     * effectProcessImpl implementation must not call any EffectThread interface, otherwise it will
-     * cause deadlock.
-     *
-     * @param in address of input float buffer.
-     * @param out address of output float buffer.
-     * @param samples number of samples to process.
-     * @return IEffect::Status
-     */
-    virtual IEffect::Status effectProcessImpl(float* in, float* out, int samples) = 0;
-
-    /**
      * process() call effectProcessImpl() for effect data processing, it is necessary for the
      * processing to be called under Effect thread mutex mThreadMutex, to avoid the effect state
      * change before/during data processing, and keep the thread and effect state consistent.
      */
-    virtual void process_l() REQUIRES(mThreadMutex);
+    virtual void process() = 0;
 
   private:
     static constexpr int kMaxTaskNameLen = 15;
@@ -80,16 +58,7 @@
     std::condition_variable mCv;
     bool mStop GUARDED_BY(mThreadMutex) = true;
     bool mExit GUARDED_BY(mThreadMutex) = false;
-    std::shared_ptr<EffectContext> mThreadContext GUARDED_BY(mThreadMutex);
 
-    struct EventFlagDeleter {
-        void operator()(::android::hardware::EventFlag* flag) const {
-            if (flag) {
-                ::android::hardware::EventFlag::deleteEventFlag(&flag);
-            }
-        }
-    };
-    std::unique_ptr<::android::hardware::EventFlag, EventFlagDeleter> mEfGroup;
     std::thread mThread;
     int mPriority;
     std::string mName;
diff --git a/audio/aidl/default/include/effect-impl/EffectTypes.h b/audio/aidl/default/include/effect-impl/EffectTypes.h
index 4bda7be..9740d6e 100644
--- a/audio/aidl/default/include/effect-impl/EffectTypes.h
+++ b/audio/aidl/default/include/effect-impl/EffectTypes.h
@@ -46,7 +46,8 @@
     ERROR_NULL_POINTER,      /* NULL pointer */
     ERROR_ALIGNMENT_ERROR,   /* Memory alignment error */
     ERROR_BLOCK_SIZE_EXCEED, /* Maximum block size exceeded */
-    ERROR_EFFECT_LIB_ERROR
+    ERROR_EFFECT_LIB_ERROR,  /* Effect implementation library error */
+    ERROR_EVENT_FLAG_ERROR   /* Error with effect event flags */
 };
 
 static const int INVALID_AUDIO_SESSION_ID = -1;
@@ -67,6 +68,8 @@
             return out << "ERROR_BLOCK_SIZE_EXCEED";
         case RetCode::ERROR_EFFECT_LIB_ERROR:
             return out << "ERROR_EFFECT_LIB_ERROR";
+        case RetCode::ERROR_EVENT_FLAG_ERROR:
+            return out << "ERROR_EVENT_FLAG_ERROR";
     }
 
     return out << "EnumError: " << code;
diff --git a/audio/aidl/default/include/effectFactory-impl/EffectConfig.h b/audio/aidl/default/include/effectFactory-impl/EffectConfig.h
index 344846a..7456b99 100644
--- a/audio/aidl/default/include/effectFactory-impl/EffectConfig.h
+++ b/audio/aidl/default/include/effectFactory-impl/EffectConfig.h
@@ -64,12 +64,16 @@
     const ProcessingLibrariesMap& getProcessingMap() const;
 
   private:
-    static constexpr const char* kEffectLibPath[] =
 #ifdef __LP64__
-            {"/odm/lib64/soundfx", "/vendor/lib64/soundfx", "/system/lib64/soundfx"};
+#define SOUND_FX_PATH "/lib64/soundfx/"
 #else
-            {"/odm/lib/soundfx", "/vendor/lib/soundfx", "/system/lib/soundfx"};
+#define SOUND_FX_PATH "/lib/soundfx/"
 #endif
+    static constexpr const char* kEffectLibPath[] =
+      { "/odm" SOUND_FX_PATH, "/vendor" SOUND_FX_PATH, "/system" SOUND_FX_PATH };
+
+    static constexpr const char* kEffectLibApexPath = SOUND_FX_PATH;
+#undef SOUND_FX_PATH
 
     int mSkippedElements;
     /* Parsed Libraries result */
diff --git a/audio/aidl/default/loudnessEnhancer/Android.bp b/audio/aidl/default/loudnessEnhancer/Android.bp
index 89a72fe..cd44b50 100644
--- a/audio/aidl/default/loudnessEnhancer/Android.bp
+++ b/audio/aidl/default/loudnessEnhancer/Android.bp
@@ -27,8 +27,6 @@
     name: "libloudnessenhancersw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "LoudnessEnhancerSw.cpp",
diff --git a/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.cpp b/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.cpp
index 7954316..1e70716 100644
--- a/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.cpp
+++ b/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.cpp
@@ -147,10 +147,6 @@
     return mContext;
 }
 
-std::shared_ptr<EffectContext> LoudnessEnhancerSw::getContext() {
-    return mContext;
-}
-
 RetCode LoudnessEnhancerSw::releaseContext() {
     if (mContext) {
         mContext.reset();
diff --git a/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.h b/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.h
index 25824f2..cf71a5f 100644
--- a/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.h
+++ b/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.h
@@ -54,20 +54,23 @@
     }
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
-    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
-    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
-                                            Parameter::Specific* specific) override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+            REQUIRES(mImplMutex) override;
 
-    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
-    std::shared_ptr<EffectContext> getContext() override;
-    RetCode releaseContext() override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+            REQUIRES(mImplMutex) override;
+    RetCode releaseContext() REQUIRES(mImplMutex) override;
 
-    IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+    IEffect::Status effectProcessImpl(float* in, float* out, int samples)
+            REQUIRES(mImplMutex) override;
     std::string getEffectName() override { return kEffectName; }
 
   private:
-    std::shared_ptr<LoudnessEnhancerSwContext> mContext;
+    std::shared_ptr<LoudnessEnhancerSwContext> mContext GUARDED_BY(mImplMutex);
     ndk::ScopedAStatus getParameterLoudnessEnhancer(const LoudnessEnhancer::Tag& tag,
-                                                    Parameter::Specific* specific);
+                                                    Parameter::Specific* specific)
+            REQUIRES(mImplMutex);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/main.cpp b/audio/aidl/default/main.cpp
index a0c0fab..6ab747d 100644
--- a/audio/aidl/default/main.cpp
+++ b/audio/aidl/default/main.cpp
@@ -16,21 +16,51 @@
 
 #include <cstdlib>
 #include <ctime>
-#include <sstream>
 #include <utility>
 #include <vector>
 
+#define LOG_TAG "AHAL_Main"
 #include <android-base/logging.h>
 #include <android-base/properties.h>
 #include <android/binder_ibinder_platform.h>
 #include <android/binder_manager.h>
 #include <android/binder_process.h>
 
+#include "core-impl/AudioPolicyConfigXmlConverter.h"
+#include "core-impl/ChildInterface.h"
 #include "core-impl/Config.h"
 #include "core-impl/Module.h"
 
+using aidl::android::hardware::audio::core::ChildInterface;
 using aidl::android::hardware::audio::core::Config;
 using aidl::android::hardware::audio::core::Module;
+using aidl::android::hardware::audio::core::internal::AudioPolicyConfigXmlConverter;
+
+namespace {
+
+ChildInterface<Module> createModule(const std::string& name,
+                                    std::unique_ptr<Module::Configuration>&& config) {
+    ChildInterface<Module> result;
+    {
+        auto moduleType = Module::typeFromString(name);
+        if (!moduleType.has_value()) {
+            LOG(ERROR) << __func__ << ": module type \"" << name << "\" is not supported";
+            return result;
+        }
+        auto module = Module::createInstance(*moduleType, std::move(config));
+        if (module == nullptr) return result;
+        result = std::move(module);
+    }
+    const std::string moduleFqn = std::string().append(Module::descriptor).append("/").append(name);
+    binder_status_t status = AServiceManager_addService(result.getBinder(), moduleFqn.c_str());
+    if (status != STATUS_OK) {
+        LOG(ERROR) << __func__ << ": failed to register service for \"" << moduleFqn << "\"";
+        return ChildInterface<Module>();
+    }
+    return result;
+};
+
+}  // namespace
 
 int main() {
     // Random values are used in the implementation.
@@ -45,29 +75,27 @@
     // Guaranteed log for b/210919187 and logd_integration_test
     LOG(INFO) << "Init for Audio AIDL HAL";
 
+    AudioPolicyConfigXmlConverter audioPolicyConverter{
+            ::android::audio_get_audio_policy_config_file()};
+
     // Make the default config service
-    auto config = ndk::SharedRefBase::make<Config>();
-    const std::string configName = std::string() + Config::descriptor + "/default";
+    auto config = ndk::SharedRefBase::make<Config>(audioPolicyConverter);
+    const std::string configFqn = std::string().append(Config::descriptor).append("/default");
     binder_status_t status =
-            AServiceManager_addService(config->asBinder().get(), configName.c_str());
-    CHECK_EQ(STATUS_OK, status);
+            AServiceManager_addService(config->asBinder().get(), configFqn.c_str());
+    if (status != STATUS_OK) {
+        LOG(ERROR) << "failed to register service for \"" << configFqn << "\"";
+    }
 
     // Make modules
-    auto createModule = [](Module::Type type) {
-        auto module = Module::createInstance(type);
-        ndk::SpAIBinder moduleBinder = module->asBinder();
-        std::stringstream moduleName;
-        moduleName << Module::descriptor << "/" << type;
-        AIBinder_setMinSchedulerPolicy(moduleBinder.get(), SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
-        binder_status_t status =
-                AServiceManager_addService(moduleBinder.get(), moduleName.str().c_str());
-        CHECK_EQ(STATUS_OK, status);
-        return std::make_pair(module, moduleBinder);
-    };
-    auto modules = {createModule(Module::Type::DEFAULT), createModule(Module::Type::R_SUBMIX),
-                    createModule(Module::Type::USB), createModule(Module::Type::STUB),
-                    createModule(Module::Type::BLUETOOTH)};
-    (void)modules;
+    std::vector<ChildInterface<Module>> moduleInstances;
+    auto configs(audioPolicyConverter.releaseModuleConfigs());
+    for (std::pair<std::string, std::unique_ptr<Module::Configuration>>& configPair : *configs) {
+        std::string name = configPair.first;
+        if (auto instance = createModule(name, std::move(configPair.second)); instance) {
+            moduleInstances.push_back(std::move(instance));
+        }
+    }
 
     ABinderProcess_joinThreadPool();
     return EXIT_FAILURE;  // should not reach
diff --git a/audio/aidl/default/noiseSuppression/Android.bp b/audio/aidl/default/noiseSuppression/Android.bp
index dad3d49..5729571 100644
--- a/audio/aidl/default/noiseSuppression/Android.bp
+++ b/audio/aidl/default/noiseSuppression/Android.bp
@@ -27,8 +27,6 @@
     name: "libnssw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "NoiseSuppressionSw.cpp",
@@ -36,6 +34,6 @@
     ],
     relative_install_path: "soundfx",
     visibility: [
-        "//hardware/interfaces/audio/aidl/default",
+        "//hardware/interfaces/audio/aidl/default:__subpackages__",
     ],
 }
diff --git a/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.cpp b/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.cpp
index 9b2cb7c..d304416 100644
--- a/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.cpp
+++ b/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.cpp
@@ -65,9 +65,9 @@
         .common = {.id = {.type = getEffectTypeUuidNoiseSuppression(),
                           .uuid = getEffectImplUuidNoiseSuppressionSw(),
                           .proxy = std::nullopt},
-                   .flags = {.type = Flags::Type::INSERT,
+                   .flags = {.type = Flags::Type::PRE_PROC,
                              .insert = Flags::Insert::FIRST,
-                             .volume = Flags::Volume::CTRL},
+                             .volume = Flags::Volume::NONE},
                    .name = NoiseSuppressionSw::kEffectName,
                    .implementor = "The Android Open Source Project"}};
 
@@ -155,10 +155,6 @@
     return mContext;
 }
 
-std::shared_ptr<EffectContext> NoiseSuppressionSw::getContext() {
-    return mContext;
-}
-
 RetCode NoiseSuppressionSw::releaseContext() {
     if (mContext) {
         mContext.reset();
diff --git a/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.h b/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.h
index fc1e028..acef8ee 100644
--- a/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.h
+++ b/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.h
@@ -55,20 +55,23 @@
     }
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
-    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
-    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
-                                            Parameter::Specific* specific) override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+            REQUIRES(mImplMutex) override;
 
-    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
-    std::shared_ptr<EffectContext> getContext() override;
-    RetCode releaseContext() override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+            REQUIRES(mImplMutex) override;
+    RetCode releaseContext() REQUIRES(mImplMutex) override;
 
     std::string getEffectName() override { return kEffectName; };
-    IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+    IEffect::Status effectProcessImpl(float* in, float* out, int samples)
+            REQUIRES(mImplMutex) override;
 
   private:
-    std::shared_ptr<NoiseSuppressionSwContext> mContext;
+    std::shared_ptr<NoiseSuppressionSwContext> mContext GUARDED_BY(mImplMutex);
     ndk::ScopedAStatus getParameterNoiseSuppression(const NoiseSuppression::Tag& tag,
-                                                    Parameter::Specific* specific);
+                                                    Parameter::Specific* specific)
+            REQUIRES(mImplMutex);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/presetReverb/Android.bp b/audio/aidl/default/presetReverb/Android.bp
index 18bdd17..2a2ae75 100644
--- a/audio/aidl/default/presetReverb/Android.bp
+++ b/audio/aidl/default/presetReverb/Android.bp
@@ -27,8 +27,6 @@
     name: "libpresetreverbsw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "PresetReverbSw.cpp",
@@ -36,6 +34,6 @@
     ],
     relative_install_path: "soundfx",
     visibility: [
-        "//hardware/interfaces/audio/aidl/default",
+        "//hardware/interfaces/audio/aidl/default:__subpackages__",
     ],
 }
diff --git a/audio/aidl/default/presetReverb/PresetReverbSw.cpp b/audio/aidl/default/presetReverb/PresetReverbSw.cpp
index 3f02eb7..2ac2010 100644
--- a/audio/aidl/default/presetReverb/PresetReverbSw.cpp
+++ b/audio/aidl/default/presetReverb/PresetReverbSw.cpp
@@ -161,10 +161,6 @@
     return mContext;
 }
 
-std::shared_ptr<EffectContext> PresetReverbSw::getContext() {
-    return mContext;
-}
-
 RetCode PresetReverbSw::releaseContext() {
     if (mContext) {
         mContext.reset();
diff --git a/audio/aidl/default/presetReverb/PresetReverbSw.h b/audio/aidl/default/presetReverb/PresetReverbSw.h
index 9ceee7c..61fc88c 100644
--- a/audio/aidl/default/presetReverb/PresetReverbSw.h
+++ b/audio/aidl/default/presetReverb/PresetReverbSw.h
@@ -56,21 +56,23 @@
     }
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
-    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
-    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
-                                            Parameter::Specific* specific) override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+            REQUIRES(mImplMutex) override;
 
-    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
-    std::shared_ptr<EffectContext> getContext() override;
-    RetCode releaseContext() override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+            REQUIRES(mImplMutex) override;
+    RetCode releaseContext() REQUIRES(mImplMutex) override;
 
-    IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+    IEffect::Status effectProcessImpl(float* in, float* out, int samples)
+            REQUIRES(mImplMutex) override;
     std::string getEffectName() override { return kEffectName; }
 
   private:
-    std::shared_ptr<PresetReverbSwContext> mContext;
+    std::shared_ptr<PresetReverbSwContext> mContext GUARDED_BY(mImplMutex);
 
     ndk::ScopedAStatus getParameterPresetReverb(const PresetReverb::Tag& tag,
-                                                Parameter::Specific* specific);
+                                                Parameter::Specific* specific) REQUIRES(mImplMutex);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/primary/StreamPrimary.cpp b/audio/aidl/default/primary/StreamPrimary.cpp
index e01be8a..7325a91 100644
--- a/audio/aidl/default/primary/StreamPrimary.cpp
+++ b/audio/aidl/default/primary/StreamPrimary.cpp
@@ -14,11 +14,11 @@
  * limitations under the License.
  */
 
-#include <limits>
-
 #define LOG_TAG "AHAL_StreamPrimary"
 #include <android-base/logging.h>
 #include <android-base/properties.h>
+#include <audio_utils/clock.h>
+#include <error/Result.h>
 #include <error/expected_utils.h>
 
 #include "PrimaryMixer.h"
@@ -37,7 +37,59 @@
 namespace aidl::android::hardware::audio::core {
 
 StreamPrimary::StreamPrimary(StreamContext* context, const Metadata& metadata)
-    : StreamAlsa(context, metadata, 3 /*readWriteRetries*/), mIsInput(isInput(metadata)) {}
+    : StreamAlsa(context, metadata, 3 /*readWriteRetries*/),
+      mIsAsynchronous(!!getContext().getAsyncCallback()) {
+    context->startStreamDataProcessor();
+}
+
+::android::status_t StreamPrimary::start() {
+    RETURN_STATUS_IF_ERROR(StreamAlsa::start());
+    mStartTimeNs = ::android::uptimeNanos();
+    mFramesSinceStart = 0;
+    mSkipNextTransfer = false;
+    return ::android::OK;
+}
+
+::android::status_t StreamPrimary::transfer(void* buffer, size_t frameCount,
+                                            size_t* actualFrameCount, int32_t* latencyMs) {
+    // This is a workaround for the emulator implementation which has a host-side buffer
+    // and is not being able to achieve real-time behavior similar to ADSPs (b/302587331).
+    if (!mSkipNextTransfer) {
+        RETURN_STATUS_IF_ERROR(
+                StreamAlsa::transfer(buffer, frameCount, actualFrameCount, latencyMs));
+    } else {
+        LOG(DEBUG) << __func__ << ": skipping transfer (" << frameCount << " frames)";
+        *actualFrameCount = frameCount;
+        if (mIsInput) memset(buffer, 0, frameCount * mFrameSizeBytes);
+        mSkipNextTransfer = false;
+    }
+    if (!mIsAsynchronous) {
+        const long bufferDurationUs =
+                (*actualFrameCount) * MICROS_PER_SECOND / mContext.getSampleRate();
+        const auto totalDurationUs =
+                (::android::uptimeNanos() - mStartTimeNs) / NANOS_PER_MICROSECOND;
+        mFramesSinceStart += *actualFrameCount;
+        const long totalOffsetUs =
+                mFramesSinceStart * MICROS_PER_SECOND / mContext.getSampleRate() - totalDurationUs;
+        LOG(VERBOSE) << __func__ << ": totalOffsetUs " << totalOffsetUs;
+        if (totalOffsetUs > 0) {
+            const long sleepTimeUs = std::min(totalOffsetUs, bufferDurationUs);
+            LOG(VERBOSE) << __func__ << ": sleeping for " << sleepTimeUs << " us";
+            usleep(sleepTimeUs);
+        } else {
+            mSkipNextTransfer = true;
+        }
+    } else {
+        LOG(VERBOSE) << __func__ << ": asynchronous transfer";
+    }
+    return ::android::OK;
+}
+
+::android::status_t StreamPrimary::refinePosition(StreamDescriptor::Position*) {
+    // Since not all data is actually sent to the HAL, use the position maintained by Stream class
+    // which accounts for all frames passed from / to the client.
+    return ::android::OK;
+}
 
 std::vector<alsa::DeviceProfile> StreamPrimary::getDeviceProfiles() {
     static const std::vector<alsa::DeviceProfile> kBuiltInSource{
@@ -64,7 +116,8 @@
             GetBoolProperty("ro.boot.audio.tinyalsa.simulate_input", false);
     return kSimulateInput || device.type.type == AudioDeviceType::IN_TELEPHONY_RX ||
            device.type.type == AudioDeviceType::IN_FM_TUNER ||
-           device.type.connection == AudioDeviceDescription::CONNECTION_BUS;
+           device.type.connection == AudioDeviceDescription::CONNECTION_BUS /*deprecated */ ||
+           (device.type.type == AudioDeviceType::IN_BUS && device.type.connection.empty());
 }
 
 StreamSwitcher::DeviceSwitchBehavior StreamInPrimary::switchCurrentStream(
@@ -99,6 +152,11 @@
     if (isStubStream()) {
         return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
     }
+    float gain;
+    RETURN_STATUS_IF_ERROR(primary::PrimaryMixer::getInstance().getMicGain(&gain));
+    _aidl_return->resize(0);
+    _aidl_return->resize(mChannelCount, gain);
+    RETURN_STATUS_IF_ERROR(setHwGainImpl(*_aidl_return));
     return getHwGainImpl(_aidl_return);
 }
 
@@ -130,7 +188,8 @@
     static const bool kSimulateOutput =
             GetBoolProperty("ro.boot.audio.tinyalsa.ignore_output", false);
     return kSimulateOutput || device.type.type == AudioDeviceType::OUT_TELEPHONY_TX ||
-           device.type.connection == AudioDeviceDescription::CONNECTION_BUS;
+           device.type.connection == AudioDeviceDescription::CONNECTION_BUS /*deprecated*/ ||
+           (device.type.type == AudioDeviceType::OUT_BUS && device.type.connection.empty());
 }
 
 StreamSwitcher::DeviceSwitchBehavior StreamOutPrimary::switchCurrentStream(
@@ -165,6 +224,9 @@
     if (isStubStream()) {
         return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
     }
+    RETURN_STATUS_IF_ERROR(primary::PrimaryMixer::getInstance().getVolumes(_aidl_return));
+    _aidl_return->resize(mChannelCount);
+    RETURN_STATUS_IF_ERROR(setHwVolumeImpl(*_aidl_return));
     return getHwVolumeImpl(_aidl_return);
 }
 
@@ -183,4 +245,15 @@
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus StreamOutPrimary::setConnectedDevices(
+        const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) {
+    if (!devices.empty()) {
+        auto streamDataProcessor = mContextInstance.getStreamDataProcessor().lock();
+        if (streamDataProcessor != nullptr) {
+            streamDataProcessor->setAudioDevice(devices[0]);
+        }
+    }
+    return StreamSwitcher::setConnectedDevices(devices);
+}
+
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/r_submix/ModuleRemoteSubmix.cpp b/audio/aidl/default/r_submix/ModuleRemoteSubmix.cpp
index adea877..b44f37b 100644
--- a/audio/aidl/default/r_submix/ModuleRemoteSubmix.cpp
+++ b/audio/aidl/default/r_submix/ModuleRemoteSubmix.cpp
@@ -16,23 +16,48 @@
 
 #define LOG_TAG "AHAL_ModuleRemoteSubmix"
 
+#include <stdio.h>
 #include <vector>
 
 #include <android-base/logging.h>
 #include <error/expected_utils.h>
 
+#include "SubmixRoute.h"
 #include "core-impl/ModuleRemoteSubmix.h"
 #include "core-impl/StreamRemoteSubmix.h"
 
 using aidl::android::hardware::audio::common::SinkMetadata;
 using aidl::android::hardware::audio::common::SourceMetadata;
+using aidl::android::media::audio::common::AudioDeviceAddress;
+using aidl::android::media::audio::common::AudioFormatType;
+using aidl::android::media::audio::common::AudioIoFlags;
 using aidl::android::media::audio::common::AudioOffloadInfo;
 using aidl::android::media::audio::common::AudioPort;
 using aidl::android::media::audio::common::AudioPortConfig;
+using aidl::android::media::audio::common::AudioPortExt;
+using aidl::android::media::audio::common::AudioProfile;
+using aidl::android::media::audio::common::Int;
 using aidl::android::media::audio::common::MicrophoneInfo;
 
 namespace aidl::android::hardware::audio::core {
 
+namespace {
+
+std::optional<r_submix::AudioConfig> getRemoteEndConfig(const AudioPort& audioPort) {
+    const auto& deviceAddress = audioPort.ext.get<AudioPortExt::device>().device.address;
+    const bool isInput = audioPort.flags.getTag() == AudioIoFlags::input;
+    if (auto submixRoute = r_submix::SubmixRoute::findRoute(deviceAddress);
+        submixRoute != nullptr) {
+        if ((isInput && submixRoute->isStreamOutOpen()) ||
+            (!isInput && submixRoute->isStreamInOpen())) {
+            return submixRoute->getPipeConfig();
+        }
+    }
+    return {};
+}
+
+}  // namespace
+
 ndk::ScopedAStatus ModuleRemoteSubmix::getMicMute(bool* _aidl_return __unused) {
     LOG(DEBUG) << __func__ << ": is not supported";
     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
@@ -43,6 +68,26 @@
     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
 }
 
+ndk::ScopedAStatus ModuleRemoteSubmix::setAudioPortConfig(const AudioPortConfig& in_requested,
+                                                          AudioPortConfig* out_suggested,
+                                                          bool* _aidl_return) {
+    auto fillConfig = [this](const AudioPort& port, AudioPortConfig* config) {
+        if (port.ext.getTag() == AudioPortExt::device) {
+            if (auto pipeConfig = getRemoteEndConfig(port); pipeConfig.has_value()) {
+                LOG(DEBUG) << "setAudioPortConfig: suggesting port config from the remote end.";
+                config->format = pipeConfig->format;
+                config->channelMask = pipeConfig->channelLayout;
+                config->sampleRate = Int{.value = pipeConfig->sampleRate};
+                config->flags = port.flags;
+                config->ext = port.ext;
+                return true;
+            }
+        }
+        return generateDefaultPortConfig(port, config);
+    };
+    return Module::setAudioPortConfigImpl(in_requested, fillConfig, out_suggested, _aidl_return);
+}
+
 ndk::ScopedAStatus ModuleRemoteSubmix::createInputStream(
         StreamContext&& context, const SinkMetadata& sinkMetadata,
         const std::vector<MicrophoneInfo>& microphones, std::shared_ptr<StreamIn>* result) {
@@ -57,27 +102,42 @@
                                                        offloadInfo);
 }
 
-ndk::ScopedAStatus ModuleRemoteSubmix::populateConnectedDevicePort(AudioPort* audioPort) {
-    // Find the corresponding mix port and copy its profiles.
-    std::vector<AudioRoute> routes;
+ndk::ScopedAStatus ModuleRemoteSubmix::populateConnectedDevicePort(AudioPort* audioPort, int32_t) {
+    if (audioPort->ext.getTag() != AudioPortExt::device) {
+        LOG(ERROR) << __func__ << ": not a device port: " << audioPort->toString();
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+    // If there is already a pipe with a stream for the port address, provide its configuration as
+    // the only option. Otherwise, find the corresponding mix port and copy its profiles.
+    if (auto pipeConfig = getRemoteEndConfig(*audioPort); pipeConfig.has_value()) {
+        audioPort->profiles.clear();
+        audioPort->profiles.push_back(AudioProfile{
+                .format = pipeConfig->format,
+                .channelMasks = std::vector<AudioChannelLayout>({pipeConfig->channelLayout}),
+                .sampleRates = std::vector<int>({pipeConfig->sampleRate})});
+        LOG(DEBUG) << __func__ << ": populated from remote end as: " << audioPort->toString();
+        return ndk::ScopedAStatus::ok();
+    }
+
     // At this moment, the port has the same ID as the template port, see connectExternalDevice.
-    RETURN_STATUS_IF_ERROR(getAudioRoutesForAudioPort(audioPort->id, &routes));
+    std::vector<AudioRoute*> routes = getAudioRoutesForAudioPortImpl(audioPort->id);
     if (routes.empty()) {
         LOG(ERROR) << __func__ << ": no routes found for the port " << audioPort->toString();
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
     const auto& route = *routes.begin();
     AudioPort mixPort;
-    if (route.sinkPortId == audioPort->id) {
-        if (route.sourcePortIds.empty()) {
-            LOG(ERROR) << __func__ << ": invalid route " << route.toString();
+    if (route->sinkPortId == audioPort->id) {
+        if (route->sourcePortIds.empty()) {
+            LOG(ERROR) << __func__ << ": invalid route " << route->toString();
             return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
         }
-        RETURN_STATUS_IF_ERROR(getAudioPort(*route.sourcePortIds.begin(), &mixPort));
+        RETURN_STATUS_IF_ERROR(getAudioPort(*route->sourcePortIds.begin(), &mixPort));
     } else {
-        RETURN_STATUS_IF_ERROR(getAudioPort(route.sinkPortId, &mixPort));
+        RETURN_STATUS_IF_ERROR(getAudioPort(route->sinkPortId, &mixPort));
     }
     audioPort->profiles = mixPort.profiles;
+    LOG(DEBUG) << __func__ << ": populated from the mix port as: " << audioPort->toString();
     return ndk::ScopedAStatus::ok();
 }
 
@@ -107,4 +167,17 @@
     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
 }
 
+int32_t ModuleRemoteSubmix::getNominalLatencyMs(const AudioPortConfig&) {
+    // See the note on kDefaultPipePeriodCount.
+    static constexpr int32_t kMaxLatencyMs =
+            (r_submix::kDefaultPipeSizeInFrames * 1000) / r_submix::kDefaultSampleRateHz;
+    static constexpr int32_t kMinLatencyMs = kMaxLatencyMs / r_submix::kDefaultPipePeriodCount;
+    return kMinLatencyMs;
+}
+
+binder_status_t ModuleRemoteSubmix::dump(int fd, const char** /*args*/, uint32_t /*numArgs*/) {
+    dprintf(fd, "\nSubmixRoutes:\n%s\n", r_submix::SubmixRoute::dumpRoutes().c_str());
+    return STATUS_OK;
+}
+
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
index 9c9c08b..fa4135d 100644
--- a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
+++ b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
@@ -16,8 +16,9 @@
 
 #define LOG_TAG "AHAL_StreamRemoteSubmix"
 #include <android-base/logging.h>
-
-#include <cmath>
+#include <audio_utils/clock.h>
+#include <error/Result.h>
+#include <error/expected_utils.h>
 
 #include "core-impl/StreamRemoteSubmix.h"
 
@@ -42,50 +43,27 @@
     mStreamConfig.sampleRate = context->getSampleRate();
 }
 
-std::mutex StreamRemoteSubmix::sSubmixRoutesLock;
-std::map<AudioDeviceAddress, std::shared_ptr<SubmixRoute>> StreamRemoteSubmix::sSubmixRoutes;
-
 ::android::status_t StreamRemoteSubmix::init() {
-    {
-        std::lock_guard guard(sSubmixRoutesLock);
-        auto routeItr = sSubmixRoutes.find(mDeviceAddress);
-        if (routeItr != sSubmixRoutes.end()) {
-            mCurrentRoute = routeItr->second;
-        }
-    }
-    // If route is not available for this port, add it.
+    mCurrentRoute = SubmixRoute::findOrCreateRoute(mDeviceAddress, mStreamConfig);
     if (mCurrentRoute == nullptr) {
-        // Initialize the pipe.
-        mCurrentRoute = std::make_shared<SubmixRoute>();
-        if (::android::OK != mCurrentRoute->createPipe(mStreamConfig)) {
-            LOG(ERROR) << __func__ << ": create pipe failed";
+        return ::android::NO_INIT;
+    }
+    if (!mCurrentRoute->isStreamConfigValid(mIsInput, mStreamConfig)) {
+        LOG(ERROR) << __func__ << ": invalid stream config";
+        return ::android::NO_INIT;
+    }
+    sp<MonoPipe> sink = mCurrentRoute->getSink();
+    if (sink == nullptr) {
+        LOG(ERROR) << __func__ << ": nullptr sink when opening stream";
+        return ::android::NO_INIT;
+    }
+    if ((!mIsInput || mCurrentRoute->isStreamInOpen()) && sink->isShutdown()) {
+        LOG(DEBUG) << __func__ << ": Shut down sink when opening stream";
+        if (::android::OK != mCurrentRoute->resetPipe()) {
+            LOG(ERROR) << __func__ << ": reset pipe failed";
             return ::android::NO_INIT;
         }
-        {
-            std::lock_guard guard(sSubmixRoutesLock);
-            sSubmixRoutes.emplace(mDeviceAddress, mCurrentRoute);
-        }
-    } else {
-        if (!mCurrentRoute->isStreamConfigValid(mIsInput, mStreamConfig)) {
-            LOG(ERROR) << __func__ << ": invalid stream config";
-            return ::android::NO_INIT;
-        }
-        sp<MonoPipe> sink = mCurrentRoute->getSink();
-        if (sink == nullptr) {
-            LOG(ERROR) << __func__ << ": nullptr sink when opening stream";
-            return ::android::NO_INIT;
-        }
-        // If the sink has been shutdown or pipe recreation is forced, delete the pipe and
-        // recreate it.
-        if (sink->isShutdown()) {
-            LOG(DEBUG) << __func__ << ": Non-nullptr shut down sink when opening stream";
-            if (::android::OK != mCurrentRoute->resetPipe()) {
-                LOG(ERROR) << __func__ << ": reset pipe failed";
-                return ::android::NO_INIT;
-            }
-        }
     }
-
     mCurrentRoute->openStream(mIsInput);
     return ::android::OK;
 }
@@ -112,19 +90,14 @@
 
 ::android::status_t StreamRemoteSubmix::start() {
     mCurrentRoute->exitStandby(mIsInput);
+    mStartTimeNs = ::android::uptimeNanos();
+    mFramesSinceStart = 0;
     return ::android::OK;
 }
 
 ndk::ScopedAStatus StreamRemoteSubmix::prepareToClose() {
     if (!mIsInput) {
-        std::shared_ptr<SubmixRoute> route = nullptr;
-        {
-            std::lock_guard guard(sSubmixRoutesLock);
-            auto routeItr = sSubmixRoutes.find(mDeviceAddress);
-            if (routeItr != sSubmixRoutes.end()) {
-                route = routeItr->second;
-            }
-        }
+        std::shared_ptr<SubmixRoute> route = SubmixRoute::findRoute(mDeviceAddress);
         if (route != nullptr) {
             sp<MonoPipe> sink = route->getSink();
             if (sink == nullptr) {
@@ -133,6 +106,8 @@
             LOG(DEBUG) << __func__ << ": shutting down MonoPipe sink";
 
             sink->shutdown(true);
+            // The client already considers this stream as closed, release the output end.
+            route->closeStream(mIsInput);
         } else {
             LOG(DEBUG) << __func__ << ": stream already closed.";
             ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
@@ -149,39 +124,31 @@
     if (!mCurrentRoute->hasAtleastOneStreamOpen()) {
         mCurrentRoute->releasePipe();
         LOG(DEBUG) << __func__ << ": pipe destroyed";
-
-        std::lock_guard guard(sSubmixRoutesLock);
-        sSubmixRoutes.erase(mDeviceAddress);
+        SubmixRoute::removeRoute(mDeviceAddress);
     }
     mCurrentRoute.reset();
 }
 
 ::android::status_t StreamRemoteSubmix::transfer(void* buffer, size_t frameCount,
                                                  size_t* actualFrameCount, int32_t* latencyMs) {
-    *latencyMs = (getStreamPipeSizeInFrames() * MILLIS_PER_SECOND) / mStreamConfig.sampleRate;
+    *latencyMs = getDelayInUsForFrameCount(getStreamPipeSizeInFrames()) / 1000;
     LOG(VERBOSE) << __func__ << ": Latency " << *latencyMs << "ms";
-
-    sp<MonoPipe> sink = mCurrentRoute->getSink();
-    if (sink != nullptr) {
-        if (sink->isShutdown()) {
-            sink.clear();
-            LOG(VERBOSE) << __func__ << ": pipe shutdown, ignoring the transfer.";
-            // the pipe has already been shutdown, this buffer will be lost but we must simulate
-            // timing so we don't drain the output faster than realtime
-            const size_t delayUs = static_cast<size_t>(
-                    std::roundf(frameCount * MICROS_PER_SECOND / mStreamConfig.sampleRate));
-            usleep(delayUs);
-
-            *actualFrameCount = frameCount;
-            return ::android::OK;
-        }
-    } else {
-        LOG(ERROR) << __func__ << ": transfer without a pipe!";
-        return ::android::UNEXPECTED_NULL;
-    }
     mCurrentRoute->exitStandby(mIsInput);
-    return (mIsInput ? inRead(buffer, frameCount, actualFrameCount)
-                     : outWrite(buffer, frameCount, actualFrameCount));
+    RETURN_STATUS_IF_ERROR(mIsInput ? inRead(buffer, frameCount, actualFrameCount)
+                                    : outWrite(buffer, frameCount, actualFrameCount));
+    const long bufferDurationUs =
+            (*actualFrameCount) * MICROS_PER_SECOND / mContext.getSampleRate();
+    const auto totalDurationUs = (::android::uptimeNanos() - mStartTimeNs) / NANOS_PER_MICROSECOND;
+    mFramesSinceStart += *actualFrameCount;
+    const long totalOffsetUs =
+            mFramesSinceStart * MICROS_PER_SECOND / mContext.getSampleRate() - totalDurationUs;
+    LOG(VERBOSE) << __func__ << ": totalOffsetUs " << totalOffsetUs;
+    if (totalOffsetUs > 0) {
+        const long sleepTimeUs = std::min(totalOffsetUs, bufferDurationUs);
+        LOG(VERBOSE) << __func__ << ": sleeping for " << sleepTimeUs << " us";
+        usleep(sleepTimeUs);
+    }
+    return ::android::OK;
 }
 
 ::android::status_t StreamRemoteSubmix::refinePosition(StreamDescriptor::Position* position) {
@@ -202,9 +169,13 @@
     return ::android::OK;
 }
 
+long StreamRemoteSubmix::getDelayInUsForFrameCount(size_t frameCount) {
+    return frameCount * MICROS_PER_SECOND / mStreamConfig.sampleRate;
+}
+
 // Calculate the maximum size of the pipe buffer in frames for the specified stream.
 size_t StreamRemoteSubmix::getStreamPipeSizeInFrames() {
-    auto pipeConfig = mCurrentRoute->mPipeConfig;
+    auto pipeConfig = mCurrentRoute->getPipeConfig();
     const size_t maxFrameSize = std::max(mStreamConfig.frameSize, pipeConfig.frameSize);
     return (pipeConfig.frameCount * pipeConfig.frameSize) / maxFrameSize;
 }
@@ -215,12 +186,7 @@
     if (sink != nullptr) {
         if (sink->isShutdown()) {
             sink.clear();
-            LOG(VERBOSE) << __func__ << ": pipe shutdown, ignoring the write.";
-            // the pipe has already been shutdown, this buffer will be lost but we must
-            // simulate timing so we don't drain the output faster than realtime
-            const size_t delayUs = static_cast<size_t>(
-                    std::roundf(frameCount * MICROS_PER_SECOND / mStreamConfig.sampleRate));
-            usleep(delayUs);
+            LOG(DEBUG) << __func__ << ": pipe shutdown, ignoring the write";
             *actualFrameCount = frameCount;
             return ::android::OK;
         }
@@ -229,17 +195,21 @@
         return ::android::UNKNOWN_ERROR;
     }
 
-    const size_t availableToWrite = sink->availableToWrite();
+    LOG(VERBOSE) << __func__ << ": " << mDeviceAddress.toString() << ", " << frameCount
+                 << " frames";
+
+    const bool shouldBlockWrite = mCurrentRoute->shouldBlockWrite();
+    size_t availableToWrite = sink->availableToWrite();
     // NOTE: sink has been checked above and sink and source life cycles are synchronized
     sp<MonoPipeReader> source = mCurrentRoute->getSource();
     // If the write to the sink should be blocked, flush enough frames from the pipe to make space
     // to write the most recent data.
-    if (!mCurrentRoute->shouldBlockWrite() && availableToWrite < frameCount) {
+    if (!shouldBlockWrite && availableToWrite < frameCount) {
         static uint8_t flushBuffer[64];
         const size_t flushBufferSizeFrames = sizeof(flushBuffer) / mStreamConfig.frameSize;
         size_t framesToFlushFromSource = frameCount - availableToWrite;
-        LOG(VERBOSE) << __func__ << ": flushing " << framesToFlushFromSource
-                     << " frames from the pipe to avoid blocking";
+        LOG(DEBUG) << __func__ << ": flushing " << framesToFlushFromSource
+                   << " frames from the pipe to avoid blocking";
         while (framesToFlushFromSource) {
             const size_t flushSize = std::min(framesToFlushFromSource, flushBufferSizeFrames);
             framesToFlushFromSource -= flushSize;
@@ -247,7 +217,14 @@
             source->read(flushBuffer, flushSize);
         }
     }
+    availableToWrite = sink->availableToWrite();
 
+    if (!shouldBlockWrite && frameCount > availableToWrite) {
+        LOG(WARNING) << __func__ << ": writing " << availableToWrite << " vs. requested "
+                     << frameCount;
+        // Truncate the request to avoid blocking.
+        frameCount = availableToWrite;
+    }
     ssize_t writtenFrames = sink->write(buffer, frameCount);
     if (writtenFrames < 0) {
         if (writtenFrames == (ssize_t)::android::NEGOTIATE) {
@@ -261,97 +238,71 @@
             writtenFrames = sink->write(buffer, frameCount);
         }
     }
-    sink.clear();
 
     if (writtenFrames < 0) {
         LOG(ERROR) << __func__ << ": failed writing to pipe with " << writtenFrames;
         *actualFrameCount = 0;
         return ::android::UNKNOWN_ERROR;
     }
-    LOG(VERBOSE) << __func__ << ": wrote " << writtenFrames << "frames";
+    if (writtenFrames > 0 && frameCount > (size_t)writtenFrames) {
+        LOG(WARNING) << __func__ << ": wrote " << writtenFrames << " vs. requested " << frameCount;
+    }
     *actualFrameCount = writtenFrames;
     return ::android::OK;
 }
 
 ::android::status_t StreamRemoteSubmix::inRead(void* buffer, size_t frameCount,
                                                size_t* actualFrameCount) {
+    // in any case, it is emulated that data for the entire buffer was available
+    memset(buffer, 0, mStreamConfig.frameSize * frameCount);
+    *actualFrameCount = frameCount;
+
     // about to read from audio source
     sp<MonoPipeReader> source = mCurrentRoute->getSource();
     if (source == nullptr) {
-        int readErrorCount = mCurrentRoute->notifyReadError();
-        if (readErrorCount < kMaxReadErrorLogs) {
+        if (++mReadErrorCount < kMaxReadErrorLogs) {
             LOG(ERROR) << __func__
                        << ": no audio pipe yet we're trying to read! (not all errors will be "
                           "logged)";
-        } else {
-            LOG(ERROR) << __func__ << ": Read errors " << readErrorCount;
         }
-        const size_t delayUs = static_cast<size_t>(
-                std::roundf(frameCount * MICROS_PER_SECOND / mStreamConfig.sampleRate));
-        usleep(delayUs);
-        memset(buffer, 0, mStreamConfig.frameSize * frameCount);
-        *actualFrameCount = frameCount;
         return ::android::OK;
     }
+    mReadErrorCount = 0;
 
+    LOG(VERBOSE) << __func__ << ": " << mDeviceAddress.toString() << ", " << frameCount
+                 << " frames";
     // read the data from the pipe
-    int attempts = 0;
-    const size_t delayUs = static_cast<size_t>(std::roundf(kReadAttemptSleepUs));
     char* buff = (char*)buffer;
-    size_t remainingFrames = frameCount;
-    int availableToRead = source->availableToRead();
-
-    while ((remainingFrames > 0) && (availableToRead > 0) && (attempts < kMaxReadFailureAttempts)) {
-        LOG(VERBOSE) << __func__ << ": frames available to read " << availableToRead;
-
+    size_t actuallyRead = 0;
+    long remainingFrames = frameCount;
+    const int64_t deadlineTimeNs = ::android::uptimeNanos() +
+                                   getDelayInUsForFrameCount(frameCount) * NANOS_PER_MICROSECOND;
+    while (remainingFrames > 0) {
         ssize_t framesRead = source->read(buff, remainingFrames);
-
         LOG(VERBOSE) << __func__ << ": frames read " << framesRead;
-
         if (framesRead > 0) {
             remainingFrames -= framesRead;
             buff += framesRead * mStreamConfig.frameSize;
-            availableToRead -= framesRead;
-            LOG(VERBOSE) << __func__ << ": (attempts = " << attempts << ") got " << framesRead
-                         << " frames, remaining=" << remainingFrames;
-        } else {
-            attempts++;
-            LOG(WARNING) << __func__ << ": read returned " << framesRead
-                         << " , read failure attempts = " << attempts;
-            usleep(delayUs);
+            LOG(VERBOSE) << __func__ << ": got " << framesRead
+                         << " frames, remaining =" << remainingFrames;
+            actuallyRead += framesRead;
+        }
+        if (::android::uptimeNanos() >= deadlineTimeNs) break;
+        if (framesRead <= 0) {
+            LOG(VERBOSE) << __func__ << ": read returned " << framesRead
+                         << ", read failure, sleeping for " << kReadAttemptSleepUs << " us";
+            usleep(kReadAttemptSleepUs);
         }
     }
-    // done using the source
-    source.clear();
-
-    if (remainingFrames > 0) {
-        const size_t remainingBytes = remainingFrames * mStreamConfig.frameSize;
-        LOG(VERBOSE) << __func__ << ": clearing remaining_frames = " << remainingFrames;
-        memset(((char*)buffer) + (mStreamConfig.frameSize * frameCount) - remainingBytes, 0,
-               remainingBytes);
+    if (actuallyRead < frameCount) {
+        if (++mReadFailureCount < kMaxReadFailureAttempts) {
+            LOG(WARNING) << __func__ << ": read " << actuallyRead << " vs. requested " << frameCount
+                         << " (not all errors will be logged)";
+        }
+    } else {
+        mReadFailureCount = 0;
     }
-
-    long readCounterFrames = mCurrentRoute->updateReadCounterFrames(frameCount);
-    *actualFrameCount = frameCount;
-
-    // compute how much we need to sleep after reading the data by comparing the wall clock with
-    //   the projected time at which we should return.
-    // wall clock after reading from the pipe
-    auto recordDurationUs = std::chrono::steady_clock::now() - mCurrentRoute->getRecordStartTime();
-
-    // readCounterFrames contains the number of frames that have been read since the beginning of
-    // recording (including this call): it's converted to usec and compared to how long we've been
-    // recording for, which gives us how long we must wait to sync the projected recording time, and
-    // the observed recording time.
-    const int projectedVsObservedOffsetUs =
-            std::roundf((readCounterFrames * MICROS_PER_SECOND / mStreamConfig.sampleRate) -
-                        recordDurationUs.count());
-
-    LOG(VERBOSE) << __func__ << ": record duration " << recordDurationUs.count()
-                 << " microseconds, will wait: " << projectedVsObservedOffsetUs << " microseconds";
-    if (projectedVsObservedOffsetUs > 0) {
-        usleep(projectedVsObservedOffsetUs);
-    }
+    mCurrentRoute->updateReadCounterFrames(*actualFrameCount);
     return ::android::OK;
 }
 
diff --git a/audio/aidl/default/r_submix/SubmixRoute.cpp b/audio/aidl/default/r_submix/SubmixRoute.cpp
index ddac64d..325a012 100644
--- a/audio/aidl/default/r_submix/SubmixRoute.cpp
+++ b/audio/aidl/default/r_submix/SubmixRoute.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include <mutex>
+
 #define LOG_TAG "AHAL_SubmixRoute"
 #include <android-base/logging.h>
 #include <media/AidlConversionCppNdk.h>
@@ -23,9 +25,65 @@
 #include "SubmixRoute.h"
 
 using aidl::android::hardware::audio::common::getChannelCount;
+using aidl::android::media::audio::common::AudioDeviceAddress;
 
 namespace aidl::android::hardware::audio::core::r_submix {
 
+// static
+SubmixRoute::RoutesMonitor SubmixRoute::getRoutes(bool tryLock) {
+    static std::mutex submixRoutesLock;
+    static RoutesMap submixRoutes;
+    return !tryLock ? RoutesMonitor(submixRoutesLock, submixRoutes)
+                    : RoutesMonitor(submixRoutesLock, submixRoutes, tryLock);
+}
+
+// static
+std::shared_ptr<SubmixRoute> SubmixRoute::findOrCreateRoute(const AudioDeviceAddress& deviceAddress,
+                                                            const AudioConfig& pipeConfig) {
+    auto routes = getRoutes();
+    auto routeItr = routes->find(deviceAddress);
+    if (routeItr != routes->end()) {
+        return routeItr->second;
+    }
+    auto route = std::make_shared<SubmixRoute>();
+    if (::android::OK != route->createPipe(pipeConfig)) {
+        LOG(ERROR) << __func__ << ": create pipe failed";
+        return nullptr;
+    }
+    routes->emplace(deviceAddress, route);
+    return route;
+}
+
+// static
+std::shared_ptr<SubmixRoute> SubmixRoute::findRoute(const AudioDeviceAddress& deviceAddress) {
+    auto routes = getRoutes();
+    auto routeItr = routes->find(deviceAddress);
+    if (routeItr != routes->end()) {
+        return routeItr->second;
+    }
+    return nullptr;
+}
+
+// static
+void SubmixRoute::removeRoute(const AudioDeviceAddress& deviceAddress) {
+    getRoutes()->erase(deviceAddress);
+}
+
+// static
+std::string SubmixRoute::dumpRoutes() {
+    auto routes = getRoutes(true /*tryLock*/);
+    std::string result;
+    if (routes->empty()) result.append(" <Empty>");
+    for (const auto& r : *(routes.operator->())) {
+        result.append(" - ")
+                .append(r.first.toString())
+                .append(": ")
+                .append(r.second->dump())
+                .append("\n");
+    }
+    return result;
+}
+
 // Verify a submix input or output stream can be opened.
 bool SubmixRoute::isStreamConfigValid(bool isInput, const AudioConfig& streamConfig) {
     // If the stream is already open, don't open it again.
@@ -44,6 +102,7 @@
 // Compare this stream config with existing pipe config, returning false if they do *not*
 // match, true otherwise.
 bool SubmixRoute::isStreamConfigCompatible(const AudioConfig& streamConfig) {
+    std::lock_guard guard(mLock);
     if (streamConfig.channelLayout != mPipeConfig.channelLayout) {
         LOG(ERROR) << __func__ << ": channel count mismatch, stream channels = "
                    << streamConfig.channelLayout.toString()
@@ -81,11 +140,6 @@
     return (mStreamInOpen || (mStreamInStandby && (mReadCounterFrames != 0)));
 }
 
-int SubmixRoute::notifyReadError() {
-    std::lock_guard guard(mLock);
-    return ++mReadErrorCount;
-}
-
 long SubmixRoute::updateReadCounterFrames(size_t frameCount) {
     std::lock_guard guard(mLock);
     mReadCounterFrames += frameCount;
@@ -103,7 +157,9 @@
         }
         mStreamInStandby = true;
         mReadCounterFrames = 0;
-        mReadErrorCount = 0;
+        if (mSink != nullptr) {
+            mSink->shutdown(false);
+        }
     } else {
         mStreamOutOpen = true;
     }
@@ -112,8 +168,7 @@
 void SubmixRoute::closeStream(bool isInput) {
     std::lock_guard guard(mLock);
     if (isInput) {
-        mInputRefCount--;
-        if (mInputRefCount == 0) {
+        if (--mInputRefCount == 0) {
             mStreamInOpen = false;
             if (mSink != nullptr) {
                 mSink->shutdown(true);
@@ -166,17 +221,14 @@
         LOG(FATAL) << __func__ << ": Negotiation for the source failed, index = " << index;
         return ::android::BAD_INDEX;
     }
-    LOG(VERBOSE) << __func__ << ": created pipe";
-
-    mPipeConfig = streamConfig;
-    mPipeConfig.frameCount = sink->maxFrames();
-
-    LOG(VERBOSE) << __func__ << ": Pipe frame size : " << mPipeConfig.frameSize
-                 << ", pipe frames : " << mPipeConfig.frameCount;
+    LOG(VERBOSE) << __func__ << ": Pipe frame size : " << streamConfig.frameSize
+                 << ", pipe frames : " << sink->maxFrames();
 
     // Save references to the source and sink.
     {
         std::lock_guard guard(mLock);
+        mPipeConfig = streamConfig;
+        mPipeConfig.frameCount = sink->maxFrames();
         mSink = std::move(sink);
         mSource = std::move(source);
     }
@@ -185,15 +237,15 @@
 }
 
 // Release references to the sink and source.
-void SubmixRoute::releasePipe() {
+AudioConfig SubmixRoute::releasePipe() {
     std::lock_guard guard(mLock);
     mSink.clear();
     mSource.clear();
+    return mPipeConfig;
 }
 
 ::android::status_t SubmixRoute::resetPipe() {
-    releasePipe();
-    return createPipe(mPipeConfig);
+    return createPipe(releasePipe());
 }
 
 void SubmixRoute::standby(bool isInput) {
@@ -214,9 +266,6 @@
         if (mStreamInStandby || mStreamOutStandbyTransition) {
             mStreamInStandby = false;
             mStreamOutStandbyTransition = false;
-            // keep track of when we exit input standby (== first read == start "real recording")
-            // or when we start recording silence, and reset projected time
-            mRecordStartTime = std::chrono::steady_clock::now();
             mReadCounterFrames = 0;
         }
     } else {
@@ -227,4 +276,23 @@
     }
 }
 
+std::string SubmixRoute::dump() NO_THREAD_SAFETY_ANALYSIS {
+    const bool isLocked = mLock.try_lock();
+    std::string result = std::string(isLocked ? "" : "! ")
+                                 .append("Input ")
+                                 .append(mStreamInOpen ? "open" : "closed")
+                                 .append(mStreamInStandby ? ", standby" : ", active")
+                                 .append(", refcount: ")
+                                 .append(std::to_string(mInputRefCount))
+                                 .append(", framesRead: ")
+                                 .append(mSource ? std::to_string(mSource->framesRead()) : "<null>")
+                                 .append("; Output ")
+                                 .append(mStreamOutOpen ? "open" : "closed")
+                                 .append(mStreamOutStandby ? ", standby" : ", active")
+                                 .append(", framesWritten: ")
+                                 .append(mSink ? std::to_string(mSink->framesWritten()) : "<null>");
+    if (isLocked) mLock.unlock();
+    return result;
+}
+
 }  // namespace aidl::android::hardware::audio::core::r_submix
diff --git a/audio/aidl/default/r_submix/SubmixRoute.h b/audio/aidl/default/r_submix/SubmixRoute.h
index 1a98df2..5425f12 100644
--- a/audio/aidl/default/r_submix/SubmixRoute.h
+++ b/audio/aidl/default/r_submix/SubmixRoute.h
@@ -14,16 +14,20 @@
  * limitations under the License.
  */
 
-#include <mutex>
+#pragma once
 
+#include <mutex>
+#include <string>
+
+#include <android-base/thread_annotations.h>
 #include <audio_utils/clock.h>
 
 #include <media/nbaio/MonoPipe.h>
 #include <media/nbaio/MonoPipeReader.h>
 
 #include <aidl/android/media/audio/common/AudioChannelLayout.h>
-
-#include "core-impl/Stream.h"
+#include <aidl/android/media/audio/common/AudioDeviceAddress.h>
+#include <aidl/android/media/audio/common/AudioFormatDescription.h>
 
 using aidl::android::media::audio::common::AudioChannelLayout;
 using aidl::android::media::audio::common::AudioFormatDescription;
@@ -36,9 +40,13 @@
 namespace aidl::android::hardware::audio::core::r_submix {
 
 static constexpr int kDefaultSampleRateHz = 48000;
-// Size at default sample rate
-// NOTE: This value will be rounded up to the nearest power of 2 by MonoPipe().
-static constexpr int kDefaultPipeSizeInFrames = (1024 * 4);
+// Value used to divide the MonoPipe buffer into segments that are written to the source and
+// read from the sink. The maximum latency of the device is the size of the MonoPipe's buffer
+// the minimum latency is the MonoPipe buffer size divided by this value.
+static constexpr int kDefaultPipePeriodCount = 4;
+// Size at the default sample rate
+// NOTE: This value will be rounded up to the nearest power of 2 by MonoPipe.
+static constexpr int kDefaultPipeSizeInFrames = 1024 * kDefaultPipePeriodCount;
 
 // Configuration of the audio stream.
 struct AudioConfig {
@@ -54,7 +62,14 @@
 
 class SubmixRoute {
   public:
-    AudioConfig mPipeConfig;
+    static std::shared_ptr<SubmixRoute> findOrCreateRoute(
+            const ::aidl::android::media::audio::common::AudioDeviceAddress& deviceAddress,
+            const AudioConfig& pipeConfig);
+    static std::shared_ptr<SubmixRoute> findRoute(
+            const ::aidl::android::media::audio::common::AudioDeviceAddress& deviceAddress);
+    static void removeRoute(
+            const ::aidl::android::media::audio::common::AudioDeviceAddress& deviceAddress);
+    static std::string dumpRoutes();
 
     bool isStreamInOpen() {
         std::lock_guard guard(mLock);
@@ -76,14 +91,6 @@
         std::lock_guard guard(mLock);
         return mReadCounterFrames;
     }
-    int getReadErrorCount() {
-        std::lock_guard guard(mLock);
-        return mReadErrorCount;
-    }
-    std::chrono::time_point<std::chrono::steady_clock> getRecordStartTime() {
-        std::lock_guard guard(mLock);
-        return mRecordStartTime;
-    }
     sp<MonoPipe> getSink() {
         std::lock_guard guard(mLock);
         return mSink;
@@ -92,6 +99,10 @@
         std::lock_guard guard(mLock);
         return mSource;
     }
+    AudioConfig getPipeConfig() {
+        std::lock_guard guard(mLock);
+        return mPipeConfig;
+    }
 
     bool isStreamConfigValid(bool isInput, const AudioConfig& streamConfig);
     void closeStream(bool isInput);
@@ -100,17 +111,35 @@
     bool hasAtleastOneStreamOpen();
     int notifyReadError();
     void openStream(bool isInput);
-    void releasePipe();
+    AudioConfig releasePipe();
     ::android::status_t resetPipe();
     bool shouldBlockWrite();
     void standby(bool isInput);
     long updateReadCounterFrames(size_t frameCount);
 
+    std::string dump();
+
   private:
+    using RoutesMap = std::map<::aidl::android::media::audio::common::AudioDeviceAddress,
+                               std::shared_ptr<r_submix::SubmixRoute>>;
+    class RoutesMonitor {
+      public:
+        RoutesMonitor(std::mutex& mutex, RoutesMap& routes) : mLock(mutex), mRoutes(routes) {}
+        RoutesMonitor(std::mutex& mutex, RoutesMap& routes, bool /*tryLock*/)
+            : mLock(mutex, std::try_to_lock), mRoutes(routes) {}
+        RoutesMap* operator->() { return &mRoutes; }
+
+      private:
+        std::unique_lock<std::mutex> mLock;
+        RoutesMap& mRoutes;
+    };
+
+    static RoutesMonitor getRoutes(bool tryLock = false);
+
     bool isStreamConfigCompatible(const AudioConfig& streamConfig);
 
     std::mutex mLock;
-
+    AudioConfig mPipeConfig GUARDED_BY(mLock);
     bool mStreamInOpen GUARDED_BY(mLock) = false;
     int mInputRefCount GUARDED_BY(mLock) = 0;
     bool mStreamInStandby GUARDED_BY(mLock) = true;
@@ -119,9 +148,6 @@
     bool mStreamOutStandby GUARDED_BY(mLock) = true;
     // how many frames have been requested to be read since standby
     long mReadCounterFrames GUARDED_BY(mLock) = 0;
-    int mReadErrorCount GUARDED_BY(mLock) = 0;
-    // wall clock when recording starts
-    std::chrono::time_point<std::chrono::steady_clock> mRecordStartTime GUARDED_BY(mLock);
 
     // Pipe variables: they handle the ring buffer that "pipes" audio:
     //  - from the submix virtual audio output == what needs to be played
diff --git a/audio/aidl/default/spatializer/Android.bp b/audio/aidl/default/spatializer/Android.bp
new file mode 100644
index 0000000..05ed365
--- /dev/null
+++ b/audio/aidl/default/spatializer/Android.bp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_shared {
+    name: "libspatializersw",
+    defaults: [
+        "aidlaudioeffectservice_defaults",
+    ],
+    srcs: [
+        "SpatializerSw.cpp",
+        ":effectCommonFile",
+    ],
+    relative_install_path: "soundfx",
+    visibility: [
+        "//hardware/interfaces/audio/aidl/default",
+    ],
+}
diff --git a/audio/aidl/default/spatializer/SpatializerSw.cpp b/audio/aidl/default/spatializer/SpatializerSw.cpp
new file mode 100644
index 0000000..6d3c4bd
--- /dev/null
+++ b/audio/aidl/default/spatializer/SpatializerSw.cpp
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_SpatializerSw"
+
+#include "SpatializerSw.h"
+
+#include <android-base/logging.h>
+#include <system/audio_effects/effect_uuid.h>
+
+#include <optional>
+
+using aidl::android::hardware::audio::common::getChannelCount;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::getEffectImplUuidSpatializerSw;
+using aidl::android::hardware::audio::effect::getEffectTypeUuidSpatializer;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::SpatializerSw;
+using aidl::android::hardware::audio::effect::State;
+using aidl::android::media::audio::common::AudioChannelLayout;
+using aidl::android::media::audio::common::AudioUuid;
+using aidl::android::media::audio::common::HeadTracking;
+using aidl::android::media::audio::common::Spatialization;
+
+extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
+                                           std::shared_ptr<IEffect>* instanceSpp) {
+    if (!in_impl_uuid || *in_impl_uuid != getEffectImplUuidSpatializerSw()) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    if (!instanceSpp) {
+        LOG(ERROR) << __func__ << " invalid input parameter!";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+
+    *instanceSpp = ndk::SharedRefBase::make<SpatializerSw>();
+    LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
+    return EX_NONE;
+}
+
+extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
+    if (!in_impl_uuid || *in_impl_uuid != getEffectImplUuidSpatializerSw()) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    *_aidl_return = SpatializerSw::kDescriptor;
+    return EX_NONE;
+}
+
+namespace aidl::android::hardware::audio::effect {
+
+const std::string SpatializerSw::kEffectName = "SpatializerSw";
+
+const std::vector<Range::SpatializerRange> SpatializerSw::kRanges = {
+        MAKE_RANGE(Spatializer, supportedChannelLayout, std::vector<AudioChannelLayout>{},
+                   std::vector<AudioChannelLayout>{}),
+        MAKE_RANGE(Spatializer, spatializationLevel, Spatialization::Level::NONE,
+                   Spatialization::Level::BED_PLUS_OBJECTS),
+        MAKE_RANGE(Spatializer, spatializationMode, Spatialization::Mode::BINAURAL,
+                   Spatialization::Mode::TRANSAURAL),
+        MAKE_RANGE(Spatializer, headTrackingSensorId, std::numeric_limits<int>::min(),
+                   std::numeric_limits<int>::max()),
+        MAKE_RANGE(Spatializer, headTrackingMode, HeadTracking::Mode::OTHER,
+                   HeadTracking::Mode::RELATIVE_SCREEN),
+        MAKE_RANGE(Spatializer, headTrackingConnectionMode,
+                   HeadTracking::ConnectionMode::FRAMEWORK_PROCESSED,
+                   HeadTracking::ConnectionMode::DIRECT_TO_SENSOR_TUNNEL)};
+const Capability SpatializerSw::kCapability = {.range = {SpatializerSw::kRanges}};
+const Descriptor SpatializerSw::kDescriptor = {
+        .common = {.id = {.type = getEffectTypeUuidSpatializer(),
+                          .uuid = getEffectImplUuidSpatializerSw()},
+                   .flags = {.type = Flags::Type::INSERT,
+                             .insert = Flags::Insert::FIRST,
+                             .hwAcceleratorMode = Flags::HardwareAccelerator::NONE},
+                   .name = SpatializerSw::kEffectName,
+                   .implementor = "The Android Open Source Project"},
+        .capability = SpatializerSw::kCapability};
+
+ndk::ScopedAStatus SpatializerSw::getDescriptor(Descriptor* _aidl_return) {
+    LOG(DEBUG) << __func__ << kDescriptor.toString();
+    *_aidl_return = kDescriptor;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus SpatializerSw::setParameterSpecific(const Parameter::Specific& specific) {
+    RETURN_IF(Parameter::Specific::spatializer != specific.getTag(), EX_ILLEGAL_ARGUMENT,
+              "EffectNotSupported");
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+    auto& param = specific.get<Parameter::Specific::spatializer>();
+    RETURN_IF(!inRange(param, kRanges), EX_ILLEGAL_ARGUMENT, "outOfRange");
+
+    return mContext->setParam(param.getTag(), param);
+}
+
+ndk::ScopedAStatus SpatializerSw::getParameterSpecific(const Parameter::Id& id,
+                                                       Parameter::Specific* specific) {
+    auto tag = id.getTag();
+    RETURN_IF(Parameter::Id::spatializerTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
+    auto spatializerId = id.get<Parameter::Id::spatializerTag>();
+    auto spatializerTag = spatializerId.getTag();
+    switch (spatializerTag) {
+        case Spatializer::Id::commonTag: {
+            auto specificTag = spatializerId.get<Spatializer::Id::commonTag>();
+            std::optional<Spatializer> param = mContext->getParam(specificTag);
+            if (!param.has_value()) {
+                return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                        EX_ILLEGAL_ARGUMENT, "SpatializerTagNotSupported");
+            }
+            specific->set<Parameter::Specific::spatializer>(param.value());
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "SpatializerTagNotSupported");
+        }
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EffectContext> SpatializerSw::createContext(const Parameter::Common& common) {
+    if (mContext) {
+        LOG(DEBUG) << __func__ << " context already exist";
+    } else {
+        mContext = std::make_shared<SpatializerSwContext>(1 /* statusFmqDepth */, common);
+    }
+    return mContext;
+}
+
+RetCode SpatializerSw::releaseContext() {
+    if (mContext) {
+        mContext.reset();
+    }
+    return RetCode::SUCCESS;
+}
+
+SpatializerSw::~SpatializerSw() {
+    cleanUp();
+    LOG(DEBUG) << __func__;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status SpatializerSw::effectProcessImpl(float* in, float* out, int samples) {
+    RETURN_VALUE_IF(!mContext, (IEffect::Status{EX_NULL_POINTER, 0, 0}), "nullContext");
+    return mContext->process(in, out, samples);
+}
+
+SpatializerSwContext::SpatializerSwContext(int statusDepth, const Parameter::Common& common)
+    : EffectContext(statusDepth, common) {
+    LOG(DEBUG) << __func__;
+}
+
+SpatializerSwContext::~SpatializerSwContext() {
+    LOG(DEBUG) << __func__;
+}
+
+template <typename TAG>
+std::optional<Spatializer> SpatializerSwContext::getParam(TAG tag) {
+    if (mParamsMap.find(tag) != mParamsMap.end()) {
+        return mParamsMap.at(tag);
+    }
+    return std::nullopt;
+}
+
+template <typename TAG>
+ndk::ScopedAStatus SpatializerSwContext::setParam(TAG tag, Spatializer spatializer) {
+    mParamsMap[tag] = spatializer;
+    return ndk::ScopedAStatus::ok();
+}
+
+IEffect::Status SpatializerSwContext::process(float* in, float* out, int samples) {
+    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
+    IEffect::Status status = {EX_ILLEGAL_ARGUMENT, 0, 0};
+
+    const auto inputChannelCount = getChannelCount(mCommon.input.base.channelMask);
+    const auto outputChannelCount = getChannelCount(mCommon.output.base.channelMask);
+    if (outputChannelCount < 2 || inputChannelCount < outputChannelCount) {
+        LOG(ERROR) << __func__ << " invalid channel count, in: " << inputChannelCount
+                   << " out: " << outputChannelCount;
+        return status;
+    }
+
+    int iFrames = samples / inputChannelCount;
+    for (int i = 0; i < iFrames; i++) {
+        std::memcpy(out, in, outputChannelCount);
+        in += inputChannelCount;
+        out += outputChannelCount;
+    }
+    return {STATUS_OK, static_cast<int32_t>(iFrames * inputChannelCount),
+            static_cast<int32_t>(iFrames * outputChannelCount)};
+}
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/spatializer/SpatializerSw.h b/audio/aidl/default/spatializer/SpatializerSw.h
new file mode 100644
index 0000000..b321e83
--- /dev/null
+++ b/audio/aidl/default/spatializer/SpatializerSw.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "effect-impl/EffectContext.h"
+#include "effect-impl/EffectImpl.h"
+
+#include <fmq/AidlMessageQueue.h>
+
+#include <unordered_map>
+#include <vector>
+
+namespace aidl::android::hardware::audio::effect {
+
+class SpatializerSwContext final : public EffectContext {
+  public:
+    SpatializerSwContext(int statusDepth, const Parameter::Common& common);
+    ~SpatializerSwContext();
+
+    template <typename TAG>
+    std::optional<Spatializer> getParam(TAG tag);
+    template <typename TAG>
+    ndk::ScopedAStatus setParam(TAG tag, Spatializer spatializer);
+
+    IEffect::Status process(float* in, float* out, int samples);
+
+  private:
+    std::unordered_map<Spatializer::Tag, Spatializer> mParamsMap;
+};
+
+class SpatializerSw final : public EffectImpl {
+  public:
+    static const std::string kEffectName;
+    static const Capability kCapability;
+    static const Descriptor kDescriptor;
+    ~SpatializerSw();
+
+    ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+            REQUIRES(mImplMutex) override;
+
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+            REQUIRES(mImplMutex) override;
+    RetCode releaseContext() REQUIRES(mImplMutex) override;
+
+    std::string getEffectName() override { return kEffectName; };
+    IEffect::Status effectProcessImpl(float* in, float* out, int samples)
+            REQUIRES(mImplMutex) override;
+
+  private:
+    static const std::vector<Range::SpatializerRange> kRanges;
+    std::shared_ptr<SpatializerSwContext> mContext GUARDED_BY(mImplMutex) = nullptr;
+};
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/stub/StreamStub.cpp b/audio/aidl/default/stub/StreamStub.cpp
index 660a51e..2422fe4 100644
--- a/audio/aidl/default/stub/StreamStub.cpp
+++ b/audio/aidl/default/stub/StreamStub.cpp
@@ -94,7 +94,7 @@
 }
 
 ::android::status_t StreamStub::transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
-                                         int32_t* latencyMs) {
+                                         int32_t*) {
     if (!mIsInitialized) {
         LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver";
     }
@@ -117,7 +117,6 @@
         }
     }
     *actualFrameCount = frameCount;
-    *latencyMs = Module::kLatencyMs;
     return ::android::OK;
 }
 
diff --git a/audio/aidl/default/usb/ModuleUsb.cpp b/audio/aidl/default/usb/ModuleUsb.cpp
index f926e09..1d97bc4 100644
--- a/audio/aidl/default/usb/ModuleUsb.cpp
+++ b/audio/aidl/default/usb/ModuleUsb.cpp
@@ -87,12 +87,13 @@
                                               offloadInfo);
 }
 
-ndk::ScopedAStatus ModuleUsb::populateConnectedDevicePort(AudioPort* audioPort) {
+ndk::ScopedAStatus ModuleUsb::populateConnectedDevicePort(AudioPort* audioPort,
+                                                          int32_t nextPortId) {
     if (!isUsbDevicePort(*audioPort)) {
         LOG(ERROR) << __func__ << ": port id " << audioPort->id << " is not a usb device port";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
-    return ModuleAlsa::populateConnectedDevicePort(audioPort);
+    return ModuleAlsa::populateConnectedDevicePort(audioPort, nextPortId);
 }
 
 ndk::ScopedAStatus ModuleUsb::checkAudioPatchEndpointsMatch(
diff --git a/audio/aidl/default/usb/StreamUsb.cpp b/audio/aidl/default/usb/StreamUsb.cpp
index b60b4fd..9b10432 100644
--- a/audio/aidl/default/usb/StreamUsb.cpp
+++ b/audio/aidl/default/usb/StreamUsb.cpp
@@ -52,7 +52,7 @@
         }
         connectedDeviceProfiles.push_back(*profile);
     }
-    RETURN_STATUS_IF_ERROR(setConnectedDevices(connectedDevices));
+    RETURN_STATUS_IF_ERROR(StreamCommonImpl::setConnectedDevices(connectedDevices));
     std::lock_guard guard(mLock);
     mConnectedDeviceProfiles = std::move(connectedDeviceProfiles);
     mConnectedDevicesUpdated.store(true, std::memory_order_release);
diff --git a/audio/aidl/default/virtualizer/Android.bp b/audio/aidl/default/virtualizer/Android.bp
index ed0199d..5d59f7c 100644
--- a/audio/aidl/default/virtualizer/Android.bp
+++ b/audio/aidl/default/virtualizer/Android.bp
@@ -27,8 +27,6 @@
     name: "libvirtualizersw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "VirtualizerSw.cpp",
@@ -36,6 +34,6 @@
     ],
     relative_install_path: "soundfx",
     visibility: [
-        "//hardware/interfaces/audio/aidl/default",
+        "//hardware/interfaces/audio/aidl/default:__subpackages__",
     ],
 }
diff --git a/audio/aidl/default/virtualizer/VirtualizerSw.cpp b/audio/aidl/default/virtualizer/VirtualizerSw.cpp
index 0e8435e..091b0b7 100644
--- a/audio/aidl/default/virtualizer/VirtualizerSw.cpp
+++ b/audio/aidl/default/virtualizer/VirtualizerSw.cpp
@@ -203,10 +203,6 @@
     return mContext;
 }
 
-std::shared_ptr<EffectContext> VirtualizerSw::getContext() {
-    return mContext;
-}
-
 RetCode VirtualizerSw::releaseContext() {
     if (mContext) {
         mContext.reset();
diff --git a/audio/aidl/default/virtualizer/VirtualizerSw.h b/audio/aidl/default/virtualizer/VirtualizerSw.h
index 5e114d9..9287838 100644
--- a/audio/aidl/default/virtualizer/VirtualizerSw.h
+++ b/audio/aidl/default/virtualizer/VirtualizerSw.h
@@ -59,24 +59,25 @@
     }
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
-    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
-    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
-                                            Parameter::Specific* specific) override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+            REQUIRES(mImplMutex) override;
 
-    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
-    std::shared_ptr<EffectContext> getContext() override;
-    RetCode releaseContext() override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+            REQUIRES(mImplMutex) override;
+    RetCode releaseContext() REQUIRES(mImplMutex) override;
 
     IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
     std::string getEffectName() override { return kEffectName; }
 
   private:
     static const std::vector<Range::VirtualizerRange> kRanges;
-    std::shared_ptr<VirtualizerSwContext> mContext;
+    std::shared_ptr<VirtualizerSwContext> mContext GUARDED_BY(mImplMutex);
 
     ndk::ScopedAStatus getParameterVirtualizer(const Virtualizer::Tag& tag,
-                                               Parameter::Specific* specific);
+                                               Parameter::Specific* specific) REQUIRES(mImplMutex);
     ndk::ScopedAStatus getSpeakerAngles(const Virtualizer::SpeakerAnglesPayload payload,
-                                        Parameter::Specific* specific);
+                                        Parameter::Specific* specific) REQUIRES(mImplMutex);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/visualizer/Android.bp b/audio/aidl/default/visualizer/Android.bp
index 091daa2..68f7177 100644
--- a/audio/aidl/default/visualizer/Android.bp
+++ b/audio/aidl/default/visualizer/Android.bp
@@ -27,8 +27,6 @@
     name: "libvisualizersw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "VisualizerSw.cpp",
diff --git a/audio/aidl/default/visualizer/VisualizerSw.cpp b/audio/aidl/default/visualizer/VisualizerSw.cpp
index 0909f25..54f7f1c 100644
--- a/audio/aidl/default/visualizer/VisualizerSw.cpp
+++ b/audio/aidl/default/visualizer/VisualizerSw.cpp
@@ -73,7 +73,7 @@
                           .proxy = std::nullopt},
                    .flags = {.type = Flags::Type::INSERT,
                              .insert = Flags::Insert::FIRST,
-                             .volume = Flags::Volume::CTRL},
+                             .volume = Flags::Volume::NONE},
                    .name = VisualizerSw::kEffectName,
                    .implementor = "The Android Open Source Project"},
         .capability = VisualizerSw::kCapability};
@@ -190,10 +190,6 @@
     return mContext;
 }
 
-std::shared_ptr<EffectContext> VisualizerSw::getContext() {
-    return mContext;
-}
-
 RetCode VisualizerSw::releaseContext() {
     if (mContext) {
         mContext.reset();
diff --git a/audio/aidl/default/visualizer/VisualizerSw.h b/audio/aidl/default/visualizer/VisualizerSw.h
index 995774e..4b87b04 100644
--- a/audio/aidl/default/visualizer/VisualizerSw.h
+++ b/audio/aidl/default/visualizer/VisualizerSw.h
@@ -72,21 +72,23 @@
     }
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
-    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
-    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
-                                            Parameter::Specific* specific) override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+            REQUIRES(mImplMutex) override;
 
-    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
-    std::shared_ptr<EffectContext> getContext() override;
-    RetCode releaseContext() override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+            REQUIRES(mImplMutex) override;
+    RetCode releaseContext() REQUIRES(mImplMutex) override;
 
-    IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+    IEffect::Status effectProcessImpl(float* in, float* out, int samples)
+            REQUIRES(mImplMutex) override;
     std::string getEffectName() override { return kEffectName; }
 
   private:
     static const std::vector<Range::VisualizerRange> kRanges;
-    std::shared_ptr<VisualizerSwContext> mContext;
+    std::shared_ptr<VisualizerSwContext> mContext GUARDED_BY(mImplMutex);
     ndk::ScopedAStatus getParameterVisualizer(const Visualizer::Tag& tag,
-                                              Parameter::Specific* specific);
+                                              Parameter::Specific* specific) REQUIRES(mImplMutex);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/volume/Android.bp b/audio/aidl/default/volume/Android.bp
index 418bb8d..8d5401a 100644
--- a/audio/aidl/default/volume/Android.bp
+++ b/audio/aidl/default/volume/Android.bp
@@ -27,8 +27,6 @@
     name: "libvolumesw",
     defaults: [
         "aidlaudioeffectservice_defaults",
-        "latest_android_media_audio_common_types_ndk_shared",
-        "latest_android_hardware_audio_effect_ndk_shared",
     ],
     srcs: [
         "VolumeSw.cpp",
@@ -36,6 +34,6 @@
     ],
     relative_install_path: "soundfx",
     visibility: [
-        "//hardware/interfaces/audio/aidl/default",
+        "//hardware/interfaces/audio/aidl/default:__subpackages__",
     ],
 }
diff --git a/audio/aidl/default/volume/VolumeSw.cpp b/audio/aidl/default/volume/VolumeSw.cpp
index 8902584..dd019f6 100644
--- a/audio/aidl/default/volume/VolumeSw.cpp
+++ b/audio/aidl/default/volume/VolumeSw.cpp
@@ -160,10 +160,6 @@
     return mContext;
 }
 
-std::shared_ptr<EffectContext> VolumeSw::getContext() {
-    return mContext;
-}
-
 RetCode VolumeSw::releaseContext() {
     if (mContext) {
         mContext.reset();
diff --git a/audio/aidl/default/volume/VolumeSw.h b/audio/aidl/default/volume/VolumeSw.h
index 1432b2b..3fc0d97 100644
--- a/audio/aidl/default/volume/VolumeSw.h
+++ b/audio/aidl/default/volume/VolumeSw.h
@@ -57,21 +57,24 @@
     }
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
-    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
-    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
-                                            Parameter::Specific* specific) override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+            REQUIRES(mImplMutex) override;
 
-    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
-    std::shared_ptr<EffectContext> getContext() override;
-    RetCode releaseContext() override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+            REQUIRES(mImplMutex) override;
+    RetCode releaseContext() REQUIRES(mImplMutex) override;
 
-    IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+    IEffect::Status effectProcessImpl(float* in, float* out, int samples)
+            REQUIRES(mImplMutex) override;
     std::string getEffectName() override { return kEffectName; }
 
   private:
     static const std::vector<Range::VolumeRange> kRanges;
-    std::shared_ptr<VolumeSwContext> mContext;
+    std::shared_ptr<VolumeSwContext> mContext GUARDED_BY(mImplMutex);
 
-    ndk::ScopedAStatus getParameterVolume(const Volume::Tag& tag, Parameter::Specific* specific);
+    ndk::ScopedAStatus getParameterVolume(const Volume::Tag& tag, Parameter::Specific* specific)
+            REQUIRES(mImplMutex);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/sounddose/Android.bp b/audio/aidl/sounddose/Android.bp
index 6f2f790..c65e4ff 100644
--- a/audio/aidl/sounddose/Android.bp
+++ b/audio/aidl/sounddose/Android.bp
@@ -52,11 +52,11 @@
         // IMPORTANT: Update latest_android_hardware_audio_sounddose every time you
         // add the latest frozen version to versions_with_info
     ],
-    frozen: true,
+    frozen: false,
 }
 
 // Note: This should always be one version ahead of the last frozen version
-latest_android_hardware_audio_sounddose = "android.hardware.audio.sounddose-V1"
+latest_android_hardware_audio_sounddose = "android.hardware.audio.sounddose-V2"
 
 // Modules that depend on android.hardware.audio.sounddose directly can include
 // the following cc_defaults to avoid explicitly managing dependency versions
diff --git a/audio/aidl/vts/Android.bp b/audio/aidl/vts/Android.bp
index f7cf4ce..85319ec 100644
--- a/audio/aidl/vts/Android.bp
+++ b/audio/aidl/vts/Android.bp
@@ -11,6 +11,7 @@
     name: "VtsHalAudioTargetTestDefaults",
     defaults: [
         "latest_android_hardware_audio_common_ndk_static",
+        "latest_android_hardware_audio_effect_ndk_static",
         "latest_android_media_audio_common_types_ndk_static",
         "use_libaidlvintf_gtest_helper_static",
         "VtsHalTargetTestDefaults",
@@ -20,24 +21,40 @@
         "libfmq",
     ],
     static_libs: [
-        "android.hardware.audio.effect-V1-ndk",
         "android.hardware.common-V2-ndk",
         "android.hardware.common.fmq-V1-ndk",
         "libaudioaidlcommon",
         "libaidlcommonsupport",
     ],
-    header_libs: ["libaudioaidl_headers"],
+    header_libs: [
+        "libaudioaidl_headers",
+        "libexpectedutils_headers",
+    ],
     cflags: [
         "-Wall",
         "-Wextra",
         "-Werror",
         "-Wthread-safety",
     ],
+    test_config_template: "VtsHalAudioTargetTestTemplate.xml",
     test_suites: [
         "general-tests",
         "vts",
     ],
-    srcs: [":effectCommonFile"],
+    srcs: [
+        "TestUtils.cpp",
+    ],
+}
+
+cc_defaults {
+    name: "VtsHalAudioEffectTargetTestDefaults",
+    defaults: [
+        "latest_android_hardware_audio_effect_ndk_static",
+        "VtsHalAudioTargetTestDefaults",
+    ],
+    srcs: [
+        ":effectCommonFile",
+    ],
 }
 
 cc_test {
@@ -55,108 +72,116 @@
         "VtsHalAudioCoreConfigTargetTest.cpp",
         "VtsHalAudioCoreModuleTargetTest.cpp",
     ],
-    test_config: "VtsHalAudioCoreTargetTest.xml",
 }
 
 cc_test {
     name: "VtsHalAudioEffectFactoryTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalAudioEffectFactoryTargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalAudioEffectTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalAudioEffectTargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalBassBoostTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalBassBoostTargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalDownmixTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalDownmixTargetTest.cpp"],
+    shared_libs: [
+        "libaudioutils",
+    ],
 }
 
 cc_test {
     name: "VtsHalDynamicsProcessingTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     static_libs: ["libaudioaidlranges"],
     srcs: ["VtsHalDynamicsProcessingTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalEnvironmentalReverbTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalEnvironmentalReverbTargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalEqualizerTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalEqualizerTargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalHapticGeneratorTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalHapticGeneratorTargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalLoudnessEnhancerTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalLoudnessEnhancerTargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalPresetReverbTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalPresetReverbTargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalVirtualizerTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalVirtualizerTargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalVisualizerTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalVisualizerTargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalVolumeTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalVolumeTargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalAECTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalAECTargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalAGC1TargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalAGC1TargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalAGC2TargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalAGC2TargetTest.cpp"],
 }
 
 cc_test {
     name: "VtsHalNSTargetTest",
-    defaults: ["VtsHalAudioTargetTestDefaults"],
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
     srcs: ["VtsHalNSTargetTest.cpp"],
 }
+
+cc_test {
+    name: "VtsHalSpatializerTargetTest",
+    defaults: ["VtsHalAudioEffectTargetTestDefaults"],
+    srcs: ["VtsHalSpatializerTargetTest.cpp"],
+}
diff --git a/audio/aidl/vts/AudioHalBinderServiceUtil.h b/audio/aidl/vts/AudioHalBinderServiceUtil.h
index b4b4632..4ebc1b1 100644
--- a/audio/aidl/vts/AudioHalBinderServiceUtil.h
+++ b/audio/aidl/vts/AudioHalBinderServiceUtil.h
@@ -42,20 +42,9 @@
 
     ndk::SpAIBinder restartService(
             std::chrono::milliseconds timeoutMs = std::chrono::milliseconds(3000)) {
-        mDeathHandler.reset(new AidlDeathRecipient(mBinder));
-        if (STATUS_OK != mDeathHandler->linkToDeath()) {
-            LOG(ERROR) << "linkToDeath failed";
-            return nullptr;
+        if (!stopService(timeoutMs)) {
+            return {};
         }
-        if (!android::base::SetProperty("sys.audio.restart.hal", "1")) {
-            LOG(ERROR) << "SetProperty failed";
-            return nullptr;
-        }
-        if (!mDeathHandler->waitForFired(timeoutMs)) {
-            LOG(ERROR) << "Timeout wait for death";
-            return nullptr;
-        }
-        mDeathHandler.reset();
         return connectToService(mServiceName);
     }
 
@@ -71,8 +60,7 @@
 
         bool waitForFired(std::chrono::milliseconds timeoutMs) {
             std::unique_lock<std::mutex> lock(mutex);
-            condition.wait_for(lock, timeoutMs, [this]() { return fired; });
-            return fired;
+            return condition.wait_for(lock, timeoutMs, [this]() { return fired; });
         }
 
       private:
@@ -94,7 +82,23 @@
         }
     };
 
+    bool stopService(std::chrono::milliseconds timeoutMs) {
+        AidlDeathRecipient deathHandler(mBinder);
+        if (STATUS_OK != deathHandler.linkToDeath()) {
+            LOG(ERROR) << "linkToDeath failed";
+            return false;
+        }
+        if (!android::base::SetProperty("sys.audio.restart.hal", "1")) {
+            LOG(ERROR) << "SetProperty failed";
+            return false;
+        }
+        if (!deathHandler.waitForFired(timeoutMs)) {
+            LOG(ERROR) << "Timeout wait for death of " << mServiceName;
+            return false;
+        }
+        return true;
+    }
+
     std::string mServiceName;
     ndk::SpAIBinder mBinder;
-    std::unique_ptr<AidlDeathRecipient> mDeathHandler;
 };
diff --git a/audio/aidl/vts/EffectFactoryHelper.h b/audio/aidl/vts/EffectFactoryHelper.h
index a2499fd..ca36655 100644
--- a/audio/aidl/vts/EffectFactoryHelper.h
+++ b/audio/aidl/vts/EffectFactoryHelper.h
@@ -21,6 +21,7 @@
 #include <unordered_map>
 #include <vector>
 
+#include <aidl/Vintf.h>
 #include <android/binder_auto_utils.h>
 
 #include "TestUtils.h"
diff --git a/audio/aidl/vts/EffectHelper.h b/audio/aidl/vts/EffectHelper.h
index 2c8edf2..9fa7f9f 100644
--- a/audio/aidl/vts/EffectHelper.h
+++ b/audio/aidl/vts/EffectHelper.h
@@ -21,6 +21,7 @@
 #include <string>
 #include <type_traits>
 #include <unordered_map>
+#include <utility>
 #include <vector>
 
 #include <Utils.h>
@@ -42,6 +43,7 @@
 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::kEventFlagDataMqUpdate;
 using aidl::android::hardware::audio::effect::kEventFlagNotEmpty;
 using aidl::android::hardware::audio::effect::Parameter;
 using aidl::android::hardware::audio::effect::Range;
@@ -190,6 +192,16 @@
             ASSERT_TRUE(dataMq->read(buffer.data(), expectFloats));
         }
     }
+    static void expectDataMqUpdateEventFlag(std::unique_ptr<StatusMQ>& statusMq) {
+        EventFlag* efGroup;
+        ASSERT_EQ(::android::OK,
+                  EventFlag::createEventFlag(statusMq->getEventFlagWord(), &efGroup));
+        ASSERT_NE(nullptr, efGroup);
+        uint32_t efState = 0;
+        EXPECT_EQ(::android::OK, efGroup->wait(kEventFlagDataMqUpdate, &efState, 1'000'000 /*1ms*/,
+                                               true /* retry */));
+        EXPECT_TRUE(efState & kEventFlagDataMqUpdate);
+    }
     static Parameter::Common createParamCommon(
             int session = 0, int ioHandle = -1, int iSampleRate = 48000, int oSampleRate = 48000,
             long iFrameCount = 0x100, long oFrameCount = 0x100,
@@ -263,12 +275,11 @@
         return s;
     }
 
-    template <typename T, typename S, Range::Tag R, typename T::Tag tag, typename Functor>
+    template <typename T, typename S, Range::Tag R, typename T::Tag tag>
     static std::set<S> getTestValueSet(
-            std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> kFactoryDescList,
-            Functor functor) {
+            std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> descList) {
         std::set<S> result;
-        for (const auto& [_, desc] : kFactoryDescList) {
+        for (const auto& [_, desc] : descList) {
             if (desc.capability.range.getTag() == R) {
                 const auto& ranges = desc.capability.range.get<R>();
                 for (const auto& range : ranges) {
@@ -281,6 +292,42 @@
                 }
             }
         }
+        return result;
+    }
+
+    template <typename T, typename S, Range::Tag R, typename T::Tag tag, typename Functor>
+    static std::set<S> getTestValueSet(
+            std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> descList,
+            Functor functor) {
+        auto result = getTestValueSet<T, S, R, tag>(descList);
         return functor(result);
     }
+
+    static void processAndWriteToOutput(std::vector<float>& inputBuffer,
+                                        std::vector<float>& outputBuffer,
+                                        const std::shared_ptr<IEffect>& mEffect,
+                                        IEffect::OpenEffectReturn* mOpenEffectReturn) {
+        // Initialize AidlMessagequeues
+        auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(mOpenEffectReturn->statusMQ);
+        ASSERT_TRUE(statusMQ->isValid());
+        auto inputMQ = std::make_unique<EffectHelper::DataMQ>(mOpenEffectReturn->inputDataMQ);
+        ASSERT_TRUE(inputMQ->isValid());
+        auto outputMQ = std::make_unique<EffectHelper::DataMQ>(mOpenEffectReturn->outputDataMQ);
+        ASSERT_TRUE(outputMQ->isValid());
+
+        // Enabling the process
+        ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+        ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+
+        // Write from buffer to message queues and calling process
+        EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ, inputMQ, inputBuffer));
+
+        // Read the updated message queues into buffer
+        EXPECT_NO_FATAL_FAILURE(EffectHelper::readFromFmq(statusMQ, 1, outputMQ,
+                                                          outputBuffer.size(), outputBuffer));
+
+        // Disable the process
+        ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::RESET));
+        ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    }
 };
diff --git a/audio/aidl/vts/ModuleConfig.cpp b/audio/aidl/vts/ModuleConfig.cpp
index 8fdb155..2b86271 100644
--- a/audio/aidl/vts/ModuleConfig.cpp
+++ b/audio/aidl/vts/ModuleConfig.cpp
@@ -17,10 +17,14 @@
 #include <algorithm>
 #include <chrono>
 
+#define LOG_TAG "VtsHalAudio.ModuleConfig"
+#include <android-base/logging.h>
+
 #include <Utils.h>
 #include <aidl/android/media/audio/common/AudioInputFlags.h>
 #include <aidl/android/media/audio/common/AudioIoFlags.h>
 #include <aidl/android/media/audio/common/AudioOutputFlags.h>
+#include <error/expected_utils.h>
 
 #include "ModuleConfig.h"
 
@@ -66,20 +70,7 @@
     return {};
 }
 
-std::vector<aidl::android::media::audio::common::AudioPort>
-ModuleConfig::getAudioPortsForDeviceTypes(const std::vector<AudioDeviceType>& deviceTypes,
-                                          const std::string& connection) {
-    return getAudioPortsForDeviceTypes(mPorts, deviceTypes, connection);
-}
-
 // static
-std::vector<aidl::android::media::audio::common::AudioPort> ModuleConfig::getBuiltInMicPorts(
-        const std::vector<aidl::android::media::audio::common::AudioPort>& ports) {
-    return getAudioPortsForDeviceTypes(
-            ports, std::vector<AudioDeviceType>{AudioDeviceType::IN_MICROPHONE,
-                                                AudioDeviceType::IN_MICROPHONE_BACK});
-}
-
 std::vector<aidl::android::media::audio::common::AudioPort>
 ModuleConfig::getAudioPortsForDeviceTypes(
         const std::vector<aidl::android::media::audio::common::AudioPort>& ports,
@@ -99,6 +90,14 @@
     return result;
 }
 
+// static
+std::vector<aidl::android::media::audio::common::AudioPort> ModuleConfig::getBuiltInMicPorts(
+        const std::vector<aidl::android::media::audio::common::AudioPort>& ports) {
+    return getAudioPortsForDeviceTypes(
+            ports, std::vector<AudioDeviceType>{AudioDeviceType::IN_MICROPHONE,
+                                                AudioDeviceType::IN_MICROPHONE_BACK});
+}
+
 template <typename T>
 auto findById(const std::vector<T>& v, int32_t id) {
     return std::find_if(v.begin(), v.end(), [&](const auto& p) { return p.id == id; });
@@ -118,10 +117,7 @@
             } else {
                 mAttachedSinkDevicePorts.insert(port.id);
             }
-        } else if (devicePort.device.type.connection != AudioDeviceDescription::CONNECTION_VIRTUAL
-                   // The "virtual" connection is used for remote submix which is a dynamic
-                   // device but it can be connected and used w/o external hardware.
-                   && port.profiles.empty()) {
+        } else {
             mExternalDevicePorts.insert(port.id);
         }
     }
@@ -140,6 +136,12 @@
     return result;
 }
 
+std::vector<aidl::android::media::audio::common::AudioPort>
+ModuleConfig::getAudioPortsForDeviceTypes(const std::vector<AudioDeviceType>& deviceTypes,
+                                          const std::string& connection) const {
+    return getAudioPortsForDeviceTypes(mPorts, deviceTypes, connection);
+}
+
 std::vector<AudioPort> ModuleConfig::getConnectedExternalDevicePorts() const {
     std::vector<AudioPort> result;
     std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result), [&](const auto& port) {
@@ -228,6 +230,16 @@
     });
 }
 
+std::vector<AudioPort> ModuleConfig::getRemoteSubmixPorts(bool isInput, bool singlePort) const {
+    AudioDeviceType deviceType = isInput ? AudioDeviceType::IN_SUBMIX : AudioDeviceType::OUT_SUBMIX;
+    auto ports = getAudioPortsForDeviceTypes(std::vector<AudioDeviceType>{deviceType},
+                                             AudioDeviceDescription::CONNECTION_VIRTUAL);
+    if (singlePort) {
+        if (!ports.empty()) ports.resize(1);
+    }
+    return ports;
+}
+
 std::vector<AudioPort> ModuleConfig::getConnectedDevicesPortsForMixPort(
         bool isInput, const AudioPortConfig& mixPortConfig) const {
     const auto mixPortIt = findById<AudioPort>(mPorts, mixPortConfig.portId);
@@ -280,6 +292,32 @@
     return {};
 }
 
+std::vector<AudioPort> ModuleConfig::getRoutableDevicePortsForMixPort(const AudioPort& port,
+                                                                      bool connectedOnly) const {
+    std::set<int32_t> portIds = findRoutablePortIds(port.id);
+    const bool isInput = port.flags.getTag() == AudioIoFlags::input;
+    std::set<int32_t> devicePortIds;
+    if (connectedOnly) {
+        devicePortIds = isInput ? getConnectedSourceDevicePorts() : getConnectedSinkDevicePorts();
+    } else {
+        devicePortIds = portIds;
+    }
+    std::vector<AudioPort> result;
+    std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result), [&](const auto& port) {
+        return port.ext.getTag() == AudioPortExt::Tag::device && portIds.count(port.id) > 0 &&
+               devicePortIds.count(port.id) > 0;
+    });
+    return result;
+}
+
+std::vector<AudioPort> ModuleConfig::getRoutableMixPortsForDevicePort(const AudioPort& port,
+                                                                      bool connectedOnly) const {
+    std::set<int32_t> portIds = findRoutablePortIds(port.id);
+    const bool isInput = port.flags.getTag() == AudioIoFlags::input;
+    return findMixPorts(isInput, connectedOnly, false /*singlePort*/,
+                        [&portIds](const AudioPort& p) { return portIds.count(p.id) > 0; });
+}
+
 std::optional<ModuleConfig::SrcSinkPair> ModuleConfig::getNonRoutableSrcSinkPair(
         bool isInput) const {
     const auto mixPorts = getMixPorts(isInput, false /*connectedOnly*/);
@@ -453,6 +491,20 @@
     return result;
 }
 
+std::set<int32_t> ModuleConfig::findRoutablePortIds(int32_t portId) const {
+    std::set<int32_t> portIds;
+    for (const auto& route : mRoutes) {
+        if (portId == route.sinkPortId) {
+            portIds.insert(route.sourcePortIds.begin(), route.sourcePortIds.end());
+        } else if (auto it = std::find(route.sourcePortIds.begin(), route.sourcePortIds.end(),
+                                       portId);
+                   it != route.sourcePortIds.end()) {
+            portIds.insert(route.sinkPortId);
+        }
+    }
+    return portIds;
+}
+
 std::vector<AudioPortConfig> ModuleConfig::generateAudioMixPortConfigs(
         const std::vector<AudioPort>& ports, bool isInput, bool singleProfile) const {
     std::vector<AudioPortConfig> result;
@@ -499,18 +551,13 @@
     return result;
 }
 
-const ndk::ScopedAStatus& ModuleConfig::onExternalDeviceConnected(IModule* module,
-                                                                  const AudioPort& port) {
-    // Update ports and routes
-    mStatus = module->getAudioPorts(&mPorts);
-    if (!mStatus.isOk()) return mStatus;
-    mStatus = module->getAudioRoutes(&mRoutes);
-    if (!mStatus.isOk()) return mStatus;
+ndk::ScopedAStatus ModuleConfig::onExternalDeviceConnected(IModule* module, const AudioPort& port) {
+    RETURN_STATUS_IF_ERROR(module->getAudioPorts(&mPorts));
+    RETURN_STATUS_IF_ERROR(module->getAudioRoutes(&mRoutes));
 
     // Validate port is present in module
     if (std::find(mPorts.begin(), mPorts.end(), port) == mPorts.end()) {
-        mStatus = ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
-        return mStatus;
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
 
     if (port.flags.getTag() == aidl::android::media::audio::common::AudioIoFlags::Tag::input) {
@@ -518,23 +565,20 @@
     } else {
         mConnectedExternalSinkDevicePorts.insert(port.id);
     }
-    return mStatus;
+    return ndk::ScopedAStatus::ok();
 }
 
-const ndk::ScopedAStatus& ModuleConfig::onExternalDeviceDisconnected(IModule* module,
-                                                                     const AudioPort& port) {
-    // Update ports and routes
-    mStatus = module->getAudioPorts(&mPorts);
-    if (!mStatus.isOk()) return mStatus;
-    mStatus = module->getAudioRoutes(&mRoutes);
-    if (!mStatus.isOk()) return mStatus;
+ndk::ScopedAStatus ModuleConfig::onExternalDeviceDisconnected(IModule* module,
+                                                              const AudioPort& port) {
+    RETURN_STATUS_IF_ERROR(module->getAudioPorts(&mPorts));
+    RETURN_STATUS_IF_ERROR(module->getAudioRoutes(&mRoutes));
 
     if (port.flags.getTag() == aidl::android::media::audio::common::AudioIoFlags::Tag::input) {
         mConnectedExternalSourceDevicePorts.erase(port.id);
     } else {
         mConnectedExternalSinkDevicePorts.erase(port.id);
     }
-    return mStatus;
+    return ndk::ScopedAStatus::ok();
 }
 
 bool ModuleConfig::isMmapSupported() const {
diff --git a/audio/aidl/vts/ModuleConfig.h b/audio/aidl/vts/ModuleConfig.h
index bce1de1..4a87f8c 100644
--- a/audio/aidl/vts/ModuleConfig.h
+++ b/audio/aidl/vts/ModuleConfig.h
@@ -38,9 +38,6 @@
     generateOffloadInfoIfNeeded(
             const aidl::android::media::audio::common::AudioPortConfig& portConfig);
 
-    std::vector<aidl::android::media::audio::common::AudioPort> getAudioPortsForDeviceTypes(
-            const std::vector<aidl::android::media::audio::common::AudioDeviceType>& deviceTypes,
-            const std::string& connection = "");
     static std::vector<aidl::android::media::audio::common::AudioPort> getAudioPortsForDeviceTypes(
             const std::vector<aidl::android::media::audio::common::AudioPort>& ports,
             const std::vector<aidl::android::media::audio::common::AudioDeviceType>& deviceTypes,
@@ -53,6 +50,9 @@
     std::string getError() const { return mStatus.getMessage(); }
 
     std::vector<aidl::android::media::audio::common::AudioPort> getAttachedDevicePorts() const;
+    std::vector<aidl::android::media::audio::common::AudioPort> getAudioPortsForDeviceTypes(
+            const std::vector<aidl::android::media::audio::common::AudioDeviceType>& deviceTypes,
+            const std::string& connection = "") const;
     std::vector<aidl::android::media::audio::common::AudioPort> getConnectedExternalDevicePorts()
             const;
     std::set<int32_t> getConnectedSinkDevicePorts() const;
@@ -85,6 +85,8 @@
     std::vector<aidl::android::media::audio::common::AudioPort> getMmapInMixPorts(
             bool connectedOnly /*Permanently attached and connected external devices*/,
             bool singlePort) const;
+    std::vector<aidl::android::media::audio::common::AudioPort> getRemoteSubmixPorts(
+            bool isInput, bool singlePort) const;
 
     std::vector<aidl::android::media::audio::common::AudioPort> getConnectedDevicesPortsForMixPort(
             bool isInput, const aidl::android::media::audio::common::AudioPort& mixPort) const {
@@ -103,6 +105,13 @@
     std::optional<aidl::android::media::audio::common::AudioPort>
     getSourceMixPortForConnectedDevice() const;
 
+    std::vector<aidl::android::media::audio::common::AudioPort> getRoutableDevicePortsForMixPort(
+            const aidl::android::media::audio::common::AudioPort& port,
+            bool connectedOnly /*Permanently attached and connected external devices*/) const;
+    std::vector<aidl::android::media::audio::common::AudioPort> getRoutableMixPortsForDevicePort(
+            const aidl::android::media::audio::common::AudioPort& port,
+            bool connectedOnly /*Permanently attached and connected external devices*/) const;
+
     std::optional<SrcSinkPair> getNonRoutableSrcSinkPair(bool isInput) const;
     std::optional<SrcSinkPair> getRoutableSrcSinkPair(bool isInput) const;
     std::vector<SrcSinkGroup> getRoutableSrcSinkGroups(bool isInput) const;
@@ -157,10 +166,10 @@
         return *config.begin();
     }
 
-    const ndk::ScopedAStatus& onExternalDeviceConnected(
+    ndk::ScopedAStatus onExternalDeviceConnected(
             aidl::android::hardware::audio::core::IModule* module,
             const aidl::android::media::audio::common::AudioPort& port);
-    const ndk::ScopedAStatus& onExternalDeviceDisconnected(
+    ndk::ScopedAStatus onExternalDeviceDisconnected(
             aidl::android::hardware::audio::core::IModule* module,
             const aidl::android::media::audio::common::AudioPort& port);
 
@@ -173,6 +182,7 @@
             bool isInput, bool connectedOnly, bool singlePort,
             const std::function<bool(const aidl::android::media::audio::common::AudioPort&)>& pred)
             const;
+    std::set<int32_t> findRoutablePortIds(int32_t portId) const;
     std::vector<aidl::android::media::audio::common::AudioPortConfig> generateAudioMixPortConfigs(
             const std::vector<aidl::android::media::audio::common::AudioPort>& ports, bool isInput,
             bool singleProfile) const;
diff --git a/audio/aidl/vts/TestUtils.cpp b/audio/aidl/vts/TestUtils.cpp
new file mode 100644
index 0000000..f018468
--- /dev/null
+++ b/audio/aidl/vts/TestUtils.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "TestUtils.h"
+
+#define LOG_TAG "VtsHalAudio_TestUtils"
+
+#include <android-base/logging.h>
+
+namespace android::hardware::audio::common::testing {
+
+namespace detail {
+void TestExecutionTracer::OnTestStart(const ::testing::TestInfo& test_info) {
+    TraceTestState("Started", test_info);
+}
+
+void TestExecutionTracer::OnTestEnd(const ::testing::TestInfo& test_info) {
+    TraceTestState("Completed", test_info);
+}
+
+void TestExecutionTracer::OnTestPartResult(const ::testing::TestPartResult& result) {
+    LOG(INFO) << result;
+}
+
+void TestExecutionTracer::TraceTestState(const std::string& state,
+                                         const ::testing::TestInfo& test_info) {
+    LOG(INFO) << state << " " << test_info.test_suite_name() << "::" << test_info.name();
+}
+}
+}
\ No newline at end of file
diff --git a/audio/aidl/vts/TestUtils.h b/audio/aidl/vts/TestUtils.h
index b559669..515b8a2 100644
--- a/audio/aidl/vts/TestUtils.h
+++ b/audio/aidl/vts/TestUtils.h
@@ -18,15 +18,24 @@
 
 #include <algorithm>
 #include <initializer_list>
-#include <iostream>
 
 #include <android/binder_auto_utils.h>
 #include <gtest/gtest.h>
+#include <system/audio_aidl_utils.h>
 
 namespace android::hardware::audio::common::testing {
 
 namespace detail {
 
+class TestExecutionTracer : public ::testing::EmptyTestEventListener {
+  public:
+    void OnTestStart(const ::testing::TestInfo& test_info) override;
+    void OnTestEnd(const ::testing::TestInfo& test_info) override;
+    void OnTestPartResult(const ::testing::TestPartResult& result) override;
+  private:
+    static void TraceTestState(const std::string& state, const ::testing::TestInfo& test_info);
+};
+
 inline ::testing::AssertionResult assertIsOk(const char* expr, const ::ndk::ScopedAStatus& status) {
     if (status.isOk()) {
         return ::testing::AssertionSuccess();
@@ -60,6 +69,23 @@
                                          << "\n  but is has completed with: " << status;
 }
 
+inline ::testing::AssertionResult assertIsOkOrUnknownTransaction(
+        const char* expr, const ::ndk::ScopedAStatus& status) {
+    if (status.getStatus() == STATUS_UNKNOWN_TRANSACTION) {
+        return ::testing::AssertionSuccess();
+    }
+    return assertIsOk(expr, status);
+}
+
+inline ::testing::AssertionResult assertResultOrUnknownTransaction(
+        const char* exp_expr, const char* act_expr, int32_t expected,
+        const ::ndk::ScopedAStatus& status) {
+    if (status.getStatus() == STATUS_UNKNOWN_TRANSACTION) {
+        return ::testing::AssertionSuccess();
+    }
+    return assertResult(exp_expr, act_expr, expected, status);
+}
+
 }  // namespace detail
 
 }  // namespace android::hardware::audio::common::testing
@@ -83,4 +109,16 @@
         if ((flags).hwAcceleratorMode == Flags::HardwareAccelerator::TUNNEL || (flags).bypass) { \
             GTEST_SKIP() << "Skip data path for offload";                                        \
         }                                                                                        \
-    })
\ No newline at end of file
+    })
+
+// Test that the transaction status 'isOk' if it is a known transaction
+#define EXPECT_IS_OK_OR_UNKNOWN_TRANSACTION(ret)                                                 \
+    EXPECT_PRED_FORMAT1(                                                                         \
+            ::android::hardware::audio::common::testing::detail::assertIsOkOrUnknownTransaction, \
+            ret)
+
+// Test that the transaction status is as expected if it is a known transaction
+#define EXPECT_STATUS_OR_UNKNOWN_TRANSACTION(expected, ret)                                        \
+    EXPECT_PRED_FORMAT2(                                                                           \
+            ::android::hardware::audio::common::testing::detail::assertResultOrUnknownTransaction, \
+            expected, ret)
diff --git a/audio/aidl/vts/VtsHalAECTargetTest.cpp b/audio/aidl/vts/VtsHalAECTargetTest.cpp
index 0354e3c..f972b84 100644
--- a/audio/aidl/vts/VtsHalAECTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAECTargetTest.cpp
@@ -18,7 +18,6 @@
 #include <string>
 #include <unordered_set>
 
-#include <aidl/Vintf.h>
 #define LOG_TAG "VtsHalAECParamTest"
 #include <android-base/logging.h>
 
@@ -34,6 +33,7 @@
 using aidl::android::hardware::audio::effect::IFactory;
 using aidl::android::hardware::audio::effect::Parameter;
 using aidl::android::hardware::audio::effect::Range;
+using android::hardware::audio::common::testing::detail::TestExecutionTracer;
 
 enum ParamName { PARAM_INSTANCE_NAME, PARAM_ECHO_DELAY, PARAM_MOBILE_MODE };
 using AECParamTestParam = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>,
@@ -178,6 +178,7 @@
 
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
+    ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
     ABinderProcess_setThreadPoolMaxThreadCount(1);
     ABinderProcess_startThreadPool();
     return RUN_ALL_TESTS();
diff --git a/audio/aidl/vts/VtsHalAGC1TargetTest.cpp b/audio/aidl/vts/VtsHalAGC1TargetTest.cpp
index 65c6a8f..75da589 100644
--- a/audio/aidl/vts/VtsHalAGC1TargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAGC1TargetTest.cpp
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include <aidl/Vintf.h>
 #define LOG_TAG "VtsHalAGC1ParamTest"
 #include <android-base/logging.h>
 
@@ -28,6 +27,7 @@
 using aidl::android::hardware::audio::effect::IEffect;
 using aidl::android::hardware::audio::effect::IFactory;
 using aidl::android::hardware::audio::effect::Parameter;
+using android::hardware::audio::common::testing::detail::TestExecutionTracer;
 
 enum ParamName {
     PARAM_INSTANCE_NAME,
@@ -189,6 +189,7 @@
 
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
+    ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
     ABinderProcess_setThreadPoolMaxThreadCount(1);
     ABinderProcess_startThreadPool();
     return RUN_ALL_TESTS();
diff --git a/audio/aidl/vts/VtsHalAGC2TargetTest.cpp b/audio/aidl/vts/VtsHalAGC2TargetTest.cpp
index 46a569e..5f57a88 100644
--- a/audio/aidl/vts/VtsHalAGC2TargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAGC2TargetTest.cpp
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include <aidl/Vintf.h>
 #define LOG_TAG "VtsHalAGC2ParamTest"
 #include <android-base/logging.h>
 #include <android/binder_enums.h>
@@ -29,6 +28,7 @@
 using aidl::android::hardware::audio::effect::IEffect;
 using aidl::android::hardware::audio::effect::IFactory;
 using aidl::android::hardware::audio::effect::Parameter;
+using android::hardware::audio::common::testing::detail::TestExecutionTracer;
 
 enum ParamName {
     PARAM_INSTANCE_NAME,
@@ -194,6 +194,7 @@
 
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
+    ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
     ABinderProcess_setThreadPoolMaxThreadCount(1);
     ABinderProcess_startThreadPool();
     return RUN_ALL_TESTS();
diff --git a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
index b1eecd2..7373073 100644
--- a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
@@ -46,6 +46,7 @@
 #include <aidl/android/media/audio/common/AudioOutputFlags.h>
 #include <android-base/chrono_utils.h>
 #include <android/binder_enums.h>
+#include <error/expected_utils.h>
 #include <fmq/AidlMessageQueue.h>
 
 #include "AudioHalBinderServiceUtil.h"
@@ -86,6 +87,7 @@
 using aidl::android::media::audio::common::AudioFormatType;
 using aidl::android::media::audio::common::AudioIoFlags;
 using aidl::android::media::audio::common::AudioLatencyMode;
+using aidl::android::media::audio::common::AudioMMapPolicy;
 using aidl::android::media::audio::common::AudioMMapPolicyInfo;
 using aidl::android::media::audio::common::AudioMMapPolicyType;
 using aidl::android::media::audio::common::AudioMode;
@@ -106,14 +108,28 @@
 using aidl::android::media::audio::common::Void;
 using android::hardware::audio::common::StreamLogic;
 using android::hardware::audio::common::StreamWorker;
+using android::hardware::audio::common::testing::detail::TestExecutionTracer;
 using ndk::enum_range;
 using ndk::ScopedAStatus;
 
 template <typename T>
-auto findById(std::vector<T>& v, int32_t id) {
+std::set<int32_t> extractIds(const std::vector<T>& v) {
+    std::set<int32_t> ids;
+    std::transform(v.begin(), v.end(), std::inserter(ids, ids.begin()),
+                   [](const auto& entity) { return entity.id; });
+    return ids;
+}
+
+template <typename T>
+auto findById(const std::vector<T>& v, int32_t id) {
     return std::find_if(v.begin(), v.end(), [&](const auto& e) { return e.id == id; });
 }
 
+template <typename T>
+auto findAny(const std::vector<T>& v, const std::set<int32_t>& ids) {
+    return std::find_if(v.begin(), v.end(), [&](const auto& e) { return ids.count(e.id) > 0; });
+}
+
 template <typename C>
 std::vector<int32_t> GetNonExistentIds(const C& allIds) {
     if (allIds.empty()) {
@@ -152,8 +168,10 @@
     static int nextId = 0;
     using Tag = AudioDeviceAddress::Tag;
     const auto& deviceDescription = port.ext.get<AudioPortExt::Tag::device>().device.type;
-    AudioDeviceAddress address;
-    if (kPointToPointConnections.count(deviceDescription.connection) == 0) {
+    AudioDeviceAddress address = port.ext.get<AudioPortExt::Tag::device>().device.address;
+    // If the address is already set, do not re-generate.
+    if (address == AudioDeviceAddress() &&
+        kPointToPointConnections.count(deviceDescription.connection) == 0) {
         switch (suggestDeviceAddressTag(deviceDescription)) {
             case Tag::id:
                 address = AudioDeviceAddress::make<Tag::id>(std::to_string(++nextId));
@@ -414,31 +432,51 @@
 // Can be used as a base for any test here, does not depend on the fixture GTest parameters.
 class AudioCoreModuleBase {
   public:
-    // Default buffer sizes are used mostly for negative tests.
-    static constexpr int kDefaultBufferSizeFrames = 256;
+    // Fixed buffer size are used for negative tests only. For any tests involving stream
+    // opening that must success, the minimum buffer size must be obtained from a patch.
+    // This is implemented by the 'StreamFixture' utility class.
+    static constexpr int kNegativeTestBufferSizeFrames = 256;
     static constexpr int kDefaultLargeBufferSizeFrames = 48000;
 
-    void SetUpImpl(const std::string& moduleName) {
-        ASSERT_NO_FATAL_FAILURE(ConnectToService(moduleName));
+    void SetUpImpl(const std::string& moduleName, bool setUpDebug = true) {
+        ASSERT_NO_FATAL_FAILURE(ConnectToService(moduleName, setUpDebug));
+        ASSERT_IS_OK(module->getAudioPorts(&initialPorts));
+        ASSERT_IS_OK(module->getAudioRoutes(&initialRoutes));
     }
 
-    void TearDownImpl() { debug.reset(); }
+    void TearDownImpl() {
+        debug.reset();
+        ASSERT_NE(module, nullptr);
+        std::vector<AudioPort> finalPorts;
+        ASSERT_IS_OK(module->getAudioPorts(&finalPorts));
+        EXPECT_NO_FATAL_FAILURE(VerifyVectorsAreEqual<AudioPort>(initialPorts, finalPorts))
+                << "The list of audio ports was not restored to the initial state";
+        std::vector<AudioRoute> finalRoutes;
+        ASSERT_IS_OK(module->getAudioRoutes(&finalRoutes));
+        EXPECT_NO_FATAL_FAILURE(VerifyVectorsAreEqual<AudioRoute>(initialRoutes, finalRoutes))
+                << "The list of audio routes was not restored to the initial state";
+    }
 
-    void ConnectToService(const std::string& moduleName) {
+    void ConnectToService(const std::string& moduleName, bool setUpDebug) {
         ASSERT_EQ(module, nullptr);
         ASSERT_EQ(debug, nullptr);
         module = IModule::fromBinder(binderUtil.connectToService(moduleName));
         ASSERT_NE(module, nullptr);
-        ASSERT_NO_FATAL_FAILURE(SetUpDebug());
+        if (setUpDebug) {
+            ASSERT_NO_FATAL_FAILURE(SetUpDebug());
+        }
     }
 
     void RestartService() {
         ASSERT_NE(module, nullptr);
         moduleConfig.reset();
+        const bool setUpDebug = !!debug;
         debug.reset();
         module = IModule::fromBinder(binderUtil.restartService());
         ASSERT_NE(module, nullptr);
-        ASSERT_NO_FATAL_FAILURE(SetUpDebug());
+        if (setUpDebug) {
+            ASSERT_NO_FATAL_FAILURE(SetUpDebug());
+        }
     }
 
     void SetUpDebug() {
@@ -478,9 +516,7 @@
                          const std::string& errorMessage) {
         std::vector<Entity> entities;
         { ASSERT_IS_OK((module.get()->*getter)(&entities)); }
-        std::transform(entities.begin(), entities.end(),
-                       std::inserter(*entityIds, entityIds->begin()),
-                       [](const auto& entity) { return entity.id; });
+        *entityIds = extractIds<Entity>(entities);
         EXPECT_EQ(entities.size(), entityIds->size()) << errorMessage;
     }
 
@@ -510,17 +546,24 @@
         }
     }
 
+    // Warning: modifies the vectors!
+    template <typename T>
+    void VerifyVectorsAreEqual(std::vector<T>& v1, std::vector<T>& v2) {
+        ASSERT_EQ(v1.size(), v2.size());
+        std::sort(v1.begin(), v1.end());
+        std::sort(v2.begin(), v2.end());
+        if (v1 != v2) {
+            FAIL() << "Vectors are not equal: v1 = " << ::android::internal::ToString(v1)
+                   << ", v2 = " << ::android::internal::ToString(v2);
+        }
+    }
+
     std::shared_ptr<IModule> module;
     std::unique_ptr<ModuleConfig> moduleConfig;
     AudioHalBinderServiceUtil binderUtil;
     std::unique_ptr<WithDebugFlags> debug;
-};
-
-class AudioCoreModule : public AudioCoreModuleBase, public testing::TestWithParam<std::string> {
-  public:
-    void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpImpl(GetParam())); }
-
-    void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownImpl()); }
+    std::vector<AudioPort> initialPorts;
+    std::vector<AudioRoute> initialRoutes;
 };
 
 class WithDevicePortConnectedState {
@@ -530,6 +573,8 @@
     WithDevicePortConnectedState& operator=(const WithDevicePortConnectedState&) = delete;
     ~WithDevicePortConnectedState() {
         if (mModule != nullptr) {
+            EXPECT_IS_OK_OR_UNKNOWN_TRANSACTION(mModule->prepareToDisconnectExternalDevice(getId()))
+                    << "when preparing to disconnect device port ID " << getId();
             EXPECT_IS_OK(mModule->disconnectExternalDevice(getId()))
                     << "when disconnecting device port ID " << getId();
         }
@@ -538,16 +583,19 @@
                     << "when external device disconnected";
         }
     }
+    ScopedAStatus SetUpNoChecks(IModule* module, ModuleConfig* moduleConfig) {
+        RETURN_STATUS_IF_ERROR(module->connectExternalDevice(mIdAndData, &mConnectedPort));
+        RETURN_STATUS_IF_ERROR(moduleConfig->onExternalDeviceConnected(module, mConnectedPort));
+        mModule = module;
+        mModuleConfig = moduleConfig;
+        return ScopedAStatus::ok();
+    }
     void SetUp(IModule* module, ModuleConfig* moduleConfig) {
-        ASSERT_IS_OK(module->connectExternalDevice(mIdAndData, &mConnectedPort))
+        ASSERT_NE(moduleConfig, nullptr);
+        ASSERT_IS_OK(SetUpNoChecks(module, moduleConfig))
                 << "when connecting device port ID & data " << mIdAndData.toString();
         ASSERT_NE(mIdAndData.id, getId())
                 << "ID of the connected port must not be the same as the ID of the template port";
-        ASSERT_NE(moduleConfig, nullptr);
-        ASSERT_IS_OK(moduleConfig->onExternalDeviceConnected(module, mConnectedPort))
-                << "when external device connected";
-        mModule = module;
-        mModuleConfig = moduleConfig;
     }
     int32_t getId() const { return mConnectedPort.id; }
     const AudioPort& get() { return mConnectedPort; }
@@ -559,6 +607,13 @@
     AudioPort mConnectedPort;
 };
 
+class AudioCoreModule : public AudioCoreModuleBase, public testing::TestWithParam<std::string> {
+  public:
+    void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpImpl(GetParam())); }
+
+    void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownImpl()); }
+};
+
 class StreamContext {
   public:
     typedef AidlMessageQueue<StreamDescriptor::Command, SynchronizedReadWrite> CommandMQ;
@@ -1080,6 +1135,7 @@
 template <typename T>
 struct IOTraits {
     static constexpr bool is_input = std::is_same_v<T, IStreamIn>;
+    static constexpr const char* directionStr = is_input ? "input" : "output";
     using Worker = std::conditional_t<is_input, StreamReader, StreamWriter>;
 };
 
@@ -1111,8 +1167,7 @@
     }
     ScopedAStatus SetUpNoChecks(IModule* module, const AudioPortConfig& portConfig,
                                 long bufferSizeFrames);
-    void SetUp(IModule* module, long bufferSizeFrames) {
-        ASSERT_NO_FATAL_FAILURE(SetUpPortConfig(module));
+    void SetUpStream(IModule* module, long bufferSizeFrames) {
         ASSERT_IS_OK(SetUpNoChecks(module, bufferSizeFrames)) << "port config id " << getPortId();
         ASSERT_NE(nullptr, mStream) << "port config id " << getPortId();
         EXPECT_GE(mDescriptor.bufferSizeFrames, bufferSizeFrames)
@@ -1120,6 +1175,10 @@
         mContext.emplace(mDescriptor);
         ASSERT_NO_FATAL_FAILURE(mContext.value().checkIsValid());
     }
+    void SetUp(IModule* module, long bufferSizeFrames) {
+        ASSERT_NO_FATAL_FAILURE(SetUpPortConfig(module));
+        ASSERT_NO_FATAL_FAILURE(SetUpStream(module, bufferSizeFrames));
+    }
     Stream* get() const { return mStream.get(); }
     const StreamContext* getContext() const { return mContext ? &(mContext.value()) : nullptr; }
     StreamEventReceiver* getEventReceiver() { return mStreamCallback->getEventReceiver(); }
@@ -1207,11 +1266,25 @@
                    const AudioPortConfig& portConfig2)
         : mSrcPortConfig(sinkIsCfg1 ? portConfig2 : portConfig1),
           mSinkPortConfig(sinkIsCfg1 ? portConfig1 : portConfig2) {}
+    WithAudioPatch(const WithAudioPatch& patch, const AudioPortConfig& srcPortConfig,
+                   const AudioPortConfig& sinkPortConfig)
+        : mInitialPatch(patch.mPatch),
+          mSrcPortConfig(srcPortConfig),
+          mSinkPortConfig(sinkPortConfig),
+          mModule(patch.mModule),
+          mPatch(patch.mPatch) {}
     WithAudioPatch(const WithAudioPatch&) = delete;
     WithAudioPatch& operator=(const WithAudioPatch&) = delete;
     ~WithAudioPatch() {
         if (mModule != nullptr && mPatch.id != 0) {
-            EXPECT_IS_OK(mModule->resetAudioPatch(mPatch.id)) << "patch id " << getId();
+            if (mInitialPatch.has_value()) {
+                AudioPatch ignored;
+                // This releases our port configs so that they can be reset.
+                EXPECT_IS_OK(mModule->setAudioPatch(*mInitialPatch, &ignored))
+                        << "patch id " << mInitialPatch->id;
+            } else {
+                EXPECT_IS_OK(mModule->resetAudioPatch(mPatch.id)) << "patch id " << getId();
+            }
         }
     }
     void SetUpPortConfigs(IModule* module) {
@@ -1233,8 +1306,21 @@
             EXPECT_GT(latencyMs, 0) << "patch id " << getId();
         }
     }
+    void VerifyAgainstAllPatches(IModule* module) {
+        std::vector<AudioPatch> allPatches;
+        ASSERT_IS_OK(module->getAudioPatches(&allPatches));
+        const auto& patchIt = findById(allPatches, getId());
+        ASSERT_NE(patchIt, allPatches.end()) << "patch id " << getId();
+        if (get() != *patchIt) {
+            FAIL() << "Stored patch: " << get().toString() << " is not the same as returned "
+                   << "by the HAL module: " << patchIt->toString();
+        }
+    }
     int32_t getId() const { return mPatch.id; }
     const AudioPatch& get() const { return mPatch; }
+    int32_t getMinimumStreamBufferSizeFrames() const {
+        return mPatch.minimumStreamBufferSizeFrames;
+    }
     const AudioPortConfig& getSinkPortConfig() const { return mSinkPortConfig.get(); }
     const AudioPortConfig& getSrcPortConfig() const { return mSrcPortConfig.get(); }
     const AudioPortConfig& getPortConfig(bool getSink) const {
@@ -1242,6 +1328,7 @@
     }
 
   private:
+    std::optional<AudioPatch> mInitialPatch;
     WithAudioPortConfig mSrcPortConfig;
     WithAudioPortConfig mSinkPortConfig;
     IModule* mModule = nullptr;
@@ -1266,11 +1353,8 @@
     ASSERT_IS_OK(module->getAudioPorts(&ports1));
     std::vector<AudioPort> ports2;
     ASSERT_IS_OK(module->getAudioPorts(&ports2));
-    ASSERT_EQ(ports1.size(), ports2.size())
-            << "Sizes of audio port arrays do not match across consequent calls to getAudioPorts";
-    std::sort(ports1.begin(), ports1.end());
-    std::sort(ports2.begin(), ports2.end());
-    EXPECT_EQ(ports1, ports2);
+    EXPECT_NO_FATAL_FAILURE(VerifyVectorsAreEqual<AudioPort>(ports1, ports2))
+            << "Audio port arrays do not match across consequent calls to getAudioPorts";
 }
 
 TEST_P(AudioCoreModule, GetAudioRoutesIsStable) {
@@ -1278,11 +1362,8 @@
     ASSERT_IS_OK(module->getAudioRoutes(&routes1));
     std::vector<AudioRoute> routes2;
     ASSERT_IS_OK(module->getAudioRoutes(&routes2));
-    ASSERT_EQ(routes1.size(), routes2.size())
-            << "Sizes of audio route arrays do not match across consequent calls to getAudioRoutes";
-    std::sort(routes1.begin(), routes1.end());
-    std::sort(routes2.begin(), routes2.end());
-    EXPECT_EQ(routes1, routes2);
+    EXPECT_NO_FATAL_FAILURE(VerifyVectorsAreEqual<AudioRoute>(routes1, routes2))
+            << " Audio route arrays do not match across consequent calls to getAudioRoutes";
 }
 
 TEST_P(AudioCoreModule, GetAudioRoutesAreValid) {
@@ -1451,8 +1532,25 @@
                 << "port ID " << connectedPortId;
         EXPECT_EQ(portConnected.get(), connectedPort);
         const auto& portProfiles = connectedPort.profiles;
-        EXPECT_NE(0UL, portProfiles.size())
-                << "Connected port has no profiles: " << connectedPort.toString();
+        if (portProfiles.empty()) {
+            const auto routableMixPorts = moduleConfig->getRoutableMixPortsForDevicePort(
+                    connectedPort, true /*connectedOnly*/);
+            bool hasMixPortWithStaticProfile = false;
+            for (const auto& mixPort : routableMixPorts) {
+                const auto& mixPortProfiles = mixPort.profiles;
+                if (!mixPortProfiles.empty() &&
+                    !std::all_of(mixPortProfiles.begin(), mixPortProfiles.end(),
+                                 [](const auto& profile) {
+                                     return profile.format.type == AudioFormatType::DEFAULT;
+                                 })) {
+                    hasMixPortWithStaticProfile = true;
+                    break;
+                }
+            }
+            EXPECT_TRUE(hasMixPortWithStaticProfile)
+                    << "Connected port has no profiles and no routable mix ports with profiles: "
+                    << connectedPort.toString();
+        }
         const auto dynamicProfileIt =
                 std::find_if(portProfiles.begin(), portProfiles.end(), [](const auto& profile) {
                     return profile.format.type == AudioFormatType::DEFAULT;
@@ -1477,7 +1575,7 @@
         {
             aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
             args.portConfigId = portConfigId;
-            args.bufferSizeFrames = kDefaultBufferSizeFrames;
+            args.bufferSizeFrames = kNegativeTestBufferSizeFrames;
             aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn ret;
             EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->openInputStream(args, &ret))
                     << "port config ID " << portConfigId;
@@ -1486,7 +1584,7 @@
         {
             aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
             args.portConfigId = portConfigId;
-            args.bufferSizeFrames = kDefaultBufferSizeFrames;
+            args.bufferSizeFrames = kNegativeTestBufferSizeFrames;
             aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
             EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->openOutputStream(args, &ret))
                     << "port config ID " << portConfigId;
@@ -1536,7 +1634,8 @@
         EXPECT_NE(portConfigsAfter.end(), afterIt)
                 << " port config ID " << c.id << " was removed by reset";
         if (afterIt != portConfigsAfter.end()) {
-            EXPECT_EQ(c, *afterIt);
+            EXPECT_TRUE(c == *afterIt)
+                    << "Expected: " << c.toString() << "; Actual: " << afterIt->toString();
         }
     }
 }
@@ -1648,10 +1747,17 @@
     doNotSimulateConnections.flags().simulateDeviceConnections = false;
     ASSERT_NO_FATAL_FAILURE(doNotSimulateConnections.SetUp(module.get()));
     for (const auto& port : ports) {
+        // Virtual devices may not require external hardware and thus can always be connected.
+        if (port.ext.get<AudioPortExt::device>().device.type.connection ==
+            AudioDeviceDescription::CONNECTION_VIRTUAL)
+            continue;
         AudioPort portWithData = GenerateUniqueDeviceAddress(port), connectedPort;
         ScopedAStatus status = module->connectExternalDevice(portWithData, &connectedPort);
         EXPECT_STATUS(EX_ILLEGAL_STATE, status) << "static port " << portWithData.toString();
         if (status.isOk()) {
+            EXPECT_IS_OK_OR_UNKNOWN_TRANSACTION(
+                    module->prepareToDisconnectExternalDevice(connectedPort.id))
+                    << "when preparing to disconnect device port ID " << connectedPort.id;
             EXPECT_IS_OK(module->disconnectExternalDevice(connectedPort.id))
                     << "when disconnecting device port ID " << connectedPort.id;
         }
@@ -1681,6 +1787,9 @@
         invalidPort.id = portId;
         EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->connectExternalDevice(invalidPort, &ignored))
                 << "port ID " << portId << ", when setting CONNECTED state";
+        EXPECT_STATUS_OR_UNKNOWN_TRANSACTION(EX_ILLEGAL_ARGUMENT,
+                                             module->prepareToDisconnectExternalDevice(portId))
+                << "port ID " << portId << ", when preparing to disconnect";
         EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(portId))
                 << "port ID " << portId << ", when setting DISCONNECTED state";
     }
@@ -1691,6 +1800,9 @@
         if (port.ext.getTag() != AudioPortExt::Tag::device) {
             EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->connectExternalDevice(port, &ignored))
                     << "non-device port ID " << port.id << " when setting CONNECTED state";
+            EXPECT_STATUS_OR_UNKNOWN_TRANSACTION(EX_ILLEGAL_ARGUMENT,
+                                                 module->prepareToDisconnectExternalDevice(port.id))
+                    << "non-device port ID " << port.id << " when preparing to disconnect";
             EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(port.id))
                     << "non-device port ID " << port.id << " when setting DISCONNECTED state";
         } else {
@@ -1699,6 +1811,10 @@
                 EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->connectExternalDevice(port, &ignored))
                         << "for a permanently attached device port ID " << port.id
                         << " when setting CONNECTED state";
+                EXPECT_STATUS_OR_UNKNOWN_TRANSACTION(
+                        EX_ILLEGAL_ARGUMENT, module->prepareToDisconnectExternalDevice(port.id))
+                        << "for a permanently attached device port ID " << port.id
+                        << " when preparing to disconnect";
                 EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(port.id))
                         << "for a permanently attached device port ID " << port.id
                         << " when setting DISCONNECTED state";
@@ -1716,6 +1832,9 @@
         GTEST_SKIP() << "No external devices in the module.";
     }
     for (const auto& port : ports) {
+        EXPECT_STATUS_OR_UNKNOWN_TRANSACTION(EX_ILLEGAL_ARGUMENT,
+                                             module->prepareToDisconnectExternalDevice(port.id))
+                << "when preparing to disconnect already disconnected device port ID " << port.id;
         EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(port.id))
                 << "when disconnecting already disconnected device port ID " << port.id;
         AudioPort portWithData = GenerateUniqueDeviceAddress(port);
@@ -1750,6 +1869,10 @@
             // Our test assumes that 'getAudioPort' returns at least one profile, and it
             // is not a dynamic profile.
             ASSERT_NO_FATAL_FAILURE(config.SetUp(module.get()));
+            EXPECT_IS_OK_OR_UNKNOWN_TRANSACTION(
+                    module->prepareToDisconnectExternalDevice(portConnected.getId()))
+                    << "when preparing to disconnect device port ID " << port.id
+                    << " with active configuration " << config.getId();
             EXPECT_STATUS(EX_ILLEGAL_STATE, module->disconnectExternalDevice(portConnected.getId()))
                     << "when trying to disconnect device port ID " << port.id
                     << " with active configuration " << config.getId();
@@ -1800,39 +1923,151 @@
     }
 }
 
+class RoutedPortsProfilesSnapshot {
+  public:
+    explicit RoutedPortsProfilesSnapshot(int32_t portId) : mPortId(portId) {}
+    void Capture(IModule* module) {
+        std::vector<AudioRoute> routes;
+        ASSERT_IS_OK(module->getAudioRoutesForAudioPort(mPortId, &routes));
+        std::vector<AudioPort> allPorts;
+        ASSERT_IS_OK(module->getAudioPorts(&allPorts));
+        ASSERT_NO_FATAL_FAILURE(GetAllRoutedPorts(routes, allPorts));
+        ASSERT_NO_FATAL_FAILURE(GetProfileSizes());
+    }
+    void VerifyNoProfilesChanges(const RoutedPortsProfilesSnapshot& before) {
+        for (const auto& p : before.mRoutedPorts) {
+            auto beforeIt = before.mPortProfileSizes.find(p.id);
+            ASSERT_NE(beforeIt, before.mPortProfileSizes.end())
+                    << "port ID " << p.id << " not found in the initial profile sizes";
+            EXPECT_EQ(beforeIt->second, mPortProfileSizes[p.id])
+                    << " port " << p.toString() << " has an unexpected profile size change"
+                    << " following an external device connection and disconnection";
+        }
+    }
+    void VerifyProfilesNonEmpty() {
+        for (const auto& p : mRoutedPorts) {
+            EXPECT_NE(0UL, mPortProfileSizes[p.id])
+                    << " port " << p.toString() << " must have had its profiles"
+                    << " populated while having a connected external device";
+        }
+    }
+
+    const std::vector<AudioPort>& getRoutedPorts() const { return mRoutedPorts; }
+
+  private:
+    void GetAllRoutedPorts(const std::vector<AudioRoute>& routes,
+                           std::vector<AudioPort>& allPorts) {
+        for (const auto& r : routes) {
+            if (r.sinkPortId == mPortId) {
+                for (const auto& srcPortId : r.sourcePortIds) {
+                    const auto srcPortIt = findById(allPorts, srcPortId);
+                    ASSERT_NE(allPorts.end(), srcPortIt) << "port ID " << srcPortId;
+                    mRoutedPorts.push_back(*srcPortIt);
+                }
+            } else {
+                const auto sinkPortIt = findById(allPorts, r.sinkPortId);
+                ASSERT_NE(allPorts.end(), sinkPortIt) << "port ID " << r.sinkPortId;
+                mRoutedPorts.push_back(*sinkPortIt);
+            }
+        }
+    }
+    void GetProfileSizes() {
+        std::transform(
+                mRoutedPorts.begin(), mRoutedPorts.end(),
+                std::inserter(mPortProfileSizes, mPortProfileSizes.end()),
+                [](const auto& port) { return std::make_pair(port.id, port.profiles.size()); });
+    }
+
+    const int32_t mPortId;
+    std::vector<AudioPort> mRoutedPorts;
+    std::map<int32_t, size_t> mPortProfileSizes;
+};
+
 // Note: This test relies on simulation of external device connections by the HAL module.
 TEST_P(AudioCoreModule, ExternalDeviceMixPortConfigs) {
     // After an external device has been connected, all mix ports that can be routed
     // to the device port for the connected device must have non-empty profiles.
+    // Since the test connects and disconnects a single device each time, the size
+    // of profiles for all mix ports routed to the device port under test must get back
+    // to the original count once the external device is disconnected.
     ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
     std::vector<AudioPort> externalDevicePorts = moduleConfig->getExternalDevicePorts();
     if (externalDevicePorts.empty()) {
         GTEST_SKIP() << "No external devices in the module.";
     }
     for (const auto& port : externalDevicePorts) {
-        WithDevicePortConnectedState portConnected(GenerateUniqueDeviceAddress(port));
-        ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get(), moduleConfig.get()));
-        std::vector<AudioRoute> routes;
-        ASSERT_IS_OK(module->getAudioRoutesForAudioPort(portConnected.getId(), &routes));
-        std::vector<AudioPort> allPorts;
-        ASSERT_IS_OK(module->getAudioPorts(&allPorts));
-        for (const auto& r : routes) {
-            if (r.sinkPortId == portConnected.getId()) {
-                for (const auto& srcPortId : r.sourcePortIds) {
-                    const auto srcPortIt = findById(allPorts, srcPortId);
-                    ASSERT_NE(allPorts.end(), srcPortIt) << "port ID " << srcPortId;
-                    EXPECT_NE(0UL, srcPortIt->profiles.size())
-                            << " source port " << srcPortIt->toString() << " must have its profiles"
-                            << " populated following external device connection";
-                }
-            } else {
-                const auto sinkPortIt = findById(allPorts, r.sinkPortId);
-                ASSERT_NE(allPorts.end(), sinkPortIt) << "port ID " << r.sinkPortId;
-                EXPECT_NE(0UL, sinkPortIt->profiles.size())
-                        << " source port " << sinkPortIt->toString() << " must have its"
-                        << " profiles populated following external device connection";
+        SCOPED_TRACE(port.toString());
+        RoutedPortsProfilesSnapshot before(port.id);
+        ASSERT_NO_FATAL_FAILURE(before.Capture(module.get()));
+        if (before.getRoutedPorts().empty()) continue;
+        {
+            WithDevicePortConnectedState portConnected(GenerateUniqueDeviceAddress(port));
+            ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get(), moduleConfig.get()));
+            RoutedPortsProfilesSnapshot connected(portConnected.getId());
+            ASSERT_NO_FATAL_FAILURE(connected.Capture(module.get()));
+            EXPECT_NO_FATAL_FAILURE(connected.VerifyProfilesNonEmpty());
+        }
+        RoutedPortsProfilesSnapshot after(port.id);
+        ASSERT_NO_FATAL_FAILURE(after.Capture(module.get()));
+        EXPECT_NO_FATAL_FAILURE(after.VerifyNoProfilesChanges(before));
+    }
+}
+
+// Note: This test relies on simulation of external device connections by the HAL module.
+TEST_P(AudioCoreModule, TwoExternalDevicesMixPortConfigsNested) {
+    // Ensure that in the case when two external devices are connected to the same
+    // device port, disconnecting one of them does not erase the profiles of routed mix ports.
+    // In this scenario, the connections are "nested."
+    ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+    std::vector<AudioPort> externalDevicePorts = moduleConfig->getExternalDevicePorts();
+    if (externalDevicePorts.empty()) {
+        GTEST_SKIP() << "No external devices in the module.";
+    }
+    for (const auto& port : externalDevicePorts) {
+        SCOPED_TRACE(port.toString());
+        WithDevicePortConnectedState portConnected1(GenerateUniqueDeviceAddress(port));
+        ASSERT_NO_FATAL_FAILURE(portConnected1.SetUp(module.get(), moduleConfig.get()));
+        {
+            // Connect and disconnect another device, if possible. It might not be possible
+            // for point-to-point connections, like analog or SPDIF.
+            WithDevicePortConnectedState portConnected2(GenerateUniqueDeviceAddress(port));
+            if (auto status = portConnected2.SetUpNoChecks(module.get(), moduleConfig.get());
+                !status.isOk()) {
+                continue;
             }
         }
+        RoutedPortsProfilesSnapshot connected(portConnected1.getId());
+        ASSERT_NO_FATAL_FAILURE(connected.Capture(module.get()));
+        EXPECT_NO_FATAL_FAILURE(connected.VerifyProfilesNonEmpty());
+    }
+}
+
+// Note: This test relies on simulation of external device connections by the HAL module.
+TEST_P(AudioCoreModule, TwoExternalDevicesMixPortConfigsInterleaved) {
+    // Ensure that in the case when two external devices are connected to the same
+    // device port, disconnecting one of them does not erase the profiles of routed mix ports.
+    // In this scenario, the connections are "interleaved."
+    ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+    std::vector<AudioPort> externalDevicePorts = moduleConfig->getExternalDevicePorts();
+    if (externalDevicePorts.empty()) {
+        GTEST_SKIP() << "No external devices in the module.";
+    }
+    for (const auto& port : externalDevicePorts) {
+        SCOPED_TRACE(port.toString());
+        auto portConnected1 =
+                std::make_unique<WithDevicePortConnectedState>(GenerateUniqueDeviceAddress(port));
+        ASSERT_NO_FATAL_FAILURE(portConnected1->SetUp(module.get(), moduleConfig.get()));
+        WithDevicePortConnectedState portConnected2(GenerateUniqueDeviceAddress(port));
+        // Connect another device, if possible. It might not be possible for point-to-point
+        // connections, like analog or SPDIF.
+        if (auto status = portConnected2.SetUpNoChecks(module.get(), moduleConfig.get());
+            !status.isOk()) {
+            continue;
+        }
+        portConnected1.reset();
+        RoutedPortsProfilesSnapshot connected(portConnected2.getId());
+        ASSERT_NO_FATAL_FAILURE(connected.Capture(module.get()));
+        EXPECT_NO_FATAL_FAILURE(connected.VerifyProfilesNonEmpty());
     }
 }
 
@@ -1997,7 +2232,13 @@
         std::vector<AudioMMapPolicyInfo> policyInfos;
         EXPECT_IS_OK(module->getMmapPolicyInfos(mmapPolicyType, &policyInfos))
                 << toString(mmapPolicyType);
-        EXPECT_EQ(isMmapSupported, !policyInfos.empty());
+        const bool isMMapSupportedByPolicyInfos =
+                std::find_if(policyInfos.begin(), policyInfos.end(), [](const auto& info) {
+                    return info.mmapPolicy == AudioMMapPolicy::AUTO ||
+                           info.mmapPolicy == AudioMMapPolicy::ALWAYS;
+                }) != policyInfos.end();
+        EXPECT_EQ(isMmapSupported, isMMapSupportedByPolicyInfos)
+                << ::android::internal::ToString(policyInfos);
     }
 }
 
@@ -2376,6 +2617,260 @@
     std::vector<std::string> mStatuses;
 };
 
+// A helper which sets up necessary HAL structures for a proper stream initialization.
+//
+// The full sequence of actions to set up a stream is as follows:
+//
+//  device port -> connect if necessary -> set up port config   | -> set up patch
+//  mix port -> set up port config, unless it has been provided |
+//
+//  then, from the patch, figure out the minimum HAL buffer size -> set up stream
+//
+// This sequence is reflected in the order of fields declaration.
+// Various tests need to be able to start and stop at various point in this sequence,
+// this is why there are methods that do just part of the work.
+//
+// Note: To maximize test coverage, this class relies on simulation of external device
+// connections by the HAL module.
+template <typename Stream>
+class StreamFixture {
+  public:
+    // Tests might need to override the direction.
+    StreamFixture(bool isInput = IOTraits<Stream>::is_input) : mIsInput(isInput) {}
+
+    void SetUpPortConfigAnyMixPort(IModule* module, ModuleConfig* moduleConfig,
+                                   bool connectedOnly) {
+        const auto mixPorts = moduleConfig->getMixPorts(mIsInput, connectedOnly);
+        mSkipTestReason = "No mix ports";
+        for (const auto& mixPort : mixPorts) {
+            mSkipTestReason = "";
+            ASSERT_NO_FATAL_FAILURE(SetUpPortConfigForMixPortOrConfig(module, moduleConfig, mixPort,
+                                                                      connectedOnly));
+            if (mSkipTestReason.empty()) break;
+        }
+    }
+
+    void SetUpPortConfigForMixPortOrConfig(
+            IModule* module, ModuleConfig* moduleConfig, const AudioPort& initialMixPort,
+            bool connectedOnly, const std::optional<AudioPortConfig>& mixPortConfig = {}) {
+        if (mixPortConfig.has_value() && !connectedOnly) {
+            // Connecting an external device may cause change in mix port profiles and the provided
+            // config may become invalid.
+            LOG(FATAL) << __func__ << ": when specifying a mix port config, it is not allowed "
+                       << "to change connected devices, thus `connectedOnly` must be `true`";
+        }
+        std::optional<AudioPort> connectedDevicePort;
+        ASSERT_NO_FATAL_FAILURE(SetUpDevicePortForMixPort(module, moduleConfig, initialMixPort,
+                                                          connectedOnly, &connectedDevicePort));
+        if (!mSkipTestReason.empty()) return;
+        if (mixPortConfig.has_value()) {
+            ASSERT_NO_FATAL_FAILURE(
+                    SetUpPortConfig(module, moduleConfig, *mixPortConfig, *connectedDevicePort));
+        } else {
+            // If an external device was connected, the profiles of the mix port might have changed.
+            AudioPort mixPort;
+            ASSERT_NO_FATAL_FAILURE(module->getAudioPort(initialMixPort.id, &mixPort));
+            ASSERT_NO_FATAL_FAILURE(
+                    SetUpPortConfig(module, moduleConfig, mixPort, *connectedDevicePort));
+        }
+    }
+
+    void SetUpPortConfig(IModule* module, ModuleConfig* moduleConfig, const AudioPort& mixPort,
+                         const AudioPort& devicePort) {
+        auto mixPortConfig = moduleConfig->getSingleConfigForMixPort(mIsInput, mixPort);
+        ASSERT_TRUE(mixPortConfig.has_value())
+                << "Unable to generate port config for mix port " << mixPort.toString();
+        ASSERT_NO_FATAL_FAILURE(SetUpPortConfig(module, moduleConfig, *mixPortConfig, devicePort));
+    }
+    void SetUpPortConfig(IModule* module, ModuleConfig* moduleConfig,
+                         const AudioPortConfig& mixPortConfig, const AudioPort& devicePort) {
+        ASSERT_NO_FATAL_FAILURE(SetUpPatch(module, moduleConfig, mixPortConfig, devicePort));
+        mStream = std::make_unique<WithStream<Stream>>(mMixPortConfig->get());
+        ASSERT_NO_FATAL_FAILURE(mStream->SetUpPortConfig(module));
+    }
+
+    ScopedAStatus SetUpStreamNoChecks(IModule* module) {
+        return mStream->SetUpNoChecks(module, getMinimumStreamBufferSizeFrames());
+    }
+    void SetUpStream(IModule* module) {
+        ASSERT_NO_FATAL_FAILURE(mStream->SetUpStream(module, getMinimumStreamBufferSizeFrames()));
+    }
+
+    void SetUpStreamForDevicePort(IModule* module, ModuleConfig* moduleConfig,
+                                  const AudioPort& devicePort, bool connectedOnly = false) {
+        ASSERT_NO_FATAL_FAILURE(
+                SetUpPortConfigForDevicePort(module, moduleConfig, devicePort, connectedOnly));
+        if (!mSkipTestReason.empty()) return;
+        ASSERT_NO_FATAL_FAILURE(SetUpStream(module));
+    }
+    void SetUpStreamForAnyMixPort(IModule* module, ModuleConfig* moduleConfig,
+                                  bool connectedOnly = false) {
+        ASSERT_NO_FATAL_FAILURE(SetUpPortConfigAnyMixPort(module, moduleConfig, connectedOnly));
+        if (!mSkipTestReason.empty()) return;
+        ASSERT_NO_FATAL_FAILURE(SetUpStream(module));
+    }
+    void SetUpStreamForMixPort(IModule* module, ModuleConfig* moduleConfig,
+                               const AudioPort& mixPort, bool connectedOnly = false) {
+        ASSERT_NO_FATAL_FAILURE(
+                SetUpPortConfigForMixPortOrConfig(module, moduleConfig, mixPort, connectedOnly));
+        if (!mSkipTestReason.empty()) return;
+        ASSERT_NO_FATAL_FAILURE(SetUpStream(module));
+    }
+    void SetUpStreamForPortsPair(IModule* module, ModuleConfig* moduleConfig,
+                                 const AudioPort& mixPort, const AudioPort& devicePort) {
+        ASSERT_NO_FATAL_FAILURE(SetUpPortConfig(module, moduleConfig, mixPort, devicePort));
+        if (!mSkipTestReason.empty()) return;
+        ASSERT_NO_FATAL_FAILURE(SetUpStream(module));
+    }
+    void SetUpStreamForMixPortConfig(IModule* module, ModuleConfig* moduleConfig,
+                                     const AudioPortConfig& mixPortConfig) {
+        // Since mix port configs may change after connecting an external device,
+        // only connected device ports are considered.
+        constexpr bool connectedOnly = true;
+        const auto& ports = moduleConfig->getMixPorts(mIsInput, connectedOnly);
+        const auto mixPortIt = findById<AudioPort>(ports, mixPortConfig.portId);
+        ASSERT_NE(mixPortIt, ports.end()) << "Port id " << mixPortConfig.portId << " not found";
+        ASSERT_NO_FATAL_FAILURE(SetUpPortConfigForMixPortOrConfig(module, moduleConfig, *mixPortIt,
+                                                                  connectedOnly, mixPortConfig));
+        if (!mSkipTestReason.empty()) return;
+        ASSERT_NO_FATAL_FAILURE(SetUpStream(module));
+    }
+    void SetUpPatchForMixPortConfig(IModule* module, ModuleConfig* moduleConfig,
+                                    const AudioPortConfig& mixPortConfig) {
+        constexpr bool connectedOnly = true;
+        const auto& ports = moduleConfig->getMixPorts(mIsInput, connectedOnly);
+        const auto mixPortIt = findById<AudioPort>(ports, mixPortConfig.portId);
+        ASSERT_NE(mixPortIt, ports.end()) << "Port id " << mixPortConfig.portId << " not found";
+        std::optional<AudioPort> connectedDevicePort;
+        ASSERT_NO_FATAL_FAILURE(SetUpDevicePortForMixPort(module, moduleConfig, *mixPortIt,
+                                                          connectedOnly, &connectedDevicePort));
+        if (!mSkipTestReason.empty()) return;
+        ASSERT_NO_FATAL_FAILURE(
+                SetUpPatch(module, moduleConfig, mixPortConfig, *connectedDevicePort));
+    }
+
+    void ReconnectPatch(IModule* module) {
+        mPatch = std::make_unique<WithAudioPatch>(mIsInput, mMixPortConfig->get(),
+                                                  mDevicePortConfig->get());
+        ASSERT_NO_FATAL_FAILURE(mPatch->SetUp(module));
+    }
+    void TeardownPatch() { mPatch.reset(); }
+    // Assuming that the patch is set up, while the stream isn't yet,
+    // tear the patch down and set up stream.
+    void TeardownPatchSetUpStream(IModule* module) {
+        const int32_t bufferSize = getMinimumStreamBufferSizeFrames();
+        ASSERT_NO_FATAL_FAILURE(TeardownPatch());
+        mStream = std::make_unique<WithStream<Stream>>(mMixPortConfig->get());
+        ASSERT_NO_FATAL_FAILURE(mStream->SetUpPortConfig(module));
+        ASSERT_NO_FATAL_FAILURE(mStream->SetUpStream(module, bufferSize));
+    }
+
+    const AudioDevice& getDevice() const { return mDevice; }
+    int32_t getMinimumStreamBufferSizeFrames() const {
+        return mPatch->getMinimumStreamBufferSizeFrames();
+    }
+    const AudioPatch& getPatch() const { return mPatch->get(); }
+    const AudioPortConfig& getPortConfig() const { return mMixPortConfig->get(); }
+    int32_t getPortId() const { return mMixPortConfig->getId(); }
+    Stream* getStream() const { return mStream->get(); }
+    const StreamContext* getStreamContext() const { return mStream->getContext(); }
+    StreamEventReceiver* getStreamEventReceiver() { return mStream->getEventReceiver(); }
+    std::shared_ptr<Stream> getStreamSharedPointer() const { return mStream->getSharedPointer(); }
+    const std::string& skipTestReason() const { return mSkipTestReason; }
+
+  private:
+    void SetUpDevicePort(IModule* module, ModuleConfig* moduleConfig,
+                         const std::set<int32_t>& devicePortIds, bool connectedOnly,
+                         std::optional<AudioPort>* connectedDevicePort) {
+        const auto attachedDevicePorts = moduleConfig->getAttachedDevicePorts();
+        if (auto it = findAny<AudioPort>(attachedDevicePorts, devicePortIds);
+            it != attachedDevicePorts.end()) {
+            *connectedDevicePort = *it;
+            LOG(DEBUG) << __func__ << ": found attached port " << it->toString();
+        }
+        const auto connectedDevicePorts = moduleConfig->getConnectedExternalDevicePorts();
+        if (auto it = findAny<AudioPort>(connectedDevicePorts, devicePortIds);
+            it != connectedDevicePorts.end()) {
+            *connectedDevicePort = *it;
+            LOG(DEBUG) << __func__ << ": found connected port " << it->toString();
+        }
+        if (!connectedOnly && !connectedDevicePort->has_value()) {
+            const auto externalDevicePorts = moduleConfig->getExternalDevicePorts();
+            if (auto it = findAny<AudioPort>(externalDevicePorts, devicePortIds);
+                it != externalDevicePorts.end()) {
+                AudioPort portWithData = GenerateUniqueDeviceAddress(*it);
+                mPortConnected = std::make_unique<WithDevicePortConnectedState>(portWithData);
+                ASSERT_NO_FATAL_FAILURE(mPortConnected->SetUp(module, moduleConfig));
+                *connectedDevicePort = mPortConnected->get();
+                LOG(DEBUG) << __func__ << ": connected port " << mPortConnected->get().toString();
+            }
+        }
+    }
+    void SetUpDevicePortForMixPort(IModule* module, ModuleConfig* moduleConfig,
+                                   const AudioPort& mixPort, bool connectedOnly,
+                                   std::optional<AudioPort>* connectedDevicePort) {
+        const auto devicePorts =
+                moduleConfig->getRoutableDevicePortsForMixPort(mixPort, connectedOnly);
+        if (devicePorts.empty()) {
+            mSkipTestReason = std::string("No routable device ports found for mix port id ")
+                                      .append(std::to_string(mixPort.id));
+            LOG(DEBUG) << __func__ << ": " << mSkipTestReason;
+            return;
+        };
+        ASSERT_NO_FATAL_FAILURE(SetUpDevicePort(module, moduleConfig,
+                                                extractIds<AudioPort>(devicePorts), connectedOnly,
+                                                connectedDevicePort));
+        if (!connectedDevicePort->has_value()) {
+            mSkipTestReason = std::string("Unable to find a device port pair for mix port id ")
+                                      .append(std::to_string(mixPort.id));
+            LOG(DEBUG) << __func__ << ": " << mSkipTestReason;
+            return;
+        }
+    }
+    void SetUpPortConfigForDevicePort(IModule* module, ModuleConfig* moduleConfig,
+                                      const AudioPort& devicePort, bool connectedOnly) {
+        std::optional<AudioPort> connectedDevicePort;
+        ASSERT_NO_FATAL_FAILURE(SetUpDevicePort(module, moduleConfig, {devicePort.id},
+                                                connectedOnly, &connectedDevicePort));
+        if (!connectedDevicePort.has_value()) {
+            mSkipTestReason = std::string("Device port id ")
+                                      .append(std::to_string(devicePort.id))
+                                      .append(" is not attached and can not be connected");
+            return;
+        }
+        const auto mixPorts = moduleConfig->getRoutableMixPortsForDevicePort(
+                *connectedDevicePort, true /*connectedOnly*/);
+        if (mixPorts.empty()) {
+            mSkipTestReason = std::string("No routable mix ports found for device port id ")
+                                      .append(std::to_string(devicePort.id));
+            return;
+        }
+        ASSERT_NO_FATAL_FAILURE(
+                SetUpPortConfig(module, moduleConfig, *mixPorts.begin(), *connectedDevicePort));
+    }
+    void SetUpPatch(IModule* module, ModuleConfig* moduleConfig,
+                    const AudioPortConfig& mixPortConfig, const AudioPort& devicePort) {
+        mMixPortConfig = std::make_unique<WithAudioPortConfig>(mixPortConfig);
+        ASSERT_NO_FATAL_FAILURE(mMixPortConfig->SetUp(module));
+        mDevicePortConfig = std::make_unique<WithAudioPortConfig>(
+                moduleConfig->getSingleConfigForDevicePort(devicePort));
+        ASSERT_NO_FATAL_FAILURE(mDevicePortConfig->SetUp(module));
+        mDevice = devicePort.ext.get<AudioPortExt::device>().device;
+        mPatch = std::make_unique<WithAudioPatch>(mIsInput, mMixPortConfig->get(),
+                                                  mDevicePortConfig->get());
+        ASSERT_NO_FATAL_FAILURE(mPatch->SetUp(module));
+    }
+
+    const bool mIsInput;
+    std::string mSkipTestReason;
+    std::unique_ptr<WithDevicePortConnectedState> mPortConnected;
+    AudioDevice mDevice;
+    std::unique_ptr<WithAudioPortConfig> mMixPortConfig;
+    std::unique_ptr<WithAudioPortConfig> mDevicePortConfig;
+    std::unique_ptr<WithAudioPatch> mPatch;
+    std::unique_ptr<WithStream<Stream>> mStream;
+};
+
 template <typename Stream>
 class AudioStream : public AudioCoreModule {
   public:
@@ -2385,16 +2880,15 @@
     }
 
     void GetStreamCommon() {
-        const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
-        if (!portConfig.has_value()) {
-            GTEST_SKIP() << "No mix port for attached devices";
+        StreamFixture<Stream> stream;
+        ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForAnyMixPort(module.get(), moduleConfig.get()));
+        if (auto reason = stream.skipTestReason(); !reason.empty()) {
+            GTEST_SKIP() << reason;
         }
-        WithStream<Stream> stream(portConfig.value());
-        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
         std::shared_ptr<IStreamCommon> streamCommon1;
-        EXPECT_IS_OK(stream.get()->getStreamCommon(&streamCommon1));
+        EXPECT_IS_OK(stream.getStream()->getStreamCommon(&streamCommon1));
         std::shared_ptr<IStreamCommon> streamCommon2;
-        EXPECT_IS_OK(stream.get()->getStreamCommon(&streamCommon2));
+        EXPECT_IS_OK(stream.getStream()->getStreamCommon(&streamCommon2));
         ASSERT_NE(nullptr, streamCommon1);
         ASSERT_NE(nullptr, streamCommon2);
         EXPECT_EQ(streamCommon1->asBinder(), streamCommon2->asBinder())
@@ -2402,31 +2896,31 @@
     }
 
     void CloseTwice() {
-        const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
-        if (!portConfig.has_value()) {
-            GTEST_SKIP() << "No mix port for attached devices";
-        }
         std::shared_ptr<Stream> heldStream;
         {
-            WithStream<Stream> stream(portConfig.value());
-            ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
-            heldStream = stream.getSharedPointer();
+            StreamFixture<Stream> stream;
+            ASSERT_NO_FATAL_FAILURE(
+                    stream.SetUpStreamForAnyMixPort(module.get(), moduleConfig.get()));
+            if (auto reason = stream.skipTestReason(); !reason.empty()) {
+                GTEST_SKIP() << reason;
+            }
+            heldStream = stream.getStreamSharedPointer();
         }
         EXPECT_STATUS(EX_ILLEGAL_STATE, WithStream<Stream>::callClose(heldStream))
                 << "when closing the stream twice";
     }
 
     void PrepareToCloseTwice() {
-        const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
-        if (!portConfig.has_value()) {
-            GTEST_SKIP() << "No mix port for attached devices";
-        }
         std::shared_ptr<IStreamCommon> heldStreamCommon;
         {
-            WithStream<Stream> stream(portConfig.value());
-            ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+            StreamFixture<Stream> stream;
+            ASSERT_NO_FATAL_FAILURE(
+                    stream.SetUpStreamForAnyMixPort(module.get(), moduleConfig.get()));
+            if (auto reason = stream.skipTestReason(); !reason.empty()) {
+                GTEST_SKIP() << reason;
+            }
             std::shared_ptr<IStreamCommon> streamCommon;
-            ASSERT_IS_OK(stream.get()->getStreamCommon(&streamCommon));
+            ASSERT_IS_OK(stream.getStream()->getStreamCommon(&streamCommon));
             heldStreamCommon = streamCommon;
             EXPECT_IS_OK(streamCommon->prepareToClose());
             EXPECT_IS_OK(streamCommon->prepareToClose())
@@ -2439,9 +2933,13 @@
     void OpenAllConfigs() {
         const auto allPortConfigs =
                 moduleConfig->getPortConfigsForMixPorts(IOTraits<Stream>::is_input);
+        if (allPortConfigs.empty()) {
+            GTEST_SKIP() << "No mix ports for attached devices";
+        }
         for (const auto& portConfig : allPortConfigs) {
-            WithStream<Stream> stream(portConfig);
-            ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+            StreamFixture<Stream> stream;
+            ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForMixPortConfig(
+                    module.get(), moduleConfig.get(), portConfig));
         }
     }
 
@@ -2461,22 +2959,21 @@
 
     void OpenInvalidDirection() {
         // Important! The direction of the port config must be reversed.
-        const auto portConfig =
-                moduleConfig->getSingleConfigForMixPort(!IOTraits<Stream>::is_input);
-        if (!portConfig.has_value()) {
-            GTEST_SKIP() << "No mix port for attached devices";
+        StreamFixture<Stream> stream(!IOTraits<Stream>::is_input);
+        ASSERT_NO_FATAL_FAILURE(stream.SetUpPortConfigAnyMixPort(module.get(), moduleConfig.get(),
+                                                                 false /*connectedOnly*/));
+        if (auto reason = stream.skipTestReason(); !reason.empty()) {
+            GTEST_SKIP() << reason;
         }
-        WithStream<Stream> stream(portConfig.value());
-        ASSERT_NO_FATAL_FAILURE(stream.SetUpPortConfig(module.get()));
-        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
-                      stream.SetUpNoChecks(module.get(), kDefaultBufferSizeFrames))
+        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, stream.SetUpStreamNoChecks(module.get()))
                 << "port config ID " << stream.getPortId();
-        EXPECT_EQ(nullptr, stream.get());
+        EXPECT_EQ(nullptr, stream.getStream());
     }
 
     void OpenOverMaxCount() {
+        constexpr bool connectedOnly = true;
         constexpr bool isInput = IOTraits<Stream>::is_input;
-        auto ports = moduleConfig->getMixPorts(isInput, true /*connectedOnly*/);
+        auto ports = moduleConfig->getMixPorts(isInput, connectedOnly);
         bool hasSingleRun = false;
         for (const auto& port : ports) {
             const size_t maxStreamCount = port.ext.get<AudioPortExt::Tag::mix>().maxOpenStreamCount;
@@ -2489,16 +2986,16 @@
                 continue;
             }
             hasSingleRun = true;
-            std::optional<WithStream<Stream>> streamWraps[maxStreamCount + 1];
+            StreamFixture<Stream> streams[maxStreamCount + 1];
             for (size_t i = 0; i <= maxStreamCount; ++i) {
-                streamWraps[i].emplace(portConfigs[i]);
-                WithStream<Stream>& stream = streamWraps[i].value();
+                ASSERT_NO_FATAL_FAILURE(streams[i].SetUpPortConfigForMixPortOrConfig(
+                        module.get(), moduleConfig.get(), port, connectedOnly, portConfigs[i]));
+                ASSERT_EQ("", streams[i].skipTestReason());
+                auto& stream = streams[i];
                 if (i < maxStreamCount) {
-                    ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+                    ASSERT_NO_FATAL_FAILURE(stream.SetUpStream(module.get()));
                 } else {
-                    ASSERT_NO_FATAL_FAILURE(stream.SetUpPortConfig(module.get()));
-                    EXPECT_STATUS(EX_ILLEGAL_STATE,
-                                  stream.SetUpNoChecks(module.get(), kDefaultBufferSizeFrames))
+                    EXPECT_STATUS(EX_ILLEGAL_STATE, stream.SetUpStreamNoChecks(module.get()))
                             << "port config ID " << stream.getPortId() << ", maxOpenStreamCount is "
                             << maxStreamCount;
                 }
@@ -2518,12 +3015,11 @@
     }
 
     void ResetPortConfigWithOpenStream() {
-        const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
-        if (!portConfig.has_value()) {
-            GTEST_SKIP() << "No mix port for attached devices";
+        StreamFixture<Stream> stream;
+        ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForAnyMixPort(module.get(), moduleConfig.get()));
+        if (auto reason = stream.skipTestReason(); !reason.empty()) {
+            GTEST_SKIP() << reason;
         }
-        WithStream<Stream> stream(portConfig.value());
-        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
         EXPECT_STATUS(EX_ILLEGAL_STATE, module->resetAudioPortConfig(stream.getPortId()))
                 << "port config ID " << stream.getPortId();
     }
@@ -2537,14 +3033,13 @@
     }
 
     void UpdateHwAvSyncId() {
-        const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
-        if (!portConfig.has_value()) {
-            GTEST_SKIP() << "No mix port for attached devices";
+        StreamFixture<Stream> stream;
+        ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForAnyMixPort(module.get(), moduleConfig.get()));
+        if (auto reason = stream.skipTestReason(); !reason.empty()) {
+            GTEST_SKIP() << reason;
         }
-        WithStream<Stream> stream(portConfig.value());
-        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
         std::shared_ptr<IStreamCommon> streamCommon;
-        ASSERT_IS_OK(stream.get()->getStreamCommon(&streamCommon));
+        ASSERT_IS_OK(stream.getStream()->getStreamCommon(&streamCommon));
         ASSERT_NE(nullptr, streamCommon);
         const auto kStatuses = {EX_NONE, EX_ILLEGAL_ARGUMENT, EX_ILLEGAL_STATE};
         for (const auto id : {-100, -1, 0, 1, 100}) {
@@ -2557,14 +3052,13 @@
     }
 
     void GetVendorParameters() {
-        const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
-        if (!portConfig.has_value()) {
-            GTEST_SKIP() << "No mix port for attached devices";
+        StreamFixture<Stream> stream;
+        ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForAnyMixPort(module.get(), moduleConfig.get()));
+        if (auto reason = stream.skipTestReason(); !reason.empty()) {
+            GTEST_SKIP() << reason;
         }
-        WithStream<Stream> stream(portConfig.value());
-        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
         std::shared_ptr<IStreamCommon> streamCommon;
-        ASSERT_IS_OK(stream.get()->getStreamCommon(&streamCommon));
+        ASSERT_IS_OK(stream.getStream()->getStreamCommon(&streamCommon));
         ASSERT_NE(nullptr, streamCommon);
 
         bool isGetterSupported = false;
@@ -2578,14 +3072,13 @@
     }
 
     void SetVendorParameters() {
-        const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
-        if (!portConfig.has_value()) {
-            GTEST_SKIP() << "No mix port for attached devices";
+        StreamFixture<Stream> stream;
+        ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForAnyMixPort(module.get(), moduleConfig.get()));
+        if (auto reason = stream.skipTestReason(); !reason.empty()) {
+            GTEST_SKIP() << reason;
         }
-        WithStream<Stream> stream(portConfig.value());
-        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
         std::shared_ptr<IStreamCommon> streamCommon;
-        ASSERT_IS_OK(stream.get()->getStreamCommon(&streamCommon));
+        ASSERT_IS_OK(stream.getStream()->getStreamCommon(&streamCommon));
         ASSERT_NE(nullptr, streamCommon);
 
         bool isSupported = false;
@@ -2596,32 +3089,37 @@
     }
 
     void HwGainHwVolume() {
-        const auto ports =
-                moduleConfig->getMixPorts(IOTraits<Stream>::is_input, true /*connectedOnly*/);
+        // Since device connection emulation does not cover complete functionality,
+        // only use this test with connected devices.
+        constexpr bool connectedOnly = true;
+        const auto ports = moduleConfig->getMixPorts(IOTraits<Stream>::is_input, connectedOnly);
         if (ports.empty()) {
             GTEST_SKIP() << "No mix ports";
         }
         bool atLeastOneSupports = false;
         for (const auto& port : ports) {
-            const auto portConfig = moduleConfig->getSingleConfigForMixPort(true, port);
-            if (!portConfig.has_value()) continue;
-            WithStream<Stream> stream(portConfig.value());
-            ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+            SCOPED_TRACE(port.toString());
+            StreamFixture<Stream> stream;
+            ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForMixPort(module.get(), moduleConfig.get(),
+                                                                 port, connectedOnly));
+            if (!stream.skipTestReason().empty()) continue;
+            const auto portConfig = stream.getPortConfig();
+            SCOPED_TRACE(portConfig.toString());
             std::vector<std::vector<float>> validValues, invalidValues;
             bool isSupported = false;
             if constexpr (IOTraits<Stream>::is_input) {
-                GenerateTestArrays<float>(getChannelCount(portConfig.value().channelMask.value()),
+                GenerateTestArrays<float>(getChannelCount(portConfig.channelMask.value()),
                                           IStreamIn::HW_GAIN_MIN, IStreamIn::HW_GAIN_MAX,
                                           &validValues, &invalidValues);
                 EXPECT_NO_FATAL_FAILURE(TestAccessors<std::vector<float>>(
-                        stream.get(), &IStreamIn::getHwGain, &IStreamIn::setHwGain, validValues,
-                        invalidValues, &isSupported));
+                        stream.getStream(), &IStreamIn::getHwGain, &IStreamIn::setHwGain,
+                        validValues, invalidValues, &isSupported));
             } else {
-                GenerateTestArrays<float>(getChannelCount(portConfig.value().channelMask.value()),
+                GenerateTestArrays<float>(getChannelCount(portConfig.channelMask.value()),
                                           IStreamOut::HW_VOLUME_MIN, IStreamOut::HW_VOLUME_MAX,
                                           &validValues, &invalidValues);
                 EXPECT_NO_FATAL_FAILURE(TestAccessors<std::vector<float>>(
-                        stream.get(), &IStreamOut::getHwVolume, &IStreamOut::setHwVolume,
+                        stream.getStream(), &IStreamOut::getHwVolume, &IStreamOut::setHwVolume,
                         validValues, invalidValues, &isSupported));
             }
             if (isSupported) atLeastOneSupports = true;
@@ -2635,19 +3133,22 @@
     // currently we can only pass a nullptr, and the HAL module must either reject
     // it as an invalid argument, or say that offloaded effects are not supported.
     void AddRemoveEffectInvalidArguments() {
-        const auto ports =
-                moduleConfig->getMixPorts(IOTraits<Stream>::is_input, true /*connectedOnly*/);
+        constexpr bool connectedOnly = true;
+        const auto ports = moduleConfig->getMixPorts(IOTraits<Stream>::is_input, connectedOnly);
         if (ports.empty()) {
             GTEST_SKIP() << "No mix ports";
         }
         bool atLeastOneSupports = false;
         for (const auto& port : ports) {
-            const auto portConfig = moduleConfig->getSingleConfigForMixPort(true, port);
-            if (!portConfig.has_value()) continue;
-            WithStream<Stream> stream(portConfig.value());
-            ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+            SCOPED_TRACE(port.toString());
+            StreamFixture<Stream> stream;
+            ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForMixPort(module.get(), moduleConfig.get(),
+                                                                 port, connectedOnly));
+            if (!stream.skipTestReason().empty()) continue;
+            const auto portConfig = stream.getPortConfig();
+            SCOPED_TRACE(portConfig.toString());
             std::shared_ptr<IStreamCommon> streamCommon;
-            ASSERT_IS_OK(stream.get()->getStreamCommon(&streamCommon));
+            ASSERT_IS_OK(stream.getStream()->getStreamCommon(&streamCommon));
             ASSERT_NE(nullptr, streamCommon);
             ndk::ScopedAStatus addEffectStatus = streamCommon->addEffect(nullptr);
             ndk::ScopedAStatus removeEffectStatus = streamCommon->removeEffect(nullptr);
@@ -2667,11 +3168,14 @@
     }
 
     void OpenTwiceSamePortConfigImpl(const AudioPortConfig& portConfig) {
-        WithStream<Stream> stream1(portConfig);
-        ASSERT_NO_FATAL_FAILURE(stream1.SetUp(module.get(), kDefaultBufferSizeFrames));
+        StreamFixture<Stream> stream1;
+        ASSERT_NO_FATAL_FAILURE(
+                stream1.SetUpStreamForMixPortConfig(module.get(), moduleConfig.get(), portConfig));
+        ASSERT_EQ("", stream1.skipTestReason());
         WithStream<Stream> stream2;
-        EXPECT_STATUS(EX_ILLEGAL_STATE, stream2.SetUpNoChecks(module.get(), stream1.getPortConfig(),
-                                                              kDefaultBufferSizeFrames))
+        EXPECT_STATUS(EX_ILLEGAL_STATE,
+                      stream2.SetUpNoChecks(module.get(), stream1.getPortConfig(),
+                                            stream1.getMinimumStreamBufferSizeFrames()))
                 << "when opening a stream twice for the same port config ID "
                 << stream1.getPortId();
     }
@@ -2706,11 +3210,13 @@
         for (const auto& seq : sequences) {
             SCOPED_TRACE(std::string("Sequence ").append(seq.first));
             LOG(DEBUG) << __func__ << ": Sequence " << seq.first;
-            WithStream<Stream> stream(portConfig);
-            ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+            StreamFixture<Stream> stream;
+            ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForMixPortConfig(
+                    module.get(), moduleConfig.get(), portConfig));
+            ASSERT_EQ("", stream.skipTestReason());
             StreamLogicDriverInvalidCommand driver(seq.second);
-            typename IOTraits<Stream>::Worker worker(*stream.getContext(), &driver,
-                                                     stream.getEventReceiver());
+            typename IOTraits<Stream>::Worker worker(*stream.getStreamContext(), &driver,
+                                                     stream.getStreamEventReceiver());
             LOG(DEBUG) << __func__ << ": starting worker...";
             ASSERT_TRUE(worker.start());
             LOG(DEBUG) << __func__ << ": joining worker...";
@@ -2763,63 +3269,59 @@
     if (ports.empty()) {
         GTEST_SKIP() << "No input mix ports for attached devices";
     }
+    bool atLeastOnePort = false;
     for (const auto& port : ports) {
-        const auto portConfig = moduleConfig->getSingleConfigForMixPort(true, port);
-        ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for input mix port";
-        WithStream<IStreamIn> stream(portConfig.value());
-        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
-        {
-            // The port of the stream is not connected, thus the list of active mics must be empty.
-            std::vector<MicrophoneDynamicInfo> activeMics;
-            EXPECT_IS_OK(stream.get()->getActiveMicrophones(&activeMics));
-            EXPECT_TRUE(activeMics.empty()) << "a stream on an unconnected port returns a "
-                                               "non-empty list of active microphones";
+        auto micDevicePorts = ModuleConfig::getBuiltInMicPorts(
+                moduleConfig->getConnectedSourceDevicesPortsForMixPort(port));
+        if (micDevicePorts.empty()) continue;
+        atLeastOnePort = true;
+        SCOPED_TRACE(port.toString());
+        StreamFixture<IStreamIn> stream;
+        ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForPortsPair(module.get(), moduleConfig.get(),
+                                                               port, micDevicePorts[0]));
+        if (!stream.skipTestReason().empty()) continue;
+        std::vector<MicrophoneDynamicInfo> activeMics;
+        EXPECT_IS_OK(stream.getStream()->getActiveMicrophones(&activeMics));
+        EXPECT_FALSE(activeMics.empty());
+        for (const auto& mic : activeMics) {
+            EXPECT_NE(micInfos.end(),
+                      std::find_if(micInfos.begin(), micInfos.end(),
+                                   [&](const auto& micInfo) { return micInfo.id == mic.id; }))
+                    << "active microphone \"" << mic.id << "\" is not listed in "
+                    << "microphone infos returned by the module: "
+                    << ::android::internal::ToString(micInfos);
+            EXPECT_NE(0UL, mic.channelMapping.size())
+                    << "No channels specified for the microphone \"" << mic.id << "\"";
         }
-        if (auto micDevicePorts = ModuleConfig::getBuiltInMicPorts(
-                    moduleConfig->getConnectedSourceDevicesPortsForMixPort(port));
-            !micDevicePorts.empty()) {
-            auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(micDevicePorts[0]);
-            WithAudioPatch patch(true /*isInput*/, stream.getPortConfig(), devicePortConfig);
-            ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
-            std::vector<MicrophoneDynamicInfo> activeMics;
-            EXPECT_IS_OK(stream.get()->getActiveMicrophones(&activeMics));
-            EXPECT_FALSE(activeMics.empty());
-            for (const auto& mic : activeMics) {
-                EXPECT_NE(micInfos.end(),
-                          std::find_if(micInfos.begin(), micInfos.end(),
-                                       [&](const auto& micInfo) { return micInfo.id == mic.id; }))
-                        << "active microphone \"" << mic.id << "\" is not listed in "
-                        << "microphone infos returned by the module: "
-                        << ::android::internal::ToString(micInfos);
-                EXPECT_NE(0UL, mic.channelMapping.size())
-                        << "No channels specified for the microphone \"" << mic.id << "\"";
-            }
-        }
-        {
-            // Now the port of the stream is not connected again, re-check that there are no
-            // active microphones.
-            std::vector<MicrophoneDynamicInfo> activeMics;
-            EXPECT_IS_OK(stream.get()->getActiveMicrophones(&activeMics));
-            EXPECT_TRUE(activeMics.empty()) << "a stream on an unconnected port returns a "
-                                               "non-empty list of active microphones";
-        }
+        stream.TeardownPatch();
+        // Now the port of the stream is not connected, check that there are no active microphones.
+        std::vector<MicrophoneDynamicInfo> emptyMics;
+        EXPECT_IS_OK(stream.getStream()->getActiveMicrophones(&emptyMics));
+        EXPECT_TRUE(emptyMics.empty()) << "a stream on an unconnected port returns a "
+                                          "non-empty list of active microphones";
+    }
+    if (!atLeastOnePort) {
+        GTEST_SKIP() << "No input mix ports could be routed to built-in microphone devices";
     }
 }
 
 TEST_P(AudioStreamIn, MicrophoneDirection) {
     using MD = IStreamIn::MicrophoneDirection;
-    const auto ports = moduleConfig->getInputMixPorts(true /*connectedOnly*/);
+    constexpr bool connectedOnly = true;
+    const auto ports = moduleConfig->getInputMixPorts(connectedOnly);
     if (ports.empty()) {
         GTEST_SKIP() << "No input mix ports for attached devices";
     }
-    bool isSupported = false;
+    bool isSupported = false, atLeastOnePort = false;
     for (const auto& port : ports) {
-        const auto portConfig = moduleConfig->getSingleConfigForMixPort(true, port);
-        ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for input mix port";
-        WithStream<IStreamIn> stream(portConfig.value());
-        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+        SCOPED_TRACE(port.toString());
+        StreamFixture<IStreamIn> stream;
+        ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForMixPort(module.get(), moduleConfig.get(), port,
+                                                             connectedOnly));
+        if (!stream.skipTestReason().empty()) continue;
+        atLeastOnePort = true;
         EXPECT_NO_FATAL_FAILURE(
-                TestAccessors<MD>(stream.get(), &IStreamIn::getMicrophoneDirection,
+                TestAccessors<MD>(stream.getStream(), &IStreamIn::getMicrophoneDirection,
                                   &IStreamIn::setMicrophoneDirection,
                                   std::vector<MD>(enum_range<MD>().begin(), enum_range<MD>().end()),
                                   {}, &isSupported));
@@ -2828,21 +3330,27 @@
     if (!isSupported) {
         GTEST_SKIP() << "Microphone direction is not supported";
     }
+    if (!atLeastOnePort) {
+        GTEST_SKIP() << "No input mix ports could be routed to built-in microphone devices";
+    }
 }
 
 TEST_P(AudioStreamIn, MicrophoneFieldDimension) {
-    const auto ports = moduleConfig->getInputMixPorts(true /*connectedOnly*/);
+    constexpr bool connectedOnly = true;
+    const auto ports = moduleConfig->getInputMixPorts(connectedOnly);
     if (ports.empty()) {
         GTEST_SKIP() << "No input mix ports for attached devices";
     }
-    bool isSupported = false;
+    bool isSupported = false, atLeastOnePort = false;
     for (const auto& port : ports) {
-        const auto portConfig = moduleConfig->getSingleConfigForMixPort(true, port);
-        ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for input mix port";
-        WithStream<IStreamIn> stream(portConfig.value());
-        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+        SCOPED_TRACE(port.toString());
+        StreamFixture<IStreamIn> stream;
+        ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForMixPort(module.get(), moduleConfig.get(), port,
+                                                             connectedOnly));
+        if (!stream.skipTestReason().empty()) continue;
+        atLeastOnePort = true;
         EXPECT_NO_FATAL_FAILURE(TestAccessors<float>(
-                stream.get(), &IStreamIn::getMicrophoneFieldDimension,
+                stream.getStream(), &IStreamIn::getMicrophoneFieldDimension,
                 &IStreamIn::setMicrophoneFieldDimension,
                 {IStreamIn::MIC_FIELD_DIMENSION_WIDE_ANGLE,
                  IStreamIn::MIC_FIELD_DIMENSION_WIDE_ANGLE / 2.0f,
@@ -2859,6 +3367,9 @@
     if (!isSupported) {
         GTEST_SKIP() << "Microphone direction is not supported";
     }
+    if (!atLeastOnePort) {
+        GTEST_SKIP() << "No input mix ports could be routed to built-in microphone devices";
+    }
 }
 
 TEST_P(AudioStreamOut, OpenTwicePrimary) {
@@ -2873,65 +3384,79 @@
 }
 
 TEST_P(AudioStreamOut, RequireOffloadInfo) {
+    constexpr bool connectedOnly = true;
     const auto offloadMixPorts =
-            moduleConfig->getOffloadMixPorts(true /*connectedOnly*/, true /*singlePort*/);
+            moduleConfig->getOffloadMixPorts(connectedOnly, true /*singlePort*/);
     if (offloadMixPorts.empty()) {
         GTEST_SKIP()
                 << "No mix port for compressed offload that could be routed to attached devices";
     }
-    const auto config = moduleConfig->getSingleConfigForMixPort(false, *offloadMixPorts.begin());
-    ASSERT_TRUE(config.has_value()) << "No profiles specified for the compressed offload mix port";
-    WithAudioPortConfig portConfig(config.value());
-    ASSERT_NO_FATAL_FAILURE(portConfig.SetUp(module.get()));
+    StreamFixture<IStreamOut> stream;
+    ASSERT_NO_FATAL_FAILURE(stream.SetUpPortConfigForMixPortOrConfig(
+            module.get(), moduleConfig.get(), *offloadMixPorts.begin(), connectedOnly));
+    if (auto reason = stream.skipTestReason(); !reason.empty()) {
+        GTEST_SKIP() << reason;
+    }
+    const auto portConfig = stream.getPortConfig();
     StreamDescriptor descriptor;
-    std::shared_ptr<IStreamOut> ignored;
     aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
-    args.portConfigId = portConfig.getId();
-    args.sourceMetadata = GenerateSourceMetadata(portConfig.get());
+    args.portConfigId = portConfig.id;
+    args.sourceMetadata = GenerateSourceMetadata(portConfig);
     args.bufferSizeFrames = kDefaultLargeBufferSizeFrames;
     aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
     EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->openOutputStream(args, &ret))
             << "when no offload info is provided for a compressed offload mix port";
+    if (ret.stream != nullptr) {
+        (void)WithStream<IStreamOut>::callClose(ret.stream);
+    }
 }
 
 TEST_P(AudioStreamOut, RequireAsyncCallback) {
+    constexpr bool connectedOnly = true;
     const auto nonBlockingMixPorts =
-            moduleConfig->getNonBlockingMixPorts(true /*connectedOnly*/, true /*singlePort*/);
+            moduleConfig->getNonBlockingMixPorts(connectedOnly, true /*singlePort*/);
     if (nonBlockingMixPorts.empty()) {
         GTEST_SKIP()
                 << "No mix port for non-blocking output that could be routed to attached devices";
     }
-    const auto config =
-            moduleConfig->getSingleConfigForMixPort(false, *nonBlockingMixPorts.begin());
-    ASSERT_TRUE(config.has_value()) << "No profiles specified for the non-blocking mix port";
-    WithAudioPortConfig portConfig(config.value());
-    ASSERT_NO_FATAL_FAILURE(portConfig.SetUp(module.get()));
+    StreamFixture<IStreamOut> stream;
+    ASSERT_NO_FATAL_FAILURE(stream.SetUpPortConfigForMixPortOrConfig(
+            module.get(), moduleConfig.get(), *nonBlockingMixPorts.begin(), connectedOnly));
+    if (auto reason = stream.skipTestReason(); !reason.empty()) {
+        GTEST_SKIP() << reason;
+    }
+    const auto portConfig = stream.getPortConfig();
     StreamDescriptor descriptor;
-    std::shared_ptr<IStreamOut> ignored;
     aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
-    args.portConfigId = portConfig.getId();
-    args.sourceMetadata = GenerateSourceMetadata(portConfig.get());
-    args.offloadInfo = ModuleConfig::generateOffloadInfoIfNeeded(portConfig.get());
-    args.bufferSizeFrames = kDefaultBufferSizeFrames;
+    args.portConfigId = portConfig.id;
+    args.sourceMetadata = GenerateSourceMetadata(portConfig);
+    args.offloadInfo = ModuleConfig::generateOffloadInfoIfNeeded(portConfig);
+    args.bufferSizeFrames = stream.getPatch().minimumStreamBufferSizeFrames;
     aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
     EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->openOutputStream(args, &ret))
             << "when no async callback is provided for a non-blocking mix port";
+    if (ret.stream != nullptr) {
+        (void)WithStream<IStreamOut>::callClose(ret.stream);
+    }
 }
 
 TEST_P(AudioStreamOut, AudioDescriptionMixLevel) {
-    const auto ports = moduleConfig->getOutputMixPorts(true /*connectedOnly*/);
+    constexpr bool connectedOnly = true;
+    const auto ports = moduleConfig->getOutputMixPorts(connectedOnly);
     if (ports.empty()) {
-        GTEST_SKIP() << "No output mix ports";
+        GTEST_SKIP() << "No output mix ports for attached devices";
     }
-    bool atLeastOneSupports = false;
+    bool atLeastOneSupports = false, atLeastOnePort = false;
     for (const auto& port : ports) {
-        const auto portConfig = moduleConfig->getSingleConfigForMixPort(false, port);
-        ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for output mix port";
-        WithStream<IStreamOut> stream(portConfig.value());
-        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+        SCOPED_TRACE(port.toString());
+        StreamFixture<IStreamOut> stream;
+        ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForMixPort(module.get(), moduleConfig.get(), port,
+                                                             connectedOnly));
+        if (!stream.skipTestReason().empty()) continue;
+        atLeastOnePort = true;
         bool isSupported = false;
         EXPECT_NO_FATAL_FAILURE(
-                TestAccessors<float>(stream.get(), &IStreamOut::getAudioDescriptionMixLevel,
+                TestAccessors<float>(stream.getStream(), &IStreamOut::getAudioDescriptionMixLevel,
                                      &IStreamOut::setAudioDescriptionMixLevel,
                                      {IStreamOut::AUDIO_DESCRIPTION_MIX_LEVEL_MAX,
                                       IStreamOut::AUDIO_DESCRIPTION_MIX_LEVEL_MAX - 1, 0,
@@ -2941,48 +3466,60 @@
                                      &isSupported));
         if (isSupported) atLeastOneSupports = true;
     }
+    if (!atLeastOnePort) {
+        GTEST_SKIP() << "No output mix ports could be routed to devices";
+    }
     if (!atLeastOneSupports) {
         GTEST_SKIP() << "Audio description mix level is not supported";
     }
 }
 
 TEST_P(AudioStreamOut, DualMonoMode) {
-    const auto ports = moduleConfig->getOutputMixPorts(true /*connectedOnly*/);
+    constexpr bool connectedOnly = true;
+    const auto ports = moduleConfig->getOutputMixPorts(connectedOnly);
     if (ports.empty()) {
-        GTEST_SKIP() << "No output mix ports";
+        GTEST_SKIP() << "No output mix ports for attached devices";
     }
-    bool atLeastOneSupports = false;
+    bool atLeastOneSupports = false, atLeastOnePort = false;
     for (const auto& port : ports) {
-        const auto portConfig = moduleConfig->getSingleConfigForMixPort(false, port);
-        ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for output mix port";
-        WithStream<IStreamOut> stream(portConfig.value());
-        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+        SCOPED_TRACE(port.toString());
+        StreamFixture<IStreamOut> stream;
+        ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForMixPort(module.get(), moduleConfig.get(), port,
+                                                             connectedOnly));
+        if (!stream.skipTestReason().empty()) continue;
+        atLeastOnePort = true;
         bool isSupported = false;
         EXPECT_NO_FATAL_FAILURE(TestAccessors<AudioDualMonoMode>(
-                stream.get(), &IStreamOut::getDualMonoMode, &IStreamOut::setDualMonoMode,
+                stream.getStream(), &IStreamOut::getDualMonoMode, &IStreamOut::setDualMonoMode,
                 std::vector<AudioDualMonoMode>(enum_range<AudioDualMonoMode>().begin(),
                                                enum_range<AudioDualMonoMode>().end()),
                 {}, &isSupported));
         if (isSupported) atLeastOneSupports = true;
     }
+    if (!atLeastOnePort) {
+        GTEST_SKIP() << "No output mix ports could be routed to devices";
+    }
     if (!atLeastOneSupports) {
         GTEST_SKIP() << "Audio dual mono mode is not supported";
     }
 }
 
 TEST_P(AudioStreamOut, LatencyMode) {
-    const auto ports = moduleConfig->getOutputMixPorts(true /*connectedOnly*/);
+    constexpr bool connectedOnly = true;
+    const auto ports = moduleConfig->getOutputMixPorts(connectedOnly);
     if (ports.empty()) {
-        GTEST_SKIP() << "No output mix ports";
+        GTEST_SKIP() << "No output mix ports for attached devices";
     }
-    bool atLeastOneSupports = false;
+    bool atLeastOneSupports = false, atLeastOnePort = false;
     for (const auto& port : ports) {
-        const auto portConfig = moduleConfig->getSingleConfigForMixPort(false, port);
-        ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for output mix port";
-        WithStream<IStreamOut> stream(portConfig.value());
-        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+        SCOPED_TRACE(port.toString());
+        StreamFixture<IStreamOut> stream;
+        ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForMixPort(module.get(), moduleConfig.get(), port,
+                                                             connectedOnly));
+        if (!stream.skipTestReason().empty()) continue;
+        atLeastOnePort = true;
         std::vector<AudioLatencyMode> supportedModes;
-        ndk::ScopedAStatus status = stream.get()->getRecommendedLatencyModes(&supportedModes);
+        ndk::ScopedAStatus status = stream.getStream()->getRecommendedLatencyModes(&supportedModes);
         if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) continue;
         atLeastOneSupports = true;
         if (!status.isOk()) {
@@ -2994,7 +3531,7 @@
                                                     enum_range<AudioLatencyMode>().end());
         for (const auto mode : supportedModes) {
             unsupportedModes.erase(mode);
-            ndk::ScopedAStatus status = stream.get()->setLatencyMode(mode);
+            ndk::ScopedAStatus status = stream.getStream()->setLatencyMode(mode);
             if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
                 ADD_FAILURE() << "When latency modes are supported, both getRecommendedLatencyModes"
                               << " and setLatencyMode must be supported";
@@ -3002,12 +3539,15 @@
             EXPECT_IS_OK(status) << "Setting of supported latency mode must succeed";
         }
         for (const auto mode : unsupportedModes) {
-            EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, stream.get()->setLatencyMode(mode));
+            EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, stream.getStream()->setLatencyMode(mode));
         }
     }
     if (!atLeastOneSupports) {
         GTEST_SKIP() << "Audio latency modes are not supported";
     }
+    if (!atLeastOnePort) {
+        GTEST_SKIP() << "No output mix ports could be routed to devices";
+    }
 }
 
 TEST_P(AudioStreamOut, PlaybackRate) {
@@ -3309,29 +3849,22 @@
         }
     }
 
-    bool ValidateObservablePosition(const AudioPortConfig& devicePortConfig) {
-        return !isTelephonyDeviceType(
-                devicePortConfig.ext.get<AudioPortExt::Tag::device>().device.type.type);
+    bool ValidateObservablePosition(const AudioDevice& device) {
+        return !isTelephonyDeviceType(device.type.type);
     }
 
     // Set up a patch first, then open a stream.
     void RunStreamIoCommandsImplSeq1(const AudioPortConfig& portConfig,
                                      std::shared_ptr<StateSequence> commandsAndStates,
                                      bool validatePositionIncrease) {
-        auto devicePorts = moduleConfig->getConnectedDevicesPortsForMixPort(
-                IOTraits<Stream>::is_input, portConfig);
-        ASSERT_FALSE(devicePorts.empty());
-        auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(devicePorts[0]);
-        SCOPED_TRACE(devicePortConfig.toString());
-        WithAudioPatch patch(IOTraits<Stream>::is_input, portConfig, devicePortConfig);
-        ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
-
-        WithStream<Stream> stream(patch.getPortConfig(IOTraits<Stream>::is_input));
-        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+        StreamFixture<Stream> stream;
+        ASSERT_NO_FATAL_FAILURE(
+                stream.SetUpStreamForMixPortConfig(module.get(), moduleConfig.get(), portConfig));
+        ASSERT_EQ("", stream.skipTestReason());
         StreamLogicDefaultDriver driver(commandsAndStates,
-                                        stream.getContext()->getFrameSizeBytes());
-        typename IOTraits<Stream>::Worker worker(*stream.getContext(), &driver,
-                                                 stream.getEventReceiver());
+                                        stream.getStreamContext()->getFrameSizeBytes());
+        typename IOTraits<Stream>::Worker worker(*stream.getStreamContext(), &driver,
+                                                 stream.getStreamEventReceiver());
 
         LOG(DEBUG) << __func__ << ": starting worker...";
         ASSERT_TRUE(worker.start());
@@ -3339,7 +3872,7 @@
         worker.join();
         EXPECT_FALSE(worker.hasError()) << worker.getError();
         EXPECT_EQ("", driver.getUnexpectedStateTransition());
-        if (ValidateObservablePosition(devicePortConfig)) {
+        if (ValidateObservablePosition(stream.getDevice())) {
             if (validatePositionIncrease) {
                 EXPECT_TRUE(driver.hasObservablePositionIncrease());
             }
@@ -3347,24 +3880,21 @@
         }
     }
 
-    // Open a stream, then set up a patch for it.
+    // Open a stream, then set up a patch for it. Since first it is needed to get
+    // the minimum buffer size, a preliminary patch is set up, then removed.
     void RunStreamIoCommandsImplSeq2(const AudioPortConfig& portConfig,
                                      std::shared_ptr<StateSequence> commandsAndStates,
                                      bool validatePositionIncrease) {
-        WithStream<Stream> stream(portConfig);
-        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+        StreamFixture<Stream> stream;
+        ASSERT_NO_FATAL_FAILURE(
+                stream.SetUpPatchForMixPortConfig(module.get(), moduleConfig.get(), portConfig));
+        ASSERT_EQ("", stream.skipTestReason());
+        ASSERT_NO_FATAL_FAILURE(stream.TeardownPatchSetUpStream(module.get()));
         StreamLogicDefaultDriver driver(commandsAndStates,
-                                        stream.getContext()->getFrameSizeBytes());
-        typename IOTraits<Stream>::Worker worker(*stream.getContext(), &driver,
-                                                 stream.getEventReceiver());
-
-        auto devicePorts = moduleConfig->getConnectedDevicesPortsForMixPort(
-                IOTraits<Stream>::is_input, portConfig);
-        ASSERT_FALSE(devicePorts.empty());
-        auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(devicePorts[0]);
-        SCOPED_TRACE(devicePortConfig.toString());
-        WithAudioPatch patch(IOTraits<Stream>::is_input, stream.getPortConfig(), devicePortConfig);
-        ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
+                                        stream.getStreamContext()->getFrameSizeBytes());
+        typename IOTraits<Stream>::Worker worker(*stream.getStreamContext(), &driver,
+                                                 stream.getStreamEventReceiver());
+        ASSERT_NO_FATAL_FAILURE(stream.ReconnectPatch(module.get()));
 
         LOG(DEBUG) << __func__ << ": starting worker...";
         ASSERT_TRUE(worker.start());
@@ -3372,7 +3902,7 @@
         worker.join();
         EXPECT_FALSE(worker.hasError()) << worker.getError();
         EXPECT_EQ("", driver.getUnexpectedStateTransition());
-        if (ValidateObservablePosition(devicePortConfig)) {
+        if (ValidateObservablePosition(stream.getDevice())) {
             if (validatePositionIncrease) {
                 EXPECT_TRUE(driver.hasObservablePositionIncrease());
             }
@@ -3494,9 +4024,12 @@
                     patches.push_back(
                             std::make_unique<WithAudioPatch>(srcSink.first, srcSink.second));
                     EXPECT_NO_FATAL_FAILURE(patches[patches.size() - 1]->SetUp(module.get()));
+                    EXPECT_NO_FATAL_FAILURE(
+                            patches[patches.size() - 1]->VerifyAgainstAllPatches(module.get()));
                 } else {
                     WithAudioPatch patch(srcSink.first, srcSink.second);
                     EXPECT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
+                    EXPECT_NO_FATAL_FAILURE(patch.VerifyAgainstAllPatches(module.get()));
                 }
             }
         }
@@ -3517,6 +4050,29 @@
         }
     }
 
+    void UpdatePatchPorts(bool isInput) {
+        auto srcSinkGroups = moduleConfig->getRoutableSrcSinkGroups(isInput);
+        if (srcSinkGroups.empty()) {
+            GTEST_SKIP() << "No routes to any attached " << direction(isInput, false) << " devices";
+        }
+        bool hasAtLeastOnePair = false;
+        for (const auto& srcSinkGroup : srcSinkGroups) {
+            const auto& srcSinks = srcSinkGroup.second;
+            if (srcSinks.size() < 2) continue;
+            hasAtLeastOnePair = true;
+            const auto& pair1 = srcSinks[0];
+            const auto& pair2 = srcSinks[1];
+            WithAudioPatch patch(pair1.first, pair1.second);
+            ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
+            WithAudioPatch update(patch, pair2.first, pair2.second);
+            EXPECT_NO_FATAL_FAILURE(update.SetUp(module.get()));
+            EXPECT_NO_FATAL_FAILURE(update.VerifyAgainstAllPatches(module.get()));
+        }
+        if (!hasAtLeastOnePair) {
+            GTEST_SKIP() << "No routes with multiple sources";
+        }
+    }
+
     void UpdateInvalidPatchId(bool isInput) {
         auto srcSinkGroups = moduleConfig->getRoutableSrcSinkGroups(isInput);
         if (srcSinkGroups.empty()) {
@@ -3556,6 +4112,7 @@
 TEST_PATCH_BOTH_DIRECTIONS(SetPatch);
 TEST_PATCH_BOTH_DIRECTIONS(UpdateInvalidPatchId);
 TEST_PATCH_BOTH_DIRECTIONS(UpdatePatch);
+TEST_PATCH_BOTH_DIRECTIONS(UpdatePatchPorts);
 
 TEST_P(AudioModulePatch, ResetInvalidPatchId) {
     std::set<int32_t> patchIds;
@@ -4026,8 +4583,7 @@
 static std::vector<std::string> getRemoteSubmixModuleInstance() {
     auto instances = android::getAidlHalInstanceNames(IModule::descriptor);
     for (auto instance : instances) {
-        if (instance.find("r_submix") != std::string::npos)
-            return (std::vector<std::string>{instance});
+        if (instance.ends_with("/r_submix")) return (std::vector<std::string>{instance});
     }
     return {};
 }
@@ -4036,174 +4592,167 @@
 class WithRemoteSubmix {
   public:
     WithRemoteSubmix() = default;
-    WithRemoteSubmix(AudioDeviceAddress address) : mAddress(address) {}
+    explicit WithRemoteSubmix(AudioDeviceAddress address) : mAddress(address) {}
     WithRemoteSubmix(const WithRemoteSubmix&) = delete;
     WithRemoteSubmix& operator=(const WithRemoteSubmix&) = delete;
-    std::optional<AudioPort> getAudioPort() {
-        AudioDeviceType deviceType = IOTraits<Stream>::is_input ? AudioDeviceType::IN_SUBMIX
-                                                                : AudioDeviceType::OUT_SUBMIX;
-        auto ports = mModuleConfig->getAudioPortsForDeviceTypes(
-                std::vector<AudioDeviceType>{deviceType},
-                AudioDeviceDescription::CONNECTION_VIRTUAL);
-        if (!ports.empty()) return ports.front();
-        return {};
-    }
-    /* Connect remote submix external device */
-    void SetUpPortConnection() {
-        auto port = getAudioPort();
-        ASSERT_TRUE(port.has_value()) << "Device AudioPort for remote submix not found";
-        if (mAddress.has_value()) {
-            port.value().ext.template get<AudioPortExt::Tag::device>().device.address =
-                    mAddress.value();
-        } else {
-            port = GenerateUniqueDeviceAddress(port.value());
-        }
-        mConnectedPort = std::make_unique<WithDevicePortConnectedState>(port.value());
-        ASSERT_NO_FATAL_FAILURE(mConnectedPort->SetUp(mModule, mModuleConfig));
-    }
-    AudioDeviceAddress getAudioDeviceAddress() {
-        if (!mAddress.has_value()) {
-            mAddress = mConnectedPort->get()
-                               .ext.template get<AudioPortExt::Tag::device>()
-                               .device.address;
-        }
-        return mAddress.value();
-    }
-    /* Get mix port config for stream and setup patch for it. */
-    void SetupPatch() {
-        const auto portConfig =
-                mModuleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
-        if (!portConfig.has_value()) {
-            LOG(DEBUG) << __func__ << ": portConfig not found";
-            mSkipTest = true;
-            return;
-        }
-        auto devicePortConfig = mModuleConfig->getSingleConfigForDevicePort(mConnectedPort->get());
-        mPatch = std::make_unique<WithAudioPatch>(IOTraits<Stream>::is_input, portConfig.value(),
-                                                  devicePortConfig);
-        ASSERT_NO_FATAL_FAILURE(mPatch->SetUp(mModule));
-    }
-    void SetUp(IModule* module, ModuleConfig* moduleConfig) {
-        mModule = module;
-        mModuleConfig = moduleConfig;
-        ASSERT_NO_FATAL_FAILURE(SetUpPortConnection());
-        ASSERT_NO_FATAL_FAILURE(SetupPatch());
-        if (!mSkipTest) {
-            // open stream
-            mStream = std::make_unique<WithStream<Stream>>(
-                    mPatch->getPortConfig(IOTraits<Stream>::is_input));
-            ASSERT_NO_FATAL_FAILURE(
-                    mStream->SetUp(mModule, AudioCoreModuleBase::kDefaultBufferSizeFrames));
-        }
-    }
-    void sendBurstCommands() {
-        const StreamContext* context = mStream->getContext();
-        StreamLogicDefaultDriver driver(makeBurstCommands(true), context->getFrameSizeBytes());
-        typename IOTraits<Stream>::Worker worker(*context, &driver, mStream->getEventReceiver());
 
-        LOG(DEBUG) << __func__ << ": starting worker...";
-        ASSERT_TRUE(worker.start());
-        LOG(DEBUG) << __func__ << ": joining worker...";
-        worker.join();
-        EXPECT_FALSE(worker.hasError()) << worker.getError();
-        EXPECT_EQ("", driver.getUnexpectedStateTransition());
-        if (IOTraits<Stream>::is_input) {
-            EXPECT_TRUE(driver.hasObservablePositionIncrease());
+    static std::optional<AudioPort> getRemoteSubmixAudioPort(
+            ModuleConfig* moduleConfig,
+            const std::optional<AudioDeviceAddress>& address = std::nullopt) {
+        auto ports =
+                moduleConfig->getRemoteSubmixPorts(IOTraits<Stream>::is_input, true /*singlePort*/);
+        if (ports.empty()) return {};
+        AudioPort port = ports.front();
+        if (address) {
+            port.ext.template get<AudioPortExt::Tag::device>().device.address = address.value();
         }
-        EXPECT_FALSE(driver.hasRetrogradeObservablePosition());
+        return port;
     }
-    bool skipTest() { return mSkipTest; }
+
+    void SetUp(IModule* module, ModuleConfig* moduleConfig) {
+        auto devicePort = getRemoteSubmixAudioPort(moduleConfig, mAddress);
+        ASSERT_TRUE(devicePort.has_value()) << "Device port for remote submix device not found";
+        ASSERT_NO_FATAL_FAILURE(SetUp(module, moduleConfig, *devicePort));
+    }
+
+    void SendBurstCommandsStartWorker() {
+        const StreamContext* context = mStream->getStreamContext();
+        mWorkerDriver = std::make_unique<StreamLogicDefaultDriver>(makeBurstCommands(true),
+                                                                   context->getFrameSizeBytes());
+        mWorker = std::make_unique<typename IOTraits<Stream>::Worker>(
+                *context, mWorkerDriver.get(), mStream->getStreamEventReceiver());
+        LOG(DEBUG) << __func__ << ": starting " << IOTraits<Stream>::directionStr << " worker...";
+        ASSERT_TRUE(mWorker->start());
+    }
+
+    void SendBurstCommandsJoinWorker() {
+        // Must call 'prepareToClose' before attempting to join because the stream may be
+        // stuck due to absence of activity from the other side of the remote submix pipe.
+        std::shared_ptr<IStreamCommon> common;
+        ASSERT_IS_OK(mStream->getStream()->getStreamCommon(&common));
+        ASSERT_IS_OK(common->prepareToClose());
+        LOG(DEBUG) << __func__ << ": joining " << IOTraits<Stream>::directionStr << " worker...";
+        mWorker->join();
+        EXPECT_FALSE(mWorker->hasError()) << mWorker->getError();
+        EXPECT_EQ("", mWorkerDriver->getUnexpectedStateTransition());
+        if (IOTraits<Stream>::is_input) {
+            EXPECT_TRUE(mWorkerDriver->hasObservablePositionIncrease());
+        }
+        EXPECT_FALSE(mWorkerDriver->hasRetrogradeObservablePosition());
+        mWorker.reset();
+        mWorkerDriver.reset();
+    }
+
+    void SendBurstCommands() {
+        ASSERT_NO_FATAL_FAILURE(SendBurstCommandsStartWorker());
+        ASSERT_NO_FATAL_FAILURE(SendBurstCommandsJoinWorker());
+    }
+
+    std::optional<AudioDeviceAddress> getAudioDeviceAddress() const { return mAddress; }
+    std::string skipTestReason() const { return mStream->skipTestReason(); }
 
   private:
-    bool mSkipTest = false;
-    IModule* mModule = nullptr;
-    ModuleConfig* mModuleConfig = nullptr;
+    void SetUp(IModule* module, ModuleConfig* moduleConfig, const AudioPort& devicePort) {
+        mStream = std::make_unique<StreamFixture<Stream>>();
+        ASSERT_NO_FATAL_FAILURE(
+                mStream->SetUpStreamForDevicePort(module, moduleConfig, devicePort));
+        mAddress = mStream->getDevice().address;
+    }
+
     std::optional<AudioDeviceAddress> mAddress;
-    std::unique_ptr<WithDevicePortConnectedState> mConnectedPort;
-    std::unique_ptr<WithAudioPatch> mPatch;
-    std::unique_ptr<WithStream<Stream>> mStream;
+    std::unique_ptr<StreamFixture<Stream>> mStream;
+    std::unique_ptr<StreamLogicDefaultDriver> mWorkerDriver;
+    std::unique_ptr<typename IOTraits<Stream>::Worker> mWorker;
 };
 
 class AudioModuleRemoteSubmix : public AudioCoreModule {
   public:
     void SetUp() override {
-        ASSERT_NO_FATAL_FAILURE(AudioCoreModule::SetUp());
+        // Turn off "debug" which enables connections simulation. Since devices of the remote
+        // submix module are virtual, there is no need for simulation.
+        ASSERT_NO_FATAL_FAILURE(SetUpImpl(GetParam(), false /*setUpDebug*/));
+        if (int32_t version; module->getInterfaceVersion(&version).isOk() && version < 2) {
+            GTEST_SKIP() << "V1 uses a deprecated remote submix device type encoding";
+        }
         ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
     }
-
-    void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownImpl()); }
 };
 
 TEST_P(AudioModuleRemoteSubmix, OutputDoesNotBlockWhenNoInput) {
-    // open output stream
     WithRemoteSubmix<IStreamOut> streamOut;
     ASSERT_NO_FATAL_FAILURE(streamOut.SetUp(module.get(), moduleConfig.get()));
-    if (streamOut.skipTest()) {
-        GTEST_SKIP() << "No mix port for attached devices";
-    }
-    // write something to stream
-    ASSERT_NO_FATAL_FAILURE(streamOut.sendBurstCommands());
+    // Note: here and in other tests any issue with connection attempts is considered as a problem.
+    ASSERT_EQ("", streamOut.skipTestReason());
+    ASSERT_NO_FATAL_FAILURE(streamOut.SendBurstCommands());
 }
 
 TEST_P(AudioModuleRemoteSubmix, OutputDoesNotBlockWhenInputStuck) {
-    // open output stream
     WithRemoteSubmix<IStreamOut> streamOut;
     ASSERT_NO_FATAL_FAILURE(streamOut.SetUp(module.get(), moduleConfig.get()));
-    if (streamOut.skipTest()) {
-        GTEST_SKIP() << "No mix port for attached devices";
-    }
+    ASSERT_EQ("", streamOut.skipTestReason());
+    auto address = streamOut.getAudioDeviceAddress();
+    ASSERT_TRUE(address.has_value());
 
-    // open input stream
-    WithRemoteSubmix<IStreamIn> streamIn(streamOut.getAudioDeviceAddress());
+    WithRemoteSubmix<IStreamIn> streamIn(address.value());
     ASSERT_NO_FATAL_FAILURE(streamIn.SetUp(module.get(), moduleConfig.get()));
-    if (streamIn.skipTest()) {
-        GTEST_SKIP() << "No mix port for attached devices";
-    }
+    ASSERT_EQ("", streamIn.skipTestReason());
 
-    // write something to stream
-    ASSERT_NO_FATAL_FAILURE(streamOut.sendBurstCommands());
+    ASSERT_NO_FATAL_FAILURE(streamOut.SendBurstCommands());
 }
 
 TEST_P(AudioModuleRemoteSubmix, OutputAndInput) {
-    // open output stream
     WithRemoteSubmix<IStreamOut> streamOut;
     ASSERT_NO_FATAL_FAILURE(streamOut.SetUp(module.get(), moduleConfig.get()));
-    if (streamOut.skipTest()) {
-        GTEST_SKIP() << "No mix port for attached devices";
-    }
+    ASSERT_EQ("", streamOut.skipTestReason());
+    auto address = streamOut.getAudioDeviceAddress();
+    ASSERT_TRUE(address.has_value());
 
-    // open input stream
-    WithRemoteSubmix<IStreamIn> streamIn(streamOut.getAudioDeviceAddress());
+    WithRemoteSubmix<IStreamIn> streamIn(address.value());
     ASSERT_NO_FATAL_FAILURE(streamIn.SetUp(module.get(), moduleConfig.get()));
-    if (streamIn.skipTest()) {
-        GTEST_SKIP() << "No mix port for attached devices";
-    }
+    ASSERT_EQ("", streamIn.skipTestReason());
 
-    // write something to stream
-    ASSERT_NO_FATAL_FAILURE(streamOut.sendBurstCommands());
-    // read from input stream
-    ASSERT_NO_FATAL_FAILURE(streamIn.sendBurstCommands());
+    // Start writing into the output stream.
+    ASSERT_NO_FATAL_FAILURE(streamOut.SendBurstCommandsStartWorker());
+    // Simultaneously, read from the input stream.
+    ASSERT_NO_FATAL_FAILURE(streamIn.SendBurstCommands());
+    ASSERT_NO_FATAL_FAILURE(streamOut.SendBurstCommandsJoinWorker());
+}
+
+TEST_P(AudioModuleRemoteSubmix, OpenInputMultipleTimes) {
+    WithRemoteSubmix<IStreamOut> streamOut;
+    ASSERT_NO_FATAL_FAILURE(streamOut.SetUp(module.get(), moduleConfig.get()));
+    ASSERT_EQ("", streamOut.skipTestReason());
+    auto address = streamOut.getAudioDeviceAddress();
+    ASSERT_TRUE(address.has_value());
+
+    const size_t streamInCount = 3;
+    std::vector<std::unique_ptr<WithRemoteSubmix<IStreamIn>>> streamIns(streamInCount);
+    for (size_t i = 0; i < streamInCount; i++) {
+        streamIns[i] = std::make_unique<WithRemoteSubmix<IStreamIn>>(address.value());
+        ASSERT_NO_FATAL_FAILURE(streamIns[i]->SetUp(module.get(), moduleConfig.get()));
+        ASSERT_EQ("", streamIns[i]->skipTestReason());
+    }
+    // Start writing into the output stream.
+    ASSERT_NO_FATAL_FAILURE(streamOut.SendBurstCommandsStartWorker());
+    // Simultaneously, read from input streams.
+    for (size_t i = 0; i < streamInCount; i++) {
+        ASSERT_NO_FATAL_FAILURE(streamIns[i]->SendBurstCommandsStartWorker());
+    }
+    for (size_t i = 0; i < streamInCount; i++) {
+        ASSERT_NO_FATAL_FAILURE(streamIns[i]->SendBurstCommandsJoinWorker());
+    }
+    ASSERT_NO_FATAL_FAILURE(streamOut.SendBurstCommandsJoinWorker());
+    // Clean up input streams in the reverse order because the device connection is owned
+    // by the first one.
+    for (size_t i = streamInCount; i != 0; --i) {
+        streamIns[i - 1].reset();
+    }
 }
 
 INSTANTIATE_TEST_SUITE_P(AudioModuleRemoteSubmixTest, AudioModuleRemoteSubmix,
                          ::testing::ValuesIn(getRemoteSubmixModuleInstance()));
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioModuleRemoteSubmix);
 
-class TestExecutionTracer : public ::testing::EmptyTestEventListener {
-  public:
-    void OnTestStart(const ::testing::TestInfo& test_info) override {
-        TraceTestState("Started", test_info);
-    }
-    void OnTestEnd(const ::testing::TestInfo& test_info) override {
-        TraceTestState("Completed", test_info);
-    }
-
-  private:
-    static void TraceTestState(const std::string& state, const ::testing::TestInfo& test_info) {
-        LOG(INFO) << state << " " << test_info.test_suite_name() << "::" << test_info.name();
-    }
-};
-
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
     ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
diff --git a/audio/aidl/vts/VtsHalAudioCoreTargetTest.xml b/audio/aidl/vts/VtsHalAudioCoreTargetTest.xml
deleted file mode 100644
index 9d3adc1..0000000
--- a/audio/aidl/vts/VtsHalAudioCoreTargetTest.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2023 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT 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 VtsHalAudioCoreTargetTest.">
-    <option name="test-suite-tag" value="apct" />
-    <option name="test-suite-tag" value="apct-native" />
-
-    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
-    <target_preparer class="com.android.tradefed.targetprep.StopServicesSetup"/>
-
-    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
-        <option name="run-command" value="setprop vts.native_server.on 1"/>
-        <option name="teardown-command" value="setprop vts.native_server.on 0"/>
-    </target_preparer>
-
-    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
-        <option name="cleanup" value="true" />
-        <option name="push" value="VtsHalAudioCoreTargetTest->/data/local/tmp/VtsHalAudioCoreTargetTest" />
-    </target_preparer>
-
-    <test class="com.android.tradefed.testtype.GTest" >
-        <option name="native-test-device-path" value="/data/local/tmp" />
-        <option name="module-name" value="VtsHalAudioCoreTargetTest" />
-        <option name="native-test-timeout" value="10m" />
-    </test>
-</configuration>
diff --git a/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp b/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp
index 225640e..523f20d 100644
--- a/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp
@@ -52,6 +52,7 @@
 using aidl::android::media::audio::common::AudioSource;
 using aidl::android::media::audio::common::AudioStreamType;
 using aidl::android::media::audio::common::AudioUuid;
+using android::hardware::audio::common::testing::detail::TestExecutionTracer;
 
 /// Effect factory testing.
 class EffectFactoryTest : public testing::TestWithParam<std::string> {
@@ -303,6 +304,7 @@
 
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
+    ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
     ABinderProcess_setThreadPoolMaxThreadCount(1);
     ABinderProcess_startThreadPool();
     return RUN_ALL_TESTS();
diff --git a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
index 1876756..01cdd81 100644
--- a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
@@ -16,13 +16,11 @@
 
 #define LOG_TAG "VtsHalAudioEffectTargetTest"
 
-#include <chrono>
 #include <memory>
 #include <string>
 #include <vector>
 
 #include <aidl/Gtest.h>
-#include <aidl/Vintf.h>
 #include <aidl/android/hardware/audio/effect/IEffect.h>
 #include <aidl/android/hardware/audio/effect/IFactory.h>
 #include <android-base/logging.h>
@@ -51,6 +49,7 @@
 using aidl::android::media::audio::common::AudioDeviceType;
 using aidl::android::media::audio::common::AudioMode;
 using aidl::android::media::audio::common::AudioSource;
+using android::hardware::audio::common::testing::detail::TestExecutionTracer;
 
 enum ParamName { PARAM_INSTANCE_NAME };
 using EffectTestParam = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>>;
@@ -595,8 +594,14 @@
 
     Parameter::Id id = Parameter::Id::make<Parameter::Id::commonTag>(Parameter::volumeStereo);
     Parameter::VolumeStereo volume = {.left = 10.0, .right = 10.0};
-    ASSERT_NO_FATAL_FAILURE(
-            setAndGetParameter(id, Parameter::make<Parameter::volumeStereo>(volume)));
+    if (mDescriptor.common.flags.volume == Flags::Volume::CTRL) {
+        Parameter get;
+        EXPECT_IS_OK(mEffect->setParameter(volume));
+        EXPECT_IS_OK(mEffect->getParameter(id, &get));
+    } else {
+        ASSERT_NO_FATAL_FAILURE(
+                setAndGetParameter(id, Parameter::make<Parameter::volumeStereo>(volume)));
+    }
 
     ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
     ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
@@ -604,6 +609,49 @@
     ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
+// Verify Parameters kept after reset.
+TEST_P(AudioEffectTest, SetCommonParameterAndReopen) {
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+
+    Parameter::Common common = EffectHelper::createParamCommon(
+            0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+            kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+    IEffect::OpenEffectReturn ret;
+    ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt /* specific */, &ret, EX_NONE));
+    auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
+    ASSERT_TRUE(statusMQ->isValid());
+    auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+    ASSERT_TRUE(inputMQ->isValid());
+    auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+    ASSERT_TRUE(outputMQ->isValid());
+
+    Parameter::Id id = Parameter::Id::make<Parameter::Id::commonTag>(Parameter::common);
+    common.input.frameCount++;
+    ASSERT_NO_FATAL_FAILURE(setAndGetParameter(id, Parameter::make<Parameter::common>(common)));
+    ASSERT_TRUE(statusMQ->isValid());
+    expectDataMqUpdateEventFlag(statusMQ);
+    EXPECT_IS_OK(mEffect->reopen(&ret));
+    inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+    outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+    ASSERT_TRUE(statusMQ->isValid());
+    ASSERT_TRUE(inputMQ->isValid());
+    ASSERT_TRUE(outputMQ->isValid());
+
+    common.output.frameCount++;
+    ASSERT_NO_FATAL_FAILURE(setAndGetParameter(id, Parameter::make<Parameter::common>(common)));
+    ASSERT_TRUE(statusMQ->isValid());
+    expectDataMqUpdateEventFlag(statusMQ);
+    EXPECT_IS_OK(mEffect->reopen(&ret));
+    inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+    outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+    ASSERT_TRUE(statusMQ->isValid());
+    ASSERT_TRUE(inputMQ->isValid());
+    ASSERT_TRUE(outputMQ->isValid());
+
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+}
+
 /// Data processing test
 // Send data to effects and expect it to be consumed by checking statusMQ.
 // Effects exposing bypass flags or operating in offload mode will be skipped.
@@ -679,6 +727,59 @@
     ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
+// Send data to effects and expect it to be consumed after effect reopen (IO AudioConfig change).
+// Effects exposing bypass flags or operating in offload mode will be skipped.
+TEST_P(AudioEffectDataPathTest, ConsumeDataAfterReopen) {
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+
+    Parameter::Common common = EffectHelper::createParamCommon(
+            0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+            kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+    IEffect::OpenEffectReturn ret;
+    ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt /* specific */, &ret, EX_NONE));
+    auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
+    ASSERT_TRUE(statusMQ->isValid());
+    auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+    ASSERT_TRUE(inputMQ->isValid());
+    auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+    ASSERT_TRUE(outputMQ->isValid());
+
+    std::vector<float> buffer;
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+    EXPECT_NO_FATAL_FAILURE(EffectHelper::allocateInputData(common, inputMQ, buffer));
+    EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ, inputMQ, buffer));
+    EXPECT_NO_FATAL_FAILURE(
+            EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer));
+
+    // set a new common parameter with different IO frameCount, reopen
+    Parameter::Id id = Parameter::Id::make<Parameter::Id::commonTag>(Parameter::common);
+    common.input.frameCount += 4;
+    common.output.frameCount += 4;
+    ASSERT_NO_FATAL_FAILURE(setAndGetParameter(id, Parameter::make<Parameter::common>(common)));
+    ASSERT_TRUE(statusMQ->isValid());
+    expectDataMqUpdateEventFlag(statusMQ);
+    EXPECT_IS_OK(mEffect->reopen(&ret));
+    inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+    outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+    ASSERT_TRUE(statusMQ->isValid());
+    ASSERT_TRUE(inputMQ->isValid());
+    ASSERT_TRUE(outputMQ->isValid());
+
+    // verify data consume again
+    EXPECT_NO_FATAL_FAILURE(EffectHelper::allocateInputData(common, inputMQ, buffer));
+    EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ, inputMQ, buffer));
+    EXPECT_NO_FATAL_FAILURE(
+            EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer));
+
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    EXPECT_NO_FATAL_FAILURE(EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer));
+
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+}
+
 // Send data to IDLE effects and expect it to be consumed after effect start.
 // Effects exposing bypass flags or operating in offload mode will be skipped.
 TEST_P(AudioEffectDataPathTest, SendDataAtIdleAndConsumeDataInProcessing) {
@@ -907,6 +1008,7 @@
 
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
+    ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
     ABinderProcess_setThreadPoolMaxThreadCount(1);
     ABinderProcess_startThreadPool();
     return RUN_ALL_TESTS();
diff --git a/audio/aidl/vts/VtsHalAudioTargetTestTemplate.xml b/audio/aidl/vts/VtsHalAudioTargetTestTemplate.xml
new file mode 100644
index 0000000..c92e852
--- /dev/null
+++ b/audio/aidl/vts/VtsHalAudioTargetTestTemplate.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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 {MODULE}.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+    <target_preparer class="com.android.tradefed.targetprep.StopServicesSetup"/>
+
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="setprop vts.native_server.on 1"/>
+        <option name="teardown-command" value="setprop vts.native_server.on 0"/>
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="{MODULE}->/data/local/tmp/{MODULE}" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="{MODULE}" />
+        <option name="native-test-timeout" value="10m" />
+    </test>
+</configuration>
diff --git a/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp b/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp
index afddb84..135940d 100644
--- a/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp
@@ -14,9 +14,6 @@
  * limitations under the License.
  */
 
-#include <limits.h>
-
-#include <aidl/Vintf.h>
 #define LOG_TAG "VtsHalBassBoostTest"
 #include <android-base/logging.h>
 
@@ -32,7 +29,7 @@
 using aidl::android::hardware::audio::effect::IFactory;
 using aidl::android::hardware::audio::effect::Parameter;
 using aidl::android::hardware::audio::effect::Range;
-
+using android::hardware::audio::common::testing::detail::TestExecutionTracer;
 /**
  * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
  * VtsAudioEffectTargetTest.
@@ -155,6 +152,7 @@
 
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
+    ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
     ABinderProcess_setThreadPoolMaxThreadCount(1);
     ABinderProcess_startThreadPool();
     return RUN_ALL_TESTS();
diff --git a/audio/aidl/vts/VtsHalDownmixTargetTest.cpp b/audio/aidl/vts/VtsHalDownmixTargetTest.cpp
index 7a2f31b..360bf26 100644
--- a/audio/aidl/vts/VtsHalDownmixTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalDownmixTargetTest.cpp
@@ -14,92 +14,120 @@
  * limitations under the License.
  */
 
-#include <aidl/Vintf.h>
 #define LOG_TAG "VtsHalDownmixTargetTest"
 #include <android-base/logging.h>
 
+#include <audio_utils/ChannelMix.h>
 #include "EffectHelper.h"
 
 using namespace android;
 
+using aidl::android::hardware::audio::common::getChannelCount;
 using aidl::android::hardware::audio::effect::Descriptor;
 using aidl::android::hardware::audio::effect::Downmix;
 using aidl::android::hardware::audio::effect::getEffectTypeUuidDownmix;
 using aidl::android::hardware::audio::effect::IEffect;
 using aidl::android::hardware::audio::effect::IFactory;
 using aidl::android::hardware::audio::effect::Parameter;
+using android::audio_utils::channels::ChannelMix;
+using android::hardware::audio::common::testing::detail::TestExecutionTracer;
 
-/**
- * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
- * VtsAudioEffectTargetTest.
- */
-enum ParamName { PARAM_INSTANCE_NAME, PARAM_TYPE };
-using DownmixParamTestParam =
-        std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, Downmix::Type>;
+// minimal HAL interface version to run downmix data path test
+constexpr int32_t kMinDataTestHalVersion = 2;
 
 // Testing for enum values
-const std::vector<Downmix::Type> kTypeValues = {Downmix::Type::STRIP, Downmix::Type::FOLD};
+static const std::vector<Downmix::Type> kTypeValues = {ndk::enum_range<Downmix::Type>().begin(),
+                                                       ndk::enum_range<Downmix::Type>().end()};
 
-class DownmixParamTest : public ::testing::TestWithParam<DownmixParamTestParam>,
-                         public EffectHelper {
+// Testing for supported layouts from AudioChannelLayout.h
+static const std::vector<int32_t> kLayoutValues = {
+        AudioChannelLayout::LAYOUT_STEREO,        AudioChannelLayout::LAYOUT_2POINT1,
+        AudioChannelLayout::LAYOUT_TRI,           AudioChannelLayout::LAYOUT_TRI_BACK,
+        AudioChannelLayout::LAYOUT_3POINT1,       AudioChannelLayout::LAYOUT_2POINT0POINT2,
+        AudioChannelLayout::LAYOUT_2POINT1POINT2, AudioChannelLayout::LAYOUT_3POINT0POINT2,
+        AudioChannelLayout::LAYOUT_3POINT1POINT2, AudioChannelLayout::LAYOUT_QUAD,
+        AudioChannelLayout::LAYOUT_QUAD_SIDE,     AudioChannelLayout::LAYOUT_SURROUND,
+        AudioChannelLayout::LAYOUT_PENTA,         AudioChannelLayout::LAYOUT_5POINT1,
+        AudioChannelLayout::LAYOUT_5POINT1_SIDE,  AudioChannelLayout::LAYOUT_5POINT1POINT2,
+        AudioChannelLayout::LAYOUT_5POINT1POINT4, AudioChannelLayout::LAYOUT_6POINT1,
+        AudioChannelLayout::LAYOUT_7POINT1,       AudioChannelLayout::LAYOUT_7POINT1POINT2,
+        AudioChannelLayout::LAYOUT_7POINT1POINT4, AudioChannelLayout::LAYOUT_9POINT1POINT4,
+        AudioChannelLayout::LAYOUT_9POINT1POINT6, AudioChannelLayout::LAYOUT_13POINT_360RA,
+        AudioChannelLayout::LAYOUT_22POINT2};
+
+static const std::vector<int32_t> kChannels = {
+        AudioChannelLayout::CHANNEL_FRONT_LEFT,
+        AudioChannelLayout::CHANNEL_FRONT_RIGHT,
+        AudioChannelLayout::CHANNEL_FRONT_CENTER,
+        AudioChannelLayout::CHANNEL_LOW_FREQUENCY,
+        AudioChannelLayout::CHANNEL_BACK_LEFT,
+        AudioChannelLayout::CHANNEL_BACK_RIGHT,
+        AudioChannelLayout::CHANNEL_BACK_CENTER,
+        AudioChannelLayout::CHANNEL_SIDE_LEFT,
+        AudioChannelLayout::CHANNEL_SIDE_RIGHT,
+        AudioChannelLayout::CHANNEL_FRONT_LEFT_OF_CENTER,
+        AudioChannelLayout::CHANNEL_FRONT_RIGHT_OF_CENTER,
+        AudioChannelLayout::CHANNEL_TOP_CENTER,
+        AudioChannelLayout::CHANNEL_TOP_FRONT_LEFT,
+        AudioChannelLayout::CHANNEL_TOP_FRONT_CENTER,
+        AudioChannelLayout::CHANNEL_TOP_FRONT_RIGHT,
+        AudioChannelLayout::CHANNEL_TOP_BACK_LEFT,
+        AudioChannelLayout::CHANNEL_TOP_BACK_CENTER,
+        AudioChannelLayout::CHANNEL_TOP_BACK_RIGHT,
+        AudioChannelLayout::CHANNEL_TOP_SIDE_LEFT,
+        AudioChannelLayout::CHANNEL_TOP_SIDE_RIGHT,
+        AudioChannelLayout::CHANNEL_BOTTOM_FRONT_LEFT,
+        AudioChannelLayout::CHANNEL_BOTTOM_FRONT_CENTER,
+        AudioChannelLayout::CHANNEL_BOTTOM_FRONT_RIGHT,
+        AudioChannelLayout::CHANNEL_LOW_FREQUENCY_2,
+        AudioChannelLayout::CHANNEL_FRONT_WIDE_LEFT,
+        AudioChannelLayout::CHANNEL_FRONT_WIDE_RIGHT,
+};
+
+class DownmixEffectHelper : public EffectHelper {
   public:
-    DownmixParamTest() : mParamType(std::get<PARAM_TYPE>(GetParam())) {
-        std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
-    }
-
-    void SetUp() override {
+    void SetUpDownmix(int32_t inputBufferLayout = AudioChannelLayout::LAYOUT_STEREO) {
         ASSERT_NE(nullptr, mFactory);
         ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
+        AudioChannelLayout inputChannelLayout =
+                AudioChannelLayout::make<AudioChannelLayout::layoutMask>(inputBufferLayout);
+
         Parameter::Specific specific = getDefaultParamSpecific();
         Parameter::Common common = EffectHelper::createParamCommon(
                 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
-                kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
-        IEffect::OpenEffectReturn ret;
-        ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &ret, EX_NONE));
+                kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */,
+                inputChannelLayout);
+        ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &mOpenEffectReturn, EX_NONE));
         ASSERT_NE(nullptr, mEffect);
     }
 
-    void TearDown() override {
+    void TearDownDownmix() {
         ASSERT_NO_FATAL_FAILURE(close(mEffect));
         ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+        mOpenEffectReturn = IEffect::OpenEffectReturn{};
     }
 
-    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
-    std::shared_ptr<IFactory> mFactory;
-    std::shared_ptr<IEffect> mEffect;
-    Descriptor mDescriptor;
-    Downmix::Type mParamType = Downmix::Type::STRIP;
-
-    void SetAndGetDownmixParameters() {
-        for (auto& it : mTags) {
-            auto& tag = it.first;
-            auto& dm = it.second;
-
-            // set parameter
-            Parameter expectParam;
-            Parameter::Specific specific;
-            specific.set<Parameter::Specific::downmix>(dm);
-            expectParam.set<Parameter::specific>(specific);
-            // All values are valid, set parameter should succeed
-            EXPECT_STATUS(EX_NONE, mEffect->setParameter(expectParam)) << expectParam.toString();
-
-            // get parameter
-            Parameter getParam;
-            Parameter::Id id;
-            Downmix::Id dmId;
-            dmId.set<Downmix::Id::commonTag>(tag);
-            id.set<Parameter::Id::downmixTag>(dmId);
-            EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam));
-
-            EXPECT_EQ(expectParam, getParam);
-        }
+    Parameter createDownmixParam(Downmix::Type type) {
+        return Parameter::make<Parameter::specific>(
+                Parameter::Specific::make<Parameter::Specific::downmix>(
+                        Downmix::make<Downmix::type>(type)));
+    }
+    void setParameters(Downmix::Type type) {
+        // set parameter
+        auto param = createDownmixParam(type);
+        EXPECT_STATUS(EX_NONE, mEffect->setParameter(param)) << param.toString();
     }
 
-    void addTypeParam(Downmix::Type type) {
-        Downmix dm;
-        dm.set<Downmix::type>(type);
-        mTags.push_back({Downmix::type, dm});
+    void validateParameters(Downmix::Type type) {
+        auto leId = Downmix::Id::make<Downmix::Id::commonTag>(Downmix::Tag(Downmix::type));
+        auto id = Parameter::Id::make<Parameter::Id::downmixTag>(leId);
+        // get parameter
+        Parameter getParam;
+        EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam));
+        auto expectedParam = createDownmixParam(type);
+        EXPECT_EQ(expectedParam, getParam) << "\nexpectedParam:" << expectedParam.toString()
+                                           << "\ngetParam:" << getParam.toString();
     }
 
     Parameter::Specific getDefaultParamSpecific() {
@@ -108,14 +136,286 @@
         return specific;
     }
 
-  private:
-    std::vector<std::pair<Downmix::Tag, Downmix>> mTags;
-    void CleanUp() { mTags.clear(); }
+    void setDataTestParams(int32_t layoutType) {
+        mInputBuffer.resize(kBufferSize);
+
+        // Get the number of channels used
+        mInputChannelCount = getChannelCount(
+                AudioChannelLayout::make<AudioChannelLayout::layoutMask>(layoutType));
+
+        // In case of downmix, output is always configured to stereo layout.
+        mOutputBufferSize = (mInputBuffer.size() / mInputChannelCount) * kOutputChannelCount;
+        mOutputBuffer.resize(mOutputBufferSize);
+    }
+
+    // Generate mInputBuffer values between -kMaxDownmixSample to kMaxDownmixSample
+    void generateInputBuffer(size_t position, bool isStrip) {
+        size_t increment;
+        if (isStrip)
+            // Fill input at all the channels
+            increment = 1;
+        else
+            // Fill input at only one channel
+            increment = mInputChannelCount;
+
+        for (size_t i = position; i < mInputBuffer.size(); i += increment) {
+            mInputBuffer[i] =
+                    ((static_cast<float>(std::rand()) / RAND_MAX) * 2 - 1) * kMaxDownmixSample;
+        }
+    }
+
+    bool isLayoutValid(int32_t inputLayout) {
+        if (inputLayout & kMaxChannelMask) {
+            return false;
+        }
+        return true;
+    }
+
+    static constexpr long kInputFrameCount = 100, kOutputFrameCount = 100;
+    std::shared_ptr<IFactory> mFactory;
+    Descriptor mDescriptor;
+    std::shared_ptr<IEffect> mEffect;
+    IEffect::OpenEffectReturn mOpenEffectReturn;
+
+    std::vector<float> mInputBuffer;
+    std::vector<float> mOutputBuffer;
+    size_t mInputChannelCount;
+    size_t mOutputBufferSize;
+    static constexpr size_t kBufferSize = 128;
+    static constexpr float kMaxDownmixSample = 1;
+    static constexpr int kOutputChannelCount = 2;
+    // Mask for layouts greater than MAX_INPUT_CHANNELS_SUPPORTED
+    static constexpr int32_t kMaxChannelMask =
+            ~((1 << ChannelMix<AUDIO_CHANNEL_OUT_STEREO>::MAX_INPUT_CHANNELS_SUPPORTED) - 1);
+};
+
+/**
+ * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
+ * VtsAudioEffectTargetTest.
+ */
+enum ParamName { PARAM_INSTANCE_NAME, PARAM_TYPE };
+
+using DownmixParamTestParam =
+        std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, Downmix::Type>;
+
+class DownmixParamTest : public ::testing::TestWithParam<DownmixParamTestParam>,
+                         public DownmixEffectHelper {
+  public:
+    DownmixParamTest() : mParamType(std::get<PARAM_TYPE>(GetParam())) {
+        std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+    }
+
+    void SetUp() override { SetUpDownmix(); }
+
+    void TearDown() override { TearDownDownmix(); }
+
+    const Downmix::Type mParamType;
 };
 
 TEST_P(DownmixParamTest, SetAndGetType) {
-    EXPECT_NO_FATAL_FAILURE(addTypeParam(mParamType));
-    SetAndGetDownmixParameters();
+    ASSERT_NO_FATAL_FAILURE(setParameters(mParamType));
+    ASSERT_NO_FATAL_FAILURE(validateParameters(mParamType));
+}
+
+enum FoldParamName { FOLD_INSTANCE_NAME, FOLD_INPUT_LAYOUT, FOLD_TEST_CHANNEL };
+
+using DownmixDataTestParamFold =
+        std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int32_t>;
+
+class DownmixFoldDataTest : public ::testing::TestWithParam<DownmixDataTestParamFold>,
+                            public DownmixEffectHelper {
+  public:
+    DownmixFoldDataTest() : mInputChannelLayout(std::get<FOLD_INPUT_LAYOUT>(GetParam())) {
+        std::tie(mFactory, mDescriptor) = std::get<FOLD_INSTANCE_NAME>(GetParam());
+    }
+
+    void SetUp() override {
+        SetUpDownmix(mInputChannelLayout);
+        if (int32_t version;
+            mEffect->getInterfaceVersion(&version).isOk() && version < kMinDataTestHalVersion) {
+            GTEST_SKIP() << "Skipping the data test for version: " << version << "\n";
+        }
+        if (!isLayoutValid(mInputChannelLayout)) {
+            GTEST_SKIP() << "Layout not supported \n";
+        }
+        setDataTestParams(mInputChannelLayout);
+    }
+
+    void TearDown() override { TearDownDownmix(); }
+
+    void checkAtLeft(int32_t position) {
+        for (size_t i = 0, j = position; i < mOutputBufferSize;
+             i += kOutputChannelCount, j += mInputChannelCount) {
+            // Validate Left channel has audio
+            if (mInputBuffer[j] != 0) {
+                ASSERT_NE(mOutputBuffer[i], 0);
+            } else {
+                // No change in output when input is 0
+                ASSERT_EQ(mOutputBuffer[i], mInputBuffer[j]);
+            }
+            // Validate Right channel has no audio
+            ASSERT_EQ(mOutputBuffer[i + 1], 0);
+        }
+    }
+
+    void checkAtRight(int32_t position) {
+        for (size_t i = 0, j = position; i < mOutputBufferSize;
+             i += kOutputChannelCount, j += mInputChannelCount) {
+            // Validate Left channel has no audio
+            ASSERT_EQ(mOutputBuffer[i], 0) << " at " << i;
+            // Validate Right channel has audio
+            if (mInputBuffer[j] != 0) {
+                ASSERT_NE(mOutputBuffer[i + 1], 0) << " at " << i;
+            } else {
+                // No change in output when input is 0
+                ASSERT_EQ(mOutputBuffer[i + 1], mInputBuffer[j]) << " at " << i;
+            }
+        }
+    }
+
+    void checkAtCenter(size_t position) {
+        for (size_t i = 0, j = position; i < mOutputBufferSize;
+             i += kOutputChannelCount, j += mInputChannelCount) {
+            // Validate both channels have audio
+            if (mInputBuffer[j] != 0) {
+                ASSERT_NE(mOutputBuffer[i], 0);
+                ASSERT_NE(mOutputBuffer[i + 1], 0);
+
+            } else {
+                // No change in output when input is 0
+                ASSERT_EQ(mOutputBuffer[i], mInputBuffer[j]);
+                ASSERT_EQ(mOutputBuffer[i + 1], mInputBuffer[j]);
+            }
+        }
+    }
+
+    void validateOutput(int32_t channel, size_t position) {
+        switch (channel) {
+            case AudioChannelLayout::CHANNEL_FRONT_LEFT:
+            case AudioChannelLayout::CHANNEL_BACK_LEFT:
+            case AudioChannelLayout::CHANNEL_SIDE_LEFT:
+            case AudioChannelLayout::CHANNEL_TOP_FRONT_LEFT:
+            case AudioChannelLayout::CHANNEL_BOTTOM_FRONT_LEFT:
+            case AudioChannelLayout::CHANNEL_TOP_BACK_LEFT:
+            case AudioChannelLayout::CHANNEL_FRONT_WIDE_LEFT:
+            case AudioChannelLayout::CHANNEL_TOP_SIDE_LEFT:
+                checkAtLeft(position);
+                break;
+
+            case AudioChannelLayout::CHANNEL_FRONT_RIGHT:
+            case AudioChannelLayout::CHANNEL_BACK_RIGHT:
+            case AudioChannelLayout::CHANNEL_SIDE_RIGHT:
+            case AudioChannelLayout::CHANNEL_TOP_FRONT_RIGHT:
+            case AudioChannelLayout::CHANNEL_BOTTOM_FRONT_RIGHT:
+            case AudioChannelLayout::CHANNEL_TOP_BACK_RIGHT:
+            case AudioChannelLayout::CHANNEL_FRONT_WIDE_RIGHT:
+            case AudioChannelLayout::CHANNEL_TOP_SIDE_RIGHT:
+            case AudioChannelLayout::CHANNEL_LOW_FREQUENCY_2:
+                checkAtRight(position);
+                break;
+
+            case AudioChannelLayout::CHANNEL_FRONT_CENTER:
+            case AudioChannelLayout::CHANNEL_BACK_CENTER:
+            case AudioChannelLayout::CHANNEL_TOP_FRONT_CENTER:
+            case AudioChannelLayout::CHANNEL_BOTTOM_FRONT_CENTER:
+            case AudioChannelLayout::CHANNEL_FRONT_LEFT_OF_CENTER:
+            case AudioChannelLayout::CHANNEL_FRONT_RIGHT_OF_CENTER:
+            case AudioChannelLayout::CHANNEL_TOP_CENTER:
+            case AudioChannelLayout::CHANNEL_TOP_BACK_CENTER:
+                checkAtCenter(position);
+                break;
+
+            case AudioChannelLayout::CHANNEL_LOW_FREQUENCY:
+                // If CHANNEL_LOW_FREQUENCY_2 is supported
+                if (mInputChannelLayout & AudioChannelLayout::CHANNEL_LOW_FREQUENCY_2) {
+                    // Validate that only Left channel has audio
+                    checkAtLeft(position);
+                } else {
+                    // Validate that both channels have audio
+                    checkAtCenter(position);
+                }
+                break;
+        }
+    }
+
+    std::set<int32_t> getInputChannelLayouts() {
+        std::set<int32_t> supportedChannels;
+        for (int32_t channel : kChannels) {
+            if ((mInputChannelLayout & channel) == channel) {
+                supportedChannels.insert(channel);
+            }
+        }
+        return supportedChannels;
+    }
+
+    int32_t mInputChannelLayout;
+};
+
+TEST_P(DownmixFoldDataTest, DownmixProcessData) {
+    // Set FOLD type parameter
+    ASSERT_NO_FATAL_FAILURE(setParameters(Downmix::Type::FOLD));
+
+    // Get all the channels from input layout
+    std::set<int32_t> supportedChannels = getInputChannelLayouts();
+
+    for (int32_t channel : supportedChannels) {
+        size_t position = std::distance(supportedChannels.begin(), supportedChannels.find(channel));
+        generateInputBuffer(position, false /*isStripe*/);
+        ASSERT_NO_FATAL_FAILURE(
+                processAndWriteToOutput(mInputBuffer, mOutputBuffer, mEffect, &mOpenEffectReturn));
+        validateOutput(channel, position);
+        std::fill(mInputBuffer.begin(), mInputBuffer.end(), 0);
+    }
+}
+
+enum StripParamName { STRIP_INSTANCE_NAME, STRIP_INPUT_LAYOUT };
+
+using DownmixStripDataTestParam =
+        std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int32_t>;
+
+class DownmixStripDataTest : public ::testing::TestWithParam<DownmixStripDataTestParam>,
+                             public DownmixEffectHelper {
+  public:
+    DownmixStripDataTest() : mInputChannelLayout(std::get<STRIP_INPUT_LAYOUT>(GetParam())) {
+        std::tie(mFactory, mDescriptor) = std::get<STRIP_INSTANCE_NAME>(GetParam());
+    }
+
+    void SetUp() override {
+        SetUpDownmix(mInputChannelLayout);
+        if (int32_t version;
+            mEffect->getInterfaceVersion(&version).isOk() && version < kMinDataTestHalVersion) {
+            GTEST_SKIP() << "Skipping the data test for version: " << version << "\n";
+        }
+        if (!isLayoutValid(mInputChannelLayout)) {
+            GTEST_SKIP() << "Layout not supported \n";
+        }
+        setDataTestParams(mInputChannelLayout);
+    }
+
+    void TearDown() override { TearDownDownmix(); }
+
+    void validateOutput() {
+        ASSERT_EQ(kBufferSize, mInputBuffer.size());
+        ASSERT_GE(kBufferSize, mOutputBufferSize);
+        for (size_t i = 0, j = 0; i < kBufferSize && j < mOutputBufferSize;
+             i += mInputChannelCount, j += kOutputChannelCount) {
+            ASSERT_EQ(mOutputBuffer[j], mInputBuffer[i]);
+            ASSERT_EQ(mOutputBuffer[j + 1], mInputBuffer[i + 1]);
+        }
+    }
+
+    int32_t mInputChannelLayout;
+};
+
+TEST_P(DownmixStripDataTest, DownmixProcessData) {
+    // Set STRIP type parameter
+    ASSERT_NO_FATAL_FAILURE(setParameters(Downmix::Type::STRIP));
+
+    // Generate input buffer, call process and compare outputs
+    generateInputBuffer(0 /*position*/, true /*isStripe*/);
+    ASSERT_NO_FATAL_FAILURE(
+            processAndWriteToOutput(mInputBuffer, mOutputBuffer, mEffect, &mOpenEffectReturn));
+    validateOutput();
 }
 
 INSTANTIATE_TEST_SUITE_P(
@@ -126,7 +426,7 @@
         [](const testing::TestParamInfo<DownmixParamTest::ParamType>& info) {
             auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
             std::string type = std::to_string(static_cast<int>(std::get<PARAM_TYPE>(info.param)));
-            std::string name = getPrefix(descriptor) + "_type" + type;
+            std::string name = getPrefix(descriptor) + "_type_" + type;
             std::replace_if(
                     name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
             return name;
@@ -134,8 +434,42 @@
 
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DownmixParamTest);
 
+INSTANTIATE_TEST_SUITE_P(
+        DownmixTest, DownmixFoldDataTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, getEffectTypeUuidDownmix())),
+                           testing::ValuesIn(kLayoutValues)),
+        [](const testing::TestParamInfo<DownmixFoldDataTest::ParamType>& info) {
+            auto descriptor = std::get<FOLD_INSTANCE_NAME>(info.param).second;
+            std::string layout = std::to_string(std::get<FOLD_INPUT_LAYOUT>(info.param));
+            std::string name = getPrefix(descriptor) + "_fold_layout_" + layout;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DownmixFoldDataTest);
+
+INSTANTIATE_TEST_SUITE_P(
+        DownmixTest, DownmixStripDataTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, getEffectTypeUuidDownmix())),
+                           testing::ValuesIn(kLayoutValues)),
+        [](const testing::TestParamInfo<DownmixStripDataTest::ParamType>& info) {
+            auto descriptor = std::get<STRIP_INSTANCE_NAME>(info.param).second;
+            std::string layout =
+                    std::to_string(static_cast<int>(std::get<STRIP_INPUT_LAYOUT>(info.param)));
+            std::string name = getPrefix(descriptor) + "_strip_layout_" + layout;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DownmixStripDataTest);
+
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
+    ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
     ABinderProcess_setThreadPoolMaxThreadCount(1);
     ABinderProcess_startThreadPool();
     return RUN_ALL_TESTS();
diff --git a/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp b/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp
index 5509c76..3f7a76d 100644
--- a/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp
+++ b/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp
@@ -18,7 +18,6 @@
 #include <string>
 #include <unordered_set>
 
-#include <aidl/Vintf.h>
 #define LOG_TAG "VtsHalDynamicsProcessingTest"
 #include <android-base/logging.h>
 
@@ -36,6 +35,7 @@
 using aidl::android::hardware::audio::effect::IEffect;
 using aidl::android::hardware::audio::effect::IFactory;
 using aidl::android::hardware::audio::effect::Parameter;
+using android::hardware::audio::common::testing::detail::TestExecutionTracer;
 
 /**
  * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
@@ -996,6 +996,7 @@
 
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
+    ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
     ABinderProcess_setThreadPoolMaxThreadCount(1);
     ABinderProcess_startThreadPool();
     return RUN_ALL_TESTS();
diff --git a/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp b/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp
index f2ef185..765c377 100644
--- a/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include <aidl/Vintf.h>
 #define LOG_TAG "VtsHalEnvironmentalReverbTest"
 #include <android-base/logging.h>
 
@@ -28,6 +27,7 @@
 using aidl::android::hardware::audio::effect::IEffect;
 using aidl::android::hardware::audio::effect::IFactory;
 using aidl::android::hardware::audio::effect::Parameter;
+using android::hardware::audio::common::testing::detail::TestExecutionTracer;
 
 /**
  * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
@@ -536,6 +536,7 @@
 
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
+    ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
     ABinderProcess_setThreadPoolMaxThreadCount(1);
     ABinderProcess_startThreadPool();
     return RUN_ALL_TESTS();
diff --git a/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp b/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp
index 37e7c0a..76838cef 100644
--- a/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp
@@ -15,15 +15,10 @@
  */
 
 #include <algorithm>
-#include <limits>
-#include <map>
-#include <memory>
-#include <optional>
 #include <string>
 #include <vector>
 
 #include <aidl/Gtest.h>
-#include <aidl/Vintf.h>
 #include <aidl/android/hardware/audio/effect/IEffect.h>
 #include <aidl/android/hardware/audio/effect/IFactory.h>
 #define LOG_TAG "VtsHalEqualizerTest"
@@ -46,6 +41,7 @@
 using aidl::android::hardware::audio::effect::IEffect;
 using aidl::android::hardware::audio::effect::IFactory;
 using aidl::android::hardware::audio::effect::Parameter;
+using android::hardware::audio::common::testing::detail::TestExecutionTracer;
 
 /**
  * Here we focus on specific effect (equalizer) parameter checking, general IEffect interfaces
@@ -220,6 +216,7 @@
 
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
+    ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
     ABinderProcess_setThreadPoolMaxThreadCount(1);
     ABinderProcess_startThreadPool();
     return RUN_ALL_TESTS();
diff --git a/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp b/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp
index b33234b..d312111 100644
--- a/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp
@@ -18,7 +18,6 @@
 #include <utility>
 #include <vector>
 
-#include <aidl/Vintf.h>
 #define LOG_TAG "VtsHalHapticGeneratorTargetTest"
 #include <android-base/logging.h>
 #include <android/binder_enums.h>
@@ -33,6 +32,7 @@
 using aidl::android::hardware::audio::effect::IEffect;
 using aidl::android::hardware::audio::effect::IFactory;
 using aidl::android::hardware::audio::effect::Parameter;
+using android::hardware::audio::common::testing::detail::TestExecutionTracer;
 
 /**
  * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
@@ -431,6 +431,7 @@
 
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
+    ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
     ABinderProcess_setThreadPoolMaxThreadCount(1);
     ABinderProcess_startThreadPool();
     return RUN_ALL_TESTS();
diff --git a/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp b/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp
index cbb80a9..7f0091f 100644
--- a/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp
@@ -16,7 +16,6 @@
 
 #include <string>
 
-#include <aidl/Vintf.h>
 #define LOG_TAG "VtsHalLoudnessEnhancerTest"
 #include <android-base/logging.h>
 
@@ -30,28 +29,21 @@
 using aidl::android::hardware::audio::effect::IFactory;
 using aidl::android::hardware::audio::effect::LoudnessEnhancer;
 using aidl::android::hardware::audio::effect::Parameter;
+using android::hardware::audio::common::testing::detail::TestExecutionTracer;
 
-/**
- * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
- * VtsAudioEffectTargetTest.
- */
-enum ParamName { PARAM_INSTANCE_NAME, PARAM_GAIN_MB };
-using LoudnessEnhancerParamTestParam =
-        std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>;
+static constexpr float kMaxAudioSample = 1;
+static constexpr int kZeroGain = 0;
+static constexpr int kMaxGain = std::numeric_limits<int>::max();
+static constexpr int kMinGain = std::numeric_limits<int>::min();
+static constexpr float kAbsError = 0.0001;
 
 // Every int 32 bit value is a valid gain, so testing the corner cases and one regular value.
 // TODO : Update the test values once range/capability is updated by implementation.
-const std::vector<int> kGainMbValues = {std::numeric_limits<int>::min(), 100,
-                                        std::numeric_limits<int>::max()};
+static const std::vector<int> kGainMbValues = {kMinGain, -100, -50, kZeroGain, 50, 100, kMaxGain};
 
-class LoudnessEnhancerParamTest : public ::testing::TestWithParam<LoudnessEnhancerParamTestParam>,
-                                  public EffectHelper {
+class LoudnessEnhancerEffectHelper : public EffectHelper {
   public:
-    LoudnessEnhancerParamTest() : mParamGainMb(std::get<PARAM_GAIN_MB>(GetParam())) {
-        std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
-    }
-
-    void SetUp() override {
+    void SetUpLoudnessEnhancer() {
         ASSERT_NE(nullptr, mFactory);
         ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
@@ -59,13 +51,14 @@
         Parameter::Common common = EffectHelper::createParamCommon(
                 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
                 kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
-        IEffect::OpenEffectReturn ret;
-        ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &ret, EX_NONE));
+        ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &mOpenEffectReturn, EX_NONE));
         ASSERT_NE(nullptr, mEffect);
     }
-    void TearDown() override {
+
+    void TearDownLoudnessEnhancer() {
         ASSERT_NO_FATAL_FAILURE(close(mEffect));
         ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+        mOpenEffectReturn = IEffect::OpenEffectReturn{};
     }
 
     Parameter::Specific getDefaultParamSpecific() {
@@ -75,52 +68,230 @@
         return specific;
     }
 
-    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
-    std::shared_ptr<IFactory> mFactory;
-    std::shared_ptr<IEffect> mEffect;
-    Descriptor mDescriptor;
-    int mParamGainMb = 0;
+    Parameter createLoudnessParam(int gainMb) {
+        LoudnessEnhancer le;
+        le.set<LoudnessEnhancer::gainMb>(gainMb);
+        Parameter param;
+        Parameter::Specific specific;
+        specific.set<Parameter::Specific::loudnessEnhancer>(le);
+        param.set<Parameter::specific>(specific);
+        return param;
+    }
 
-    void SetAndGetParameters() {
-        for (auto& it : mTags) {
-            auto& tag = it.first;
-            auto& le = it.second;
-
-            // set parameter
-            Parameter expectParam;
-            Parameter::Specific specific;
-            specific.set<Parameter::Specific::loudnessEnhancer>(le);
-            expectParam.set<Parameter::specific>(specific);
-            // All values are valid, set parameter should succeed
-            EXPECT_STATUS(EX_NONE, mEffect->setParameter(expectParam)) << expectParam.toString();
-
-            // get parameter
-            Parameter getParam;
-            Parameter::Id id;
-            LoudnessEnhancer::Id leId;
-            leId.set<LoudnessEnhancer::Id::commonTag>(tag);
-            id.set<Parameter::Id::loudnessEnhancerTag>(leId);
-            EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam));
-
-            EXPECT_EQ(expectParam, getParam) << "\nexpect:" << expectParam.toString()
-                                             << "\ngetParam:" << getParam.toString();
+    binder_exception_t isGainValid(int gainMb) {
+        LoudnessEnhancer le;
+        le.set<LoudnessEnhancer::gainMb>(gainMb);
+        if (isParameterValid<LoudnessEnhancer, Range::loudnessEnhancer>(le, mDescriptor)) {
+            return EX_NONE;
+        } else {
+            return EX_ILLEGAL_ARGUMENT;
         }
     }
 
-    void addGainMbParam(int gainMb) {
-        LoudnessEnhancer le;
-        le.set<LoudnessEnhancer::gainMb>(gainMb);
-        mTags.push_back({LoudnessEnhancer::gainMb, le});
+    void setParameters(int gain, binder_exception_t expected) {
+        // set parameter
+        auto param = createLoudnessParam(gain);
+        EXPECT_STATUS(expected, mEffect->setParameter(param)) << param.toString();
     }
 
-  private:
-    std::vector<std::pair<LoudnessEnhancer::Tag, LoudnessEnhancer>> mTags;
-    void CleanUp() { mTags.clear(); }
+    void validateParameters(int gain) {
+        // get parameter
+        LoudnessEnhancer::Id leId;
+        Parameter getParam;
+        Parameter::Id id;
+
+        LoudnessEnhancer::Tag tag(LoudnessEnhancer::gainMb);
+        leId.set<LoudnessEnhancer::Id::commonTag>(tag);
+        id.set<Parameter::Id::loudnessEnhancerTag>(leId);
+        EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam));
+        auto expectedParam = createLoudnessParam(gain);
+        EXPECT_EQ(expectedParam, getParam) << "\nexpectedParam:" << expectedParam.toString()
+                                           << "\ngetParam:" << getParam.toString();
+    }
+
+    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+    IEffect::OpenEffectReturn mOpenEffectReturn;
+    std::shared_ptr<IFactory> mFactory;
+    std::shared_ptr<IEffect> mEffect;
+    Descriptor mDescriptor;
+};
+
+/**
+ * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
+ * VtsAudioEffectTargetTest.
+ */
+enum ParamName { PARAM_INSTANCE_NAME, PARAM_GAIN_MB };
+using LoudnessEnhancerParamTestParam =
+        std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>;
+
+class LoudnessEnhancerParamTest : public ::testing::TestWithParam<LoudnessEnhancerParamTestParam>,
+                                  public LoudnessEnhancerEffectHelper {
+  public:
+    LoudnessEnhancerParamTest() : mParamGainMb(std::get<PARAM_GAIN_MB>(GetParam())) {
+        std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+    }
+
+    void SetUp() override { SetUpLoudnessEnhancer(); }
+    void TearDown() override { TearDownLoudnessEnhancer(); }
+    int mParamGainMb = 0;
 };
 
 TEST_P(LoudnessEnhancerParamTest, SetAndGetGainMb) {
-    EXPECT_NO_FATAL_FAILURE(addGainMbParam(mParamGainMb));
-    SetAndGetParameters();
+    binder_exception_t expected = isGainValid(mParamGainMb);
+    setParameters(mParamGainMb, expected);
+    if (expected == EX_NONE) {
+        validateParameters(mParamGainMb);
+    }
+}
+
+using LoudnessEnhancerDataTestParam = std::pair<std::shared_ptr<IFactory>, Descriptor>;
+
+class LoudnessEnhancerDataTest : public ::testing::TestWithParam<LoudnessEnhancerDataTestParam>,
+                                 public LoudnessEnhancerEffectHelper {
+  public:
+    LoudnessEnhancerDataTest() {
+        std::tie(mFactory, mDescriptor) = GetParam();
+        generateInputBuffer();
+        mOutputBuffer.resize(kBufferSize);
+    }
+
+    void SetUp() override {
+        SetUpLoudnessEnhancer();
+
+        // Creating AidlMessageQueues
+        mStatusMQ = std::make_unique<EffectHelper::StatusMQ>(mOpenEffectReturn.statusMQ);
+        mInputMQ = std::make_unique<EffectHelper::DataMQ>(mOpenEffectReturn.inputDataMQ);
+        mOutputMQ = std::make_unique<EffectHelper::DataMQ>(mOpenEffectReturn.outputDataMQ);
+    }
+
+    void TearDown() override { TearDownLoudnessEnhancer(); }
+
+    // Fill inputBuffer with random values between -kMaxAudioSample to kMaxAudioSample
+    void generateInputBuffer() {
+        for (size_t i = 0; i < kBufferSize; i++) {
+            mInputBuffer.push_back(((static_cast<float>(std::rand()) / RAND_MAX) * 2 - 1) *
+                                   kMaxAudioSample);
+        }
+    }
+
+    // Add gains to the mInputBuffer and store processed output to mOutputBuffer
+    void processAndWriteToOutput() {
+        // Check AidlMessageQueues are not null
+        ASSERT_TRUE(mStatusMQ->isValid());
+        ASSERT_TRUE(mInputMQ->isValid());
+        ASSERT_TRUE(mOutputMQ->isValid());
+
+        // Enabling the process
+        ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+        ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+
+        // Write from buffer to message queues and calling process
+        EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(mStatusMQ, mInputMQ, mInputBuffer));
+
+        // Read the updated message queues into buffer
+        EXPECT_NO_FATAL_FAILURE(EffectHelper::readFromFmq(mStatusMQ, 1, mOutputMQ,
+                                                          mOutputBuffer.size(), mOutputBuffer));
+
+        // Disable the process
+        ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+    }
+
+    void assertGreaterGain(const std::vector<float>& first, const std::vector<float>& second) {
+        for (size_t i = 0; i < first.size(); i++) {
+            if (first[i] != 0) {
+                ASSERT_GT(abs(first[i]), abs(second[i]));
+
+            } else {
+                ASSERT_EQ(first[i], second[i]);
+            }
+        }
+    }
+
+    void assertSequentialGains(const std::vector<int>& gainValues, bool isIncreasing) {
+        std::vector<float> baseOutput(kBufferSize);
+
+        // Process a reference output buffer with 0 gain which gives compressed input values
+        binder_exception_t expected;
+        expected = isGainValid(kZeroGain);
+        ASSERT_EQ(expected, EX_NONE);
+        setParameters(kZeroGain, expected);
+        ASSERT_NO_FATAL_FAILURE(processAndWriteToOutput());
+        baseOutput = mOutputBuffer;
+
+        // Compare the outputs for increasing gain
+        for (int gain : gainValues) {
+            // Setting the parameters
+            binder_exception_t expected = isGainValid(gain);
+            if (expected != EX_NONE) {
+                GTEST_SKIP() << "Gains not supported.";
+            }
+            setParameters(gain, expected);
+            ASSERT_NO_FATAL_FAILURE(processAndWriteToOutput());
+
+            // Compare the mOutputBuffer values with baseOutput and update it
+            if (isIncreasing) {
+                ASSERT_NO_FATAL_FAILURE(assertGreaterGain(mOutputBuffer, baseOutput));
+            } else {
+                ASSERT_NO_FATAL_FAILURE(assertGreaterGain(baseOutput, mOutputBuffer));
+            }
+
+            baseOutput = mOutputBuffer;
+        }
+    }
+
+    std::unique_ptr<StatusMQ> mStatusMQ;
+    std::unique_ptr<DataMQ> mInputMQ;
+    std::unique_ptr<DataMQ> mOutputMQ;
+
+    std::vector<float> mInputBuffer;
+    std::vector<float> mOutputBuffer;
+    static constexpr float kBufferSize = 128;
+};
+
+TEST_P(LoudnessEnhancerDataTest, IncreasingGains) {
+    static const std::vector<int> kIncreasingGains = {50, 100};
+
+    assertSequentialGains(kIncreasingGains, true /*isIncreasing*/);
+}
+
+TEST_P(LoudnessEnhancerDataTest, DecreasingGains) {
+    static const std::vector<int> kDecreasingGains = {-50, -100};
+
+    assertSequentialGains(kDecreasingGains, false /*isIncreasing*/);
+}
+
+TEST_P(LoudnessEnhancerDataTest, MinimumGain) {
+    // Setting the parameters
+    binder_exception_t expected = isGainValid(kMinGain);
+    if (expected != EX_NONE) {
+        GTEST_SKIP() << "Minimum integer value not supported";
+    }
+    setParameters(kMinGain, expected);
+    ASSERT_NO_FATAL_FAILURE(processAndWriteToOutput());
+
+    // Validate that mOutputBuffer has 0 values for INT_MIN gain
+    for (size_t i = 0; i < mOutputBuffer.size(); i++) {
+        ASSERT_FLOAT_EQ(mOutputBuffer[i], 0);
+    }
+}
+
+TEST_P(LoudnessEnhancerDataTest, MaximumGain) {
+    // Setting the parameters
+    binder_exception_t expected = isGainValid(kMaxGain);
+    if (expected != EX_NONE) {
+        GTEST_SKIP() << "Maximum integer value not supported";
+    }
+    setParameters(kMaxGain, expected);
+    ASSERT_NO_FATAL_FAILURE(processAndWriteToOutput());
+
+    // Validate that mOutputBuffer reaches to kMaxAudioSample for INT_MAX gain
+    for (size_t i = 0; i < mOutputBuffer.size(); i++) {
+        if (mInputBuffer[i] != 0) {
+            EXPECT_NEAR(kMaxAudioSample, abs(mOutputBuffer[i]), kAbsError);
+        } else {
+            ASSERT_EQ(mOutputBuffer[i], mInputBuffer[i]);
+        }
+    }
 }
 
 INSTANTIATE_TEST_SUITE_P(
@@ -139,8 +310,23 @@
 
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(LoudnessEnhancerParamTest);
 
+INSTANTIATE_TEST_SUITE_P(
+        LoudnessEnhancerTest, LoudnessEnhancerDataTest,
+        testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                IFactory::descriptor, getEffectTypeUuidLoudnessEnhancer())),
+        [](const testing::TestParamInfo<LoudnessEnhancerDataTest::ParamType>& info) {
+            auto descriptor = info.param;
+            std::string name = getPrefix(descriptor.second);
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(LoudnessEnhancerDataTest);
+
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
+    ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
     ABinderProcess_setThreadPoolMaxThreadCount(1);
     ABinderProcess_startThreadPool();
     return RUN_ALL_TESTS();
diff --git a/audio/aidl/vts/VtsHalNSTargetTest.cpp b/audio/aidl/vts/VtsHalNSTargetTest.cpp
index 624d5d2..5c13512 100644
--- a/audio/aidl/vts/VtsHalNSTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalNSTargetTest.cpp
@@ -16,7 +16,6 @@
 
 #include <unordered_set>
 
-#include <aidl/Vintf.h>
 #include <aidl/android/hardware/audio/effect/NoiseSuppression.h>
 #define LOG_TAG "VtsHalNSParamTest"
 #include <android-base/logging.h>
@@ -32,6 +31,7 @@
 using aidl::android::hardware::audio::effect::IFactory;
 using aidl::android::hardware::audio::effect::NoiseSuppression;
 using aidl::android::hardware::audio::effect::Parameter;
+using android::hardware::audio::common::testing::detail::TestExecutionTracer;
 
 enum ParamName { PARAM_INSTANCE_NAME, PARAM_LEVEL, PARAM_TYPE };
 using NSParamTestParam = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>,
@@ -171,6 +171,7 @@
 
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
+    ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
     ABinderProcess_setThreadPoolMaxThreadCount(1);
     ABinderProcess_startThreadPool();
     return RUN_ALL_TESTS();
diff --git a/audio/aidl/vts/VtsHalPresetReverbTargetTest.cpp b/audio/aidl/vts/VtsHalPresetReverbTargetTest.cpp
index 3056c6c..1453495 100644
--- a/audio/aidl/vts/VtsHalPresetReverbTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalPresetReverbTargetTest.cpp
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include <aidl/Vintf.h>
 #define LOG_TAG "VtsHalPresetReverbTargetTest"
 #include <android-base/logging.h>
 #include <android/binder_enums.h>
@@ -29,6 +28,7 @@
 using aidl::android::hardware::audio::effect::IFactory;
 using aidl::android::hardware::audio::effect::Parameter;
 using aidl::android::hardware::audio::effect::PresetReverb;
+using android::hardware::audio::common::testing::detail::TestExecutionTracer;
 
 /**
  * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
@@ -147,6 +147,7 @@
 
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
+    ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
     ABinderProcess_setThreadPoolMaxThreadCount(1);
     ABinderProcess_startThreadPool();
     return RUN_ALL_TESTS();
diff --git a/audio/aidl/vts/VtsHalSpatializerTargetTest.cpp b/audio/aidl/vts/VtsHalSpatializerTargetTest.cpp
new file mode 100644
index 0000000..f0b51b9
--- /dev/null
+++ b/audio/aidl/vts/VtsHalSpatializerTargetTest.cpp
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "VtsHalSpatializerTest"
+#include <android-base/logging.h>
+
+#include "EffectHelper.h"
+
+using namespace android;
+
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::getEffectTypeUuidSpatializer;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::Parameter;
+using aidl::android::hardware::audio::effect::Range;
+using aidl::android::hardware::audio::effect::Spatializer;
+using aidl::android::media::audio::common::HeadTracking;
+using aidl::android::media::audio::common::Spatialization;
+using android::hardware::audio::common::testing::detail::TestExecutionTracer;
+using ::android::internal::ToString;
+
+enum ParamName {
+    PARAM_INSTANCE_NAME,
+    PARAM_SPATIALIZATION_LEVEL,
+    PARAM_SPATIALIZATION_MODE,
+    PARAM_HEADTRACK_SENSORID,
+    PARAM_HEADTRACK_MODE,
+    PARAM_HEADTRACK_CONNECTION_MODE
+};
+
+using SpatializerParamTestParam =
+        std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, Spatialization::Level,
+                   Spatialization::Mode, int /* sensor ID */, HeadTracking::Mode,
+                   HeadTracking::ConnectionMode>;
+
+class SpatializerParamTest : public ::testing::TestWithParam<SpatializerParamTestParam>,
+                             public EffectHelper {
+  public:
+    SpatializerParamTest()
+        : mSpatializerParams([&]() {
+              Spatialization::Level level = std::get<PARAM_SPATIALIZATION_LEVEL>(GetParam());
+              Spatialization::Mode mode = std::get<PARAM_SPATIALIZATION_MODE>(GetParam());
+              int sensorId = std::get<PARAM_HEADTRACK_SENSORID>(GetParam());
+              HeadTracking::Mode htMode = std::get<PARAM_HEADTRACK_MODE>(GetParam());
+              HeadTracking::ConnectionMode htConnectMode =
+                      std::get<PARAM_HEADTRACK_CONNECTION_MODE>(GetParam());
+              std::map<Spatializer::Tag, Spatializer> params;
+              params[Spatializer::spatializationLevel] =
+                      Spatializer::make<Spatializer::spatializationLevel>(level);
+              params[Spatializer::spatializationMode] =
+                      Spatializer::make<Spatializer::spatializationMode>(mode);
+              params[Spatializer::headTrackingSensorId] =
+                      Spatializer::make<Spatializer::headTrackingSensorId>(sensorId);
+              params[Spatializer::headTrackingMode] =
+                      Spatializer::make<Spatializer::headTrackingMode>(htMode);
+              params[Spatializer::headTrackingConnectionMode] =
+                      Spatializer::make<Spatializer::headTrackingConnectionMode>(htConnectMode);
+              return params;
+          }()) {
+        std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+    }
+
+    void SetUp() override {
+        ASSERT_NE(nullptr, mFactory);
+        ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+
+        Parameter::Specific specific = getDefaultParamSpecific();
+        Parameter::Common common = EffectHelper::createParamCommon(
+                0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+                kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+        IEffect::OpenEffectReturn ret;
+        ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &ret, EX_NONE));
+        ASSERT_NE(nullptr, mEffect);
+    }
+
+    void TearDown() override {
+        ASSERT_NO_FATAL_FAILURE(close(mEffect));
+        ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+    }
+
+    Parameter::Specific getDefaultParamSpecific() {
+        Spatializer spatializer = Spatializer::make<Spatializer::headTrackingSensorId>(0);
+        Parameter::Specific specific =
+                Parameter::Specific::make<Parameter::Specific::spatializer>(spatializer);
+        return specific;
+    }
+
+    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+    std::shared_ptr<IFactory> mFactory;
+    std::shared_ptr<IEffect> mEffect;
+    Descriptor mDescriptor;
+    const std::map<Spatializer::Tag, Spatializer> mSpatializerParams;
+};
+
+TEST_P(SpatializerParamTest, SetAndGetParam) {
+    for (const auto& it : mSpatializerParams) {
+        auto& tag = it.first;
+        auto& spatializer = it.second;
+
+        // validate parameter
+        Descriptor desc;
+        ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
+        const bool valid = isParameterValid<Spatializer, Range::spatializer>(it.second, desc);
+        const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
+
+        // set parameter
+        Parameter expectParam;
+        Parameter::Specific specific;
+        specific.set<Parameter::Specific::spatializer>(spatializer);
+        expectParam.set<Parameter::specific>(specific);
+        EXPECT_STATUS(expected, mEffect->setParameter(expectParam)) << expectParam.toString();
+
+        // only get if parameter in range and set success
+        if (expected == EX_NONE) {
+            Parameter getParam;
+            Parameter::Id id;
+            Spatializer::Id spatializerId;
+            spatializerId.set<Spatializer::Id::commonTag>(tag);
+            id.set<Parameter::Id::spatializerTag>(spatializerId);
+            // if set success, then get should match
+            EXPECT_STATUS(expected, mEffect->getParameter(id, &getParam));
+            EXPECT_EQ(expectParam, getParam);
+        }
+    }
+}
+
+std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> kDescPair;
+INSTANTIATE_TEST_SUITE_P(
+        SpatializerTest, SpatializerParamTest,
+        ::testing::Combine(
+                testing::ValuesIn(kDescPair = EffectFactoryHelper::getAllEffectDescriptors(
+                                          IFactory::descriptor, getEffectTypeUuidSpatializer())),
+                testing::ValuesIn(EffectHelper::getTestValueSet<
+                                  Spatializer, Spatialization::Level, Range::spatializer,
+                                  Spatializer::spatializationLevel>(kDescPair)),
+                testing::ValuesIn(EffectHelper::getTestValueSet<
+                                  Spatializer, Spatialization::Mode, Range::spatializer,
+                                  Spatializer::spatializationMode>(kDescPair)),
+                testing::ValuesIn(
+                        EffectHelper::getTestValueSet<Spatializer, int, Range::spatializer,
+                                                      Spatializer::headTrackingSensorId>(
+                                kDescPair, EffectHelper::expandTestValueBasic<int>)),
+                testing::ValuesIn(EffectHelper::getTestValueSet<
+                                  Spatializer, HeadTracking::Mode, Range::spatializer,
+                                  Spatializer::headTrackingMode>(kDescPair)),
+                testing::ValuesIn(EffectHelper::getTestValueSet<
+                                  Spatializer, HeadTracking::ConnectionMode, Range::spatializer,
+                                  Spatializer::headTrackingConnectionMode>(kDescPair))),
+        [](const testing::TestParamInfo<SpatializerParamTest::ParamType>& info) {
+            auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
+            std::string level = ToString(std::get<PARAM_SPATIALIZATION_LEVEL>(info.param));
+            std::string mode = ToString(std::get<PARAM_SPATIALIZATION_MODE>(info.param));
+            std::string sensorId = ToString(std::get<PARAM_HEADTRACK_SENSORID>(info.param));
+            std::string htMode = ToString(std::get<PARAM_HEADTRACK_MODE>(info.param));
+            std::string htConnectMode =
+                    ToString(std::get<PARAM_HEADTRACK_CONNECTION_MODE>(info.param));
+            std::string name = getPrefix(descriptor) + "_sensorID_" + level + "_mode_" + mode +
+                               "_sensorID_" + sensorId + "_HTMode_" + htMode +
+                               "_HTConnectionMode_" + htConnectMode;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SpatializerParamTest);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp b/audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp
index 07a9fa4..0c24f90 100644
--- a/audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include <aidl/Vintf.h>
 #define LOG_TAG "VtsHalVirtualizerTest"
 #include <android-base/logging.h>
 
@@ -28,6 +27,7 @@
 using aidl::android::hardware::audio::effect::IFactory;
 using aidl::android::hardware::audio::effect::Parameter;
 using aidl::android::hardware::audio::effect::Virtualizer;
+using android::hardware::audio::common::testing::detail::TestExecutionTracer;
 
 /**
  * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
@@ -151,6 +151,7 @@
 
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
+    ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
     ABinderProcess_setThreadPoolMaxThreadCount(1);
     ABinderProcess_startThreadPool();
     return RUN_ALL_TESTS();
diff --git a/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp b/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp
index 903ba69..db83715 100644
--- a/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp
@@ -16,7 +16,6 @@
 
 #include <unordered_set>
 
-#include <aidl/Vintf.h>
 #define LOG_TAG "VtsHalVisualizerTest"
 #include <android-base/logging.h>
 #include <android/binder_enums.h>
@@ -31,6 +30,7 @@
 using aidl::android::hardware::audio::effect::IFactory;
 using aidl::android::hardware::audio::effect::Parameter;
 using aidl::android::hardware::audio::effect::Visualizer;
+using android::hardware::audio::common::testing::detail::TestExecutionTracer;
 
 /**
  * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
@@ -207,6 +207,7 @@
 
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
+    ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
     ABinderProcess_setThreadPoolMaxThreadCount(1);
     ABinderProcess_startThreadPool();
     return RUN_ALL_TESTS();
diff --git a/audio/aidl/vts/VtsHalVolumeTargetTest.cpp b/audio/aidl/vts/VtsHalVolumeTargetTest.cpp
index 0b5b9fc..aa2c05f 100644
--- a/audio/aidl/vts/VtsHalVolumeTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalVolumeTargetTest.cpp
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include <aidl/Vintf.h>
 #define LOG_TAG "VtsHalVolumeTest"
 #include <android-base/logging.h>
 
@@ -28,6 +27,7 @@
 using aidl::android::hardware::audio::effect::IFactory;
 using aidl::android::hardware::audio::effect::Parameter;
 using aidl::android::hardware::audio::effect::Volume;
+using android::hardware::audio::common::testing::detail::TestExecutionTracer;
 
 /**
  * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
@@ -159,6 +159,7 @@
 
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
+    ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
     ABinderProcess_setThreadPoolMaxThreadCount(1);
     ABinderProcess_startThreadPool();
     return RUN_ALL_TESTS();
diff --git a/audio/common/all-versions/default/service/android.hardware.audio.service.rc b/audio/common/all-versions/default/service/android.hardware.audio.service.rc
index 0de4eea..a1df67a 100644
--- a/audio/common/all-versions/default/service/android.hardware.audio.service.rc
+++ b/audio/common/all-versions/default/service/android.hardware.audio.service.rc
@@ -2,7 +2,7 @@
     class hal
     user audioserver
     # media gid needed for /dev/fm (radio) and for /data/misc/media (tee)
-    group audio camera drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct wakelock context_hub
+    group audio camera drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct wakelock context_hub system
     capabilities BLOCK_SUSPEND SYS_NICE
     # setting RLIMIT_RTPRIO allows binder RT priority inheritance
     rlimit rtprio 10 10
diff --git a/audio/common/all-versions/test/utility/Android.bp b/audio/common/all-versions/test/utility/Android.bp
index 757f8a8..c6a3963 100644
--- a/audio/common/all-versions/test/utility/Android.bp
+++ b/audio/common/all-versions/test/utility/Android.bp
@@ -62,6 +62,5 @@
         "libxml2",
         "liblog",
     ],
-    static_libs: ["libgtest"],
     test_suites: ["general-tests"],
 }
diff --git a/audio/common/all-versions/test/utility/src/ValidateXml.cpp b/audio/common/all-versions/test/utility/src/ValidateXml.cpp
index 4d6f003..b7e685b 100644
--- a/audio/common/all-versions/test/utility/src/ValidateXml.cpp
+++ b/audio/common/all-versions/test/utility/src/ValidateXml.cpp
@@ -19,6 +19,7 @@
 
 #include <numeric>
 
+#include <libxml/parser.h>
 #define LIBXML_SCHEMAS_ENABLED
 #include <libxml/xmlschemastypes.h>
 #define LIBXML_XINCLUDE_ENABLED
diff --git a/audio/common/all-versions/test/utility/tests/utility_tests.cpp b/audio/common/all-versions/test/utility/tests/utility_tests.cpp
index c523066..c2bcfbc 100644
--- a/audio/common/all-versions/test/utility/tests/utility_tests.cpp
+++ b/audio/common/all-versions/test/utility/tests/utility_tests.cpp
@@ -70,6 +70,7 @@
 std::string substitute(const char* fmt, const char* param) {
     std::string buffer(static_cast<size_t>(strlen(fmt) + strlen(param)), '\0');
     snprintf(buffer.data(), buffer.size(), fmt, param);
+    buffer.resize(strlen(buffer.c_str()));
     return buffer;
 }
 
diff --git a/audio/core/all-versions/default/ParametersUtil.cpp b/audio/core/all-versions/default/ParametersUtil.cpp
index e21eff2..4d8a208 100644
--- a/audio/core/all-versions/default/ParametersUtil.cpp
+++ b/audio/core/all-versions/default/ParametersUtil.cpp
@@ -51,7 +51,7 @@
     Result retval = getParam(name, &halValue);
     *value = false;
     if (retval == Result::OK) {
-        if (halValue.empty()) {
+        if (halValue.length() == 0) {
             return Result::NOT_SUPPORTED;
         }
         *value = !(halValue == AudioParameter::valueOff);
@@ -97,17 +97,17 @@
             retval = getHalStatusToResult(status);
             break;
         }
-        result[i].key = halKey.string();
-        result[i].value = halValue.string();
+        result[i].key = halKey.c_str();
+        result[i].value = halValue.c_str();
     }
     cb(retval, result);
 }
 
 std::unique_ptr<AudioParameter> ParametersUtil::getParams(const AudioParameter& keys) {
     String8 paramsAndValues;
-    char* halValues = halGetParameters(keys.keysToString().string());
+    char* halValues = halGetParameters(keys.keysToString().c_str());
     if (halValues != NULL) {
-        paramsAndValues.setTo(halValues);
+        paramsAndValues = halValues;
         free(halValues);
     } else {
         paramsAndValues.clear();
@@ -163,7 +163,7 @@
 }
 
 Result ParametersUtil::setParams(const AudioParameter& param) {
-    int halStatus = halSetParameters(param.toString().string());
+    int halStatus = halSetParameters(param.toString().c_str());
     return util::analyzeStatus(halStatus);
 }
 
diff --git a/audio/core/all-versions/default/PrimaryDevice.cpp b/audio/core/all-versions/default/PrimaryDevice.cpp
index cf162f1..13efbbc 100644
--- a/audio/core/all-versions/default/PrimaryDevice.cpp
+++ b/audio/core/all-versions/default/PrimaryDevice.cpp
@@ -283,7 +283,7 @@
         _hidl_cb(retval, TtyMode::OFF);
         return Void();
     }
-    TtyMode mode = convertTtyModeToHIDL(halMode);
+    TtyMode mode = convertTtyModeToHIDL(halMode.c_str());
     if (mode == TtyMode(-1)) {
         ALOGE("HAL returned invalid TTY value: %s", halMode.c_str());
         _hidl_cb(Result::INVALID_STATE, TtyMode::OFF);
diff --git a/audio/core/all-versions/default/Stream.cpp b/audio/core/all-versions/default/Stream.cpp
index 8e85a8b..c11b675 100644
--- a/audio/core/all-versions/default/Stream.cpp
+++ b/audio/core/all-versions/default/Stream.cpp
@@ -114,7 +114,7 @@
     SampleRateSet halSampleRates;
     if (result == Result::OK) {
         halSampleRates =
-            samplingRatesFromString(halListValue.string(), AudioParameter::valueListSeparator);
+                samplingRatesFromString(halListValue.c_str(), AudioParameter::valueListSeparator);
         sampleRates = hidl_vec<uint32_t>(halSampleRates.begin(), halSampleRates.end());
         // Legacy get_parameter does not return a status_t, thus can not advertise of failure.
         // Note that this method must succeed (non empty list) if the format is supported.
@@ -140,7 +140,7 @@
     ChannelMaskSet halChannelMasks;
     if (result == Result::OK) {
         halChannelMasks =
-            channelMasksFromString(halListValue.string(), AudioParameter::valueListSeparator);
+                channelMasksFromString(halListValue.c_str(), AudioParameter::valueListSeparator);
         channelMasks.resize(halChannelMasks.size());
         size_t i = 0;
         for (auto channelMask : halChannelMasks) {
@@ -182,7 +182,7 @@
     hidl_vec<AudioFormat> formats;
     FormatVector halFormats;
     if (result == Result::OK) {
-        halFormats = formatsFromString(halListValue.string(), AudioParameter::valueListSeparator);
+        halFormats = formatsFromString(halListValue.c_str(), AudioParameter::valueListSeparator);
         formats.resize(halFormats.size());
         for (size_t i = 0; i < halFormats.size(); ++i) {
             formats[i] = AudioFormat(halFormats[i]);
@@ -226,7 +226,7 @@
     // Ensure that the separator is one character, despite that it's defined as a C string.
     static_assert(sizeof(AUDIO_PARAMETER_VALUE_LIST_SEPARATOR) == 2);
     std::vector<std::string> halFormats =
-            splitString(halListValue.string(), AUDIO_PARAMETER_VALUE_LIST_SEPARATOR[0]);
+            splitString(halListValue.c_str(), AUDIO_PARAMETER_VALUE_LIST_SEPARATOR[0]);
     hidl_vec<AudioFormat> formats;
     (void)HidlUtils::audioFormatsFromHal(halFormats, &formats);
     std::vector<AudioProfile> tempProfiles;
@@ -241,7 +241,7 @@
         result = getParam(AudioParameter::keyStreamSupportedSamplingRates, &halListValue, context);
         if (result != Result::OK) break;
         std::vector<std::string> halSampleRates =
-                splitString(halListValue.string(), AUDIO_PARAMETER_VALUE_LIST_SEPARATOR[0]);
+                splitString(halListValue.c_str(), AUDIO_PARAMETER_VALUE_LIST_SEPARATOR[0]);
         hidl_vec<uint32_t> sampleRates;
         sampleRates.resize(halSampleRates.size());
         for (size_t i = 0; i < sampleRates.size(); ++i) {
@@ -251,7 +251,7 @@
         result = getParam(AudioParameter::keyStreamSupportedChannels, &halListValue, context);
         if (result != Result::OK) break;
         std::vector<std::string> halChannelMasks =
-                splitString(halListValue.string(), AUDIO_PARAMETER_VALUE_LIST_SEPARATOR[0]);
+                splitString(halListValue.c_str(), AUDIO_PARAMETER_VALUE_LIST_SEPARATOR[0]);
         hidl_vec<AudioChannelMask> channelMasks;
         (void)HidlUtils::audioChannelMasksFromHal(halChannelMasks, &channelMasks);
         // Create a profile.
diff --git a/audio/effect/4.0/xml/Android.bp b/audio/effect/4.0/xml/Android.bp
index 8c03a35..bdffe60 100644
--- a/audio/effect/4.0/xml/Android.bp
+++ b/audio/effect/4.0/xml/Android.bp
@@ -9,9 +9,9 @@
 
 genrule {
     name: "audio_effects_conf_V4_0",
-    srcs: ["audio_effects_conf.xsd"],
+    srcs: [":audio_effects_conf_V2_0"],
     out: [
         "audio_effects_conf_V4_0.xsd",
     ],
-    cmd: "cp -f $(in) $(genDir)/audio_effects_conf_V4_0.xsd",
+    cmd: "cp -f $(in) $(out)",
 }
diff --git a/audio/effect/4.0/xml/audio_effects_conf.xsd b/audio/effect/4.0/xml/audio_effects_conf.xsd
deleted file mode 120000
index 9d85fa7..0000000
--- a/audio/effect/4.0/xml/audio_effects_conf.xsd
+++ /dev/null
@@ -1 +0,0 @@
-../../2.0/xml/audio_effects_conf.xsd
\ No newline at end of file
diff --git a/audio/effect/5.0/xml/Android.bp b/audio/effect/5.0/xml/Android.bp
index 7982e2a..ed12e38 100644
--- a/audio/effect/5.0/xml/Android.bp
+++ b/audio/effect/5.0/xml/Android.bp
@@ -9,6 +9,6 @@
 
 xsd_config {
     name: "audio_effects_conf_V5_0",
-    srcs: ["audio_effects_conf.xsd"],
+    srcs: [":audio_effects_conf_V2_0"],
     package_name: "audio.effects.V5_0",
 }
diff --git a/audio/effect/5.0/xml/audio_effects_conf.xsd b/audio/effect/5.0/xml/audio_effects_conf.xsd
deleted file mode 120000
index 9d85fa7..0000000
--- a/audio/effect/5.0/xml/audio_effects_conf.xsd
+++ /dev/null
@@ -1 +0,0 @@
-../../2.0/xml/audio_effects_conf.xsd
\ No newline at end of file
diff --git a/audio/effect/all-versions/default/Effect.cpp b/audio/effect/all-versions/default/Effect.cpp
index 5aecd32..4a9e144 100644
--- a/audio/effect/all-versions/default/Effect.cpp
+++ b/audio/effect/all-versions/default/Effect.cpp
@@ -315,7 +315,7 @@
 
 Effect::~Effect() {
     ATRACE_CALL();
-    (void)close();
+    auto [_, handle] = closeImpl();
     if (mProcessThread.get()) {
         ATRACE_NAME("mProcessThread->join");
         status_t status = mProcessThread->join();
@@ -328,11 +328,10 @@
     mInBuffer.clear();
     mOutBuffer.clear();
 #if MAJOR_VERSION <= 5
-    int status = EffectRelease(mHandle);
-    ALOGW_IF(status, "Error releasing effect %p: %s", mHandle, strerror(-status));
+    int status = EffectRelease(handle);
+    ALOGW_IF(status, "Error releasing effect %p: %s", handle, strerror(-status));
 #endif
-    EffectMap::getInstance().remove(mHandle);
-    mHandle = 0;
+    EffectMap::getInstance().remove(handle);
 }
 
 // static
@@ -459,7 +458,19 @@
     }
 }
 
-void Effect::getConfigImpl(int commandCode, const char* commandName, GetConfigCallback cb) {
+#define RETURN_IF_EFFECT_CLOSED()          \
+    if (mHandle == kInvalidEffectHandle) { \
+        return Result::INVALID_STATE;      \
+    }
+#define RETURN_RESULT_IF_EFFECT_CLOSED(result)   \
+    if (mHandle == kInvalidEffectHandle) {       \
+        _hidl_cb(Result::INVALID_STATE, result); \
+        return Void();                           \
+    }
+
+Return<void> Effect::getConfigImpl(int commandCode, const char* commandName,
+                                   GetConfigCallback _hidl_cb) {
+    RETURN_RESULT_IF_EFFECT_CLOSED(EffectConfig());
     uint32_t halResultSize = sizeof(effect_config_t);
     effect_config_t halConfig{};
     status_t status =
@@ -468,7 +479,8 @@
     if (status == OK) {
         status = EffectUtils::effectConfigFromHal(halConfig, mIsInput, &config);
     }
-    cb(analyzeCommandStatus(commandName, sContextCallToCommand, status), config);
+    _hidl_cb(analyzeCommandStatus(commandName, sContextCallToCommand, status), config);
+    return Void();
 }
 
 Result Effect::getCurrentConfigImpl(uint32_t featureId, uint32_t configSize,
@@ -530,6 +542,7 @@
 }
 
 Return<void> Effect::prepareForProcessing(prepareForProcessing_cb _hidl_cb) {
+    RETURN_RESULT_IF_EFFECT_CLOSED(StatusMQ::Descriptor());
     status_t status;
     // Create message queue.
     if (mStatusMQ) {
@@ -576,6 +589,7 @@
 
 Return<Result> Effect::setProcessBuffers(const AudioBuffer& inBuffer,
                                          const AudioBuffer& outBuffer) {
+    RETURN_IF_EFFECT_CLOSED();
     AudioBufferManager& manager = AudioBufferManager::getInstance();
     sp<AudioBufferWrapper> tempInBuffer, tempOutBuffer;
     if (!manager.wrap(inBuffer, &tempInBuffer)) {
@@ -600,6 +614,7 @@
 }
 
 Result Effect::sendCommand(int commandCode, const char* commandName, uint32_t size, void* data) {
+    RETURN_IF_EFFECT_CLOSED();
     status_t status = (*mHandle)->command(mHandle, commandCode, size, data, 0, NULL);
     return analyzeCommandStatus(commandName, sContextCallToCommand, status);
 }
@@ -611,6 +626,7 @@
 
 Result Effect::sendCommandReturningData(int commandCode, const char* commandName, uint32_t size,
                                         void* data, uint32_t* replySize, void* replyData) {
+    RETURN_IF_EFFECT_CLOSED();
     uint32_t expectedReplySize = *replySize;
     status_t status = (*mHandle)->command(mHandle, commandCode, size, data, replySize, replyData);
     if (status == OK && *replySize != expectedReplySize) {
@@ -635,6 +651,7 @@
                                                  uint32_t size, void* data, uint32_t* replySize,
                                                  void* replyData, uint32_t minReplySize,
                                                  CommandSuccessCallback onSuccess) {
+    RETURN_IF_EFFECT_CLOSED();
     status_t status = (*mHandle)->command(mHandle, commandCode, size, data, replySize, replyData);
     Result retval;
     if (status == OK && minReplySize >= sizeof(uint32_t) && *replySize >= minReplySize) {
@@ -792,13 +809,11 @@
 }
 
 Return<void> Effect::getConfig(getConfig_cb _hidl_cb) {
-    getConfigImpl(EFFECT_CMD_GET_CONFIG, "GET_CONFIG", _hidl_cb);
-    return Void();
+    return getConfigImpl(EFFECT_CMD_GET_CONFIG, "GET_CONFIG", _hidl_cb);
 }
 
 Return<void> Effect::getConfigReverse(getConfigReverse_cb _hidl_cb) {
-    getConfigImpl(EFFECT_CMD_GET_CONFIG_REVERSE, "GET_CONFIG_REVERSE", _hidl_cb);
-    return Void();
+    return getConfigImpl(EFFECT_CMD_GET_CONFIG_REVERSE, "GET_CONFIG_REVERSE", _hidl_cb);
 }
 
 Return<void> Effect::getSupportedAuxChannelsConfigs(uint32_t maxConfigs,
@@ -845,6 +860,7 @@
 }
 
 Return<void> Effect::getDescriptor(getDescriptor_cb _hidl_cb) {
+    RETURN_RESULT_IF_EFFECT_CLOSED(EffectDescriptor());
     effect_descriptor_t halDescriptor;
     memset(&halDescriptor, 0, sizeof(effect_descriptor_t));
     status_t status = (*mHandle)->get_descriptor(mHandle, &halDescriptor);
@@ -858,6 +874,10 @@
 
 Return<void> Effect::command(uint32_t commandId, const hidl_vec<uint8_t>& data,
                              uint32_t resultMaxSize, command_cb _hidl_cb) {
+    if (mHandle == kInvalidEffectHandle) {
+        _hidl_cb(-ENODATA, hidl_vec<uint8_t>());
+        return Void();
+    }
     uint32_t halDataSize;
     std::unique_ptr<uint8_t[]> halData = hidlVecToHal(data, &halDataSize);
     uint32_t halResultSize = resultMaxSize;
@@ -942,26 +962,33 @@
                                       halCmd.size(), &halCmd[0]);
 }
 
-Return<Result> Effect::close() {
+std::tuple<Result, effect_handle_t> Effect::closeImpl() {
     if (mStopProcessThread.load(std::memory_order_relaxed)) {  // only this thread modifies
-        return Result::INVALID_STATE;
+        return {Result::INVALID_STATE, kInvalidEffectHandle};
     }
     mStopProcessThread.store(true, std::memory_order_release);
     if (mEfGroup) {
         mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_QUIT));
     }
+    effect_handle_t handle = mHandle;
+    mHandle = kInvalidEffectHandle;
 #if MAJOR_VERSION <= 5
-    return Result::OK;
+    return {Result::OK, handle};
 #elif MAJOR_VERSION >= 6
     // No need to join the processing thread, it is part of the API contract that the client
     // must finish processing before closing the effect.
-    Result retval =
-            analyzeStatus("EffectRelease", "", sContextCallFunction, EffectRelease(mHandle));
-    EffectMap::getInstance().remove(mHandle);
-    return retval;
+    Result retval = analyzeStatus("EffectRelease", "", sContextCallFunction, EffectRelease(handle));
+    EffectMap::getInstance().remove(handle);
+    return {retval, handle};
 #endif
 }
 
+Return<Result> Effect::close() {
+    RETURN_IF_EFFECT_CLOSED();
+    auto [result, _] = closeImpl();
+    return result;
+}
+
 Return<void> Effect::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& /* options */) {
     if (fd.getNativeHandle() != nullptr && fd->numFds == 1) {
         uint32_t cmdData = fd->data[0];
diff --git a/audio/effect/all-versions/default/Effect.h b/audio/effect/all-versions/default/Effect.h
index 5d8dccc..2bcecec 100644
--- a/audio/effect/all-versions/default/Effect.h
+++ b/audio/effect/all-versions/default/Effect.h
@@ -23,6 +23,7 @@
 
 #include <atomic>
 #include <memory>
+#include <tuple>
 #include <vector>
 
 #include <fmq/EventFlag.h>
@@ -186,6 +187,7 @@
 
     // Sets the limit on the maximum size of vendor-provided data structures.
     static constexpr size_t kMaxDataSize = 1 << 20;
+    static constexpr effect_handle_t kInvalidEffectHandle = nullptr;
 
     static const char* sContextResultOfCommand;
     static const char* sContextCallToCommand;
@@ -208,6 +210,7 @@
     static size_t alignedSizeIn(size_t s);
     template <typename T>
     std::unique_ptr<uint8_t[]> hidlVecToHal(const hidl_vec<T>& vec, uint32_t* halDataSize);
+    std::tuple<Result, effect_handle_t> closeImpl();
     void effectAuxChannelsConfigFromHal(const channel_config_t& halConfig,
                                         EffectAuxChannelsConfig* config);
     static void effectAuxChannelsConfigToHal(const EffectAuxChannelsConfig& config,
@@ -218,7 +221,8 @@
                                const void** valueData, std::vector<uint8_t>* halParamBuffer);
 
     Result analyzeCommandStatus(const char* commandName, const char* context, status_t status);
-    void getConfigImpl(int commandCode, const char* commandName, GetConfigCallback cb);
+    Return<void> getConfigImpl(int commandCode, const char* commandName,
+                               GetConfigCallback _hidl_cb);
     Result getCurrentConfigImpl(uint32_t featureId, uint32_t configSize,
                                 GetCurrentConfigSuccessCallback onSuccess);
     Result getSupportedConfigsImpl(uint32_t featureId, uint32_t maxConfigs, uint32_t configSize,
diff --git a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
index d95bb06..ff84f9d 100644
--- a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
+++ b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
@@ -169,13 +169,15 @@
     0xfe3199be, 0xaed0, 0x413f, 0x87bb,
     std::array<uint8_t, 6>{{0x11, 0x26, 0x0e, 0xb6, 0x3c, 0xf1}}};
 
-enum { PARAM_FACTORY_NAME, PARAM_EFFECT_UUID };
-using EffectParameter = std::tuple<std::string, Uuid>;
+enum { PARAM_FACTORY_NAME, PARAM_EFFECT_UUID, PARAM_USE_AFTER_CLOSE };
+using EffectParameter = std::tuple<std::string, Uuid, bool>;
 
 static inline std::string EffectParameterToString(
         const ::testing::TestParamInfo<EffectParameter>& info) {
-    return ::android::hardware::PrintInstanceNameToString(::testing::TestParamInfo<std::string>{
-            std::get<PARAM_FACTORY_NAME>(info.param), info.index});
+    std::string prefix = std::get<PARAM_USE_AFTER_CLOSE>(info.param) ? "UseAfterClose_" : "";
+    return prefix.append(
+            ::android::hardware::PrintInstanceNameToString(::testing::TestParamInfo<std::string>{
+                    std::get<PARAM_FACTORY_NAME>(info.param), info.index}));
 }
 
 // The main test class for Audio Effect HIDL HAL.
@@ -191,6 +193,13 @@
         Return<Result> ret = effect->init();
         ASSERT_TRUE(ret.isOk());
         ASSERT_EQ(Result::OK, ret);
+
+        useAfterClose = std::get<PARAM_USE_AFTER_CLOSE>(GetParam());
+        if (useAfterClose) {
+            Return<Result> ret = effect->close();
+            ASSERT_TRUE(ret.isOk());
+            ASSERT_EQ(Result::OK, ret);
+        }
     }
 
     void TearDown() override {
@@ -205,14 +214,34 @@
 
     Uuid getEffectType() const { return std::get<PARAM_EFFECT_UUID>(GetParam()); }
 
+    void checkResult(const Result& result);
+    void checkResultForUseAfterClose(const Result& result);
     void findAndCreateEffect(const Uuid& type);
     void findEffectInstance(const Uuid& type, Uuid* uuid);
     void getChannelCount(uint32_t* channelCount);
 
     sp<IEffectsFactory> effectsFactory;
     sp<IEffect> effect;
+    bool useAfterClose;
 };
 
+void AudioEffectHidlTest::checkResult(const Result& result) {
+    if (!useAfterClose) {
+        ASSERT_EQ(Result::OK, result);
+    } else {
+        ASSERT_NO_FATAL_FAILURE(checkResultForUseAfterClose(result));
+    }
+}
+
+void AudioEffectHidlTest::checkResultForUseAfterClose(const Result& result) {
+    if (useAfterClose) {
+        // The actual error does not matter. It's important that the effect did not crash
+        // while executing any command after a call to "close", and that the returned status
+        // is not OK.
+        ASSERT_NE(Result::OK, result);
+    }
+}
+
 void AudioEffectHidlTest::findAndCreateEffect(const Uuid& type) {
     Uuid effectUuid;
     ASSERT_NO_FATAL_FAILURE(findEffectInstance(type, &effectUuid));
@@ -257,7 +286,11 @@
         }
     });
     ASSERT_TRUE(ret.isOk());
-    ASSERT_EQ(Result::OK, retval);
+    ASSERT_NO_FATAL_FAILURE(checkResult(retval));
+    if (useAfterClose) {
+        *channelCount = 1;
+        return;
+    }
 #if MAJOR_VERSION <= 6
     ASSERT_TRUE(audio_channel_mask_is_valid(
         static_cast<audio_channel_mask_t>(currentConfig.outputCfg.channels)));
@@ -276,7 +309,7 @@
     description("Verify that an effect can be closed");
     Return<Result> ret = effect->close();
     EXPECT_TRUE(ret.isOk());
-    EXPECT_EQ(Result::OK, ret);
+    ASSERT_NO_FATAL_FAILURE(checkResult(ret));
 }
 
 TEST_P(AudioEffectHidlTest, GetDescriptor) {
@@ -290,7 +323,8 @@
         }
     });
     EXPECT_TRUE(ret.isOk());
-    EXPECT_EQ(Result::OK, retval);
+    ASSERT_NO_FATAL_FAILURE(checkResult(retval));
+    if (useAfterClose) return;
     EXPECT_EQ(getEffectType(), actualType);
 }
 
@@ -307,7 +341,8 @@
         }
     });
     EXPECT_TRUE(ret.isOk());
-    EXPECT_EQ(Result::OK, retval);
+    EXPECT_NO_FATAL_FAILURE(checkResult(retval));
+    if (useAfterClose) return;
     Return<Result> ret2 = effect->setConfig(currentConfig, nullptr, nullptr);
     EXPECT_TRUE(ret2.isOk());
     EXPECT_EQ(Result::OK, ret2);
@@ -336,7 +371,8 @@
         }
     });
     EXPECT_TRUE(ret.isOk());
-    EXPECT_EQ(Result::OK, retval);
+    EXPECT_NO_FATAL_FAILURE(checkResult(retval));
+    if (useAfterClose) return;
     for (const auto& invalidInputCfg : generateInvalidConfigs(currentConfig.inputCfg)) {
         EffectConfig invalidConfig = currentConfig;
         invalidConfig.inputCfg = invalidInputCfg;
@@ -356,27 +392,35 @@
 
 TEST_P(AudioEffectHidlTest, GetConfigReverse) {
     description("Verify that GetConfigReverse does not crash");
-    Return<void> ret = effect->getConfigReverse([&](Result, const EffectConfig&) {});
+    Result retval = Result::OK;
+    Return<void> ret = effect->getConfigReverse([&](Result r, const EffectConfig&) { retval = r; });
     EXPECT_TRUE(ret.isOk());
+    EXPECT_NO_FATAL_FAILURE(checkResultForUseAfterClose(retval));
 }
 
 TEST_P(AudioEffectHidlTest, GetSupportedAuxChannelsConfigs) {
     description("Verify that GetSupportedAuxChannelsConfigs does not crash");
+    Result retval = Result::OK;
     Return<void> ret = effect->getSupportedAuxChannelsConfigs(
-        0, [&](Result, const hidl_vec<EffectAuxChannelsConfig>&) {});
+            0, [&](Result r, const hidl_vec<EffectAuxChannelsConfig>&) { retval = r; });
     EXPECT_TRUE(ret.isOk());
+    EXPECT_NO_FATAL_FAILURE(checkResultForUseAfterClose(retval));
 }
 
 TEST_P(AudioEffectHidlTest, GetAuxChannelsConfig) {
     description("Verify that GetAuxChannelsConfig does not crash");
-    Return<void> ret = effect->getAuxChannelsConfig([&](Result, const EffectAuxChannelsConfig&) {});
+    Result retval = Result::OK;
+    Return<void> ret = effect->getAuxChannelsConfig(
+            [&](Result r, const EffectAuxChannelsConfig&) { retval = r; });
     EXPECT_TRUE(ret.isOk());
+    EXPECT_NO_FATAL_FAILURE(checkResultForUseAfterClose(retval));
 }
 
 TEST_P(AudioEffectHidlTest, SetAuxChannelsConfig) {
     description("Verify that SetAuxChannelsConfig does not crash");
     Return<Result> ret = effect->setAuxChannelsConfig(EffectAuxChannelsConfig());
     EXPECT_TRUE(ret.isOk());
+    EXPECT_NO_FATAL_FAILURE(checkResultForUseAfterClose(ret));
 }
 
 // Not generated automatically because AudioBuffer contains
@@ -427,45 +471,56 @@
     description("Verify that Reset preserves effect configuration");
     Result retval = Result::NOT_INITIALIZED;
     EffectConfig originalConfig;
-    Return<void> ret = effect->getConfig([&](Result r, const EffectConfig& conf) {
-        retval = r;
-        if (r == Result::OK) {
-            originalConfig = conf;
-        }
-    });
-    ASSERT_TRUE(ret.isOk());
-    ASSERT_EQ(Result::OK, retval);
+    if (!useAfterClose) {
+        Return<void> ret = effect->getConfig([&](Result r, const EffectConfig& conf) {
+            retval = r;
+            if (r == Result::OK) {
+                originalConfig = conf;
+            }
+        });
+        ASSERT_TRUE(ret.isOk());
+        ASSERT_EQ(Result::OK, retval);
+    }
     Return<Result> ret2 = effect->reset();
     EXPECT_TRUE(ret2.isOk());
-    EXPECT_EQ(Result::OK, ret2);
-    EffectConfig configAfterReset;
-    ret = effect->getConfig([&](Result r, const EffectConfig& conf) {
-        retval = r;
-        if (r == Result::OK) {
-            configAfterReset = conf;
-        }
-    });
-    EXPECT_EQ(originalConfig, configAfterReset);
+    EXPECT_NO_FATAL_FAILURE(checkResult(ret2));
+    if (!useAfterClose) {
+        EffectConfig configAfterReset;
+        Return<void> ret = effect->getConfig([&](Result r, const EffectConfig& conf) {
+            retval = r;
+            if (r == Result::OK) {
+                configAfterReset = conf;
+            }
+        });
+        EXPECT_EQ(originalConfig, configAfterReset);
+    }
 }
 
 TEST_P(AudioEffectHidlTest, DisableEnableDisable) {
     description("Verify Disable -> Enable -> Disable sequence for an effect");
     Return<Result> ret = effect->disable();
     EXPECT_TRUE(ret.isOk());
-    // Note: some legacy effects may return -EINVAL (INVALID_ARGUMENTS),
-    //       more canonical is to return -ENOSYS (NOT_SUPPORTED)
-    EXPECT_TRUE(ret == Result::NOT_SUPPORTED || ret == Result::INVALID_ARGUMENTS);
+    if (!useAfterClose) {
+        // Note: some legacy effects may return -EINVAL (INVALID_ARGUMENTS),
+        //       more canonical is to return -ENOSYS (NOT_SUPPORTED)
+        EXPECT_TRUE(ret == Result::NOT_SUPPORTED || ret == Result::INVALID_ARGUMENTS);
+    } else {
+        EXPECT_NO_FATAL_FAILURE(checkResultForUseAfterClose(ret));
+    }
     ret = effect->enable();
     EXPECT_TRUE(ret.isOk());
-    EXPECT_EQ(Result::OK, ret);
+    EXPECT_NO_FATAL_FAILURE(checkResult(ret));
     ret = effect->disable();
     EXPECT_TRUE(ret.isOk());
-    EXPECT_EQ(Result::OK, ret);
+    EXPECT_NO_FATAL_FAILURE(checkResult(ret));
 }
 
 #if MAJOR_VERSION >= 7
 TEST_P(AudioEffectHidlTest, SetDeviceInvalidDeviceAddress) {
     description("Verify that invalid device address is rejected by SetDevice");
+    if (useAfterClose) {
+        GTEST_SKIP() << "Does not make sense for the useAfterClose case";
+    }
     DeviceAddress device{.deviceType = "random_string"};
     Return<Result> ret = effect->setDevice(device);
     EXPECT_TRUE(ret.isOk());
@@ -482,13 +537,13 @@
     Return<Result> ret = effect->setDevice(device);
 #endif
     EXPECT_TRUE(ret.isOk());
-    EXPECT_EQ(Result::OK, ret);
+    EXPECT_NO_FATAL_FAILURE(checkResult(ret));
 }
 
 TEST_P(AudioEffectHidlTest, SetAndGetVolume) {
     description("Verify that SetAndGetVolume method works for an effect");
     uint32_t channelCount;
-    getChannelCount(&channelCount);
+    ASSERT_NO_FATAL_FAILURE(getChannelCount(&channelCount));
     hidl_vec<uint32_t> volumes;
     volumes.resize(channelCount);
     for (uint32_t i = 0; i < channelCount; ++i) {
@@ -498,13 +553,13 @@
     Return<void> ret =
         effect->setAndGetVolume(volumes, [&](Result r, const hidl_vec<uint32_t>&) { retval = r; });
     EXPECT_TRUE(ret.isOk());
-    EXPECT_EQ(Result::OK, retval);
+    EXPECT_NO_FATAL_FAILURE(checkResult(retval));
 }
 
 TEST_P(AudioEffectHidlTest, VolumeChangeNotification) {
     description("Verify that effect accepts VolumeChangeNotification");
     uint32_t channelCount;
-    getChannelCount(&channelCount);
+    ASSERT_NO_FATAL_FAILURE(getChannelCount(&channelCount));
     hidl_vec<uint32_t> volumes;
     volumes.resize(channelCount);
     for (uint32_t i = 0; i < channelCount; ++i) {
@@ -512,25 +567,29 @@
     }
     Return<Result> ret = effect->volumeChangeNotification(volumes);
     EXPECT_TRUE(ret.isOk());
-    EXPECT_EQ(Result::OK, ret);
+    EXPECT_NO_FATAL_FAILURE(checkResult(ret));
 }
 
 TEST_P(AudioEffectHidlTest, SetAudioMode) {
     description("Verify that SetAudioMode works for an effect");
     Return<Result> ret = effect->setAudioMode(AudioMode::NORMAL);
     EXPECT_TRUE(ret.isOk());
-    EXPECT_EQ(Result::OK, ret);
+    EXPECT_NO_FATAL_FAILURE(checkResult(ret));
 }
 
 TEST_P(AudioEffectHidlTest, SetConfigReverse) {
     description("Verify that SetConfigReverse does not crash");
     Return<Result> ret = effect->setConfigReverse(EffectConfig(), nullptr, nullptr);
     EXPECT_TRUE(ret.isOk());
+    EXPECT_NO_FATAL_FAILURE(checkResultForUseAfterClose(ret));
 }
 
 #if MAJOR_VERSION >= 7
 TEST_P(AudioEffectHidlTest, SetInputDeviceInvalidDeviceAddress) {
     description("Verify that invalid device address is rejected by SetInputDevice");
+    if (useAfterClose) {
+        GTEST_SKIP() << "Does not make sense for the useAfterClose case";
+    }
     DeviceAddress device{.deviceType = "random_string"};
     Return<Result> ret = effect->setInputDevice(device);
     EXPECT_TRUE(ret.isOk());
@@ -548,11 +607,15 @@
     Return<Result> ret = effect->setInputDevice(device);
 #endif
     EXPECT_TRUE(ret.isOk());
+    EXPECT_NO_FATAL_FAILURE(checkResultForUseAfterClose(ret));
 }
 
 #if MAJOR_VERSION >= 7
 TEST_P(AudioEffectHidlTest, SetInvalidAudioSource) {
     description("Verify that an invalid audio source is rejected by SetAudioSource");
+    if (useAfterClose) {
+        GTEST_SKIP() << "Does not make sense for the useAfterClose case";
+    }
     Return<Result> ret = effect->setAudioSource("random_string");
     ASSERT_TRUE(ret.isOk());
     EXPECT_TRUE(ret == Result::INVALID_ARGUMENTS || ret == Result::NOT_SUPPORTED)
@@ -568,12 +631,14 @@
     Return<Result> ret = effect->setAudioSource(toString(xsd::AudioSource::AUDIO_SOURCE_MIC));
 #endif
     EXPECT_TRUE(ret.isOk());
+    EXPECT_NO_FATAL_FAILURE(checkResultForUseAfterClose(ret));
 }
 
 TEST_P(AudioEffectHidlTest, Offload) {
     description("Verify that calling Offload method does not crash");
     Return<Result> ret = effect->offload(EffectOffloadParameter{});
     EXPECT_TRUE(ret.isOk());
+    EXPECT_NO_FATAL_FAILURE(checkResultForUseAfterClose(ret));
 }
 
 TEST_P(AudioEffectHidlTest, PrepareForProcessing) {
@@ -582,7 +647,7 @@
     Return<void> ret = effect->prepareForProcessing(
         [&](Result r, const MQDescriptorSync<Result>&) { retval = r; });
     EXPECT_TRUE(ret.isOk());
-    EXPECT_EQ(Result::OK, retval);
+    EXPECT_NO_FATAL_FAILURE(checkResult(retval));
 }
 
 TEST_P(AudioEffectHidlTest, SetProcessBuffers) {
@@ -601,7 +666,7 @@
     ASSERT_TRUE(success);
     Return<Result> ret2 = effect->setProcessBuffers(buffer, buffer);
     EXPECT_TRUE(ret2.isOk());
-    EXPECT_EQ(Result::OK, ret2);
+    EXPECT_NO_FATAL_FAILURE(checkResult(ret2));
 }
 
 TEST_P(AudioEffectHidlTest, Command) {
@@ -615,6 +680,7 @@
     description("Verify that SetParameter does not crash");
     Return<Result> ret = effect->setParameter(hidl_vec<uint8_t>(), hidl_vec<uint8_t>());
     EXPECT_TRUE(ret.isOk());
+    EXPECT_NO_FATAL_FAILURE(checkResultForUseAfterClose(ret));
 }
 
 TEST_P(AudioEffectHidlTest, GetParameter) {
@@ -630,6 +696,9 @@
     if (!isNewDeviceLaunchingOnTPlus) {
         GTEST_SKIP() << "The test only applies to devices launching on T or later";
     }
+    if (useAfterClose) {
+        GTEST_SKIP() << "Does not make sense for the useAfterClose case";
+    }
     // Use a non-empty parameter to avoid being rejected by any earlier checks.
     hidl_vec<uint8_t> parameter;
     parameter.resize(16);
@@ -647,16 +716,20 @@
 
 TEST_P(AudioEffectHidlTest, GetSupportedConfigsForFeature) {
     description("Verify that GetSupportedConfigsForFeature does not crash");
+    Result retval = Result::OK;
     Return<void> ret = effect->getSupportedConfigsForFeature(
-        0, 0, 0, [&](Result, uint32_t, const hidl_vec<uint8_t>&) {});
+            0, 0, 0, [&](Result r, uint32_t, const hidl_vec<uint8_t>&) { retval = r; });
     EXPECT_TRUE(ret.isOk());
+    EXPECT_NO_FATAL_FAILURE(checkResultForUseAfterClose(retval));
 }
 
 TEST_P(AudioEffectHidlTest, GetCurrentConfigForFeature) {
     description("Verify that GetCurrentConfigForFeature does not crash");
-    Return<void> ret =
-        effect->getCurrentConfigForFeature(0, 0, [&](Result, const hidl_vec<uint8_t>&) {});
+    Result retval = Result::OK;
+    Return<void> ret = effect->getCurrentConfigForFeature(
+            0, 0, [&](Result r, const hidl_vec<uint8_t>&) { retval = r; });
     EXPECT_TRUE(ret.isOk());
+    EXPECT_NO_FATAL_FAILURE(checkResultForUseAfterClose(retval));
 }
 
 TEST_P(AudioEffectHidlTest, SetCurrentConfigForFeature) {
@@ -671,6 +744,9 @@
     if (!isNewDeviceLaunchingOnTPlus) {
         GTEST_SKIP() << "The test only applies to devices launching on T or later";
     }
+    if (useAfterClose) {
+        GTEST_SKIP() << "Does not make sense for the useAfterClose case";
+    }
     // Use very large size to ensure that the service does not crash.
     const uint32_t veryLargeConfigSize = std::numeric_limits<uint32_t>::max() - 100;
     Result retval = Result::OK;
@@ -687,6 +763,9 @@
     if (!isNewDeviceLaunchingOnTPlus) {
         GTEST_SKIP() << "The test only applies to devices launching on T or later";
     }
+    if (useAfterClose) {
+        GTEST_SKIP() << "Does not make sense for the useAfterClose case";
+    }
     // Use very large size to ensure that the service does not crash.
     const uint32_t veryLargeConfigSize = std::numeric_limits<uint32_t>::max() - 100;
     Result retval = Result::OK;
@@ -729,7 +808,8 @@
         }
     });
     ASSERT_TRUE(ret.isOk());
-    ASSERT_EQ(Result::OK, retval);
+    ASSERT_NO_FATAL_FAILURE(checkResult(retval));
+    if (useAfterClose) *numBands = 1;
 }
 
 void EqualizerAudioEffectHidlTest::getLevelRange(int16_t* minLevel, int16_t* maxLevel) {
@@ -742,7 +822,11 @@
         }
     });
     ASSERT_TRUE(ret.isOk());
-    ASSERT_EQ(Result::OK, retval);
+    ASSERT_NO_FATAL_FAILURE(checkResult(retval));
+    if (useAfterClose) {
+        *minLevel = 0;
+        *maxLevel = 255;
+    }
 }
 
 void EqualizerAudioEffectHidlTest::getBandFrequencyRange(uint16_t band, uint32_t* minFreq,
@@ -757,7 +841,7 @@
             }
         });
     ASSERT_TRUE(ret.isOk());
-    ASSERT_EQ(Result::OK, retval);
+    ASSERT_NO_FATAL_FAILURE(checkResult(retval));
     ret = equalizer->getBandCenterFrequency(band, [&](Result r, uint32_t center) {
         retval = r;
         if (retval == Result::OK) {
@@ -765,7 +849,12 @@
         }
     });
     ASSERT_TRUE(ret.isOk());
-    ASSERT_EQ(Result::OK, retval);
+    ASSERT_NO_FATAL_FAILURE(checkResult(retval));
+    if (useAfterClose) {
+        *minFreq = 20;
+        *centerFreq = 10000;
+        *maxFreq = 20000;
+    }
 }
 
 void EqualizerAudioEffectHidlTest::getPresetCount(size_t* count) {
@@ -777,37 +866,38 @@
         }
     });
     ASSERT_TRUE(ret.isOk());
-    ASSERT_EQ(Result::OK, retval);
+    ASSERT_NO_FATAL_FAILURE(checkResult(retval));
+    if (useAfterClose) *count = 1;
 }
 
 TEST_P(EqualizerAudioEffectHidlTest, GetNumBands) {
     description("Verify that Equalizer effect reports at least one band");
     uint16_t numBands = 0;
-    getNumBands(&numBands);
+    ASSERT_NO_FATAL_FAILURE(getNumBands(&numBands));
     EXPECT_GT(numBands, 0);
 }
 
 TEST_P(EqualizerAudioEffectHidlTest, GetLevelRange) {
     description("Verify that Equalizer effect reports adequate band level range");
     int16_t minLevel = 0x7fff, maxLevel = 0;
-    getLevelRange(&minLevel, &maxLevel);
+    ASSERT_NO_FATAL_FAILURE(getLevelRange(&minLevel, &maxLevel));
     EXPECT_GT(maxLevel, minLevel);
 }
 
 TEST_P(EqualizerAudioEffectHidlTest, GetSetBandLevel) {
     description("Verify that manipulating band levels works for Equalizer effect");
     uint16_t numBands = 0;
-    getNumBands(&numBands);
+    ASSERT_NO_FATAL_FAILURE(getNumBands(&numBands));
     ASSERT_GT(numBands, 0);
     int16_t levels[3]{0x7fff, 0, 0};
-    getLevelRange(&levels[0], &levels[2]);
+    ASSERT_NO_FATAL_FAILURE(getLevelRange(&levels[0], &levels[2]));
     ASSERT_GT(levels[2], levels[0]);
     levels[1] = (levels[2] + levels[0]) / 2;
     for (uint16_t i = 0; i < numBands; ++i) {
         for (size_t j = 0; j < ARRAY_SIZE(levels); ++j) {
             Return<Result> ret = equalizer->setBandLevel(i, levels[j]);
             EXPECT_TRUE(ret.isOk());
-            EXPECT_EQ(Result::OK, ret);
+            EXPECT_NO_FATAL_FAILURE(checkResult(ret));
             Result retval = Result::NOT_INITIALIZED;
             int16_t actualLevel;
             Return<void> ret2 = equalizer->getBandLevel(i, [&](Result r, int16_t l) {
@@ -817,8 +907,10 @@
                 }
             });
             EXPECT_TRUE(ret2.isOk());
-            EXPECT_EQ(Result::OK, retval);
-            EXPECT_EQ(levels[j], actualLevel);
+            EXPECT_NO_FATAL_FAILURE(checkResult(retval));
+            if (!useAfterClose) {
+                EXPECT_EQ(levels[j], actualLevel);
+            }
         }
     }
 }
@@ -826,11 +918,11 @@
 TEST_P(EqualizerAudioEffectHidlTest, GetBandCenterFrequencyAndRange) {
     description("Verify that Equalizer effect reports adequate band frequency range");
     uint16_t numBands = 0;
-    getNumBands(&numBands);
+    ASSERT_NO_FATAL_FAILURE(getNumBands(&numBands));
     ASSERT_GT(numBands, 0);
     for (uint16_t i = 0; i < numBands; ++i) {
         uint32_t minFreq = 0xffffffff, centerFreq = 0xffffffff, maxFreq = 0xffffffff;
-        getBandFrequencyRange(i, &minFreq, &centerFreq, &maxFreq);
+        ASSERT_NO_FATAL_FAILURE(getBandFrequencyRange(i, &minFreq, &centerFreq, &maxFreq));
         // Note: NXP legacy implementation reports "1" as upper bound for last band,
         // so this check fails.
         EXPECT_GE(maxFreq, centerFreq);
@@ -841,7 +933,7 @@
 TEST_P(EqualizerAudioEffectHidlTest, GetBandForFrequency) {
     description("Verify that Equalizer effect supports GetBandForFrequency correctly");
     uint16_t numBands = 0;
-    getNumBands(&numBands);
+    ASSERT_NO_FATAL_FAILURE(getNumBands(&numBands));
     ASSERT_GT(numBands, 0);
     for (uint16_t i = 0; i < numBands; ++i) {
         uint32_t freqs[3]{0, 0, 0};
@@ -861,8 +953,10 @@
                 }
             });
             EXPECT_TRUE(ret.isOk());
-            EXPECT_EQ(Result::OK, retval);
-            EXPECT_EQ(i, actualBand) << "Frequency: " << freqs[j];
+            EXPECT_NO_FATAL_FAILURE(checkResult(retval));
+            if (!useAfterClose) {
+                EXPECT_EQ(i, actualBand) << "Frequency: " << freqs[j];
+            }
         }
     }
 }
@@ -870,19 +964,19 @@
 TEST_P(EqualizerAudioEffectHidlTest, GetPresetNames) {
     description("Verify that Equalizer effect reports at least one preset");
     size_t presetCount;
-    getPresetCount(&presetCount);
+    ASSERT_NO_FATAL_FAILURE(getPresetCount(&presetCount));
     EXPECT_GT(presetCount, 0u);
 }
 
 TEST_P(EqualizerAudioEffectHidlTest, GetSetCurrentPreset) {
     description("Verify that manipulating the current preset for Equalizer effect");
     size_t presetCount;
-    getPresetCount(&presetCount);
+    ASSERT_NO_FATAL_FAILURE(getPresetCount(&presetCount));
     ASSERT_GT(presetCount, 0u);
     for (uint16_t i = 0; i < presetCount; ++i) {
         Return<Result> ret = equalizer->setCurrentPreset(i);
         EXPECT_TRUE(ret.isOk());
-        EXPECT_EQ(Result::OK, ret);
+        EXPECT_NO_FATAL_FAILURE(checkResult(ret));
         Result retval = Result::NOT_INITIALIZED;
         uint16_t actualPreset = 0xffff;
         Return<void> ret2 = equalizer->getCurrentPreset([&](Result r, uint16_t p) {
@@ -892,8 +986,10 @@
             }
         });
         EXPECT_TRUE(ret2.isOk());
-        EXPECT_EQ(Result::OK, retval);
-        EXPECT_EQ(i, actualPreset);
+        EXPECT_NO_FATAL_FAILURE(checkResult(retval));
+        if (!useAfterClose) {
+            EXPECT_EQ(i, actualPreset);
+        }
     }
 }
 
@@ -904,7 +1000,7 @@
     using AllProperties =
         ::android::hardware::audio::effect::CPP_VERSION::IEqualizerEffect::AllProperties;
     uint16_t numBands = 0;
-    getNumBands(&numBands);
+    ASSERT_NO_FATAL_FAILURE(getNumBands(&numBands));
     ASSERT_GT(numBands, 0);
     AllProperties props;
     props.bandLevels.resize(numBands);
@@ -919,7 +1015,7 @@
     props.curPreset = -1;
     Return<Result> ret = equalizer->setAllProperties(props);
     EXPECT_TRUE(ret.isOk());
-    EXPECT_EQ(Result::OK, ret);
+    EXPECT_NO_FATAL_FAILURE(checkResult(ret));
     Return<void> ret2 = equalizer->getAllProperties([&](Result r, AllProperties p) {
         retval = r;
         if (retval == Result::OK) {
@@ -927,14 +1023,16 @@
         }
     });
     EXPECT_TRUE(ret2.isOk());
-    EXPECT_EQ(Result::OK, retval);
-    EXPECT_EQ(props.bandLevels, actualProps.bandLevels);
+    EXPECT_NO_FATAL_FAILURE(checkResult(retval));
+    if (!useAfterClose) {
+        EXPECT_EQ(props.bandLevels, actualProps.bandLevels);
+    }
 
     // Verify setting of the current preset via properties.
     props.curPreset = 0;  // Assuming there is at least one preset.
     ret = equalizer->setAllProperties(props);
     EXPECT_TRUE(ret.isOk());
-    EXPECT_EQ(Result::OK, ret);
+    EXPECT_NO_FATAL_FAILURE(checkResult(ret));
     ret2 = equalizer->getAllProperties([&](Result r, AllProperties p) {
         retval = r;
         if (retval == Result::OK) {
@@ -942,8 +1040,10 @@
         }
     });
     EXPECT_TRUE(ret2.isOk());
-    EXPECT_EQ(Result::OK, retval);
-    EXPECT_EQ(props.curPreset, actualProps.curPreset);
+    EXPECT_NO_FATAL_FAILURE(checkResult(retval));
+    if (!useAfterClose) {
+        EXPECT_EQ(props.curPreset, actualProps.curPreset);
+    }
 }
 
 // The main test class for Equalizer Audio Effect HIDL HAL.
@@ -971,7 +1071,7 @@
     const int32_t gain = 100;
     Return<Result> ret = enhancer->setTargetGain(gain);
     EXPECT_TRUE(ret.isOk());
-    EXPECT_EQ(Result::OK, ret);
+    EXPECT_NO_FATAL_FAILURE(checkResult(ret));
     int32_t actualGain = 0;
     Result retval;
     Return<void> ret2 = enhancer->getTargetGain([&](Result r, int32_t g) {
@@ -981,8 +1081,10 @@
         }
     });
     EXPECT_TRUE(ret2.isOk());
-    EXPECT_EQ(Result::OK, retval);
-    EXPECT_EQ(gain, actualGain);
+    EXPECT_NO_FATAL_FAILURE(checkResult(retval));
+    if (!useAfterClose) {
+        EXPECT_EQ(gain, actualGain);
+    }
 }
 
 INSTANTIATE_TEST_SUITE_P(EffectsFactory, AudioEffectsFactoryHidlTest,
@@ -993,25 +1095,29 @@
         Equalizer_IEffect, AudioEffectHidlTest,
         ::testing::Combine(::testing::ValuesIn(::android::hardware::getAllHalInstanceNames(
                                    IEffectsFactory::descriptor)),
-                           ::testing::Values(EQUALIZER_EFFECT_TYPE)),
+                           ::testing::Values(EQUALIZER_EFFECT_TYPE),
+                           ::testing::Values(false, true) /*useAfterClose*/),
         EffectParameterToString);
 INSTANTIATE_TEST_SUITE_P(
         LoudnessEnhancer_IEffect, AudioEffectHidlTest,
         ::testing::Combine(::testing::ValuesIn(::android::hardware::getAllHalInstanceNames(
                                    IEffectsFactory::descriptor)),
-                           ::testing::Values(LOUDNESS_ENHANCER_EFFECT_TYPE)),
+                           ::testing::Values(LOUDNESS_ENHANCER_EFFECT_TYPE),
+                           ::testing::Values(false, true) /*useAfterClose*/),
         EffectParameterToString);
 INSTANTIATE_TEST_SUITE_P(
         Equalizer, EqualizerAudioEffectHidlTest,
         ::testing::Combine(::testing::ValuesIn(::android::hardware::getAllHalInstanceNames(
                                    IEffectsFactory::descriptor)),
-                           ::testing::Values(EQUALIZER_EFFECT_TYPE)),
+                           ::testing::Values(EQUALIZER_EFFECT_TYPE),
+                           ::testing::Values(false, true) /*useAfterClose*/),
         EffectParameterToString);
 INSTANTIATE_TEST_SUITE_P(
         LoudnessEnhancer, LoudnessEnhancerAudioEffectHidlTest,
         ::testing::Combine(::testing::ValuesIn(::android::hardware::getAllHalInstanceNames(
                                    IEffectsFactory::descriptor)),
-                           ::testing::Values(LOUDNESS_ENHANCER_EFFECT_TYPE)),
+                           ::testing::Values(LOUDNESS_ENHANCER_EFFECT_TYPE),
+                           ::testing::Values(false, true) /*useAfterClose*/),
         EffectParameterToString);
 // When the VTS test runs on a device lacking the corresponding HAL version the parameter
 // list is empty, this isn't a problem.
diff --git a/audio/policy/1.0/xml/pfw_schemas/Android.bp b/audio/policy/1.0/xml/pfw_schemas/Android.bp
index 5d669c2..225c065 100644
--- a/audio/policy/1.0/xml/pfw_schemas/Android.bp
+++ b/audio/policy/1.0/xml/pfw_schemas/Android.bp
@@ -11,6 +11,7 @@
     name: "audio_policy_engine_configurable_configuration_V1_0",
     srcs: ["AllSchemas.xsd"],
     package_name: "audio.policy.configurable.V1_0",
+    root_elements: ["ParameterFrameworkConfiguration"],
 }
 
 // Unfortunately, all rules only have a single output, thus
diff --git a/audio/policy/1.0/xml/pfw_schemas/api/current.txt b/audio/policy/1.0/xml/pfw_schemas/api/current.txt
index c2fb6fc..2b83e60 100644
--- a/audio/policy/1.0/xml/pfw_schemas/api/current.txt
+++ b/audio/policy/1.0/xml/pfw_schemas/api/current.txt
@@ -470,23 +470,7 @@
 
   public class XmlParser {
     ctor public XmlParser();
-    method public static audio.policy.configurable.V1_0.BitParameterBlock readBitParameterBlock(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public static audio.policy.configurable.V1_0.BooleanParameter readBooleanParameter(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public static audio.policy.configurable.V1_0.ComponentTypeSetType readComponentTypeSetType(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public static audio.policy.configurable.V1_0.ComponentTypeSetType readComponentTypeSetType(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public static audio.policy.configurable.V1_0.ConfigurableDomainType readConfigurableDomainType(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public static audio.policy.configurable.V1_0.ConfigurableDomains readConfigurableDomains(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public static audio.policy.configurable.V1_0.EnumParameterType readEnumParameterType(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public static audio.policy.configurable.V1_0.FixedPointParameterType readFixedPointParameterType(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public static audio.policy.configurable.V1_0.FloatingPointParameterType readFloatingPointParameterType(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public static audio.policy.configurable.V1_0.IntegerParameterType readIntegerParameterType(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public static audio.policy.configurable.V1_0.LinearAdaptationType readLinearAdaptationType(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public static audio.policy.configurable.V1_0.LogarithmicAdaptation readLogarithmicAdaptation(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public static audio.policy.configurable.V1_0.ParameterFrameworkConfiguration readParameterFrameworkConfiguration(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public static audio.policy.configurable.V1_0.StringParameter readStringParameter(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public static audio.policy.configurable.V1_0.SubsystemPlugins readSubsystemPlugins(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public static audio.policy.configurable.V1_0.SubsystemType readSubsystemType(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public static audio.policy.configurable.V1_0.SystemClass readSystemClass(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
   }
diff --git a/authsecret/1.0/vts/functional/OWNERS b/authsecret/1.0/vts/functional/OWNERS
deleted file mode 100644
index ec8c304..0000000
--- a/authsecret/1.0/vts/functional/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 186411
-chengyouho@google.com
-frankwoo@google.com
diff --git a/authsecret/OWNERS b/authsecret/OWNERS
new file mode 100644
index 0000000..5a5d074
--- /dev/null
+++ b/authsecret/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 186411
+
+chengyouho@google.com
+frankwoo@google.com
diff --git a/authsecret/aidl/default/Android.bp b/authsecret/aidl/default/Android.bp
index 7ce83fd..91f4fae 100644
--- a/authsecret/aidl/default/Android.bp
+++ b/authsecret/aidl/default/Android.bp
@@ -26,16 +26,49 @@
 cc_binary {
     name: "android.hardware.authsecret-service.example",
     relative_install_path: "hw",
-    init_rc: ["android.hardware.authsecret-service.example.rc"],
-    vintf_fragments: ["android.hardware.authsecret-service.example.xml"],
     vendor: true,
     srcs: [
         "service.cpp",
         "AuthSecret.cpp",
     ],
     shared_libs: [
+        "libbinder_ndk",
+        "liblog",
+    ],
+    static_libs: [
         "android.hardware.authsecret-V1-ndk",
         "libbase",
-        "libbinder_ndk",
+    ],
+    stl: "c++_static",
+}
+
+prebuilt_etc {
+    name: "android.hardware.authsecret-service.example.rc",
+    src: "android.hardware.authsecret-service.example.rc",
+    installable: false,
+}
+
+prebuilt_etc {
+    name: "android.hardware.authsecret-service.example.xml",
+    src: "android.hardware.authsecret-service.example.xml",
+    sub_dir: "vintf",
+    installable: false,
+}
+
+apex {
+    name: "com.android.hardware.authsecret",
+    manifest: "manifest.json",
+    file_contexts: "file_contexts",
+    key: "com.android.hardware.key",
+    certificate: ":com.android.hardware.certificate",
+    updatable: false,
+    vendor: true,
+
+    binaries: [
+        "android.hardware.authsecret-service.example",
+    ],
+    prebuilts: [
+        "android.hardware.authsecret-service.example.rc", // init_rc
+        "android.hardware.authsecret-service.example.xml", // vintf_fragments
     ],
 }
diff --git a/authsecret/aidl/default/android.hardware.authsecret-service.example.rc b/authsecret/aidl/default/android.hardware.authsecret-service.example.rc
index fef6e24..9f51837 100644
--- a/authsecret/aidl/default/android.hardware.authsecret-service.example.rc
+++ b/authsecret/aidl/default/android.hardware.authsecret-service.example.rc
@@ -1,4 +1,4 @@
-service vendor.authsecret_default /vendor/bin/hw/android.hardware.authsecret-service.example
+service vendor.authsecret_default /apex/com.android.hardware.authsecret/bin/hw/android.hardware.authsecret-service.example
     class hal
     user hsm
     group hsm
diff --git a/authsecret/aidl/default/file_contexts b/authsecret/aidl/default/file_contexts
new file mode 100644
index 0000000..8e79f26
--- /dev/null
+++ b/authsecret/aidl/default/file_contexts
@@ -0,0 +1,3 @@
+(/.*)?                                                      u:object_r:vendor_file:s0
+/etc(/.*)?                                                  u:object_r:vendor_configs_file:s0
+/bin/hw/android\.hardware\.authsecret-service\.example      u:object_r:hal_authsecret_default_exec:s0
\ No newline at end of file
diff --git a/authsecret/aidl/default/manifest.json b/authsecret/aidl/default/manifest.json
new file mode 100644
index 0000000..ad5a45b
--- /dev/null
+++ b/authsecret/aidl/default/manifest.json
@@ -0,0 +1,4 @@
+{
+    "name": "com.android.hardware.authsecret",
+    "version": 1
+}
diff --git a/authsecret/aidl/vts/OWNERS b/authsecret/aidl/vts/OWNERS
deleted file mode 100644
index 40d95e4..0000000
--- a/authsecret/aidl/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-chengyouho@google.com
-frankwoo@google.com
diff --git a/automotive/audiocontrol/aidl/Android.bp b/automotive/audiocontrol/aidl/Android.bp
index 9ae77cd..86b63a6 100644
--- a/automotive/audiocontrol/aidl/Android.bp
+++ b/automotive/audiocontrol/aidl/Android.bp
@@ -13,9 +13,9 @@
     name: "android.hardware.automotive.audiocontrol",
     vendor_available: true,
     srcs: ["android/hardware/automotive/audiocontrol/*.aidl"],
-    imports: [
-        "android.hardware.audio.common-V1",
-        "android.media.audio.common.types-V2",
+    defaults: [
+        "latest_android_hardware_audio_common_import_interface",
+        "latest_android_media_audio_common_types_import_interface",
     ],
     stability: "vintf",
     backend: {
@@ -52,6 +52,37 @@
         },
 
     ],
-    frozen: true,
+    frozen: false,
 
 }
+
+// Note: This should always be one version ahead of the last frozen version
+latest_android_hardware_automotive_audiocontrol = "android.hardware.automotive.audiocontrol-V4"
+
+cc_defaults {
+    name: "latest_android_hardware_automotive_audiocontrol_cpp_static",
+    static_libs: [
+        latest_android_hardware_automotive_audiocontrol + "-cpp",
+    ],
+}
+
+cc_defaults {
+    name: "latest_android_hardware_automotive_audiocontrol_cpp_shared",
+    shared_libs: [
+        latest_android_hardware_automotive_audiocontrol + "-cpp",
+    ],
+}
+
+cc_defaults {
+    name: "latest_android_hardware_automotive_audiocontrol_ndk_static",
+    static_libs: [
+        latest_android_hardware_automotive_audiocontrol + "-ndk",
+    ],
+}
+
+cc_defaults {
+    name: "latest_android_hardware_automotive_audiocontrol_ndk_shared",
+    shared_libs: [
+        latest_android_hardware_automotive_audiocontrol + "-ndk",
+    ],
+}
diff --git a/automotive/audiocontrol/aidl/default/Android.bp b/automotive/audiocontrol/aidl/default/Android.bp
index 435c2d6..a48d228 100644
--- a/automotive/audiocontrol/aidl/default/Android.bp
+++ b/automotive/audiocontrol/aidl/default/Android.bp
@@ -27,11 +27,13 @@
     init_rc: ["audiocontrol-default.rc"],
     vintf_fragments: ["audiocontrol-default.xml"],
     vendor: true,
+    defaults: [
+        "latest_android_hardware_audio_common_ndk_shared",
+        "latest_android_hardware_automotive_audiocontrol_ndk_shared",
+    ],
     shared_libs: [
         "android.hardware.audio.common@7.0-enums",
-        "android.hardware.audio.common-V1-ndk",
         "android.frameworks.automotive.powerpolicy-V2-ndk",
-        "android.hardware.automotive.audiocontrol-V3-ndk",
         "libbase",
         "libbinder_ndk",
         "libcutils",
diff --git a/automotive/audiocontrol/aidl/default/AudioControl.cpp b/automotive/audiocontrol/aidl/default/AudioControl.cpp
index cf7307d..7e7e145 100644
--- a/automotive/audiocontrol/aidl/default/AudioControl.cpp
+++ b/automotive/audiocontrol/aidl/default/AudioControl.cpp
@@ -244,15 +244,15 @@
 template <typename aidl_type>
 static inline std::string toString(const std::vector<aidl_type>& in_values) {
     return std::accumulate(std::begin(in_values), std::end(in_values), std::string{},
-                           [](std::string& ls, const aidl_type& rs) {
-                               return ls += (ls.empty() ? "" : ",") + rs.toString();
+                           [](const std::string& ls, const aidl_type& rs) {
+                               return ls + (ls.empty() ? "" : ",") + rs.toString();
                            });
 }
 template <typename aidl_enum_type>
 static inline std::string toEnumString(const std::vector<aidl_enum_type>& in_values) {
     return std::accumulate(std::begin(in_values), std::end(in_values), std::string{},
-                           [](std::string& ls, const aidl_enum_type& rs) {
-                               return ls += (ls.empty() ? "" : ",") + toString(rs);
+                           [](const std::string& ls, const aidl_enum_type& rs) {
+                               return ls + (ls.empty() ? "" : ",") + toString(rs);
                            });
 }
 
diff --git a/automotive/audiocontrol/aidl/default/audiocontrol-default.xml b/automotive/audiocontrol/aidl/default/audiocontrol-default.xml
index 95cd7f0..bcb5669 100644
--- a/automotive/audiocontrol/aidl/default/audiocontrol-default.xml
+++ b/automotive/audiocontrol/aidl/default/audiocontrol-default.xml
@@ -1,7 +1,7 @@
 <manifest version="2.0" type="device">
     <hal format="aidl">
         <name>android.hardware.automotive.audiocontrol</name>
-        <version>3</version>
+        <version>4</version>
         <fqname>IAudioControl/default</fqname>
     </hal>
 </manifest>
diff --git a/automotive/audiocontrol/aidl/vts/Android.bp b/automotive/audiocontrol/aidl/vts/Android.bp
index cfc2a3e..c73ad79 100644
--- a/automotive/audiocontrol/aidl/vts/Android.bp
+++ b/automotive/audiocontrol/aidl/vts/Android.bp
@@ -24,6 +24,8 @@
 cc_test {
     name: "VtsAidlHalAudioControlTest",
     defaults: [
+        "latest_android_hardware_audio_common_cpp_static",
+        "latest_android_hardware_automotive_audiocontrol_cpp_static",
         "latest_android_media_audio_common_types_cpp_static",
         "VtsHalTargetTestDefaults",
         "use_libaidlvintf_gtest_helper_static",
@@ -38,8 +40,6 @@
         "libxml2",
     ],
     static_libs: [
-        "android.hardware.automotive.audiocontrol-V3-cpp",
-        "android.hardware.audio.common-V1-cpp",
         "libgmock",
     ],
     test_suites: [
diff --git a/automotive/can/1.0/default/CanSocket.h b/automotive/can/1.0/default/CanSocket.h
index fd956b5..f3e8e60 100644
--- a/automotive/can/1.0/default/CanSocket.h
+++ b/automotive/can/1.0/default/CanSocket.h
@@ -22,6 +22,7 @@
 
 #include <atomic>
 #include <chrono>
+#include <functional>
 #include <thread>
 
 namespace android::hardware::automotive::can::V1_0::implementation {
diff --git a/automotive/can/1.0/default/libc++fs/include/automotive/filesystem b/automotive/can/1.0/default/libc++fs/include/automotive/filesystem
index 660ad09..bd3dda5 100644
--- a/automotive/can/1.0/default/libc++fs/include/automotive/filesystem
+++ b/automotive/can/1.0/default/libc++fs/include/automotive/filesystem
@@ -9,6 +9,18 @@
 //===----------------------------------------------------------------------===//
 #ifndef _LIBAUTO_FILESYSTEM
 #define _LIBAUTO_FILESYSTEM
+
+// TODO(152067309): Remove this once the libc++ upgrade is complete.
+#include <__config>
+#if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION > 8000
+
+#include <filesystem>
+namespace android::hardware::automotive {
+namespace filesystem = std::filesystem;
+}
+
+#else
+
 /*
     filesystem synopsis
 
@@ -2696,4 +2708,6 @@
 
 _LIBCPP_POP_MACROS
 
+#endif  // defined(_LIBCPP_VERSION) && _LIBCPP_VERSION > 8000
+
 #endif // _LIBAUTO_FILESYSTEM
diff --git a/automotive/can/1.0/default/libc++fs/src/filesystem/directory_iterator.cpp b/automotive/can/1.0/default/libc++fs/src/filesystem/directory_iterator.cpp
index 37c863b..0dbf492 100644
--- a/automotive/can/1.0/default/libc++fs/src/filesystem/directory_iterator.cpp
+++ b/automotive/can/1.0/default/libc++fs/src/filesystem/directory_iterator.cpp
@@ -6,9 +6,15 @@
 // Source Licenses. See LICENSE.TXT for details.
 //
 //===----------------------------------------------------------------------===//
+
+// TODO(152067309): Remove this once the libc++ upgrade is complete.
+#include <__config>
+#if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION <= 8000
+
 /* clang-format off */
 #include "automotive/filesystem"
 #include <__config>
+
 #if defined(_LIBCPP_WIN32API)
 #define WIN32_LEAN_AND_MEAN
 #include <Windows.h>
@@ -395,3 +401,5 @@
 
 }  // namespace android::hardware::automotive::filesystem
 /* clang-format on */
+
+#endif // defined(_LIBCPP_VERSION) && _LIBCPP_VERSION <= 8000
diff --git a/automotive/can/1.0/default/libc++fs/src/filesystem/operations.cpp b/automotive/can/1.0/default/libc++fs/src/filesystem/operations.cpp
index 404c0bd..6a76bdc 100644
--- a/automotive/can/1.0/default/libc++fs/src/filesystem/operations.cpp
+++ b/automotive/can/1.0/default/libc++fs/src/filesystem/operations.cpp
@@ -6,6 +6,11 @@
 // Source Licenses. See LICENSE.TXT for details.
 //
 //===----------------------------------------------------------------------===//
+
+// TODO(152067309): Remove this once the libc++ upgrade is complete.
+#include <__config>
+#if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION <= 8000
+
 /* clang-format off */
 #include "automotive/filesystem"
 #include <array>
@@ -1771,3 +1776,5 @@
 #endif
 }  // namespace android::hardware::automotive::filesystem
 /* clang-format on */
+
+#endif // defined(_LIBCPP_VERSION) && _LIBCPP_VERSION <= 8000
diff --git a/automotive/can/1.0/default/libnetdevice/ifreqs.h b/automotive/can/1.0/default/libnetdevice/ifreqs.h
index d8d6fe0..aa7030b 100644
--- a/automotive/can/1.0/default/libnetdevice/ifreqs.h
+++ b/automotive/can/1.0/default/libnetdevice/ifreqs.h
@@ -18,6 +18,7 @@
 
 #include <net/if.h>
 
+#include <atomic>
 #include <string>
 
 namespace android::netdevice::ifreqs {
diff --git a/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp b/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
index aad07de..413b4b1 100644
--- a/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
+++ b/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
@@ -27,6 +27,8 @@
 #include <linux/rtnetlink.h>
 #include <net/if.h>
 
+#include <algorithm>
+#include <iterator>
 #include <sstream>
 
 namespace android::netdevice {
@@ -102,7 +104,7 @@
 
 static bool hasIpv4(std::string ifname) {
     auto ifr = ifreqs::fromName(ifname);
-    switch (const auto status = ifreqs::trySend(SIOCGIFADDR, ifr)) {
+    switch (ifreqs::trySend(SIOCGIFADDR, ifr)) {
         case 0:
             return true;
         case EADDRNOTAVAIL:
diff --git a/automotive/can/1.0/default/libnl++/common.cpp b/automotive/can/1.0/default/libnl++/common.cpp
index 23c2d94..1287bb5 100644
--- a/automotive/can/1.0/default/libnl++/common.cpp
+++ b/automotive/can/1.0/default/libnl++/common.cpp
@@ -20,6 +20,8 @@
 
 #include <net/if.h>
 
+#include <algorithm>
+
 namespace android::nl {
 
 unsigned int nametoindex(const std::string& ifname) {
diff --git a/automotive/can/1.0/default/tests/fuzzer/AutomotiveCanV1_0Fuzzer.cpp b/automotive/can/1.0/default/tests/fuzzer/AutomotiveCanV1_0Fuzzer.cpp
index 96110db..e882160 100644
--- a/automotive/can/1.0/default/tests/fuzzer/AutomotiveCanV1_0Fuzzer.cpp
+++ b/automotive/can/1.0/default/tests/fuzzer/AutomotiveCanV1_0Fuzzer.cpp
@@ -18,9 +18,9 @@
 
 namespace android::hardware::automotive::can::V1_0::implementation::fuzzer {
 
-constexpr CanController::InterfaceType kInterfaceType[] = {CanController::InterfaceType::VIRTUAL,
-                                                           CanController::InterfaceType::SOCKETCAN,
-                                                           CanController::InterfaceType::SLCAN};
+constexpr CanController::InterfaceType kInterfaceType[] = {
+        CanController::InterfaceType::VIRTUAL, CanController::InterfaceType::SOCKETCAN,
+        CanController::InterfaceType::SLCAN, CanController::InterfaceType::INDEXED};
 constexpr FilterFlag kFilterFlag[] = {FilterFlag::DONT_CARE, FilterFlag::SET, FilterFlag::NOT_SET};
 constexpr size_t kInterfaceTypeLength = std::size(kInterfaceType);
 constexpr size_t kFilterFlagLength = std::size(kFilterFlag);
@@ -28,8 +28,8 @@
 constexpr size_t kMaxPayloadBytes = 64;
 constexpr size_t kMaxFilters = 20;
 constexpr size_t kMaxSerialNumber = 1000;
-constexpr size_t kMaxBuses = 10;
-constexpr size_t kMaxRepeat = 5;
+constexpr size_t kMaxBuses = 100;
+constexpr size_t kMaxRepeat = 100;
 
 Bus CanFuzzer::makeBus() {
     ICanController::BusConfig config = {};
@@ -56,9 +56,13 @@
 }
 
 void CanFuzzer::invokeUpInterface() {
-    const CanController::InterfaceType iftype =
-            kInterfaceType[mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(
-                    0, kInterfaceTypeLength - 1)];
+    CanController::InterfaceType controller;
+    if (mFuzzedDataProvider->ConsumeBool()) {
+        controller = (CanController::InterfaceType)mFuzzedDataProvider->ConsumeIntegral<uint8_t>();
+    } else {
+        controller = kInterfaceType[mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(
+                0, kInterfaceTypeLength - 1)];
+    }
     std::string configName;
 
     if (const bool shouldInvokeValidBus = mFuzzedDataProvider->ConsumeBool();
@@ -73,7 +77,7 @@
 
     ICanController::BusConfig config = {.name = configName};
 
-    if (iftype == CanController::InterfaceType::SOCKETCAN) {
+    if (controller == CanController::InterfaceType::SOCKETCAN) {
         CanController::BusConfig::InterfaceId::Socketcan socketcan = {};
         if (const bool shouldPassSerialSocket = mFuzzedDataProvider->ConsumeBool();
             shouldPassSerialSocket) {
@@ -83,7 +87,7 @@
             socketcan.ifname(ifname);
         }
         config.interfaceId.socketcan(socketcan);
-    } else if (iftype == CanController::InterfaceType::SLCAN) {
+    } else if (controller == CanController::InterfaceType::SLCAN) {
         CanController::BusConfig::InterfaceId::Slcan slcan = {};
         if (const bool shouldPassSerialSlcan = mFuzzedDataProvider->ConsumeBool();
             shouldPassSerialSlcan) {
@@ -93,8 +97,12 @@
             slcan.ttyname(ifname);
         }
         config.interfaceId.slcan(slcan);
-    } else if (iftype == CanController::InterfaceType::VIRTUAL) {
+    } else if (controller == CanController::InterfaceType::VIRTUAL) {
         config.interfaceId.virtualif({ifname});
+    } else if (controller == CanController::InterfaceType::INDEXED) {
+        CanController::BusConfig::InterfaceId::Indexed indexed;
+        indexed.index = mFuzzedDataProvider->ConsumeIntegral<uint8_t>();
+        config.interfaceId.indexed(indexed);
     }
 
     const size_t numInvocations =
@@ -108,8 +116,13 @@
     hidl_string configName;
     if (const bool shouldInvokeValidBus = mFuzzedDataProvider->ConsumeBool();
         (shouldInvokeValidBus) && (mBusNames.size() > 0)) {
-        const size_t busNameIndex =
-                mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(0, mBusNames.size() - 1);
+        size_t busNameIndex;
+        if (mBusNames.size() == 1) {
+            busNameIndex = 0;
+        } else {
+            busNameIndex =
+                    mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(0, mBusNames.size() - 1);
+        }
         configName = mBusNames[busNameIndex];
     } else {
         configName = mFuzzedDataProvider->ConsumeRandomLengthString(kMaxCharacters);
@@ -122,12 +135,6 @@
     }
 }
 
-void CanFuzzer::invokeController() {
-    getSupportedInterfaceTypes();
-    invokeUpInterface();
-    invokeDownInterface();
-}
-
 void CanFuzzer::invokeBus() {
     const size_t numBuses = mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(1, kMaxBuses);
     for (size_t i = 0; i < numBuses; ++i) {
@@ -152,12 +159,22 @@
             for (uint32_t k = 0; k < numFilters; ++k) {
                 filterVector[k].id = mFuzzedDataProvider->ConsumeIntegral<uint32_t>();
                 filterVector[k].mask = mFuzzedDataProvider->ConsumeIntegral<uint32_t>();
-                filterVector[k].rtr =
-                        kFilterFlag[mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(
-                                0, kFilterFlagLength - 1)];
-                filterVector[k].extendedFormat =
-                        kFilterFlag[mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(
-                                0, kFilterFlagLength - 1)];
+                if (mFuzzedDataProvider->ConsumeBool()) {
+                    filterVector[k].rtr =
+                            (FilterFlag)mFuzzedDataProvider->ConsumeIntegral<uint8_t>();
+                } else {
+                    filterVector[k].rtr =
+                            kFilterFlag[mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(
+                                    0, kFilterFlagLength - 1)];
+                }
+                if (mFuzzedDataProvider->ConsumeBool()) {
+                    filterVector[k].extendedFormat =
+                            (FilterFlag)mFuzzedDataProvider->ConsumeIntegral<uint8_t>();
+                } else {
+                    filterVector[k].extendedFormat =
+                            kFilterFlag[mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(
+                                    0, kFilterFlagLength - 1)];
+                }
                 filterVector[k].exclude = mFuzzedDataProvider->ConsumeBool();
             }
             auto listener = listeningBus.listen(filterVector);
@@ -175,8 +192,16 @@
 
 void CanFuzzer::process(const uint8_t* data, size_t size) {
     mFuzzedDataProvider = new FuzzedDataProvider(data, size);
-    invokeController();
-    invokeBus();
+    while (mFuzzedDataProvider->remaining_bytes()) {
+        auto CanFuzzerFunction =
+                mFuzzedDataProvider->PickValueInArray<const std::function<void()>>({
+                        [&]() { getSupportedInterfaceTypes(); },
+                        [&]() { invokeUpInterface(); },
+                        [&]() { invokeDownInterface(); },
+                        [&]() { invokeBus(); },
+                });
+        CanFuzzerFunction();
+    }
 }
 
 bool CanFuzzer::init() {
diff --git a/automotive/can/1.0/default/tests/fuzzer/AutomotiveCanV1_0Fuzzer.h b/automotive/can/1.0/default/tests/fuzzer/AutomotiveCanV1_0Fuzzer.h
index 930cddd..3211bd0 100644
--- a/automotive/can/1.0/default/tests/fuzzer/AutomotiveCanV1_0Fuzzer.h
+++ b/automotive/can/1.0/default/tests/fuzzer/AutomotiveCanV1_0Fuzzer.h
@@ -116,7 +116,6 @@
     hidl_vec<hidl_string> getBusNames();
     void getSupportedInterfaceTypes();
     void invokeBus();
-    void invokeController();
     void invokeUpInterface();
     void invokeDownInterface();
     FuzzedDataProvider* mFuzzedDataProvider = nullptr;
diff --git a/automotive/evs/OWNERS b/automotive/evs/OWNERS
index 15de48f..4787f0b 100644
--- a/automotive/evs/OWNERS
+++ b/automotive/evs/OWNERS
@@ -1,2 +1,2 @@
 ankitarora@google.com
-jwhpryor@google.com
+changyeon@google.com
diff --git a/automotive/evs/aidl/Android.bp b/automotive/evs/aidl/Android.bp
index bafb4af..3bfe8f3 100644
--- a/automotive/evs/aidl/Android.bp
+++ b/automotive/evs/aidl/Android.bp
@@ -30,7 +30,7 @@
     stability: "vintf",
     imports: [
         "android.hardware.common-V2",
-        "android.hardware.graphics.common-V4",
+        "android.hardware.graphics.common-V5",
     ],
     backend: {
         java: {
@@ -53,14 +53,14 @@
             version: "1",
             imports: [
                 "android.hardware.common-V2",
-                "android.hardware.graphics.common-V4",
+                "android.hardware.graphics.common-V5",
             ],
         },
         {
             version: "2",
             imports: [
                 "android.hardware.common-V2",
-                "android.hardware.graphics.common-V4",
+                "android.hardware.graphics.common-V5",
             ],
         },
 
diff --git a/automotive/evs/aidl/impl/default/Android.bp b/automotive/evs/aidl/impl/default/Android.bp
index 70c523b..3d5b7c4 100644
--- a/automotive/evs/aidl/impl/default/Android.bp
+++ b/automotive/evs/aidl/impl/default/Android.bp
@@ -21,24 +21,11 @@
     default_applicable_licenses: ["hardware_interfaces_license"],
 }
 
-cc_binary {
-    name: "android.hardware.automotive.evs-aidl-default-service",
+cc_defaults {
+    name: "android.hardware.automotive.evs-aidl-default-service-default",
     defaults: ["EvsHalDefaults"],
-    vintf_fragments: ["manifest_evs-default-service.xml"],
-    init_rc: ["evs-default-service.rc"],
-    vendor: true,
-    relative_install_path: "hw",
-    cflags: [
-        "-DGL_GLEXT_PROTOTYPES",
-        "-DEGL_EGLEXT_PROTOTYPES",
-        "-Wall",
-        "-Wextra",
-        "-Werror",
-        "-Wthread-safety",
-    ],
-    srcs: [
-        ":libgui_frame_event_aidl",
-        "src/*.cpp",
+    header_libs: [
+        "libstagefright_headers",
     ],
     shared_libs: [
         "android.hardware.graphics.bufferqueue@1.0",
@@ -46,28 +33,63 @@
         "android.hidl.token@1.0-utils",
         "libEGL",
         "libGLESv2",
-        "libbase",
         "libbinder_ndk",
         "libbufferqueueconverter",
         "libcamera_metadata",
         "libhardware_legacy",
         "libhidlbase",
-        "liblog",
+        "libmediandk",
         "libnativewindow",
         "libtinyxml2",
         "libui",
-        "libutils",
         "libyuv",
     ],
-    static_libs: [
-        "android.frameworks.automotive.display-V1-ndk",
+}
+
+cc_library {
+    name: "android.hardware.automotive.evs-aidl-default-service-lib",
+    defaults: ["android.hardware.automotive.evs-aidl-default-service-default"],
+    vendor: true,
+    cflags: [
+        "-DGL_GLEXT_PROTOTYPES",
+        "-DEGL_EGLEXT_PROTOTYPES",
+    ],
+    srcs: [
+        ":libgui_frame_event_aidl",
+        "src/*.cpp",
+    ],
+    exclude_srcs: ["src/service.cpp"],
+    whole_static_libs: [
+        "android.frameworks.automotive.display-V2-ndk",
         "android.hardware.automotive.evs-V2-ndk",
         "android.hardware.common-V2-ndk",
         "libaidlcommonsupport",
         "libcutils",
     ],
+    header_libs: [
+        "libgui_aidl_headers",
+    ],
     local_include_dirs: ["include"],
     include_dirs: ["frameworks/native/include/"],
+    export_include_dirs: ["include"],
+}
+
+cc_binary {
+    name: "android.hardware.automotive.evs-aidl-default-service",
+    defaults: ["android.hardware.automotive.evs-aidl-default-service-default"],
+    vintf_fragments: ["manifest_evs-default-service.xml"],
+    init_rc: ["evs-default-service.rc"],
+    vendor: true,
+    relative_install_path: "hw",
+    cflags: [
+        "-DGL_GLEXT_PROTOTYPES",
+        "-DEGL_EGLEXT_PROTOTYPES",
+    ],
+    srcs: ["src/service.cpp"],
+    static_libs: [
+        "android.hardware.automotive.evs-aidl-default-service-lib",
+    ],
+    include_dirs: ["frameworks/native/include/"],
     required: ["evs_mock_hal_configuration.xml"],
 }
 
@@ -77,3 +99,31 @@
     src: "resources/evs_mock_configuration.xml",
     sub_dir: "automotive/evs",
 }
+
+cc_test {
+    name: "android.hardware.automotive.evs-aidl-default-service_cam_buffer_test",
+    defaults: ["android.hardware.automotive.evs-aidl-default-service-default"],
+    vendor: true,
+    srcs: ["tests/EvsCameraBufferTest.cpp"],
+    static_libs: [
+        "android.hardware.automotive.evs-aidl-default-service-lib",
+        "libgmock",
+    ],
+    test_suites: [
+        "general-tests",
+    ],
+}
+
+cc_test {
+    name: "android.hardware.automotive.evs-aidl-default-service_cam_state_test",
+    defaults: ["android.hardware.automotive.evs-aidl-default-service-default"],
+    vendor: true,
+    srcs: ["tests/EvsCameraStateTest.cpp"],
+    static_libs: [
+        "android.hardware.automotive.evs-aidl-default-service-lib",
+        "libgmock",
+    ],
+    test_suites: [
+        "general-tests",
+    ],
+}
diff --git a/automotive/evs/aidl/impl/default/include/ConfigManager.h b/automotive/evs/aidl/impl/default/include/ConfigManager.h
index 1d5fe77..37a17dc 100644
--- a/automotive/evs/aidl/impl/default/include/ConfigManager.h
+++ b/automotive/evs/aidl/impl/default/include/ConfigManager.h
@@ -25,8 +25,10 @@
 
 #include <tinyxml2.h>
 
+#include <limits>
 #include <string>
 #include <string_view>
+#include <type_traits>
 #include <unordered_map>
 #include <unordered_set>
 #include <vector>
@@ -54,6 +56,15 @@
     /* Camera device's capabilities and metadata */
     class CameraInfo {
       public:
+        enum class DeviceType : std::int32_t {
+            NONE = 0,
+            MOCK = 1,
+            V4L2 = 2,
+            VIDEO = 3,
+
+            UNKNOWN = std::numeric_limits<std::underlying_type_t<DeviceType>>::max(),
+        };
+
         CameraInfo() : characteristics(nullptr) {}
 
         virtual ~CameraInfo();
@@ -69,6 +80,10 @@
             return characteristics != nullptr;
         }
 
+        static DeviceType deviceTypeFromSV(const std::string_view sv);
+
+        DeviceType deviceType{DeviceType::NONE};
+
         /*
          * List of supported controls that the primary client can program.
          * Paraemters are stored with its valid range
diff --git a/automotive/evs/aidl/impl/default/include/EvsAllCameras.h b/automotive/evs/aidl/impl/default/include/EvsAllCameras.h
new file mode 100644
index 0000000..a76501d
--- /dev/null
+++ b/automotive/evs/aidl/impl/default/include/EvsAllCameras.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "EvsMockCamera.h"
+#include "EvsVideoEmulatedCamera.h"
diff --git a/automotive/evs/aidl/impl/default/include/EvsCamera.h b/automotive/evs/aidl/impl/default/include/EvsCamera.h
new file mode 100644
index 0000000..539d5f6
--- /dev/null
+++ b/automotive/evs/aidl/impl/default/include/EvsCamera.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "EvsCameraBase.h"
+
+#include <aidl/android/hardware/automotive/evs/IEvsCameraStream.h>
+#include <cutils/native_handle.h>
+
+#include <cstddef>
+#include <mutex>
+#include <utility>
+#include <vector>
+
+namespace aidl::android::hardware::automotive::evs::implementation {
+
+class EvsCamera : public EvsCameraBase {
+  private:
+    using Base = EvsCameraBase;
+    using Self = EvsCamera;
+
+  public:
+    using Base::Base;
+
+    ~EvsCamera() override;
+
+    // Methods from ::android::hardware::automotive::evs::IEvsCamera follow.
+    ndk::ScopedAStatus doneWithFrame(const std::vector<evs::BufferDesc>& buffers) override;
+
+    ndk::ScopedAStatus importExternalBuffers(const std::vector<evs::BufferDesc>& buffers,
+                                             int32_t* _aidl_return) override;
+
+    ndk::ScopedAStatus setMaxFramesInFlight(int32_t bufferCount) override;
+
+    ndk::ScopedAStatus startVideoStream(
+            const std::shared_ptr<evs::IEvsCameraStream>& receiver) override;
+
+    ndk::ScopedAStatus stopVideoStream() override;
+
+    ndk::ScopedAStatus pauseVideoStream() override;
+
+    ndk::ScopedAStatus resumeVideoStream() override;
+
+  protected:
+    virtual ::android::status_t allocateOneFrame(buffer_handle_t* handle) = 0;
+
+    virtual void freeOneFrame(const buffer_handle_t handle);
+
+    virtual bool preVideoStreamStart_locked(const std::shared_ptr<evs::IEvsCameraStream>& receiver,
+                                            ndk::ScopedAStatus& status,
+                                            std::unique_lock<std::mutex>& lck);
+
+    virtual bool startVideoStreamImpl_locked(const std::shared_ptr<evs::IEvsCameraStream>& receiver,
+                                             ndk::ScopedAStatus& status,
+                                             std::unique_lock<std::mutex>& lck) = 0;
+
+    virtual bool postVideoStreamStart_locked(const std::shared_ptr<evs::IEvsCameraStream>& receiver,
+                                             ndk::ScopedAStatus& status,
+                                             std::unique_lock<std::mutex>& lck);
+
+    virtual bool preVideoStreamStop_locked(ndk::ScopedAStatus& status,
+                                           std::unique_lock<std::mutex>& lck);
+
+    virtual bool stopVideoStreamImpl_locked(ndk::ScopedAStatus& status,
+                                            std::unique_lock<std::mutex>& lck) = 0;
+
+    virtual bool postVideoStreamStop_locked(ndk::ScopedAStatus& status,
+                                            std::unique_lock<std::mutex>& lck);
+
+    void shutdown() override;
+
+    void closeAllBuffers_unsafe();
+
+    // Returns (ID, handle) if succeeds. (kInvalidBufferID, nullptr) otherwise.
+    [[nodiscard]] std::pair<std::size_t, buffer_handle_t> useBuffer_unsafe();
+
+    void returnBuffer_unsafe(const std::size_t id);
+
+    bool increaseAvailableFrames_unsafe(const buffer_handle_t handle);
+
+    bool decreaseAvailableFrames_unsafe();
+
+    bool setAvailableFrames_unsafe(const std::size_t bufferCount);
+
+    void swapBufferFrames_unsafe(const std::size_t pos1, const std::size_t pos2);
+
+    struct BufferRecord {
+        BufferRecord() = default;
+        BufferRecord(const BufferRecord&) = default;
+        BufferRecord(BufferRecord&&) = default;
+        BufferRecord& operator=(const BufferRecord&) = default;
+        BufferRecord& operator=(BufferRecord&&) = default;
+        ~BufferRecord() = default;
+
+        explicit BufferRecord(buffer_handle_t h) : handle(h) {}
+
+        buffer_handle_t handle{nullptr};
+        bool inUse{false};
+    };
+
+    enum class StreamState {
+        STOPPED = 0,
+        RUNNING = 1,
+        STOPPING = 2,
+        DEAD = 3,
+    };
+
+    StreamState mStreamState{StreamState::STOPPED};
+
+    std::mutex mMutex;
+
+    // Graphics buffers to transfer images, always in the order of:
+    // In use buffers ... available buffers ... unavailable (unallocated) buffers.
+    std::vector<BufferRecord> mBuffers;
+
+    // Double-mapping between buffer position and ID.
+    std::vector<std::size_t> mBufferPosToId;
+    std::vector<std::size_t> mBufferIdToPos;
+
+    std::size_t mAvailableFrames{0};
+    std::size_t mFramesInUse{0};
+
+    // We use all 1's as a reserved invalid buffer ID.
+    static constexpr std::size_t kInvalidBufferID = ~static_cast<std::size_t>(0);
+
+  public:
+    static bool IsBufferIDValid(const std::size_t bufferId) { return ~bufferId; }
+};
+
+}  // namespace aidl::android::hardware::automotive::evs::implementation
diff --git a/automotive/evs/aidl/impl/default/include/EvsCameraBase.h b/automotive/evs/aidl/impl/default/include/EvsCameraBase.h
new file mode 100644
index 0000000..c3e9dfc
--- /dev/null
+++ b/automotive/evs/aidl/impl/default/include/EvsCameraBase.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/automotive/evs/BnEvsCamera.h>
+
+namespace aidl::android::hardware::automotive::evs::implementation {
+
+class EvsCameraBase : public evs::BnEvsCamera {
+  private:
+    using Base = evs::BnEvsCamera;
+    using Self = EvsCameraBase;
+
+  public:
+    using Base::Base;
+
+    ~EvsCameraBase() override = default;
+
+    virtual void shutdown() = 0;
+
+  protected:
+    // This is used for the derived classes and it prevents constructors from direct access
+    // while it allows this class to be instantiated via ndk::SharedRefBase::make<>.
+    struct Sigil {
+        explicit Sigil() = default;
+    };
+};
+
+}  // namespace aidl::android::hardware::automotive::evs::implementation
diff --git a/automotive/evs/aidl/impl/default/include/EvsEnumerator.h b/automotive/evs/aidl/impl/default/include/EvsEnumerator.h
index 259c266..9dcc774 100644
--- a/automotive/evs/aidl/impl/default/include/EvsEnumerator.h
+++ b/automotive/evs/aidl/impl/default/include/EvsEnumerator.h
@@ -17,8 +17,8 @@
 #pragma once
 
 #include "ConfigManager.h"
+#include "EvsCameraBase.h"
 #include "EvsGlDisplay.h"
-#include "EvsMockCamera.h"
 
 #include <aidl/android/frameworks/automotive/display/ICarDisplayProxy.h>
 #include <aidl/android/hardware/automotive/evs/BnEvsEnumerator.h>
@@ -27,6 +27,7 @@
 #include <aidl/android/hardware/automotive/evs/IEvsCamera.h>
 #include <aidl/android/hardware/automotive/evs/IEvsEnumeratorStatusCallback.h>
 #include <aidl/android/hardware/automotive/evs/Stream.h>
+#include <android-base/thread_annotations.h>
 #include <utils/Thread.h>
 
 #include <atomic>
@@ -72,7 +73,7 @@
   private:
     struct CameraRecord {
         evs::CameraDesc desc;
-        std::weak_ptr<EvsMockCamera> activeInstance;
+        std::weak_ptr<EvsCameraBase> activeInstance;
 
         CameraRecord(const char* cameraId) : desc() { desc.id = cameraId; }
     };
diff --git a/automotive/evs/aidl/impl/default/include/EvsGlDisplay.h b/automotive/evs/aidl/impl/default/include/EvsGlDisplay.h
index ceabd9e..0865a04 100644
--- a/automotive/evs/aidl/impl/default/include/EvsGlDisplay.h
+++ b/automotive/evs/aidl/impl/default/include/EvsGlDisplay.h
@@ -23,6 +23,7 @@
 #include <aidl/android/hardware/automotive/evs/BufferDesc.h>
 #include <aidl/android/hardware/automotive/evs/DisplayDesc.h>
 #include <aidl/android/hardware/automotive/evs/DisplayState.h>
+#include <android-base/thread_annotations.h>
 
 #include <thread>
 
diff --git a/automotive/evs/aidl/impl/default/include/EvsMockCamera.h b/automotive/evs/aidl/impl/default/include/EvsMockCamera.h
index 7e010a2..cd68532 100644
--- a/automotive/evs/aidl/impl/default/include/EvsMockCamera.h
+++ b/automotive/evs/aidl/impl/default/include/EvsMockCamera.h
@@ -17,36 +17,36 @@
 #pragma once
 
 #include "ConfigManager.h"
+#include "EvsCamera.h"
 
-#include <aidl/android/hardware/automotive/evs/BnEvsCamera.h>
-#include <aidl/android/hardware/automotive/evs/BufferDesc.h>
 #include <aidl/android/hardware/automotive/evs/CameraDesc.h>
 #include <aidl/android/hardware/automotive/evs/CameraParam.h>
-#include <aidl/android/hardware/automotive/evs/EvsResult.h>
 #include <aidl/android/hardware/automotive/evs/IEvsCameraStream.h>
 #include <aidl/android/hardware/automotive/evs/IEvsDisplay.h>
 #include <aidl/android/hardware/automotive/evs/ParameterRange.h>
 #include <aidl/android/hardware/automotive/evs/Stream.h>
-// #include <android-base/result.h>
 #include <android/hardware_buffer.h>
 #include <ui/GraphicBuffer.h>
 
-#include <functional>
+#include <cstdint>
+#include <memory>
 #include <thread>
+#include <unordered_map>
+#include <vector>
 
 namespace aidl::android::hardware::automotive::evs::implementation {
 
-class EvsMockCamera : public evs::BnEvsCamera {
-    // This prevents constructors from direct access while it allows this class to
-    // be instantiated via ndk::SharedRefBase::make<>.
+class EvsMockCamera : public EvsCamera {
   private:
-    struct Sigil {
-        explicit Sigil() = default;
-    };
+    using Base = EvsCamera;
 
   public:
+    EvsMockCamera(Sigil sigil, const char* deviceName,
+                  std::unique_ptr<ConfigManager::CameraInfo>& camInfo);
+    EvsMockCamera(const EvsMockCamera&) = delete;
+    EvsMockCamera& operator=(const EvsMockCamera&) = delete;
+
     // Methods from ::android::hardware::automotive::evs::IEvsCamera follow.
-    ndk::ScopedAStatus doneWithFrame(const std::vector<evs::BufferDesc>& buffers) override;
     ndk::ScopedAStatus forcePrimaryClient(
             const std::shared_ptr<evs::IEvsDisplay>& display) override;
     ndk::ScopedAStatus getCameraInfo(evs::CameraDesc* _aidl_return) override;
@@ -58,47 +58,37 @@
     ndk::ScopedAStatus getParameterList(std::vector<evs::CameraParam>* _aidl_return) override;
     ndk::ScopedAStatus getPhysicalCameraInfo(const std::string& deviceId,
                                              evs::CameraDesc* _aidl_return) override;
-    ndk::ScopedAStatus importExternalBuffers(const std::vector<evs::BufferDesc>& buffers,
-                                             int32_t* _aidl_return) override;
-    ndk::ScopedAStatus pauseVideoStream() override;
-    ndk::ScopedAStatus resumeVideoStream() override;
     ndk::ScopedAStatus setExtendedInfo(int32_t opaqueIdentifier,
                                        const std::vector<uint8_t>& opaqueValue) override;
     ndk::ScopedAStatus setIntParameter(evs::CameraParam id, int32_t value,
                                        std::vector<int32_t>* effectiveValue) override;
     ndk::ScopedAStatus setPrimaryClient() override;
-    ndk::ScopedAStatus setMaxFramesInFlight(int32_t bufferCount) override;
-    ndk::ScopedAStatus startVideoStream(
-            const std::shared_ptr<evs::IEvsCameraStream>& receiver) override;
-    ndk::ScopedAStatus stopVideoStream() override;
     ndk::ScopedAStatus unsetPrimaryClient() override;
 
+    const evs::CameraDesc& getDesc() { return mDescription; }
+
     static std::shared_ptr<EvsMockCamera> Create(const char* deviceName);
     static std::shared_ptr<EvsMockCamera> Create(
             const char* deviceName, std::unique_ptr<ConfigManager::CameraInfo>& camInfo,
             const evs::Stream* streamCfg = nullptr);
-    EvsMockCamera(const EvsMockCamera&) = delete;
-    EvsMockCamera& operator=(const EvsMockCamera&) = delete;
-
-    virtual ~EvsMockCamera() override;
-    void shutdown();
-
-    const evs::CameraDesc& getDesc() { return mDescription; }
-
-    // Constructors
-    EvsMockCamera(Sigil sigil, const char* deviceName,
-                  std::unique_ptr<ConfigManager::CameraInfo>& camInfo);
 
   private:
-    // These three functions are expected to be called while mAccessLock is held
-    bool setAvailableFrames_Locked(unsigned bufferCount);
-    unsigned increaseAvailableFrames_Locked(unsigned numToAdd);
-    unsigned decreaseAvailableFrames_Locked(unsigned numToRemove);
-
     void generateFrames();
     void fillMockFrame(buffer_handle_t handle, const AHardwareBuffer_Desc* pDesc);
-    void returnBufferLocked(const uint32_t bufferId);
-    ndk::ScopedAStatus stopVideoStream_impl();
+
+    ::android::status_t allocateOneFrame(buffer_handle_t* handle) override;
+
+    bool startVideoStreamImpl_locked(const std::shared_ptr<evs::IEvsCameraStream>& receiver,
+                                     ndk::ScopedAStatus& status,
+                                     std::unique_lock<std::mutex>& lck) override;
+
+    bool stopVideoStreamImpl_locked(ndk::ScopedAStatus& status,
+                                    std::unique_lock<std::mutex>& lck) override;
+
+    bool postVideoStreamStop_locked(ndk::ScopedAStatus& status,
+                                    std::unique_lock<std::mutex>& lck) override;
+
+    void initializeParameters();
 
     CameraDesc mDescription = {};  // The properties of this camera
 
@@ -119,28 +109,6 @@
     // Bytes per line in the buffers
     uint32_t mStride = 0;
 
-    struct BufferRecord {
-        buffer_handle_t handle;
-        bool inUse;
-
-        explicit BufferRecord(buffer_handle_t h) : handle(h), inUse(false){};
-    };
-
-    std::vector<BufferRecord> mBuffers;  // Graphics buffers to transfer images
-    unsigned mFramesAllowed;             // How many buffers are we currently using
-    unsigned mFramesInUse;               // How many buffers are currently outstanding
-
-    enum StreamStateValues {
-        STOPPED,
-        RUNNING,
-        STOPPING,
-        DEAD,
-    };
-    StreamStateValues mStreamState;
-
-    // Synchronization necessary to deconflict mCaptureThread from the main service thread
-    std::mutex mAccessLock;
-
     // Static camera module information
     std::unique_ptr<ConfigManager::CameraInfo>& mCameraInfo;
 
@@ -160,7 +128,6 @@
         int32_t value;
     };
     std::unordered_map<CameraParam, std::shared_ptr<CameraParameterDesc>> mParams;
-    void initializeParameters();
 };
 
 }  // namespace aidl::android::hardware::automotive::evs::implementation
diff --git a/automotive/evs/aidl/impl/default/include/EvsVideoEmulatedCamera.h b/automotive/evs/aidl/impl/default/include/EvsVideoEmulatedCamera.h
new file mode 100644
index 0000000..a850d65
--- /dev/null
+++ b/automotive/evs/aidl/impl/default/include/EvsVideoEmulatedCamera.h
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "ConfigManager.h"
+#include "EvsCamera.h"
+
+#include <aidl/android/hardware/automotive/evs/BufferDesc.h>
+#include <aidl/android/hardware/automotive/evs/CameraDesc.h>
+#include <aidl/android/hardware/automotive/evs/CameraParam.h>
+#include <aidl/android/hardware/automotive/evs/IEvsCameraStream.h>
+#include <aidl/android/hardware/automotive/evs/IEvsDisplay.h>
+#include <aidl/android/hardware/automotive/evs/ParameterRange.h>
+#include <aidl/android/hardware/automotive/evs/Stream.h>
+#include <media/NdkMediaExtractor.h>
+
+#include <ui/GraphicBuffer.h>
+
+#include <cstdint>
+#include <memory>
+#include <thread>
+#include <unordered_map>
+#include <vector>
+
+namespace aidl::android::hardware::automotive::evs::implementation {
+
+class EvsVideoEmulatedCamera : public EvsCamera {
+  private:
+    using Base = EvsCamera;
+
+  public:
+    EvsVideoEmulatedCamera(Sigil sigil, const char* deviceName,
+                           std::unique_ptr<ConfigManager::CameraInfo>& camInfo);
+
+    ~EvsVideoEmulatedCamera() override = default;
+
+    // Methods from ::android::hardware::automotive::evs::IEvsCamera follow.
+    ndk::ScopedAStatus forcePrimaryClient(
+            const std::shared_ptr<evs::IEvsDisplay>& display) override;
+    ndk::ScopedAStatus getCameraInfo(evs::CameraDesc* _aidl_return) override;
+    ndk::ScopedAStatus getExtendedInfo(int32_t opaqueIdentifier,
+                                       std::vector<uint8_t>* value) override;
+    ndk::ScopedAStatus getIntParameter(evs::CameraParam id, std::vector<int32_t>* value) override;
+    ndk::ScopedAStatus getIntParameterRange(evs::CameraParam id,
+                                            evs::ParameterRange* _aidl_return) override;
+    ndk::ScopedAStatus getParameterList(std::vector<evs::CameraParam>* _aidl_return) override;
+    ndk::ScopedAStatus getPhysicalCameraInfo(const std::string& deviceId,
+                                             evs::CameraDesc* _aidl_return) override;
+    ndk::ScopedAStatus setExtendedInfo(int32_t opaqueIdentifier,
+                                       const std::vector<uint8_t>& opaqueValue) override;
+    ndk::ScopedAStatus setIntParameter(evs::CameraParam id, int32_t value,
+                                       std::vector<int32_t>* effectiveValue) override;
+    ndk::ScopedAStatus setPrimaryClient() override;
+    ndk::ScopedAStatus unsetPrimaryClient() override;
+
+    // Methods from EvsCameraBase follow.
+    void shutdown() override;
+
+    const evs::CameraDesc& getDesc() { return mDescription; }
+
+    static std::shared_ptr<EvsVideoEmulatedCamera> Create(const char* deviceName);
+    static std::shared_ptr<EvsVideoEmulatedCamera> Create(
+            const char* deviceName, std::unique_ptr<ConfigManager::CameraInfo>& camInfo,
+            const evs::Stream* streamCfg = nullptr);
+
+  private:
+    // For the camera parameters.
+    struct CameraParameterDesc {
+        CameraParameterDesc(int min = 0, int max = 0, int step = 0, int value = 0) {
+            this->range.min = min;
+            this->range.max = max;
+            this->range.step = step;
+            this->value = value;
+        }
+
+        ParameterRange range;
+        int32_t value;
+    };
+
+    bool initialize();
+
+    void generateFrames();
+
+    void renderOneFrame();
+
+    void initializeParameters();
+
+    void onCodecInputAvailable(const int32_t index);
+
+    void onCodecOutputAvailable(const int32_t index, const AMediaCodecBufferInfo& info);
+
+    ::android::status_t allocateOneFrame(buffer_handle_t* handle) override;
+
+    bool startVideoStreamImpl_locked(const std::shared_ptr<evs::IEvsCameraStream>& receiver,
+                                     ndk::ScopedAStatus& status,
+                                     std::unique_lock<std::mutex>& lck) override;
+
+    bool stopVideoStreamImpl_locked(ndk::ScopedAStatus& status,
+                                    std::unique_lock<std::mutex>& lck) override;
+
+    bool postVideoStreamStop_locked(ndk::ScopedAStatus& status,
+                                    std::unique_lock<std::mutex>& lck) override;
+
+    // The properties of this camera.
+    CameraDesc mDescription = {};
+
+    std::thread mCaptureThread;
+
+    // The callback used to deliver each frame
+    std::shared_ptr<evs::IEvsCameraStream> mStream;
+
+    std::string mVideoFileName;
+    // Media decoder resources - Owned by mDecoderThead when thread is running.
+    int mVideoFd = 0;
+
+    struct AMediaExtractorDeleter {
+        void operator()(AMediaExtractor* extractor) const { AMediaExtractor_delete(extractor); }
+    };
+    struct AMediaCodecDeleter {
+        void operator()(AMediaCodec* codec) const { AMediaCodec_delete(codec); }
+    };
+
+    std::unique_ptr<AMediaExtractor, AMediaExtractorDeleter> mVideoExtractor;
+    std::unique_ptr<AMediaCodec, AMediaCodecDeleter> mVideoCodec;
+
+    // Horizontal pixel count in the buffers
+    int32_t mWidth = 0;
+    // Vertical pixel count in the buffers
+    int32_t mHeight = 0;
+    // Values from android_pixel_format_t
+    uint32_t mFormat = 0;
+    // Values from from Gralloc.h
+    uint64_t mUsage = 0;
+    // Bytes per line in the buffers
+    uint32_t mStride = 0;
+
+    // Camera parameters.
+    std::unordered_map<CameraParam, std::shared_ptr<CameraParameterDesc>> mParams;
+
+    // Static camera module information
+    std::unique_ptr<ConfigManager::CameraInfo>& mCameraInfo;
+
+    // For the extended info
+    std::unordered_map<uint32_t, std::vector<uint8_t>> mExtInfo;
+};
+
+}  // namespace aidl::android::hardware::automotive::evs::implementation
diff --git a/automotive/evs/aidl/impl/default/include/GlWrapper.h b/automotive/evs/aidl/impl/default/include/GlWrapper.h
index adb250c..7ff6104 100644
--- a/automotive/evs/aidl/impl/default/include/GlWrapper.h
+++ b/automotive/evs/aidl/impl/default/include/GlWrapper.h
@@ -25,7 +25,7 @@
 #include <aidl/android/frameworks/automotive/display/ICarDisplayProxy.h>
 #include <aidl/android/hardware/automotive/evs/BufferDesc.h>
 #include <android-base/logging.h>
-#include <bufferqueueconverter/BufferQueueConverter.h>
+#include <cutils/native_handle.h>
 
 namespace aidl::android::hardware::automotive::evs::implementation {
 
@@ -33,7 +33,6 @@
 
 class GlWrapper {
   public:
-    GlWrapper() : mSurfaceHolder(::android::SurfaceHolderUniquePtr(nullptr, nullptr)) {}
     bool initialize(const std::shared_ptr<automotivedisplay::ICarDisplayProxy>& svc,
                     uint64_t displayId);
     void shutdown();
@@ -53,9 +52,6 @@
     unsigned getHeight() { return mHeight; };
 
   private:
-    ::android::sp<::android::hardware::graphics::bufferqueue::V2_0::IGraphicBufferProducer>
-            mGfxBufferProducer;
-
     EGLDisplay mDisplay;
     EGLSurface mSurface;
     EGLContext mContext;
@@ -71,9 +67,6 @@
     // Opaque handle for a native hardware buffer defined in
     // frameworks/native/opengl/include/EGL/eglplatform.h
     ANativeWindow* mWindow;
-
-    // Pointer to a Surface wrapper.
-    ::android::SurfaceHolderUniquePtr mSurfaceHolder;
 };
 
 }  // namespace aidl::android::hardware::automotive::evs::implementation
diff --git a/automotive/evs/aidl/impl/default/src/ConfigManager.cpp b/automotive/evs/aidl/impl/default/src/ConfigManager.cpp
index da791ed..ba4cdc0 100644
--- a/automotive/evs/aidl/impl/default/src/ConfigManager.cpp
+++ b/automotive/evs/aidl/impl/default/src/ConfigManager.cpp
@@ -40,6 +40,18 @@
 std::string_view ConfigManager::sConfigOverridePath =
         "/vendor/etc/automotive/evs/evs_configuration_override.xml";
 
+ConfigManager::CameraInfo::DeviceType ConfigManager::CameraInfo::deviceTypeFromSV(
+        const std::string_view sv) {
+    using namespace std::string_view_literals;
+    static const std::unordered_map<std::string_view, DeviceType> nameToType = {
+            {"mock"sv, DeviceType::MOCK},
+            {"v4l2"sv, DeviceType::V4L2},
+            {"video"sv, DeviceType::VIDEO},
+    };
+    const auto search = nameToType.find(sv);
+    return search == nameToType.end() ? DeviceType::UNKNOWN : search->second;
+}
+
 void ConfigManager::printElementNames(const XMLElement* rootElem, const std::string& prefix) const {
     const XMLElement* curElem = rootElem;
 
@@ -128,6 +140,10 @@
         return false;
     }
 
+    if (const auto typeAttr = aDeviceElem->FindAttribute("type")) {
+        aCamera->deviceType = CameraInfo::deviceTypeFromSV(typeAttr->Value());
+    }
+
     /* size information to allocate camera_metadata_t */
     size_t totalEntries = 0;
     size_t totalDataSize = 0;
diff --git a/automotive/evs/aidl/impl/default/src/EvsCamera.cpp b/automotive/evs/aidl/impl/default/src/EvsCamera.cpp
new file mode 100644
index 0000000..bc3bfdd
--- /dev/null
+++ b/automotive/evs/aidl/impl/default/src/EvsCamera.cpp
@@ -0,0 +1,378 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "EvsCamera.h"
+
+#include <aidl/android/hardware/automotive/evs/EvsResult.h>
+#include <aidlcommonsupport/NativeHandle.h>
+#include <android-base/logging.h>
+#include <android/hardware_buffer.h>
+#include <ui/GraphicBufferAllocator.h>
+#include <ui/GraphicBufferMapper.h>
+
+#include <cstddef>
+#include <mutex>
+
+namespace aidl::android::hardware::automotive::evs::implementation {
+
+// Arbitrary limit on number of graphics buffers allowed to be allocated
+// Safeguards against unreasonable resource consumption and provides a testable limit
+constexpr std::size_t kMaxBuffersInFlight = 100;
+
+// Minimum number of buffers to run a video stream
+constexpr int kMinimumBuffersInFlight = 1;
+
+EvsCamera::~EvsCamera() {
+    shutdown();
+}
+
+ndk::ScopedAStatus EvsCamera::doneWithFrame(const std::vector<evs::BufferDesc>& buffers) {
+    std::lock_guard lck(mMutex);
+    for (const auto& desc : buffers) {
+        returnBuffer_unsafe(desc.bufferId);
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EvsCamera::importExternalBuffers(const std::vector<evs::BufferDesc>& buffers,
+                                                    int32_t* _aidl_return) {
+    if (buffers.empty()) {
+        LOG(DEBUG) << __func__
+                   << ": Ignoring a request to import external buffers with an empty list.";
+        return ndk::ScopedAStatus::ok();
+    }
+    static auto& mapper = ::android::GraphicBufferMapper::get();
+    std::lock_guard lck(mMutex);
+    std::size_t numBuffersToAdd = std::min(buffers.size(), kMaxBuffersInFlight - mAvailableFrames);
+    if (numBuffersToAdd == 0) {
+        LOG(WARNING) << __func__ << ": The number of buffers has hit the upper limit ("
+                     << kMaxBuffersInFlight << "). Stop importing.";
+        return ndk::ScopedAStatus::ok();
+    } else if (numBuffersToAdd < buffers.size()) {
+        LOG(WARNING) << "Exceeds the limit on the number of buffers. Only " << numBuffersToAdd
+                     << " buffers will be imported. " << buffers.size() << " are asked.";
+    }
+    const size_t before = mAvailableFrames;
+    for (std::size_t idx = 0; idx < numBuffersToAdd; ++idx) {
+        auto& buffer = buffers[idx];
+        const AHardwareBuffer_Desc* pDesc =
+                reinterpret_cast<const AHardwareBuffer_Desc*>(&buffer.buffer.description);
+
+        buffer_handle_t handleToImport = ::android::dupFromAidl(buffer.buffer.handle);
+        buffer_handle_t handleToStore = nullptr;
+        if (handleToImport == nullptr) {
+            LOG(WARNING) << "Failed to duplicate a memory handle. Ignoring a buffer "
+                         << buffer.bufferId;
+            continue;
+        }
+
+        ::android::status_t result =
+                mapper.importBuffer(handleToImport, pDesc->width, pDesc->height, pDesc->layers,
+                                    pDesc->format, pDesc->usage, pDesc->stride, &handleToStore);
+        if (result != ::android::NO_ERROR || handleToStore == nullptr ||
+            !increaseAvailableFrames_unsafe(handleToStore)) {
+            LOG(WARNING) << "Failed to import a buffer " << buffer.bufferId;
+        }
+    }
+    *_aidl_return = mAvailableFrames - before;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EvsCamera::setMaxFramesInFlight(int32_t bufferCount) {
+    std::lock_guard lock(mMutex);
+    if (bufferCount < 1) {
+        LOG(ERROR) << "Ignoring setMaxFramesInFlight with less than one buffer requested.";
+        return ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int>(EvsResult::INVALID_ARG));
+    }
+    if (!setAvailableFrames_unsafe(bufferCount)) {
+        LOG(ERROR) << "Failed to adjust the maximum number of frames in flight.";
+        return ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int>(EvsResult::BUFFER_NOT_AVAILABLE));
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+void EvsCamera::freeOneFrame(const buffer_handle_t handle) {
+    static auto& alloc = ::android::GraphicBufferAllocator::get();
+    alloc.free(handle);
+}
+
+bool EvsCamera::preVideoStreamStart_locked(const std::shared_ptr<evs::IEvsCameraStream>& receiver,
+                                           ndk::ScopedAStatus& status,
+                                           std::unique_lock<std::mutex>& /* lck */) {
+    if (!receiver) {
+        LOG(ERROR) << __func__ << ": Null receiver.";
+        status = ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int>(EvsResult::INVALID_ARG));
+        return false;
+    }
+
+    // If we've been displaced by another owner of the camera, then we can't do anything else
+    if (mStreamState == StreamState::DEAD) {
+        LOG(ERROR) << __func__ << ": Ignoring when camera has been lost.";
+        status = ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int>(EvsResult::OWNERSHIP_LOST));
+        return false;
+    }
+
+    if (mStreamState != StreamState::STOPPED) {
+        LOG(ERROR) << __func__ << ": Ignoring when a stream is already running.";
+        status = ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int>(EvsResult::STREAM_ALREADY_RUNNING));
+        return false;
+    }
+
+    // If the client never indicated otherwise, configure ourselves for a single streaming buffer
+    if (mAvailableFrames < kMinimumBuffersInFlight &&
+        !setAvailableFrames_unsafe(kMinimumBuffersInFlight)) {
+        LOG(ERROR) << __func__ << "Failed to because we could not get a graphics buffer.";
+        status = ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int>(EvsResult::BUFFER_NOT_AVAILABLE));
+        return false;
+    }
+    mStreamState = StreamState::RUNNING;
+    return true;
+}
+
+bool EvsCamera::postVideoStreamStart_locked(
+        const std::shared_ptr<evs::IEvsCameraStream>& /* receiver */,
+        ndk::ScopedAStatus& /* status */, std::unique_lock<std::mutex>& /* lck */) {
+    return true;
+}
+
+bool EvsCamera::preVideoStreamStop_locked(ndk::ScopedAStatus& status,
+                                          std::unique_lock<std::mutex>& /* lck */) {
+    if (mStreamState != StreamState::RUNNING) {
+        // Terminate the stop process because a stream is not running.
+        status = ndk::ScopedAStatus::ok();
+        return false;
+    }
+    mStreamState = StreamState::STOPPING;
+    return true;
+}
+
+bool EvsCamera::postVideoStreamStop_locked(ndk::ScopedAStatus& /* status */,
+                                           std::unique_lock<std::mutex>& /* lck */) {
+    mStreamState = StreamState::STOPPED;
+    return true;
+}
+
+ndk::ScopedAStatus EvsCamera::startVideoStream(
+        const std::shared_ptr<evs::IEvsCameraStream>& receiver) {
+    bool needShutdown = false;
+    auto status = ndk::ScopedAStatus::ok();
+    {
+        std::unique_lock lck(mMutex);
+        if (!preVideoStreamStart_locked(receiver, status, lck)) {
+            return status;
+        }
+
+        if ((!startVideoStreamImpl_locked(receiver, status, lck) ||
+             !postVideoStreamStart_locked(receiver, status, lck)) &&
+            !status.isOk()) {
+            needShutdown = true;
+        }
+    }
+    if (needShutdown) {
+        shutdown();
+    }
+    return status;
+}
+
+ndk::ScopedAStatus EvsCamera::stopVideoStream() {
+    bool needShutdown = false;
+    auto status = ndk::ScopedAStatus::ok();
+    {
+        std::unique_lock lck(mMutex);
+        if ((!preVideoStreamStop_locked(status, lck) || !stopVideoStreamImpl_locked(status, lck) ||
+             !postVideoStreamStop_locked(status, lck)) &&
+            !status.isOk()) {
+            needShutdown = true;
+        }
+    }
+    if (needShutdown) {
+        shutdown();
+    }
+    return status;
+}
+
+ndk::ScopedAStatus EvsCamera::pauseVideoStream() {
+    return ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int>(EvsResult::NOT_SUPPORTED));
+}
+
+ndk::ScopedAStatus EvsCamera::resumeVideoStream() {
+    return ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int>(EvsResult::NOT_SUPPORTED));
+}
+
+bool EvsCamera::setAvailableFrames_unsafe(const std::size_t bufferCount) {
+    if (bufferCount < 1) {
+        LOG(ERROR) << "Ignoring request to set buffer count to zero.";
+        return false;
+    }
+    if (bufferCount > kMaxBuffersInFlight) {
+        LOG(ERROR) << "Rejecting buffer request in excess of internal limit";
+        return false;
+    }
+
+    if (bufferCount > mAvailableFrames) {
+        bool success = true;
+        const std::size_t numBufferBeforeAlloc = mAvailableFrames;
+        for (int numBufferToAllocate = bufferCount - mAvailableFrames;
+             success && numBufferToAllocate > 0; --numBufferToAllocate) {
+            buffer_handle_t handle = nullptr;
+            const auto result = allocateOneFrame(&handle);
+            if (result != ::android::NO_ERROR || !handle) {
+                LOG(ERROR) << __func__ << ": Failed to allocate a graphics buffer. Error " << result
+                           << ", handle: " << handle;
+                success = false;
+                break;
+            }
+            success &= increaseAvailableFrames_unsafe(handle);
+        }
+        if (!success) {
+            // Rollback when failure.
+            for (int numBufferToRelease = mAvailableFrames - numBufferBeforeAlloc;
+                 numBufferToRelease > 0; --numBufferToRelease) {
+                decreaseAvailableFrames_unsafe();
+            }
+            return false;
+        }
+    } else {
+        for (int numBufferToRelease = mAvailableFrames - std::max(bufferCount, mFramesInUse);
+             numBufferToRelease > 0; --numBufferToRelease) {
+            decreaseAvailableFrames_unsafe();
+        }
+        if (mAvailableFrames > bufferCount) {
+            // This shouldn't happen with a properly behaving client because the client
+            // should only make this call after returning sufficient outstanding buffers
+            // to allow a clean resize.
+            LOG(ERROR) << "Buffer queue shrink failed, asked: " << bufferCount
+                       << ", actual: " << mAvailableFrames
+                       << " -- too many buffers currently in use?";
+        }
+    }
+    return true;
+}
+
+void EvsCamera::shutdown() {
+    stopVideoStream();
+    std::lock_guard lck(mMutex);
+    closeAllBuffers_unsafe();
+    mStreamState = StreamState::DEAD;
+}
+
+void EvsCamera::closeAllBuffers_unsafe() {
+    if (mFramesInUse > 0) {
+        LOG(WARNING) << __func__ << ": Closing while " << mFramesInUse
+                     << " frame(s) are still in use.";
+    }
+    for (auto& buffer : mBuffers) {
+        freeOneFrame(buffer.handle);
+        buffer.handle = nullptr;
+    }
+    mBuffers.clear();
+    mBufferPosToId.clear();
+    mBufferIdToPos.clear();
+}
+
+std::pair<std::size_t, buffer_handle_t> EvsCamera::useBuffer_unsafe() {
+    if (mFramesInUse >= mAvailableFrames) {
+        DCHECK_EQ(mFramesInUse, mAvailableFrames);
+        return {kInvalidBufferID, nullptr};
+    }
+    const std::size_t pos = mFramesInUse++;
+    auto& buffer = mBuffers[pos];
+    DCHECK(!buffer.inUse);
+    DCHECK(buffer.handle);
+    buffer.inUse = true;
+    return {mBufferPosToId[pos], buffer.handle};
+}
+
+void EvsCamera::returnBuffer_unsafe(const std::size_t id) {
+    if (id >= mBuffers.size()) {
+        LOG(ERROR) << __func__ << ": ID out-of-bound. id: " << id
+                   << " max: " << mBuffers.size() - 1;
+        return;
+    }
+    const std::size_t pos = mBufferIdToPos[id];
+
+    if (!mBuffers[pos].inUse) {
+        LOG(ERROR) << __func__ << ": Ignoring returning frame " << id << " which is already free.";
+        return;
+    }
+    DCHECK_LT(pos, mFramesInUse);
+    const std::size_t last_in_use_pos = --mFramesInUse;
+    swapBufferFrames_unsafe(pos, last_in_use_pos);
+    mBuffers[last_in_use_pos].inUse = false;
+}
+
+bool EvsCamera::increaseAvailableFrames_unsafe(const buffer_handle_t handle) {
+    if (mAvailableFrames >= kMaxBuffersInFlight) {
+        LOG(WARNING) << __func__ << ": The number of buffers has hit the upper limit ("
+                     << kMaxBuffersInFlight << "). Stop increasing.";
+        return false;
+    }
+    const std::size_t pos = mAvailableFrames++;
+    if (mAvailableFrames > mBuffers.size()) {
+        const std::size_t oldBufferSize = mBuffers.size();
+        mBuffers.resize(mAvailableFrames);
+        mBufferPosToId.resize(mAvailableFrames);
+        mBufferIdToPos.resize(mAvailableFrames);
+        // Build position/ID mapping.
+        for (std::size_t idx = oldBufferSize; idx < mBuffers.size(); ++idx) {
+            mBufferPosToId[idx] = idx;
+            mBufferIdToPos[idx] = idx;
+        }
+    }
+    auto& buffer = mBuffers[pos];
+    DCHECK(!buffer.inUse);
+    DCHECK(!buffer.handle);
+    buffer.handle = handle;
+    return true;
+}
+
+bool EvsCamera::decreaseAvailableFrames_unsafe() {
+    if (mFramesInUse >= mAvailableFrames) {
+        DCHECK_EQ(mFramesInUse, mAvailableFrames);
+        return false;
+    }
+    const std::size_t pos = --mAvailableFrames;
+    auto& buffer = mBuffers[pos];
+    DCHECK(!buffer.inUse);
+    DCHECK(buffer.handle);
+    freeOneFrame(buffer.handle);
+    buffer.handle = nullptr;
+    return true;
+}
+
+void EvsCamera::swapBufferFrames_unsafe(const std::size_t pos1, const std::size_t pos2) {
+    if (pos1 == pos2) {
+        return;
+    }
+    if (pos1 >= mBuffers.size() || pos2 >= mBuffers.size()) {
+        LOG(ERROR) << __func__ << ": Index out-of-bound. pos1: " << pos1 << ", pos2: " << pos2
+                   << ", buffer size: " << mBuffers.size();
+        return;
+    }
+    const std::size_t id1 = mBufferPosToId[pos1];
+    const std::size_t id2 = mBufferPosToId[pos2];
+    std::swap(mBufferPosToId[pos1], mBufferPosToId[pos2]);
+    std::swap(mBufferIdToPos[id1], mBufferIdToPos[id2]);
+    std::swap(mBuffers[pos1], mBuffers[pos2]);
+}
+
+}  // namespace aidl::android::hardware::automotive::evs::implementation
diff --git a/automotive/evs/aidl/impl/default/src/EvsEnumerator.cpp b/automotive/evs/aidl/impl/default/src/EvsEnumerator.cpp
index 5178958..80e72a7 100644
--- a/automotive/evs/aidl/impl/default/src/EvsEnumerator.cpp
+++ b/automotive/evs/aidl/impl/default/src/EvsEnumerator.cpp
@@ -17,8 +17,9 @@
 #include "EvsEnumerator.h"
 
 #include "ConfigManager.h"
+#include "EvsAllCameras.h"
+#include "EvsCameraBase.h"
 #include "EvsGlDisplay.h"
-#include "EvsMockCamera.h"
 
 #include <aidl/android/hardware/automotive/evs/EvsResult.h>
 #include <aidl/android/hardware/graphics/common/BufferUsage.h>
@@ -243,7 +244,7 @@
     }
 
     // Has this camera already been instantiated by another caller?
-    std::shared_ptr<EvsMockCamera> pActiveCamera = pRecord->activeInstance.lock();
+    std::shared_ptr<EvsCameraBase> pActiveCamera = pRecord->activeInstance.lock();
     if (pActiveCamera) {
         LOG(WARNING) << "Killing previous camera because of new caller";
         closeCamera(pActiveCamera);
@@ -253,12 +254,31 @@
     if (!sConfigManager) {
         pActiveCamera = EvsMockCamera::Create(id.data());
     } else {
-        pActiveCamera = EvsMockCamera::Create(id.data(), sConfigManager->getCameraInfo(id), &cfg);
+        auto& cameraInfo = sConfigManager->getCameraInfo(id);
+        switch (cameraInfo->deviceType) {
+            using DeviceType = ConfigManager::CameraInfo::DeviceType;
+
+            // Default to MOCK for backward compatibility.
+            case DeviceType::NONE:
+            case DeviceType::MOCK:
+                pActiveCamera = EvsMockCamera::Create(id.data(), cameraInfo, &cfg);
+                break;
+
+            case DeviceType::VIDEO:
+                pActiveCamera = EvsVideoEmulatedCamera::Create(id.data(), cameraInfo, &cfg);
+                break;
+
+            default:
+                LOG(ERROR) << __func__ << ": camera device type "
+                           << static_cast<std::int32_t>(cameraInfo->deviceType)
+                           << " is not supported.";
+                break;
+        }
     }
 
     pRecord->activeInstance = pActiveCamera;
     if (!pActiveCamera) {
-        LOG(ERROR) << "Failed to create new EvsMockCamera object for " << id;
+        LOG(ERROR) << "Failed to create new EVS camera object for " << id;
         return ScopedAStatus::fromServiceSpecificError(
                 static_cast<int>(EvsResult::UNDERLYING_SERVICE_ERROR));
     }
@@ -445,7 +465,7 @@
     if (!pRecord) {
         LOG(ERROR) << "Asked to close a camera whose name isn't recognized";
     } else {
-        std::shared_ptr<EvsMockCamera> pActiveCamera = pRecord->activeInstance.lock();
+        std::shared_ptr<EvsCameraBase> pActiveCamera = pRecord->activeInstance.lock();
         if (!pActiveCamera) {
             LOG(WARNING) << "Somehow a camera is being destroyed "
                          << "when the enumerator didn't know one existed";
diff --git a/automotive/evs/aidl/impl/default/src/EvsGlDisplay.cpp b/automotive/evs/aidl/impl/default/src/EvsGlDisplay.cpp
index e5f8e4c..5b5cbcc 100644
--- a/automotive/evs/aidl/impl/default/src/EvsGlDisplay.cpp
+++ b/automotive/evs/aidl/impl/default/src/EvsGlDisplay.cpp
@@ -352,8 +352,8 @@
     BufferDesc bufferDescToSend = {
             .buffer =
                     {
-                            .handle = std::move(::android::dupToAidl(mBuffer.handle)),
                             .description = mBuffer.description,
+                            .handle = std::move(::android::dupToAidl(mBuffer.handle)),
                     },
             .pixelSizeBytes = 4,  // RGBA_8888 is 4-byte-per-pixel format
             .bufferId = mBuffer.fingerprint,
diff --git a/automotive/evs/aidl/impl/default/src/EvsMockCamera.cpp b/automotive/evs/aidl/impl/default/src/EvsMockCamera.cpp
index 797b221..ef43925 100644
--- a/automotive/evs/aidl/impl/default/src/EvsMockCamera.cpp
+++ b/automotive/evs/aidl/impl/default/src/EvsMockCamera.cpp
@@ -15,28 +15,25 @@
  */
 
 #include "EvsMockCamera.h"
-#include "ConfigManager.h"
-#include "EvsEnumerator.h"
+
+#include <aidl/android/hardware/automotive/evs/EvsResult.h>
 
 #include <aidlcommonsupport/NativeHandle.h>
+#include <android-base/logging.h>
 #include <ui/GraphicBufferAllocator.h>
 #include <ui/GraphicBufferMapper.h>
 #include <utils/SystemClock.h>
 
+#include <cstddef>
+#include <cstdint>
 #include <memory>
+#include <tuple>
 
 namespace {
 
 using ::aidl::android::hardware::graphics::common::BufferUsage;
 using ::ndk::ScopedAStatus;
 
-// Arbitrary limit on number of graphics buffers allowed to be allocated
-// Safeguards against unreasonable resource consumption and provides a testable limit
-constexpr unsigned kMaxBuffersInFlight = 100;
-
-// Minimum number of buffers to run a video stream
-constexpr int kMinimumBuffersInFlight = 1;
-
 // Colors for the colorbar test pattern in ABGR format
 constexpr uint32_t kColors[] = {
         0xFFFFFFFF,  // white
@@ -56,7 +53,7 @@
 
 EvsMockCamera::EvsMockCamera([[maybe_unused]] Sigil sigil, const char* id,
                              std::unique_ptr<ConfigManager::CameraInfo>& camInfo)
-    : mFramesAllowed(0), mFramesInUse(0), mStreamState(STOPPED), mCameraInfo(camInfo) {
+    : mCameraInfo(camInfo) {
     LOG(DEBUG) << __FUNCTION__;
 
     /* set a camera id */
@@ -73,11 +70,6 @@
     initializeParameters();
 }
 
-EvsMockCamera::~EvsMockCamera() {
-    LOG(DEBUG) << __FUNCTION__;
-    shutdown();
-}
-
 void EvsMockCamera::initializeParameters() {
     mParams.emplace(
             CameraParam::BRIGHTNESS,
@@ -90,35 +82,6 @@
             new CameraParameterDesc(/* min= */ 0, /* max= */ 255, /* step= */ 1, /* value= */ 255));
 }
 
-// This gets called if another caller "steals" ownership of the camera
-void EvsMockCamera::shutdown() {
-    LOG(DEBUG) << __FUNCTION__;
-
-    // Make sure our output stream is cleaned up
-    // (It really should be already)
-    stopVideoStream_impl();
-
-    // Claim the lock while we work on internal state
-    std::lock_guard lock(mAccessLock);
-
-    // Drop all the graphics buffers we've been using
-    if (mBuffers.size() > 0) {
-        ::android::GraphicBufferAllocator& alloc(::android::GraphicBufferAllocator::get());
-        for (auto&& rec : mBuffers) {
-            if (rec.inUse) {
-                LOG(WARNING) << "WARNING: releasing a buffer remotely owned.";
-            }
-            alloc.free(rec.handle);
-            rec.handle = nullptr;
-        }
-        mBuffers.clear();
-    }
-
-    // Put this object into an unrecoverable error state since somebody else
-    // is going to own the underlying camera now
-    mStreamState = DEAD;
-}
-
 // Methods from ::aidl::android::hardware::automotive::evs::IEvsCamera follow.
 ScopedAStatus EvsMockCamera::getCameraInfo(CameraDesc* _aidl_return) {
     LOG(DEBUG) << __FUNCTION__;
@@ -128,115 +91,6 @@
     return ScopedAStatus::ok();
 }
 
-ScopedAStatus EvsMockCamera::setMaxFramesInFlight(int32_t bufferCount) {
-    LOG(DEBUG) << __FUNCTION__ << ", bufferCount = " << bufferCount;
-    ;
-
-    std::lock_guard lock(mAccessLock);
-
-    // If we've been displaced by another owner of the camera, then we can't do anything else
-    if (mStreamState == DEAD) {
-        LOG(ERROR) << "Ignoring setMaxFramesInFlight call when camera has been lost.";
-        return ScopedAStatus::fromServiceSpecificError(static_cast<int>(EvsResult::OWNERSHIP_LOST));
-    }
-
-    // We cannot function without at least one video buffer to send data
-    if (bufferCount < 1) {
-        LOG(ERROR) << "Ignoring setMaxFramesInFlight with less than one buffer requested.";
-        return ScopedAStatus::fromServiceSpecificError(static_cast<int>(EvsResult::INVALID_ARG));
-    }
-
-    // Update our internal state
-    if (!setAvailableFrames_Locked(bufferCount)) {
-        LOG(ERROR) << "Failed to adjust the maximum number of frames in flight.";
-        return ScopedAStatus::fromServiceSpecificError(
-                static_cast<int>(EvsResult::BUFFER_NOT_AVAILABLE));
-    }
-
-    return ScopedAStatus::ok();
-}
-
-ScopedAStatus EvsMockCamera::startVideoStream(const std::shared_ptr<IEvsCameraStream>& cb) {
-    LOG(DEBUG) << __FUNCTION__;
-
-    if (!cb) {
-        LOG(ERROR) << "A given stream callback is invalid.";
-        return ScopedAStatus::fromServiceSpecificError(static_cast<int>(EvsResult::INVALID_ARG));
-    }
-
-    std::lock_guard lock(mAccessLock);
-
-    // If we've been displaced by another owner of the camera, then we can't do anything else
-    if (mStreamState == DEAD) {
-        LOG(ERROR) << "Ignoring startVideoStream call when camera has been lost.";
-        return ScopedAStatus::fromServiceSpecificError(static_cast<int>(EvsResult::OWNERSHIP_LOST));
-    }
-
-    if (mStreamState != STOPPED) {
-        LOG(ERROR) << "Ignoring startVideoStream call when a stream is already running.";
-        return ScopedAStatus::fromServiceSpecificError(
-                static_cast<int>(EvsResult::STREAM_ALREADY_RUNNING));
-    }
-
-    // If the client never indicated otherwise, configure ourselves for a single streaming buffer
-    if (mFramesAllowed < kMinimumBuffersInFlight &&
-        !setAvailableFrames_Locked(kMinimumBuffersInFlight)) {
-        LOG(ERROR) << "Failed to start stream because we couldn't get a graphics buffer";
-        return ScopedAStatus::fromServiceSpecificError(
-                static_cast<int>(EvsResult::BUFFER_NOT_AVAILABLE));
-    }
-
-    // Record the user's callback for use when we have a frame ready
-    mStream = cb;
-
-    // Start the frame generation thread
-    mStreamState = RUNNING;
-    mCaptureThread = std::thread([this]() { generateFrames(); });
-
-    return ScopedAStatus::ok();
-}
-
-ScopedAStatus EvsMockCamera::doneWithFrame(const std::vector<BufferDesc>& list) {
-    std::lock_guard lock(mAccessLock);
-    for (const auto& desc : list) {
-        returnBufferLocked(desc.bufferId);
-    }
-
-    return ScopedAStatus::ok();
-}
-
-ScopedAStatus EvsMockCamera::stopVideoStream() {
-    LOG(DEBUG) << __FUNCTION__;
-    return stopVideoStream_impl();
-}
-
-ScopedAStatus EvsMockCamera::stopVideoStream_impl() {
-    std::unique_lock lock(mAccessLock);
-
-    if (mStreamState != RUNNING) {
-        // Safely return here because a stream is not running.
-        return ScopedAStatus::ok();
-    }
-
-    // Tell the GenerateFrames loop we want it to stop
-    mStreamState = STOPPING;
-
-    // Block outside the mutex until the "stop" flag has been acknowledged
-    // We won't send any more frames, but the client might still get some already in flight
-    LOG(DEBUG) << "Waiting for stream thread to end...";
-    lock.unlock();
-    if (mCaptureThread.joinable()) {
-        mCaptureThread.join();
-    }
-    lock.lock();
-
-    mStreamState = STOPPED;
-    mStream = nullptr;
-    LOG(DEBUG) << "Stream marked STOPPED.";
-
-    return ScopedAStatus::ok();
-}
-
 ScopedAStatus EvsMockCamera::getExtendedInfo(int32_t opaqueIdentifier,
                                              std::vector<uint8_t>* opaqueValue) {
     const auto it = mExtInfo.find(opaqueIdentifier);
@@ -264,14 +118,6 @@
     return ScopedAStatus::ok();
 }
 
-ScopedAStatus EvsMockCamera::pauseVideoStream() {
-    return ScopedAStatus::fromServiceSpecificError(static_cast<int>(EvsResult::NOT_SUPPORTED));
-}
-
-ScopedAStatus EvsMockCamera::resumeVideoStream() {
-    return ScopedAStatus::fromServiceSpecificError(static_cast<int>(EvsResult::NOT_SUPPORTED));
-}
-
 ScopedAStatus EvsMockCamera::setPrimaryClient() {
     /* Because EVS HW module reference implementation expects a single client at
      * a time, this returns a success code always.
@@ -346,232 +192,27 @@
     return ScopedAStatus::ok();
 }
 
-ScopedAStatus EvsMockCamera::importExternalBuffers(const std::vector<BufferDesc>& buffers,
-                                                   int32_t* _aidl_return) {
-    size_t numBuffersToAdd = buffers.size();
-    if (numBuffersToAdd < 1) {
-        LOG(DEBUG) << "Ignoring a request to import external buffers with an empty list.";
-        return ScopedAStatus::ok();
-    }
-
-    std::lock_guard lock(mAccessLock);
-    if (numBuffersToAdd > (kMaxBuffersInFlight - mFramesAllowed)) {
-        numBuffersToAdd -= (kMaxBuffersInFlight - mFramesAllowed);
-        LOG(WARNING) << "Exceed the limit on the number of buffers. " << numBuffersToAdd
-                     << " buffers will be imported only.";
-    }
-
-    ::android::GraphicBufferMapper& mapper = ::android::GraphicBufferMapper::get();
-    const size_t before = mFramesAllowed;
-    for (size_t i = 0; i < numBuffersToAdd; ++i) {
-        auto& b = buffers[i];
-        const AHardwareBuffer_Desc* pDesc =
-                reinterpret_cast<const AHardwareBuffer_Desc*>(&b.buffer.description);
-
-        buffer_handle_t handleToImport = ::android::dupFromAidl(b.buffer.handle);
-        buffer_handle_t handleToStore = nullptr;
-        if (handleToImport == nullptr) {
-            LOG(WARNING) << "Failed to duplicate a memory handle. Ignoring a buffer " << b.bufferId;
-            continue;
-        }
-
-        ::android::status_t result =
-                mapper.importBuffer(handleToImport, pDesc->width, pDesc->height, pDesc->layers,
-                                    pDesc->format, pDesc->usage, pDesc->stride, &handleToStore);
-        if (result != ::android::NO_ERROR || handleToStore == nullptr) {
-            LOG(WARNING) << "Failed to import a buffer " << b.bufferId;
-            continue;
-        }
-
-        bool stored = false;
-        for (auto&& rec : mBuffers) {
-            if (rec.handle != nullptr) {
-                continue;
-            }
-
-            // Use this existing entry.
-            rec.handle = handleToStore;
-            rec.inUse = false;
-            stored = true;
-            break;
-        }
-
-        if (!stored) {
-            // Add a BufferRecord wrapping this handle to our set of available buffers.
-            mBuffers.push_back(BufferRecord(handleToStore));
-        }
-        ++mFramesAllowed;
-    }
-
-    *_aidl_return = mFramesAllowed - before;
-    return ScopedAStatus::ok();
-}
-
-bool EvsMockCamera::setAvailableFrames_Locked(unsigned bufferCount) {
-    if (bufferCount < 1) {
-        LOG(ERROR) << "Ignoring request to set buffer count to zero";
-        return false;
-    }
-    if (bufferCount > kMaxBuffersInFlight) {
-        LOG(ERROR) << "Rejecting buffer request in excess of internal limit";
-        return false;
-    }
-
-    // Is an increase required?
-    if (mFramesAllowed < bufferCount) {
-        // An increase is required
-        auto needed = bufferCount - mFramesAllowed;
-        LOG(INFO) << "Allocating " << needed << " buffers for camera frames";
-
-        auto added = increaseAvailableFrames_Locked(needed);
-        if (added != needed) {
-            // If we didn't add all the frames we needed, then roll back to the previous state
-            LOG(ERROR) << "Rolling back to previous frame queue size";
-            decreaseAvailableFrames_Locked(added);
-            return false;
-        }
-    } else if (mFramesAllowed > bufferCount) {
-        // A decrease is required
-        auto framesToRelease = mFramesAllowed - bufferCount;
-        LOG(INFO) << "Returning " << framesToRelease << " camera frame buffers";
-
-        auto released = decreaseAvailableFrames_Locked(framesToRelease);
-        if (released != framesToRelease) {
-            // This shouldn't happen with a properly behaving client because the client
-            // should only make this call after returning sufficient outstanding buffers
-            // to allow a clean resize.
-            LOG(ERROR) << "Buffer queue shrink failed -- too many buffers currently in use?";
-        }
-    }
-
-    return true;
-}
-
-unsigned EvsMockCamera::increaseAvailableFrames_Locked(unsigned numToAdd) {
-    // Acquire the graphics buffer allocator
-    ::android::GraphicBufferAllocator& alloc(::android::GraphicBufferAllocator::get());
-
-    unsigned added = 0;
-    while (added < numToAdd) {
-        unsigned pixelsPerLine = 0;
-        buffer_handle_t memHandle = nullptr;
-        auto result = alloc.allocate(mWidth, mHeight, mFormat, 1, mUsage, &memHandle,
-                                     &pixelsPerLine, 0, "EvsMockCamera");
-        if (result != ::android::NO_ERROR) {
-            LOG(ERROR) << "Error " << result << " allocating " << mWidth << " x " << mHeight
-                       << " graphics buffer";
-            break;
-        }
-        if (memHandle == nullptr) {
-            LOG(ERROR) << "We didn't get a buffer handle back from the allocator";
-            break;
-        }
-        if (mStride > 0) {
-            if (mStride != pixelsPerLine) {
-                LOG(ERROR) << "We did not expect to get buffers with different strides!";
-            }
-        } else {
-            // Gralloc defines stride in terms of pixels per line
-            mStride = pixelsPerLine;
-        }
-
-        // Find a place to store the new buffer
-        auto stored = false;
-        for (auto&& rec : mBuffers) {
-            if (rec.handle == nullptr) {
-                // Use this existing entry
-                rec.handle = memHandle;
-                rec.inUse = false;
-                stored = true;
-                break;
-            }
-        }
-        if (!stored) {
-            // Add a BufferRecord wrapping this handle to our set of available buffers
-            mBuffers.push_back(BufferRecord(memHandle));
-        }
-
-        ++mFramesAllowed;
-        ++added;
-    }
-
-    return added;
-}
-
-unsigned EvsMockCamera::decreaseAvailableFrames_Locked(unsigned numToRemove) {
-    // Acquire the graphics buffer allocator
-    ::android::GraphicBufferAllocator& alloc(::android::GraphicBufferAllocator::get());
-
-    unsigned removed = 0;
-    for (auto&& rec : mBuffers) {
-        // Is this record not in use, but holding a buffer that we can free?
-        if ((rec.inUse == false) && (rec.handle != nullptr)) {
-            // Release buffer and update the record so we can recognize it as "empty"
-            alloc.free(rec.handle);
-            rec.handle = nullptr;
-
-            --mFramesAllowed;
-            ++removed;
-
-            if (removed == numToRemove) {
-                break;
-            }
-        }
-    }
-
-    return removed;
-}
-
 // This is the asynchronous frame generation thread that runs in parallel with the
 // main serving thread.  There is one for each active camera instance.
 void EvsMockCamera::generateFrames() {
     LOG(DEBUG) << "Frame generation loop started.";
 
-    unsigned idx = 0;
     while (true) {
-        bool timeForFrame = false;
         const nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
-
-        // Lock scope for updating shared state
+        std::size_t bufferId = kInvalidBufferID;
+        buffer_handle_t bufferHandle = nullptr;
         {
-            std::lock_guard lock(mAccessLock);
-
-            if (mStreamState != RUNNING) {
-                // Break out of our main thread loop
+            std::lock_guard lock(mMutex);
+            if (mStreamState != StreamState::RUNNING) {
                 break;
             }
-
-            // Are we allowed to issue another buffer?
-            if (mFramesInUse >= mFramesAllowed) {
-                // Can't do anything right now -- skip this frame
-                LOG(WARNING) << "Skipped a frame because too many are in flight.";
-            } else {
-                // Identify an available buffer to fill
-                for (idx = 0; idx < mBuffers.size(); idx++) {
-                    if (!mBuffers[idx].inUse) {
-                        if (mBuffers[idx].handle != nullptr) {
-                            // Found an available record, so stop looking
-                            break;
-                        }
-                    }
-                }
-                if (idx >= mBuffers.size()) {
-                    // This shouldn't happen since we already checked mFramesInUse vs mFramesAllowed
-                    ALOGE("Failed to find an available buffer slot\n");
-                } else {
-                    // We're going to make the frame busy
-                    mBuffers[idx].inUse = true;
-                    mFramesInUse++;
-                    timeForFrame = true;
-                }
-            }
+            std::tie(bufferId, bufferHandle) = useBuffer_unsafe();
         }
 
-        if (timeForFrame) {
+        if (bufferHandle != nullptr) {
             using AidlPixelFormat = ::aidl::android::hardware::graphics::common::PixelFormat;
 
             // Assemble the buffer description we'll transmit below
-            buffer_handle_t memHandle = mBuffers[idx].handle;
             BufferDesc newBuffer = {
                     .buffer =
                             {
@@ -584,39 +225,31 @@
                                                     .usage = static_cast<BufferUsage>(mUsage),
                                                     .stride = static_cast<int32_t>(mStride),
                                             },
-                                    .handle = ::android::dupToAidl(memHandle),
+                                    .handle = ::android::dupToAidl(bufferHandle),
                             },
-                    .bufferId = static_cast<int32_t>(idx),
+                    .bufferId = static_cast<int32_t>(bufferId),
                     .deviceId = mDescription.id,
                     .timestamp = static_cast<int64_t>(::android::elapsedRealtimeNano() *
                                                       1e+3),  // timestamps is in microseconds
             };
 
             // Write test data into the image buffer
-            fillMockFrame(memHandle, reinterpret_cast<const AHardwareBuffer_Desc*>(
-                                             &newBuffer.buffer.description));
+            fillMockFrame(bufferHandle, reinterpret_cast<const AHardwareBuffer_Desc*>(
+                                                &newBuffer.buffer.description));
+
+            std::vector<BufferDesc> frames;
+            frames.push_back(std::move(newBuffer));
 
             // Issue the (asynchronous) callback to the client -- can't be holding the lock
-            auto flag = false;
-            if (mStream) {
-                std::vector<BufferDesc> frames;
-                frames.push_back(std::move(newBuffer));
-                flag = mStream->deliverFrame(frames).isOk();
-            }
-
-            if (flag) {
-                LOG(DEBUG) << "Delivered " << memHandle << ", id = " << mBuffers[idx].handle;
+            if (mStream && mStream->deliverFrame(frames).isOk()) {
+                LOG(DEBUG) << "Delivered " << bufferHandle << ", id = " << bufferId;
             } else {
                 // This can happen if the client dies and is likely unrecoverable.
                 // To avoid consuming resources generating failing calls, we stop sending
                 // frames.  Note, however, that the stream remains in the "STREAMING" state
                 // until cleaned up on the main thread.
                 LOG(ERROR) << "Frame delivery call failed in the transport layer.";
-
-                // Since we didn't actually deliver it, mark the frame as available
-                std::lock_guard<std::mutex> lock(mAccessLock);
-                mBuffers[idx].inUse = false;
-                mFramesInUse--;
+                doneWithFrame(frames);
             }
         }
 
@@ -671,34 +304,45 @@
     mapper.unlock(handle);
 }
 
-void EvsMockCamera::returnBufferLocked(const uint32_t bufferId) {
-    if (bufferId >= mBuffers.size()) {
-        ALOGE("ignoring doneWithFrame called with invalid bufferId %d (max is %zu)", bufferId,
-              mBuffers.size() - 1);
-        return;
+::android::status_t EvsMockCamera::allocateOneFrame(buffer_handle_t* handle) {
+    static auto& alloc = ::android::GraphicBufferAllocator::get();
+    unsigned pixelsPerLine = 0;
+    const auto result = alloc.allocate(mWidth, mHeight, mFormat, 1, mUsage, handle, &pixelsPerLine,
+                                       0, "EvsMockCamera");
+    if (mStride < mWidth) {
+        // Gralloc defines stride in terms of pixels per line
+        mStride = pixelsPerLine;
+    } else if (mStride != pixelsPerLine) {
+        LOG(ERROR) << "We did not expect to get buffers with different strides!";
     }
+    return result;
+}
 
-    if (!mBuffers[bufferId].inUse) {
-        ALOGE("ignoring doneWithFrame called on frame %d which is already free", bufferId);
-        return;
+bool EvsMockCamera::startVideoStreamImpl_locked(
+        const std::shared_ptr<evs::IEvsCameraStream>& receiver, ndk::ScopedAStatus& /* status */,
+        std::unique_lock<std::mutex>& /* lck */) {
+    mStream = receiver;
+    mCaptureThread = std::thread([this]() { generateFrames(); });
+    return true;
+}
+
+bool EvsMockCamera::stopVideoStreamImpl_locked(ndk::ScopedAStatus& /* status */,
+                                               std::unique_lock<std::mutex>& lck) {
+    lck.unlock();
+    if (mCaptureThread.joinable()) {
+        mCaptureThread.join();
     }
+    lck.lock();
+    return true;
+}
 
-    // Mark the frame as available
-    mBuffers[bufferId].inUse = false;
-    mFramesInUse--;
-
-    // If this frame's index is high in the array, try to move it down
-    // to improve locality after mFramesAllowed has been reduced.
-    if (bufferId >= mFramesAllowed) {
-        // Find an empty slot lower in the array (which should always exist in this case)
-        for (auto&& rec : mBuffers) {
-            if (rec.handle == nullptr) {
-                rec.handle = mBuffers[bufferId].handle;
-                mBuffers[bufferId].handle = nullptr;
-                break;
-            }
-        }
+bool EvsMockCamera::postVideoStreamStop_locked(ndk::ScopedAStatus& status,
+                                               std::unique_lock<std::mutex>& lck) {
+    if (!Base::postVideoStreamStop_locked(status, lck)) {
+        return false;
     }
+    mStream = nullptr;
+    return true;
 }
 
 std::shared_ptr<EvsMockCamera> EvsMockCamera::Create(const char* deviceName) {
diff --git a/automotive/evs/aidl/impl/default/src/EvsVideoEmulatedCamera.cpp b/automotive/evs/aidl/impl/default/src/EvsVideoEmulatedCamera.cpp
new file mode 100644
index 0000000..e3f7b5e
--- /dev/null
+++ b/automotive/evs/aidl/impl/default/src/EvsVideoEmulatedCamera.cpp
@@ -0,0 +1,505 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "EvsVideoEmulatedCamera.h"
+
+#include <aidl/android/hardware/automotive/evs/EvsResult.h>
+
+#include <aidlcommonsupport/NativeHandle.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <media/stagefright/MediaCodecConstants.h>
+#include <ui/GraphicBufferAllocator.h>
+#include <utils/SystemClock.h>
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <chrono>
+#include <cstddef>
+#include <cstdint>
+#include <tuple>
+#include <utility>
+
+namespace aidl::android::hardware::automotive::evs::implementation {
+
+namespace {
+struct FormatDeleter {
+    void operator()(AMediaFormat* format) const { AMediaFormat_delete(format); }
+};
+}  // namespace
+
+EvsVideoEmulatedCamera::EvsVideoEmulatedCamera(Sigil, const char* deviceName,
+                                               std::unique_ptr<ConfigManager::CameraInfo>& camInfo)
+    : mVideoFileName(deviceName), mCameraInfo(camInfo) {
+    mDescription.id = mVideoFileName;
+
+    /* set camera metadata */
+    if (camInfo) {
+        uint8_t* ptr = reinterpret_cast<uint8_t*>(camInfo->characteristics);
+        const size_t len = get_camera_metadata_size(camInfo->characteristics);
+        mDescription.metadata.insert(mDescription.metadata.end(), ptr, ptr + len);
+    }
+
+    initializeParameters();
+}
+
+bool EvsVideoEmulatedCamera::initialize() {
+    // Open file.
+    mVideoFd = open(mVideoFileName.c_str(), 0, O_RDONLY);
+    if (mVideoFd < 0) {
+        PLOG(ERROR) << __func__ << ": Failed to open video file \"" << mVideoFileName << "\".";
+        return false;
+    }
+
+    // Initialize Media Extractor.
+    {
+        mVideoExtractor.reset(AMediaExtractor_new());
+        off64_t filesize = lseek64(mVideoFd, 0, SEEK_END);
+        lseek(mVideoFd, 0, SEEK_SET);
+        const media_status_t status =
+                AMediaExtractor_setDataSourceFd(mVideoExtractor.get(), mVideoFd, 0, filesize);
+        if (status != AMEDIA_OK) {
+            LOG(ERROR) << __func__
+                       << ": Received error when initializing media extractor. Error code: "
+                       << status << ".";
+            return false;
+        }
+    }
+
+    // Initialize Media Codec and file format.
+    std::unique_ptr<AMediaFormat, FormatDeleter> format;
+    const char* mime;
+    bool selected = false;
+    int numTracks = AMediaExtractor_getTrackCount(mVideoExtractor.get());
+    for (int i = 0; i < numTracks; i++) {
+        format.reset(AMediaExtractor_getTrackFormat(mVideoExtractor.get(), i));
+        if (!AMediaFormat_getString(format.get(), AMEDIAFORMAT_KEY_MIME, &mime)) {
+            LOG(ERROR) << __func__ << ": Error in fetching format string";
+            continue;
+        }
+        if (!::android::base::StartsWith(mime, "video/")) {
+            continue;
+        }
+        const media_status_t status = AMediaExtractor_selectTrack(mVideoExtractor.get(), i);
+        if (status != AMEDIA_OK) {
+            LOG(ERROR) << __func__
+                       << ": Media extractor returned error to select track. Error Code: " << status
+                       << ".";
+            return false;
+        }
+        selected = true;
+        break;
+    }
+    if (!selected) {
+        LOG(ERROR) << __func__ << ": No video track in video file \"" << mVideoFileName << "\".";
+        return false;
+    }
+
+    mVideoCodec.reset(AMediaCodec_createDecoderByType(mime));
+    if (!mVideoCodec) {
+        LOG(ERROR) << __func__ << ": Unable to create decoder.";
+        return false;
+    }
+
+    mDescription.vendorFlags = 0xFFFFFFFF;  // Arbitrary test value
+    mUsage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_CAMERA_WRITE |
+             GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_RARELY;
+    mFormat = HAL_PIXEL_FORMAT_YCBCR_420_888;
+    AMediaFormat_setInt32(format.get(), AMEDIAFORMAT_KEY_COLOR_FORMAT, COLOR_FormatYUV420Flexible);
+    {
+        const media_status_t status =
+                AMediaCodec_configure(mVideoCodec.get(), format.get(), nullptr, nullptr, 0);
+        if (status != AMEDIA_OK) {
+            LOG(ERROR) << __func__
+                       << ": Received error in configuring mCodec. Error code: " << status << ".";
+            return false;
+        }
+    }
+    format.reset(AMediaCodec_getOutputFormat(mVideoCodec.get()));
+    AMediaFormat_getInt32(format.get(), AMEDIAFORMAT_KEY_WIDTH, &mWidth);
+    AMediaFormat_getInt32(format.get(), AMEDIAFORMAT_KEY_HEIGHT, &mHeight);
+    return true;
+}
+
+void EvsVideoEmulatedCamera::generateFrames() {
+    while (true) {
+        {
+            std::lock_guard lock(mMutex);
+            if (mStreamState != StreamState::RUNNING) {
+                return;
+            }
+        }
+        renderOneFrame();
+    }
+}
+
+void EvsVideoEmulatedCamera::onCodecInputAvailable(const int32_t index) {
+    const size_t sampleSize = AMediaExtractor_getSampleSize(mVideoExtractor.get());
+    const int64_t presentationTime = AMediaExtractor_getSampleTime(mVideoExtractor.get());
+    size_t bufferSize = 0;
+    uint8_t* const codecInputBuffer =
+            AMediaCodec_getInputBuffer(mVideoCodec.get(), index, &bufferSize);
+    if (sampleSize > bufferSize) {
+        LOG(ERROR) << __func__ << ": Buffer is not large enough.";
+    }
+    if (presentationTime < 0) {
+        AMediaCodec_queueInputBuffer(mVideoCodec.get(), index, /* offset = */ 0,
+                                     /* size = */ 0, presentationTime,
+                                     AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM);
+        LOG(INFO) << __func__ << ": Reaching the end of stream.";
+        return;
+    }
+    const size_t readSize =
+            AMediaExtractor_readSampleData(mVideoExtractor.get(), codecInputBuffer, sampleSize);
+    const media_status_t status = AMediaCodec_queueInputBuffer(
+            mVideoCodec.get(), index, /*offset = */ 0, readSize, presentationTime, /* flags = */ 0);
+    if (status != AMEDIA_OK) {
+        LOG(ERROR) << __func__
+                   << ": Received error in queueing input buffer. Error code: " << status;
+    }
+}
+
+void EvsVideoEmulatedCamera::onCodecOutputAvailable(const int32_t index,
+                                                    const AMediaCodecBufferInfo& info) {
+    using std::chrono::duration_cast;
+    using std::chrono::microseconds;
+    using std::chrono::nanoseconds;
+    using AidlPixelFormat = ::aidl::android::hardware::graphics::common::PixelFormat;
+    using ::aidl::android::hardware::graphics::common::BufferUsage;
+
+    size_t decodedOutSize = 0;
+    uint8_t* const codecOutputBuffer =
+            AMediaCodec_getOutputBuffer(mVideoCodec.get(), index, &decodedOutSize) + info.offset;
+
+    std::size_t renderBufferId = static_cast<std::size_t>(-1);
+    buffer_handle_t renderBufferHandle = nullptr;
+    {
+        std::lock_guard lock(mMutex);
+        if (mStreamState != StreamState::RUNNING) {
+            return;
+        }
+        std::tie(renderBufferId, renderBufferHandle) = useBuffer_unsafe();
+    }
+    if (!renderBufferHandle) {
+        LOG(ERROR) << __func__ << ": Camera failed to get an available render buffer.";
+        return;
+    }
+    std::vector<BufferDesc> renderBufferDescs;
+    renderBufferDescs.push_back({
+            .buffer =
+                    {
+                            .description =
+                                    {
+                                            .width = static_cast<int32_t>(mWidth),
+                                            .height = static_cast<int32_t>(mHeight),
+                                            .layers = 1,
+                                            .format = static_cast<AidlPixelFormat>(mFormat),
+                                            .usage = static_cast<BufferUsage>(mUsage),
+                                            .stride = static_cast<int32_t>(mStride),
+                                    },
+                            .handle = ::android::dupToAidl(renderBufferHandle),
+                    },
+            .bufferId = static_cast<int32_t>(renderBufferId),
+            .deviceId = mDescription.id,
+            .timestamp = duration_cast<microseconds>(nanoseconds(::android::elapsedRealtimeNano()))
+                                 .count(),
+    });
+
+    // Lock our output buffer for writing
+    uint8_t* pixels = nullptr;
+    auto& mapper = ::android::GraphicBufferMapper::get();
+    mapper.lock(renderBufferHandle, GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_NEVER,
+                ::android::Rect(mWidth, mHeight), (void**)&pixels);
+
+    // If we failed to lock the pixel buffer, we're about to crash, but log it first
+    if (!pixels) {
+        LOG(ERROR) << __func__ << ": Camera failed to gain access to image buffer for writing";
+        return;
+    }
+
+    std::size_t ySize = mHeight * mStride;
+    std::size_t uvSize = ySize / 4;
+
+    std::memcpy(pixels, codecOutputBuffer, ySize);
+    pixels += ySize;
+
+    uint8_t* u_head = codecOutputBuffer + ySize;
+    uint8_t* v_head = u_head + uvSize;
+
+    for (size_t i = 0; i < uvSize; ++i) {
+        *(pixels++) = *(u_head++);
+        *(pixels++) = *(v_head++);
+    }
+
+    // Release our output buffer
+    mapper.unlock(renderBufferHandle);
+
+    // Issue the (asynchronous) callback to the client -- can't be holding the lock
+    if (mStream && mStream->deliverFrame(renderBufferDescs).isOk()) {
+        LOG(DEBUG) << __func__ << ": Delivered " << renderBufferHandle
+                   << ", id = " << renderBufferId;
+    } else {
+        // This can happen if the client dies and is likely unrecoverable.
+        // To avoid consuming resources generating failing calls, we stop sending
+        // frames.  Note, however, that the stream remains in the "STREAMING" state
+        // until cleaned up on the main thread.
+        LOG(ERROR) << __func__ << ": Frame delivery call failed in the transport layer.";
+        doneWithFrame(renderBufferDescs);
+    }
+}
+
+void EvsVideoEmulatedCamera::renderOneFrame() {
+    using std::chrono::duration_cast;
+    using std::chrono::microseconds;
+    using namespace std::chrono_literals;
+
+    // push to codec input
+    while (true) {
+        int codecInputBufferIdx =
+                AMediaCodec_dequeueInputBuffer(mVideoCodec.get(), /* timeoutUs = */ 0);
+        if (codecInputBufferIdx < 0) {
+            if (codecInputBufferIdx != AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
+                LOG(ERROR) << __func__
+                           << ": Received error in AMediaCodec_dequeueInputBuffer. Error code: "
+                           << codecInputBufferIdx;
+            }
+            break;
+        }
+        onCodecInputAvailable(codecInputBufferIdx);
+        AMediaExtractor_advance(mVideoExtractor.get());
+    }
+
+    // pop from codec output
+
+    AMediaCodecBufferInfo info;
+    int codecOutputputBufferIdx = AMediaCodec_dequeueOutputBuffer(
+            mVideoCodec.get(), &info, /* timeoutUs = */ duration_cast<microseconds>(1ms).count());
+    if (codecOutputputBufferIdx < 0) {
+        if (codecOutputputBufferIdx != AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
+            LOG(ERROR) << __func__
+                       << ": Received error in AMediaCodec_dequeueOutputBuffer. Error code: "
+                       << codecOutputputBufferIdx;
+        }
+        return;
+    }
+    onCodecOutputAvailable(codecOutputputBufferIdx, info);
+    const auto release_status = AMediaCodec_releaseOutputBuffer(
+            mVideoCodec.get(), codecOutputputBufferIdx, /* render = */ false);
+    if (release_status != AMEDIA_OK) {
+        LOG(ERROR) << __func__
+                   << ": Received error in releasing output buffer. Error code: " << release_status;
+    }
+}
+
+void EvsVideoEmulatedCamera::initializeParameters() {
+    mParams.emplace(
+            CameraParam::BRIGHTNESS,
+            new CameraParameterDesc(/* min= */ 0, /* max= */ 255, /* step= */ 1, /* value= */ 255));
+    mParams.emplace(
+            CameraParam::CONTRAST,
+            new CameraParameterDesc(/* min= */ 0, /* max= */ 255, /* step= */ 1, /* value= */ 255));
+    mParams.emplace(
+            CameraParam::SHARPNESS,
+            new CameraParameterDesc(/* min= */ 0, /* max= */ 255, /* step= */ 1, /* value= */ 255));
+}
+
+::android::status_t EvsVideoEmulatedCamera::allocateOneFrame(buffer_handle_t* handle) {
+    static auto& alloc = ::android::GraphicBufferAllocator::get();
+    unsigned pixelsPerLine = 0;
+    const auto result = alloc.allocate(mWidth, mHeight, mFormat, 1, mUsage, handle, &pixelsPerLine,
+                                       0, "EvsVideoEmulatedCamera");
+    if (mStride == 0) {
+        // Gralloc defines stride in terms of pixels per line
+        mStride = pixelsPerLine;
+    } else if (mStride != pixelsPerLine) {
+        LOG(ERROR) << "We did not expect to get buffers with different strides!";
+    }
+    return result;
+}
+
+bool EvsVideoEmulatedCamera::startVideoStreamImpl_locked(
+        const std::shared_ptr<evs::IEvsCameraStream>& receiver, ndk::ScopedAStatus& /* status */,
+        std::unique_lock<std::mutex>& /* lck */) {
+    mStream = receiver;
+
+    const media_status_t status = AMediaCodec_start(mVideoCodec.get());
+    if (status != AMEDIA_OK) {
+        LOG(ERROR) << __func__ << ": Received error in starting decoder. Error code: " << status
+                   << ".";
+        return false;
+    }
+    mCaptureThread = std::thread([this]() { generateFrames(); });
+
+    return true;
+}
+
+bool EvsVideoEmulatedCamera::stopVideoStreamImpl_locked(ndk::ScopedAStatus& /* status */,
+                                                        std::unique_lock<std::mutex>& lck) {
+    const media_status_t status = AMediaCodec_stop(mVideoCodec.get());
+    lck.unlock();
+    if (mCaptureThread.joinable()) {
+        mCaptureThread.join();
+    }
+    lck.lock();
+    return status == AMEDIA_OK;
+}
+
+bool EvsVideoEmulatedCamera::postVideoStreamStop_locked(ndk::ScopedAStatus& status,
+                                                        std::unique_lock<std::mutex>& lck) {
+    if (!Base::postVideoStreamStop_locked(status, lck)) {
+        return false;
+    }
+    mStream = nullptr;
+    return true;
+}
+
+ndk::ScopedAStatus EvsVideoEmulatedCamera::forcePrimaryClient(
+        const std::shared_ptr<evs::IEvsDisplay>& /* display */) {
+    /* Because EVS HW module reference implementation expects a single client at
+     * a time, this returns a success code always.
+     */
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EvsVideoEmulatedCamera::getCameraInfo(evs::CameraDesc* _aidl_return) {
+    *_aidl_return = mDescription;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EvsVideoEmulatedCamera::getExtendedInfo(int32_t opaqueIdentifier,
+                                                           std::vector<uint8_t>* value) {
+    const auto it = mExtInfo.find(opaqueIdentifier);
+    if (it == mExtInfo.end()) {
+        return ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int>(EvsResult::INVALID_ARG));
+    } else {
+        *value = mExtInfo[opaqueIdentifier];
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EvsVideoEmulatedCamera::getIntParameter(evs::CameraParam id,
+                                                           std::vector<int32_t>* value) {
+    const auto it = mParams.find(id);
+    if (it == mParams.end()) {
+        return ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int>(EvsResult::NOT_SUPPORTED));
+    }
+    value->push_back(it->second->value);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EvsVideoEmulatedCamera::getIntParameterRange(evs::CameraParam id,
+                                                                evs::ParameterRange* _aidl_return) {
+    const auto it = mParams.find(id);
+    if (it == mParams.end()) {
+        return ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int>(EvsResult::NOT_SUPPORTED));
+    }
+    _aidl_return->min = it->second->range.min;
+    _aidl_return->max = it->second->range.max;
+    _aidl_return->step = it->second->range.step;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EvsVideoEmulatedCamera::getParameterList(
+        std::vector<evs::CameraParam>* _aidl_return) {
+    if (mCameraInfo) {
+        _aidl_return->resize(mCameraInfo->controls.size());
+        std::size_t idx = 0;
+        for (const auto& [name, range] : mCameraInfo->controls) {
+            (*_aidl_return)[idx++] = name;
+        }
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EvsVideoEmulatedCamera::getPhysicalCameraInfo(const std::string& /* deviceId */,
+                                                                 evs::CameraDesc* _aidl_return) {
+    return getCameraInfo(_aidl_return);
+}
+
+ndk::ScopedAStatus EvsVideoEmulatedCamera::setExtendedInfo(
+        int32_t opaqueIdentifier, const std::vector<uint8_t>& opaqueValue) {
+    mExtInfo.insert_or_assign(opaqueIdentifier, opaqueValue);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EvsVideoEmulatedCamera::setIntParameter(evs::CameraParam id, int32_t value,
+                                                           std::vector<int32_t>* effectiveValue) {
+    const auto it = mParams.find(id);
+    if (it == mParams.end()) {
+        return ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int>(EvsResult::NOT_SUPPORTED));
+    }
+    // Rounding down to the closest value.
+    int32_t candidate = value / it->second->range.step * it->second->range.step;
+    if (candidate < it->second->range.min || candidate > it->second->range.max) {
+        return ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int>(EvsResult::INVALID_ARG));
+    }
+    it->second->value = candidate;
+    effectiveValue->push_back(candidate);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EvsVideoEmulatedCamera::setPrimaryClient() {
+    /* Because EVS HW module reference implementation expects a single client at
+     * a time, this returns a success code always.
+     */
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EvsVideoEmulatedCamera::unsetPrimaryClient() {
+    /* Because EVS HW module reference implementation expects a single client at
+     * a time, there is no chance that this is called by the secondary client and
+     * therefore returns a success code always.
+     */
+    return ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EvsVideoEmulatedCamera> EvsVideoEmulatedCamera::Create(const char* deviceName) {
+    std::unique_ptr<ConfigManager::CameraInfo> nullCamInfo = nullptr;
+    return Create(deviceName, nullCamInfo);
+}
+
+std::shared_ptr<EvsVideoEmulatedCamera> EvsVideoEmulatedCamera::Create(
+        const char* deviceName, std::unique_ptr<ConfigManager::CameraInfo>& camInfo,
+        const evs::Stream* /* streamCfg */) {
+    std::shared_ptr<EvsVideoEmulatedCamera> c =
+            ndk::SharedRefBase::make<EvsVideoEmulatedCamera>(Sigil{}, deviceName, camInfo);
+    if (!c) {
+        LOG(ERROR) << "Failed to instantiate EvsVideoEmulatedCamera.";
+        return nullptr;
+    }
+    if (!c->initialize()) {
+        LOG(ERROR) << "Failed to initialize EvsVideoEmulatedCamera.";
+        return nullptr;
+    }
+    return c;
+}
+
+void EvsVideoEmulatedCamera::shutdown() {
+    mVideoCodec.reset();
+    mVideoExtractor.reset();
+    close(mVideoFd);
+    mVideoFd = 0;
+    Base::shutdown();
+}
+
+}  // namespace aidl::android::hardware::automotive::evs::implementation
diff --git a/automotive/evs/aidl/impl/default/src/GlWrapper.cpp b/automotive/evs/aidl/impl/default/src/GlWrapper.cpp
index 0ee5ecb..a9d0213 100644
--- a/automotive/evs/aidl/impl/default/src/GlWrapper.cpp
+++ b/automotive/evs/aidl/impl/default/src/GlWrapper.cpp
@@ -19,6 +19,7 @@
 #include <aidl/android/frameworks/automotive/display/DisplayDesc.h>
 #include <aidl/android/hardware/graphics/common/HardwareBufferDescription.h>
 #include <aidlcommonsupport/NativeHandle.h>
+#include <gui/view/Surface.h>
 #include <ui/DisplayMode.h>
 #include <ui/DisplayState.h>
 #include <ui/GraphicBuffer.h>
@@ -183,20 +184,6 @@
     return program;
 }
 
-::android::sp<HGraphicBufferProducer> convertNativeHandleToHGBP(const NativeHandle& aidlHandle) {
-    native_handle_t* handle = ::android::dupFromAidl(aidlHandle);
-    if (handle->numFds != 0 || handle->numInts < std::ceil(sizeof(size_t) / sizeof(int))) {
-        LOG(ERROR) << "Invalid native handle";
-        return nullptr;
-    }
-    ::android::hardware::hidl_vec<uint8_t> halToken;
-    halToken.setToExternal(reinterpret_cast<uint8_t*>(const_cast<int*>(&(handle->data[1]))),
-                           handle->data[0]);
-    ::android::sp<HGraphicBufferProducer> hgbp =
-            HGraphicBufferProducer::castFrom(::android::retrieveHalInterface(halToken));
-    return std::move(hgbp);
-}
-
 }  // namespace
 
 namespace aidl::android::hardware::automotive::evs::implementation {
@@ -226,30 +213,19 @@
     }
     LOG(INFO) << "Display resolution is " << mWidth << "x" << mHeight;
 
-    NativeHandle aidlHandle;
-    status = pWindowProxy->getHGraphicBufferProducer(displayId, &aidlHandle);
+    aidl::android::view::Surface shimSurface;
+    status = pWindowProxy->getSurface(displayId, &shimSurface);
     if (!status.isOk()) {
-        LOG(ERROR) << "Failed to get IGraphicBufferProducer from ICarDisplayProxy.";
+        LOG(ERROR) << "Failed to obtain the surface.";
         return false;
     }
 
-    mGfxBufferProducer = convertNativeHandleToHGBP(aidlHandle);
-    if (!mGfxBufferProducer) {
-        LOG(ERROR) << "Failed to convert a NativeHandle to HGBP.";
-        return false;
-    }
-
-    mSurfaceHolder = getSurfaceFromHGBP(mGfxBufferProducer);
-    if (mSurfaceHolder == nullptr) {
-        LOG(ERROR) << "Failed to get a Surface from HGBP.";
-        return false;
-    }
-
-    mWindow = getNativeWindow(mSurfaceHolder.get());
+    mWindow = shimSurface.get();
     if (mWindow == nullptr) {
         LOG(ERROR) << "Failed to get a native window from Surface.";
         return false;
     }
+    ANativeWindow_acquire(mWindow);
 
     // Set up our OpenGL ES context associated with the default display
     mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
@@ -350,7 +326,12 @@
     mDisplay = EGL_NO_DISPLAY;
 
     // Release the window
-    mSurfaceHolder = nullptr;
+    if (mWindow == nullptr) {
+        return;
+    }
+
+    ANativeWindow_release(mWindow);
+    mWindow = nullptr;
 }
 
 void GlWrapper::showWindow(const std::shared_ptr<ICarDisplayProxy>& pWindowProxy, uint64_t id) {
diff --git a/automotive/evs/aidl/impl/default/tests/EvsCameraBufferTest.cpp b/automotive/evs/aidl/impl/default/tests/EvsCameraBufferTest.cpp
new file mode 100644
index 0000000..8b4676e
--- /dev/null
+++ b/automotive/evs/aidl/impl/default/tests/EvsCameraBufferTest.cpp
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "EvsCamera.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <cstdint>
+#include <unordered_set>
+#include <vector>
+
+namespace aidl::android::hardware::automotive::evs::implementation {
+
+class EvsCameraForTest : public EvsCamera {
+  public:
+    using EvsCamera::increaseAvailableFrames_unsafe;
+    using EvsCamera::returnBuffer_unsafe;
+    using EvsCamera::useBuffer_unsafe;
+
+    ~EvsCameraForTest() override { shutdown(); }
+
+    ::android::status_t allocateOneFrame(buffer_handle_t* handle) override {
+        static std::intptr_t handle_cnt = 0;
+        *handle = reinterpret_cast<buffer_handle_t>(++handle_cnt);
+        return ::android::OK;
+    }
+
+    void freeOneFrame(const buffer_handle_t /* handle */) override {
+        // Nothing to free because the handles are fake.
+    }
+
+    void checkBufferOrder() {
+        for (std::size_t idx = 0; idx < mBuffers.size(); ++idx) {
+            const auto& buffer = mBuffers[idx];
+            EXPECT_EQ(idx < mFramesInUse, buffer.inUse);
+            EXPECT_EQ(idx < mAvailableFrames, buffer.handle != nullptr);
+            EXPECT_LE(mFramesInUse, mAvailableFrames);
+        }
+    }
+
+    MOCK_METHOD(::ndk::ScopedAStatus, forcePrimaryClient,
+                (const std::shared_ptr<::aidl::android::hardware::automotive::evs::IEvsDisplay>&
+                         in_display),
+                (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, getCameraInfo,
+                (::aidl::android::hardware::automotive::evs::CameraDesc * _aidl_return),
+                (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, getExtendedInfo,
+                (int32_t in_opaqueIdentifier, std::vector<uint8_t>* _aidl_return), (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, getIntParameter,
+                (::aidl::android::hardware::automotive::evs::CameraParam in_id,
+                 std::vector<int32_t>* _aidl_return),
+                (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, getIntParameterRange,
+                (::aidl::android::hardware::automotive::evs::CameraParam in_id,
+                 ::aidl::android::hardware::automotive::evs::ParameterRange* _aidl_return),
+                (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, getParameterList,
+                (std::vector<::aidl::android::hardware::automotive::evs::CameraParam> *
+                 _aidl_return),
+                (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, getPhysicalCameraInfo,
+                (const std::string& in_deviceId,
+                 ::aidl::android::hardware::automotive::evs::CameraDesc* _aidl_return),
+                (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, setExtendedInfo,
+                (int32_t in_opaqueIdentifier, const std::vector<uint8_t>& in_opaqueValue),
+                (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, setIntParameter,
+                (::aidl::android::hardware::automotive::evs::CameraParam in_id, int32_t in_value,
+                 std::vector<int32_t>* _aidl_return),
+                (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, setPrimaryClient, (), (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, unsetPrimaryClient, (), (override));
+    MOCK_METHOD(bool, startVideoStreamImpl_locked,
+                (const std::shared_ptr<evs::IEvsCameraStream>& receiver, ndk::ScopedAStatus& status,
+                 std::unique_lock<std::mutex>& lck),
+                (override));
+    MOCK_METHOD(bool, stopVideoStreamImpl_locked,
+                (ndk::ScopedAStatus & status, std::unique_lock<std::mutex>& lck), (override));
+};
+
+TEST(EvsCameraBufferTest, ChangeBufferPoolSize) {
+    auto evsCam = ndk::SharedRefBase::make<EvsCameraForTest>();
+    EXPECT_TRUE(evsCam->setMaxFramesInFlight(100).isOk());
+    evsCam->checkBufferOrder();
+    EXPECT_TRUE(evsCam->setMaxFramesInFlight(50).isOk());
+    evsCam->checkBufferOrder();
+
+    // 2 buffers in use.
+    const auto [id1, handle1] = evsCam->useBuffer_unsafe();
+    const auto [id2, handle2] = evsCam->useBuffer_unsafe();
+    std::ignore = evsCam->useBuffer_unsafe();
+
+    // It allows you to set the buffer pool size to 1, but it will keep the space for the in use
+    // buffers.
+    EXPECT_TRUE(evsCam->setMaxFramesInFlight(1).isOk());
+    evsCam->checkBufferOrder();
+
+    evsCam->returnBuffer_unsafe(id1);
+    evsCam->checkBufferOrder();
+    evsCam->returnBuffer_unsafe(id2);
+    evsCam->checkBufferOrder();
+}
+
+TEST(EvsCameraBufferTest, UseAndReturn) {
+    constexpr std::size_t kNumOfHandles = 20;
+    auto evsCam = ndk::SharedRefBase::make<EvsCameraForTest>();
+
+    // Our "fake handles" of this test case is 1 to kNumOfHandles.
+    for (std::size_t i = 1; i <= kNumOfHandles; ++i) {
+        evsCam->increaseAvailableFrames_unsafe(reinterpret_cast<buffer_handle_t>(i));
+    }
+    evsCam->checkBufferOrder();
+
+    {
+        std::vector<std::pair<std::size_t, std::intptr_t>> inUseIDHandlePairs;
+        std::unordered_set<std::size_t> inUseIDs;
+        std::unordered_set<std::intptr_t> inUseHandles;
+        for (std::size_t i = 0; i < kNumOfHandles; ++i) {
+            const auto [id, handle] = evsCam->useBuffer_unsafe();
+            const std::size_t handleInt = reinterpret_cast<std::size_t>(handle);
+            EXPECT_TRUE(EvsCamera::IsBufferIDValid(id));
+            EXPECT_NE(handle, nullptr);
+            EXPECT_LT(id, kNumOfHandles);
+
+            // handleInt must be between [1, kNumOfHandles] as we "allocated" above.
+            EXPECT_LT(0u, handleInt);
+            EXPECT_LE(handleInt, kNumOfHandles);
+
+            inUseIDHandlePairs.push_back({id, handleInt});
+            EXPECT_TRUE(inUseIDs.insert(id).second);
+            EXPECT_TRUE(inUseHandles.insert(handleInt).second);
+            evsCam->checkBufferOrder();
+        }
+        // Return buffers in the order of acquiring.
+        for (const auto [id, handleInt] : inUseIDHandlePairs) {
+            evsCam->returnBuffer_unsafe(id);
+            evsCam->checkBufferOrder();
+        }
+    }
+
+    {
+        std::vector<std::pair<std::size_t, std::intptr_t>> inUseIDHandlePairs;
+        std::unordered_set<std::size_t> inUseIDs;
+        std::unordered_set<std::intptr_t> inUseHandles;
+        for (std::size_t i = 0; i < kNumOfHandles; ++i) {
+            const auto [id, handle] = evsCam->useBuffer_unsafe();
+            const std::size_t handleInt = reinterpret_cast<std::size_t>(handle);
+            EXPECT_TRUE(EvsCamera::IsBufferIDValid(id));
+            EXPECT_NE(handle, nullptr);
+            EXPECT_LT(id, kNumOfHandles);
+
+            // handleInt must be between [1, kNumOfHandles] as we "allocated" above.
+            EXPECT_LT(0u, handleInt);
+            EXPECT_LE(handleInt, kNumOfHandles);
+
+            inUseIDHandlePairs.push_back({id, handleInt});
+            EXPECT_TRUE(inUseIDs.insert(id).second);
+            EXPECT_TRUE(inUseHandles.insert(handleInt).second);
+            evsCam->checkBufferOrder();
+        }
+        // Return buffers in the reverse order of acquiring.
+        std::reverse(inUseIDHandlePairs.begin(), inUseIDHandlePairs.end());
+        for (const auto [id, handleInt] : inUseIDHandlePairs) {
+            evsCam->returnBuffer_unsafe(id);
+            evsCam->checkBufferOrder();
+        }
+    }
+
+    {
+        // Making sure the handles are still in [1, kNumOfHandles] and IDs are still [0,
+        // kNumOfHandles). The mapping may be different, though.
+        std::vector<std::pair<std::size_t, std::intptr_t>> inUseIDHandlePairs;
+        std::unordered_set<std::size_t> inUseIDs;
+        std::unordered_set<std::intptr_t> inUseHandles;
+        for (std::size_t i = 0; i < kNumOfHandles; ++i) {
+            const auto [id, handle] = evsCam->useBuffer_unsafe();
+            const std::size_t handleInt = reinterpret_cast<std::size_t>(handle);
+            EXPECT_TRUE(EvsCamera::IsBufferIDValid(id));
+            EXPECT_NE(handle, nullptr);
+            EXPECT_LT(id, kNumOfHandles);
+
+            // handleInt must be between [1, kNumOfHandles] as we "allocated" above.
+            EXPECT_LT(0u, handleInt);
+            EXPECT_LE(handleInt, kNumOfHandles);
+
+            inUseIDHandlePairs.push_back({id, handleInt});
+            EXPECT_TRUE(inUseIDs.insert(id).second);
+            EXPECT_TRUE(inUseHandles.insert(handleInt).second);
+            evsCam->checkBufferOrder();
+        }
+    }
+}
+
+}  // namespace aidl::android::hardware::automotive::evs::implementation
diff --git a/automotive/evs/aidl/impl/default/tests/EvsCameraStateTest.cpp b/automotive/evs/aidl/impl/default/tests/EvsCameraStateTest.cpp
new file mode 100644
index 0000000..1925c79
--- /dev/null
+++ b/automotive/evs/aidl/impl/default/tests/EvsCameraStateTest.cpp
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "EvsCamera.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <cstdint>
+#include <unordered_set>
+#include <vector>
+
+namespace aidl::android::hardware::automotive::evs::implementation {
+
+class EvsCameraForTest : public EvsCamera {
+  private:
+    using Base = EvsCamera;
+
+  public:
+    using EvsCamera::mStreamState;
+    using EvsCamera::shutdown;
+    using EvsCamera::StreamState;
+
+    ~EvsCameraForTest() override { shutdown(); }
+
+    ::android::status_t allocateOneFrame(buffer_handle_t* handle) override {
+        static std::intptr_t handle_cnt = 0;
+        *handle = reinterpret_cast<buffer_handle_t>(++handle_cnt);
+        return ::android::OK;
+    }
+
+    void freeOneFrame(const buffer_handle_t /* handle */) override {
+        // Nothing to free because the handles are fake.
+    }
+
+    bool preVideoStreamStart_locked(const std::shared_ptr<evs::IEvsCameraStream>& receiver,
+                                    ndk::ScopedAStatus& status,
+                                    std::unique_lock<std::mutex>& lck) override {
+        mPreStartCalled = true;
+        EXPECT_EQ(mStreamState, StreamState::STOPPED);
+        EXPECT_FALSE(mStreamStarted);
+        EXPECT_FALSE(mStreamStopped);
+        return Base::preVideoStreamStart_locked(receiver, status, lck);
+    }
+
+    bool startVideoStreamImpl_locked(const std::shared_ptr<evs::IEvsCameraStream>& /* receiver */,
+                                     ndk::ScopedAStatus& /* status */,
+                                     std::unique_lock<std::mutex>& /* lck */) override {
+        EXPECT_EQ(mStreamState, StreamState::RUNNING);
+        EXPECT_FALSE(mStreamStarted);
+        EXPECT_FALSE(mStreamStopped);
+        mStreamStarted = true;
+        return true;
+    }
+
+    bool postVideoStreamStart_locked(const std::shared_ptr<evs::IEvsCameraStream>& receiver,
+                                     ndk::ScopedAStatus& status,
+                                     std::unique_lock<std::mutex>& lck) override {
+        mPostStartCalled = true;
+        EXPECT_EQ(mStreamState, StreamState::RUNNING);
+        EXPECT_TRUE(mStreamStarted);
+        EXPECT_FALSE(mStreamStopped);
+        return Base::postVideoStreamStart_locked(receiver, status, lck);
+    }
+
+    bool preVideoStreamStop_locked(ndk::ScopedAStatus& status,
+                                   std::unique_lock<std::mutex>& lck) override {
+        // Skip the check if stop was called before.
+        if (!mPreStopCalled) {
+            mPreStopCalled = true;
+            EXPECT_EQ(mStreamState, StreamState::RUNNING);
+            EXPECT_TRUE(mStreamStarted);
+            EXPECT_FALSE(mStreamStopped);
+        }
+        return Base::preVideoStreamStop_locked(status, lck);
+    }
+
+    bool stopVideoStreamImpl_locked(ndk::ScopedAStatus& /* status */,
+                                    std::unique_lock<std::mutex>& /* lck */) override {
+        EXPECT_EQ(mStreamState, StreamState::STOPPING);
+        EXPECT_TRUE(mStreamStarted);
+        EXPECT_FALSE(mStreamStopped);
+        mStreamStopped = true;
+        return true;
+    }
+
+    bool postVideoStreamStop_locked(ndk::ScopedAStatus& status,
+                                    std::unique_lock<std::mutex>& lck) override {
+        mPostStopCalled = true;
+        const auto ret = Base::postVideoStreamStop_locked(status, lck);
+        EXPECT_EQ(mStreamState, StreamState::STOPPED);
+        EXPECT_TRUE(mStreamStarted);
+        EXPECT_TRUE(mStreamStopped);
+        return ret;
+    }
+
+    MOCK_METHOD(::ndk::ScopedAStatus, forcePrimaryClient,
+                (const std::shared_ptr<::aidl::android::hardware::automotive::evs::IEvsDisplay>&
+                         in_display),
+                (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, getCameraInfo,
+                (::aidl::android::hardware::automotive::evs::CameraDesc * _aidl_return),
+                (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, getExtendedInfo,
+                (int32_t in_opaqueIdentifier, std::vector<uint8_t>* _aidl_return), (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, getIntParameter,
+                (::aidl::android::hardware::automotive::evs::CameraParam in_id,
+                 std::vector<int32_t>* _aidl_return),
+                (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, getIntParameterRange,
+                (::aidl::android::hardware::automotive::evs::CameraParam in_id,
+                 ::aidl::android::hardware::automotive::evs::ParameterRange* _aidl_return),
+                (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, getParameterList,
+                (std::vector<::aidl::android::hardware::automotive::evs::CameraParam> *
+                 _aidl_return),
+                (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, getPhysicalCameraInfo,
+                (const std::string& in_deviceId,
+                 ::aidl::android::hardware::automotive::evs::CameraDesc* _aidl_return),
+                (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, setExtendedInfo,
+                (int32_t in_opaqueIdentifier, const std::vector<uint8_t>& in_opaqueValue),
+                (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, setIntParameter,
+                (::aidl::android::hardware::automotive::evs::CameraParam in_id, int32_t in_value,
+                 std::vector<int32_t>* _aidl_return),
+                (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, setPrimaryClient, (), (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, unsetPrimaryClient, (), (override));
+
+    bool mStreamStarted = false;
+    bool mStreamStopped = false;
+    bool mPreStartCalled = false;
+    bool mPostStartCalled = false;
+    bool mPreStopCalled = false;
+    bool mPostStopCalled = false;
+};
+
+class MockEvsCameraStream : public evs::IEvsCameraStream {
+    MOCK_METHOD(::ndk::SpAIBinder, asBinder, (), (override));
+    MOCK_METHOD(bool, isRemote, (), (override));
+    MOCK_METHOD(
+            ::ndk::ScopedAStatus, deliverFrame,
+            (const std::vector<::aidl::android::hardware::automotive::evs::BufferDesc>& in_buffer),
+            (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, notify,
+                (const ::aidl::android::hardware::automotive::evs::EvsEventDesc& in_event),
+                (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, getInterfaceVersion, (int32_t * _aidl_return), (override));
+    MOCK_METHOD(::ndk::ScopedAStatus, getInterfaceHash, (std::string * _aidl_return), (override));
+};
+
+using StreamState = EvsCameraForTest::StreamState;
+
+TEST(EvsCameraStateTest, StateChangeHooks) {
+    auto evsCam = ndk::SharedRefBase::make<EvsCameraForTest>();
+    auto mockStream = ndk::SharedRefBase::make<MockEvsCameraStream>();
+    EXPECT_FALSE(evsCam->mPreStartCalled);
+    EXPECT_FALSE(evsCam->mPostStartCalled);
+    EXPECT_FALSE(evsCam->mPreStopCalled);
+    EXPECT_FALSE(evsCam->mPostStopCalled);
+    EXPECT_FALSE(evsCam->mStreamStarted);
+    EXPECT_FALSE(evsCam->mStreamStopped);
+    EXPECT_EQ(evsCam->mStreamState, StreamState::STOPPED);
+    evsCam->startVideoStream(mockStream);
+
+    EXPECT_TRUE(evsCam->mPreStartCalled);
+    EXPECT_TRUE(evsCam->mPostStartCalled);
+    EXPECT_FALSE(evsCam->mPreStopCalled);
+    EXPECT_FALSE(evsCam->mPostStopCalled);
+    EXPECT_TRUE(evsCam->mStreamStarted);
+    EXPECT_FALSE(evsCam->mStreamStopped);
+    EXPECT_EQ(evsCam->mStreamState, StreamState::RUNNING);
+    evsCam->stopVideoStream();
+
+    EXPECT_TRUE(evsCam->mPreStartCalled);
+    EXPECT_TRUE(evsCam->mPostStartCalled);
+    EXPECT_TRUE(evsCam->mPreStopCalled);
+    EXPECT_TRUE(evsCam->mPostStopCalled);
+    EXPECT_TRUE(evsCam->mStreamStarted);
+    EXPECT_TRUE(evsCam->mStreamStopped);
+    EXPECT_EQ(evsCam->mStreamState, StreamState::STOPPED);
+
+    evsCam->shutdown();
+    EXPECT_EQ(evsCam->mStreamState, StreamState::DEAD);
+}
+
+}  // namespace aidl::android::hardware::automotive::evs::implementation
diff --git a/automotive/evs/aidl/vts/VtsHalEvsTargetTest.cpp b/automotive/evs/aidl/vts/VtsHalEvsTargetTest.cpp
index 3419b3c..477de31 100644
--- a/automotive/evs/aidl/vts/VtsHalEvsTargetTest.cpp
+++ b/automotive/evs/aidl/vts/VtsHalEvsTargetTest.cpp
@@ -1399,6 +1399,12 @@
 
     // Test each reported camera
     for (auto&& cam : mCameraInfo) {
+        bool isLogicalCam = false;
+        if (getPhysicalCameraIds(cam.id, isLogicalCam); isLogicalCam) {
+            LOG(INFO) << "Skip a logical device, " << cam.id;
+            continue;
+        }
+
         // Request available display IDs
         uint8_t targetDisplayId = 0;
         std::vector<uint8_t> displayIds;
@@ -1973,6 +1979,13 @@
 
     // Test each reported camera
     for (auto&& cam : mCameraInfo) {
+        bool isLogicalCam = false;
+        getPhysicalCameraIds(cam.id, isLogicalCam);
+        if (isLogicalCam) {
+            LOG(INFO) << "Skip a logical device, " << cam.id;
+            continue;
+        }
+
         // Read a target resolution from the metadata
         Stream targetCfg = getFirstStreamConfiguration(
                 reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
@@ -2014,9 +2027,6 @@
             }
         }
 
-        bool isLogicalCam = false;
-        getPhysicalCameraIds(cam.id, isLogicalCam);
-
         std::shared_ptr<IEvsCamera> pCam;
         ASSERT_TRUE(mEnumerator->openCamera(cam.id, targetCfg, &pCam).isOk());
         EXPECT_NE(pCam, nullptr);
@@ -2027,11 +2037,6 @@
         // Request to import buffers
         int delta = 0;
         auto status = pCam->importExternalBuffers(buffers, &delta);
-        if (isLogicalCam) {
-            ASSERT_FALSE(status.isOk());
-            continue;
-        }
-
         ASSERT_TRUE(status.isOk());
         EXPECT_GE(delta, kBuffersToHold);
 
diff --git a/automotive/remoteaccess/Android.bp b/automotive/remoteaccess/Android.bp
index 7cd6f60..e1e9041 100644
--- a/automotive/remoteaccess/Android.bp
+++ b/automotive/remoteaccess/Android.bp
@@ -42,6 +42,5 @@
             imports: [],
         },
     ],
-    frozen: true,
-
+    frozen: false,
 }
diff --git a/automotive/remoteaccess/aidl_api/android.hardware.automotive.remoteaccess/current/android/hardware/automotive/remoteaccess/IRemoteAccess.aidl b/automotive/remoteaccess/aidl_api/android.hardware.automotive.remoteaccess/current/android/hardware/automotive/remoteaccess/IRemoteAccess.aidl
index b0935c2..5c5917b 100644
--- a/automotive/remoteaccess/aidl_api/android.hardware.automotive.remoteaccess/current/android/hardware/automotive/remoteaccess/IRemoteAccess.aidl
+++ b/automotive/remoteaccess/aidl_api/android.hardware.automotive.remoteaccess/current/android/hardware/automotive/remoteaccess/IRemoteAccess.aidl
@@ -40,4 +40,11 @@
   void setRemoteTaskCallback(android.hardware.automotive.remoteaccess.IRemoteTaskCallback callback);
   void clearRemoteTaskCallback();
   void notifyApStateChange(in android.hardware.automotive.remoteaccess.ApState state);
+  boolean isTaskScheduleSupported();
+  android.hardware.automotive.remoteaccess.TaskType[] getSupportedTaskTypesForScheduling();
+  void scheduleTask(in android.hardware.automotive.remoteaccess.ScheduleInfo scheduleInfo);
+  void unscheduleTask(String clientId, String scheduleId);
+  void unscheduleAllTasks(String clientId);
+  boolean isTaskScheduled(String clientId, String scheduleId);
+  List<android.hardware.automotive.remoteaccess.ScheduleInfo> getAllPendingScheduledTasks(String clientId);
 }
diff --git a/automotive/remoteaccess/aidl_api/android.hardware.automotive.remoteaccess/current/android/hardware/automotive/remoteaccess/ScheduleInfo.aidl b/automotive/remoteaccess/aidl_api/android.hardware.automotive.remoteaccess/current/android/hardware/automotive/remoteaccess/ScheduleInfo.aidl
new file mode 100644
index 0000000..ec8733a
--- /dev/null
+++ b/automotive/remoteaccess/aidl_api/android.hardware.automotive.remoteaccess/current/android/hardware/automotive/remoteaccess/ScheduleInfo.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.remoteaccess;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable ScheduleInfo {
+  String clientId;
+  String scheduleId;
+  android.hardware.automotive.remoteaccess.TaskType taskType;
+  byte[] taskData;
+  int count;
+  long startTimeInEpochSeconds;
+  long periodicInSeconds;
+  const int MAX_TASK_DATA_SIZE_IN_BYTES = 10240;
+}
diff --git a/automotive/remoteaccess/aidl_api/android.hardware.automotive.remoteaccess/current/android/hardware/automotive/remoteaccess/TaskType.aidl b/automotive/remoteaccess/aidl_api/android.hardware.automotive.remoteaccess/current/android/hardware/automotive/remoteaccess/TaskType.aidl
new file mode 100644
index 0000000..da70626
--- /dev/null
+++ b/automotive/remoteaccess/aidl_api/android.hardware.automotive.remoteaccess/current/android/hardware/automotive/remoteaccess/TaskType.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.remoteaccess;
+@Backing(type="int") @VintfStability
+enum TaskType {
+  CUSTOM = 0,
+  ENTER_GARAGE_MODE = 1,
+}
diff --git a/automotive/remoteaccess/android/hardware/automotive/remoteaccess/IRemoteAccess.aidl b/automotive/remoteaccess/android/hardware/automotive/remoteaccess/IRemoteAccess.aidl
index 0f4125f..f0468c4 100644
--- a/automotive/remoteaccess/android/hardware/automotive/remoteaccess/IRemoteAccess.aidl
+++ b/automotive/remoteaccess/android/hardware/automotive/remoteaccess/IRemoteAccess.aidl
@@ -18,12 +18,40 @@
 
 import android.hardware.automotive.remoteaccess.ApState;
 import android.hardware.automotive.remoteaccess.IRemoteTaskCallback;
+import android.hardware.automotive.remoteaccess.ScheduleInfo;
+import android.hardware.automotive.remoteaccess.TaskType;
 
 /**
- * Interface representing a remote wakeup client.
+ * The remote access HAL.
  *
- * A wakeup client is a binary outside Android framework that communicates with
- * a wakeup server and receives wake up command.
+ * <p>This HAL represents an external system that is always on even when Android
+ * is powered off. It is capable of wakeing up and notifying Android when a
+ * remote task arrives.
+ *
+ * <p>For cloud-based remote access, a cloud server will issue the remote task
+ * to the external system, which will then be forwarded to Android. The client
+ * is expected to call {@code setRemoteTaskCallback} to register the remote
+ * task callback and uses the information returned from {@code getVehicleId},
+ * {@code getWakeupServiceName} and {@code getProcessorId} to register with
+ * a remote server.
+ *
+ * <p>For serverless remote access, the remote task comes from the external
+ * system alone and no server is involved. The external system may support
+ * scheduling a remote task to executed later through {@code scheduleTask}.
+ *
+ * <p>For both cloud-based and serverless remote access, the ideal use case
+ * is to wake up Android when the vehicle is not in use and then shutdown
+ * Android after the task is complete. However, user may access the vehicle
+ * during this period, and Android must not be shutdown if this happens.
+ *
+ * <p>If this interface is implemented, then VHAL property
+ * {@code VEHICLE_IN_USE} must be supported to represent whether the vehicle is
+ * currently in use. Android will check this before sending the shutdown
+ * request.
+ *
+ * <p>The external power controller system must also check whether vehicle is
+ * in use upon receiving the shutdown request and makes sure that an
+ * user-unexpected shutdown must not happen.
  */
 @VintfStability
 interface IRemoteAccess {
@@ -96,4 +124,85 @@
      * <p>If {@code isWakeupRequired} is false, it must not try to wake up AP.
      */
     void notifyApStateChange(in ApState state);
+
+    /**
+     * Returns whether task scheduling is supported.
+     *
+     * <p>If this returns {@code true}, user may use {@link scheduleTask} to schedule a task to be
+     * executed at a later time. If the device is off when the task is scheduled to be executed,
+     * the device will be woken up to execute the task.
+     *
+     * @return {@code true} if serverless remote task scheduling is supported.
+     */
+    boolean isTaskScheduleSupported();
+
+    /**
+     * Returns the supported task types for scheduling.
+     *
+     * <p>If task scheduling is not supported, this returns an empty array.
+     *
+     * <p>Otherwise, at least {@code TaskType.CUSTOM} must be supported.
+     *
+     * @return An array of supported task types.
+     */
+    TaskType[] getSupportedTaskTypesForScheduling();
+
+    /**
+     * Schedules a task to be executed later even when the vehicle is off.
+     *
+     * <p>If {@link isTaskScheduleSupported} returns {@code false}. This is no-op.
+     *
+     * <p>This sends a scheduled task message to a device external to Android so that the device
+     * can wake up Android and deliver the task through {@link IRemoteTaskCallback}.
+     *
+     * <p>Note that the scheduled task execution is on a best-effort basis. Multiple situations
+     * might cause the task not to execute successfully:
+     *
+     * <ul>
+     * <li>The vehicle is low on battery and the other device decides not to wake up Android.
+     * <li>User turns off vehicle while the task is executing.
+     * <li>The task logic itself fails.
+     *
+     * <p>Must return {@code EX_ILLEGAL_ARGUMENT} if a pending schedule with the same
+     * {@code scheduleId} for this client exists.
+     *
+     * <p>Must return {@code EX_ILLEGAL_ARGUMENT} if the task type is not supported.
+     *
+     * <p>Must return {@code EX_ILLEGLA_ARGUMENT} if the scheduleInfo is not valid (e.g. count is
+     * a negative number).
+     */
+    void scheduleTask(in ScheduleInfo scheduleInfo);
+
+    /**
+     * Unschedules a scheduled task.
+     *
+     * <p>If {@link isTaskScheduleSupported} returns {@code false}. This is no-op.
+     *
+     * <p>Does nothing if a pending schedule with {@code clientId} and {@code scheduleId} does not
+     * exist.
+     */
+    void unscheduleTask(String clientId, String scheduleId);
+
+    /**
+     * Unschedules all scheduled tasks for the client.
+     *
+     * <p>If {@link isTaskScheduleSupported} returns {@code false}. This is no-op.
+     */
+    void unscheduleAllTasks(String clientId);
+
+    /**
+     * Returns whether the specified task is scheduled.
+     *
+     * <p>If {@link isTaskScheduleSupported} returns {@code false}, This must return {@code false}.
+     */
+    boolean isTaskScheduled(String clientId, String scheduleId);
+
+    /**
+     * Gets all pending scheduled tasks for the client.
+     *
+     * <p>If {@link isTaskScheduleSupported} returns {@code false}. This must return empty array.
+     *
+     * <p>The finished scheduled tasks will not be included.
+     */
+    List<ScheduleInfo> getAllPendingScheduledTasks(String clientId);
 }
diff --git a/automotive/remoteaccess/android/hardware/automotive/remoteaccess/IRemoteTaskCallback.aidl b/automotive/remoteaccess/android/hardware/automotive/remoteaccess/IRemoteTaskCallback.aidl
index 2cd7a5d..ee6f900 100644
--- a/automotive/remoteaccess/android/hardware/automotive/remoteaccess/IRemoteTaskCallback.aidl
+++ b/automotive/remoteaccess/android/hardware/automotive/remoteaccess/IRemoteTaskCallback.aidl
@@ -22,7 +22,7 @@
 @VintfStability
 interface IRemoteTaskCallback {
     /**
-     * A callback that is called when a remote task is requested.
+     * A callback that is called when a custom type remote task is requested.
      *
      * The data is passed down from the remote server to the remote task client
      * which is an Android application, and is not interpreted/parsed by the
diff --git a/automotive/remoteaccess/android/hardware/automotive/remoteaccess/ScheduleInfo.aidl b/automotive/remoteaccess/android/hardware/automotive/remoteaccess/ScheduleInfo.aidl
new file mode 100644
index 0000000..4f2537c
--- /dev/null
+++ b/automotive/remoteaccess/android/hardware/automotive/remoteaccess/ScheduleInfo.aidl
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.remoteaccess;
+
+import android.hardware.automotive.remoteaccess.TaskType;
+
+@VintfStability
+@JavaDerive(equals=true, toString=true)
+parcelable ScheduleInfo {
+    const int MAX_TASK_DATA_SIZE_IN_BYTES = 10240;
+    /**
+     * The ID used to identify the client this schedule is for. This must be one of the
+     * preconfigured remote access serverless client ID defined in car service resource
+     * {@code R.xml.remote_access_serverless_client_map}.
+     */
+    String clientId;
+    /**
+     * A unique scheduling ID (among the same client). Adding a new schedule info with a duplicate
+     * scheduleId will return {@code EX_ILLEGAL_ARGUMENT}.
+     */
+    String scheduleId;
+    /**
+     * The type for the task.
+     */
+    TaskType taskType;
+    /**
+     * The opaque task data that will be sent back to the remote task client app when the task is
+     * executed. It is not interpreted/parsed by the Android system.
+     *
+     * <p>This is only used for {@code TaskType.CUSTOM}.
+     *
+     * <p>The data size must be less than {@link MAX_TASK_DATA_SIZE_IN_BYTES}.
+     */
+    byte[] taskData;
+    /**
+     * How many times this task will be executed. 0 means infinite.
+     *
+     * <p>This must be >= 0.
+     */
+    int count;
+    /**
+     * The start time in epoch seconds.
+     *
+     * <p>The external device issuing remote task must have a clock synced with the
+     * {@code System.currentTimeMillis()} used in Android system.
+     *
+     * <p>Optionally, the VHAL property {@code EPOCH_TIME} can be used to sync the time.
+     *
+     * <p>This must be >= 0.
+     */
+    long startTimeInEpochSeconds;
+    /**
+     * The interval (in seconds) between scheduled task execution.
+     *
+     * <p>This must be >=0. This is not useful when {@code count} is 1. If this is 0,
+     * The tasks will be delivered multiple times with no interval in between.
+     */
+    long periodicInSeconds;
+}
diff --git a/automotive/remoteaccess/android/hardware/automotive/remoteaccess/TaskType.aidl b/automotive/remoteaccess/android/hardware/automotive/remoteaccess/TaskType.aidl
new file mode 100644
index 0000000..761eb15
--- /dev/null
+++ b/automotive/remoteaccess/android/hardware/automotive/remoteaccess/TaskType.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.remoteaccess;
+
+@VintfStability
+@Backing(type="int")
+enum TaskType {
+    /**
+     * A custom task that is opaque to anyone other than the remote task client app.
+     *
+     * <p>The opaque task data in the {@code ScheduleInfo} will be sent back to the app when the
+     * task is to be executed.
+     */
+    CUSTOM = 0,
+    /**
+     * Enters the garage mode if allowed.
+     *
+     * <p>Make the Android system enters garage mode if vehicle is currently not in use and
+     * entering garage mode is allowed (e.g. battery level is high enough).
+     *
+     * <p>This is based on best-effort and it is not guaranteed.
+     *
+     * <p>If allowed, the external system should set {@code AP_POWER_BOOTUP_REASON} to
+     * {@code SYSTEM_ENTER_GARAGE_MODE} and then boot up (or resume) the head unit.
+     */
+    ENTER_GARAGE_MODE = 1,
+}
diff --git a/automotive/remoteaccess/hal/default/Android.bp b/automotive/remoteaccess/hal/default/Android.bp
index 0155667..be6a425 100644
--- a/automotive/remoteaccess/hal/default/Android.bp
+++ b/automotive/remoteaccess/hal/default/Android.bp
@@ -48,17 +48,19 @@
 }
 
 cc_binary {
-    name: "android.hardware.automotive.remoteaccess@V1-default-service",
+    name: "android.hardware.automotive.remoteaccess@V2-default-service",
     defaults: ["remote-access-hal-defaults"],
     vintf_fragments: ["remoteaccess-default-service.xml"],
     init_rc: ["remoteaccess-default-service.rc"],
     cflags: [
-        "-DGRPC_SERVICE_ADDRESS=\"localhost:50051\"",
+        // Uncomment this if running on emulator and connecting to a local grpc server
+        // running on host 127.0.0.1:50051 (TestWakeupClientServerHost)
+        // "-DGRPC_SERVICE_ADDRESS=\"10.0.2.2:50051\"",
     ],
 }
 
 cc_binary {
-    name: "android.hardware.automotive.remoteaccess@V1-tcu-test-service",
+    name: "android.hardware.automotive.remoteaccess@V2-tcu-test-service",
     defaults: ["remote-access-hal-defaults"],
     vintf_fragments: ["remoteaccess-default-service.xml"],
     init_rc: ["remoteaccess-tcu-test-service.rc"],
@@ -77,7 +79,7 @@
         "src/RemoteAccessService.cpp",
     ],
     whole_static_libs: [
-        "android.hardware.automotive.remoteaccess-V1-ndk",
+        "android.hardware.automotive.remoteaccess-V2-ndk",
         "wakeup_client_protos",
         "libvhalclient",
     ],
@@ -99,7 +101,7 @@
 }
 
 cc_fuzz {
-    name: "android.hardware.automotive.remoteaccess@V1-default-service.aidl_fuzzer",
+    name: "android.hardware.automotive.remoteaccess@V2-default-service.aidl_fuzzer",
     srcs: ["fuzzer/fuzzer.cpp"],
     whole_static_libs: [
         "RemoteAccessService",
diff --git a/automotive/remoteaccess/hal/default/fuzzer/fuzzer.cpp b/automotive/remoteaccess/hal/default/fuzzer/fuzzer.cpp
index 292c80e..7707ee6 100644
--- a/automotive/remoteaccess/hal/default/fuzzer/fuzzer.cpp
+++ b/automotive/remoteaccess/hal/default/fuzzer/fuzzer.cpp
@@ -55,6 +55,32 @@
         return Status::OK;
     }
 
+    Status ScheduleTask(ClientContext* context, const ScheduleTaskRequest& request,
+                        ScheduleTaskResponse* response) {
+        return Status::OK;
+    }
+
+    Status UnscheduleTask(ClientContext* context, const UnscheduleTaskRequest& request,
+                          UnscheduleTaskResponse* response) {
+        return Status::OK;
+    }
+
+    Status UnscheduleAllTasks(ClientContext* context, const UnscheduleAllTasksRequest& request,
+                              UnscheduleAllTasksResponse* response) {
+        return Status::OK;
+    }
+
+    Status IsTaskScheduled(ClientContext* context, const IsTaskScheduledRequest& request,
+                           IsTaskScheduledResponse* response) {
+        return Status::OK;
+    }
+
+    Status GetAllPendingScheduledTasks(ClientContext* context,
+                                       const GetAllPendingScheduledTasksRequest& request,
+                                       GetAllPendingScheduledTasksResponse* response) {
+        return Status::OK;
+    }
+
     // Async methods which we do not care.
     ClientAsyncReaderInterface<GetRemoteTasksResponse>* AsyncGetRemoteTasksRaw(
             [[maybe_unused]] ClientContext* context,
@@ -83,6 +109,78 @@
                                         [[maybe_unused]] CompletionQueue* c) {
         return nullptr;
     }
+
+    ClientAsyncResponseReaderInterface<ScheduleTaskResponse>* AsyncScheduleTaskRaw(
+            [[maybe_unused]] ClientContext* context,
+            [[maybe_unused]] const ScheduleTaskRequest& request,
+            [[maybe_unused]] CompletionQueue* cq) {
+        return nullptr;
+    }
+
+    ClientAsyncResponseReaderInterface<ScheduleTaskResponse>* PrepareAsyncScheduleTaskRaw(
+            [[maybe_unused]] ClientContext* context,
+            [[maybe_unused]] const ScheduleTaskRequest& request,
+            [[maybe_unused]] CompletionQueue* c) {
+        return nullptr;
+    }
+
+    ClientAsyncResponseReaderInterface<UnscheduleTaskResponse>* AsyncUnscheduleTaskRaw(
+            [[maybe_unused]] ClientContext* context,
+            [[maybe_unused]] const UnscheduleTaskRequest& request,
+            [[maybe_unused]] CompletionQueue* cq) {
+        return nullptr;
+    }
+
+    ClientAsyncResponseReaderInterface<UnscheduleTaskResponse>* PrepareAsyncUnscheduleTaskRaw(
+            [[maybe_unused]] ClientContext* context,
+            [[maybe_unused]] const UnscheduleTaskRequest& request,
+            [[maybe_unused]] CompletionQueue* c) {
+        return nullptr;
+    }
+
+    ClientAsyncResponseReaderInterface<UnscheduleAllTasksResponse>* AsyncUnscheduleAllTasksRaw(
+            [[maybe_unused]] ClientContext* context,
+            [[maybe_unused]] const UnscheduleAllTasksRequest& request,
+            [[maybe_unused]] CompletionQueue* cq) {
+        return nullptr;
+    }
+
+    ClientAsyncResponseReaderInterface<UnscheduleAllTasksResponse>*
+    PrepareAsyncUnscheduleAllTasksRaw([[maybe_unused]] ClientContext* context,
+                                      [[maybe_unused]] const UnscheduleAllTasksRequest& request,
+                                      [[maybe_unused]] CompletionQueue* c) {
+        return nullptr;
+    }
+
+    ClientAsyncResponseReaderInterface<IsTaskScheduledResponse>* AsyncIsTaskScheduledRaw(
+            [[maybe_unused]] ClientContext* context,
+            [[maybe_unused]] const IsTaskScheduledRequest& request,
+            [[maybe_unused]] CompletionQueue* cq) {
+        return nullptr;
+    }
+
+    ClientAsyncResponseReaderInterface<IsTaskScheduledResponse>* PrepareAsyncIsTaskScheduledRaw(
+            [[maybe_unused]] ClientContext* context,
+            [[maybe_unused]] const IsTaskScheduledRequest& request,
+            [[maybe_unused]] CompletionQueue* c) {
+        return nullptr;
+    }
+
+    ClientAsyncResponseReaderInterface<GetAllPendingScheduledTasksResponse>*
+    AsyncGetAllPendingScheduledTasksRaw(
+            [[maybe_unused]] ClientContext* context,
+            [[maybe_unused]] const GetAllPendingScheduledTasksRequest& request,
+            [[maybe_unused]] CompletionQueue* cq) {
+        return nullptr;
+    }
+
+    ClientAsyncResponseReaderInterface<GetAllPendingScheduledTasksResponse>*
+    PrepareAsyncGetAllPendingScheduledTasksRaw(
+            [[maybe_unused]] ClientContext* context,
+            [[maybe_unused]] const GetAllPendingScheduledTasksRequest& request,
+            [[maybe_unused]] CompletionQueue* c) {
+        return nullptr;
+    }
 };
 
 }  // namespace remoteaccess
diff --git a/automotive/remoteaccess/hal/default/include/RemoteAccessService.h b/automotive/remoteaccess/hal/default/include/RemoteAccessService.h
index b18986a..8716e48 100644
--- a/automotive/remoteaccess/hal/default/include/RemoteAccessService.h
+++ b/automotive/remoteaccess/hal/default/include/RemoteAccessService.h
@@ -21,6 +21,7 @@
 #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 <aidl/android/hardware/automotive/remoteaccess/ScheduleInfo.h>
 #include <android-base/thread_annotations.h>
 #include <android/binder_auto_utils.h>
 #include <utils/SystemClock.h>
@@ -78,6 +79,28 @@
     ndk::ScopedAStatus notifyApStateChange(
             const aidl::android::hardware::automotive::remoteaccess::ApState& newState) override;
 
+    ndk::ScopedAStatus isTaskScheduleSupported(bool* out) override;
+
+    ndk::ScopedAStatus getSupportedTaskTypesForScheduling(
+            std::vector<aidl::android::hardware::automotive::remoteaccess::TaskType>* out) override;
+
+    ndk::ScopedAStatus scheduleTask(
+            const aidl::android::hardware::automotive::remoteaccess::ScheduleInfo& scheduleInfo)
+            override;
+
+    ndk::ScopedAStatus unscheduleTask(const std::string& clientId,
+                                      const std::string& scheduleId) override;
+
+    ndk::ScopedAStatus unscheduleAllTasks(const std::string& clientId) override;
+
+    ndk::ScopedAStatus isTaskScheduled(const std::string& clientId, const std::string& scheduleId,
+                                       bool* out) override;
+
+    ndk::ScopedAStatus getAllPendingScheduledTasks(
+            const std::string& clientId,
+            std::vector<aidl::android::hardware::automotive::remoteaccess::ScheduleInfo>* out)
+            override;
+
     binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
 
   private:
@@ -88,6 +111,8 @@
 
     WakeupClient::StubInterface* mGrpcStub;
     std::thread mThread;
+    // Whether the GRPC server exists. Only checked and set during init.
+    bool mGrpcServerExist = false;
     std::mutex mLock;
     std::condition_variable mCv;
     std::shared_ptr<aidl::android::hardware::automotive::remoteaccess::IRemoteTaskCallback>
@@ -98,7 +123,7 @@
     // A mutex to make sure startTaskLoop does not overlap with stopTaskLoop.
     std::mutex mStartStopTaskLoopLock;
     bool mTaskLoopRunning GUARDED_BY(mStartStopTaskLoopLock) = false;
-    bool mGrpcConnected GUARDED_BY(mLock) = false;
+    bool mGrpcReadChannelOpen GUARDED_BY(mLock) = false;
     std::unordered_map<std::string, size_t> mClientIdToTaskCount GUARDED_BY(mLock);
 
     // Default wait time before retry connecting to remote access client is 10s.
@@ -120,9 +145,10 @@
     void debugInjectTask(int fd, std::string_view clientId, std::string_view taskData);
     void debugInjectTaskNextReboot(int fd, std::string_view clientId, std::string_view taskData,
                                    const char* latencyInSecStr);
-    void updateGrpcConnected(bool connected);
+    void updateGrpcReadChannelOpen(bool grpcReadChannelOpen);
     android::base::Result<void> deliverRemoteTaskThroughCallback(const std::string& clientId,
                                                                  std::string_view taskData);
+    bool isTaskScheduleSupported();
 };
 
 }  // namespace remoteaccess
diff --git a/automotive/remoteaccess/hal/default/proto/wakeup_client.proto b/automotive/remoteaccess/hal/default/proto/wakeup_client.proto
index 4fe0d01..14ba0a5 100644
--- a/automotive/remoteaccess/hal/default/proto/wakeup_client.proto
+++ b/automotive/remoteaccess/hal/default/proto/wakeup_client.proto
@@ -18,6 +18,12 @@
 
 package android.hardware.automotive.remoteaccess;
 
+enum ErrorCode {
+    OK = 0;
+    UNSPECIFIED = 1;
+    INVALID_ARG = 2;
+}
+
 /**
  * Service provided by a wakeup client running on TCU.
  */
@@ -50,6 +56,51 @@
      * to wake up AP.
      */
     rpc NotifyWakeupRequired(NotifyWakeupRequiredRequest) returns (NotifyWakeupRequiredResponse) {}
+
+    /**
+     * Schedules a task to be executed later even when the vehicle is off.
+     *
+     * <p>This sends a scheduled task message to a device external to Android so that the device
+     * can wake up Android and deliver the task through {@link IRemoteTaskCallback}.
+     *
+     * <p>Note that the scheduled task execution is on a best-effort basis. Multiple situations
+     * might cause the task not to execute successfully:
+     *
+     * <ul>
+     * <li>The vehicle is low on battery and the other device decides not to wake up Android.
+     * <li>User turns off vehicle while the task is executing.
+     * <li>The task logic itself fails.
+     *
+     * <p>Must return a response with error code: {@code INVALID_ARG} if a pending schedule with the
+     * same {@code scheduleId} for this client exists.
+     */
+    rpc ScheduleTask(ScheduleTaskRequest) returns (ScheduleTaskResponse) {}
+
+    /**
+     * Unschedules a scheduled task.
+     *
+     * <p>Does nothing if a pending schedule with {@code clientId} and {@code scheduleId} does not
+     * exist.
+     */
+    rpc UnscheduleTask(UnscheduleTaskRequest) returns (UnscheduleTaskResponse) {}
+
+    /**
+     * Unschedules all scheduled tasks for the client.
+     */
+    rpc UnscheduleAllTasks(UnscheduleAllTasksRequest) returns (UnscheduleAllTasksResponse) {}
+
+    /**
+     * Returns whether the specified task is scheduled.
+     */
+    rpc IsTaskScheduled(IsTaskScheduledRequest) returns (IsTaskScheduledResponse) {}
+
+    /**
+     * Gets all pending scheduled tasks for the client.
+     *
+     * <p>The finished scheduled tasks will not be included.
+     */
+    rpc GetAllPendingScheduledTasks(GetAllPendingScheduledTasksRequest)
+            returns (GetAllPendingScheduledTasksResponse) {}
 }
 
 message GetRemoteTasksRequest {}
@@ -64,3 +115,50 @@
 }
 
 message NotifyWakeupRequiredResponse {}
+
+message ScheduleTaskRequest {
+    GrpcScheduleInfo scheduleInfo = 1;
+}
+
+message ScheduleTaskResponse {
+    ErrorCode errorCode = 1;
+}
+
+message GrpcScheduleInfo {
+    string clientId = 1;
+    string scheduleId = 2;
+    bytes data = 3;
+    int32 count = 4;
+    int64 startTimeInEpochSeconds = 5;
+    int64 periodicInSeconds = 6;
+}
+
+message UnscheduleTaskRequest {
+    string clientId = 1;
+    string scheduleId = 2;
+}
+
+message UnscheduleTaskResponse {}
+
+message UnscheduleAllTasksRequest {
+    string clientId = 1;
+}
+
+message UnscheduleAllTasksResponse {}
+
+message IsTaskScheduledRequest {
+    string clientId = 1;
+    string scheduleId = 2;
+}
+
+message IsTaskScheduledResponse {
+    bool isTaskScheduled = 1;
+}
+
+message GetAllPendingScheduledTasksRequest {
+    string clientId = 1;
+}
+
+message GetAllPendingScheduledTasksResponse {
+    repeated GrpcScheduleInfo allScheduledTasks = 1;
+}
diff --git a/automotive/remoteaccess/hal/default/remoteaccess-default-service.rc b/automotive/remoteaccess/hal/default/remoteaccess-default-service.rc
index b7a9cdc..c9b282c 100644
--- a/automotive/remoteaccess/hal/default/remoteaccess-default-service.rc
+++ b/automotive/remoteaccess/hal/default/remoteaccess-default-service.rc
@@ -1,4 +1,4 @@
-service vendor.remoteaccess-default /vendor/bin/hw/android.hardware.automotive.remoteaccess@V1-default-service
+service vendor.remoteaccess-default /vendor/bin/hw/android.hardware.automotive.remoteaccess@V2-default-service
     class hal
     user vehicle_network
     group system inet
diff --git a/automotive/remoteaccess/hal/default/remoteaccess-default-service.xml b/automotive/remoteaccess/hal/default/remoteaccess-default-service.xml
index d050a1b..44ac309 100644
--- a/automotive/remoteaccess/hal/default/remoteaccess-default-service.xml
+++ b/automotive/remoteaccess/hal/default/remoteaccess-default-service.xml
@@ -1,7 +1,7 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.automotive.remoteaccess</name>
-        <version>1</version>
+        <version>2</version>
         <fqname>IRemoteAccess/default</fqname>
     </hal>
 </manifest>
diff --git a/automotive/remoteaccess/hal/default/remoteaccess-tcu-test-service.rc b/automotive/remoteaccess/hal/default/remoteaccess-tcu-test-service.rc
index 59315eb..19faaf4 100644
--- a/automotive/remoteaccess/hal/default/remoteaccess-tcu-test-service.rc
+++ b/automotive/remoteaccess/hal/default/remoteaccess-tcu-test-service.rc
@@ -1,4 +1,4 @@
-service vendor.remoteaccess-default /vendor/bin/hw/android.hardware.automotive.remoteaccess@V1-tcu-test-service
+service vendor.remoteaccess-default /vendor/bin/hw/android.hardware.automotive.remoteaccess@V2-tcu-test-service
     class hal
     user vehicle_network
     group system inet
diff --git a/automotive/remoteaccess/hal/default/src/RemoteAccessImpl.cpp b/automotive/remoteaccess/hal/default/src/RemoteAccessImpl.cpp
index b091162..28c5cd5 100644
--- a/automotive/remoteaccess/hal/default/src/RemoteAccessImpl.cpp
+++ b/automotive/remoteaccess/hal/default/src/RemoteAccessImpl.cpp
@@ -30,12 +30,11 @@
 constexpr char SERVICE_NAME[] = "android.hardware.automotive.remoteaccess.IRemoteAccess/default";
 
 int main(int /* argc */, char* /* argv */[]) {
-    LOG(INFO) << "Registering RemoteAccessService as service...";
+    android::hardware::automotive::remoteaccess::WakeupClient::StubInterface* grpcStub = nullptr;
 
-#ifndef GRPC_SERVICE_ADDRESS
-    LOG(ERROR) << "GRPC_SERVICE_ADDRESS is not defined, exiting";
-    exit(1);
-#endif
+#ifdef GRPC_SERVICE_ADDRESS
+    LOG(INFO) << "Registering RemoteAccessService as service, server: " << GRPC_SERVICE_ADDRESS
+              << "...";
     grpc::ChannelArguments grpcargs = {};
 
 #ifdef GRPC_SERVICE_IFNAME
@@ -47,12 +46,18 @@
     android::netdevice::waitFor({GRPC_SERVICE_IFNAME},
                                 android::netdevice::WaitCondition::PRESENT_AND_UP);
     LOG(INFO) << "Waiting for interface: " << GRPC_SERVICE_IFNAME << " done";
-#endif
-    auto channel = grpc::CreateCustomChannel(GRPC_SERVICE_ADDRESS,
-                                             grpc::InsecureChannelCredentials(), grpcargs);
+#endif  // #ifdef GRPC_SERVICE_IFNAME
+    auto channel = grpc::CreateChannel(GRPC_SERVICE_ADDRESS, grpc::InsecureChannelCredentials());
     auto clientStub = android::hardware::automotive::remoteaccess::WakeupClient::NewStub(channel);
+
+    grpcStub = clientStub.get();
+
+#else
+    LOG(INFO) << "GRPC_SERVICE_ADDRESS is not defined, work in fake mode";
+#endif  // #ifdef GRPC_SERVICE_ADDRESS
+
     auto service = ndk::SharedRefBase::make<
-            android::hardware::automotive::remoteaccess::RemoteAccessService>(clientStub.get());
+            android::hardware::automotive::remoteaccess::RemoteAccessService>(grpcStub);
 
     binder_exception_t err = AServiceManager_addService(service->asBinder().get(), SERVICE_NAME);
     if (err != EX_NONE) {
diff --git a/automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp b/automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp
index 5081ac0..dbd5bed 100644
--- a/automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp
+++ b/automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp
@@ -39,6 +39,8 @@
 
 using ::aidl::android::hardware::automotive::remoteaccess::ApState;
 using ::aidl::android::hardware::automotive::remoteaccess::IRemoteTaskCallback;
+using ::aidl::android::hardware::automotive::remoteaccess::ScheduleInfo;
+using ::aidl::android::hardware::automotive::remoteaccess::TaskType;
 using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
 using ::android::base::Error;
 using ::android::base::ParseInt;
@@ -101,6 +103,10 @@
 
 RemoteAccessService::RemoteAccessService(WakeupClient::StubInterface* grpcStub)
     : mGrpcStub(grpcStub) {
+    if (mGrpcStub != nullptr) {
+        mGrpcServerExist = true;
+    }
+
     std::ifstream debugTaskFile;
     debugTaskFile.open(DEBUG_TASK_FILE, std::ios::in);
     if (!debugTaskFile.is_open()) {
@@ -175,9 +181,9 @@
     mTaskLoopRunning = false;
 }
 
-void RemoteAccessService::updateGrpcConnected(bool connected) {
+void RemoteAccessService::updateGrpcReadChannelOpen(bool grpcReadChannelOpen) {
     std::lock_guard<std::mutex> lockGuard(mLock);
-    mGrpcConnected = connected;
+    mGrpcReadChannelOpen = grpcReadChannelOpen;
 }
 
 Result<void> RemoteAccessService::deliverRemoteTaskThroughCallback(const std::string& clientId,
@@ -211,7 +217,7 @@
             mGetRemoteTasksContext.reset(new ClientContext());
             reader = mGrpcStub->GetRemoteTasks(mGetRemoteTasksContext.get(), request);
         }
-        updateGrpcConnected(true);
+        updateGrpcReadChannelOpen(true);
         GetRemoteTasksResponse response;
         while (reader->Read(&response)) {
             ALOGI("Receiving one task from remote task client");
@@ -223,7 +229,7 @@
                 continue;
             }
         }
-        updateGrpcConnected(false);
+        updateGrpcReadChannelOpen(false);
         Status status = reader->Finish();
         mGetRemoteTasksContext.reset();
 
@@ -296,6 +302,11 @@
 }
 
 ScopedAStatus RemoteAccessService::notifyApStateChange(const ApState& newState) {
+    if (!mGrpcServerExist) {
+        ALOGW("GRPC server does not exist, do nothing");
+        return ScopedAStatus::ok();
+    }
+
     ClientContext context;
     NotifyWakeupRequiredRequest request = {};
     request.set_iswakeuprequired(newState.isWakeupRequired);
@@ -313,6 +324,178 @@
     return ScopedAStatus::ok();
 }
 
+bool RemoteAccessService::isTaskScheduleSupported() {
+    if (!mGrpcServerExist) {
+        ALOGW("GRPC server does not exist, task scheduling not supported");
+        return false;
+    }
+
+    return true;
+}
+
+ScopedAStatus RemoteAccessService::isTaskScheduleSupported(bool* out) {
+    *out = isTaskScheduleSupported();
+    return ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RemoteAccessService::getSupportedTaskTypesForScheduling(
+        std::vector<TaskType>* out) {
+    out->clear();
+    if (!isTaskScheduleSupported()) {
+        ALOGW("Task scheduleing is not supported, return empty task types");
+        return ScopedAStatus::ok();
+    }
+
+    // TODO(b/316233421): support ENTER_GARAGE_MODE type.
+    out->push_back(TaskType::CUSTOM);
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus RemoteAccessService::scheduleTask(const ScheduleInfo& scheduleInfo) {
+    if (!isTaskScheduleSupported()) {
+        ALOGW("Task scheduleing is not supported, return exception");
+        return ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                           "task scheduling is not supported");
+    }
+
+    ClientContext context;
+    ScheduleTaskRequest request = {};
+    ScheduleTaskResponse response = {};
+
+    if (scheduleInfo.count < 0) {
+        return ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                           "count must be >= 0");
+    }
+    if (scheduleInfo.startTimeInEpochSeconds < 0) {
+        return ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                           "startTimeInEpochSeconds must be >= 0");
+    }
+    if (scheduleInfo.periodicInSeconds < 0) {
+        return ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                           "periodicInSeconds must be >= 0");
+    }
+    if (scheduleInfo.taskData.size() > scheduleInfo.MAX_TASK_DATA_SIZE_IN_BYTES) {
+        return ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                           "task data too big");
+    }
+
+    request.mutable_scheduleinfo()->set_clientid(scheduleInfo.clientId);
+    request.mutable_scheduleinfo()->set_scheduleid(scheduleInfo.scheduleId);
+    request.mutable_scheduleinfo()->set_data(scheduleInfo.taskData.data(),
+                                             scheduleInfo.taskData.size());
+    request.mutable_scheduleinfo()->set_count(scheduleInfo.count);
+    request.mutable_scheduleinfo()->set_starttimeinepochseconds(
+            scheduleInfo.startTimeInEpochSeconds);
+    request.mutable_scheduleinfo()->set_periodicinseconds(scheduleInfo.periodicInSeconds);
+    Status status = mGrpcStub->ScheduleTask(&context, request, &response);
+    if (!status.ok()) {
+        return rpcStatusToScopedAStatus(status, "Failed to call ScheduleTask");
+    }
+    int errorCode = response.errorcode();
+    switch (errorCode) {
+        case ErrorCode::OK:
+            return ScopedAStatus::ok();
+        case ErrorCode::INVALID_ARG:
+            return ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "received invalid_arg from grpc server");
+        default:
+            // Should not happen.
+            return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                    -1, ("Got unknown error code: " + ErrorCode_Name(errorCode) +
+                         " from remote access HAL")
+                                .c_str());
+    }
+}
+
+ScopedAStatus RemoteAccessService::unscheduleTask(const std::string& clientId,
+                                                  const std::string& scheduleId) {
+    if (!isTaskScheduleSupported()) {
+        ALOGW("Task scheduleing is not supported, do nothing");
+        return ScopedAStatus::ok();
+    }
+
+    ClientContext context;
+    UnscheduleTaskRequest request = {};
+    UnscheduleTaskResponse response = {};
+    request.set_clientid(clientId);
+    request.set_scheduleid(scheduleId);
+    Status status = mGrpcStub->UnscheduleTask(&context, request, &response);
+    if (!status.ok()) {
+        return rpcStatusToScopedAStatus(status, "Failed to call UnscheduleTask");
+    }
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus RemoteAccessService::unscheduleAllTasks(const std::string& clientId) {
+    if (!isTaskScheduleSupported()) {
+        ALOGW("Task scheduleing is not supported, do nothing");
+        return ScopedAStatus::ok();
+    }
+
+    ClientContext context;
+    UnscheduleAllTasksRequest request = {};
+    UnscheduleAllTasksResponse response = {};
+    request.set_clientid(clientId);
+    Status status = mGrpcStub->UnscheduleAllTasks(&context, request, &response);
+    if (!status.ok()) {
+        return rpcStatusToScopedAStatus(status, "Failed to call UnscheduleAllTasks");
+    }
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus RemoteAccessService::isTaskScheduled(const std::string& clientId,
+                                                   const std::string& scheduleId, bool* out) {
+    if (!isTaskScheduleSupported()) {
+        ALOGW("Task scheduleing is not supported, return false");
+        *out = false;
+        return ScopedAStatus::ok();
+    }
+
+    ClientContext context;
+    IsTaskScheduledRequest request = {};
+    IsTaskScheduledResponse response = {};
+    request.set_clientid(clientId);
+    request.set_scheduleid(scheduleId);
+    Status status = mGrpcStub->IsTaskScheduled(&context, request, &response);
+    if (!status.ok()) {
+        return rpcStatusToScopedAStatus(status, "Failed to call isTaskScheduled");
+    }
+    *out = response.istaskscheduled();
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus RemoteAccessService::getAllPendingScheduledTasks(const std::string& clientId,
+                                                               std::vector<ScheduleInfo>* out) {
+    if (!isTaskScheduleSupported()) {
+        ALOGW("Task scheduleing is not supported, return empty array");
+        out->clear();
+        return ScopedAStatus::ok();
+    }
+
+    ClientContext context;
+    GetAllPendingScheduledTasksRequest request = {};
+    GetAllPendingScheduledTasksResponse response = {};
+    request.set_clientid(clientId);
+    Status status = mGrpcStub->GetAllPendingScheduledTasks(&context, request, &response);
+    if (!status.ok()) {
+        return rpcStatusToScopedAStatus(status, "Failed to call isTaskScheduled");
+    }
+    out->clear();
+    for (int i = 0; i < response.allscheduledtasks_size(); i++) {
+        const GrpcScheduleInfo& rpcScheduleInfo = response.allscheduledtasks(i);
+        ScheduleInfo scheduleInfo = {
+                .clientId = rpcScheduleInfo.clientid(),
+                .scheduleId = rpcScheduleInfo.scheduleid(),
+                .taskData = stringToBytes(rpcScheduleInfo.data()),
+                .count = rpcScheduleInfo.count(),
+                .startTimeInEpochSeconds = rpcScheduleInfo.starttimeinepochseconds(),
+                .periodicInSeconds = rpcScheduleInfo.periodicinseconds(),
+        };
+        out->push_back(std::move(scheduleInfo));
+    }
+    return ScopedAStatus::ok();
+}
+
 bool RemoteAccessService::checkDumpPermission() {
     uid_t uid = AIBinder_getCallingUid();
     return uid == AID_ROOT || uid == AID_SHELL || uid == AID_SYSTEM;
@@ -429,9 +612,11 @@
     dprintf(fd,
             "\nRemoteAccess HAL status \n"
             "Remote task callback registered: %s\n"
-            "Task receiving GRPC connection established: %s\n"
+            "GRPC server exist: %s\n"
+            "GRPC read channel for receiving tasks open: %s\n"
             "Received task count by clientId: \n%s\n",
-            boolToString(mRemoteTaskCallback.get()).c_str(), boolToString(mGrpcConnected).c_str(),
+            boolToString(mRemoteTaskCallback.get()).c_str(), boolToString(mGrpcServerExist).c_str(),
+            boolToString(mGrpcReadChannelOpen).c_str(),
             clientIdToTaskCountToStringLocked().c_str());
 }
 
diff --git a/automotive/remoteaccess/hal/default/test/RemoteAccessServiceUnitTest.cpp b/automotive/remoteaccess/hal/default/test/RemoteAccessServiceUnitTest.cpp
index c5afd63..7992a50 100644
--- a/automotive/remoteaccess/hal/default/test/RemoteAccessServiceUnitTest.cpp
+++ b/automotive/remoteaccess/hal/default/test/RemoteAccessServiceUnitTest.cpp
@@ -21,6 +21,7 @@
 #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 <android/binder_status.h>
 #include <gmock/gmock.h>
 #include <grpcpp/test/mock_stream.h>
 #include <gtest/gtest.h>
@@ -46,6 +47,8 @@
 
 using ::aidl::android::hardware::automotive::remoteaccess::ApState;
 using ::aidl::android::hardware::automotive::remoteaccess::BnRemoteTaskCallback;
+using ::aidl::android::hardware::automotive::remoteaccess::ScheduleInfo;
+using ::aidl::android::hardware::automotive::remoteaccess::TaskType;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
 
 using ::grpc::ClientAsyncReaderInterface;
@@ -59,10 +62,17 @@
 using ::ndk::ScopedAStatus;
 using ::testing::_;
 using ::testing::DoAll;
+using ::testing::ElementsAre;
 using ::testing::Return;
 using ::testing::SetArgPointee;
 
 constexpr char kTestVin[] = "test_VIN";
+const std::string kTestClientId = "test client id";
+const std::string kTestScheduleId = "test schedule id";
+const std::vector<uint8_t> kTestData = {0xde, 0xad, 0xbe, 0xef};
+constexpr int32_t kTestCount = 1234;
+constexpr int64_t kTestStartTimeInEpochSeconds = 2345;
+constexpr int64_t kTestPeriodicInSeconds = 123;
 
 }  // namespace
 
@@ -73,6 +83,21 @@
     MOCK_METHOD(Status, NotifyWakeupRequired,
                 (ClientContext * context, const NotifyWakeupRequiredRequest& request,
                  NotifyWakeupRequiredResponse* response));
+    MOCK_METHOD(Status, ScheduleTask,
+                (ClientContext * context, const ScheduleTaskRequest& request,
+                 ScheduleTaskResponse* response));
+    MOCK_METHOD(Status, UnscheduleTask,
+                (ClientContext * context, const UnscheduleTaskRequest& request,
+                 UnscheduleTaskResponse* response));
+    MOCK_METHOD(Status, UnscheduleAllTasks,
+                (ClientContext * context, const UnscheduleAllTasksRequest& request,
+                 UnscheduleAllTasksResponse* response));
+    MOCK_METHOD(Status, IsTaskScheduled,
+                (ClientContext * context, const IsTaskScheduledRequest& request,
+                 IsTaskScheduledResponse* response));
+    MOCK_METHOD(Status, GetAllPendingScheduledTasks,
+                (ClientContext * context, const GetAllPendingScheduledTasksRequest& request,
+                 GetAllPendingScheduledTasksResponse* response));
     // Async methods which we do not care.
     MOCK_METHOD(ClientAsyncReaderInterface<GetRemoteTasksResponse>*, AsyncGetRemoteTasksRaw,
                 (ClientContext * context, const GetRemoteTasksRequest& request, CompletionQueue* cq,
@@ -88,6 +113,42 @@
                 PrepareAsyncNotifyWakeupRequiredRaw,
                 (ClientContext * context, const NotifyWakeupRequiredRequest& request,
                  CompletionQueue* cq));
+    MOCK_METHOD(ClientAsyncResponseReaderInterface<ScheduleTaskResponse>*, AsyncScheduleTaskRaw,
+                (ClientContext * context, const ScheduleTaskRequest& request, CompletionQueue* cq));
+    MOCK_METHOD(ClientAsyncResponseReaderInterface<ScheduleTaskResponse>*,
+                PrepareAsyncScheduleTaskRaw,
+                (ClientContext * context, const ScheduleTaskRequest& request, CompletionQueue* cq));
+    MOCK_METHOD(ClientAsyncResponseReaderInterface<UnscheduleTaskResponse>*, AsyncUnscheduleTaskRaw,
+                (ClientContext * context, const UnscheduleTaskRequest& request,
+                 CompletionQueue* cq));
+    MOCK_METHOD(ClientAsyncResponseReaderInterface<UnscheduleTaskResponse>*,
+                PrepareAsyncUnscheduleTaskRaw,
+                (ClientContext * context, const UnscheduleTaskRequest& request,
+                 CompletionQueue* cq));
+    MOCK_METHOD(ClientAsyncResponseReaderInterface<UnscheduleAllTasksResponse>*,
+                AsyncUnscheduleAllTasksRaw,
+                (ClientContext * context, const UnscheduleAllTasksRequest& request,
+                 CompletionQueue* cq));
+    MOCK_METHOD(ClientAsyncResponseReaderInterface<UnscheduleAllTasksResponse>*,
+                PrepareAsyncUnscheduleAllTasksRaw,
+                (ClientContext * context, const UnscheduleAllTasksRequest& request,
+                 CompletionQueue* cq));
+    MOCK_METHOD(ClientAsyncResponseReaderInterface<IsTaskScheduledResponse>*,
+                AsyncIsTaskScheduledRaw,
+                (ClientContext * context, const IsTaskScheduledRequest& request,
+                 CompletionQueue* cq));
+    MOCK_METHOD(ClientAsyncResponseReaderInterface<IsTaskScheduledResponse>*,
+                PrepareAsyncIsTaskScheduledRaw,
+                (ClientContext * context, const IsTaskScheduledRequest& request,
+                 CompletionQueue* cq));
+    MOCK_METHOD(ClientAsyncResponseReaderInterface<GetAllPendingScheduledTasksResponse>*,
+                AsyncGetAllPendingScheduledTasksRaw,
+                (ClientContext * context, const GetAllPendingScheduledTasksRequest& request,
+                 CompletionQueue* cq));
+    MOCK_METHOD(ClientAsyncResponseReaderInterface<GetAllPendingScheduledTasksResponse>*,
+                PrepareAsyncGetAllPendingScheduledTasksRaw,
+                (ClientContext * context, const GetAllPendingScheduledTasksRequest& request,
+                 CompletionQueue* cq));
 };
 
 class FakeVhalClient final : public android::frameworks::automotive::vhal::IVhalClient {
@@ -367,6 +428,246 @@
     ASSERT_EQ(vehicleId, kTestVin);
 }
 
+TEST_F(RemoteAccessServiceUnitTest, TestIsTaskScheduleSupported) {
+    bool out = false;
+    ScopedAStatus status = getService()->isTaskScheduleSupported(&out);
+
+    EXPECT_TRUE(status.isOk());
+    EXPECT_TRUE(out);
+}
+
+TEST_F(RemoteAccessServiceUnitTest, TestGetSupportedTaskTypesForScheduling) {
+    std::vector<TaskType> out;
+    ScopedAStatus status = getService()->getSupportedTaskTypesForScheduling(&out);
+
+    EXPECT_TRUE(status.isOk());
+    EXPECT_THAT(out, ElementsAre(TaskType::CUSTOM));
+}
+
+TEST_F(RemoteAccessServiceUnitTest, TestScheduleTask) {
+    ScheduleTaskRequest grpcRequest = {};
+    EXPECT_CALL(*getGrpcWakeupClientStub(), ScheduleTask)
+            .WillOnce([&grpcRequest]([[maybe_unused]] ClientContext* context,
+                                     const ScheduleTaskRequest& request,
+                                     [[maybe_unused]] ScheduleTaskResponse* response) {
+                grpcRequest = request;
+                return Status();
+            });
+    ScheduleInfo scheduleInfo = {
+            .clientId = kTestClientId,
+            .scheduleId = kTestScheduleId,
+            .taskData = kTestData,
+            .count = kTestCount,
+            .startTimeInEpochSeconds = kTestStartTimeInEpochSeconds,
+            .periodicInSeconds = kTestPeriodicInSeconds,
+    };
+
+    ScopedAStatus status = getService()->scheduleTask(scheduleInfo);
+
+    ASSERT_TRUE(status.isOk());
+    EXPECT_EQ(grpcRequest.scheduleinfo().clientid(), kTestClientId);
+    EXPECT_EQ(grpcRequest.scheduleinfo().scheduleid(), kTestScheduleId);
+    EXPECT_EQ(grpcRequest.scheduleinfo().data(), std::string(kTestData.begin(), kTestData.end()));
+    EXPECT_EQ(grpcRequest.scheduleinfo().count(), kTestCount);
+    EXPECT_EQ(grpcRequest.scheduleinfo().starttimeinepochseconds(), kTestStartTimeInEpochSeconds);
+    EXPECT_EQ(grpcRequest.scheduleinfo().periodicinseconds(), kTestPeriodicInSeconds);
+}
+
+TEST_F(RemoteAccessServiceUnitTest, TestScheduleTask_InvalidCount) {
+    ScheduleInfo scheduleInfo = {
+            .clientId = kTestClientId,
+            .scheduleId = kTestScheduleId,
+            .taskData = kTestData,
+            .count = -1,
+            .startTimeInEpochSeconds = kTestStartTimeInEpochSeconds,
+            .periodicInSeconds = kTestPeriodicInSeconds,
+    };
+
+    ScopedAStatus status = getService()->scheduleTask(scheduleInfo);
+
+    ASSERT_FALSE(status.isOk());
+    ASSERT_EQ(status.getExceptionCode(), EX_ILLEGAL_ARGUMENT);
+}
+
+TEST_F(RemoteAccessServiceUnitTest, TestScheduleTask_InvalidStartTimeInEpochSeconds) {
+    ScheduleInfo scheduleInfo = {
+            .clientId = kTestClientId,
+            .scheduleId = kTestScheduleId,
+            .taskData = kTestData,
+            .count = kTestCount,
+            .startTimeInEpochSeconds = -1,
+            .periodicInSeconds = kTestPeriodicInSeconds,
+    };
+
+    ScopedAStatus status = getService()->scheduleTask(scheduleInfo);
+
+    ASSERT_FALSE(status.isOk());
+    ASSERT_EQ(status.getExceptionCode(), EX_ILLEGAL_ARGUMENT);
+}
+
+TEST_F(RemoteAccessServiceUnitTest, TestScheduleTask_InvalidPeriodicInSeconds) {
+    ScheduleInfo scheduleInfo = {
+            .clientId = kTestClientId,
+            .scheduleId = kTestScheduleId,
+            .taskData = kTestData,
+            .count = kTestCount,
+            .startTimeInEpochSeconds = kTestStartTimeInEpochSeconds,
+            .periodicInSeconds = -1,
+    };
+
+    ScopedAStatus status = getService()->scheduleTask(scheduleInfo);
+
+    ASSERT_FALSE(status.isOk());
+    ASSERT_EQ(status.getExceptionCode(), EX_ILLEGAL_ARGUMENT);
+}
+
+TEST_F(RemoteAccessServiceUnitTest, TestScheduleTask_TaskDataTooLarge) {
+    ScheduleInfo scheduleInfo = {
+            .clientId = kTestClientId,
+            .scheduleId = kTestScheduleId,
+            .taskData = std::vector<uint8_t>(ScheduleInfo::MAX_TASK_DATA_SIZE_IN_BYTES + 1),
+            .count = kTestCount,
+            .startTimeInEpochSeconds = kTestStartTimeInEpochSeconds,
+            .periodicInSeconds = kTestPeriodicInSeconds,
+    };
+
+    ScopedAStatus status = getService()->scheduleTask(scheduleInfo);
+
+    ASSERT_FALSE(status.isOk());
+    ASSERT_EQ(status.getExceptionCode(), EX_ILLEGAL_ARGUMENT);
+}
+
+TEST_F(RemoteAccessServiceUnitTest, TestScheduleTask_InvalidArgFromGrpcServer) {
+    EXPECT_CALL(*getGrpcWakeupClientStub(), ScheduleTask)
+            .WillOnce([]([[maybe_unused]] ClientContext* context,
+                         [[maybe_unused]] const ScheduleTaskRequest& request,
+                         ScheduleTaskResponse* response) {
+                response->set_errorcode(ErrorCode::INVALID_ARG);
+                return Status();
+            });
+    ScheduleInfo scheduleInfo = {
+            .clientId = kTestClientId,
+            .scheduleId = kTestScheduleId,
+            .taskData = kTestData,
+            .count = kTestCount,
+            .startTimeInEpochSeconds = kTestStartTimeInEpochSeconds,
+            .periodicInSeconds = kTestPeriodicInSeconds,
+    };
+
+    ScopedAStatus status = getService()->scheduleTask(scheduleInfo);
+
+    ASSERT_FALSE(status.isOk());
+    ASSERT_EQ(status.getExceptionCode(), EX_ILLEGAL_ARGUMENT);
+}
+
+TEST_F(RemoteAccessServiceUnitTest, TestScheduleTask_UnspecifiedError) {
+    EXPECT_CALL(*getGrpcWakeupClientStub(), ScheduleTask)
+            .WillOnce([]([[maybe_unused]] ClientContext* context,
+                         [[maybe_unused]] const ScheduleTaskRequest& request,
+                         ScheduleTaskResponse* response) {
+                response->set_errorcode(ErrorCode::UNSPECIFIED);
+                return Status();
+            });
+    ScheduleInfo scheduleInfo = {
+            .clientId = kTestClientId,
+            .scheduleId = kTestScheduleId,
+            .taskData = kTestData,
+            .count = kTestCount,
+            .startTimeInEpochSeconds = kTestStartTimeInEpochSeconds,
+            .periodicInSeconds = kTestPeriodicInSeconds,
+    };
+
+    ScopedAStatus status = getService()->scheduleTask(scheduleInfo);
+
+    ASSERT_FALSE(status.isOk());
+    ASSERT_EQ(status.getExceptionCode(), EX_SERVICE_SPECIFIC);
+}
+
+TEST_F(RemoteAccessServiceUnitTest, TestUnscheduleTask) {
+    UnscheduleTaskRequest grpcRequest = {};
+    EXPECT_CALL(*getGrpcWakeupClientStub(), UnscheduleTask)
+            .WillOnce([&grpcRequest]([[maybe_unused]] ClientContext* context,
+                                     const UnscheduleTaskRequest& request,
+                                     [[maybe_unused]] UnscheduleTaskResponse* response) {
+                grpcRequest = request;
+                return Status();
+            });
+
+    ScopedAStatus status = getService()->unscheduleTask(kTestClientId, kTestScheduleId);
+
+    ASSERT_TRUE(status.isOk());
+    EXPECT_EQ(grpcRequest.clientid(), kTestClientId);
+    EXPECT_EQ(grpcRequest.scheduleid(), kTestScheduleId);
+}
+
+TEST_F(RemoteAccessServiceUnitTest, TestUnscheduleAllTasks) {
+    UnscheduleAllTasksRequest grpcRequest = {};
+    EXPECT_CALL(*getGrpcWakeupClientStub(), UnscheduleAllTasks)
+            .WillOnce([&grpcRequest]([[maybe_unused]] ClientContext* context,
+                                     const UnscheduleAllTasksRequest& request,
+                                     [[maybe_unused]] UnscheduleAllTasksResponse* response) {
+                grpcRequest = request;
+                return Status();
+            });
+
+    ScopedAStatus status = getService()->unscheduleAllTasks(kTestClientId);
+
+    ASSERT_TRUE(status.isOk());
+    EXPECT_EQ(grpcRequest.clientid(), kTestClientId);
+}
+
+TEST_F(RemoteAccessServiceUnitTest, TestIsTaskScheduled) {
+    bool isTaskScheduled = false;
+    IsTaskScheduledRequest grpcRequest = {};
+    EXPECT_CALL(*getGrpcWakeupClientStub(), IsTaskScheduled)
+            .WillOnce([&grpcRequest]([[maybe_unused]] ClientContext* context,
+                                     const IsTaskScheduledRequest& request,
+                                     IsTaskScheduledResponse* response) {
+                grpcRequest = request;
+                response->set_istaskscheduled(true);
+                return Status();
+            });
+
+    ScopedAStatus status =
+            getService()->isTaskScheduled(kTestClientId, kTestScheduleId, &isTaskScheduled);
+
+    ASSERT_TRUE(status.isOk());
+    EXPECT_TRUE(isTaskScheduled);
+    EXPECT_EQ(grpcRequest.clientid(), kTestClientId);
+    EXPECT_EQ(grpcRequest.scheduleid(), kTestScheduleId);
+}
+
+TEST_F(RemoteAccessServiceUnitTest, testGetAllPendingScheduledTasks) {
+    std::vector<ScheduleInfo> result;
+    GetAllPendingScheduledTasksRequest grpcRequest = {};
+    EXPECT_CALL(*getGrpcWakeupClientStub(), GetAllPendingScheduledTasks)
+            .WillOnce([&grpcRequest]([[maybe_unused]] ClientContext* context,
+                                     const GetAllPendingScheduledTasksRequest& request,
+                                     GetAllPendingScheduledTasksResponse* response) {
+                grpcRequest = request;
+                GrpcScheduleInfo* newInfo = response->add_allscheduledtasks();
+                newInfo->set_clientid(kTestClientId);
+                newInfo->set_scheduleid(kTestScheduleId);
+                newInfo->set_data(kTestData.data(), kTestData.size());
+                newInfo->set_count(kTestCount);
+                newInfo->set_starttimeinepochseconds(kTestStartTimeInEpochSeconds);
+                newInfo->set_periodicinseconds(kTestPeriodicInSeconds);
+                return Status();
+            });
+
+    ScopedAStatus status = getService()->getAllPendingScheduledTasks(kTestClientId, &result);
+
+    ASSERT_TRUE(status.isOk());
+    EXPECT_EQ(grpcRequest.clientid(), kTestClientId);
+    ASSERT_EQ(result.size(), 1u);
+    ASSERT_EQ(result[0].clientId, kTestClientId);
+    ASSERT_EQ(result[0].scheduleId, kTestScheduleId);
+    ASSERT_EQ(result[0].taskData, kTestData);
+    ASSERT_EQ(result[0].count, kTestCount);
+    ASSERT_EQ(result[0].startTimeInEpochSeconds, kTestStartTimeInEpochSeconds);
+    ASSERT_EQ(result[0].periodicInSeconds, kTestPeriodicInSeconds);
+}
+
 }  // namespace remoteaccess
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/remoteaccess/test_grpc_server/README.md b/automotive/remoteaccess/test_grpc_server/README.md
index af3d54a..d2b6bbe 100644
--- a/automotive/remoteaccess/test_grpc_server/README.md
+++ b/automotive/remoteaccess/test_grpc_server/README.md
@@ -141,7 +141,7 @@
 * The android lunch target: sdk_car_x86_64-userdebug and
   cf_x86_64_auto-userdebug already contains the default remote access HAL. For
   other lunch target, you can add the default remote access HAL by adding
-  'android.hardware.automotive.remoteaccess@V1-default-service' to
+  'android.hardware.automotive.remoteaccess@V2-default-service' to
   'PRODUCT_PACKAGES' variable in mk file, see `device/generic/car/common/car.mk`
   as example.
 
diff --git a/automotive/remoteaccess/test_grpc_server/impl/Android.bp b/automotive/remoteaccess/test_grpc_server/impl/Android.bp
index 152b528..fd174bf 100644
--- a/automotive/remoteaccess/test_grpc_server/impl/Android.bp
+++ b/automotive/remoteaccess/test_grpc_server/impl/Android.bp
@@ -38,6 +38,50 @@
     ],
     cflags: [
         "-Wno-unused-parameter",
-        "-DGRPC_SERVICE_ADDRESS=\"localhost:50051\"",
+        "-DGRPC_SERVICE_ADDRESS=\"127.0.0.1:50051\"",
+    ],
+}
+
+cc_binary_host {
+    name: "TestWakeupClientServerHost",
+    srcs: ["src/*.cpp"],
+    local_include_dirs: ["include"],
+    shared_libs: [
+        "libbase",
+        "libutils",
+        "libgrpc++",
+        "libprotobuf-cpp-full",
+    ],
+    whole_static_libs: [
+        "wakeup_client_protos",
+    ],
+    cflags: [
+        "-Wno-unused-parameter",
+        "-DGRPC_SERVICE_ADDRESS=\"127.0.0.1:50051\"",
+        "-DHOST",
+    ],
+}
+
+cc_test_host {
+    name: "TestWakeupClientServerHostUnitTest",
+    srcs: [
+        "test/*.cpp",
+        "src/TestWakeupClientServiceImpl.cpp",
+    ],
+    local_include_dirs: ["include"],
+    shared_libs: [
+        "libbase",
+        "libutils",
+        "libgrpc++",
+        "libprotobuf-cpp-full",
+    ],
+    static_libs: [
+        "libgtest",
+    ],
+    whole_static_libs: [
+        "wakeup_client_protos",
+    ],
+    cflags: [
+        "-Wno-unused-parameter",
     ],
 }
diff --git a/automotive/remoteaccess/test_grpc_server/impl/include/TestWakeupClientServiceImpl.h b/automotive/remoteaccess/test_grpc_server/impl/include/TestWakeupClientServiceImpl.h
index 6b86b35..41cc5d0 100644
--- a/automotive/remoteaccess/test_grpc_server/impl/include/TestWakeupClientServiceImpl.h
+++ b/automotive/remoteaccess/test_grpc_server/impl/include/TestWakeupClientServiceImpl.h
@@ -34,11 +34,9 @@
 // implementation, the task should come from remote task server. This class is thread-safe.
 class FakeTaskGenerator final {
   public:
-    GetRemoteTasksResponse generateTask();
+    GetRemoteTasksResponse generateTask(const std::string& clientId);
 
   private:
-    // Simulates the client ID for each task.
-    std::atomic<int> mCurrentClientId = 0;
     constexpr static uint8_t DATA[] = {0xde, 0xad, 0xbe, 0xef};
 };
 
@@ -73,38 +71,53 @@
 // TaskQueue is thread-safe.
 class TaskQueue final {
   public:
-    TaskQueue();
-    ~TaskQueue();
+    TaskQueue(android::sp<Looper> looper);
 
     void add(const GetRemoteTasksResponse& response);
     std::optional<GetRemoteTasksResponse> maybePopOne();
     void waitForTask();
     void stopWait();
-    void handleTaskTimeout();
     bool isEmpty();
+    bool isStopped();
 
   private:
-    std::thread mCheckTaskTimeoutThread;
+    friend class TaskTimeoutMessageHandler;
+
     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);
+    std::atomic<bool> mStopped = false;
     android::sp<Looper> mLooper;
     android::sp<TaskTimeoutMessageHandler> mTaskTimeoutMessageHandler;
     std::atomic<int> mTaskIdCounter = 0;
 
-    void checkForTestTimeoutLoop();
-    void waitForTaskWithLock(std::unique_lock<std::mutex>& lock);
+    void loop();
+    void handleTaskTimeout();
 };
 
-class TestWakeupClientServiceImpl final : public WakeupClient::Service {
+// forward-declaration
+class TestWakeupClientServiceImpl;
+
+class TaskScheduleMsgHandler final : public android::MessageHandler {
+  public:
+    TaskScheduleMsgHandler(TestWakeupClientServiceImpl* mImpl);
+    void handleMessage(const android::Message& message) override;
+
+  private:
+    TestWakeupClientServiceImpl* mImpl;
+};
+
+class TestWakeupClientServiceImpl : public WakeupClient::Service {
   public:
     TestWakeupClientServiceImpl();
 
     ~TestWakeupClientServiceImpl();
 
+    // Stop the handling for all income requests. Prepare for shutdown.
+    void stopServer();
+
     grpc::Status GetRemoteTasks(grpc::ServerContext* context, const GetRemoteTasksRequest* request,
                                 grpc::ServerWriter<GetRemoteTasksResponse>* writer) override;
 
@@ -112,25 +125,111 @@
                                       const NotifyWakeupRequiredRequest* request,
                                       NotifyWakeupRequiredResponse* response) override;
 
+    grpc::Status ScheduleTask(grpc::ServerContext* context, const ScheduleTaskRequest* request,
+                              ScheduleTaskResponse* response) override;
+
+    grpc::Status UnscheduleTask(grpc::ServerContext* context, const UnscheduleTaskRequest* request,
+                                UnscheduleTaskResponse* response) override;
+
+    grpc::Status UnscheduleAllTasks(grpc::ServerContext* context,
+                                    const UnscheduleAllTasksRequest* request,
+                                    UnscheduleAllTasksResponse* response) override;
+
+    grpc::Status IsTaskScheduled(grpc::ServerContext* context,
+                                 const IsTaskScheduledRequest* request,
+                                 IsTaskScheduledResponse* response) override;
+
+    grpc::Status GetAllPendingScheduledTasks(
+            grpc::ServerContext* context, const GetAllPendingScheduledTasksRequest* request,
+            GetAllPendingScheduledTasksResponse* response) override;
+
+    /**
+     * Starts generating fake tasks for the specific client repeatedly.
+     *
+     * The fake task will have {0xDE 0xAD 0xBE 0xEF} as payload. A new fake task will be sent
+     * to the client every 5s.
+     */
+    void startGeneratingFakeTask(const std::string& clientId);
+
+    /**
+     * stops generating fake tasks.
+     */
+    void stopGeneratingFakeTask();
+
+    /**
+     * Returns whether we need to wakeup the target device to send remote tasks.
+     */
+    bool isWakeupRequired();
+
+    /**
+     * Returns whether we have an active connection with the target device.
+     */
+    bool isRemoteTaskConnectionAlive();
+
+    /**
+     * Injects a fake task with taskData to be sent to the specific client.
+     */
+    void injectTask(const std::string& taskData, const std::string& clientId);
+
+    /**
+     * Wakes up the target device.
+     *
+     * This must be implemented by child class and contains device specific logic. E.g. this might
+     * be sending QEMU commands for the emulator device.
+     */
+    virtual void wakeupApplicationProcessor() = 0;
+
+    /**
+     * Cleans up a scheduled task info.
+     */
+    void cleanupScheduledTaskLocked(const std::string& clientId, const std::string& scheduleId)
+            REQUIRES(mLock);
+
   private:
-    // This is a thread for communicating with remote wakeup server (via network) and receive tasks
-    // from it.
-    std::thread mThread;
+    friend class TaskScheduleMsgHandler;
+
+    struct ScheduleInfo {
+        std::unique_ptr<GrpcScheduleInfo> grpcScheduleInfo;
+        // This is a unique ID to represent this schedule. Each repeated tasks will have different
+        // task ID but will have the same scheduleMsgId so that we can use to unschedule. This has
+        // to be an int so we cannot use the scheduleId provided by the client.
+        int scheduleMsgId;
+        int64_t periodicInSeconds;
+        int32_t currentCount;
+        int32_t totalCount;
+    };
+
+    std::atomic<int> mScheduleMsgCounter = 0;
+    // This is a looper for scheduling tasks to be executed in the future.
+    android::sp<Looper> mLooper;
+    android::sp<TaskScheduleMsgHandler> mTaskScheduleMsgHandler;
+    // This is a thread for generating fake tasks.
+    std::thread mFakeTaskThread;
+    // This is a thread for the looper.
+    std::thread mLooperThread;
     // A variable to notify server is stopping.
-    std::condition_variable mServerStoppedCv;
+    std::condition_variable mTaskLoopStoppedCv;
     // Whether wakeup AP is required for executing tasks.
     std::atomic<bool> mWakeupRequired = true;
+    // Whether we currently have an active long-live connection to deliver remote tasks.
+    std::atomic<bool> mRemoteTaskConnectionAlive = false;
     std::mutex mLock;
-    bool mServerStopped GUARDED_BY(mLock);
+    bool mGeneratingFakeTask GUARDED_BY(mLock);
+    std::atomic<bool> mServerStopped = false;
+    std::unordered_map<std::string, std::unordered_map<std::string, ScheduleInfo>>
+            mInfoByScheduleIdByClientId GUARDED_BY(mLock);
 
     // Thread-safe. For test impl only.
     FakeTaskGenerator mFakeTaskGenerator;
-    // Thread-sfae.
-    TaskQueue mTaskQueue;
+    // Thread-safe.
+    std::unique_ptr<TaskQueue> mTaskQueue;
 
-    void fakeTaskGenerateLoop();
-
-    void wakeupApplicationProcessor();
+    void fakeTaskGenerateLoop(const std::string& clientId);
+    void injectTaskResponse(const GetRemoteTasksResponse& response);
+    bool getScheduleInfoLocked(int scheduleMsgId, ScheduleInfo** outScheduleInfoPtr)
+            REQUIRES(mLock);
+    void handleAddTask(int scheduleMsgId);
+    void loop();
 };
 
 }  // namespace remoteaccess
diff --git a/automotive/remoteaccess/test_grpc_server/impl/src/TestWakeupClientServiceImpl.cpp b/automotive/remoteaccess/test_grpc_server/impl/src/TestWakeupClientServiceImpl.cpp
index 7dcd31e..eed3495 100644
--- a/automotive/remoteaccess/test_grpc_server/impl/src/TestWakeupClientServiceImpl.cpp
+++ b/automotive/remoteaccess/test_grpc_server/impl/src/TestWakeupClientServiceImpl.cpp
@@ -16,8 +16,6 @@
 
 #include "TestWakeupClientServiceImpl.h"
 
-#include "ApPowerControl.h"
-
 #include <android-base/stringprintf.h>
 #include <inttypes.h>
 #include <utils/Looper.h>
@@ -39,17 +37,24 @@
 using ::grpc::ServerWriter;
 using ::grpc::Status;
 
-constexpr int kTaskIntervalInMs = 5'000;
-constexpr int64_t KTaskTimeoutInMs = 20'000;
+constexpr int64_t kTaskIntervalInMs = 5'000;
+constexpr int64_t kTaskTimeoutInMs = 20'000;
+
+int64_t msToNs(int64_t ms) {
+    return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::milliseconds(ms))
+            .count();
+}
+
+int64_t sToNs(int64_t s) {
+    return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(s)).count();
+}
 
 }  // namespace
 
-GetRemoteTasksResponse FakeTaskGenerator::generateTask() {
-    int clientId = mCurrentClientId++;
+GetRemoteTasksResponse FakeTaskGenerator::generateTask(const std::string& clientId) {
     GetRemoteTasksResponse response;
-    response.set_data(std::string(reinterpret_cast<const char*>(DATA), sizeof(DATA)));
-    std::string clientIdStr = StringPrintf("%d", clientId);
-    response.set_clientid(clientIdStr);
+    response.set_data(reinterpret_cast<const char*>(DATA), sizeof(DATA));
+    response.set_clientid(clientId);
     return response;
 }
 
@@ -60,26 +65,9 @@
     mTaskQueue->handleTaskTimeout();
 }
 
-TaskQueue::TaskQueue() {
+TaskQueue::TaskQueue(android::sp<Looper> looper) {
     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();
-    }
+    mLooper = looper;
 }
 
 std::optional<GetRemoteTasksResponse> TaskQueue::maybePopOne() {
@@ -105,26 +93,28 @@
             .taskData = task,
     });
     android::Message message(taskId);
-    mLooper->sendMessageDelayed(KTaskTimeoutInMs * 1000, mTaskTimeoutMessageHandler, message);
+    mLooper->sendMessageDelayed(msToNs(kTaskTimeoutInMs), 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;
     });
 }
 
+bool TaskQueue::isStopped() {
+    return mStopped;
+}
+
 void TaskQueue::stopWait() {
-    std::lock_guard<std::mutex> lockGuard(mLock);
     mStopped = true;
-    mTasksNotEmptyCv.notify_all();
+    {
+        std::lock_guard<std::mutex> lockGuard(mLock);
+        mTasksNotEmptyCv.notify_all();
+    }
 }
 
 bool TaskQueue::isEmpty() {
@@ -132,21 +122,6 @@
     return mTasks.size() == 0 || mStopped;
 }
 
-void TaskQueue::checkForTestTimeoutLoop() {
-    Looper::setForThread(mLooper);
-
-    while (true) {
-        {
-            std::unique_lock<std::mutex> lock(mLock);
-            if (mStopped) {
-                return;
-            }
-        }
-
-        mLooper->pollAll(/*timeoutMillis=*/-1);
-    }
-}
-
 void TaskQueue::handleTaskTimeout() {
     // We know which task timed-out from the taskId in the message. However, there is no easy way
     // to remove a specific task with the task ID from the priority_queue, so we just check from
@@ -155,48 +130,106 @@
     int64_t now = uptimeMillis();
     while (mTasks.size() > 0) {
         const TaskInfo& taskInfo = mTasks.top();
-        if (taskInfo.timestampInMs + KTaskTimeoutInMs > now) {
+        if (taskInfo.timestampInMs + kTaskTimeoutInMs > now) {
             break;
         }
         // In real implementation, this should report task failure to remote wakeup server.
-        printf("Task for client ID: %s timed-out, added at %" PRId64 " ms, now %" PRId64 " ms",
+        printf("Task for client ID: %s timed-out, added at %" PRId64 " ms, now %" PRId64 " ms\n",
                taskInfo.taskData.clientid().c_str(), taskInfo.timestampInMs, now);
         mTasks.pop();
     }
 }
 
 TestWakeupClientServiceImpl::TestWakeupClientServiceImpl() {
-    mThread = std::thread([this] { fakeTaskGenerateLoop(); });
+    mTaskScheduleMsgHandler = android::sp<TaskScheduleMsgHandler>::make(this);
+    mLooper = android::sp<Looper>::make(/*opts=*/0);
+    mLooperThread = std::thread([this] { loop(); });
+    mTaskQueue = std::make_unique<TaskQueue>(mLooper);
 }
 
 TestWakeupClientServiceImpl::~TestWakeupClientServiceImpl() {
-    {
-        std::lock_guard<std::mutex> lockGuard(mLock);
-        mServerStopped = true;
-        mServerStoppedCv.notify_all();
+    if (mServerStopped) {
+        return;
     }
-    mTaskQueue.stopWait();
-    if (mThread.joinable()) {
-        mThread.join();
+    stopServer();
+}
+
+void TestWakeupClientServiceImpl::stopServer() {
+    mTaskQueue->stopWait();
+    stopGeneratingFakeTask();
+    // Set the flag so that the loop thread will exit.
+    mServerStopped = true;
+    mLooper->wake();
+    if (mLooperThread.joinable()) {
+        mLooperThread.join();
     }
 }
 
-void TestWakeupClientServiceImpl::fakeTaskGenerateLoop() {
+void TestWakeupClientServiceImpl::loop() {
+    Looper::setForThread(mLooper);
+
+    while (true) {
+        mLooper->pollAll(/*timeoutMillis=*/-1);
+        if (mServerStopped) {
+            return;
+        }
+    }
+}
+
+void TestWakeupClientServiceImpl::injectTask(const std::string& taskData,
+                                             const std::string& clientId) {
+    GetRemoteTasksResponse response;
+    response.set_data(taskData);
+    response.set_clientid(clientId);
+    injectTaskResponse(response);
+}
+
+void TestWakeupClientServiceImpl::injectTaskResponse(const GetRemoteTasksResponse& response) {
+    printf("Receive a new task\n");
+    mTaskQueue->add(response);
+    if (mWakeupRequired) {
+        wakeupApplicationProcessor();
+    }
+}
+
+void TestWakeupClientServiceImpl::startGeneratingFakeTask(const std::string& clientId) {
+    std::lock_guard<std::mutex> lockGuard(mLock);
+    if (mGeneratingFakeTask) {
+        printf("Fake task is already being generated\n");
+        return;
+    }
+    mGeneratingFakeTask = true;
+    mFakeTaskThread = std::thread([this, clientId] { fakeTaskGenerateLoop(clientId); });
+    printf("Started generating fake tasks\n");
+}
+
+void TestWakeupClientServiceImpl::stopGeneratingFakeTask() {
+    {
+        std::lock_guard<std::mutex> lockGuard(mLock);
+        if (!mGeneratingFakeTask) {
+            printf("Fake task is not being generated, do nothing\n");
+            return;
+        }
+        mTaskLoopStoppedCv.notify_all();
+        mGeneratingFakeTask = false;
+    }
+    if (mFakeTaskThread.joinable()) {
+        mFakeTaskThread.join();
+    }
+    printf("Stopped generating fake tasks\n");
+}
+
+void TestWakeupClientServiceImpl::fakeTaskGenerateLoop(const std::string& clientId) {
     // In actual implementation, this should communicate with the remote server and receives tasks
     // from it. Here we simulate receiving one remote task every {kTaskIntervalInMs}ms.
     while (true) {
-        mTaskQueue.add(mFakeTaskGenerator.generateTask());
-        printf("Received a new task\n");
-        if (mWakeupRequired) {
-            wakeupApplicationProcessor();
-        }
-
-        printf("Sleeping for %d seconds until next task\n", kTaskIntervalInMs);
+        injectTaskResponse(mFakeTaskGenerator.generateTask(clientId));
+        printf("Sleeping for %" PRId64 " seconds until next task\n", kTaskIntervalInMs);
 
         std::unique_lock lk(mLock);
-        if (mServerStoppedCv.wait_for(lk, std::chrono::milliseconds(kTaskIntervalInMs), [this] {
+        if (mTaskLoopStoppedCv.wait_for(lk, std::chrono::milliseconds(kTaskIntervalInMs), [this] {
                 ScopedLockAssertion lockAssertion(mLock);
-                return mServerStopped;
+                return !mGeneratingFakeTask;
             })) {
             // If the stopped flag is set, we are quitting, exit the loop.
             return;
@@ -208,46 +241,264 @@
                                                    const GetRemoteTasksRequest* request,
                                                    ServerWriter<GetRemoteTasksResponse>* writer) {
     printf("GetRemoteTasks called\n");
+    mRemoteTaskConnectionAlive = true;
     while (true) {
-        mTaskQueue.waitForTask();
+        mTaskQueue->waitForTask();
+
+        if (mTaskQueue->isStopped()) {
+            // Server stopped, exit the loop.
+            printf("Server stopped exit loop\n");
+            break;
+        }
 
         while (true) {
-            auto maybeTask = mTaskQueue.maybePopOne();
+            auto maybeTask = mTaskQueue->maybePopOne();
             if (!maybeTask.has_value()) {
+                printf("no task left\n");
                 // 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.
+            printf("Sending one remote task\n");
             const GetRemoteTasksResponse& response = maybeTask.value();
             if (!writer->Write(response)) {
                 // Broken stream, maybe the client is shutting down.
                 printf("Failed to deliver remote task to remote access HAL\n");
                 // The task failed to be sent, add it back to the queue. The order might change, but
                 // it is okay.
-                mTaskQueue.add(response);
+                mTaskQueue->add(response);
+                mRemoteTaskConnectionAlive = false;
                 return Status::CANCELLED;
             }
         }
     }
-    return Status::OK;
+    // Server stopped, exit the loop.
+    return Status::CANCELLED;
 }
 
 Status TestWakeupClientServiceImpl::NotifyWakeupRequired(ServerContext* context,
                                                          const NotifyWakeupRequiredRequest* request,
                                                          NotifyWakeupRequiredResponse* response) {
-    if (request->iswakeuprequired() && !mWakeupRequired && !mTaskQueue.isEmpty()) {
+    printf("NotifyWakeupRequired called\n");
+    if (request->iswakeuprequired() && !mWakeupRequired && !mTaskQueue->isEmpty()) {
         // If wakeup is now required and previously not required, this means we have finished
         // shutting down the device. If there are still pending tasks, try waking up AP again
         // to finish executing those tasks.
         wakeupApplicationProcessor();
     }
     mWakeupRequired = request->iswakeuprequired();
+    if (mWakeupRequired) {
+        // We won't know the connection is down unless we try to send a task over. If wakeup is
+        // required, the connection is very likely already down.
+        mRemoteTaskConnectionAlive = false;
+    }
     return Status::OK;
 }
 
-void TestWakeupClientServiceImpl::wakeupApplicationProcessor() {
-    wakeupAp();
+void TestWakeupClientServiceImpl::cleanupScheduledTaskLocked(const std::string& clientId,
+                                                             const std::string& scheduleId) {
+    mInfoByScheduleIdByClientId[clientId].erase(scheduleId);
+    if (mInfoByScheduleIdByClientId[clientId].size() == 0) {
+        mInfoByScheduleIdByClientId.erase(clientId);
+    }
+}
+
+TaskScheduleMsgHandler::TaskScheduleMsgHandler(TestWakeupClientServiceImpl* impl) : mImpl(impl) {}
+
+void TaskScheduleMsgHandler::handleMessage(const android::Message& message) {
+    mImpl->handleAddTask(message.what);
+}
+
+Status TestWakeupClientServiceImpl::ScheduleTask(ServerContext* context,
+                                                 const ScheduleTaskRequest* request,
+                                                 ScheduleTaskResponse* response) {
+    std::lock_guard<std::mutex> lockGuard(mLock);
+
+    const GrpcScheduleInfo& grpcScheduleInfo = request->scheduleinfo();
+    const std::string& scheduleId = grpcScheduleInfo.scheduleid();
+    const std::string& clientId = grpcScheduleInfo.clientid();
+    response->set_errorcode(ErrorCode::OK);
+
+    if (mInfoByScheduleIdByClientId.find(clientId) != mInfoByScheduleIdByClientId.end() &&
+        mInfoByScheduleIdByClientId[clientId].find(scheduleId) !=
+                mInfoByScheduleIdByClientId[clientId].end()) {
+        printf("Duplicate schedule Id: %s for client Id: %s\n", scheduleId.c_str(),
+               clientId.c_str());
+        response->set_errorcode(ErrorCode::INVALID_ARG);
+        return Status::OK;
+    }
+
+    int64_t startTimeInEpochSeconds = grpcScheduleInfo.starttimeinepochseconds();
+    int64_t periodicInSeconds = grpcScheduleInfo.periodicinseconds();
+    int32_t count = grpcScheduleInfo.count();
+
+    int scheduleMsgId = mScheduleMsgCounter++;
+    mInfoByScheduleIdByClientId[clientId][scheduleId] = {
+            .grpcScheduleInfo = std::make_unique<GrpcScheduleInfo>(grpcScheduleInfo),
+            .scheduleMsgId = scheduleMsgId,
+            .periodicInSeconds = periodicInSeconds,
+            .currentCount = 0,
+            .totalCount = count,
+    };
+
+    int64_t delayInSeconds =
+            startTimeInEpochSeconds - std::chrono::duration_cast<std::chrono::seconds>(
+                                              std::chrono::system_clock::now().time_since_epoch())
+                                              .count();
+    if (delayInSeconds < 0) {
+        delayInSeconds = 0;
+    }
+
+    printf("ScheduleTask called with client Id: %s, schedule Id: %s, delay: %" PRId64 " s\n",
+           clientId.c_str(), scheduleId.c_str(), delayInSeconds);
+
+    mLooper->sendMessageDelayed(sToNs(delayInSeconds), mTaskScheduleMsgHandler,
+                                android::Message(scheduleMsgId));
+
+    return Status::OK;
+}
+
+bool TestWakeupClientServiceImpl::getScheduleInfoLocked(int scheduleMsgId,
+                                                        ScheduleInfo** outScheduleInfoPtr) {
+    for (auto& [_, infoByScheduleId] : mInfoByScheduleIdByClientId) {
+        for (auto& [_, scheduleInfo] : infoByScheduleId) {
+            if (scheduleInfo.scheduleMsgId == scheduleMsgId) {
+                *outScheduleInfoPtr = &scheduleInfo;
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+void TestWakeupClientServiceImpl::handleAddTask(int scheduleMsgId) {
+    std::lock_guard<std::mutex> lockGuard(mLock);
+
+    ScheduleInfo* scheduleInfoPtr;
+    bool found = getScheduleInfoLocked(scheduleMsgId, &scheduleInfoPtr);
+    if (!found) {
+        printf("The schedule msg Id: %d is not found\n", scheduleMsgId);
+        return;
+    }
+
+    const GrpcScheduleInfo& grpcScheduleInfo = *scheduleInfoPtr->grpcScheduleInfo;
+    const std::string scheduleId = grpcScheduleInfo.scheduleid();
+    const std::string clientId = grpcScheduleInfo.clientid();
+
+    GetRemoteTasksResponse injectResponse;
+    injectResponse.set_data(grpcScheduleInfo.data().data(), grpcScheduleInfo.data().size());
+    injectResponse.set_clientid(clientId);
+    injectTaskResponse(injectResponse);
+    scheduleInfoPtr->currentCount++;
+
+    printf("Sending scheduled tasks for scheduleId: %s, clientId: %s, taskCount: %d\n",
+           scheduleId.c_str(), clientId.c_str(), scheduleInfoPtr->currentCount);
+
+    if (scheduleInfoPtr->totalCount != 0 &&
+        scheduleInfoPtr->currentCount == scheduleInfoPtr->totalCount) {
+        // This schedule is finished.
+        cleanupScheduledTaskLocked(clientId, scheduleId);
+        return;
+    }
+
+    // Schedule the task for the next period.
+    mLooper->sendMessageDelayed(sToNs(scheduleInfoPtr->periodicInSeconds), mTaskScheduleMsgHandler,
+                                android::Message(scheduleMsgId));
+}
+
+Status TestWakeupClientServiceImpl::UnscheduleTask(ServerContext* context,
+                                                   const UnscheduleTaskRequest* request,
+                                                   UnscheduleTaskResponse* response) {
+    std::lock_guard<std::mutex> lockGuard(mLock);
+
+    const std::string& clientId = request->clientid();
+    const std::string& scheduleId = request->scheduleid();
+    printf("UnscheduleTask called with client Id: %s, schedule Id: %s\n", clientId.c_str(),
+           scheduleId.c_str());
+
+    if (mInfoByScheduleIdByClientId.find(clientId) == mInfoByScheduleIdByClientId.end() ||
+        mInfoByScheduleIdByClientId[clientId].find(scheduleId) ==
+                mInfoByScheduleIdByClientId[clientId].end()) {
+        printf("UnscheduleTask: no task associated with clientId: %s, scheduleId: %s\n",
+               clientId.c_str(), scheduleId.c_str());
+        return Status::OK;
+    }
+
+    mLooper->removeMessages(mTaskScheduleMsgHandler,
+                            mInfoByScheduleIdByClientId[clientId][scheduleId].scheduleMsgId);
+    cleanupScheduledTaskLocked(clientId, scheduleId);
+    return Status::OK;
+}
+
+Status TestWakeupClientServiceImpl::UnscheduleAllTasks(ServerContext* context,
+                                                       const UnscheduleAllTasksRequest* request,
+                                                       UnscheduleAllTasksResponse* response) {
+    std::lock_guard<std::mutex> lockGuard(mLock);
+
+    const std::string& clientId = request->clientid();
+    printf("UnscheduleAllTasks called with client Id: %s\n", clientId.c_str());
+    if (mInfoByScheduleIdByClientId.find(clientId) == mInfoByScheduleIdByClientId.end()) {
+        printf("UnscheduleTask: no task associated with clientId: %s\n", clientId.c_str());
+        return Status::OK;
+    }
+    const auto& infoByScheduleId = mInfoByScheduleIdByClientId[clientId];
+    std::vector<int> scheduleMsgIds;
+    for (const auto& [_, scheduleInfo] : infoByScheduleId) {
+        mLooper->removeMessages(mTaskScheduleMsgHandler, /*what=*/scheduleInfo.scheduleMsgId);
+    }
+
+    mInfoByScheduleIdByClientId.erase(clientId);
+    return Status::OK;
+}
+
+Status TestWakeupClientServiceImpl::IsTaskScheduled(ServerContext* context,
+                                                    const IsTaskScheduledRequest* request,
+                                                    IsTaskScheduledResponse* response) {
+    std::lock_guard<std::mutex> lockGuard(mLock);
+
+    const std::string& clientId = request->clientid();
+    const std::string& scheduleId = request->scheduleid();
+    printf("IsTaskScheduled called with client Id: %s, scheduleId: %s\n", clientId.c_str(),
+           scheduleId.c_str());
+
+    if (mInfoByScheduleIdByClientId.find(clientId) == mInfoByScheduleIdByClientId.end()) {
+        response->set_istaskscheduled(false);
+        return Status::OK;
+    }
+    if (mInfoByScheduleIdByClientId[clientId].find(scheduleId) ==
+        mInfoByScheduleIdByClientId[clientId].end()) {
+        response->set_istaskscheduled(false);
+        return Status::OK;
+    }
+    response->set_istaskscheduled(true);
+    return Status::OK;
+}
+
+Status TestWakeupClientServiceImpl::GetAllPendingScheduledTasks(
+        ServerContext* context, const GetAllPendingScheduledTasksRequest* request,
+        GetAllPendingScheduledTasksResponse* response) {
+    const std::string& clientId = request->clientid();
+    printf("GetAllPendingScheduledTasks called with client Id: %s\n", clientId.c_str());
+    response->clear_allscheduledtasks();
+    {
+        std::unique_lock lk(mLock);
+        if (mInfoByScheduleIdByClientId.find(clientId) == mInfoByScheduleIdByClientId.end()) {
+            return Status::OK;
+        }
+        for (const auto& [_, scheduleInfo] : mInfoByScheduleIdByClientId[clientId]) {
+            (*response->add_allscheduledtasks()) = *scheduleInfo.grpcScheduleInfo;
+        }
+    }
+    return Status::OK;
+}
+
+bool TestWakeupClientServiceImpl::isWakeupRequired() {
+    return mWakeupRequired;
+}
+
+bool TestWakeupClientServiceImpl::isRemoteTaskConnectionAlive() {
+    return mRemoteTaskConnectionAlive;
 }
 
 }  // namespace remoteaccess
diff --git a/automotive/remoteaccess/test_grpc_server/impl/src/main.cpp b/automotive/remoteaccess/test_grpc_server/impl/src/main.cpp
index d3f519c..5443ad9 100644
--- a/automotive/remoteaccess/test_grpc_server/impl/src/main.cpp
+++ b/automotive/remoteaccess/test_grpc_server/impl/src/main.cpp
@@ -14,7 +14,17 @@
  * limitations under the License.
  */
 
+#include <signal.h>
+#include <stdio.h>
+#include <sys/wait.h>
+#include <iostream>
+#include <sstream>
 #include <string>
+#include <thread>
+
+#ifndef HOST
+#include "ApPowerControl.h"
+#endif  // #ifndef HOST
 
 #include "TestWakeupClientServiceImpl.h"
 
@@ -28,10 +38,18 @@
 using ::grpc::ServerBuilder;
 using ::grpc::ServerWriter;
 
-void RunServer(const std::string& serviceAddr) {
-    std::shared_ptr<TestWakeupClientServiceImpl> service =
-            std::make_unique<TestWakeupClientServiceImpl>();
+constexpr int SHUTDOWN_REQUEST = 289410889;
+constexpr int VEHICLE_IN_USE = 287313738;
+const char* COMMAND_RUN_EMU = "source ~/.aae-toolbox/bin/bashrc && aae emulator run";
+const char* COMMAND_SET_VHAL_PROP =
+        "adb -s emulator-5554 wait-for-device && adb -s emulator-5554 root "
+        "&& sleep 1 && adb -s emulator-5554 wait-for-device && adb -s emulator-5554 shell "
+        "dumpsys android.hardware.automotive.vehicle.IVehicle/default --set %d -i %d";
 
+pid_t emuPid = 0;
+
+void RunServer(const std::string& serviceAddr,
+               std::shared_ptr<TestWakeupClientServiceImpl> service) {
     ServerBuilder builder;
     builder.AddListeningPort(serviceAddr, grpc::InsecureServerCredentials());
     builder.RegisterService(service.get());
@@ -40,11 +58,228 @@
     server->Wait();
 }
 
+pid_t runCommand(const char* bashCommand) {
+    pid_t pid = fork();
+    if (pid == 0) {
+        // In child process. Put it into a separate process group so we can kill it.
+        setpgid(0, 0);
+        execl("/bin/bash", "bash", "-c", bashCommand, /*terminateArg=*/nullptr);
+        exit(0);
+    } else {
+        return pid;
+    }
+}
+
+void updateEmuStatus() {
+    if (emuPid == 0) {
+        return;
+    }
+    pid_t pid = waitpid(emuPid, nullptr, WNOHANG);
+    if (pid == emuPid) {
+        // Emu process already exited. If Emu process is still running, pid will be 0.
+        emuPid = 0;
+    }
+}
+
+bool powerOnEmu() {
+    updateEmuStatus();
+    if (emuPid != 0) {
+        printf("The emulator is already running\n");
+        return false;
+    }
+    emuPid = runCommand(COMMAND_RUN_EMU);
+    printf("Emulator started in process: %d\n", emuPid);
+    return true;
+}
+
+bool powerOn() {
+#ifdef HOST
+    return powerOnEmu();
+#else
+    printf("power on is only supported on host\n");
+    return false;
+#endif
+}
+
+const char* getSetPropCommand(int propId, int value) {
+    int size = snprintf(nullptr, 0, COMMAND_SET_VHAL_PROP, propId, value);
+    char* command = new char[size + 1];
+    snprintf(command, size + 1, COMMAND_SET_VHAL_PROP, propId, value);
+    return command;
+}
+
+const char* getSetPropCommand(int propId) {
+    return getSetPropCommand(propId, /*value=*/1);
+}
+
+void powerOffEmu() {
+    updateEmuStatus();
+    if (emuPid == 0) {
+        printf("The emulator is not running\n");
+        return;
+    }
+    const char* command = getSetPropCommand(SHUTDOWN_REQUEST);
+    runCommand(command);
+    delete[] command;
+    waitpid(emuPid, nullptr, /*options=*/0);
+    emuPid = 0;
+}
+
+void powerOff() {
+#ifdef HOST
+    powerOffEmu();
+#else
+    printf("power off is only supported on host\n");
+#endif
+}
+
+void setVehicleInUse(bool vehicleInUse) {
+#ifdef HOST
+    printf("Set vehicleInUse to %d\n", vehicleInUse);
+    int value = 0;
+    if (vehicleInUse) {
+        value = 1;
+    }
+    const char* command = getSetPropCommand(VEHICLE_IN_USE, value);
+    runCommand(command);
+    delete[] command;
+#else
+    printf("set vehicleInUse is only supported on host\n");
+#endif
+}
+
+void help() {
+    std::cout << "Remote Access Host Test Utility" << std::endl
+              << "help:\t"
+              << "Print out this help info" << std::endl
+              << "genFakeTask start [clientID]:\t"
+              << "Start generating a fake task every 5s" << std::endl
+              << "genFakeTask stop:\t"
+              << "Stop the fake task generation" << std::endl
+              << "status:\t"
+              << "Print current status" << std::endl
+              << "power on:\t"
+              << "Power on the emulator, simulate user enters vehicle while AP is off"
+              << " (only supported on host)" << std::endl
+              << "power off:\t"
+              << "Power off the emulator, simulate user leaves vehicle"
+              << " (only supported on host)" << std::endl
+              << "inject task [clientID] [taskData]:\t"
+              << "Inject a remote task" << std::endl
+              << "set vehicleInUse:\t"
+              << "Set vehicle in use, simulate user enter vehicle while boot up for remote task "
+              << "(only supported on host)" << std::endl;
+}
+
+void parseCommand(const std::string& userInput,
+                  std::shared_ptr<TestWakeupClientServiceImpl> service) {
+    if (userInput == "") {
+        // ignore empty line.
+    } else if (userInput == "help") {
+        help();
+    } else if (userInput.rfind("genFakeTask start", 0) == 0) {
+        std::string clientId;
+        std::stringstream ss;
+        ss << userInput;
+        int i = 0;
+        while (std::getline(ss, clientId, ' ')) {
+            i++;
+            if (i == 3) {
+                break;
+            }
+        }
+        if (i != 3) {
+            printf("Missing clientId, see 'help'\n");
+            return;
+        }
+        service->startGeneratingFakeTask(clientId);
+    } else if (userInput == "genFakeTask stop") {
+        service->stopGeneratingFakeTask();
+    } else if (userInput == "status") {
+        printf("isWakeupRequired: %B, isRemoteTaskConnectionAlive: %B\n",
+               service->isWakeupRequired(), service->isRemoteTaskConnectionAlive());
+    } else if (userInput == "power on") {
+        powerOn();
+    } else if (userInput == "power off") {
+        powerOff();
+    } else if (userInput.rfind("inject task", 0) == 0) {
+        std::stringstream ss;
+        ss << userInput;
+        std::string data;
+        std::string taskData;
+        std::string clientId;
+        int i = 0;
+        while (std::getline(ss, data, ' ')) {
+            i++;
+            if (i == 3) {
+                clientId = data;
+            }
+            if (i == 4) {
+                taskData = data;
+            }
+        }
+        if (taskData == "" || clientId == "") {
+            printf("Missing taskData or clientId, see 'help'\n");
+            return;
+        }
+        service->injectTask(taskData, clientId);
+        printf("Remote task with client ID: %s, data: %s injected\n", clientId.c_str(),
+               taskData.c_str());
+    } else if (userInput == "set vehicleInUse") {
+        setVehicleInUse(true);
+    } else {
+        printf("Unknown command, see 'help'\n");
+    }
+}
+
+void saHandler(int signum) {
+    if (emuPid != 0) {
+        kill(-emuPid, signum);
+        waitpid(emuPid, nullptr, /*options=*/0);
+        // Sleep for 1 seconds to allow emulator to print out logs.
+        sleep(1);
+    }
+    exit(-1);
+}
+
+class MyTestWakeupClientServiceImpl final : public TestWakeupClientServiceImpl {
+  public:
+    void wakeupApplicationProcessor() override {
+#ifdef HOST
+        if (powerOnEmu()) {
+            // If we wake up AP to execute remote task, vehicle in use should be false.
+            setVehicleInUse(false);
+        }
+#else
+        wakeupAp();
+#endif
+    };
+};
+
 int main(int argc, char** argv) {
     std::string serviceAddr = GRPC_SERVICE_ADDRESS;
     if (argc > 1) {
         serviceAddr = argv[1];
     }
-    RunServer(serviceAddr);
+    // Let the server thread run, we will force kill the server when we exit the program.
+    std::shared_ptr<TestWakeupClientServiceImpl> service =
+            std::make_shared<MyTestWakeupClientServiceImpl>();
+    std::thread serverThread([serviceAddr, service] { RunServer(serviceAddr, service); });
+
+    // Register the signal handler for SIGTERM and SIGINT so that we can stop the emulator before
+    // exit.
+    struct sigaction sa = {};
+    sigemptyset(&sa.sa_mask);
+    sa.sa_handler = saHandler;
+    sigaction(SIGTERM, &sa, nullptr);
+    sigaction(SIGINT, &sa, nullptr);
+
+    // Start processing the user inputs.
+    std::string userInput;
+    while (true) {
+        std::cout << ">>> ";
+        std::getline(std::cin, userInput);
+        parseCommand(userInput, service);
+    }
     return 0;
 }
diff --git a/automotive/remoteaccess/test_grpc_server/impl/test/TestWakeupClientServiceImplUnitTest.cpp b/automotive/remoteaccess/test_grpc_server/impl/test/TestWakeupClientServiceImplUnitTest.cpp
new file mode 100644
index 0000000..63458ae
--- /dev/null
+++ b/automotive/remoteaccess/test_grpc_server/impl/test/TestWakeupClientServiceImplUnitTest.cpp
@@ -0,0 +1,339 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <grpcpp/channel.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/security/credentials.h>
+#include <grpcpp/security/server_credentials.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+#include <gtest/gtest.h>
+#include <chrono>
+
+namespace android::hardware::automotive::remoteaccess::test {
+
+using ::android::base::ScopedLockAssertion;
+
+using ::grpc::Channel;
+using ::grpc::ClientContext;
+using ::grpc::Server;
+using ::grpc::ServerBuilder;
+using ::grpc::Status;
+
+const std::string kTestClientId = "test client id";
+const std::string kTestScheduleId = "test schedule id";
+const std::vector<uint8_t> kTestData = {0xde, 0xad, 0xbe, 0xef};
+constexpr int32_t kTestCount = 1234;
+constexpr int64_t kTestStartTimeInEpochSeconds = 2345;
+constexpr int64_t kTestPeriodicInSeconds = 123;
+const std::string kTestGrpcAddr = "localhost:50051";
+
+class MyTestWakeupClientServiceImpl final : public TestWakeupClientServiceImpl {
+  public:
+    void wakeupApplicationProcessor() override {
+        // Do nothing.
+    }
+};
+
+class TestWakeupClientServiceImplUnitTest : public ::testing::Test {
+  public:
+    virtual void SetUp() override {
+        mServerThread = std::thread([this] {
+            {
+                std::unique_lock<std::mutex> lock(mLock);
+                mService = std::make_unique<MyTestWakeupClientServiceImpl>();
+                ServerBuilder builder;
+                builder.AddListeningPort(kTestGrpcAddr, grpc::InsecureServerCredentials());
+                builder.RegisterService(mService.get());
+                mServer = builder.BuildAndStart();
+                mServerStartCv.notify_one();
+            }
+            mServer->Wait();
+        });
+        {
+            std::unique_lock<std::mutex> lock(mLock);
+            mServerStartCv.wait(lock, [this] {
+                ScopedLockAssertion lockAssertion(mLock);
+                return mServer != nullptr;
+            });
+        }
+        mChannel = grpc::CreateChannel(kTestGrpcAddr, grpc::InsecureChannelCredentials());
+        mStub = WakeupClient::NewStub(mChannel);
+    }
+
+    virtual void TearDown() override {
+        printf("Start server shutdown\n");
+        mService->stopServer();
+        mServer->Shutdown();
+        printf("Server shutdown complete\n");
+        mServerThread.join();
+        printf("Server thread exits\n");
+        mServer.reset();
+        mService.reset();
+        printf("Server and service classes reset\n");
+    }
+
+    WakeupClient::Stub* getStub() { return mStub.get(); }
+
+    size_t waitForRemoteTasks(size_t count) {
+        ClientContext context = {};
+        GetRemoteTasksResponse response;
+        auto reader = mStub->GetRemoteTasks(&context, GetRemoteTasksRequest{});
+        size_t got = 0;
+        while (reader->Read(&response)) {
+            got++;
+            mRemoteTaskResponses.push_back(response);
+            if (got == count) {
+                break;
+            }
+        }
+        // If there is more messages to be read in the reader, cancel them all so that we can
+        // finish.
+        context.TryCancel();
+        reader->Finish();
+        return got;
+    }
+
+    std::vector<GetRemoteTasksResponse> getRemoteTaskResponses() { return mRemoteTaskResponses; }
+
+    Status scheduleTask(int32_t count, int64_t startTimeInEpochSeconds, int64_t periodicInSeconds) {
+        return scheduleTask(kTestScheduleId, count, startTimeInEpochSeconds, periodicInSeconds);
+    }
+
+    Status scheduleTask(const std::string& scheduleId, int32_t count,
+                        int64_t startTimeInEpochSeconds, int64_t periodicInSeconds) {
+        ClientContext context;
+        ScheduleTaskRequest request;
+        ScheduleTaskResponse response;
+        int64_t now = std::chrono::duration_cast<std::chrono::seconds>(
+                              std::chrono::system_clock::now().time_since_epoch())
+                              .count();
+        request.mutable_scheduleinfo()->set_clientid(kTestClientId);
+        request.mutable_scheduleinfo()->set_scheduleid(scheduleId);
+        request.mutable_scheduleinfo()->set_data(kTestData.data(), kTestData.size());
+        request.mutable_scheduleinfo()->set_count(count);
+        request.mutable_scheduleinfo()->set_starttimeinepochseconds(startTimeInEpochSeconds);
+        request.mutable_scheduleinfo()->set_periodicinseconds(periodicInSeconds);
+
+        return getStub()->ScheduleTask(&context, request, &response);
+    }
+
+    int64_t getNow() {
+        return std::chrono::duration_cast<std::chrono::seconds>(
+                       std::chrono::system_clock::now().time_since_epoch())
+                .count();
+    }
+
+  private:
+    std::condition_variable mServerStartCv;
+    std::mutex mLock;
+    std::thread mServerThread;
+    std::unique_ptr<MyTestWakeupClientServiceImpl> mService;
+    std::unique_ptr<Server> mServer;
+    std::shared_ptr<Channel> mChannel;
+    std::unique_ptr<WakeupClient::Stub> mStub;
+    std::vector<GetRemoteTasksResponse> mRemoteTaskResponses;
+};
+
+TEST_F(TestWakeupClientServiceImplUnitTest, TestScheduleTask) {
+    ClientContext context = {};
+    ScheduleTaskRequest request = {};
+    ScheduleTaskResponse response = {};
+
+    request.mutable_scheduleinfo()->set_clientid(kTestClientId);
+    request.mutable_scheduleinfo()->set_scheduleid(kTestScheduleId);
+    request.mutable_scheduleinfo()->set_data(kTestData.data(), kTestData.size());
+    request.mutable_scheduleinfo()->set_count(2);
+    // Schedule the task to be executed 1s later.
+    request.mutable_scheduleinfo()->set_starttimeinepochseconds(getNow() + 1);
+    request.mutable_scheduleinfo()->set_periodicinseconds(1);
+
+    Status status = getStub()->ScheduleTask(&context, request, &response);
+
+    ASSERT_TRUE(status.ok());
+    ASSERT_EQ(response.errorcode(), ErrorCode::OK);
+
+    size_t gotTaskCount = waitForRemoteTasks(/*count=*/2);
+
+    EXPECT_EQ(gotTaskCount, 2);
+    auto responses = getRemoteTaskResponses();
+    for (const auto& response : responses) {
+        EXPECT_EQ(response.clientid(), kTestClientId);
+        EXPECT_EQ(response.data(), std::string(kTestData.begin(), kTestData.end()));
+    }
+}
+
+TEST_F(TestWakeupClientServiceImplUnitTest, TestScheduleTask_conflictScheduleId) {
+    Status status = scheduleTask(/*count=*/2, /*startTimeInEpochSeconds=*/getNow() + 1,
+                                 /*periodicInSeconds=*/1);
+
+    ASSERT_TRUE(status.ok());
+
+    // Schedule the same task again.
+    ClientContext context = {};
+    ScheduleTaskRequest request = {};
+    ScheduleTaskResponse response = {};
+
+    request.mutable_scheduleinfo()->set_clientid(kTestClientId);
+    request.mutable_scheduleinfo()->set_scheduleid(kTestScheduleId);
+    request.mutable_scheduleinfo()->set_data(kTestData.data(), kTestData.size());
+    request.mutable_scheduleinfo()->set_count(2);
+    request.mutable_scheduleinfo()->set_starttimeinepochseconds(getNow() + 1);
+    request.mutable_scheduleinfo()->set_periodicinseconds(1);
+
+    status = getStub()->ScheduleTask(&context, request, &response);
+
+    ASSERT_TRUE(status.ok());
+    ASSERT_EQ(response.errorcode(), ErrorCode::INVALID_ARG);
+}
+
+TEST_F(TestWakeupClientServiceImplUnitTest, TestUnscheduleTask) {
+    Status status = scheduleTask(/*count=*/2, /*startTimeInEpochSeconds=*/getNow() + 1,
+                                 /*periodicInSeconds=*/1);
+
+    ASSERT_TRUE(status.ok());
+
+    ClientContext context;
+    UnscheduleTaskRequest request;
+    UnscheduleTaskResponse response;
+    request.set_clientid(kTestClientId);
+    request.set_scheduleid(kTestScheduleId);
+    status = getStub()->UnscheduleTask(&context, request, &response);
+
+    ASSERT_TRUE(status.ok());
+
+    sleep(2);
+
+    // There should be no remote tasks received after 2s because the task was unscheduled.
+    EXPECT_EQ(getRemoteTaskResponses().size(), 0);
+}
+
+TEST_F(TestWakeupClientServiceImplUnitTest, TestIsTaskScheduled) {
+    int64_t startTimeInEpochSeconds = getNow() + 1;
+    int64_t periodicInSeconds = 1234;
+
+    Status status = scheduleTask(/*count=*/2, startTimeInEpochSeconds, periodicInSeconds);
+
+    ASSERT_TRUE(status.ok());
+
+    ClientContext context;
+    IsTaskScheduledRequest request;
+    IsTaskScheduledResponse response;
+    request.set_clientid(kTestClientId);
+    request.set_scheduleid(kTestScheduleId);
+    status = getStub()->IsTaskScheduled(&context, request, &response);
+
+    ASSERT_TRUE(status.ok());
+    EXPECT_TRUE(response.istaskscheduled());
+
+    ClientContext context2;
+    IsTaskScheduledRequest request2;
+    IsTaskScheduledResponse response2;
+    request.set_clientid(kTestClientId);
+    request.set_scheduleid("invalid id");
+    status = getStub()->IsTaskScheduled(&context2, request2, &response2);
+
+    ASSERT_TRUE(status.ok());
+    EXPECT_FALSE(response2.istaskscheduled());
+}
+
+TEST_F(TestWakeupClientServiceImplUnitTest, TestUnscheduleAllTasks) {
+    std::string scheduleId1 = "scheduleId1";
+    std::string scheduleId2 = "scheduleId2";
+    int64_t time1 = getNow();
+    int64_t time2 = getNow() + 1;
+    int64_t periodicInSeconds1 = 1;
+    int64_t periodicInSeconds2 = 1;
+    int32_t count1 = 2;
+    int64_t count2 = 5;
+
+    Status status = scheduleTask(scheduleId1, count1, time1, periodicInSeconds1);
+    ASSERT_TRUE(status.ok());
+    status = scheduleTask(scheduleId2, count2, time2, periodicInSeconds2);
+    ASSERT_TRUE(status.ok());
+
+    ClientContext context;
+    UnscheduleAllTasksRequest request;
+    UnscheduleAllTasksResponse response;
+    request.set_clientid(kTestClientId);
+    status = getStub()->UnscheduleAllTasks(&context, request, &response);
+    ASSERT_TRUE(status.ok());
+
+    sleep(2);
+
+    // There should be no remote tasks received after 2s because the tasks were unscheduled.
+    EXPECT_EQ(getRemoteTaskResponses().size(), 0);
+}
+
+TEST_F(TestWakeupClientServiceImplUnitTest, TestGetAllPendingScheduledTasks) {
+    std::string scheduleId1 = "scheduleId1";
+    std::string scheduleId2 = "scheduleId2";
+    int64_t time1 = getNow();
+    int64_t time2 = getNow() + 1;
+    int64_t periodicInSeconds1 = 1;
+    int64_t periodicInSeconds2 = 1;
+    int32_t count1 = 2;
+    int64_t count2 = 5;
+
+    Status status = scheduleTask(scheduleId1, count1, time1, periodicInSeconds1);
+    ASSERT_TRUE(status.ok());
+    status = scheduleTask(scheduleId2, count2, time2, periodicInSeconds2);
+    ASSERT_TRUE(status.ok());
+
+    ClientContext context;
+    GetAllPendingScheduledTasksRequest request;
+    GetAllPendingScheduledTasksResponse response;
+    request.set_clientid("invalid client Id");
+    status = getStub()->GetAllPendingScheduledTasks(&context, request, &response);
+
+    ASSERT_TRUE(status.ok());
+    EXPECT_EQ(response.allscheduledtasks_size(), 0);
+
+    ClientContext context2;
+    GetAllPendingScheduledTasksRequest request2;
+    GetAllPendingScheduledTasksResponse response2;
+    request2.set_clientid(kTestClientId);
+    status = getStub()->GetAllPendingScheduledTasks(&context2, request2, &response2);
+
+    ASSERT_TRUE(status.ok());
+    ASSERT_EQ(response2.allscheduledtasks_size(), 2);
+    for (int i = 0; i < 2; i++) {
+        EXPECT_EQ(response2.allscheduledtasks(i).clientid(), kTestClientId);
+        if (response2.allscheduledtasks(i).scheduleid() == scheduleId1) {
+            EXPECT_EQ(response2.allscheduledtasks(i).data(),
+                      std::string(kTestData.begin(), kTestData.end()));
+            EXPECT_EQ(response2.allscheduledtasks(i).count(), count1);
+            EXPECT_EQ(response2.allscheduledtasks(i).starttimeinepochseconds(), time1);
+            EXPECT_EQ(response2.allscheduledtasks(i).periodicinseconds(), periodicInSeconds1);
+        } else {
+            EXPECT_EQ(response2.allscheduledtasks(i).scheduleid(), scheduleId2);
+            EXPECT_EQ(response2.allscheduledtasks(i).data(),
+                      std::string(kTestData.begin(), kTestData.end()));
+            EXPECT_EQ(response2.allscheduledtasks(i).count(), count2);
+            EXPECT_EQ(response2.allscheduledtasks(i).starttimeinepochseconds(), time2);
+            EXPECT_EQ(response2.allscheduledtasks(i).periodicinseconds(), periodicInSeconds2);
+        }
+    }
+}
+
+}  // namespace android::hardware::automotive::remoteaccess::test
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    return RUN_ALL_TESTS();
+}
diff --git a/automotive/remoteaccess/test_grpc_server/lib/Android.bp b/automotive/remoteaccess/test_grpc_server/lib/Android.bp
index 7e95f53..8391018 100644
--- a/automotive/remoteaccess/test_grpc_server/lib/Android.bp
+++ b/automotive/remoteaccess/test_grpc_server/lib/Android.bp
@@ -26,7 +26,7 @@
 cc_library_shared {
     name: "ApPowerControlLib",
     vendor: true,
-    srcs: ["*.cpp"],
+    srcs: ["ApPowerControl.cpp"],
     local_include_dirs: ["."],
     export_include_dirs: ["."],
 }
diff --git a/automotive/remoteaccess/test_grpc_server/lib/ApPowerControlHost.cpp b/automotive/remoteaccess/test_grpc_server/lib/ApPowerControlHost.cpp
new file mode 100644
index 0000000..a475b00
--- /dev/null
+++ b/automotive/remoteaccess/test_grpc_server/lib/ApPowerControlHost.cpp
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ApPowerControl.h"
+
+#include <cstdio>
+
+void wakeupAp() {
+    printf("Waking up application processor...\n");
+}
diff --git a/automotive/sv/1.0/default/tests/fuzzer/AutomotiveSvV1_0Fuzzer.cpp b/automotive/sv/1.0/default/tests/fuzzer/AutomotiveSvV1_0Fuzzer.cpp
index 98834f5..4c4cc70 100644
--- a/automotive/sv/1.0/default/tests/fuzzer/AutomotiveSvV1_0Fuzzer.cpp
+++ b/automotive/sv/1.0/default/tests/fuzzer/AutomotiveSvV1_0Fuzzer.cpp
@@ -41,35 +41,32 @@
 
 void SurroundViewFuzzer::invoke2dSessionAPI() {
     sp<ISurroundView2dSession> surroundView2dSession;
+    sp<SurroundViewStream> handler;
+    mSurroundViewService->start2dSession(
+            [&surroundView2dSession](const sp<ISurroundView2dSession>& session, SvResult result) {
+                if (result == SvResult::OK) {
+                    surroundView2dSession = session;
+                }
+            });
+
+    if (surroundView2dSession && !mIs2dStreamStarted) {
+        handler = sp<SurroundViewStream>::make(surroundView2dSession);
+        if (surroundView2dSession->startStream(handler) == SvResult::OK) {
+            mIs2dStreamStarted = true;
+        }
+    }
 
     while (mFuzzedDataProvider.remaining_bytes() > 0) {
         auto surroundView2dFunc = mFuzzedDataProvider.PickValueInArray<
                 const std::function<void()>>({
                 [&]() {
-                    mSurroundViewService->start2dSession(
-                            [&surroundView2dSession](const sp<ISurroundView2dSession>& session,
-                                                     SvResult result) {
-                                if (result == SvResult::OK) {
-                                    surroundView2dSession = session;
-                                }
-                            });
-                },
-                [&]() {
-                    if (surroundView2dSession) {
-                        sp<SurroundViewStream> handler =
-                                sp<SurroundViewStream>::make(surroundView2dSession);
-                        surroundView2dSession->startStream(handler);
-                        mIs2dStreamStarted = true;
-                    }
-                },
-                [&]() {
                     if (surroundView2dSession) {
                         surroundView2dSession->get2dMappingInfo(
                                 []([[maybe_unused]] Sv2dMappingInfo info) {});
                     }
                 },
                 [&]() {
-                    if (surroundView2dSession) {
+                    if (surroundView2dSession && mIs2dStreamStarted) {
                         Sv2dConfig config;
                         config.width = mFuzzedDataProvider.ConsumeIntegralInRange<uint32_t>(
                                 kMinConfigDimension, kMaxConfigDimension);
@@ -149,8 +146,11 @@
                     }
                 },
                 [&]() {
-                    mSurroundViewService->stop2dSession(
+                    SvResult result = mSurroundViewService->stop2dSession(
                             mFuzzedDataProvider.ConsumeBool() ? surroundView2dSession : nullptr);
+                    if (result == SvResult::OK) {
+                        mIs2dStreamStarted = false;
+                    }
                 },
         });
         surroundView2dFunc();
@@ -159,31 +159,40 @@
     if (surroundView2dSession && mIs2dStreamStarted) {
         surroundView2dSession->stopStream();
     }
+
+    if (surroundView2dSession) {
+        mSurroundViewService->stop2dSession(surroundView2dSession);
+    }
 }
 
 void SurroundViewFuzzer::invoke3dSessionAPI() {
     sp<ISurroundView3dSession> surroundView3dSession;
+    sp<SurroundViewStream> handler;
+    mSurroundViewService->start3dSession(
+            [&surroundView3dSession](const sp<ISurroundView3dSession>& session, SvResult result) {
+                if (result == SvResult::OK) {
+                    surroundView3dSession = session;
+                }
+            });
+
+    const size_t numViews = mFuzzedDataProvider.ConsumeIntegralInRange<size_t>(1, kMaxViews);
+    std::vector<View3d> views(numViews);
+    for (size_t i = 0; i < numViews; ++i) {
+        views[i].viewId = mFuzzedDataProvider.ConsumeIntegral<uint32_t>();
+    }
+    surroundView3dSession->setViews(views);
+
+    if (surroundView3dSession) {
+        handler = sp<SurroundViewStream>::make(surroundView3dSession);
+
+        if (surroundView3dSession->startStream(handler) == SvResult::OK) {
+            mIs3dStreamStarted = true;
+        }
+    }
     while (mFuzzedDataProvider.remaining_bytes() > 0) {
         auto surroundView3dFunc = mFuzzedDataProvider.PickValueInArray<
                 const std::function<void()>>({
                 [&]() {
-                    mSurroundViewService->start3dSession(
-                            [&surroundView3dSession](const sp<ISurroundView3dSession>& session,
-                                                     SvResult result) {
-                                if (result == SvResult::OK) {
-                                    surroundView3dSession = session;
-                                }
-                            });
-                },
-                [&]() {
-                    if (surroundView3dSession) {
-                        sp<SurroundViewStream> handler =
-                                sp<SurroundViewStream>::make(surroundView3dSession);
-                        surroundView3dSession->startStream(handler);
-                        mIs3dStreamStarted = true;
-                    }
-                },
-                [&]() {
                     if (surroundView3dSession) {
                         const size_t numViews =
                                 mFuzzedDataProvider.ConsumeIntegralInRange<size_t>(1, kMaxViews);
@@ -195,7 +204,7 @@
                     }
                 },
                 [&]() {
-                    if (surroundView3dSession) {
+                    if (surroundView3dSession && mIs3dStreamStarted) {
                         Sv3dConfig config;
                         config.width = mFuzzedDataProvider.ConsumeIntegralInRange<uint32_t>(
                                 kMinConfigDimension, kMaxConfigDimension);
@@ -306,8 +315,11 @@
                     }
                 },
                 [&]() {
-                    mSurroundViewService->stop3dSession(
+                    SvResult result = mSurroundViewService->stop3dSession(
                             mFuzzedDataProvider.ConsumeBool() ? surroundView3dSession : nullptr);
+                    if (result == SvResult::OK) {
+                        mIs3dStreamStarted = false;
+                    }
                 },
         });
         surroundView3dFunc();
@@ -315,6 +327,10 @@
     if (surroundView3dSession && mIs3dStreamStarted) {
         surroundView3dSession->stopStream();
     }
+
+    if (surroundView3dSession) {
+        mSurroundViewService->stop3dSession(surroundView3dSession);
+    }
 }
 
 void SurroundViewFuzzer::process() {
diff --git a/automotive/vehicle/2.0/default/TEST_MAPPING b/automotive/vehicle/2.0/default/TEST_MAPPING
index bb58700..63ea3d5 100644
--- a/automotive/vehicle/2.0/default/TEST_MAPPING
+++ b/automotive/vehicle/2.0/default/TEST_MAPPING
@@ -2,7 +2,9 @@
   "presubmit": [
     {
       "name": "android.hardware.automotive.vehicle@2.0-manager-unit-tests"
-    },
+    }
+  ],
+  "postsubmit": [
     {
       "name": "android.hardware.automotive.vehicle@2.0-default-impl-unit-tests"
     }
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/RecurrentTimer.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/RecurrentTimer.h
index 0ed8742..0f5987e 100644
--- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/RecurrentTimer.h
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/RecurrentTimer.h
@@ -122,21 +122,29 @@
             }
 
             std::unique_lock<std::mutex> g(mLock);
+            // mStopRequested might be set to true after we enter the loop. Must check inside
+            // the lock to make sure the value will not change before we start the wait.
+            if (mStopRequested) {
+                return;
+            }
             mCond.wait_until(g, nextEventTime);  // nextEventTime can be nanoseconds::max()
         }
     }
 
     void stop() {
-        mStopRequested = true;
         {
             std::lock_guard<std::mutex> g(mLock);
             mCookieToEventsMap.clear();
+            // Even though this is atomic, this must be set inside the lock to make sure we will
+            // not change this after we check mStopRequested, but before we start the wait.
+            mStopRequested = true;
         }
         mCond.notify_one();
         if (mTimerThread.joinable()) {
             mTimerThread.join();
         }
     }
+
 private:
     mutable std::mutex mLock;
     std::thread mTimerThread;
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehiclePropertyStore.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehiclePropertyStore.h
index 6a02cf3..abbcd35 100644
--- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehiclePropertyStore.h
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehiclePropertyStore.h
@@ -70,6 +70,16 @@
      * example wasn't registered. */
     bool writeValue(const VehiclePropValue& propValue, bool updateStatus);
 
+    /*
+     * Stores provided value. Returns true if value was written returns false if config for
+     * example wasn't registered.
+     *
+     * The property value's timestamp will be set to the current ElapsedRealTimeNano.
+     */
+    bool writeValueWithCurrentTimestamp(VehiclePropValue* propValuePtr, bool updateStatus);
+
+    std::unique_ptr<VehiclePropValue> refreshTimestamp(int32_t propId, int32_t areaId);
+
     void removeValue(const VehiclePropValue& propValue);
     void removeValuesForProperty(int32_t propId);
 
@@ -94,6 +104,8 @@
     std::unordered_map<int32_t /* VehicleProperty */, RecordConfig> mConfigs;
 
     PropertyMap mPropertyValues;  // Sorted map of RecordId : VehiclePropValue.
+
+    bool writeValueLocked(const VehiclePropValue& propValue, bool updateStatus);
 };
 
 }  // namespace V2_0
diff --git a/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp b/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp
index 6087bfa..c12904e 100644
--- a/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp
+++ b/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp
@@ -15,6 +15,7 @@
  */
 #define LOG_TAG "VehiclePropertyStore"
 #include <log/log.h>
+#include <utils/SystemClock.h>
 
 #include <common/include/vhal_v2_0/VehicleUtils.h>
 #include "VehiclePropertyStore.h"
@@ -41,9 +42,7 @@
     mConfigs.insert({ config.prop, RecordConfig { config, tokenFunc } });
 }
 
-bool VehiclePropertyStore::writeValue(const VehiclePropValue& propValue,
-                                        bool updateStatus) {
-    MuxGuard g(mLock);
+bool VehiclePropertyStore::writeValueLocked(const VehiclePropValue& propValue, bool updateStatus) {
     if (!mConfigs.count(propValue.prop)) return false;
 
     RecordId recId = getRecordIdLocked(propValue);
@@ -68,6 +67,36 @@
     return true;
 }
 
+bool VehiclePropertyStore::writeValue(const VehiclePropValue& propValue, bool updateStatus) {
+    MuxGuard g(mLock);
+
+    return writeValueLocked(propValue, updateStatus);
+}
+
+bool VehiclePropertyStore::writeValueWithCurrentTimestamp(VehiclePropValue* propValuePtr,
+                                                          bool updateStatus) {
+    MuxGuard g(mLock);
+
+    propValuePtr->timestamp = elapsedRealtimeNano();
+    return writeValueLocked(*propValuePtr, updateStatus);
+}
+
+std::unique_ptr<VehiclePropValue> VehiclePropertyStore::refreshTimestamp(int32_t propId,
+                                                                         int32_t areaId) {
+    MuxGuard g(mLock);
+    RecordId recId = getRecordIdLocked(VehiclePropValue{
+            .prop = propId,
+            .areaId = areaId,
+    });
+    auto it = mPropertyValues.find(recId);
+    if (it == mPropertyValues.end()) {
+        return nullptr;
+    }
+
+    it->second.timestamp = elapsedRealtimeNano();
+    return std::make_unique<VehiclePropValue>(it->second);
+}
+
 void VehiclePropertyStore::removeValue(const VehiclePropValue& propValue) {
     MuxGuard g(mLock);
     RecordId recId = getRecordIdLocked(propValue);
diff --git a/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp b/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp
index c16b29a..03a9df5 100644
--- a/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp
+++ b/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp
@@ -30,7 +30,7 @@
 
 std::unique_ptr<VehiclePropValue> createVehiclePropValue(
     VehiclePropertyType type, size_t vecSize) {
-    auto val = std::unique_ptr<VehiclePropValue>(new VehiclePropValue);
+    auto val = std::unique_ptr<VehiclePropValue>(new VehiclePropValue());
     switch (type) {
         case VehiclePropertyType::INT32:      // fall through
         case VehiclePropertyType::INT32_VEC:  // fall through
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/BackportedPropertyHelper.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/BackportedPropertyHelper.h
new file mode 100644
index 0000000..78ae940
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/BackportedPropertyHelper.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This file contains backported system property definitions and backported enums.
+
+#pragma once
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+namespace backportedproperty {
+
+/**
+ * Characterization of inputs used for computing location.
+ *
+ * This property must indicate what (if any) data and sensor inputs are considered by the system
+ * when computing the vehicle's location that is shared with Android through the GNSS HAL.
+ *
+ * The value must return a collection of bit flags. The bit flags are defined in
+ * LocationCharacterization. The value must also include exactly one of DEAD_RECKONED or
+ * RAW_GNSS_ONLY among its collection of bit flags.
+ *
+ * When this property is not supported, it is assumed that no additional sensor inputs are fused
+ * into the GNSS updates provided through the GNSS HAL. That is unless otherwise specified
+ * through the GNSS HAL interfaces.
+ *
+ * @change_mode VehiclePropertyChangeMode.STATIC
+ * @access VehiclePropertyAccess.READ
+ */
+constexpr int32_t LOCATION_CHARACTERIZATION = 0x31400C10;
+
+/**
+ * Used by LOCATION_CHARACTERIZATION to enumerate the supported bit flags.
+ *
+ * These flags are used to indicate to what transformations are performed on the
+ * GNSS data before the location data is sent, so that location processing
+ * algorithms can take into account prior fusion.
+ *
+ * This enum can be extended in future releases to include additional bit flags.
+ */
+enum class LocationCharacterization : int32_t {
+    /**
+     * Prior location samples have been used to refine the raw GNSS data (e.g. a
+     * Kalman Filter).
+     */
+    PRIOR_LOCATIONS = 0x1,
+    /**
+     * Gyroscope data has been used to refine the raw GNSS data.
+     */
+    GYROSCOPE_FUSION = 0x2,
+    /**
+     * Accelerometer data has been used to refine the raw GNSS data.
+     */
+    ACCELEROMETER_FUSION = 0x4,
+    /**
+     * Compass data has been used to refine the raw GNSS data.
+     */
+    COMPASS_FUSION = 0x8,
+    /**
+     * Wheel speed has been used to refine the raw GNSS data.
+     */
+    WHEEL_SPEED_FUSION = 0x10,
+    /**
+     * Steering angle has been used to refine the raw GNSS data.
+     */
+    STEERING_ANGLE_FUSION = 0x20,
+    /**
+     * Car speed has been used to refine the raw GNSS data.
+     */
+    CAR_SPEED_FUSION = 0x40,
+    /**
+     * Some effort is made to dead-reckon location. In particular, this means that
+     * relative changes in location have meaning when no GNSS satellite is
+     * available.
+     */
+    DEAD_RECKONED = 0x80,
+    /**
+     * Location is based on GNSS satellite signals without sufficient fusion of
+     * other sensors for complete dead reckoning. This flag should be set when
+     * relative changes to location cannot be relied on when no GNSS satellite is
+     * available.
+     */
+    RAW_GNSS_ONLY = 0x100,
+};
+
+}  // namespace backportedproperty
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
index cfa3b0c..4846bfb 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
@@ -17,6 +17,7 @@
 #ifndef android_hardware_automotive_vehicle_V2_0_impl_DefaultConfig_H_
 #define android_hardware_automotive_vehicle_V2_0_impl_DefaultConfig_H_
 
+#include "BackportedPropertyHelper.h"
 #include "PropertyUtils.h"
 
 #include <map>
@@ -29,6 +30,9 @@
 
 namespace impl {
 
+using ::android::hardware::automotive::vehicle::V2_0::backportedproperty::LOCATION_CHARACTERIZATION;
+using ::android::hardware::automotive::vehicle::V2_0::backportedproperty::LocationCharacterization;
+
 struct ConfigDeclaration {
     VehiclePropConfig config;
 
@@ -938,7 +942,10 @@
                                   (int)VehicleVendorPermission::PERMISSION_NOT_ACCESSIBLE,
                                   VENDOR_EXTENSION_FLOAT_PROPERTY,
                                   (int)VehicleVendorPermission::PERMISSION_DEFAULT,
-                                  (int)VehicleVendorPermission::PERMISSION_DEFAULT},
+                                  (int)VehicleVendorPermission::PERMISSION_DEFAULT,
+                                  LOCATION_CHARACTERIZATION,
+                                  (int)VehicleVendorPermission::PERMISSION_GET_VENDOR_CATEGORY_INFO,
+                                  (int)VehicleVendorPermission::PERMISSION_NOT_ACCESSIBLE},
                  },
          .initialValue = {.int32Values = {1}}},
 
@@ -1131,6 +1138,15 @@
                 // GsrComplianceRequirementType::GSR_COMPLIANCE_REQUIRED_V1
                 .initialValue = {.int32Values = {1}},
         },
+        {
+                .config =
+                        {
+                                .prop = LOCATION_CHARACTERIZATION,
+                                .access = VehiclePropertyAccess::READ,
+                                .changeMode = VehiclePropertyChangeMode::STATIC,
+                        },
+                .initialValue = {.int32Values = {toInt(LocationCharacterization::RAW_GNSS_ONLY)}},
+        },
 #ifdef ENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING
         // Vendor propetry for E2E ClusterHomeService testing.
         {
@@ -1195,29 +1211,131 @@
                         },
                 // All supported property IDs. This list is checked by
                 // DefaultConfigSupportedPropertyIds_test.
-                .initialValue =
-                        {.int32Values =
-                                 {291504388, 289472773, 291504390, 289472775, 289407240, 289407241,
-                                  289472780, 286261505, 286261506, 289407235, 289472779, 291504647,
-                                  289408517, 356518832, 356516106, 291504644, 291504649, 291504656,
-                                  291504901, 291504903, 287310600, 291504905, 287310602, 287310603,
-                                  291504908, 291504904, 392168201, 392168202, 289408514, 289408001,
-                                  287310850, 287310851, 287310853, 289408513, 289475088, 289475104,
-                                  289475120, 354419984, 320865540, 320865556, 354419975, 354419976,
-                                  354419986, 354419973, 354419974, 354419978, 354419977, 356517120,
-                                  356517121, 356582673, 356517139, 289408269, 356517131, 358614275,
-                                  291570965, 291505923, 289408270, 289408512, 287310855, 289408000,
-                                  289408008, 289408009, 289407747, 291504900, 568332561, 371198722,
-                                  373295872, 320867268, 322964416, 290521862, 287310858, 287310859,
-                                  289475072, 289475073, 289409539, 299896064, 299896065, 299896066,
-                                  299896067, 289410560, 289410561, 289410562, 289410563, 289410576,
-                                  289410577, 289410578, 289410579, 289476368, 299895808, 639631617,
-                                  627048706, 591397123, 554696964, 289410873, 289410874, 287313669,
-                                  299896583, 299896584, 299896585, 299896586, 299896587, 286265121,
-                                  286265122, 286265123, 290457094, 290459441, 299896626, 290459443,
-                                  289410868, 289476405, 299896630, 289410871, 292556600, 557853201,
-                                  559950353, 555756049, 554707473, 289410887, 557846324, 557911861,
-                                  568332086, 557846327, 560992056, 289476424}},
+                .initialValue = {.int32Values = {291504388,
+                                                 289472773,
+                                                 291504390,
+                                                 289472775,
+                                                 289407240,
+                                                 289407241,
+                                                 289472780,
+                                                 286261505,
+                                                 286261506,
+                                                 289407235,
+                                                 289472779,
+                                                 291504647,
+                                                 289408517,
+                                                 356518832,
+                                                 356516106,
+                                                 291504644,
+                                                 291504649,
+                                                 291504656,
+                                                 291504901,
+                                                 291504903,
+                                                 287310600,
+                                                 291504905,
+                                                 287310602,
+                                                 287310603,
+                                                 291504908,
+                                                 291504904,
+                                                 392168201,
+                                                 392168202,
+                                                 289408514,
+                                                 289408001,
+                                                 287310850,
+                                                 287310851,
+                                                 287310853,
+                                                 289408513,
+                                                 289475088,
+                                                 289475104,
+                                                 289475120,
+                                                 354419984,
+                                                 320865540,
+                                                 320865556,
+                                                 354419975,
+                                                 354419976,
+                                                 354419986,
+                                                 354419973,
+                                                 354419974,
+                                                 354419978,
+                                                 354419977,
+                                                 356517120,
+                                                 356517121,
+                                                 356582673,
+                                                 356517139,
+                                                 289408269,
+                                                 356517131,
+                                                 358614275,
+                                                 291570965,
+                                                 291505923,
+                                                 289408270,
+                                                 289408512,
+                                                 287310855,
+                                                 289408000,
+                                                 289408008,
+                                                 289408009,
+                                                 289407747,
+                                                 291504900,
+                                                 568332561,
+                                                 371198722,
+                                                 373295872,
+                                                 320867268,
+                                                 322964416,
+                                                 290521862,
+                                                 287310858,
+                                                 287310859,
+                                                 289475072,
+                                                 289475073,
+                                                 289409539,
+                                                 299896064,
+                                                 299896065,
+                                                 299896066,
+                                                 299896067,
+                                                 289410560,
+                                                 289410561,
+                                                 289410562,
+                                                 289410563,
+                                                 289410576,
+                                                 289410577,
+                                                 289410578,
+                                                 289410579,
+                                                 289476368,
+                                                 299895808,
+                                                 639631617,
+                                                 627048706,
+                                                 591397123,
+                                                 554696964,
+                                                 289410873,
+                                                 289410874,
+                                                 287313669,
+                                                 299896583,
+                                                 299896584,
+                                                 299896585,
+                                                 299896586,
+                                                 299896587,
+                                                 286265121,
+                                                 286265122,
+                                                 286265123,
+                                                 290457094,
+                                                 290459441,
+                                                 299896626,
+                                                 290459443,
+                                                 289410868,
+                                                 289476405,
+                                                 299896630,
+                                                 289410871,
+                                                 292556600,
+                                                 557853201,
+                                                 559950353,
+                                                 555756049,
+                                                 554707473,
+                                                 289410887,
+                                                 557846324,
+                                                 557911861,
+                                                 568332086,
+                                                 557846327,
+                                                 560992056,
+                                                 289476424,
+                                                 LOCATION_CHARACTERIZATION}},
         },
 #endif  // ENABLE_GET_PROP_CONFIGS_BY_MULTIPLE_REQUESTS
 };
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.cpp
index 318e9dd..82e357f 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.cpp
@@ -57,12 +57,6 @@
     return nullptr;
 }
 
-VehicleHal::VehiclePropValuePtr addTimestamp(VehicleHal::VehiclePropValuePtr v) {
-    if (v.get()) {
-        v->timestamp = elapsedRealtimeNano();
-    }
-    return v;
-}
 }  // namespace
 
 VehicleHal::VehiclePropValuePtr DefaultVehicleHal::createVhalHeartBeatProp() {
@@ -102,7 +96,7 @@
             *outStatus = StatusCode::INTERNAL_ERROR;
         }
     }
-    return addTimestamp(std::move(v));
+    return v;
 }
 
 VehicleHal::VehiclePropValuePtr DefaultVehicleHal::get(const VehiclePropValue& requestedPropValue,
@@ -118,13 +112,13 @@
     if (propId == OBD2_FREEZE_FRAME) {
         v = getValuePool()->obtainComplex();
         *outStatus = fillObd2FreezeFrame(mPropStore, requestedPropValue, v.get());
-        return addTimestamp(std::move(v));
+        return v;
     }
 
     if (propId == OBD2_FREEZE_FRAME_INFO) {
         v = getValuePool()->obtainComplex();
         *outStatus = fillObd2DtcInfo(mPropStore, v.get());
-        return addTimestamp(std::move(v));
+        return v;
     }
 
     auto internalPropValue = mPropStore->readValueOrNull(requestedPropValue);
@@ -139,7 +133,7 @@
     } else {
         *outStatus = StatusCode::TRY_AGAIN;
     }
-    return addTimestamp(std::move(v));
+    return v;
 }
 
 std::vector<VehiclePropConfig> DefaultVehicleHal::listProperties() {
@@ -486,26 +480,46 @@
 
 void DefaultVehicleHal::onContinuousPropertyTimer(const std::vector<int32_t>& properties) {
     auto& pool = *getValuePool();
-
     for (int32_t property : properties) {
-        VehiclePropValuePtr v;
+        std::vector<VehiclePropValuePtr> events;
         if (isContinuousProperty(property)) {
-            auto internalPropValue = mPropStore->readValueOrNull(property);
-            if (internalPropValue != nullptr) {
-                v = pool.obtain(*internalPropValue);
+            const VehiclePropConfig* config = mPropStore->getConfigOrNull(property);
+            std::vector<int32_t> areaIds;
+            if (isGlobalProp(property)) {
+                areaIds.push_back(0);
+            } else {
+                for (auto& c : config->areaConfigs) {
+                    areaIds.push_back(c.areaId);
+                }
+            }
+
+            for (int areaId : areaIds) {
+                auto refreshedProp = mPropStore->refreshTimestamp(property, areaId);
+                VehiclePropValuePtr v = nullptr;
+                if (refreshedProp != nullptr) {
+                    v = pool.obtain(*refreshedProp);
+                }
+                if (v.get()) {
+                    events.push_back(std::move(v));
+                }
             }
         } else if (property == static_cast<int32_t>(VehicleProperty::VHAL_HEARTBEAT)) {
             // VHAL_HEARTBEAT is not a continuous value, but it needs to be updated periodically.
             // So, the update is done through onContinuousPropertyTimer.
-            v = doInternalHealthCheck();
+            auto v = doInternalHealthCheck();
+            if (!v.get()) {
+                // Internal health check failed.
+                continue;
+            }
+            mPropStore->writeValueWithCurrentTimestamp(v.get(), /*updateStatus=*/true);
+            events.push_back(std::move(v));
         } else {
             ALOGE("Unexpected onContinuousPropertyTimer for property: 0x%x", property);
             continue;
         }
 
-        if (v.get()) {
-            v->timestamp = elapsedRealtimeNano();
-            doHalEvent(std::move(v));
+        for (VehiclePropValuePtr& event : events) {
+            doHalEvent(std::move(event));
         }
     }
 }
@@ -556,7 +570,7 @@
 void DefaultVehicleHal::onPropertyValue(const VehiclePropValue& value, bool updateStatus) {
     VehiclePropValuePtr updatedPropValue = getValuePool()->obtain(value);
 
-    if (mPropStore->writeValue(*updatedPropValue, updateStatus)) {
+    if (mPropStore->writeValueWithCurrentTimestamp(updatedPropValue.get(), updateStatus)) {
         doHalEvent(std::move(updatedPropValue));
     }
 }
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultVhalImpl_test.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultVhalImpl_test.cpp
index edd4484..c876836 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultVhalImpl_test.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultVhalImpl_test.cpp
@@ -81,8 +81,13 @@
 using ::android::hardware::automotive::vehicle::V2_0::impl::OBD2_FREEZE_FRAME_CLEAR;
 using ::android::hardware::automotive::vehicle::V2_0::impl::OBD2_FREEZE_FRAME_INFO;
 using ::android::hardware::automotive::vehicle::V2_0::impl::OBD2_LIVE_FRAME;
+using ::android::hardware::automotive::vehicle::V2_0::impl::WHEEL_FRONT_LEFT;
+using ::android::hardware::automotive::vehicle::V2_0::impl::WHEEL_FRONT_RIGHT;
+using ::android::hardware::automotive::vehicle::V2_0::impl::WHEEL_REAR_LEFT;
+using ::android::hardware::automotive::vehicle::V2_0::impl::WHEEL_REAR_RIGHT;
 
 using ::testing::HasSubstr;
+using ::testing::UnorderedElementsAre;
 
 using VehiclePropValuePtr = recyclable_ptr<VehiclePropValue>;
 
@@ -152,7 +157,7 @@
 TEST_F(DefaultVhalImplTest, testListProperties) {
     std::vector<VehiclePropConfig> configs = mHal->listProperties();
 
-    EXPECT_EQ((size_t)124, configs.size());
+    EXPECT_EQ((size_t)125, configs.size());
 }
 
 TEST_F(DefaultVhalImplTest, testGetDefaultPropertyFloat) {
@@ -346,6 +351,38 @@
     EXPECT_EQ(1.0f, lastEvent->value.floatValues[0]);
 }
 
+TEST_F(DefaultVhalImplTest, testSubscribeContinuous_withMultipleAreaIds) {
+    // Clear existing events.
+    mEventQueue.flush();
+    int propId = toInt(VehicleProperty::TIRE_PRESSURE);
+
+    auto status = mHal->subscribe(propId, 1);
+
+    ASSERT_EQ(StatusCode::OK, status);
+
+    std::vector<VehiclePropValuePtr> receivedEvents;
+    // Wait for 2 updates, each for 4 area IDs.
+    waitForEvents(&receivedEvents, 4 * 2);
+
+    std::vector<int> areasForUpdate1;
+    std::vector<int> areasForUpdate2;
+
+    for (size_t i = 0; i < receivedEvents.size(); i++) {
+        ASSERT_EQ(receivedEvents[i]->prop, propId);
+
+        if (i < 4) {
+            areasForUpdate1.push_back(receivedEvents[i]->areaId);
+        } else {
+            areasForUpdate2.push_back(receivedEvents[i]->areaId);
+        }
+    }
+
+    ASSERT_THAT(areasForUpdate1, UnorderedElementsAre(WHEEL_FRONT_LEFT, WHEEL_FRONT_RIGHT,
+                                                      WHEEL_REAR_LEFT, WHEEL_REAR_RIGHT));
+    ASSERT_THAT(areasForUpdate2, UnorderedElementsAre(WHEEL_FRONT_LEFT, WHEEL_FRONT_RIGHT,
+                                                      WHEEL_REAR_LEFT, WHEEL_REAR_RIGHT));
+}
+
 TEST_F(DefaultVhalImplTest, testSubscribeInvalidProp) {
     EXPECT_EQ(StatusCode::INVALID_ARG, mHal->subscribe(toInt(VehicleProperty::INFO_MAKE), 10));
 }
@@ -1318,7 +1355,6 @@
     ASSERT_EQ((size_t)1, events.size());
     ASSERT_EQ((size_t)1, events[0]->value.int32Values.size());
     EXPECT_EQ(2022, events[0]->value.int32Values[0]);
-    EXPECT_EQ(1000, events[0]->timestamp);
 
     VehiclePropValue value;
     StatusCode status;
@@ -1352,7 +1388,6 @@
     ASSERT_EQ((size_t)1, events.size());
     EXPECT_EQ(0, events[0]->value.int32Values[0]);
     EXPECT_EQ(DOOR_1_LEFT, events[0]->areaId);
-    EXPECT_EQ(1000, events[0]->timestamp);
 
     VehiclePropValue value;
     StatusCode status;
@@ -1391,7 +1426,6 @@
     ASSERT_EQ((size_t)1, events.size());
     ASSERT_EQ((size_t)1, events[0]->value.floatValues.size());
     EXPECT_EQ(10.5, events[0]->value.floatValues[0]);
-    EXPECT_EQ(1000, events[0]->timestamp);
 
     VehiclePropValue value;
     StatusCode status;
diff --git a/automotive/vehicle/2.0/default/tests/fuzzer/VehicleManager_fuzzer.cpp b/automotive/vehicle/2.0/default/tests/fuzzer/VehicleManager_fuzzer.cpp
index 796c08f..4d0995d 100644
--- a/automotive/vehicle/2.0/default/tests/fuzzer/VehicleManager_fuzzer.cpp
+++ b/automotive/vehicle/2.0/default/tests/fuzzer/VehicleManager_fuzzer.cpp
@@ -76,30 +76,20 @@
 using ::android::hardware::automotive::vehicle::V2_0::vms::VmsLayerOffering;
 using ::android::hardware::automotive::vehicle::V2_0::vms::VmsOffers;
 
-constexpr const char kCarMake[] = "Default Car";
-constexpr VehicleProperty kVehicleProp[] = {VehicleProperty::INVALID,
-                                            VehicleProperty::HVAC_FAN_SPEED,
-                                            VehicleProperty::INFO_MAKE,
-                                            VehicleProperty::DISPLAY_BRIGHTNESS,
-                                            VehicleProperty::INFO_FUEL_CAPACITY,
-                                            VehicleProperty::HVAC_SEAT_TEMPERATURE};
-constexpr DiagnosticIntegerSensorIndex kDiagnosticIntIndex[] = {
-        DiagnosticIntegerSensorIndex::FUEL_SYSTEM_STATUS,
-        DiagnosticIntegerSensorIndex::MALFUNCTION_INDICATOR_LIGHT_ON,
-        DiagnosticIntegerSensorIndex::NUM_OXYGEN_SENSORS_PRESENT,
-        DiagnosticIntegerSensorIndex::FUEL_TYPE};
-constexpr DiagnosticFloatSensorIndex kDiagnosticFloatIndex[] = {
-        DiagnosticFloatSensorIndex::CALCULATED_ENGINE_LOAD,
-        DiagnosticFloatSensorIndex::SHORT_TERM_FUEL_TRIM_BANK1,
-        DiagnosticFloatSensorIndex::LONG_TERM_FUEL_TRIM_BANK1,
-        DiagnosticFloatSensorIndex::THROTTLE_POSITION};
-constexpr size_t kVehiclePropArrayLength = std::size(kVehicleProp);
-constexpr size_t kIntSensorArrayLength = std::size(kDiagnosticIntIndex);
-constexpr size_t kFloatSensorArrayLength = std::size(kDiagnosticFloatIndex);
-constexpr VmsMessageType kAvailabilityMessageType[] = {VmsMessageType::AVAILABILITY_CHANGE,
-                                                       VmsMessageType::AVAILABILITY_RESPONSE};
-constexpr VmsMessageType kSubscriptionMessageType[] = {VmsMessageType::SUBSCRIPTIONS_CHANGE,
-                                                       VmsMessageType::SUBSCRIPTIONS_RESPONSE};
+std::string kCarMake;
+constexpr int32_t kMaxCaseMessage = 8;
+constexpr int32_t kMaxRuns = 20;
+constexpr int32_t kMaxSize = 1000;
+constexpr int32_t kMinSize = 0;
+constexpr int32_t kMaxFileSize = 100;
+float kFloatValue;
+std::vector<int32_t> kVec32;
+std::vector<int64_t> kVec64;
+std::vector<uint8_t> kVec8;
+std::vector<float> kVecFloat;
+static const std::vector<std::string> kSampleDtcs = {"P0070",
+                                                     "P0102"
+                                                     "P0123"};
 
 MockedVehicleHal::VehiclePropValuePtr MockedVehicleHal::get(
         const VehiclePropValue& requestedPropValue, StatusCode* outStatus) {
@@ -113,23 +103,23 @@
 
     switch (property) {
         case VehicleProperty::INFO_MAKE:
-            pValue = getValuePool()->obtainString(kCarMake);
+            pValue = getValuePool()->obtainString(kCarMake.c_str());
             break;
         case VehicleProperty::INFO_FUEL_CAPACITY:
             if (mFuelCapacityAttemptsLeft-- > 0) {
                 *outStatus = StatusCode::TRY_AGAIN;
             } else {
-                pValue = getValuePool()->obtainFloat(42.42);
+                pValue = getValuePool()->obtainFloat(kFloatValue);
             }
             break;
         default:
             if (requestedPropValue.prop == kCustomComplexProperty) {
                 pValue = getValuePool()->obtainComplex();
-                pValue->value.int32Values = hidl_vec<int32_t>{10, 20};
-                pValue->value.int64Values = hidl_vec<int64_t>{30, 40};
-                pValue->value.floatValues = hidl_vec<float_t>{1.1, 2.2};
-                pValue->value.bytes = hidl_vec<uint8_t>{1, 2, 3};
-                pValue->value.stringValue = kCarMake;
+                pValue->value.int32Values = hidl_vec<int32_t>{kVec32};
+                pValue->value.int64Values = hidl_vec<int64_t>{kVec64};
+                pValue->value.floatValues = hidl_vec<float_t>{kVecFloat};
+                pValue->value.bytes = hidl_vec<uint8_t>{kVec8};
+                pValue->value.stringValue = kCarMake.c_str();
                 break;
             }
             auto key = makeKey(toInt(property), areaId);
@@ -145,26 +135,73 @@
     return pValue;
 }
 
+void VehicleHalManagerFuzzer::initValue() {
+    kCarMake = mFuzzedDataProvider->ConsumeRandomLengthString(kMaxFileSize);
+    kFloatValue = mFuzzedDataProvider->ConsumeFloatingPoint<float>();
+    fillParameter<int32_t>(mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize),
+                           kVec32);
+    fillParameter<int64_t>(mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize),
+                           kVec64);
+    fillParameter<uint8_t>(mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize),
+                           kVec8);
+    size_t size = mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize);
+    for (size_t i = 0; i < size; ++i) {
+        kVecFloat.push_back(mFuzzedDataProvider->ConsumeFloatingPoint<float>());
+    }
+}
+
 void VehicleHalManagerFuzzer::process(const uint8_t* data, size_t size) {
     mFuzzedDataProvider = new FuzzedDataProvider(data, size);
-    invokeDebug();
-    invokePropConfigs();
-    invokeSubscribe();
-    invokeSetAndGetValues();
-    invokeObd2SensorStore();
-    invokeVmsUtils();
-    invokeVehiclePropStore();
-    invokeWatchDogClient();
+    initValue();
+    /* Limited while loop runs to prevent timeouts caused
+     * by repeated calls to high-execution-time APIs.
+     */
+    size_t maxRuns = mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxRuns);
+    size_t itr = 0;
+    while (mFuzzedDataProvider->remaining_bytes() && ++itr <= maxRuns) {
+        auto invokeVehicleHalManagerFuzzer =
+                mFuzzedDataProvider->PickValueInArray<const std::function<void()>>({
+                        [&]() { invokeDebug(); },
+                        [&]() { invokePropConfigs(); },
+                        [&]() { invokeSubscribe(); },
+                        [&]() { invokeSetAndGetValues(); },
+                        [&]() { invokeObd2SensorStore(); },
+                        [&]() { invokeVmsUtils(); },
+                        [&]() { invokeVehiclePropStore(); },
+                        [&]() { invokeWatchDogClient(); },
+                });
+        invokeVehicleHalManagerFuzzer();
+    }
 }
 
 void VehicleHalManagerFuzzer::invokeDebug() {
-    hidl_string debugOption = mFuzzedDataProvider->PickValueInArray(
-            {"--help", "--list", "--get", "--set", "", "invalid"});
     hidl_handle fd = {};
-    fd.setTo(native_handle_create(/*numFds=*/1, /*numInts=*/0), /*shouldOwn=*/true);
 
-    mManager->debug(fd, {});
-    mManager->debug(fd, {debugOption});
+    native_handle_t* rawHandle = native_handle_create(/*numFds=*/1, /*numInts=*/0);
+    fd.setTo(native_handle_clone(rawHandle), /*shouldOwn=*/true);
+    int32_t size = mFuzzedDataProvider->ConsumeIntegralInRange<int32_t>(kMinSize, kMaxFileSize);
+    hidl_vec<hidl_string> options(size);
+
+    for (int32_t idx = 0; idx < size; ++idx) {
+        if (idx == 0 && mFuzzedDataProvider->ConsumeBool()) {
+            options[idx] = mFuzzedDataProvider->PickValueInArray(
+                    {"--help", "--list", "--get", "--set", "", "invalid"});
+        } else if (idx == 2 && mFuzzedDataProvider->ConsumeBool()) {
+            options[idx] =
+                    mFuzzedDataProvider->PickValueInArray({"-i", "-i64", "-f", "-s", "-b", "-a"});
+        } else if (mFuzzedDataProvider->ConsumeBool()) {
+            options[idx] = mFuzzedDataProvider->ConsumeRandomLengthString(kMaxSize);
+        } else {
+            options[idx] = std::to_string(mFuzzedDataProvider->ConsumeIntegral<int32_t>());
+        }
+    }
+
+    if (mFuzzedDataProvider->ConsumeBool()) {
+        mManager->debug(fd, {});
+    } else {
+        mManager->debug(fd, options);
+    }
+    native_handle_delete(rawHandle);
 }
 
 void VehicleHalManagerFuzzer::invokePropConfigs() {
@@ -172,178 +209,245 @@
     int32_t vehicleProp2 = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
 
     hidl_vec<int32_t> properties = {vehicleProp1, vehicleProp2};
+    auto invokePropConfigsAPI = mFuzzedDataProvider->PickValueInArray<const std::function<void()>>({
+            [&]() {
+                mManager->getPropConfigs(
+                        properties, []([[maybe_unused]] StatusCode status,
+                                       [[maybe_unused]] const hidl_vec<VehiclePropConfig>& c) {});
+            },
+            [&]() {
+                mManager->getPropConfigs(
+                        {mFuzzedDataProvider->ConsumeIntegral<int32_t>()},
+                        []([[maybe_unused]] StatusCode status,
+                           [[maybe_unused]] const hidl_vec<VehiclePropConfig>& c) {});
+            },
+            [&]() {
+                mManager->getAllPropConfigs(
+                        []([[maybe_unused]] const hidl_vec<VehiclePropConfig>& propConfigs) {});
+            },
 
-    mManager->getPropConfigs(properties,
-                             []([[maybe_unused]] StatusCode status,
-                                [[maybe_unused]] const hidl_vec<VehiclePropConfig>& c) {});
-
-    mManager->getPropConfigs({toInt(kVehicleProp[abs(vehicleProp1) % kVehiclePropArrayLength])},
-                             []([[maybe_unused]] StatusCode status,
-                                [[maybe_unused]] const hidl_vec<VehiclePropConfig>& c) {});
-
-    mManager->getAllPropConfigs(
-            []([[maybe_unused]] const hidl_vec<VehiclePropConfig>& propConfigs) {});
+    });
+    invokePropConfigsAPI();
 }
 
 void VehicleHalManagerFuzzer::invokeSubscribe() {
-    int32_t vehicleProp1 = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
     int32_t vehicleProp2 = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
     int32_t vehicleProp3 = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
 
-    const auto prop1 = toInt(kVehicleProp[abs(vehicleProp1) % kVehiclePropArrayLength]);
     sp<MockedVehicleCallback> cb = new MockedVehicleCallback();
+    VehiclePropertyType type =
+            static_cast<VehiclePropertyType>(mFuzzedDataProvider->ConsumeIntegral<int32_t>());
 
-    hidl_vec<SubscribeOptions> options = {
-            SubscribeOptions{.propId = prop1, .flags = SubscribeFlags::EVENTS_FROM_CAR}};
+    auto invokeSubscribeAPI = mFuzzedDataProvider->PickValueInArray<const std::function<void()>>({
+            [&]() {
+                size_t size =
+                        mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize);
+                hidl_vec<SubscribeOptions> options(size);
+                for (size_t idx = 0; idx < size; ++idx) {
+                    options[idx] = {SubscribeOptions{
+                            .propId = mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+                            .flags = static_cast<SubscribeFlags>(
+                                    mFuzzedDataProvider->ConsumeIntegral<int32_t>())}};
+                }
+                mManager->subscribe(cb, options);
+            },
+            [&]() {
+                auto unsubscribedValue = mObjectPool->obtain(type);
+                if (!unsubscribedValue) {
+                    return;
+                }
+                unsubscribedValue->prop = vehicleProp2;
+                unsubscribedValue->value.int32Values[0] = INT32_MAX;
+                mHal->sendPropEvent(std::move(unsubscribedValue));
+                cb->waitForExpectedEvents(mFuzzedDataProvider->ConsumeIntegral<size_t>());
+            },
+            [&]() {
+                const auto prop1 = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
+                mManager->unsubscribe(cb, prop1);
+            },
+            [&]() {
+                mHal->sendHalError(StatusCode::TRY_AGAIN, vehicleProp3,
+                                   mFuzzedDataProvider->ConsumeIntegral<int32_t>() /*areaId=*/);
+            },
 
-    mManager->subscribe(cb, options);
-
-    auto unsubscribedValue = mObjectPool->obtain(VehiclePropertyType::INT32);
-    unsubscribedValue->prop = toInt(kVehicleProp[abs(vehicleProp2) % kVehiclePropArrayLength]);
-
-    mHal->sendPropEvent(std::move(unsubscribedValue));
-    cb->getReceivedEvents();
-    cb->waitForExpectedEvents(0);
-
-    auto subscribedValue = mObjectPool->obtain(VehiclePropertyType::INT32);
-    subscribedValue->prop = toInt(kVehicleProp[abs(vehicleProp2) % kVehiclePropArrayLength]);
-    subscribedValue->value.int32Values[0] = INT32_MAX;
-
-    cb->reset();
-    VehiclePropValue actualValue(*subscribedValue.get());
-    mHal->sendPropEvent(std::move(subscribedValue));
-    cb->waitForExpectedEvents(1);
-    mManager->unsubscribe(cb, prop1);
-
-    sp<MockedVehicleCallback> cb2 = new MockedVehicleCallback();
-
-    hidl_vec<SubscribeOptions> options2 = {
-            SubscribeOptions{
-                    .propId = toInt(kVehicleProp[abs(vehicleProp3) % kVehiclePropArrayLength]),
-                    .flags = SubscribeFlags::EVENTS_FROM_CAR},
-    };
-
-    mManager->subscribe(cb2, options2);
-
-    mHal->sendHalError(StatusCode::TRY_AGAIN,
-                       toInt(kVehicleProp[abs(vehicleProp3) % kVehiclePropArrayLength]),
-                       /*areaId=*/0);
+    });
+    invokeSubscribeAPI();
 }
 
 void VehicleHalManagerFuzzer::invokeSetAndGetValues() {
-    uint32_t vehicleProp1 =
-            mFuzzedDataProvider->ConsumeIntegralInRange<uint32_t>(0, kVehiclePropArrayLength - 1);
-    uint32_t vehicleProp2 =
-            mFuzzedDataProvider->ConsumeIntegralInRange<uint32_t>(0, kVehiclePropArrayLength - 1);
-    uint32_t vehicleProp3 =
-            mFuzzedDataProvider->ConsumeIntegralInRange<uint32_t>(0, kVehiclePropArrayLength - 1);
-
-    invokeGet(kCustomComplexProperty, 0);
-    invokeGet(toInt(kVehicleProp[vehicleProp2]), 0);
-    invokeGet(toInt(kVehicleProp[vehicleProp1]), 0);
-
-    auto expectedValue = mObjectPool->obtainInt32(mFuzzedDataProvider->ConsumeIntegral<int32_t>());
-    mObjectPool->obtainInt64(mFuzzedDataProvider->ConsumeIntegral<int64_t>());
-    mObjectPool->obtainFloat(mFuzzedDataProvider->ConsumeFloatingPoint<float>());
-    mObjectPool->obtainBoolean(mFuzzedDataProvider->ConsumeBool());
-    expectedValue->prop = toInt(kVehicleProp[vehicleProp2]);
-    expectedValue->areaId = 0;
-
-    mManager->set(*expectedValue.get());
-    invokeGet(toInt(kVehicleProp[vehicleProp2]), 0);
-    expectedValue->prop = toInt(kVehicleProp[vehicleProp3]);
-    mManager->set(*expectedValue.get());
-    expectedValue->prop = toInt(VehicleProperty::INVALID);
-    mManager->set(*expectedValue.get());
+    auto invokeSetAndGetAPI = mFuzzedDataProvider->PickValueInArray<const std::function<void()>>({
+            [&]() {
+                invokeGet(mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+                          mFuzzedDataProvider->ConsumeIntegral<int32_t>());
+            },
+            [&]() { mObjectPool->obtainInt64(mFuzzedDataProvider->ConsumeIntegral<int64_t>()); },
+            [&]() { mObjectPool->obtainFloat(mFuzzedDataProvider->ConsumeFloatingPoint<float>()); },
+            [&]() { mObjectPool->obtainBoolean(mFuzzedDataProvider->ConsumeBool()); },
+            [&]() {
+                int32_t vehicleProp2 = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
+                auto expectedValue =
+                        mObjectPool->obtainInt32(mFuzzedDataProvider->ConsumeIntegral<int32_t>());
+                expectedValue->prop = vehicleProp2;
+                expectedValue->areaId = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
+                mManager->set(*expectedValue.get());
+            },
+    });
+    invokeSetAndGetAPI();
 }
 
 void VehicleHalManagerFuzzer::invokeObd2SensorStore() {
-    uint32_t diagnosticIntIndex =
-            mFuzzedDataProvider->ConsumeIntegralInRange<uint32_t>(0, kIntSensorArrayLength - 1);
-    int32_t diagnosticIntValue = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
-    uint32_t diagnosticFloatIndex =
-            mFuzzedDataProvider->ConsumeIntegralInRange<uint32_t>(0, kFloatSensorArrayLength - 1);
-    float diagnosticFloatValue = mFuzzedDataProvider->ConsumeFloatingPoint<float>();
+    size_t diagnosticInt = mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize);
+    size_t diagnosticFloat =
+            mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize);
 
     std::unique_ptr<Obd2SensorStore> sensorStore(
-            new Obd2SensorStore(kIntSensorArrayLength, kFloatSensorArrayLength));
-    if (sensorStore) {
-        sensorStore->setIntegerSensor(kDiagnosticIntIndex[diagnosticIntIndex], diagnosticIntValue);
-        sensorStore->setFloatSensor(kDiagnosticFloatIndex[diagnosticFloatIndex],
-                                    diagnosticFloatValue);
-        sensorStore->getIntegerSensors();
-        sensorStore->getFloatSensors();
-        sensorStore->getSensorsBitmask();
-        static std::vector<std::string> sampleDtcs = {"P0070",
-                                                      "P0102"
-                                                      "P0123"};
-        for (auto&& dtc : sampleDtcs) {
-            auto freezeFrame = createVehiclePropValue(VehiclePropertyType::MIXED, 0);
-            sensorStore->fillPropValue(dtc, freezeFrame.get());
-            freezeFrame->prop = static_cast<int>(VehicleProperty::OBD2_FREEZE_FRAME);
-        }
+            new Obd2SensorStore(diagnosticInt, diagnosticFloat));
+
+    if (!sensorStore.get()) {
+        return;
     }
+
+    auto invokeObd2SensorStoreAPI =
+            mFuzzedDataProvider->PickValueInArray<const std::function<void()>>({
+                    [&]() {
+                        int32_t diagnosticIntValue =
+                                mFuzzedDataProvider->ConsumeIntegral<int32_t>();
+                        int32_t diagnosticIntIndex =
+                                mFuzzedDataProvider->ConsumeIntegralInRange<int32_t>(
+                                        kMinSize,
+                                        toInt(DiagnosticIntegerSensorIndex::LAST_SYSTEM_INDEX) +
+                                                diagnosticInt);
+                        sensorStore->setIntegerSensor(
+                                static_cast<DiagnosticIntegerSensorIndex>(diagnosticIntIndex),
+                                diagnosticIntValue);
+                    },
+                    [&]() {
+                        float diagnosticFloatValue =
+                                mFuzzedDataProvider->ConsumeFloatingPoint<float>();
+                        int32_t diagnosticFloatIndex =
+                                mFuzzedDataProvider->ConsumeIntegralInRange<int32_t>(
+                                        kMinSize,
+                                        toInt(DiagnosticFloatSensorIndex::LAST_SYSTEM_INDEX) +
+                                                diagnosticFloat);
+                        sensorStore->setFloatSensor(
+                                static_cast<DiagnosticFloatSensorIndex>(diagnosticFloatIndex),
+                                diagnosticFloatValue);
+                    },
+                    [&]() { sensorStore->getIntegerSensors(); },
+                    [&]() { sensorStore->getFloatSensors(); },
+                    [&]() { sensorStore->getSensorsBitmask(); },
+                    [&]() {
+                        for (auto&& dtc : kSampleDtcs) {
+                            VehiclePropertyType type = static_cast<VehiclePropertyType>(
+                                    mFuzzedDataProvider->ConsumeIntegral<int32_t>());
+                            auto freezeFrame = createVehiclePropValue(
+                                    type, mFuzzedDataProvider->ConsumeIntegralInRange<int32_t>(
+                                                  kMinSize, kMaxSize));
+                            if (!freezeFrame.get()) {
+                                return;
+                            }
+                            freezeFrame->prop = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
+                            sensorStore->fillPropValue(dtc, freezeFrame.get());
+                        }
+                    },
+            });
+    invokeObd2SensorStoreAPI();
 }
 
 void VehicleHalManagerFuzzer::invokeVmsUtils() {
-    bool availabilityMsgType = mFuzzedDataProvider->ConsumeBool();
-    bool subscriptionMsgType = mFuzzedDataProvider->ConsumeBool();
+    std::unique_ptr<VehiclePropValue> message;
     int32_t intValue = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
+    VmsLayer layer(mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+                   mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+                   mFuzzedDataProvider->ConsumeIntegral<int32_t>());
+    VmsOffers offers = {
+            intValue,
+            {VmsLayerOffering(VmsLayer(mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+                                       mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+                                       mFuzzedDataProvider->ConsumeIntegral<int32_t>()))}};
+    const VmsLayerAndPublisher layer_and_publisher(
+            VmsLayer(mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+                     mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+                     mFuzzedDataProvider->ConsumeIntegral<int32_t>()),
+            intValue);
 
-    VmsLayer layer(1, 0, 2);
-    auto message = createSubscribeMessage(layer);
+    switch (mFuzzedDataProvider->ConsumeIntegralInRange<int32_t>(kMinSize, kMaxCaseMessage)) {
+        case 0: {
+            message = createSubscribeMessage(layer);
+            break;
+        }
+        case 1: {
+            message = createUnsubscribeMessage(layer);
+            break;
+        }
+        case 2: {
+            message = createSubscriptionsRequest();
+            break;
+        }
+        case 3: {
+            message = createOfferingMessage(offers);
+            break;
+        }
+        case 4: {
+            message = createAvailabilityRequest();
+            break;
+        }
+        case 5: {
+            std::string pub_bytes;
+            if (mFuzzedDataProvider->ConsumeBool()) {
+                pub_bytes = "pub_id";
+            } else {
+                pub_bytes = mFuzzedDataProvider->ConsumeRandomLengthString(kMaxFileSize);
+            }
+            message = createPublisherIdRequest(pub_bytes);
+            break;
+        }
+        case 6: {
+            std::string bytes = "placeholder";
+            if (mFuzzedDataProvider->ConsumeBool()) {
+                bytes = "placeholder";
+            } else {
+                bytes = mFuzzedDataProvider->ConsumeRandomLengthString(kMaxFileSize);
+            }
+            message = createDataMessageWithLayerPublisherInfo(layer_and_publisher, bytes);
+            break;
+        }
+        case 7: {
+            message = createBaseVmsMessage(
+                    mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize));
+            break;
+        }
+        case 8: {
+            message = createStartSessionMessage(intValue, intValue + 1);
+            break;
+        }
+    }
+
     isValidVmsMessage(*message);
-    message = createUnsubscribeMessage(layer);
-
-    VmsOffers offers = {intValue, {VmsLayerOffering(VmsLayer(1, 0, 2))}};
-    message = createOfferingMessage(offers);
-    std::vector<VmsLayer> dependencies = {VmsLayer(2, 0, 2), VmsLayer(3, 0, 3)};
-    std::vector<VmsLayerOffering> offering = {VmsLayerOffering(layer, dependencies)};
-    offers = {intValue, offering};
-    message = createOfferingMessage(offers);
-
-    message = createAvailabilityRequest();
-    message = createSubscriptionsRequest();
-
-    std::string bytes = "placeholder";
-    const VmsLayerAndPublisher layer_and_publisher(VmsLayer(2, 0, 1), intValue);
-    message = createDataMessageWithLayerPublisherInfo(layer_and_publisher, bytes);
-    parseData(*message);
-    createSubscribeToPublisherMessage(layer_and_publisher);
-    createUnsubscribeToPublisherMessage(layer_and_publisher);
-
-    std::string pub_bytes = "pub_id";
-    message = createPublisherIdRequest(pub_bytes);
-    message = createBaseVmsMessage(2);
     message->value.int32Values =
-            hidl_vec<int32_t>{toInt(VmsMessageType::PUBLISHER_ID_RESPONSE), intValue};
-    parsePublisherIdResponse(*message);
+            hidl_vec<int32_t>{mFuzzedDataProvider->ConsumeIntegral<int32_t>(), intValue};
 
-    message->value.int32Values =
-            hidl_vec<int32_t>{toInt(kSubscriptionMessageType[subscriptionMsgType]), intValue};
-    getSequenceNumberForSubscriptionsState(*message);
-
-    message->value.int32Values = hidl_vec<int32_t>{toInt(kSubscriptionMessageType[0]), intValue};
-    isSequenceNumberNewer(*message, intValue + 1);
-    invokeGetSubscribedLayers(kSubscriptionMessageType[subscriptionMsgType]);
-
-    message->value.int32Values =
-            hidl_vec<int32_t>{toInt(kAvailabilityMessageType[availabilityMsgType]), 0};
-    hasServiceNewlyStarted(*message);
-    message = createStartSessionMessage(intValue, intValue + 1);
-    parseMessageType(*message);
-
-    message->value.int32Values =
-            hidl_vec<int32_t>{toInt(kAvailabilityMessageType[availabilityMsgType]), intValue};
-    isAvailabilitySequenceNumberNewer(*message, intValue + 1);
-
-    message->value.int32Values =
-            hidl_vec<int32_t>{toInt(kAvailabilityMessageType[availabilityMsgType]), intValue};
-    getSequenceNumberForAvailabilityState(*message);
-    message = createBaseVmsMessage(3);
-    int new_service_id;
-    message->value.int32Values = hidl_vec<int32_t>{toInt(VmsMessageType::START_SESSION), 0, -1};
-    parseStartSessionMessage(*message, -1, 0, &new_service_id);
+    auto invokeVmsUtilsAPI = mFuzzedDataProvider->PickValueInArray<const std::function<void()>>({
+            [&]() { parseData(*message); },
+            [&]() { createSubscribeToPublisherMessage(layer_and_publisher); },
+            [&]() { createUnsubscribeToPublisherMessage(layer_and_publisher); },
+            [&]() { parsePublisherIdResponse(*message); },
+            [&]() { getSequenceNumberForSubscriptionsState(*message); },
+            [&]() { isSequenceNumberNewer(*message, intValue + 1); },
+            [&]() {
+                invokeGetSubscribedLayers(
+                        (VmsMessageType)mFuzzedDataProvider->ConsumeIntegral<int32_t>());
+            },
+            [&]() { hasServiceNewlyStarted(*message); },
+            [&]() { parseMessageType(*message); },
+            [&]() { isAvailabilitySequenceNumberNewer(*message, intValue + 1); },
+            [&]() { getSequenceNumberForAvailabilityState(*message); },
+            [&]() {
+                int32_t new_service_id;
+                parseStartSessionMessage(*message, -1, 0, &new_service_id);
+            },
+    });
+    invokeVmsUtilsAPI();
 }
 
 void VehicleHalManagerFuzzer::invokeGet(int32_t property, int32_t areaId) {
@@ -364,27 +468,31 @@
     mActualStatusCode = refStatus;
 }
 
-void VehicleHalManagerFuzzer::invokeGetSubscribedLayers(VmsMessageType type) {
-    VmsOffers offers = {123,
-                        {VmsLayerOffering(VmsLayer(1, 0, 1), {VmsLayer(4, 1, 1)}),
-                         VmsLayerOffering(VmsLayer(2, 0, 1))}};
-    auto message = createBaseVmsMessage(16);
-    message->value.int32Values = hidl_vec<int32_t>{toInt(type),
-                                                   1234,  // sequence number
-                                                   2,     // number of layers
-                                                   1,     // number of associated layers
-                                                   1,     // layer 1
-                                                   0,           1,
-                                                   4,  // layer 2
-                                                   1,           1,
-                                                   2,  // associated layer
-                                                   0,           1,
-                                                   2,    // number of publisher IDs
-                                                   111,  // publisher IDs
-                                                   123};
-    isValidVmsMessage(*message);
-    getSubscribedLayers(*message, offers);
-    getAvailableLayers(*message);
+void VehicleHalManagerFuzzer::invokeGetSubscribedLayers(VmsMessageType /*type*/) {
+    int32_t intValue = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
+    VmsOffers offers = {
+            intValue,
+            {VmsLayerOffering(VmsLayer(mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+                                       mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+                                       mFuzzedDataProvider->ConsumeIntegral<int32_t>()))}};
+    auto message = createBaseVmsMessage(
+            mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxFileSize));
+    std::vector<int32_t> v;
+    size_t size = mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize);
+    for (size_t i = 0; i < size; i++) {
+        v.push_back(mFuzzedDataProvider->ConsumeIntegralInRange<int32_t>(kMinSize, kMaxSize));
+    }
+
+    message->value.int32Values = hidl_vec<int32_t>(v);
+    if (!isValidVmsMessage(*message)) {
+        return;
+    }
+
+    if (mFuzzedDataProvider->ConsumeBool()) {
+        getSubscribedLayers(*message, offers);
+    } else {
+        getAvailableLayers(*message);
+    }
 }
 
 void VehicleHalManagerFuzzer::invokeVehiclePropStore() {
@@ -395,33 +503,49 @@
             .prop = vehicleProp,
             .access = VehiclePropertyAccess::READ,
             .changeMode = VehiclePropertyChangeMode::STATIC,
-            .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+            .areaConfigs = {VehicleAreaConfig{
+                    .areaId = (mFuzzedDataProvider->ConsumeIntegral<int32_t>())}},
     };
-    store->registerProperty(config);
     VehiclePropValue propValue{};
     propValue.prop = vehicleProp;
-    propValue.areaId = 0;
-    store->writeValue(propValue, shouldWriteStatus);
-    store->readAllValues();
-    store->getAllConfigs();
-    store->getConfigOrNull(vehicleProp);
-    store->readValuesForProperty(vehicleProp);
-    store->readValueOrNull(propValue);
-    store->readValueOrNull(propValue.prop, propValue.areaId, 0);
-    store->removeValuesForProperty(vehicleProp);
-    store->removeValue(propValue);
-    store->getConfigOrDie(vehicleProp);
+    propValue.areaId = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
+
+    auto invokeVehiclePropStoreAPI =
+            mFuzzedDataProvider->PickValueInArray<const std::function<void()>>({
+                    [&]() { store->registerProperty(config); },
+                    [&]() { store->writeValue(propValue, shouldWriteStatus); },
+                    [&]() { store->readAllValues(); },
+                    [&]() { store->getAllConfigs(); },
+                    [&]() { store->getConfigOrNull(vehicleProp); },
+                    [&]() { store->readValuesForProperty(vehicleProp); },
+                    [&]() { store->readValueOrNull(propValue); },
+                    [&]() {
+                        store->readValueOrNull(propValue.prop, propValue.areaId,
+                                               mFuzzedDataProvider->ConsumeIntegralInRange<int64_t>(
+                                                       kMinSize, kMaxFileSize));
+                    },
+                    [&]() { store->removeValuesForProperty(vehicleProp); },
+                    [&]() { store->removeValue(propValue); },
+                    [&]() {
+                        if (store->getConfigOrNull(vehicleProp)) {
+                            store->getConfigOrDie(vehicleProp);
+                        }
+                    },
+            });
+    invokeVehiclePropStoreAPI();
 }
 
 void VehicleHalManagerFuzzer::invokeWatchDogClient() {
-    auto service = new VehicleHalManager(mHal.get());
     sp<Looper> looper(Looper::prepare(/*opts=*/mFuzzedDataProvider->ConsumeBool()));
-    if (auto watchdogClient = ndk::SharedRefBase::make<WatchdogClient>(looper, service);
+    if (auto watchdogClient = ndk::SharedRefBase::make<WatchdogClient>(looper, mManager.get());
         watchdogClient->initialize()) {
-        watchdogClient->checkIfAlive(-1, TimeoutLength::TIMEOUT_NORMAL);
+        if (mFuzzedDataProvider->ConsumeBool()) {
+            watchdogClient->checkIfAlive(
+                    mFuzzedDataProvider->ConsumeIntegral<int32_t>(),
+                    (TimeoutLength)mFuzzedDataProvider->ConsumeIntegral<int32_t>());
+        }
         watchdogClient->prepareProcessTermination();
     }
-    delete service;
 }
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
diff --git a/automotive/vehicle/2.0/default/tests/fuzzer/VehicleManager_fuzzer.h b/automotive/vehicle/2.0/default/tests/fuzzer/VehicleManager_fuzzer.h
index e9335d3..26ac11e 100644
--- a/automotive/vehicle/2.0/default/tests/fuzzer/VehicleManager_fuzzer.h
+++ b/automotive/vehicle/2.0/default/tests/fuzzer/VehicleManager_fuzzer.h
@@ -98,6 +98,13 @@
     }
     void process(const uint8_t* data, size_t size);
 
+    template <typename T>
+    void fillParameter(size_t size, std::vector<T>& data) {
+        for (size_t i = 0; i < size; ++i) {
+            data.push_back(mFuzzedDataProvider->ConsumeIntegral<T>());
+        }
+    }
+
   private:
     FuzzedDataProvider* mFuzzedDataProvider = nullptr;
     VehiclePropValue mActualValue = VehiclePropValue{};
@@ -108,6 +115,7 @@
     std::unique_ptr<VehicleHalManager> mManager;
 
     void invokeDebug();
+    void initValue();
     void invokePropConfigs();
     void invokeSubscribe();
     void invokeSetAndGetValues();
diff --git a/automotive/vehicle/Android.bp b/automotive/vehicle/Android.bp
index c0d71d7..3549519 100644
--- a/automotive/vehicle/Android.bp
+++ b/automotive/vehicle/Android.bp
@@ -21,7 +21,7 @@
 cc_defaults {
     name: "VehicleHalInterfaceDefaults",
     static_libs: [
-        "android.hardware.automotive.vehicle-V2-ndk",
-        "android.hardware.automotive.vehicle.property-V2-ndk",
+        "android.hardware.automotive.vehicle-V3-ndk",
+        "android.hardware.automotive.vehicle.property-V3-ndk",
     ],
 }
diff --git a/automotive/vehicle/OWNERS b/automotive/vehicle/OWNERS
index 429ec39..9a6b65d 100644
--- a/automotive/vehicle/OWNERS
+++ b/automotive/vehicle/OWNERS
@@ -1,3 +1,9 @@
 ericjeong@google.com
-keunyoung@google.com
 shanyu@google.com
+
+# GRPC VHAL
+per-file aidl/impl/grpc/** = chenhaosjtuacm@google.com, egranata@google.com
+
+# Property definition
+per-file aidl_property/** = tylertrephan@google.com
+per-file aidl/generated_lib/** = tylertrephan@google.com
diff --git a/automotive/vehicle/TEST_MAPPING b/automotive/vehicle/TEST_MAPPING
index da8416c..e1a90cb 100644
--- a/automotive/vehicle/TEST_MAPPING
+++ b/automotive/vehicle/TEST_MAPPING
@@ -43,6 +43,17 @@
   "auto-presubmit": [
     {
       "name": "VtsHalAutomotiveVehicle_TargetTest"
+    },
+    {
+      "name": "CarServiceUnitTest",
+      "options" : [
+        {
+          "include-filter": "com.android.car.hal.fakevhal.FakeVehicleStubUnitTest"
+        }
+      ]
+    },
+    {
+      "name": "VehicleHalProtoMessageConverterTest"
     }
   ]
 }
diff --git a/automotive/vehicle/aidl/Android.bp b/automotive/vehicle/aidl/Android.bp
index 3b93bca..5ca1fc8 100644
--- a/automotive/vehicle/aidl/Android.bp
+++ b/automotive/vehicle/aidl/Android.bp
@@ -27,7 +27,7 @@
     srcs: [
         "android/hardware/automotive/vehicle/*.aidl",
     ],
-    frozen: true,
+    frozen: false,
     stability: "vintf",
     backend: {
         cpp: {
@@ -41,6 +41,9 @@
                 "com.android.car.framework",
             ],
         },
+        rust: {
+            enabled: true,
+        },
     },
     versions_with_info: [
         {
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/SubscribeOptions.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/SubscribeOptions.aidl
index 91e7c14..1b1696b 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/SubscribeOptions.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/SubscribeOptions.aidl
@@ -37,4 +37,6 @@
   int propId;
   int[] areaIds;
   float sampleRate;
+  float resolution = 0.0f;
+  boolean enableVariableUpdateRate;
 }
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl
index 6960894..08d4ee4 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl
@@ -42,4 +42,6 @@
   float minFloatValue;
   float maxFloatValue;
   @nullable long[] supportedEnumValues;
+  android.hardware.automotive.vehicle.VehiclePropertyAccess access = android.hardware.automotive.vehicle.VehiclePropertyAccess.NONE;
+  boolean supportVariableUpdateRate;
 }
diff --git a/automotive/vehicle/aidl/aidl_test/Android.bp b/automotive/vehicle/aidl/aidl_test/Android.bp
index 44d7445..bb976af 100644
--- a/automotive/vehicle/aidl/aidl_test/Android.bp
+++ b/automotive/vehicle/aidl/aidl_test/Android.bp
@@ -51,10 +51,10 @@
         ":IVehicleGeneratedJavaFiles",
     ],
     static_libs: [
-        "android.hardware.automotive.vehicle-V2-java",
-        "android.hardware.automotive.vehicle.property-V2-java",
+        "android.hardware.automotive.vehicle-V3-java",
+        "android.hardware.automotive.vehicle.property-V3-java",
         "androidx.test.runner",
-        "truth-prebuilt",
+        "truth",
     ],
     test_suites: ["general-tests"],
 }
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/SubscribeOptions.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/SubscribeOptions.aidl
index e68f7e3..14469b5 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/SubscribeOptions.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/SubscribeOptions.aidl
@@ -39,4 +39,29 @@
      * This value indicates how many updates per second client wants to receive.
      */
     float sampleRate;
+
+    /**
+     * Requested resolution of property updates.
+     *
+     * This value indicates the resolution at which continuous property updates should be sent to
+     * the platform. For example, if resolution is 0.01, the subscribed property value should be
+     * rounded to two decimal places. If the incoming resolution value is not an integer power of
+     * 10 (i.e. 10^-2, 10^-1, 10^2, etc.), VHAL should return a StatusCode::INVALID_ARG.
+     */
+    float resolution = 0.0f;
+
+    /**
+     * Whether to enable variable update rate.
+     *
+     * This only applies for continuous property. If variable update rate is
+     * enabled, for each given areaId, if VHAL supports variable update rate for
+     * the [propId, areaId], VHAL must ignore duplicate property value events
+     * and only sends changed value events (a.k.a treat continuous as an
+     * on-change property).
+     *
+     * If VHAL does not support variable update rate for the [propId, areaId],
+     * indicated by 'supportVariableUpdateRate' in 'VehicleAreaConfig', or if
+     * this property is not a continuous property, this option must be ignored.
+     */
+    boolean enableVariableUpdateRate;
 }
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl
index 20c046d..aab3c46 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl
@@ -16,6 +16,8 @@
 
 package android.hardware.automotive.vehicle;
 
+import android.hardware.automotive.vehicle.VehiclePropertyAccess;
+
 @VintfStability
 @JavaDerive(equals=true, toString=true)
 parcelable VehicleAreaConfig {
@@ -47,4 +49,55 @@
      * assumed all @data_enum values are supported unless specified through another mechanism.
      */
     @nullable long[] supportedEnumValues;
+
+    /**
+     * Defines if the area ID for this property is READ, WRITE or READ_WRITE. This only applies if
+     * the property is defined in the framework as a READ_WRITE property. Access (if set) should be
+     * equal to, or a superset of, the VehiclePropConfig.access of the property.
+     *
+     * For example, if a property is defined as READ_WRITE, but the OEM wants to specify certain
+     * area Ids as READ-only, the corresponding areaIds should have an access set to READ, while the
+     * others must be set to READ_WRITE. We do not support setting specific area Ids to WRITE-only
+     * when the property is READ-WRITE.
+     *
+     * Exclusively one of VehiclePropConfig and the VehicleAreaConfigs should be specified for a
+     * single property. If VehiclePropConfig.access is populated, none of the
+     * VehicleAreaConfig.access values should be populated. If VehicleAreaConfig.access values are
+     * populated, VehiclePropConfig.access must not be populated.
+     *
+     * VehicleAreaConfigs should not be partially populated with access. If the OEM wants to specify
+     * access for one area Id, all other configs should be populated with their access levels as
+     * well.
+     */
+    VehiclePropertyAccess access = VehiclePropertyAccess.NONE;
+
+    /**
+     * Whether variable update rate is supported.
+     *
+     * This applies for continuous property only.
+     *
+     * It is HIGHLY RECOMMENDED to support variable update rate for all non-heartbeat continuous
+     * properties for better performance unless the property is large.
+     *
+     * If variable update rate is supported and 'enableVariableUpdateRate' is true in subscribe
+     * options, VHAL must only sends property update event when the property's value changes
+     * (a.k.a treat continuous as an on-change property).
+     *
+     * E.g. if the client is subscribing at 5hz at time 0. If the property's value is 0 initially
+     * and becomes 1 after 1 second.
+
+     * If variable update rate is not enabled, VHAL clients will receive 5 property change events
+     * with value 0 and 5 events with value 1 after 2 seconds.
+     *
+     * If variable update rate is enabled, VHAL clients will receive 1 property change event
+     * with value 1 at time 1s. VHAL may/may not send a property event for the initial value (e.g.
+     * a property change event with value 0 at time 0s). VHAL client must not rely on the first
+     * property event, and must use getValues to fetch the initial value. In fact, car service is
+     * using getValues to fetch the initial value, convert it to a property event and deliver to
+     * car service clients.
+     *
+     * NOTE: If this is true, car service may cache the property update event for filtering purpose,
+     * so this should be false if the property is large (e.g. a byte array of 1k in size).
+     */
+    boolean supportVariableUpdateRate;
 }
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehiclePropConfig.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehiclePropConfig.aidl
index 61b9369..1135b26 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehiclePropConfig.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehiclePropConfig.aidl
@@ -28,6 +28,10 @@
 
     /**
      * Defines if the property is read or write or both.
+     *
+     * If populating VehicleAreaConfig.access fields for this property, this field should not be
+     * populated. If the OEM decides to populate this field, none of the VehicleAreaConfig.access
+     * fields should be populated.
      */
     VehiclePropertyAccess access = VehiclePropertyAccess.NONE;
 
diff --git a/automotive/vehicle/aidl/emu_metadata/android.hardware.automotive.vehicle-types-meta.json b/automotive/vehicle/aidl/emu_metadata/android.hardware.automotive.vehicle-types-meta.json
index e312a3a..6d856a8 100644
--- a/automotive/vehicle/aidl/emu_metadata/android.hardware.automotive.vehicle-types-meta.json
+++ b/automotive/vehicle/aidl/emu_metadata/android.hardware.automotive.vehicle-types-meta.json
@@ -1,34 +1,22 @@
 [
   {
-    "name": "VehicleApPowerStateReqIndex",
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleOilLevel",
     "values": [
       {
-        "name": "STATE",
+        "name": "CRITICALLY_LOW",
         "value": 0
       },
       {
-        "name": "ADDITIONAL",
-        "value": 1
-      }
-    ]
-  },
-  {
-    "name": "EvChargeState",
-    "values": [
-      {
-        "name": "UNKNOWN",
-        "value": 0
-      },
-      {
-        "name": "CHARGING",
+        "name": "LOW",
         "value": 1
       },
       {
-        "name": "FULLY_CHARGED",
+        "name": "NORMAL",
         "value": 2
       },
       {
-        "name": "NOT_CHARGING",
+        "name": "HIGH",
         "value": 3
       },
       {
@@ -38,220 +26,123 @@
     ]
   },
   {
-    "name": "TrailerState",
+    "package": "android.hardware.automotive.vehicle",
+    "name": "LocationCharacterization",
     "values": [
       {
-        "name": "UNKNOWN",
-        "value": 0
-      },
-      {
-        "name": "NOT_PRESENT",
+        "name": "PRIOR_LOCATIONS",
         "value": 1
       },
       {
-        "name": "PRESENT",
+        "name": "GYROSCOPE_FUSION",
         "value": 2
       },
       {
-        "name": "ERROR",
-        "value": 3
-      }
-    ]
-  },
-  {
-    "name": "ProcessTerminationReason",
-    "values": [
-      {
-        "name": "NOT_RESPONDING",
-        "value": 1
-      },
-      {
-        "name": "IO_OVERUSE",
-        "value": 2
-      },
-      {
-        "name": "MEMORY_OVERUSE",
-        "value": 3
-      }
-    ]
-  },
-  {
-    "name": "VehicleApPowerStateConfigFlag",
-    "values": [
-      {
-        "name": "ENABLE_DEEP_SLEEP_FLAG",
-        "value": 1
-      },
-      {
-        "name": "CONFIG_SUPPORT_TIMER_POWER_ON_FLAG",
-        "value": 2
-      },
-      {
-        "name": "ENABLE_HIBERNATION_FLAG",
-        "value": 3
-      }
-    ]
-  },
-  {
-    "name": "Obd2FuelType",
-    "values": [
-      {
-        "name": "NOT_AVAILABLE",
-        "value": 0
-      },
-      {
-        "name": "GASOLINE",
-        "value": 1
-      },
-      {
-        "name": "METHANOL",
-        "value": 2
-      },
-      {
-        "name": "ETHANOL",
-        "value": 3
-      },
-      {
-        "name": "DIESEL",
+        "name": "ACCELEROMETER_FUSION",
         "value": 4
       },
       {
-        "name": "LPG",
-        "value": 5
-      },
-      {
-        "name": "CNG",
-        "value": 6
-      },
-      {
-        "name": "PROPANE",
-        "value": 7
-      },
-      {
-        "name": "ELECTRIC",
+        "name": "COMPASS_FUSION",
         "value": 8
       },
       {
-        "name": "BIFUEL_RUNNING_GASOLINE",
-        "value": 9
-      },
-      {
-        "name": "BIFUEL_RUNNING_METHANOL",
-        "value": 10
-      },
-      {
-        "name": "BIFUEL_RUNNING_ETHANOL",
-        "value": 11
-      },
-      {
-        "name": "BIFUEL_RUNNING_LPG",
-        "value": 12
-      },
-      {
-        "name": "BIFUEL_RUNNING_CNG",
-        "value": 13
-      },
-      {
-        "name": "BIFUEL_RUNNING_PROPANE",
-        "value": 14
-      },
-      {
-        "name": "BIFUEL_RUNNING_ELECTRIC",
-        "value": 15
-      },
-      {
-        "name": "BIFUEL_RUNNING_ELECTRIC_AND_COMBUSTION",
+        "name": "WHEEL_SPEED_FUSION",
         "value": 16
       },
       {
-        "name": "HYBRID_GASOLINE",
-        "value": 17
+        "name": "STEERING_ANGLE_FUSION",
+        "value": 32
       },
       {
-        "name": "HYBRID_ETHANOL",
-        "value": 18
+        "name": "CAR_SPEED_FUSION",
+        "value": 64
       },
       {
-        "name": "HYBRID_DIESEL",
-        "value": 19
+        "name": "DEAD_RECKONED",
+        "value": 128
       },
       {
-        "name": "HYBRID_ELECTRIC",
-        "value": 20
-      },
-      {
-        "name": "HYBRID_RUNNING_ELECTRIC_AND_COMBUSTION",
-        "value": 21
-      },
-      {
-        "name": "HYBRID_REGENERATIVE",
-        "value": 22
-      },
-      {
-        "name": "BIFUEL_RUNNING_DIESEL",
-        "value": 23
+        "name": "RAW_GNSS_ONLY",
+        "value": 256
       }
     ]
   },
   {
-    "name": "VmsSubscriptionsStateIntegerValuesIndex",
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleDisplay",
     "values": [
       {
-        "name": "MESSAGE_TYPE",
+        "name": "MAIN",
         "value": 0
       },
       {
-        "name": "SEQUENCE_NUMBER",
+        "name": "INSTRUMENT_CLUSTER",
         "value": 1
       },
       {
-        "name": "NUMBER_OF_LAYERS",
+        "name": "HUD",
         "value": 2
       },
       {
-        "name": "NUMBER_OF_ASSOCIATED_LAYERS",
+        "name": "INPUT",
         "value": 3
       },
       {
-        "name": "SUBSCRIPTIONS_START",
+        "name": "AUXILIARY",
         "value": 4
       }
     ]
   },
   {
-    "name": "VehicleArea",
+    "package": "android.hardware.automotive.vehicle",
+    "name": "CruiseControlState",
     "values": [
       {
-        "name": "GLOBAL",
-        "value": 16777216
+        "name": "OTHER",
+        "value": 0
       },
       {
-        "name": "WINDOW",
-        "value": 50331648
+        "name": "ENABLED",
+        "value": 1
       },
       {
-        "name": "MIRROR",
-        "value": 67108864
+        "name": "ACTIVATED",
+        "value": 2
       },
       {
-        "name": "SEAT",
-        "value": 83886080
+        "name": "USER_OVERRIDE",
+        "value": 3
       },
       {
-        "name": "DOOR",
-        "value": 100663296
+        "name": "SUSPENDED",
+        "value": 4
       },
       {
-        "name": "WHEEL",
-        "value": 117440512
-      },
-      {
-        "name": "MASK",
-        "value": 251658240
+        "name": "FORCED_DEACTIVATION_WARNING",
+        "value": 5
       }
     ]
   },
   {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "HandsOnDetectionWarning",
+    "values": [
+      {
+        "name": "OTHER",
+        "value": 0
+      },
+      {
+        "name": "NO_WARNING",
+        "value": 1
+      },
+      {
+        "name": "WARNING",
+        "value": 2
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
     "name": "VehicleAreaWindow",
     "values": [
       {
@@ -297,27 +188,99 @@
     ]
   },
   {
-    "name": "ElectronicTollCollectionCardStatus",
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VmsAvailabilityStateIntegerValuesIndex",
     "values": [
       {
-        "name": "UNKNOWN",
+        "name": "MESSAGE_TYPE",
         "value": 0
       },
       {
-        "name": "ELECTRONIC_TOLL_COLLECTION_CARD_VALID",
+        "name": "SEQUENCE_NUMBER",
         "value": 1
       },
       {
-        "name": "ELECTRONIC_TOLL_COLLECTION_CARD_INVALID",
+        "name": "NUMBER_OF_ASSOCIATED_LAYERS",
         "value": 2
       },
       {
-        "name": "ELECTRONIC_TOLL_COLLECTION_CARD_NOT_INSERTED",
+        "name": "LAYERS_START",
         "value": 3
       }
     ]
   },
   {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleLightSwitch",
+    "values": [
+      {
+        "name": "OFF",
+        "value": 0
+      },
+      {
+        "name": "ON",
+        "value": 1
+      },
+      {
+        "name": "DAYTIME_RUNNING",
+        "value": 2
+      },
+      {
+        "name": "AUTOMATIC",
+        "value": 256
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "Obd2IgnitionMonitorKind",
+    "values": [
+      {
+        "name": "SPARK",
+        "value": 0
+      },
+      {
+        "name": "COMPRESSION",
+        "value": 1
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleHwMotionButtonStateFlag",
+    "values": [
+      {
+        "name": "BUTTON_PRIMARY",
+        "value": 1
+      },
+      {
+        "name": "BUTTON_SECONDARY",
+        "value": 2
+      },
+      {
+        "name": "BUTTON_TERTIARY",
+        "value": 4
+      },
+      {
+        "name": "BUTTON_BACK",
+        "value": 8
+      },
+      {
+        "name": "BUTTON_FORWARD",
+        "value": 16
+      },
+      {
+        "name": "BUTTON_STYLUS_PRIMARY",
+        "value": 32
+      },
+      {
+        "name": "BUTTON_STYLUS_SECONDARY",
+        "value": 64
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
     "name": "VehiclePropertyType",
     "values": [
       {
@@ -367,1694 +330,7 @@
     ]
   },
   {
-    "name": "StatusCode",
-    "values": [
-      {
-        "name": "OK",
-        "value": 0
-      },
-      {
-        "name": "TRY_AGAIN",
-        "value": 1
-      },
-      {
-        "name": "INVALID_ARG",
-        "value": 2
-      },
-      {
-        "name": "NOT_AVAILABLE",
-        "value": 3
-      },
-      {
-        "name": "ACCESS_DENIED",
-        "value": 4
-      },
-      {
-        "name": "INTERNAL_ERROR",
-        "value": 5
-      }
-    ]
-  },
-  {
-    "name": "CreateUserStatus",
-    "values": [
-      {
-        "name": "SUCCESS",
-        "value": 1
-      },
-      {
-        "name": "FAILURE",
-        "value": 2
-      }
-    ]
-  },
-  {
-    "name": "ElectronicTollCollectionCardType",
-    "values": [
-      {
-        "name": "UNKNOWN",
-        "value": 0
-      },
-      {
-        "name": "JP_ELECTRONIC_TOLL_COLLECTION_CARD",
-        "value": 1
-      },
-      {
-        "name": "JP_ELECTRONIC_TOLL_COLLECTION_CARD_V2",
-        "value": 2
-      }
-    ]
-  },
-  {
-    "name": "VehicleAreaMirror",
-    "values": [
-      {
-        "name": "DRIVER_LEFT",
-        "value": 1
-      },
-      {
-        "name": "DRIVER_RIGHT",
-        "value": 2
-      },
-      {
-        "name": "DRIVER_CENTER",
-        "value": 4
-      }
-    ]
-  },
-  {
-    "name": "InitialUserInfoResponseAction",
-    "values": [
-      {
-        "name": "DEFAULT",
-        "value": 0
-      },
-      {
-        "name": "SWITCH",
-        "value": 1
-      },
-      {
-        "name": "CREATE",
-        "value": 2
-      }
-    ]
-  },
-  {
-    "name": "VehicleHvacFanDirection",
-    "values": [
-      {
-        "name": "UNKNOWN",
-        "value": 0
-      },
-      {
-        "name": "FACE",
-        "value": 1
-      },
-      {
-        "name": "FLOOR",
-        "value": 2
-      },
-      {
-        "name": "FACE_AND_FLOOR",
-        "value": 3
-      },
-      {
-        "name": "DEFROST",
-        "value": 4
-      },
-      {
-        "name": "DEFROST_AND_FLOOR",
-        "value": 6
-      }
-    ]
-  },
-  {
-    "name": "Obd2SecondaryAirStatus",
-    "values": [
-      {
-        "name": "UPSTREAM",
-        "value": 1
-      },
-      {
-        "name": "DOWNSTREAM_OF_CATALYCIC_CONVERTER",
-        "value": 2
-      },
-      {
-        "name": "FROM_OUTSIDE_OR_OFF",
-        "value": 4
-      },
-      {
-        "name": "PUMP_ON_FOR_DIAGNOSTICS",
-        "value": 8
-      }
-    ]
-  },
-  {
-    "name": "VmsStartSessionMessageIntegerValuesIndex",
-    "values": [
-      {
-        "name": "MESSAGE_TYPE",
-        "value": 0
-      },
-      {
-        "name": "SERVICE_ID",
-        "value": 1
-      },
-      {
-        "name": "CLIENT_ID",
-        "value": 2
-      }
-    ]
-  },
-  {
-    "name": "VehicleOilLevel",
-    "values": [
-      {
-        "name": "CRITICALLY_LOW",
-        "value": 0
-      },
-      {
-        "name": "LOW",
-        "value": 1
-      },
-      {
-        "name": "NORMAL",
-        "value": 2
-      },
-      {
-        "name": "HIGH",
-        "value": 3
-      },
-      {
-        "name": "ERROR",
-        "value": 4
-      }
-    ]
-  },
-  {
-    "name": "VehicleUnit",
-    "values": [
-      {
-        "name": "SHOULD_NOT_USE",
-        "value": 0
-      },
-      {
-        "name": "METER_PER_SEC",
-        "value": 1
-      },
-      {
-        "name": "RPM",
-        "value": 2
-      },
-      {
-        "name": "HERTZ",
-        "value": 3
-      },
-      {
-        "name": "PERCENTILE",
-        "value": 16
-      },
-      {
-        "name": "MILLIMETER",
-        "value": 32
-      },
-      {
-        "name": "METER",
-        "value": 33
-      },
-      {
-        "name": "KILOMETER",
-        "value": 35
-      },
-      {
-        "name": "MILE",
-        "value": 36
-      },
-      {
-        "name": "CELSIUS",
-        "value": 48
-      },
-      {
-        "name": "FAHRENHEIT",
-        "value": 49
-      },
-      {
-        "name": "KELVIN",
-        "value": 50
-      },
-      {
-        "name": "MILLILITER",
-        "value": 64
-      },
-      {
-        "name": "LITER",
-        "value": 65
-      },
-      {
-        "name": "GALLON",
-        "value": 66
-      },
-      {
-        "name": "US_GALLON",
-        "value": 66
-      },
-      {
-        "name": "IMPERIAL_GALLON",
-        "value": 67
-      },
-      {
-        "name": "NANO_SECS",
-        "value": 80
-      },
-      {
-        "name": "SECS",
-        "value": 83
-      },
-      {
-        "name": "YEAR",
-        "value": 89
-      },
-      {
-        "name": "WATT_HOUR",
-        "value": 96
-      },
-      {
-        "name": "MILLIAMPERE",
-        "value": 97
-      },
-      {
-        "name": "MILLIVOLT",
-        "value": 98
-      },
-      {
-        "name": "MILLIWATTS",
-        "value": 99
-      },
-      {
-        "name": "AMPERE_HOURS",
-        "value": 100
-      },
-      {
-        "name": "KILOWATT_HOUR",
-        "value": 101
-      },
-      {
-        "name": "AMPERE",
-        "value": 102
-      },
-      {
-        "name": "KILOPASCAL",
-        "value": 112
-      },
-      {
-        "name": "PSI",
-        "value": 113
-      },
-      {
-        "name": "BAR",
-        "value": 114
-      },
-      {
-        "name": "DEGREES",
-        "value": 128
-      },
-      {
-        "name": "MILES_PER_HOUR",
-        "value": 144
-      },
-      {
-        "name": "KILOMETERS_PER_HOUR",
-        "value": 145
-      }
-    ]
-  },
-  {
-    "name": "VehicleAreaWheel",
-    "values": [
-      {
-        "name": "UNKNOWN",
-        "value": 0
-      },
-      {
-        "name": "LEFT_FRONT",
-        "value": 1
-      },
-      {
-        "name": "RIGHT_FRONT",
-        "value": 2
-      },
-      {
-        "name": "LEFT_REAR",
-        "value": 4
-      },
-      {
-        "name": "RIGHT_REAR",
-        "value": 8
-      }
-    ]
-  },
-  {
-    "name": "EvsServiceState",
-    "values": [
-      {
-        "name": "OFF",
-        "value": 0
-      },
-      {
-        "name": "ON",
-        "value": 1
-      }
-    ]
-  },
-  {
-    "name": "EvsServiceRequestIndex",
-    "values": [
-      {
-        "name": "TYPE",
-        "value": 0
-      },
-      {
-        "name": "STATE",
-        "value": 1
-      }
-    ]
-  },
-  {
-    "name": "VehicleSeatOccupancyState",
-    "values": [
-      {
-        "name": "UNKNOWN",
-        "value": 0
-      },
-      {
-        "name": "VACANT",
-        "value": 1
-      },
-      {
-        "name": "OCCUPIED",
-        "value": 2
-      }
-    ]
-  },
-  {
-    "name": "VehicleProperty",
-    "values": [
-      {
-        "name": "Undefined property.",
-        "value": 0
-      },
-      {
-        "name": "VIN of vehicle",
-        "value": 286261504,
-        "change_mode": "VehiclePropertyChangeMode:STATIC",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "Manufacturer of vehicle",
-        "value": 286261505,
-        "change_mode": "VehiclePropertyChangeMode:STATIC",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "Model of vehicle",
-        "value": 286261506,
-        "change_mode": "VehiclePropertyChangeMode:STATIC",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "Model year of vehicle.",
-        "value": 289407235,
-        "change_mode": "VehiclePropertyChangeMode:STATIC",
-        "access": "VehiclePropertyAccess:READ",
-        "unit": "VehicleUnit:YEAR"
-      },
-      {
-        "name": "Fuel capacity of the vehicle in milliliters",
-        "value": 291504388,
-        "change_mode": "VehiclePropertyChangeMode:STATIC",
-        "access": "VehiclePropertyAccess:READ",
-        "unit": "VehicleUnit:MILLILITER"
-      },
-      {
-        "name": "List of fuels the vehicle may use",
-        "value": 289472773,
-        "change_mode": "VehiclePropertyChangeMode:STATIC",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "FuelType"
-      },
-      {
-        "name": "INFO_EV_BATTERY_CAPACITY",
-        "value": 291504390,
-        "change_mode": "VehiclePropertyChangeMode:STATIC",
-        "access": "VehiclePropertyAccess:READ",
-        "unit": "VehicleUnit:WH"
-      },
-      {
-        "name": "List of connectors this EV may use",
-        "value": 289472775,
-        "change_mode": "VehiclePropertyChangeMode:STATIC",
-        "data_enum": "EvConnectorType",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "Fuel door location",
-        "value": 289407240,
-        "change_mode": "VehiclePropertyChangeMode:STATIC",
-        "data_enum": "PortLocationType",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "EV port location",
-        "value": 289407241,
-        "change_mode": "VehiclePropertyChangeMode:STATIC",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "PortLocationType"
-      },
-      {
-        "name": "INFO_DRIVER_SEAT",
-        "value": 356516106,
-        "change_mode": "VehiclePropertyChangeMode:STATIC",
-        "data_enum": "VehicleAreaSeat",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "Exterior dimensions of vehicle.",
-        "value": 289472779,
-        "change_mode": "VehiclePropertyChangeMode:STATIC",
-        "access": "VehiclePropertyAccess:READ",
-        "unit": "VehicleUnit:MILLIMETER"
-      },
-      {
-        "name": "Multiple EV port locations",
-        "value": 289472780,
-        "change_mode": "VehiclePropertyChangeMode:STATIC",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "PortLocationType"
-      },
-      {
-        "name": "Current odometer value of the vehicle",
-        "value": 291504644,
-        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
-        "access": "VehiclePropertyAccess:READ",
-        "unit": "VehicleUnit:KILOMETER"
-      },
-      {
-        "name": "Speed of the vehicle",
-        "value": 291504647,
-        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
-        "access": "VehiclePropertyAccess:READ",
-        "unit": "VehicleUnit:METER_PER_SEC"
-      },
-      {
-        "name": "Speed of the vehicle for displays",
-        "value": 291504648,
-        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
-        "access": "VehiclePropertyAccess:READ",
-        "unit": "VehicleUnit:METER_PER_SEC"
-      },
-      {
-        "name": "Front bicycle model steering angle for vehicle",
-        "value": 291504649,
-        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
-        "access": "VehiclePropertyAccess:READ",
-        "unit": "VehicleUnit:DEGREES"
-      },
-      {
-        "name": "Rear bicycle model steering angle for vehicle",
-        "value": 291504656,
-        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
-        "access": "VehiclePropertyAccess:READ",
-        "unit": "VehicleUnit:DEGREES"
-      },
-      {
-        "name": "Temperature of engine coolant",
-        "value": 291504897,
-        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
-        "access": "VehiclePropertyAccess:READ",
-        "unit": "VehicleUnit:CELSIUS"
-      },
-      {
-        "name": "Engine oil level",
-        "value": 289407747,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "VehicleOilLevel"
-      },
-      {
-        "name": "Temperature of engine oil",
-        "value": 291504900,
-        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
-        "access": "VehiclePropertyAccess:READ",
-        "unit": "VehicleUnit:CELSIUS"
-      },
-      {
-        "name": "Engine rpm",
-        "value": 291504901,
-        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
-        "access": "VehiclePropertyAccess:READ",
-        "unit": "VehicleUnit:RPM"
-      },
-      {
-        "name": "Reports wheel ticks",
-        "value": 290521862,
-        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "FUEL_LEVEL",
-        "value": 291504903,
-        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
-        "access": "VehiclePropertyAccess:READ",
-        "unit": "VehicleUnit:MILLILITER"
-      },
-      {
-        "name": "Fuel door open",
-        "value": 287310600,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "EV_BATTERY_LEVEL",
-        "value": 291504905,
-        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
-        "access": "VehiclePropertyAccess:READ",
-        "unit": "VehicleUnit:WH"
-      },
-      {
-        "name": "EV charge port open",
-        "value": 287310602,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "EV charge port connected",
-        "value": 287310603,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "EV instantaneous charge rate in milliwatts",
-        "value": 291504908,
-        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
-        "access": "VehiclePropertyAccess:READ",
-        "unit": "VehicleUnit:MW"
-      },
-      {
-        "name": "Range remaining",
-        "value": 291504904,
-        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
-        "access": "VehiclePropertyAccess:READ_WRITE",
-        "unit": "VehicleUnit:METER"
-      },
-      {
-        "name": "Tire pressure",
-        "value": 392168201,
-        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
-        "access": "VehiclePropertyAccess:READ",
-        "unit": "VehicleUnit:KILOPASCAL"
-      },
-      {
-        "name": "Critically low tire pressure",
-        "value": 392168202,
-        "change_mode": "VehiclePropertyChangeMode:STATIC",
-        "access": "VehiclePropertyAccess:READ",
-        "unit": "VehicleUnit:KILOPASCAL"
-      },
-      {
-        "name": "Currently selected gear",
-        "value": 289408000,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "VehicleGear"
-      },
-      {
-        "name": "CURRENT_GEAR",
-        "value": 289408001,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "VehicleGear"
-      },
-      {
-        "name": "Parking brake state.",
-        "value": 287310850,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "PARKING_BRAKE_AUTO_APPLY",
-        "value": 287310851,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "Warning for fuel low level.",
-        "value": 287310853,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "Night mode",
-        "value": 287310855,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "State of the vehicles turn signals",
-        "value": 289408008,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "VehicleTurnSignal"
-      },
-      {
-        "name": "Represents ignition state",
-        "value": 289408009,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "VehicleIgnitionState"
-      },
-      {
-        "name": "ABS is active",
-        "value": 287310858,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "Traction Control is active",
-        "value": 287310859,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "HVAC_FAN_SPEED",
-        "value": 356517120
-      },
-      {
-        "name": "Fan direction setting",
-        "value": 356517121,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE",
-        "data_enum": "VehicleHvacFanDirection"
-      },
-      {
-        "name": "HVAC current temperature.",
-        "value": 358614274,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ",
-        "unit": "VehicleUnit:CELSIUS"
-      },
-      {
-        "name": "HVAC_TEMPERATURE_SET",
-        "value": 358614275,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE",
-        "unit": "VehicleUnit:CELSIUS"
-      },
-      {
-        "name": "HVAC_DEFROSTER",
-        "value": 320865540,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "HVAC_AC_ON",
-        "value": 354419973,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE",
-        "config_flags": "Supported"
-      },
-      {
-        "name": "HVAC_MAX_AC_ON",
-        "value": 354419974,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "HVAC_MAX_DEFROST_ON",
-        "value": 354419975,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "HVAC_RECIRC_ON",
-        "value": 354419976,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Enable temperature coupling between areas.",
-        "value": 354419977,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "HVAC_AUTO_ON",
-        "value": 354419978,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "HVAC_SEAT_TEMPERATURE",
-        "value": 356517131,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Side Mirror Heat",
-        "value": 339739916,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "HVAC_STEERING_WHEEL_HEAT",
-        "value": 289408269,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Temperature units for display",
-        "value": 289408270,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE",
-        "data_enum": "VehicleUnit"
-      },
-      {
-        "name": "Actual fan speed",
-        "value": 356517135,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "HVAC_POWER_ON",
-        "value": 354419984,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Fan Positions Available",
-        "value": 356582673,
-        "change_mode": "VehiclePropertyChangeMode:STATIC",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "VehicleHvacFanDirection"
-      },
-      {
-        "name": "HVAC_AUTO_RECIRC_ON",
-        "value": 354419986,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Seat ventilation",
-        "value": 356517139,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "HVAC_ELECTRIC_DEFROSTER_ON",
-        "value": 320865556,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Suggested values for setting HVAC temperature.",
-        "value": 291570965,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Distance units for display",
-        "value": 289408512,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE",
-        "data_enum": "VehicleUnit"
-      },
-      {
-        "name": "Fuel volume units for display",
-        "value": 289408513,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE",
-        "data_enum": "VehicleUnit"
-      },
-      {
-        "name": "Tire pressure units for display",
-        "value": 289408514,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE",
-        "data_enum": "VehicleUnit"
-      },
-      {
-        "name": "EV battery units for display",
-        "value": 289408515,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE",
-        "data_enum": "VehicleUnit"
-      },
-      {
-        "name": "Fuel consumption units for display",
-        "value": 287311364,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Speed units for display",
-        "value": 289408517,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "ANDROID_EPOCH_TIME",
-        "value": 290457094,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:WRITE_ONLY",
-        "unit": "VehicleUnit:MILLI_SECS"
-      },
-      {
-        "name": "External encryption binding seed.",
-        "value": 292554247,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Outside temperature",
-        "value": 291505923,
-        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
-        "access": "VehiclePropertyAccess:READ",
-        "unit": "VehicleUnit:CELSIUS"
-      },
-      {
-        "name": "Property to control power state of application processor",
-        "value": 289475072,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "Property to report power state of application processor",
-        "value": 289475073,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "AP_POWER_BOOTUP_REASON",
-        "value": 289409538,
-        "change_mode": "VehiclePropertyChangeMode:STATIC",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "DISPLAY_BRIGHTNESS",
-        "value": 289409539,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "HW_KEY_INPUT",
-        "value": 289475088,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ",
-        "config_flags": ""
-      },
-      {
-        "name": "HW_ROTARY_INPUT",
-        "value": 289475104,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "data_enum": "RotaryInputType",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "Defines a custom OEM partner input event.",
-        "value": 289475120,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "data_enum": "CustomInputType",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "DOOR_POS",
-        "value": 373295872,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Door move",
-        "value": 373295873,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Door lock",
-        "value": 371198722,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Mirror Z Position",
-        "value": 339741504,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Mirror Z Move",
-        "value": 339741505,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Mirror Y Position",
-        "value": 339741506,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Mirror Y Move",
-        "value": 339741507,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Mirror Lock",
-        "value": 287312708,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Mirror Fold",
-        "value": 287312709,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Seat memory select",
-        "value": 356518784,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:WRITE"
-      },
-      {
-        "name": "Seat memory set",
-        "value": 356518785,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:WRITE"
-      },
-      {
-        "name": "Seatbelt buckled",
-        "value": 354421634,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Seatbelt height position",
-        "value": 356518787,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Seatbelt height move",
-        "value": 356518788,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "SEAT_FORE_AFT_POS",
-        "value": 356518789,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "SEAT_FORE_AFT_MOVE",
-        "value": 356518790,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Seat backrest angle 1 position",
-        "value": 356518791,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Seat backrest angle 1 move",
-        "value": 356518792,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Seat backrest angle 2 position",
-        "value": 356518793,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Seat backrest angle 2 move",
-        "value": 356518794,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Seat height position",
-        "value": 356518795,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Seat height move",
-        "value": 356518796,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Seat depth position",
-        "value": 356518797,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Seat depth move",
-        "value": 356518798,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Seat tilt position",
-        "value": 356518799,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Seat tilt move",
-        "value": 356518800,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "SEAT_LUMBAR_FORE_AFT_POS",
-        "value": 356518801,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "SEAT_LUMBAR_FORE_AFT_MOVE",
-        "value": 356518802,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Lumbar side support position",
-        "value": 356518803,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Lumbar side support move",
-        "value": 356518804,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Headrest height position",
-        "value": 289409941,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Headrest height move",
-        "value": 356518806,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Headrest angle position",
-        "value": 356518807,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Headrest angle move",
-        "value": 356518808,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "SEAT_HEADREST_FORE_AFT_POS",
-        "value": 356518809,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "SEAT_HEADREST_FORE_AFT_MOVE",
-        "value": 356518810,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Seat Occupancy",
-        "value": 356518832,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "VehicleSeatOccupancyState"
-      },
-      {
-        "name": "Window Position",
-        "value": 322964416,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Window Move",
-        "value": 322964417,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Window Lock",
-        "value": 320867268,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "VEHICLE_MAP_SERVICE",
-        "value": 299895808,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "OBD2 Live Sensor Data",
-        "value": 299896064,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "OBD2 Freeze Frame Sensor Data",
-        "value": 299896065,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "OBD2 Freeze Frame Information",
-        "value": 299896066,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "OBD2 Freeze Frame Clear",
-        "value": 299896067,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:WRITE"
-      },
-      {
-        "name": "Headlights State",
-        "value": 289410560,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "VehicleLightState"
-      },
-      {
-        "name": "High beam lights state",
-        "value": 289410561,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "VehicleLightState"
-      },
-      {
-        "name": "Fog light state",
-        "value": 289410562,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "VehicleLightState"
-      },
-      {
-        "name": "Hazard light status",
-        "value": 289410563,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "VehicleLightState"
-      },
-      {
-        "name": "Headlight switch",
-        "value": 289410576,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE",
-        "data_enum": "VehicleLightSwitch"
-      },
-      {
-        "name": "High beam light switch",
-        "value": 289410577,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE",
-        "data_enum": "VehicleLightSwitch"
-      },
-      {
-        "name": "Fog light switch",
-        "value": 289410578,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE",
-        "data_enum": "VehicleLightSwitch"
-      },
-      {
-        "name": "Hazard light switch",
-        "value": 289410579,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE",
-        "data_enum": "VehicleLightSwitch"
-      },
-      {
-        "name": "Cabin lights",
-        "value": 289410817,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "VehicleLightState"
-      },
-      {
-        "name": "Cabin lights switch",
-        "value": 289410818,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE",
-        "data_enum": "VehicleLightSwitch"
-      },
-      {
-        "name": "Reading lights",
-        "value": 356519683,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "VehicleLightState"
-      },
-      {
-        "name": "Reading lights switch",
-        "value": 356519684,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE",
-        "data_enum": "VehicleLightSwitch"
-      },
-      {
-        "name": "Support customize permissions for vendor properties",
-        "value": 287313669,
-        "change_mode": "VehiclePropertyChangeMode:STATIC",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "Allow disabling optional featurs from vhal.",
-        "value": 286265094,
-        "change_mode": "VehiclePropertyChangeMode:STATIC",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "Defines the initial Android user to be used during initialization.",
-        "value": 299896583,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Defines a request to switch the foreground Android user.",
-        "value": 299896584,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Called by the Android System after an Android user was created.",
-        "value": 299896585,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Called by the Android System after an Android user was removed.",
-        "value": 299896586,
-        "change_mode": "VehiclePropertyChangeMode:STATIC",
-        "access": "VehiclePropertyAccess:WRITE"
-      },
-      {
-        "name": "USER_IDENTIFICATION_ASSOCIATION",
-        "value": 299896587,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "EVS_SERVICE_REQUEST",
-        "value": 289476368,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "Defines a request to apply power policy.",
-        "value": 286265121,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "POWER_POLICY_GROUP_REQ",
-        "value": 286265122,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "Notifies the current power policy to VHAL layer.",
-        "value": 286265123,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "WATCHDOG_ALIVE",
-        "value": 290459441,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:WRITE"
-      },
-      {
-        "name": "Defines a process terminated by car watchdog and the reason of termination.",
-        "value": 299896626,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:WRITE"
-      },
-      {
-        "name": "Defines an event that VHAL signals to car watchdog as a heartbeat.",
-        "value": 290459443,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "Starts the ClusterUI in cluster display.",
-        "value": 289410868,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "Changes the state of the cluster display.",
-        "value": 289476405,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ"
-      },
-      {
-        "name": "Reports the current display state and ClusterUI state.",
-        "value": 299896630,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:WRITE"
-      },
-      {
-        "name": "Requests to change the cluster display state to show some ClusterUI.",
-        "value": 289410871,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:WRITE"
-      },
-      {
-        "name": "Informs the current navigation state.",
-        "value": 292556600,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:WRITE"
-      },
-      {
-        "name": "Electronic Toll Collection card type.",
-        "value": 289410873,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "ElectronicTollCollectionCardType"
-      },
-      {
-        "name": "Electronic Toll Collection card status.",
-        "value": 289410874,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "ElectronicTollCollectionCardStatus"
-      },
-      {
-        "name": "Front fog lights state",
-        "value": 289410875,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "VehicleLightState"
-      },
-      {
-        "name": "Front fog lights switch",
-        "value": 289410876,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE",
-        "data_enum": "VehicleLightSwitch"
-      },
-      {
-        "name": "Rear fog lights state",
-        "value": 289410877,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "VehicleLightState"
-      },
-      {
-        "name": "Rear fog lights switch",
-        "value": 289410878,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE",
-        "data_enum": "VehicleLightSwitch"
-      },
-      {
-        "name": "Indicates the maximum current draw threshold for charging set by the user",
-        "value": 291508031,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE",
-        "unit": "VehicleUnit:AMPERE"
-      },
-      {
-        "name": "Indicates the maximum charge percent threshold set by the user",
-        "value": 291508032,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Charging state of the car",
-        "value": 289410881,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "EvChargeState"
-      },
-      {
-        "name": "Start or stop charging the EV battery",
-        "value": 287313730,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ_WRITE"
-      },
-      {
-        "name": "Estimated charge time remaining in seconds",
-        "value": 289410883,
-        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
-        "access": "VehiclePropertyAccess:READ",
-        "unit": "VehicleUnit:SECS"
-      },
-      {
-        "name": "EV_REGENERATIVE_BRAKING_STATE",
-        "value": 289410884,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "EvRegenerativeBrakingState"
-      },
-      {
-        "name": "Indicates if there is a trailer present or not.",
-        "value": 289410885,
-        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
-        "access": "VehiclePropertyAccess:READ",
-        "data_enum": "TrailerState"
-      },
-      {
-        "name": "VEHICLE_CURB_WEIGHT",
-        "value": 289410886,
-        "change_mode": "VehiclePropertyChangeMode:STATIC",
-        "access": "VehiclePropertyAccess:READ",
-        "unit": "VehicleUnit:KILOGRAM"
-      }
-    ]
-  },
-  {
-    "name": "EvsServiceType",
-    "values": [
-      {
-        "name": "REARVIEW",
-        "value": 0
-      },
-      {
-        "name": "SURROUNDVIEW",
-        "value": 1
-      }
-    ]
-  },
-  {
-    "name": "VehiclePropertyChangeMode",
-    "values": [
-      {
-        "name": "STATIC",
-        "value": 0
-      },
-      {
-        "name": "ON_CHANGE",
-        "value": 1
-      },
-      {
-        "name": "CONTINUOUS",
-        "value": 2
-      }
-    ]
-  },
-  {
-    "name": "Obd2CompressionIgnitionMonitors",
-    "values": []
-  },
-  {
-    "name": "VehicleLightState",
-    "values": [
-      {
-        "name": "OFF",
-        "value": 0
-      },
-      {
-        "name": "ON",
-        "value": 1
-      },
-      {
-        "name": "DAYTIME_RUNNING",
-        "value": 2
-      }
-    ]
-  },
-  {
-    "name": "SwitchUserMessageType",
-    "values": [
-      {
-        "name": "UNKNOWN",
-        "value": 0
-      },
-      {
-        "name": "LEGACY_ANDROID_SWITCH",
-        "value": 1
-      },
-      {
-        "name": "ANDROID_SWITCH",
-        "value": 2
-      },
-      {
-        "name": "VEHICLE_RESPONSE",
-        "value": 3
-      },
-      {
-        "name": "VEHICLE_REQUEST",
-        "value": 4
-      },
-      {
-        "name": "ANDROID_POST_SWITCH",
-        "value": 5
-      }
-    ]
-  },
-  {
-    "name": "PortLocationType",
-    "values": [
-      {
-        "name": "UNKNOWN",
-        "value": 0
-      },
-      {
-        "name": "FRONT_LEFT",
-        "value": 1
-      },
-      {
-        "name": "FRONT_RIGHT",
-        "value": 2
-      },
-      {
-        "name": "REAR_RIGHT",
-        "value": 3
-      },
-      {
-        "name": "REAR_LEFT",
-        "value": 4
-      },
-      {
-        "name": "FRONT",
-        "value": 5
-      },
-      {
-        "name": "REAR",
-        "value": 6
-      }
-    ]
-  },
-  {
-    "name": "VehiclePropertyStatus",
-    "values": [
-      {
-        "name": "AVAILABLE",
-        "value": 0
-      },
-      {
-        "name": "UNAVAILABLE",
-        "value": 1
-      },
-      {
-        "name": "ERROR",
-        "value": 2
-      }
-    ]
-  },
-  {
-    "name": "VehicleDisplay",
-    "values": [
-      {
-        "name": "MAIN",
-        "value": 0
-      },
-      {
-        "name": "INSTRUMENT_CLUSTER",
-        "value": 1
-      }
-    ]
-  },
-  {
-    "name": "SwitchUserStatus",
-    "values": [
-      {
-        "name": "SUCCESS",
-        "value": 1
-      },
-      {
-        "name": "FAILURE",
-        "value": 2
-      }
-    ]
-  },
-  {
-    "name": "InitialUserInfoRequestType",
-    "values": [
-      {
-        "name": "UNKNOWN",
-        "value": 0
-      },
-      {
-        "name": "FIRST_BOOT",
-        "value": 1
-      },
-      {
-        "name": "FIRST_BOOT_AFTER_OTA",
-        "value": 2
-      },
-      {
-        "name": "COLD_BOOT",
-        "value": 3
-      },
-      {
-        "name": "RESUME",
-        "value": 4
-      }
-    ]
-  },
-  {
-    "name": "UserIdentificationAssociationSetValue",
-    "values": [
-      {
-        "name": "INVALID",
-        "value": 0
-      },
-      {
-        "name": "ASSOCIATE_CURRENT_USER",
-        "value": 1
-      },
-      {
-        "name": "DISASSOCIATE_CURRENT_USER",
-        "value": 2
-      },
-      {
-        "name": "DISASSOCIATE_ALL_USERS",
-        "value": 3
-      }
-    ]
-  },
-  {
+    "package": "android.hardware.automotive.vehicle",
     "name": "VehicleAreaDoor",
     "values": [
       {
@@ -2092,250 +368,477 @@
     ]
   },
   {
-    "name": "VehicleLightSwitch",
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleApPowerBootupReason",
     "values": [
       {
-        "name": "OFF",
+        "name": "USER_POWER_ON",
         "value": 0
       },
       {
-        "name": "ON",
+        "name": "SYSTEM_USER_DETECTION",
         "value": 1
       },
       {
-        "name": "DAYTIME_RUNNING",
+        "name": "SYSTEM_REMOTE_ACCESS",
         "value": 2
-      },
-      {
-        "name": "AUTOMATIC",
-        "value": 256
       }
     ]
   },
   {
-    "name": "VehicleGear",
+    "package": "android.hardware.automotive.vehicle",
+    "name": "EmergencyLaneKeepAssistState",
     "values": [
       {
-        "name": "GEAR_UNKNOWN",
+        "name": "OTHER",
         "value": 0
       },
       {
-        "name": "GEAR_NEUTRAL",
+        "name": "ENABLED",
         "value": 1
       },
       {
-        "name": "GEAR_REVERSE",
+        "name": "WARNING_LEFT",
         "value": 2
       },
       {
-        "name": "GEAR_PARK",
-        "value": 4
-      },
-      {
-        "name": "GEAR_DRIVE",
-        "value": 8
-      },
-      {
-        "name": "GEAR_1",
-        "value": 16
-      },
-      {
-        "name": "GEAR_2",
-        "value": 32
-      },
-      {
-        "name": "GEAR_3",
-        "value": 64
-      },
-      {
-        "name": "GEAR_4",
-        "value": 128
-      },
-      {
-        "name": "GEAR_5",
-        "value": 256
-      },
-      {
-        "name": "GEAR_6",
-        "value": 512
-      },
-      {
-        "name": "GEAR_7",
-        "value": 1024
-      },
-      {
-        "name": "GEAR_8",
-        "value": 2048
-      },
-      {
-        "name": "GEAR_9",
-        "value": 4096
-      }
-    ]
-  },
-  {
-    "name": "Obd2IgnitionMonitorKind",
-    "values": [
-      {
-        "name": "SPARK",
-        "value": 0
-      },
-      {
-        "name": "COMPRESSION",
-        "value": 1
-      }
-    ]
-  },
-  {
-    "name": "CustomInputType",
-    "values": [
-      {
-        "name": "CUSTOM_EVENT_F1",
-        "value": 1001
-      },
-      {
-        "name": "CUSTOM_EVENT_F2",
-        "value": 1002
-      },
-      {
-        "name": "CUSTOM_EVENT_F3",
-        "value": 1003
-      },
-      {
-        "name": "CUSTOM_EVENT_F4",
-        "value": 1004
-      },
-      {
-        "name": "CUSTOM_EVENT_F5",
-        "value": 1005
-      },
-      {
-        "name": "CUSTOM_EVENT_F6",
-        "value": 1006
-      },
-      {
-        "name": "CUSTOM_EVENT_F7",
-        "value": 1007
-      },
-      {
-        "name": "CUSTOM_EVENT_F8",
-        "value": 1008
-      },
-      {
-        "name": "CUSTOM_EVENT_F9",
-        "value": 1009
-      },
-      {
-        "name": "CUSTOM_EVENT_F10",
-        "value": 1010
-      }
-    ]
-  },
-  {
-    "name": "VehicleApPowerStateReport",
-    "values": [
-      {
-        "name": "WAIT_FOR_VHAL",
-        "value": 1
-      },
-      {
-        "name": "DEEP_SLEEP_ENTRY",
-        "value": 2
-      },
-      {
-        "name": "DEEP_SLEEP_EXIT",
+        "name": "WARNING_RIGHT",
         "value": 3
       },
       {
-        "name": "SHUTDOWN_POSTPONE",
+        "name": "ACTIVATED_STEER_LEFT",
         "value": 4
       },
       {
-        "name": "SHUTDOWN_START",
+        "name": "ACTIVATED_STEER_RIGHT",
         "value": 5
       },
       {
-        "name": "ON",
+        "name": "USER_OVERRIDE",
         "value": 6
-      },
-      {
-        "name": "SHUTDOWN_PREPARE",
-        "value": 7
-      },
-      {
-        "name": "SHUTDOWN_CANCELLED",
-        "value": 8
-      },
-      {
-        "name": "HIBERNATION_ENTRY",
-        "value": 9
-      },
-      {
-        "name": "HIBERNATION_EXIT",
-        "value": 10
       }
     ]
   },
   {
-    "name": "VmsMessageWithLayerIntegerValuesIndex",
-    "values": [
-      {
-        "name": "MESSAGE_TYPE",
-        "value": 0
-      },
-      {
-        "name": "LAYER_TYPE",
-        "value": 1
-      },
-      {
-        "name": "LAYER_SUBTYPE",
-        "value": 2
-      },
-      {
-        "name": "LAYER_VERSION",
-        "value": 3
-      }
-    ]
-  },
-  {
-    "name": "EvRegenerativeBrakingState",
+    "package": "android.hardware.automotive.vehicle",
+    "name": "EvConnectorType",
     "values": [
       {
         "name": "UNKNOWN",
         "value": 0
       },
       {
-        "name": "DISABLED",
+        "name": "IEC_TYPE_1_AC",
         "value": 1
       },
       {
-        "name": "PARTIALLY_ENABLED",
+        "name": "IEC_TYPE_2_AC",
         "value": 2
       },
       {
-        "name": "FULLY_ENABLED",
+        "name": "IEC_TYPE_3_AC",
         "value": 3
+      },
+      {
+        "name": "IEC_TYPE_4_DC",
+        "value": 4
+      },
+      {
+        "name": "IEC_TYPE_1_CCS_DC",
+        "value": 5
+      },
+      {
+        "name": "IEC_TYPE_2_CCS_DC",
+        "value": 6
+      },
+      {
+        "name": "TESLA_ROADSTER",
+        "value": 7
+      },
+      {
+        "name": "TESLA_HPWC",
+        "value": 8
+      },
+      {
+        "name": "TESLA_SUPERCHARGER",
+        "value": 9
+      },
+      {
+        "name": "GBT_AC",
+        "value": 10
+      },
+      {
+        "name": "GBT_DC",
+        "value": 11
+      },
+      {
+        "name": "OTHER",
+        "value": 101
       }
     ]
   },
   {
-    "name": "VehiclePropertyGroup",
+    "package": "android.hardware.automotive.vehicle",
+    "name": "UserIdentificationAssociationType",
     "values": [
       {
-        "name": "SYSTEM",
-        "value": 268435456
+        "name": "INVALID",
+        "value": 0
       },
       {
-        "name": "VENDOR",
-        "value": 536870912
+        "name": "KEY_FOB",
+        "value": 1
       },
       {
-        "name": "MASK",
-        "value": 4026531840
+        "name": "CUSTOM_1",
+        "value": 101
+      },
+      {
+        "name": "CUSTOM_2",
+        "value": 102
+      },
+      {
+        "name": "CUSTOM_3",
+        "value": 103
+      },
+      {
+        "name": "CUSTOM_4",
+        "value": 104
       }
     ]
   },
   {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleHvacFanDirection",
+    "values": [
+      {
+        "name": "UNKNOWN",
+        "value": 0
+      },
+      {
+        "name": "FACE",
+        "value": 1
+      },
+      {
+        "name": "FLOOR",
+        "value": 2
+      },
+      {
+        "name": "FACE_AND_FLOOR",
+        "value": 3
+      },
+      {
+        "name": "DEFROST",
+        "value": 4
+      },
+      {
+        "name": "DEFROST_AND_FLOOR",
+        "value": 6
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleAreaWheel",
+    "values": [
+      {
+        "name": "UNKNOWN",
+        "value": 0
+      },
+      {
+        "name": "LEFT_FRONT",
+        "value": 1
+      },
+      {
+        "name": "RIGHT_FRONT",
+        "value": 2
+      },
+      {
+        "name": "LEFT_REAR",
+        "value": 4
+      },
+      {
+        "name": "RIGHT_REAR",
+        "value": 8
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "InitialUserInfoRequestType",
+    "values": [
+      {
+        "name": "UNKNOWN",
+        "value": 0
+      },
+      {
+        "name": "FIRST_BOOT",
+        "value": 1
+      },
+      {
+        "name": "FIRST_BOOT_AFTER_OTA",
+        "value": 2
+      },
+      {
+        "name": "COLD_BOOT",
+        "value": 3
+      },
+      {
+        "name": "RESUME",
+        "value": 4
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "HandsOnDetectionDriverState",
+    "values": [
+      {
+        "name": "OTHER",
+        "value": 0
+      },
+      {
+        "name": "HANDS_ON",
+        "value": 1
+      },
+      {
+        "name": "HANDS_OFF",
+        "value": 2
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "CruiseControlCommand",
+    "values": [
+      {
+        "name": "ACTIVATE",
+        "value": 1
+      },
+      {
+        "name": "SUSPEND",
+        "value": 2
+      },
+      {
+        "name": "INCREASE_TARGET_SPEED",
+        "value": 3
+      },
+      {
+        "name": "DECREASE_TARGET_SPEED",
+        "value": 4
+      },
+      {
+        "name": "INCREASE_TARGET_TIME_GAP",
+        "value": 5
+      },
+      {
+        "name": "DECREASE_TARGET_TIME_GAP",
+        "value": 6
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "WindshieldWipersSwitch",
+    "values": [
+      {
+        "name": "OTHER",
+        "value": 0
+      },
+      {
+        "name": "OFF",
+        "value": 1
+      },
+      {
+        "name": "MIST",
+        "value": 2
+      },
+      {
+        "name": "INTERMITTENT_LEVEL_1",
+        "value": 3
+      },
+      {
+        "name": "INTERMITTENT_LEVEL_2",
+        "value": 4
+      },
+      {
+        "name": "INTERMITTENT_LEVEL_3",
+        "value": 5
+      },
+      {
+        "name": "INTERMITTENT_LEVEL_4",
+        "value": 6
+      },
+      {
+        "name": "INTERMITTENT_LEVEL_5",
+        "value": 7
+      },
+      {
+        "name": "CONTINUOUS_LEVEL_1",
+        "value": 8
+      },
+      {
+        "name": "CONTINUOUS_LEVEL_2",
+        "value": 9
+      },
+      {
+        "name": "CONTINUOUS_LEVEL_3",
+        "value": 10
+      },
+      {
+        "name": "CONTINUOUS_LEVEL_4",
+        "value": 11
+      },
+      {
+        "name": "CONTINUOUS_LEVEL_5",
+        "value": 12
+      },
+      {
+        "name": "AUTO",
+        "value": 13
+      },
+      {
+        "name": "SERVICE",
+        "value": 14
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleHwMotionToolType",
+    "values": [
+      {
+        "name": "TOOL_TYPE_UNKNOWN",
+        "value": 0
+      },
+      {
+        "name": "TOOL_TYPE_FINGER",
+        "value": 1
+      },
+      {
+        "name": "TOOL_TYPE_STYLUS",
+        "value": 2
+      },
+      {
+        "name": "TOOL_TYPE_MOUSE",
+        "value": 3
+      },
+      {
+        "name": "TOOL_TYPE_ERASER",
+        "value": 4
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "SwitchUserStatus",
+    "values": [
+      {
+        "name": "SUCCESS",
+        "value": 1
+      },
+      {
+        "name": "FAILURE",
+        "value": 2
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "EvsServiceType",
+    "values": [
+      {
+        "name": "REARVIEW",
+        "value": 0
+      },
+      {
+        "name": "SURROUNDVIEW",
+        "value": 1
+      },
+      {
+        "name": "FRONTVIEW",
+        "value": 2
+      },
+      {
+        "name": "LEFTVIEW",
+        "value": 3
+      },
+      {
+        "name": "RIGHTVIEW",
+        "value": 4
+      },
+      {
+        "name": "DRIVERVIEW",
+        "value": 5
+      },
+      {
+        "name": "FRONTPASSENGERSVIEW",
+        "value": 6
+      },
+      {
+        "name": "REARPASSENGERSVIEW",
+        "value": 7
+      },
+      {
+        "name": "USER_DEFINED",
+        "value": 1000
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "UserIdentificationAssociationValue",
+    "values": [
+      {
+        "name": "UNKNOWN",
+        "value": 1
+      },
+      {
+        "name": "ASSOCIATED_CURRENT_USER",
+        "value": 2
+      },
+      {
+        "name": "ASSOCIATED_ANOTHER_USER",
+        "value": 3
+      },
+      {
+        "name": "NOT_ASSOCIATED_ANY_USER",
+        "value": 4
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "ErrorState",
+    "values": [
+      {
+        "name": "OTHER_ERROR_STATE",
+        "value": -1
+      },
+      {
+        "name": "NOT_AVAILABLE_DISABLED",
+        "value": -2
+      },
+      {
+        "name": "NOT_AVAILABLE_SPEED_LOW",
+        "value": -3
+      },
+      {
+        "name": "NOT_AVAILABLE_SPEED_HIGH",
+        "value": -4
+      },
+      {
+        "name": "NOT_AVAILABLE_POOR_VISIBILITY",
+        "value": -5
+      },
+      {
+        "name": "NOT_AVAILABLE_SAFETY",
+        "value": -6
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
     "name": "VehicleIgnitionState",
     "values": [
       {
@@ -2365,173 +868,302 @@
     ]
   },
   {
-    "name": "VehicleHwKeyInputAction",
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleAreaSeat",
     "values": [
       {
-        "name": "ACTION_DOWN",
-        "value": 0
-      },
-      {
-        "name": "ACTION_UP",
-        "value": 1
-      }
-    ]
-  },
-  {
-    "name": "DiagnosticIntegerSensorIndex",
-    "values": [
-      {
-        "name": "FUEL_SYSTEM_STATUS",
-        "value": 0
-      },
-      {
-        "name": "MALFUNCTION_INDICATOR_LIGHT_ON",
+        "name": "ROW_1_LEFT",
         "value": 1
       },
       {
-        "name": "IGNITION_MONITORS_SUPPORTED",
+        "name": "ROW_1_CENTER",
         "value": 2
       },
       {
-        "name": "IGNITION_SPECIFIC_MONITORS",
-        "value": 3
-      },
-      {
-        "name": "INTAKE_AIR_TEMPERATURE",
+        "name": "ROW_1_RIGHT",
         "value": 4
       },
       {
-        "name": "COMMANDED_SECONDARY_AIR_STATUS",
-        "value": 5
-      },
-      {
-        "name": "NUM_OXYGEN_SENSORS_PRESENT",
-        "value": 6
-      },
-      {
-        "name": "RUNTIME_SINCE_ENGINE_START",
-        "value": 7
-      },
-      {
-        "name": "DISTANCE_TRAVELED_WITH_MALFUNCTION_INDICATOR_LIGHT_ON",
-        "value": 8
-      },
-      {
-        "name": "WARMUPS_SINCE_CODES_CLEARED",
-        "value": 9
-      },
-      {
-        "name": "DISTANCE_TRAVELED_SINCE_CODES_CLEARED",
-        "value": 10
-      },
-      {
-        "name": "ABSOLUTE_BAROMETRIC_PRESSURE",
-        "value": 11
-      },
-      {
-        "name": "CONTROL_MODULE_VOLTAGE",
-        "value": 12
-      },
-      {
-        "name": "AMBIENT_AIR_TEMPERATURE",
-        "value": 13
-      },
-      {
-        "name": "TIME_WITH_MALFUNCTION_LIGHT_ON",
-        "value": 14
-      },
-      {
-        "name": "TIME_SINCE_TROUBLE_CODES_CLEARED",
-        "value": 15
-      },
-      {
-        "name": "MAX_FUEL_AIR_EQUIVALENCE_RATIO",
+        "name": "ROW_2_LEFT",
         "value": 16
       },
       {
-        "name": "MAX_OXYGEN_SENSOR_VOLTAGE",
-        "value": 17
+        "name": "ROW_2_CENTER",
+        "value": 32
       },
       {
-        "name": "MAX_OXYGEN_SENSOR_CURRENT",
-        "value": 18
+        "name": "ROW_2_RIGHT",
+        "value": 64
       },
       {
-        "name": "MAX_INTAKE_MANIFOLD_ABSOLUTE_PRESSURE",
-        "value": 19
+        "name": "ROW_3_LEFT",
+        "value": 256
       },
       {
-        "name": "MAX_AIR_FLOW_RATE_FROM_MASS_AIR_FLOW_SENSOR",
-        "value": 20
+        "name": "ROW_3_CENTER",
+        "value": 512
       },
       {
-        "name": "FUEL_TYPE",
-        "value": 21
-      },
-      {
-        "name": "FUEL_RAIL_ABSOLUTE_PRESSURE",
-        "value": 22
-      },
-      {
-        "name": "ENGINE_OIL_TEMPERATURE",
-        "value": 23
-      },
-      {
-        "name": "DRIVER_DEMAND_PERCENT_TORQUE",
-        "value": 24
-      },
-      {
-        "name": "ENGINE_ACTUAL_PERCENT_TORQUE",
-        "value": 25
-      },
-      {
-        "name": "ENGINE_REFERENCE_PERCENT_TORQUE",
-        "value": 26
-      },
-      {
-        "name": "ENGINE_PERCENT_TORQUE_DATA_IDLE",
-        "value": 27
-      },
-      {
-        "name": "ENGINE_PERCENT_TORQUE_DATA_POINT1",
-        "value": 28
-      },
-      {
-        "name": "ENGINE_PERCENT_TORQUE_DATA_POINT2",
-        "value": 29
-      },
-      {
-        "name": "ENGINE_PERCENT_TORQUE_DATA_POINT3",
-        "value": 30
-      },
-      {
-        "name": "ENGINE_PERCENT_TORQUE_DATA_POINT4",
-        "value": 31
+        "name": "ROW_3_RIGHT",
+        "value": 1024
       }
     ]
   },
   {
-    "name": "UserIdentificationAssociationValue",
+    "package": "android.hardware.automotive.vehicle",
+    "name": "EvsServiceRequestIndex",
     "values": [
       {
-        "name": "UNKNOWN",
+        "name": "TYPE",
+        "value": 0
+      },
+      {
+        "name": "STATE",
+        "value": 1
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "LaneDepartureWarningState",
+    "values": [
+      {
+        "name": "OTHER",
+        "value": 0
+      },
+      {
+        "name": "NO_WARNING",
         "value": 1
       },
       {
-        "name": "ASSOCIATED_CURRENT_USER",
+        "name": "WARNING_LEFT",
         "value": 2
       },
       {
-        "name": "ASSOCIATED_ANOTHER_USER",
+        "name": "WARNING_RIGHT",
         "value": 3
-      },
-      {
-        "name": "NOT_ASSOCIATED_ANY_USER",
-        "value": 4
       }
     ]
   },
   {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "Obd2SparkIgnitionMonitors",
+    "values": []
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "CreateUserStatus",
+    "values": [
+      {
+        "name": "SUCCESS",
+        "value": 1
+      },
+      {
+        "name": "FAILURE",
+        "value": 2
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehiclePropertyGroup",
+    "values": [
+      {
+        "name": "SYSTEM",
+        "value": 268435456
+      },
+      {
+        "name": "VENDOR",
+        "value": 536870912
+      },
+      {
+        "name": "MASK",
+        "value": 4026531840
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleVendorPermission",
+    "values": [
+      {
+        "name": "PERMISSION_DEFAULT",
+        "value": 0
+      },
+      {
+        "name": "PERMISSION_SET_VENDOR_CATEGORY_WINDOW",
+        "value": 1
+      },
+      {
+        "name": "PERMISSION_GET_VENDOR_CATEGORY_WINDOW",
+        "value": 2
+      },
+      {
+        "name": "PERMISSION_SET_VENDOR_CATEGORY_DOOR",
+        "value": 3
+      },
+      {
+        "name": "PERMISSION_GET_VENDOR_CATEGORY_DOOR",
+        "value": 4
+      },
+      {
+        "name": "PERMISSION_SET_VENDOR_CATEGORY_SEAT",
+        "value": 5
+      },
+      {
+        "name": "PERMISSION_GET_VENDOR_CATEGORY_SEAT",
+        "value": 6
+      },
+      {
+        "name": "PERMISSION_SET_VENDOR_CATEGORY_MIRROR",
+        "value": 7
+      },
+      {
+        "name": "PERMISSION_GET_VENDOR_CATEGORY_MIRROR",
+        "value": 8
+      },
+      {
+        "name": "PERMISSION_SET_VENDOR_CATEGORY_INFO",
+        "value": 9
+      },
+      {
+        "name": "PERMISSION_GET_VENDOR_CATEGORY_INFO",
+        "value": 10
+      },
+      {
+        "name": "PERMISSION_SET_VENDOR_CATEGORY_ENGINE",
+        "value": 11
+      },
+      {
+        "name": "PERMISSION_GET_VENDOR_CATEGORY_ENGINE",
+        "value": 12
+      },
+      {
+        "name": "PERMISSION_SET_VENDOR_CATEGORY_HVAC",
+        "value": 13
+      },
+      {
+        "name": "PERMISSION_GET_VENDOR_CATEGORY_HVAC",
+        "value": 14
+      },
+      {
+        "name": "PERMISSION_SET_VENDOR_CATEGORY_LIGHT",
+        "value": 15
+      },
+      {
+        "name": "PERMISSION_GET_VENDOR_CATEGORY_LIGHT",
+        "value": 16
+      },
+      {
+        "name": "PERMISSION_SET_VENDOR_CATEGORY_1",
+        "value": 65536
+      },
+      {
+        "name": "PERMISSION_GET_VENDOR_CATEGORY_1",
+        "value": 69632
+      },
+      {
+        "name": "PERMISSION_SET_VENDOR_CATEGORY_2",
+        "value": 131072
+      },
+      {
+        "name": "PERMISSION_GET_VENDOR_CATEGORY_2",
+        "value": 135168
+      },
+      {
+        "name": "PERMISSION_SET_VENDOR_CATEGORY_3",
+        "value": 196608
+      },
+      {
+        "name": "PERMISSION_GET_VENDOR_CATEGORY_3",
+        "value": 200704
+      },
+      {
+        "name": "PERMISSION_SET_VENDOR_CATEGORY_4",
+        "value": 262144
+      },
+      {
+        "name": "PERMISSION_GET_VENDOR_CATEGORY_4",
+        "value": 266240
+      },
+      {
+        "name": "PERMISSION_SET_VENDOR_CATEGORY_5",
+        "value": 327680
+      },
+      {
+        "name": "PERMISSION_GET_VENDOR_CATEGORY_5",
+        "value": 331776
+      },
+      {
+        "name": "PERMISSION_SET_VENDOR_CATEGORY_6",
+        "value": 393216
+      },
+      {
+        "name": "PERMISSION_GET_VENDOR_CATEGORY_6",
+        "value": 397312
+      },
+      {
+        "name": "PERMISSION_SET_VENDOR_CATEGORY_7",
+        "value": 458752
+      },
+      {
+        "name": "PERMISSION_GET_VENDOR_CATEGORY_7",
+        "value": 462848
+      },
+      {
+        "name": "PERMISSION_SET_VENDOR_CATEGORY_8",
+        "value": 524288
+      },
+      {
+        "name": "PERMISSION_GET_VENDOR_CATEGORY_8",
+        "value": 528384
+      },
+      {
+        "name": "PERMISSION_SET_VENDOR_CATEGORY_9",
+        "value": 589824
+      },
+      {
+        "name": "PERMISSION_GET_VENDOR_CATEGORY_9",
+        "value": 593920
+      },
+      {
+        "name": "PERMISSION_SET_VENDOR_CATEGORY_10",
+        "value": 655360
+      },
+      {
+        "name": "PERMISSION_GET_VENDOR_CATEGORY_10",
+        "value": 659456
+      },
+      {
+        "name": "PERMISSION_NOT_ACCESSIBLE",
+        "value": 4026531840
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VmsOfferingMessageIntegerValuesIndex",
+    "values": [
+      {
+        "name": "MESSAGE_TYPE",
+        "value": 0
+      },
+      {
+        "name": "PUBLISHER_ID",
+        "value": 1
+      },
+      {
+        "name": "NUMBER_OF_OFFERS",
+        "value": 2
+      },
+      {
+        "name": "OFFERING_START",
+        "value": 3
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
     "name": "VmsBaseMessageIntegerValuesIndex",
     "values": [
       {
@@ -2541,6 +1173,473 @@
     ]
   },
   {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "Obd2CompressionIgnitionMonitors",
+    "values": []
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "LaneKeepAssistState",
+    "values": [
+      {
+        "name": "OTHER",
+        "value": 0
+      },
+      {
+        "name": "ENABLED",
+        "value": 1
+      },
+      {
+        "name": "ACTIVATED_STEER_LEFT",
+        "value": 2
+      },
+      {
+        "name": "ACTIVATED_STEER_RIGHT",
+        "value": 3
+      },
+      {
+        "name": "USER_OVERRIDE",
+        "value": 4
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleHwMotionInputAction",
+    "values": [
+      {
+        "name": "ACTION_DOWN",
+        "value": 0
+      },
+      {
+        "name": "ACTION_UP",
+        "value": 1
+      },
+      {
+        "name": "ACTION_MOVE",
+        "value": 2
+      },
+      {
+        "name": "ACTION_CANCEL",
+        "value": 3
+      },
+      {
+        "name": "ACTION_OUTSIDE",
+        "value": 4
+      },
+      {
+        "name": "ACTION_POINTER_DOWN",
+        "value": 5
+      },
+      {
+        "name": "ACTION_POINTER_UP",
+        "value": 6
+      },
+      {
+        "name": "ACTION_HOVER_MOVE",
+        "value": 7
+      },
+      {
+        "name": "ACTION_SCROLL",
+        "value": 8
+      },
+      {
+        "name": "ACTION_HOVER_ENTER",
+        "value": 9
+      },
+      {
+        "name": "ACTION_HOVER_EXIT",
+        "value": 10
+      },
+      {
+        "name": "ACTION_BUTTON_PRESS",
+        "value": 11
+      },
+      {
+        "name": "ACTION_BUTTON_RELEASE",
+        "value": 12
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleApPowerStateConfigFlag",
+    "values": [
+      {
+        "name": "ENABLE_DEEP_SLEEP_FLAG",
+        "value": 1
+      },
+      {
+        "name": "CONFIG_SUPPORT_TIMER_POWER_ON_FLAG",
+        "value": 2
+      },
+      {
+        "name": "ENABLE_HIBERNATION_FLAG",
+        "value": 4
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "Obd2SecondaryAirStatus",
+    "values": [
+      {
+        "name": "UPSTREAM",
+        "value": 1
+      },
+      {
+        "name": "DOWNSTREAM_OF_CATALYCIC_CONVERTER",
+        "value": 2
+      },
+      {
+        "name": "FROM_OUTSIDE_OR_OFF",
+        "value": 4
+      },
+      {
+        "name": "PUMP_ON_FOR_DIAGNOSTICS",
+        "value": 8
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VmsPublisherInformationIntegerValuesIndex",
+    "values": [
+      {
+        "name": "MESSAGE_TYPE",
+        "value": 0
+      },
+      {
+        "name": "PUBLISHER_ID",
+        "value": 1
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleApPowerStateReq",
+    "values": [
+      {
+        "name": "ON",
+        "value": 0
+      },
+      {
+        "name": "SHUTDOWN_PREPARE",
+        "value": 1
+      },
+      {
+        "name": "CANCEL_SHUTDOWN",
+        "value": 2
+      },
+      {
+        "name": "FINISHED",
+        "value": 3
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "WindshieldWipersState",
+    "values": [
+      {
+        "name": "OTHER",
+        "value": 0
+      },
+      {
+        "name": "OFF",
+        "value": 1
+      },
+      {
+        "name": "ON",
+        "value": 2
+      },
+      {
+        "name": "SERVICE",
+        "value": 3
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "LaneCenteringAssistState",
+    "values": [
+      {
+        "name": "OTHER",
+        "value": 0
+      },
+      {
+        "name": "ENABLED",
+        "value": 1
+      },
+      {
+        "name": "ACTIVATION_REQUESTED",
+        "value": 2
+      },
+      {
+        "name": "ACTIVATED",
+        "value": 3
+      },
+      {
+        "name": "USER_OVERRIDE",
+        "value": 4
+      },
+      {
+        "name": "FORCED_DEACTIVATION_WARNING",
+        "value": 5
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "UserIdentificationAssociationSetValue",
+    "values": [
+      {
+        "name": "INVALID",
+        "value": 0
+      },
+      {
+        "name": "ASSOCIATE_CURRENT_USER",
+        "value": 1
+      },
+      {
+        "name": "DISASSOCIATE_CURRENT_USER",
+        "value": 2
+      },
+      {
+        "name": "DISASSOCIATE_ALL_USERS",
+        "value": 3
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "Obd2CommonIgnitionMonitors",
+    "values": []
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleHwMotionInputSource",
+    "values": [
+      {
+        "name": "SOURCE_UNKNOWN",
+        "value": 0
+      },
+      {
+        "name": "SOURCE_KEYBOARD",
+        "value": 1
+      },
+      {
+        "name": "SOURCE_DPAD",
+        "value": 2
+      },
+      {
+        "name": "SOURCE_GAMEPAD",
+        "value": 3
+      },
+      {
+        "name": "SOURCE_TOUCHSCREEN",
+        "value": 4
+      },
+      {
+        "name": "SOURCE_MOUSE",
+        "value": 5
+      },
+      {
+        "name": "SOURCE_STYLUS",
+        "value": 6
+      },
+      {
+        "name": "SOURCE_BLUETOOTH_STYLUS",
+        "value": 7
+      },
+      {
+        "name": "SOURCE_TRACKBALL",
+        "value": 8
+      },
+      {
+        "name": "SOURCE_MOUSE_RELATIVE",
+        "value": 9
+      },
+      {
+        "name": "SOURCE_TOUCHPAD",
+        "value": 10
+      },
+      {
+        "name": "SOURCE_TOUCH_NAVIGATION",
+        "value": 11
+      },
+      {
+        "name": "SOURCE_ROTARY_ENCODER",
+        "value": 12
+      },
+      {
+        "name": "SOURCE_JOYSTICK",
+        "value": 13
+      },
+      {
+        "name": "SOURCE_HDMI",
+        "value": 14
+      },
+      {
+        "name": "SOURCE_SENSOR",
+        "value": 15
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "ForwardCollisionWarningState",
+    "values": [
+      {
+        "name": "OTHER",
+        "value": 0
+      },
+      {
+        "name": "NO_WARNING",
+        "value": 1
+      },
+      {
+        "name": "WARNING",
+        "value": 2
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleArea",
+    "values": [
+      {
+        "name": "GLOBAL",
+        "value": 16777216
+      },
+      {
+        "name": "WINDOW",
+        "value": 50331648
+      },
+      {
+        "name": "MIRROR",
+        "value": 67108864
+      },
+      {
+        "name": "SEAT",
+        "value": 83886080
+      },
+      {
+        "name": "DOOR",
+        "value": 100663296
+      },
+      {
+        "name": "WHEEL",
+        "value": 117440512
+      },
+      {
+        "name": "MASK",
+        "value": 251658240
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "PortLocationType",
+    "values": [
+      {
+        "name": "UNKNOWN",
+        "value": 0
+      },
+      {
+        "name": "FRONT_LEFT",
+        "value": 1
+      },
+      {
+        "name": "FRONT_RIGHT",
+        "value": 2
+      },
+      {
+        "name": "REAR_RIGHT",
+        "value": 3
+      },
+      {
+        "name": "REAR_LEFT",
+        "value": 4
+      },
+      {
+        "name": "FRONT",
+        "value": 5
+      },
+      {
+        "name": "REAR",
+        "value": 6
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "InitialUserInfoResponseAction",
+    "values": [
+      {
+        "name": "DEFAULT",
+        "value": 0
+      },
+      {
+        "name": "SWITCH",
+        "value": 1
+      },
+      {
+        "name": "CREATE",
+        "value": 2
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VmsSubscriptionsStateIntegerValuesIndex",
+    "values": [
+      {
+        "name": "MESSAGE_TYPE",
+        "value": 0
+      },
+      {
+        "name": "SEQUENCE_NUMBER",
+        "value": 1
+      },
+      {
+        "name": "NUMBER_OF_LAYERS",
+        "value": 2
+      },
+      {
+        "name": "NUMBER_OF_ASSOCIATED_LAYERS",
+        "value": 3
+      },
+      {
+        "name": "SUBSCRIPTIONS_START",
+        "value": 4
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "CruiseControlType",
+    "values": [
+      {
+        "name": "OTHER",
+        "value": 0
+      },
+      {
+        "name": "STANDARD",
+        "value": 1
+      },
+      {
+        "name": "ADAPTIVE",
+        "value": 2
+      },
+      {
+        "name": "PREDICTIVE",
+        "value": 3
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
     "name": "DiagnosticFloatSensorIndex",
     "values": [
       {
@@ -2830,7 +1929,40 @@
     ]
   },
   {
-    "name": "VmsMessageWithLayerAndPublisherIdIntegerValuesIndex",
+    "package": "android.hardware.automotive.vehicle",
+    "name": "GsrComplianceRequirementType",
+    "values": [
+      {
+        "name": "GSR_COMPLIANCE_NOT_REQUIRED",
+        "value": 0
+      },
+      {
+        "name": "GSR_COMPLIANCE_REQUIRED_V1",
+        "value": 1
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleLightState",
+    "values": [
+      {
+        "name": "OFF",
+        "value": 0
+      },
+      {
+        "name": "ON",
+        "value": 1
+      },
+      {
+        "name": "DAYTIME_RUNNING",
+        "value": 2
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VmsMessageWithLayerIntegerValuesIndex",
     "values": [
       {
         "name": "MESSAGE_TYPE",
@@ -2847,92 +1979,61 @@
       {
         "name": "LAYER_VERSION",
         "value": 3
-      },
-      {
-        "name": "PUBLISHER_ID",
-        "value": 4
       }
     ]
   },
   {
-    "name": "FuelType",
+    "package": "android.hardware.automotive.vehicle",
+    "name": "EvRegenerativeBrakingState",
     "values": [
       {
-        "name": "FUEL_TYPE_UNKNOWN",
+        "name": "UNKNOWN",
         "value": 0
       },
       {
-        "name": "FUEL_TYPE_UNLEADED",
+        "name": "DISABLED",
         "value": 1
       },
       {
-        "name": "FUEL_TYPE_LEADED",
+        "name": "PARTIALLY_ENABLED",
         "value": 2
       },
       {
-        "name": "FUEL_TYPE_DIESEL_1",
-        "value": 3
-      },
-      {
-        "name": "FUEL_TYPE_DIESEL_2",
-        "value": 4
-      },
-      {
-        "name": "FUEL_TYPE_BIODIESEL",
-        "value": 5
-      },
-      {
-        "name": "FUEL_TYPE_E85",
-        "value": 6
-      },
-      {
-        "name": "FUEL_TYPE_LPG",
-        "value": 7
-      },
-      {
-        "name": "FUEL_TYPE_CNG",
-        "value": 8
-      },
-      {
-        "name": "FUEL_TYPE_LNG",
-        "value": 9
-      },
-      {
-        "name": "FUEL_TYPE_ELECTRIC",
-        "value": 10
-      },
-      {
-        "name": "FUEL_TYPE_HYDROGEN",
-        "value": 11
-      },
-      {
-        "name": "FUEL_TYPE_OTHER",
-        "value": 12
-      }
-    ]
-  },
-  {
-    "name": "VehicleApPowerStateReq",
-    "values": [
-      {
-        "name": "ON",
-        "value": 0
-      },
-      {
-        "name": "SHUTDOWN_PREPARE",
-        "value": 1
-      },
-      {
-        "name": "CANCEL_SHUTDOWN",
-        "value": 2
-      },
-      {
-        "name": "FINISHED",
+        "name": "FULLY_ENABLED",
         "value": 3
       }
     ]
   },
   {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleApPowerStateReqIndex",
+    "values": [
+      {
+        "name": "STATE",
+        "value": 0
+      },
+      {
+        "name": "ADDITIONAL",
+        "value": 1
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "RotaryInputType",
+    "values": [
+      {
+        "name": "ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION",
+        "value": 0
+      },
+      {
+        "name": "ROTARY_INPUT_TYPE_AUDIO_VOLUME",
+        "value": 1
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
     "name": "VmsMessageType",
     "values": [
       {
@@ -3006,96 +2107,417 @@
     ]
   },
   {
-    "name": "Obd2CommonIgnitionMonitors",
-    "values": []
-  },
-  {
-    "name": "UserIdentificationAssociationType",
+    "package": "android.hardware.automotive.vehicle",
+    "name": "FuelType",
     "values": [
       {
-        "name": "INVALID",
+        "name": "FUEL_TYPE_UNKNOWN",
         "value": 0
       },
       {
-        "name": "KEY_FOB",
+        "name": "FUEL_TYPE_UNLEADED",
         "value": 1
       },
       {
-        "name": "CUSTOM_1",
-        "value": 101
+        "name": "FUEL_TYPE_LEADED",
+        "value": 2
       },
       {
-        "name": "CUSTOM_2",
-        "value": 102
+        "name": "FUEL_TYPE_DIESEL_1",
+        "value": 3
       },
       {
-        "name": "CUSTOM_3",
-        "value": 103
+        "name": "FUEL_TYPE_DIESEL_2",
+        "value": 4
       },
       {
-        "name": "CUSTOM_4",
-        "value": 104
+        "name": "FUEL_TYPE_BIODIESEL",
+        "value": 5
+      },
+      {
+        "name": "FUEL_TYPE_E85",
+        "value": 6
+      },
+      {
+        "name": "FUEL_TYPE_LPG",
+        "value": 7
+      },
+      {
+        "name": "FUEL_TYPE_CNG",
+        "value": 8
+      },
+      {
+        "name": "FUEL_TYPE_LNG",
+        "value": 9
+      },
+      {
+        "name": "FUEL_TYPE_ELECTRIC",
+        "value": 10
+      },
+      {
+        "name": "FUEL_TYPE_HYDROGEN",
+        "value": 11
+      },
+      {
+        "name": "FUEL_TYPE_OTHER",
+        "value": 12
       }
     ]
   },
   {
-    "name": "EvConnectorType",
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleSeatOccupancyState",
     "values": [
       {
         "name": "UNKNOWN",
         "value": 0
       },
       {
-        "name": "IEC_TYPE_1_AC",
+        "name": "VACANT",
         "value": 1
       },
       {
-        "name": "IEC_TYPE_2_AC",
+        "name": "OCCUPIED",
         "value": 2
-      },
-      {
-        "name": "IEC_TYPE_3_AC",
-        "value": 3
-      },
-      {
-        "name": "IEC_TYPE_4_DC",
-        "value": 4
-      },
-      {
-        "name": "IEC_TYPE_1_CCS_DC",
-        "value": 5
-      },
-      {
-        "name": "IEC_TYPE_2_CCS_DC",
-        "value": 6
-      },
-      {
-        "name": "TESLA_ROADSTER",
-        "value": 7
-      },
-      {
-        "name": "TESLA_HPWC",
-        "value": 8
-      },
-      {
-        "name": "TESLA_SUPERCHARGER",
-        "value": 9
-      },
-      {
-        "name": "GBT_AC",
-        "value": 10
-      },
-      {
-        "name": "GBT_DC",
-        "value": 11
-      },
-      {
-        "name": "OTHER",
-        "value": 101
       }
     ]
   },
   {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "EvStoppingMode",
+    "values": [
+      {
+        "name": "OTHER",
+        "value": 0
+      },
+      {
+        "name": "CREEP",
+        "value": 1
+      },
+      {
+        "name": "ROLL",
+        "value": 2
+      },
+      {
+        "name": "HOLD",
+        "value": 3
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "AutomaticEmergencyBrakingState",
+    "values": [
+      {
+        "name": "OTHER",
+        "value": 0
+      },
+      {
+        "name": "ENABLED",
+        "value": 1
+      },
+      {
+        "name": "ACTIVATED",
+        "value": 2
+      },
+      {
+        "name": "USER_OVERRIDE",
+        "value": 3
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleApPowerStateReport",
+    "values": [
+      {
+        "name": "WAIT_FOR_VHAL",
+        "value": 1
+      },
+      {
+        "name": "DEEP_SLEEP_ENTRY",
+        "value": 2
+      },
+      {
+        "name": "DEEP_SLEEP_EXIT",
+        "value": 3
+      },
+      {
+        "name": "SHUTDOWN_POSTPONE",
+        "value": 4
+      },
+      {
+        "name": "SHUTDOWN_START",
+        "value": 5
+      },
+      {
+        "name": "ON",
+        "value": 6
+      },
+      {
+        "name": "SHUTDOWN_PREPARE",
+        "value": 7
+      },
+      {
+        "name": "SHUTDOWN_CANCELLED",
+        "value": 8
+      },
+      {
+        "name": "HIBERNATION_ENTRY",
+        "value": 9
+      },
+      {
+        "name": "HIBERNATION_EXIT",
+        "value": 10
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "SwitchUserMessageType",
+    "values": [
+      {
+        "name": "UNKNOWN",
+        "value": 0
+      },
+      {
+        "name": "LEGACY_ANDROID_SWITCH",
+        "value": 1
+      },
+      {
+        "name": "ANDROID_SWITCH",
+        "value": 2
+      },
+      {
+        "name": "VEHICLE_RESPONSE",
+        "value": 3
+      },
+      {
+        "name": "VEHICLE_REQUEST",
+        "value": 4
+      },
+      {
+        "name": "ANDROID_POST_SWITCH",
+        "value": 5
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleAreaMirror",
+    "values": [
+      {
+        "name": "DRIVER_LEFT",
+        "value": 1
+      },
+      {
+        "name": "DRIVER_RIGHT",
+        "value": 2
+      },
+      {
+        "name": "DRIVER_CENTER",
+        "value": 4
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "TrailerState",
+    "values": [
+      {
+        "name": "UNKNOWN",
+        "value": 0
+      },
+      {
+        "name": "NOT_PRESENT",
+        "value": 1
+      },
+      {
+        "name": "PRESENT",
+        "value": 2
+      },
+      {
+        "name": "ERROR",
+        "value": 3
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "EvsServiceState",
+    "values": [
+      {
+        "name": "OFF",
+        "value": 0
+      },
+      {
+        "name": "ON",
+        "value": 1
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleHwKeyInputAction",
+    "values": [
+      {
+        "name": "ACTION_DOWN",
+        "value": 0
+      },
+      {
+        "name": "ACTION_UP",
+        "value": 1
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "BlindSpotWarningState",
+    "values": [
+      {
+        "name": "OTHER",
+        "value": 0
+      },
+      {
+        "name": "NO_WARNING",
+        "value": 1
+      },
+      {
+        "name": "WARNING",
+        "value": 2
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleGear",
+    "values": [
+      {
+        "name": "GEAR_UNKNOWN",
+        "value": 0
+      },
+      {
+        "name": "GEAR_NEUTRAL",
+        "value": 1
+      },
+      {
+        "name": "GEAR_REVERSE",
+        "value": 2
+      },
+      {
+        "name": "GEAR_PARK",
+        "value": 4
+      },
+      {
+        "name": "GEAR_DRIVE",
+        "value": 8
+      },
+      {
+        "name": "GEAR_1",
+        "value": 16
+      },
+      {
+        "name": "GEAR_2",
+        "value": 32
+      },
+      {
+        "name": "GEAR_3",
+        "value": 64
+      },
+      {
+        "name": "GEAR_4",
+        "value": 128
+      },
+      {
+        "name": "GEAR_5",
+        "value": 256
+      },
+      {
+        "name": "GEAR_6",
+        "value": 512
+      },
+      {
+        "name": "GEAR_7",
+        "value": 1024
+      },
+      {
+        "name": "GEAR_8",
+        "value": 2048
+      },
+      {
+        "name": "GEAR_9",
+        "value": 4096
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VmsStartSessionMessageIntegerValuesIndex",
+    "values": [
+      {
+        "name": "MESSAGE_TYPE",
+        "value": 0
+      },
+      {
+        "name": "SERVICE_ID",
+        "value": 1
+      },
+      {
+        "name": "CLIENT_ID",
+        "value": 2
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "Obd2FuelSystemStatus",
+    "values": [
+      {
+        "name": "OPEN_INSUFFICIENT_ENGINE_TEMPERATURE",
+        "value": 1
+      },
+      {
+        "name": "CLOSED_LOOP",
+        "value": 2
+      },
+      {
+        "name": "OPEN_ENGINE_LOAD_OR_DECELERATION",
+        "value": 4
+      },
+      {
+        "name": "OPEN_SYSTEM_FAILURE",
+        "value": 8
+      },
+      {
+        "name": "CLOSED_LOOP_BUT_FEEDBACK_FAULT",
+        "value": 16
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "ElectronicTollCollectionCardStatus",
+    "values": [
+      {
+        "name": "UNKNOWN",
+        "value": 0
+      },
+      {
+        "name": "ELECTRONIC_TOLL_COLLECTION_CARD_VALID",
+        "value": 1
+      },
+      {
+        "name": "ELECTRONIC_TOLL_COLLECTION_CARD_INVALID",
+        "value": 2
+      },
+      {
+        "name": "ELECTRONIC_TOLL_COLLECTION_CARD_NOT_INSERTED",
+        "value": 3
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
     "name": "VehicleApPowerStateShutdownParam",
     "values": [
       {
@@ -3125,271 +2547,53 @@
     ]
   },
   {
-    "name": "VmsOfferingMessageIntegerValuesIndex",
+    "package": "android.hardware.automotive.vehicle",
+    "name": "CustomInputType",
     "values": [
       {
-        "name": "MESSAGE_TYPE",
-        "value": 0
+        "name": "CUSTOM_EVENT_F1",
+        "value": 1001
       },
       {
-        "name": "PUBLISHER_ID",
-        "value": 1
+        "name": "CUSTOM_EVENT_F2",
+        "value": 1002
       },
       {
-        "name": "NUMBER_OF_OFFERS",
-        "value": 2
+        "name": "CUSTOM_EVENT_F3",
+        "value": 1003
       },
       {
-        "name": "OFFERING_START",
-        "value": 3
+        "name": "CUSTOM_EVENT_F4",
+        "value": 1004
+      },
+      {
+        "name": "CUSTOM_EVENT_F5",
+        "value": 1005
+      },
+      {
+        "name": "CUSTOM_EVENT_F6",
+        "value": 1006
+      },
+      {
+        "name": "CUSTOM_EVENT_F7",
+        "value": 1007
+      },
+      {
+        "name": "CUSTOM_EVENT_F8",
+        "value": 1008
+      },
+      {
+        "name": "CUSTOM_EVENT_F9",
+        "value": 1009
+      },
+      {
+        "name": "CUSTOM_EVENT_F10",
+        "value": 1010
       }
     ]
   },
   {
-    "name": "VehicleAreaSeat",
-    "values": [
-      {
-        "name": "ROW_1_LEFT",
-        "value": 1
-      },
-      {
-        "name": "ROW_1_CENTER",
-        "value": 2
-      },
-      {
-        "name": "ROW_1_RIGHT",
-        "value": 4
-      },
-      {
-        "name": "ROW_2_LEFT",
-        "value": 16
-      },
-      {
-        "name": "ROW_2_CENTER",
-        "value": 32
-      },
-      {
-        "name": "ROW_2_RIGHT",
-        "value": 64
-      },
-      {
-        "name": "ROW_3_LEFT",
-        "value": 256
-      },
-      {
-        "name": "ROW_3_CENTER",
-        "value": 512
-      },
-      {
-        "name": "ROW_3_RIGHT",
-        "value": 1024
-      }
-    ]
-  },
-  {
-    "name": "VehicleVendorPermission",
-    "values": [
-      {
-        "name": "PERMISSION_DEFAULT",
-        "value": 0
-      },
-      {
-        "name": "PERMISSION_SET_VENDOR_CATEGORY_WINDOW",
-        "value": 1
-      },
-      {
-        "name": "PERMISSION_GET_VENDOR_CATEGORY_WINDOW",
-        "value": 2
-      },
-      {
-        "name": "PERMISSION_SET_VENDOR_CATEGORY_DOOR",
-        "value": 3
-      },
-      {
-        "name": "PERMISSION_GET_VENDOR_CATEGORY_DOOR",
-        "value": 4
-      },
-      {
-        "name": "PERMISSION_SET_VENDOR_CATEGORY_SEAT",
-        "value": 5
-      },
-      {
-        "name": "PERMISSION_GET_VENDOR_CATEGORY_SEAT",
-        "value": 6
-      },
-      {
-        "name": "PERMISSION_SET_VENDOR_CATEGORY_MIRROR",
-        "value": 7
-      },
-      {
-        "name": "PERMISSION_GET_VENDOR_CATEGORY_MIRROR",
-        "value": 8
-      },
-      {
-        "name": "PERMISSION_SET_VENDOR_CATEGORY_INFO",
-        "value": 9
-      },
-      {
-        "name": "PERMISSION_GET_VENDOR_CATEGORY_INFO",
-        "value": 10
-      },
-      {
-        "name": "PERMISSION_SET_VENDOR_CATEGORY_ENGINE",
-        "value": 11
-      },
-      {
-        "name": "PERMISSION_GET_VENDOR_CATEGORY_ENGINE",
-        "value": 12
-      },
-      {
-        "name": "PERMISSION_SET_VENDOR_CATEGORY_HVAC",
-        "value": 13
-      },
-      {
-        "name": "PERMISSION_GET_VENDOR_CATEGORY_HVAC",
-        "value": 14
-      },
-      {
-        "name": "PERMISSION_SET_VENDOR_CATEGORY_LIGHT",
-        "value": 15
-      },
-      {
-        "name": "PERMISSION_GET_VENDOR_CATEGORY_LIGHT",
-        "value": 16
-      },
-      {
-        "name": "PERMISSION_SET_VENDOR_CATEGORY_1",
-        "value": 65536
-      },
-      {
-        "name": "PERMISSION_GET_VENDOR_CATEGORY_1",
-        "value": 69632
-      },
-      {
-        "name": "PERMISSION_SET_VENDOR_CATEGORY_2",
-        "value": 131072
-      },
-      {
-        "name": "PERMISSION_GET_VENDOR_CATEGORY_2",
-        "value": 135168
-      },
-      {
-        "name": "PERMISSION_SET_VENDOR_CATEGORY_3",
-        "value": 196608
-      },
-      {
-        "name": "PERMISSION_GET_VENDOR_CATEGORY_3",
-        "value": 200704
-      },
-      {
-        "name": "PERMISSION_SET_VENDOR_CATEGORY_4",
-        "value": 262144
-      },
-      {
-        "name": "PERMISSION_GET_VENDOR_CATEGORY_4",
-        "value": 266240
-      },
-      {
-        "name": "PERMISSION_SET_VENDOR_CATEGORY_5",
-        "value": 327680
-      },
-      {
-        "name": "PERMISSION_GET_VENDOR_CATEGORY_5",
-        "value": 331776
-      },
-      {
-        "name": "PERMISSION_SET_VENDOR_CATEGORY_6",
-        "value": 393216
-      },
-      {
-        "name": "PERMISSION_GET_VENDOR_CATEGORY_6",
-        "value": 397312
-      },
-      {
-        "name": "PERMISSION_SET_VENDOR_CATEGORY_7",
-        "value": 458752
-      },
-      {
-        "name": "PERMISSION_GET_VENDOR_CATEGORY_7",
-        "value": 462848
-      },
-      {
-        "name": "PERMISSION_SET_VENDOR_CATEGORY_8",
-        "value": 524288
-      },
-      {
-        "name": "PERMISSION_GET_VENDOR_CATEGORY_8",
-        "value": 528384
-      },
-      {
-        "name": "PERMISSION_SET_VENDOR_CATEGORY_9",
-        "value": 589824
-      },
-      {
-        "name": "PERMISSION_GET_VENDOR_CATEGORY_9",
-        "value": 593920
-      },
-      {
-        "name": "PERMISSION_SET_VENDOR_CATEGORY_10",
-        "value": 655360
-      },
-      {
-        "name": "PERMISSION_GET_VENDOR_CATEGORY_10",
-        "value": 659456
-      },
-      {
-        "name": "PERMISSION_NOT_ACCESSIBLE",
-        "value": 4026531840
-      }
-    ]
-  },
-  {
-    "name": "VehiclePropertyAccess",
-    "values": [
-      {
-        "name": "NONE",
-        "value": 0
-      },
-      {
-        "name": "READ",
-        "value": 1
-      },
-      {
-        "name": "WRITE",
-        "value": 2
-      },
-      {
-        "name": "READ_WRITE",
-        "value": 3
-      }
-    ]
-  },
-  {
-    "name": "VmsAvailabilityStateIntegerValuesIndex",
-    "values": [
-      {
-        "name": "MESSAGE_TYPE",
-        "value": 0
-      },
-      {
-        "name": "SEQUENCE_NUMBER",
-        "value": 1
-      },
-      {
-        "name": "NUMBER_OF_ASSOCIATED_LAYERS",
-        "value": 2
-      },
-      {
-        "name": "LAYERS_START",
-        "value": 3
-      }
-    ]
-  },
-  {
-    "name": "Obd2SparkIgnitionMonitors",
-    "values": []
-  },
-  {
+    "package": "android.hardware.automotive.vehicle",
     "name": "VehicleTurnSignal",
     "values": [
       {
@@ -3407,53 +2611,1992 @@
     ]
   },
   {
-    "name": "VmsPublisherInformationIntegerValuesIndex",
+    "package": "android.hardware.automotive.vehicle",
+    "name": "ElectronicTollCollectionCardType",
+    "values": [
+      {
+        "name": "UNKNOWN",
+        "value": 0
+      },
+      {
+        "name": "JP_ELECTRONIC_TOLL_COLLECTION_CARD",
+        "value": 1
+      },
+      {
+        "name": "JP_ELECTRONIC_TOLL_COLLECTION_CARD_V2",
+        "value": 2
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleProperty",
+    "values": [
+      {
+        "name": "Undefined property.",
+        "value": 0
+      },
+      {
+        "name": "VIN of vehicle",
+        "value": 286261504,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "Manufacturer of vehicle",
+        "value": 286261505,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "Model of vehicle",
+        "value": 286261506,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "Model year of vehicle.",
+        "value": 289407235,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:YEAR"
+      },
+      {
+        "name": "Fuel capacity of the vehicle in milliliters",
+        "value": 291504388,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:MILLILITER"
+      },
+      {
+        "name": "List of fuels the vehicle may use.",
+        "value": 289472773,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "FuelType"
+      },
+      {
+        "name": "Nominal battery capacity for EV or hybrid vehicle",
+        "value": 291504390,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:WH"
+      },
+      {
+        "name": "List of connectors this EV may use",
+        "value": 289472775,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "data_enum": "EvConnectorType",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "Fuel door location",
+        "value": 289407240,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "data_enum": "PortLocationType",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "EV port location",
+        "value": 289407241,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "PortLocationType"
+      },
+      {
+        "name": "INFO_DRIVER_SEAT",
+        "value": 356516106,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "data_enum": "VehicleAreaSeat",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "Exterior dimensions of vehicle.",
+        "value": 289472779,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:MILLIMETER"
+      },
+      {
+        "name": "Multiple EV port locations",
+        "value": 289472780,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "PortLocationType"
+      },
+      {
+        "name": "Current odometer value of the vehicle",
+        "value": 291504644,
+        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:KILOMETER"
+      },
+      {
+        "name": "Speed of the vehicle",
+        "value": 291504647,
+        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:METER_PER_SEC"
+      },
+      {
+        "name": "Speed of the vehicle for displays",
+        "value": 291504648,
+        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:METER_PER_SEC"
+      },
+      {
+        "name": "Front bicycle model steering angle for vehicle",
+        "value": 291504649,
+        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:DEGREES"
+      },
+      {
+        "name": "Rear bicycle model steering angle for vehicle",
+        "value": 291504656,
+        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:DEGREES"
+      },
+      {
+        "name": "Temperature of engine coolant",
+        "value": 291504897,
+        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:CELSIUS"
+      },
+      {
+        "name": "Engine oil level",
+        "value": 289407747,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "VehicleOilLevel"
+      },
+      {
+        "name": "Temperature of engine oil",
+        "value": 291504900,
+        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:CELSIUS"
+      },
+      {
+        "name": "Engine rpm",
+        "value": 291504901,
+        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:RPM"
+      },
+      {
+        "name": "Reports wheel ticks",
+        "value": 290521862,
+        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "FUEL_LEVEL",
+        "value": 291504903,
+        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:MILLILITER"
+      },
+      {
+        "name": "Fuel door open",
+        "value": 287310600,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Battery level for EV or hybrid vehicle",
+        "value": 291504905,
+        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:WH"
+      },
+      {
+        "name": "Current battery capacity for EV or hybrid vehicle",
+        "value": 291504909,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:WH"
+      },
+      {
+        "name": "EV charge port open",
+        "value": 287310602,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "EV charge port connected",
+        "value": 287310603,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "EV instantaneous charge rate in milliwatts",
+        "value": 291504908,
+        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:MW"
+      },
+      {
+        "name": "Range remaining",
+        "value": 291504904,
+        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "unit": "VehicleUnit:METER"
+      },
+      {
+        "name": "Tire pressure",
+        "value": 392168201,
+        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:KILOPASCAL"
+      },
+      {
+        "name": "Critically low tire pressure",
+        "value": 392168202,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:KILOPASCAL"
+      },
+      {
+        "name": "Represents feature for engine idle automatic stop.",
+        "value": 287310624,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Currently selected gear",
+        "value": 289408000,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "VehicleGear"
+      },
+      {
+        "name": "CURRENT_GEAR",
+        "value": 289408001,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "VehicleGear"
+      },
+      {
+        "name": "Parking brake state.",
+        "value": 287310850,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "PARKING_BRAKE_AUTO_APPLY",
+        "value": 287310851,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "Regenerative braking level of a electronic vehicle",
+        "value": 289408012,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Warning for fuel low level.",
+        "value": 287310853,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "Night mode",
+        "value": 287310855,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "State of the vehicles turn signals",
+        "value": 289408008,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "VehicleTurnSignal"
+      },
+      {
+        "name": "Represents ignition state",
+        "value": 289408009,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "VehicleIgnitionState"
+      },
+      {
+        "name": "ABS is active",
+        "value": 287310858,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "Traction Control is active",
+        "value": 287310859,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "Represents property for the current stopping mode of the vehicle.",
+        "value": 289408013,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "data_enum": "EvStoppingMode"
+      },
+      {
+        "name": "HVAC Properties",
+        "value": 356517120,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Fan direction setting",
+        "value": 356517121,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "data_enum": "VehicleHvacFanDirection"
+      },
+      {
+        "name": "HVAC current temperature.",
+        "value": 358614274,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:CELSIUS"
+      },
+      {
+        "name": "HVAC_TEMPERATURE_SET",
+        "value": 358614275,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "unit": "VehicleUnit:CELSIUS"
+      },
+      {
+        "name": "HVAC_DEFROSTER",
+        "value": 320865540,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "HVAC_AC_ON",
+        "value": 354419973,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "config_flags": "Supported"
+      },
+      {
+        "name": "HVAC_MAX_AC_ON",
+        "value": 354419974,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "HVAC_MAX_DEFROST_ON",
+        "value": 354419975,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "HVAC_RECIRC_ON",
+        "value": 354419976,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Enable temperature coupling between areas.",
+        "value": 354419977,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "HVAC_AUTO_ON",
+        "value": 354419978,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "HVAC_SEAT_TEMPERATURE",
+        "value": 356517131,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Side Mirror Heat",
+        "value": 339739916,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "HVAC_STEERING_WHEEL_HEAT",
+        "value": 289408269,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Temperature units for display",
+        "value": 289408270,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "data_enum": "VehicleUnit"
+      },
+      {
+        "name": "Actual fan speed",
+        "value": 356517135,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "HVAC_POWER_ON",
+        "value": 354419984,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Fan Positions Available",
+        "value": 356582673,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "VehicleHvacFanDirection"
+      },
+      {
+        "name": "HVAC_AUTO_RECIRC_ON",
+        "value": 354419986,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Seat ventilation",
+        "value": 356517139,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "HVAC_ELECTRIC_DEFROSTER_ON",
+        "value": 320865556,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Suggested values for setting HVAC temperature.",
+        "value": 291570965,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Distance units for display",
+        "value": 289408512,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "data_enum": "VehicleUnit"
+      },
+      {
+        "name": "Fuel volume units for display",
+        "value": 289408513,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "data_enum": "VehicleUnit"
+      },
+      {
+        "name": "Tire pressure units for display",
+        "value": 289408514,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "data_enum": "VehicleUnit"
+      },
+      {
+        "name": "EV battery units for display",
+        "value": 289408515,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "data_enum": "VehicleUnit"
+      },
+      {
+        "name": "Fuel consumption units for display",
+        "value": 287311364,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Speed units for display",
+        "value": 289408517,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "ANDROID_EPOCH_TIME",
+        "value": 290457094,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:WRITE",
+        "unit": "VehicleUnit:MILLI_SECS"
+      },
+      {
+        "name": "External encryption binding seed.",
+        "value": 292554247,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Outside temperature",
+        "value": 291505923,
+        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:CELSIUS"
+      },
+      {
+        "name": "Property to control power state of application processor",
+        "value": 289475072,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "Property to report power state of application processor",
+        "value": 289475073,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "AP_POWER_BOOTUP_REASON",
+        "value": 289409538,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "Property to represent brightness of the display.",
+        "value": 289409539,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Property to represent brightness of the displays which are controlled separately.",
+        "value": 289475076,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "HW_KEY_INPUT",
+        "value": 289475088,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "config_flags": ""
+      },
+      {
+        "name": "HW_KEY_INPUT_V2",
+        "value": 367004177,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "config_flags": ""
+      },
+      {
+        "name": "HW_MOTION_INPUT",
+        "value": 367004178,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "config_flags": ""
+      },
+      {
+        "name": "HW_ROTARY_INPUT",
+        "value": 289475104,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "data_enum": "RotaryInputType",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "Defines a custom OEM partner input event.",
+        "value": 289475120,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "data_enum": "CustomInputType",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "DOOR_POS",
+        "value": 373295872,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Door move",
+        "value": 373295873,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Door lock",
+        "value": 371198722,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Door child lock feature enabled",
+        "value": 371198723,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Mirror Z Position",
+        "value": 339741504,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Mirror Z Move",
+        "value": 339741505,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Mirror Y Position",
+        "value": 339741506,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Mirror Y Move",
+        "value": 339741507,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Mirror Lock",
+        "value": 287312708,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Mirror Fold",
+        "value": 287312709,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Represents property for Mirror Auto Fold feature.",
+        "value": 337644358,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Represents property for Mirror Auto Tilt feature.",
+        "value": 337644359,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Seat memory select",
+        "value": 356518784,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:WRITE"
+      },
+      {
+        "name": "Seat memory set",
+        "value": 356518785,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:WRITE"
+      },
+      {
+        "name": "Seatbelt buckled",
+        "value": 354421634,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Seatbelt height position",
+        "value": 356518787,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Seatbelt height move",
+        "value": 356518788,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "SEAT_FORE_AFT_POS",
+        "value": 356518789,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "SEAT_FORE_AFT_MOVE",
+        "value": 356518790,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Seat backrest angle 1 position",
+        "value": 356518791,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Seat backrest angle 1 move",
+        "value": 356518792,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Seat backrest angle 2 position",
+        "value": 356518793,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Seat backrest angle 2 move",
+        "value": 356518794,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Seat height position",
+        "value": 356518795,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Seat height move",
+        "value": 356518796,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Seat depth position",
+        "value": 356518797,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Seat depth move",
+        "value": 356518798,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Seat tilt position",
+        "value": 356518799,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Seat tilt move",
+        "value": 356518800,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "SEAT_LUMBAR_FORE_AFT_POS",
+        "value": 356518801,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "SEAT_LUMBAR_FORE_AFT_MOVE",
+        "value": 356518802,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Lumbar side support position",
+        "value": 356518803,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Lumbar side support move",
+        "value": 356518804,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "SEAT_HEADREST_HEIGHT_POS",
+        "value": 289409941,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Headrest height position",
+        "value": 356518820,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Headrest height move",
+        "value": 356518806,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Headrest angle position",
+        "value": 356518807,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Headrest angle move",
+        "value": 356518808,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "SEAT_HEADREST_FORE_AFT_POS",
+        "value": 356518809,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "SEAT_HEADREST_FORE_AFT_MOVE",
+        "value": 356518810,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Represents property for the seat footwell lights state.",
+        "value": 356518811,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "VehicleLightState"
+      },
+      {
+        "name": "Represents property for the seat footwell lights switch.",
+        "value": 356518812,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "data_enum": "VehicleLightSwitch"
+      },
+      {
+        "name": "Represents property for Seat easy access feature.",
+        "value": 354421661,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "SEAT_AIRBAG_ENABLED",
+        "value": 354421662,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "SEAT_CUSHION_SIDE_SUPPORT_POS",
+        "value": 356518815,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Represents property for movement direction and speed of seat cushion side support.",
+        "value": 356518816,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "SEAT_LUMBAR_VERTICAL_POS",
+        "value": 356518817,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Represents property for vertical movement direction and speed of seat lumbar support.",
+        "value": 356518818,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "SEAT_WALK_IN_POS",
+        "value": 356518819,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Seat Occupancy",
+        "value": 356518832,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "VehicleSeatOccupancyState"
+      },
+      {
+        "name": "Window Position",
+        "value": 322964416,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Window Move",
+        "value": 322964417,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Window Lock",
+        "value": 320867268,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "WINDSHIELD_WIPERS_PERIOD",
+        "value": 322964421,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:MILLI_SECS"
+      },
+      {
+        "name": "Windshield wipers state.",
+        "value": 322964422,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "WindshieldWipersState"
+      },
+      {
+        "name": "Windshield wipers switch.",
+        "value": 322964423,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "data_enum": "WindshieldWipersSwitch"
+      },
+      {
+        "name": "Steering wheel depth position",
+        "value": 289410016,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Steering wheel depth movement",
+        "value": 289410017,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Steering wheel height position",
+        "value": 289410018,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Steering wheel height movement",
+        "value": 289410019,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Steering wheel theft lock feature enabled",
+        "value": 287312868,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Steering wheel locked",
+        "value": 287312869,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Steering wheel easy access feature enabled",
+        "value": 287312870,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Property that represents the current position of the glove box door.",
+        "value": 356518896,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Lock or unlock the glove box.",
+        "value": 354421745,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "VEHICLE_MAP_SERVICE",
+        "value": 299895808,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Characterization of inputs used for computing location.",
+        "value": 289410064,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "OBD2 Live Sensor Data",
+        "value": 299896064,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "OBD2 Freeze Frame Sensor Data",
+        "value": 299896065,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "OBD2 Freeze Frame Information",
+        "value": 299896066,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "OBD2 Freeze Frame Clear",
+        "value": 299896067,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:WRITE"
+      },
+      {
+        "name": "Headlights State",
+        "value": 289410560,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "VehicleLightState"
+      },
+      {
+        "name": "High beam lights state",
+        "value": 289410561,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "VehicleLightState"
+      },
+      {
+        "name": "Fog light state",
+        "value": 289410562,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "VehicleLightState"
+      },
+      {
+        "name": "Hazard light status",
+        "value": 289410563,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "VehicleLightState"
+      },
+      {
+        "name": "Headlight switch",
+        "value": 289410576,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "data_enum": "VehicleLightSwitch"
+      },
+      {
+        "name": "High beam light switch",
+        "value": 289410577,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "data_enum": "VehicleLightSwitch"
+      },
+      {
+        "name": "Fog light switch",
+        "value": 289410578,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "data_enum": "VehicleLightSwitch"
+      },
+      {
+        "name": "Hazard light switch",
+        "value": 289410579,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "data_enum": "VehicleLightSwitch"
+      },
+      {
+        "name": "Cabin lights",
+        "value": 289410817,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "VehicleLightState"
+      },
+      {
+        "name": "Cabin lights switch",
+        "value": 289410818,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "data_enum": "VehicleLightSwitch"
+      },
+      {
+        "name": "Reading lights",
+        "value": 356519683,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "VehicleLightState"
+      },
+      {
+        "name": "Reading lights switch",
+        "value": 356519684,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "data_enum": "VehicleLightSwitch"
+      },
+      {
+        "name": "Steering wheel lights state",
+        "value": 289410828,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "VehicleLightState"
+      },
+      {
+        "name": "Steering wheel lights switch",
+        "value": 289410829,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "data_enum": "VehicleLightSwitch"
+      },
+      {
+        "name": "Support customize permissions for vendor properties",
+        "value": 287313669,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "Allow disabling optional featurs from vhal.",
+        "value": 286265094,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "Defines the initial Android user to be used during initialization.",
+        "value": 299896583,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Defines a request to switch the foreground Android user.",
+        "value": 299896584,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Called by the Android System after an Android user was created.",
+        "value": 299896585,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Called by the Android System after an Android user was removed.",
+        "value": 299896586,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "access": "VehiclePropertyAccess:WRITE"
+      },
+      {
+        "name": "USER_IDENTIFICATION_ASSOCIATION",
+        "value": 299896587,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "EVS_SERVICE_REQUEST",
+        "value": 289476368,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "Defines a request to apply power policy.",
+        "value": 286265121,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "POWER_POLICY_GROUP_REQ",
+        "value": 286265122,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "Notifies the current power policy to VHAL layer.",
+        "value": 286265123,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "WATCHDOG_ALIVE",
+        "value": 290459441,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:WRITE"
+      },
+      {
+        "name": "Defines a process terminated by car watchdog and the reason of termination.",
+        "value": 299896626,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:WRITE"
+      },
+      {
+        "name": "Defines an event that VHAL signals to car watchdog as a heartbeat.",
+        "value": 290459443,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "Starts the ClusterUI in cluster display.",
+        "value": 289410868,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "Changes the state of the cluster display.",
+        "value": 289476405,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "Reports the current display state and ClusterUI state.",
+        "value": 299896630,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:WRITE"
+      },
+      {
+        "name": "Requests to change the cluster display state to show some ClusterUI.",
+        "value": 289410871,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:WRITE"
+      },
+      {
+        "name": "Informs the current navigation state.",
+        "value": 292556600,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:WRITE"
+      },
+      {
+        "name": "Electronic Toll Collection card type.",
+        "value": 289410873,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "ElectronicTollCollectionCardType"
+      },
+      {
+        "name": "Electronic Toll Collection card status.",
+        "value": 289410874,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "ElectronicTollCollectionCardStatus"
+      },
+      {
+        "name": "Front fog lights state",
+        "value": 289410875,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "VehicleLightState"
+      },
+      {
+        "name": "Front fog lights switch",
+        "value": 289410876,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "data_enum": "VehicleLightSwitch"
+      },
+      {
+        "name": "Rear fog lights state",
+        "value": 289410877,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "VehicleLightState"
+      },
+      {
+        "name": "Rear fog lights switch",
+        "value": 289410878,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "data_enum": "VehicleLightSwitch"
+      },
+      {
+        "name": "Indicates the maximum current draw threshold for charging set by the user",
+        "value": 291508031,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "unit": "VehicleUnit:AMPERE"
+      },
+      {
+        "name": "Indicates the maximum charge percent threshold set by the user",
+        "value": 291508032,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Charging state of the car",
+        "value": 289410881,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "EvChargeState"
+      },
+      {
+        "name": "Start or stop charging the EV battery",
+        "value": 287313730,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Estimated charge time remaining in seconds",
+        "value": 289410883,
+        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:SECS"
+      },
+      {
+        "name": "EV_REGENERATIVE_BRAKING_STATE",
+        "value": 289410884,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "EvRegenerativeBrakingState"
+      },
+      {
+        "name": "Indicates if there is a trailer present or not.",
+        "value": 289410885,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "TrailerState"
+      },
+      {
+        "name": "VEHICLE_CURB_WEIGHT",
+        "value": 289410886,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:KILOGRAM"
+      },
+      {
+        "name": "GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT",
+        "value": 289410887,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "GsrComplianceRequirementType"
+      },
+      {
+        "name": "SUPPORTED_PROPERTY_IDS",
+        "value": 289476424,
+        "change_mode": "VehiclePropertyChangeMode:STATIC",
+        "access": "VehiclePropertyAccess:READ"
+      },
+      {
+        "name": "Request the head unit to be shutdown.",
+        "value": 289410889,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:WRITE",
+        "data_enum": "VehicleApPowerStateShutdownParam"
+      },
+      {
+        "name": "Whether the vehicle is currently in use.",
+        "value": 287313738,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "Start of ADAS Properties",
+        "value": 287313920,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "AUTOMATIC_EMERGENCY_BRAKING_STATE",
+        "value": 289411073,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "ErrorState"
+      },
+      {
+        "name": "FORWARD_COLLISION_WARNING_ENABLED",
+        "value": 287313922,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "FORWARD_COLLISION_WARNING_STATE",
+        "value": 289411075,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "ErrorState"
+      },
+      {
+        "name": "BLIND_SPOT_WARNING_ENABLED",
+        "value": 287313924,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "BLIND_SPOT_WARNING_STATE",
+        "value": 339742725,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "ErrorState"
+      },
+      {
+        "name": "LANE_DEPARTURE_WARNING_ENABLED",
+        "value": 287313926,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "LANE_DEPARTURE_WARNING_STATE",
+        "value": 289411079,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "ErrorState"
+      },
+      {
+        "name": "LANE_KEEP_ASSIST_ENABLED",
+        "value": 287313928,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "LANE_KEEP_ASSIST_STATE",
+        "value": 289411081,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "ErrorState"
+      },
+      {
+        "name": "LANE_CENTERING_ASSIST_ENABLED",
+        "value": 287313930,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "LANE_CENTERING_ASSIST_COMMAND",
+        "value": 289411083,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:WRITE",
+        "data_enum": "LaneCenteringAssistCommand"
+      },
+      {
+        "name": "LANE_CENTERING_ASSIST_STATE",
+        "value": 289411084,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "ErrorState"
+      },
+      {
+        "name": "EMERGENCY_LANE_KEEP_ASSIST_ENABLED",
+        "value": 287313933
+      },
+      {
+        "name": "EMERGENCY_LANE_KEEP_ASSIST_STATE",
+        "value": 289411086,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "ErrorState"
+      },
+      {
+        "name": "CRUISE_CONTROL_ENABLED",
+        "value": 287313935,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "CRUISE_CONTROL_TYPE",
+        "value": 289411088,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "data_enum": "ErrorState"
+      },
+      {
+        "name": "CRUISE_CONTROL_STATE",
+        "value": 289411089,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "ErrorState"
+      },
+      {
+        "name": "CRUISE_CONTROL_COMMAND",
+        "value": 289411090,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:WRITE",
+        "data_enum": "CruiseControlCommand"
+      },
+      {
+        "name": "CRUISE_CONTROL_TARGET_SPEED",
+        "value": 291508243,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:METER_PER_SEC"
+      },
+      {
+        "name": "ADAPTIVE_CRUISE_CONTROL_TARGET_TIME_GAP",
+        "value": 289411092,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE",
+        "unit": "VehicleUnit:MILLI_SECS"
+      },
+      {
+        "name": "ADAPTIVE_CRUISE_CONTROL_LEAD_VEHICLE_MEASURED_DISTANCE",
+        "value": 289411093,
+        "change_mode": "VehiclePropertyChangeMode:CONTINUOUS",
+        "access": "VehiclePropertyAccess:READ",
+        "unit": "VehicleUnit:MILLIMETER"
+      },
+      {
+        "name": "HANDS_ON_DETECTION_ENABLED",
+        "value": 287313942,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ_WRITE"
+      },
+      {
+        "name": "HANDS_ON_DETECTION_DRIVER_STATE",
+        "value": 289411095,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "ErrorState"
+      },
+      {
+        "name": "HANDS_ON_DETECTION_WARNING",
+        "value": 289411096,
+        "change_mode": "VehiclePropertyChangeMode:ON_CHANGE",
+        "access": "VehiclePropertyAccess:READ",
+        "data_enum": "ErrorState"
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "DiagnosticIntegerSensorIndex",
+    "values": [
+      {
+        "name": "FUEL_SYSTEM_STATUS",
+        "value": 0
+      },
+      {
+        "name": "MALFUNCTION_INDICATOR_LIGHT_ON",
+        "value": 1
+      },
+      {
+        "name": "IGNITION_MONITORS_SUPPORTED",
+        "value": 2
+      },
+      {
+        "name": "IGNITION_SPECIFIC_MONITORS",
+        "value": 3
+      },
+      {
+        "name": "INTAKE_AIR_TEMPERATURE",
+        "value": 4
+      },
+      {
+        "name": "COMMANDED_SECONDARY_AIR_STATUS",
+        "value": 5
+      },
+      {
+        "name": "NUM_OXYGEN_SENSORS_PRESENT",
+        "value": 6
+      },
+      {
+        "name": "RUNTIME_SINCE_ENGINE_START",
+        "value": 7
+      },
+      {
+        "name": "DISTANCE_TRAVELED_WITH_MALFUNCTION_INDICATOR_LIGHT_ON",
+        "value": 8
+      },
+      {
+        "name": "WARMUPS_SINCE_CODES_CLEARED",
+        "value": 9
+      },
+      {
+        "name": "DISTANCE_TRAVELED_SINCE_CODES_CLEARED",
+        "value": 10
+      },
+      {
+        "name": "ABSOLUTE_BAROMETRIC_PRESSURE",
+        "value": 11
+      },
+      {
+        "name": "CONTROL_MODULE_VOLTAGE",
+        "value": 12
+      },
+      {
+        "name": "AMBIENT_AIR_TEMPERATURE",
+        "value": 13
+      },
+      {
+        "name": "TIME_WITH_MALFUNCTION_LIGHT_ON",
+        "value": 14
+      },
+      {
+        "name": "TIME_SINCE_TROUBLE_CODES_CLEARED",
+        "value": 15
+      },
+      {
+        "name": "MAX_FUEL_AIR_EQUIVALENCE_RATIO",
+        "value": 16
+      },
+      {
+        "name": "MAX_OXYGEN_SENSOR_VOLTAGE",
+        "value": 17
+      },
+      {
+        "name": "MAX_OXYGEN_SENSOR_CURRENT",
+        "value": 18
+      },
+      {
+        "name": "MAX_INTAKE_MANIFOLD_ABSOLUTE_PRESSURE",
+        "value": 19
+      },
+      {
+        "name": "MAX_AIR_FLOW_RATE_FROM_MASS_AIR_FLOW_SENSOR",
+        "value": 20
+      },
+      {
+        "name": "FUEL_TYPE",
+        "value": 21
+      },
+      {
+        "name": "FUEL_RAIL_ABSOLUTE_PRESSURE",
+        "value": 22
+      },
+      {
+        "name": "ENGINE_OIL_TEMPERATURE",
+        "value": 23
+      },
+      {
+        "name": "DRIVER_DEMAND_PERCENT_TORQUE",
+        "value": 24
+      },
+      {
+        "name": "ENGINE_ACTUAL_PERCENT_TORQUE",
+        "value": 25
+      },
+      {
+        "name": "ENGINE_REFERENCE_PERCENT_TORQUE",
+        "value": 26
+      },
+      {
+        "name": "ENGINE_PERCENT_TORQUE_DATA_IDLE",
+        "value": 27
+      },
+      {
+        "name": "ENGINE_PERCENT_TORQUE_DATA_POINT1",
+        "value": 28
+      },
+      {
+        "name": "ENGINE_PERCENT_TORQUE_DATA_POINT2",
+        "value": 29
+      },
+      {
+        "name": "ENGINE_PERCENT_TORQUE_DATA_POINT3",
+        "value": 30
+      },
+      {
+        "name": "ENGINE_PERCENT_TORQUE_DATA_POINT4",
+        "value": 31
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VehicleUnit",
+    "values": [
+      {
+        "name": "SHOULD_NOT_USE",
+        "value": 0
+      },
+      {
+        "name": "METER_PER_SEC",
+        "value": 1
+      },
+      {
+        "name": "RPM",
+        "value": 2
+      },
+      {
+        "name": "HERTZ",
+        "value": 3
+      },
+      {
+        "name": "PERCENTILE",
+        "value": 16
+      },
+      {
+        "name": "MILLIMETER",
+        "value": 32
+      },
+      {
+        "name": "METER",
+        "value": 33
+      },
+      {
+        "name": "KILOMETER",
+        "value": 35
+      },
+      {
+        "name": "MILE",
+        "value": 36
+      },
+      {
+        "name": "CELSIUS",
+        "value": 48
+      },
+      {
+        "name": "FAHRENHEIT",
+        "value": 49
+      },
+      {
+        "name": "KELVIN",
+        "value": 50
+      },
+      {
+        "name": "MILLILITER",
+        "value": 64
+      },
+      {
+        "name": "LITER",
+        "value": 65
+      },
+      {
+        "name": "GALLON",
+        "value": 66
+      },
+      {
+        "name": "US_GALLON",
+        "value": 66
+      },
+      {
+        "name": "IMPERIAL_GALLON",
+        "value": 67
+      },
+      {
+        "name": "NANO_SECS",
+        "value": 80
+      },
+      {
+        "name": "MILLI_SECS",
+        "value": 81
+      },
+      {
+        "name": "SECS",
+        "value": 83
+      },
+      {
+        "name": "YEAR",
+        "value": 89
+      },
+      {
+        "name": "WATT_HOUR",
+        "value": 96
+      },
+      {
+        "name": "MILLIAMPERE",
+        "value": 97
+      },
+      {
+        "name": "MILLIVOLT",
+        "value": 98
+      },
+      {
+        "name": "MILLIWATTS",
+        "value": 99
+      },
+      {
+        "name": "AMPERE_HOURS",
+        "value": 100
+      },
+      {
+        "name": "KILOWATT_HOUR",
+        "value": 101
+      },
+      {
+        "name": "AMPERE",
+        "value": 102
+      },
+      {
+        "name": "KILOPASCAL",
+        "value": 112
+      },
+      {
+        "name": "PSI",
+        "value": 113
+      },
+      {
+        "name": "BAR",
+        "value": 114
+      },
+      {
+        "name": "DEGREES",
+        "value": 128
+      },
+      {
+        "name": "MILES_PER_HOUR",
+        "value": 144
+      },
+      {
+        "name": "KILOMETERS_PER_HOUR",
+        "value": 145
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "LaneCenteringAssistCommand",
+    "values": [
+      {
+        "name": "ACTIVATE",
+        "value": 1
+      },
+      {
+        "name": "DEACTIVATE",
+        "value": 2
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "Obd2FuelType",
+    "values": [
+      {
+        "name": "NOT_AVAILABLE",
+        "value": 0
+      },
+      {
+        "name": "GASOLINE",
+        "value": 1
+      },
+      {
+        "name": "METHANOL",
+        "value": 2
+      },
+      {
+        "name": "ETHANOL",
+        "value": 3
+      },
+      {
+        "name": "DIESEL",
+        "value": 4
+      },
+      {
+        "name": "LPG",
+        "value": 5
+      },
+      {
+        "name": "CNG",
+        "value": 6
+      },
+      {
+        "name": "PROPANE",
+        "value": 7
+      },
+      {
+        "name": "ELECTRIC",
+        "value": 8
+      },
+      {
+        "name": "BIFUEL_RUNNING_GASOLINE",
+        "value": 9
+      },
+      {
+        "name": "BIFUEL_RUNNING_METHANOL",
+        "value": 10
+      },
+      {
+        "name": "BIFUEL_RUNNING_ETHANOL",
+        "value": 11
+      },
+      {
+        "name": "BIFUEL_RUNNING_LPG",
+        "value": 12
+      },
+      {
+        "name": "BIFUEL_RUNNING_CNG",
+        "value": 13
+      },
+      {
+        "name": "BIFUEL_RUNNING_PROPANE",
+        "value": 14
+      },
+      {
+        "name": "BIFUEL_RUNNING_ELECTRIC",
+        "value": 15
+      },
+      {
+        "name": "BIFUEL_RUNNING_ELECTRIC_AND_COMBUSTION",
+        "value": 16
+      },
+      {
+        "name": "HYBRID_GASOLINE",
+        "value": 17
+      },
+      {
+        "name": "HYBRID_ETHANOL",
+        "value": 18
+      },
+      {
+        "name": "HYBRID_DIESEL",
+        "value": 19
+      },
+      {
+        "name": "HYBRID_ELECTRIC",
+        "value": 20
+      },
+      {
+        "name": "HYBRID_RUNNING_ELECTRIC_AND_COMBUSTION",
+        "value": 21
+      },
+      {
+        "name": "HYBRID_REGENERATIVE",
+        "value": 22
+      },
+      {
+        "name": "BIFUEL_RUNNING_DIESEL",
+        "value": 23
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "ProcessTerminationReason",
+    "values": [
+      {
+        "name": "NOT_RESPONDING",
+        "value": 1
+      },
+      {
+        "name": "IO_OVERUSE",
+        "value": 2
+      },
+      {
+        "name": "MEMORY_OVERUSE",
+        "value": 3
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "VmsMessageWithLayerAndPublisherIdIntegerValuesIndex",
     "values": [
       {
         "name": "MESSAGE_TYPE",
         "value": 0
       },
       {
-        "name": "PUBLISHER_ID",
-        "value": 1
-      }
-    ]
-  },
-  {
-    "name": "RotaryInputType",
-    "values": [
-      {
-        "name": "ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION",
-        "value": 0
-      },
-      {
-        "name": "ROTARY_INPUT_TYPE_AUDIO_VOLUME",
-        "value": 1
-      }
-    ]
-  },
-  {
-    "name": "Obd2FuelSystemStatus",
-    "values": [
-      {
-        "name": "OPEN_INSUFFICIENT_ENGINE_TEMPERATURE",
+        "name": "LAYER_TYPE",
         "value": 1
       },
       {
-        "name": "CLOSED_LOOP",
+        "name": "LAYER_SUBTYPE",
         "value": 2
       },
       {
-        "name": "OPEN_ENGINE_LOAD_OR_DECELERATION",
+        "name": "LAYER_VERSION",
+        "value": 3
+      },
+      {
+        "name": "PUBLISHER_ID",
         "value": 4
+      }
+    ]
+  },
+  {
+    "package": "android.hardware.automotive.vehicle",
+    "name": "EvChargeState",
+    "values": [
+      {
+        "name": "UNKNOWN",
+        "value": 0
       },
       {
-        "name": "OPEN_SYSTEM_FAILURE",
-        "value": 8
+        "name": "CHARGING",
+        "value": 1
       },
       {
-        "name": "CLOSED_LOOP_BUT_FEEDBACK_FAULT",
-        "value": 16
+        "name": "FULLY_CHARGED",
+        "value": 2
+      },
+      {
+        "name": "NOT_CHARGING",
+        "value": 3
+      },
+      {
+        "name": "ERROR",
+        "value": 4
       }
     ]
   }
diff --git a/automotive/vehicle/aidl/emu_metadata/generate_emulator_metadata.py b/automotive/vehicle/aidl/emu_metadata/generate_emulator_metadata.py
index b2eb172..5706571 100755
--- a/automotive/vehicle/aidl/emu_metadata/generate_emulator_metadata.py
+++ b/automotive/vehicle/aidl/emu_metadata/generate_emulator_metadata.py
@@ -19,23 +19,56 @@
 
 from pathlib import Path
 
+RE_PACKAGE = re.compile(r"\npackage\s([\.a-z0-9]*);")
+RE_IMPORT = re.compile(r"\nimport\s([\.a-zA-Z0-9]*);")
 RE_ENUM = re.compile(r"\s*enum\s+(\w*) {\n(.*)}", re.MULTILINE | re.DOTALL)
-RE_COMMENT = re.compile(r"(?:(?:\/\*\*)((?:.|\n)*?)(?:\*\/))?(?:\n|^)\s*(\w*)(?:\s+=\s*)?((?:[a-zA-Z0-9]|\s|\+|)*),", re.DOTALL)
+RE_COMMENT = re.compile(r"(?:(?:\/\*\*)((?:.|\n)*?)(?:\*\/))?(?:\n|^)\s*(\w*)(?:\s+=\s*)?((?:[\.\-a-zA-Z0-9]|\s|\+|)*),",
+                        re.DOTALL)
 RE_BLOCK_COMMENT_TITLE = re.compile("^(?:\s|\*)*((?:\w|\s|\.)*)\n(?:\s|\*)*(?:\n|$)")
-RE_BLOCK_COMMENT_ANNOTATION = re.compile("^(?:\s|\*)*@(\w*)\s+((?:\w|:)*)", re.MULTILINE)
-RE_HEX_NUMBER = re.compile("([0-9A-Fa-fxX]+)")
+RE_BLOCK_COMMENT_ANNOTATION = re.compile("^(?:\s|\*)*@(\w*)\s+((?:[\w:\.])*)", re.MULTILINE)
+RE_HEX_NUMBER = re.compile("([\.\-0-9A-Za-z]+)")
 
 
 class JEnum:
-    def __init__(self, name):
+    def __init__(self, package, name):
+        self.package = package
         self.name = name
         self.values = []
 
+class Enum:
+    def __init__(self, package, name, text, imports):
+        self.text = text
+        self.parsed = False
+        self.imports = imports
+        self.jenum = JEnum(package, name)
 
-class Converter:
-    # Only addition is supported for now, but that covers all existing properties except
-    # OBD diagnostics, which use bitwise shifts
-    def calculateValue(self, expression, default_value):
+    def parse(self, enums):
+        if self.parsed:
+            return
+        for dep in self.imports:
+            enums[dep].parse(enums)
+        print("Parsing " + self.jenum.name)
+        matches = RE_COMMENT.findall(self.text)
+        defaultValue = 0
+        for match in matches:
+            value = dict()
+            value['name'] = match[1]
+            value['value'] = self.calculateValue(match[2], defaultValue, enums)
+            defaultValue = value['value'] + 1
+            if self.jenum.name == "VehicleProperty":
+                block_comment = match[0]
+                self.parseBlockComment(value, block_comment)
+            self.jenum.values.append(value)
+        self.parsed = True
+        self.text = None
+
+    def get_value(self, value_name):
+        for value in self.jenum.values:
+            if value['name'] == value_name:
+                return value['value']
+        raise Exception("Cannot decode value: " + self.jenum.package + " : " + value_name)
+
+    def calculateValue(self, expression, default_value, enums):
         numbers = RE_HEX_NUMBER.findall(expression)
         if len(numbers) == 0:
             return default_value
@@ -44,7 +77,13 @@
         if numbers[0].lower().startswith("0x"):
             base = 16
         for number in numbers:
-            result += int(number, base)
+            if '.' in number:
+                package, val_name = number.split('.')
+                for dep in self.imports:
+                    if package in dep:
+                        result += enums[dep].get_value(val_name)
+            else:
+                result += int(number, base)
         return result
 
     def parseBlockComment(self, value, blockComment):
@@ -54,30 +93,22 @@
             break
         annots_res = RE_BLOCK_COMMENT_ANNOTATION.findall(blockComment)
         for annot in annots_res:
-            value[annot[0]] = annot[1]
+            value[annot[0]] = annot[1].replace(".", ":")
 
-    def parseEnumContents(self, enum: JEnum, enumValue):
-        matches = RE_COMMENT.findall(enumValue)
-        defaultValue = 0
-        for match in matches:
-            value = dict()
-            value['name'] = match[1]
-            value['value'] = self.calculateValue(match[2], defaultValue)
-            defaultValue = value['value'] + 1
-            if enum.name == "VehicleProperty":
-                block_comment = match[0]
-                self.parseBlockComment(value, block_comment)
-            enum.values.append(value)
-
+class Converter:
+    # Only addition is supported for now, but that covers all existing properties except
+    # OBD diagnostics, which use bitwise shifts
     def convert(self, input):
         text = Path(input).read_text()
         matches = RE_ENUM.findall(text)
-        jenums = []
+        package = RE_PACKAGE.findall(text)[0]
+        imports = RE_IMPORT.findall(text)
+        enums = []
         for match in matches:
-            enum = JEnum(match[0])
-            self.parseEnumContents(enum, match[1])
-            jenums.append(enum)
-        return jenums
+            enum = Enum(package, match[0], match[1], imports)
+            enums.append(enum)
+        return enums
+
 
 def main():
     if (len(sys.argv) != 3):
@@ -85,10 +116,18 @@
         sys.exit(1)
     aidl_path = sys.argv[1]
     out_path = sys.argv[2]
-    result = []
+    enums_dict = dict()
     for file in os.listdir(aidl_path):
-        result.extend(Converter().convert(os.path.join(aidl_path, file)))
-    json_result = json.dumps(result, default=vars, indent=2)
+        enums = Converter().convert(os.path.join(aidl_path, file))
+        for enum in enums:
+            enums_dict[enum.jenum.package + "." + enum.jenum.name] = enum
+
+    result = []
+    for enum_name, enum in enums_dict.items():
+        enum.parse(enums_dict)
+        result.append(enum.jenum.__dict__)
+
+    json_result = json.dumps(result, default=None, indent=2)
     with open(out_path, 'w') as f:
         f.write(json_result)
 
diff --git a/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h b/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h
index d0c6e83..15056e2 100644
--- a/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h
+++ b/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -22,8 +22,7 @@
 
 // clang-format off
 
-#ifndef android_hardware_automotive_vehicle_aidl_generated_lib_AccessForVehicleProperty_H_
-#define android_hardware_automotive_vehicle_aidl_generated_lib_AccessForVehicleProperty_H_
+#pragma once
 
 #include <aidl/android/hardware/automotive/vehicle/VehicleProperty.h>
 #include <aidl/android/hardware/automotive/vehicle/VehiclePropertyAccess.h>
@@ -68,9 +67,11 @@
         {VehicleProperty::EV_CHARGE_PORT_CONNECTED, VehiclePropertyAccess::READ},
         {VehicleProperty::EV_BATTERY_INSTANTANEOUS_CHARGE_RATE, VehiclePropertyAccess::READ},
         {VehicleProperty::RANGE_REMAINING, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::EV_BATTERY_AVERAGE_TEMPERATURE, VehiclePropertyAccess::READ},
         {VehicleProperty::TIRE_PRESSURE, VehiclePropertyAccess::READ},
         {VehicleProperty::CRITICALLY_LOW_TIRE_PRESSURE, VehiclePropertyAccess::READ},
         {VehicleProperty::ENGINE_IDLE_AUTO_STOP_ENABLED, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::IMPACT_DETECTED, VehiclePropertyAccess::READ},
         {VehicleProperty::GEAR_SELECTION, VehiclePropertyAccess::READ},
         {VehicleProperty::CURRENT_GEAR, VehiclePropertyAccess::READ},
         {VehicleProperty::PARKING_BRAKE_ON, VehiclePropertyAccess::READ},
@@ -83,6 +84,8 @@
         {VehicleProperty::ABS_ACTIVE, VehiclePropertyAccess::READ},
         {VehicleProperty::TRACTION_CONTROL_ACTIVE, VehiclePropertyAccess::READ},
         {VehicleProperty::EV_STOPPING_MODE, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::ELECTRONIC_STABILITY_CONTROL_ENABLED, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::ELECTRONIC_STABILITY_CONTROL_STATE, VehiclePropertyAccess::READ},
         {VehicleProperty::HVAC_FAN_SPEED, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::HVAC_FAN_DIRECTION, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::HVAC_TEMPERATURE_CURRENT, VehiclePropertyAccess::READ},
@@ -120,6 +123,8 @@
         {VehicleProperty::AP_POWER_BOOTUP_REASON, VehiclePropertyAccess::READ},
         {VehicleProperty::DISPLAY_BRIGHTNESS, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::PER_DISPLAY_BRIGHTNESS, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::VALET_MODE_ENABLED, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::HEAD_UP_DISPLAY_ENABLED, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::HW_KEY_INPUT, VehiclePropertyAccess::READ},
         {VehicleProperty::HW_KEY_INPUT_V2, VehiclePropertyAccess::READ},
         {VehicleProperty::HW_MOTION_INPUT, VehiclePropertyAccess::READ},
@@ -169,11 +174,13 @@
         {VehicleProperty::SEAT_FOOTWELL_LIGHTS_SWITCH, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::SEAT_EASY_ACCESS_ENABLED, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::SEAT_AIRBAG_ENABLED, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::SEAT_AIRBAGS_DEPLOYED, VehiclePropertyAccess::READ},
         {VehicleProperty::SEAT_CUSHION_SIDE_SUPPORT_POS, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::SEAT_CUSHION_SIDE_SUPPORT_MOVE, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::SEAT_LUMBAR_VERTICAL_POS, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::SEAT_LUMBAR_VERTICAL_MOVE, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::SEAT_WALK_IN_POS, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::SEAT_BELT_PRETENSIONER_DEPLOYED, VehiclePropertyAccess::READ},
         {VehicleProperty::SEAT_OCCUPANCY, VehiclePropertyAccess::READ},
         {VehicleProperty::WINDOW_POS, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::WINDOW_MOVE, VehiclePropertyAccess::READ_WRITE},
@@ -192,6 +199,12 @@
         {VehicleProperty::GLOVE_BOX_LOCKED, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::VEHICLE_MAP_SERVICE, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::LOCATION_CHARACTERIZATION, VehiclePropertyAccess::READ},
+        {VehicleProperty::ULTRASONICS_SENSOR_POSITION, VehiclePropertyAccess::READ},
+        {VehicleProperty::ULTRASONICS_SENSOR_ORIENTATION, VehiclePropertyAccess::READ},
+        {VehicleProperty::ULTRASONICS_SENSOR_FIELD_OF_VIEW, VehiclePropertyAccess::READ},
+        {VehicleProperty::ULTRASONICS_SENSOR_DETECTION_RANGE, VehiclePropertyAccess::READ},
+        {VehicleProperty::ULTRASONICS_SENSOR_SUPPORTED_RANGES, VehiclePropertyAccess::READ},
+        {VehicleProperty::ULTRASONICS_SENSOR_MEASURED_DISTANCE, VehiclePropertyAccess::READ},
         {VehicleProperty::OBD2_LIVE_FRAME, VehiclePropertyAccess::READ},
         {VehicleProperty::OBD2_FREEZE_FRAME, VehiclePropertyAccess::READ},
         {VehicleProperty::OBD2_FREEZE_FRAME_INFO, VehiclePropertyAccess::READ},
@@ -247,6 +260,8 @@
         {VehicleProperty::SUPPORTED_PROPERTY_IDS, VehiclePropertyAccess::READ},
         {VehicleProperty::SHUTDOWN_REQUEST, VehiclePropertyAccess::WRITE},
         {VehicleProperty::VEHICLE_IN_USE, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::CLUSTER_HEARTBEAT, VehiclePropertyAccess::WRITE},
+        {VehicleProperty::VEHICLE_DRIVING_AUTOMATION_CURRENT_LEVEL, VehiclePropertyAccess::READ},
         {VehicleProperty::AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::AUTOMATIC_EMERGENCY_BRAKING_STATE, VehiclePropertyAccess::READ},
         {VehicleProperty::FORWARD_COLLISION_WARNING_ENABLED, VehiclePropertyAccess::READ_WRITE},
@@ -272,6 +287,20 @@
         {VehicleProperty::HANDS_ON_DETECTION_ENABLED, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::HANDS_ON_DETECTION_DRIVER_STATE, VehiclePropertyAccess::READ},
         {VehicleProperty::HANDS_ON_DETECTION_WARNING, VehiclePropertyAccess::READ},
+        {VehicleProperty::DRIVER_DROWSINESS_ATTENTION_SYSTEM_ENABLED, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::DRIVER_DROWSINESS_ATTENTION_STATE, VehiclePropertyAccess::READ},
+        {VehicleProperty::DRIVER_DROWSINESS_ATTENTION_WARNING_ENABLED, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::DRIVER_DROWSINESS_ATTENTION_WARNING, VehiclePropertyAccess::READ},
+        {VehicleProperty::DRIVER_DISTRACTION_SYSTEM_ENABLED, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::DRIVER_DISTRACTION_STATE, VehiclePropertyAccess::READ},
+        {VehicleProperty::DRIVER_DISTRACTION_WARNING_ENABLED, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::DRIVER_DISTRACTION_WARNING, VehiclePropertyAccess::READ},
+        {VehicleProperty::LOW_SPEED_COLLISION_WARNING_ENABLED, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::LOW_SPEED_COLLISION_WARNING_STATE, VehiclePropertyAccess::READ},
+        {VehicleProperty::CROSS_TRAFFIC_MONITORING_ENABLED, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::CROSS_TRAFFIC_MONITORING_WARNING_STATE, VehiclePropertyAccess::READ},
+        {VehicleProperty::LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE, VehiclePropertyAccess::READ},
 };
 
 }  // namespace vehicle
@@ -279,5 +308,3 @@
 }  // namespace hardware
 }  // namespace android
 }  // aidl
-
-#endif  // android_hardware_automotive_vehicle_aidl_generated_lib_AccessForVehicleProperty_H_
diff --git a/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h b/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h
index 48532c9..d3f97e3 100644
--- a/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h
+++ b/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -22,8 +22,7 @@
 
 // clang-format off
 
-#ifndef android_hardware_automotive_vehicle_aidl_generated_lib_ChangeModeForVehicleProperty_H_
-#define android_hardware_automotive_vehicle_aidl_generated_lib_ChangeModeForVehicleProperty_H_
+#pragma once
 
 #include <aidl/android/hardware/automotive/vehicle/VehicleProperty.h>
 #include <aidl/android/hardware/automotive/vehicle/VehiclePropertyChangeMode.h>
@@ -68,9 +67,11 @@
         {VehicleProperty::EV_CHARGE_PORT_CONNECTED, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::EV_BATTERY_INSTANTANEOUS_CHARGE_RATE, VehiclePropertyChangeMode::CONTINUOUS},
         {VehicleProperty::RANGE_REMAINING, VehiclePropertyChangeMode::CONTINUOUS},
+        {VehicleProperty::EV_BATTERY_AVERAGE_TEMPERATURE, VehiclePropertyChangeMode::CONTINUOUS},
         {VehicleProperty::TIRE_PRESSURE, VehiclePropertyChangeMode::CONTINUOUS},
         {VehicleProperty::CRITICALLY_LOW_TIRE_PRESSURE, VehiclePropertyChangeMode::STATIC},
         {VehicleProperty::ENGINE_IDLE_AUTO_STOP_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::IMPACT_DETECTED, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::GEAR_SELECTION, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::CURRENT_GEAR, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::PARKING_BRAKE_ON, VehiclePropertyChangeMode::ON_CHANGE},
@@ -83,6 +84,8 @@
         {VehicleProperty::ABS_ACTIVE, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::TRACTION_CONTROL_ACTIVE, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::EV_STOPPING_MODE, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::ELECTRONIC_STABILITY_CONTROL_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::ELECTRONIC_STABILITY_CONTROL_STATE, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::HVAC_FAN_SPEED, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::HVAC_FAN_DIRECTION, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::HVAC_TEMPERATURE_CURRENT, VehiclePropertyChangeMode::ON_CHANGE},
@@ -120,6 +123,8 @@
         {VehicleProperty::AP_POWER_BOOTUP_REASON, VehiclePropertyChangeMode::STATIC},
         {VehicleProperty::DISPLAY_BRIGHTNESS, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::PER_DISPLAY_BRIGHTNESS, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::VALET_MODE_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::HEAD_UP_DISPLAY_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::HW_KEY_INPUT, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::HW_KEY_INPUT_V2, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::HW_MOTION_INPUT, VehiclePropertyChangeMode::ON_CHANGE},
@@ -169,11 +174,13 @@
         {VehicleProperty::SEAT_FOOTWELL_LIGHTS_SWITCH, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::SEAT_EASY_ACCESS_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::SEAT_AIRBAG_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::SEAT_AIRBAGS_DEPLOYED, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::SEAT_CUSHION_SIDE_SUPPORT_POS, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::SEAT_CUSHION_SIDE_SUPPORT_MOVE, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::SEAT_LUMBAR_VERTICAL_POS, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::SEAT_LUMBAR_VERTICAL_MOVE, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::SEAT_WALK_IN_POS, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::SEAT_BELT_PRETENSIONER_DEPLOYED, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::SEAT_OCCUPANCY, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::WINDOW_POS, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::WINDOW_MOVE, VehiclePropertyChangeMode::ON_CHANGE},
@@ -192,6 +199,12 @@
         {VehicleProperty::GLOVE_BOX_LOCKED, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::VEHICLE_MAP_SERVICE, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::LOCATION_CHARACTERIZATION, VehiclePropertyChangeMode::STATIC},
+        {VehicleProperty::ULTRASONICS_SENSOR_POSITION, VehiclePropertyChangeMode::STATIC},
+        {VehicleProperty::ULTRASONICS_SENSOR_ORIENTATION, VehiclePropertyChangeMode::STATIC},
+        {VehicleProperty::ULTRASONICS_SENSOR_FIELD_OF_VIEW, VehiclePropertyChangeMode::STATIC},
+        {VehicleProperty::ULTRASONICS_SENSOR_DETECTION_RANGE, VehiclePropertyChangeMode::STATIC},
+        {VehicleProperty::ULTRASONICS_SENSOR_SUPPORTED_RANGES, VehiclePropertyChangeMode::STATIC},
+        {VehicleProperty::ULTRASONICS_SENSOR_MEASURED_DISTANCE, VehiclePropertyChangeMode::CONTINUOUS},
         {VehicleProperty::OBD2_LIVE_FRAME, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::OBD2_FREEZE_FRAME, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::OBD2_FREEZE_FRAME_INFO, VehiclePropertyChangeMode::ON_CHANGE},
@@ -247,6 +260,8 @@
         {VehicleProperty::SUPPORTED_PROPERTY_IDS, VehiclePropertyChangeMode::STATIC},
         {VehicleProperty::SHUTDOWN_REQUEST, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::VEHICLE_IN_USE, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::CLUSTER_HEARTBEAT, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::VEHICLE_DRIVING_AUTOMATION_CURRENT_LEVEL, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::AUTOMATIC_EMERGENCY_BRAKING_STATE, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::FORWARD_COLLISION_WARNING_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
@@ -272,6 +287,20 @@
         {VehicleProperty::HANDS_ON_DETECTION_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::HANDS_ON_DETECTION_DRIVER_STATE, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::HANDS_ON_DETECTION_WARNING, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::DRIVER_DROWSINESS_ATTENTION_SYSTEM_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::DRIVER_DROWSINESS_ATTENTION_STATE, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::DRIVER_DROWSINESS_ATTENTION_WARNING_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::DRIVER_DROWSINESS_ATTENTION_WARNING, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::DRIVER_DISTRACTION_SYSTEM_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::DRIVER_DISTRACTION_STATE, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::DRIVER_DISTRACTION_WARNING_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::DRIVER_DISTRACTION_WARNING, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::LOW_SPEED_COLLISION_WARNING_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::LOW_SPEED_COLLISION_WARNING_STATE, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::CROSS_TRAFFIC_MONITORING_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::CROSS_TRAFFIC_MONITORING_WARNING_STATE, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE, VehiclePropertyChangeMode::ON_CHANGE},
 };
 
 }  // namespace vehicle
@@ -279,5 +308,3 @@
 }  // namespace hardware
 }  // namespace android
 }  // aidl
-
-#endif  // android_hardware_automotive_vehicle_aidl_generated_lib_ChangeModeForVehicleProperty_H_
diff --git a/automotive/vehicle/aidl/generated_lib/cpp/VersionForVehicleProperty.h b/automotive/vehicle/aidl/generated_lib/cpp/VersionForVehicleProperty.h
new file mode 100644
index 0000000..70c914d
--- /dev/null
+++ b/automotive/vehicle/aidl/generated_lib/cpp/VersionForVehicleProperty.h
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * DO NOT EDIT MANUALLY!!!
+ *
+ * Generated by tools/generate_annotation_enums.py.
+ */
+
+// clang-format off
+
+#pragma once
+
+#include <aidl/android/hardware/automotive/vehicle/VehicleProperty.h>
+
+#include <unordered_map>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+
+std::unordered_map<VehicleProperty, int32_t> VersionForVehicleProperty = {
+        {VehicleProperty::INFO_VIN, 2},
+        {VehicleProperty::INFO_MAKE, 2},
+        {VehicleProperty::INFO_MODEL, 2},
+        {VehicleProperty::INFO_MODEL_YEAR, 2},
+        {VehicleProperty::INFO_FUEL_CAPACITY, 2},
+        {VehicleProperty::INFO_FUEL_TYPE, 2},
+        {VehicleProperty::INFO_EV_BATTERY_CAPACITY, 2},
+        {VehicleProperty::INFO_EV_CONNECTOR_TYPE, 2},
+        {VehicleProperty::INFO_FUEL_DOOR_LOCATION, 2},
+        {VehicleProperty::INFO_EV_PORT_LOCATION, 2},
+        {VehicleProperty::INFO_DRIVER_SEAT, 2},
+        {VehicleProperty::INFO_EXTERIOR_DIMENSIONS, 2},
+        {VehicleProperty::INFO_MULTI_EV_PORT_LOCATIONS, 2},
+        {VehicleProperty::PERF_ODOMETER, 2},
+        {VehicleProperty::PERF_VEHICLE_SPEED, 2},
+        {VehicleProperty::PERF_VEHICLE_SPEED_DISPLAY, 2},
+        {VehicleProperty::PERF_STEERING_ANGLE, 2},
+        {VehicleProperty::PERF_REAR_STEERING_ANGLE, 2},
+        {VehicleProperty::ENGINE_COOLANT_TEMP, 2},
+        {VehicleProperty::ENGINE_OIL_LEVEL, 2},
+        {VehicleProperty::ENGINE_OIL_TEMP, 2},
+        {VehicleProperty::ENGINE_RPM, 2},
+        {VehicleProperty::WHEEL_TICK, 2},
+        {VehicleProperty::FUEL_LEVEL, 2},
+        {VehicleProperty::FUEL_DOOR_OPEN, 2},
+        {VehicleProperty::EV_BATTERY_LEVEL, 2},
+        {VehicleProperty::EV_CURRENT_BATTERY_CAPACITY, 2},
+        {VehicleProperty::EV_CHARGE_PORT_OPEN, 2},
+        {VehicleProperty::EV_CHARGE_PORT_CONNECTED, 2},
+        {VehicleProperty::EV_BATTERY_INSTANTANEOUS_CHARGE_RATE, 2},
+        {VehicleProperty::RANGE_REMAINING, 2},
+        {VehicleProperty::EV_BATTERY_AVERAGE_TEMPERATURE, 3},
+        {VehicleProperty::TIRE_PRESSURE, 2},
+        {VehicleProperty::CRITICALLY_LOW_TIRE_PRESSURE, 2},
+        {VehicleProperty::ENGINE_IDLE_AUTO_STOP_ENABLED, 2},
+        {VehicleProperty::IMPACT_DETECTED, 3},
+        {VehicleProperty::GEAR_SELECTION, 2},
+        {VehicleProperty::CURRENT_GEAR, 2},
+        {VehicleProperty::PARKING_BRAKE_ON, 2},
+        {VehicleProperty::PARKING_BRAKE_AUTO_APPLY, 2},
+        {VehicleProperty::EV_BRAKE_REGENERATION_LEVEL, 2},
+        {VehicleProperty::FUEL_LEVEL_LOW, 2},
+        {VehicleProperty::NIGHT_MODE, 2},
+        {VehicleProperty::TURN_SIGNAL_STATE, 2},
+        {VehicleProperty::IGNITION_STATE, 2},
+        {VehicleProperty::ABS_ACTIVE, 2},
+        {VehicleProperty::TRACTION_CONTROL_ACTIVE, 2},
+        {VehicleProperty::EV_STOPPING_MODE, 2},
+        {VehicleProperty::ELECTRONIC_STABILITY_CONTROL_ENABLED, 3},
+        {VehicleProperty::ELECTRONIC_STABILITY_CONTROL_STATE, 2},
+        {VehicleProperty::HVAC_FAN_SPEED, 2},
+        {VehicleProperty::HVAC_FAN_DIRECTION, 2},
+        {VehicleProperty::HVAC_TEMPERATURE_CURRENT, 2},
+        {VehicleProperty::HVAC_TEMPERATURE_SET, 2},
+        {VehicleProperty::HVAC_DEFROSTER, 2},
+        {VehicleProperty::HVAC_AC_ON, 2},
+        {VehicleProperty::HVAC_MAX_AC_ON, 2},
+        {VehicleProperty::HVAC_MAX_DEFROST_ON, 2},
+        {VehicleProperty::HVAC_RECIRC_ON, 2},
+        {VehicleProperty::HVAC_DUAL_ON, 2},
+        {VehicleProperty::HVAC_AUTO_ON, 2},
+        {VehicleProperty::HVAC_SEAT_TEMPERATURE, 2},
+        {VehicleProperty::HVAC_SIDE_MIRROR_HEAT, 2},
+        {VehicleProperty::HVAC_STEERING_WHEEL_HEAT, 2},
+        {VehicleProperty::HVAC_TEMPERATURE_DISPLAY_UNITS, 2},
+        {VehicleProperty::HVAC_ACTUAL_FAN_SPEED_RPM, 2},
+        {VehicleProperty::HVAC_POWER_ON, 2},
+        {VehicleProperty::HVAC_FAN_DIRECTION_AVAILABLE, 2},
+        {VehicleProperty::HVAC_AUTO_RECIRC_ON, 2},
+        {VehicleProperty::HVAC_SEAT_VENTILATION, 2},
+        {VehicleProperty::HVAC_ELECTRIC_DEFROSTER_ON, 2},
+        {VehicleProperty::HVAC_TEMPERATURE_VALUE_SUGGESTION, 2},
+        {VehicleProperty::DISTANCE_DISPLAY_UNITS, 2},
+        {VehicleProperty::FUEL_VOLUME_DISPLAY_UNITS, 2},
+        {VehicleProperty::TIRE_PRESSURE_DISPLAY_UNITS, 2},
+        {VehicleProperty::EV_BATTERY_DISPLAY_UNITS, 2},
+        {VehicleProperty::FUEL_CONSUMPTION_UNITS_DISTANCE_OVER_VOLUME, 2},
+        {VehicleProperty::VEHICLE_SPEED_DISPLAY_UNITS, 2},
+        {VehicleProperty::EXTERNAL_CAR_TIME, 2},
+        {VehicleProperty::ANDROID_EPOCH_TIME, 2},
+        {VehicleProperty::STORAGE_ENCRYPTION_BINDING_SEED, 2},
+        {VehicleProperty::ENV_OUTSIDE_TEMPERATURE, 2},
+        {VehicleProperty::AP_POWER_STATE_REQ, 2},
+        {VehicleProperty::AP_POWER_STATE_REPORT, 2},
+        {VehicleProperty::AP_POWER_BOOTUP_REASON, 2},
+        {VehicleProperty::DISPLAY_BRIGHTNESS, 2},
+        {VehicleProperty::PER_DISPLAY_BRIGHTNESS, 2},
+        {VehicleProperty::VALET_MODE_ENABLED, 3},
+        {VehicleProperty::HEAD_UP_DISPLAY_ENABLED, 3},
+        {VehicleProperty::HW_KEY_INPUT, 2},
+        {VehicleProperty::HW_KEY_INPUT_V2, 2},
+        {VehicleProperty::HW_MOTION_INPUT, 2},
+        {VehicleProperty::HW_ROTARY_INPUT, 2},
+        {VehicleProperty::HW_CUSTOM_INPUT, 2},
+        {VehicleProperty::DOOR_POS, 2},
+        {VehicleProperty::DOOR_MOVE, 2},
+        {VehicleProperty::DOOR_LOCK, 2},
+        {VehicleProperty::DOOR_CHILD_LOCK_ENABLED, 2},
+        {VehicleProperty::MIRROR_Z_POS, 2},
+        {VehicleProperty::MIRROR_Z_MOVE, 2},
+        {VehicleProperty::MIRROR_Y_POS, 2},
+        {VehicleProperty::MIRROR_Y_MOVE, 2},
+        {VehicleProperty::MIRROR_LOCK, 2},
+        {VehicleProperty::MIRROR_FOLD, 2},
+        {VehicleProperty::MIRROR_AUTO_FOLD_ENABLED, 2},
+        {VehicleProperty::MIRROR_AUTO_TILT_ENABLED, 2},
+        {VehicleProperty::SEAT_MEMORY_SELECT, 2},
+        {VehicleProperty::SEAT_MEMORY_SET, 2},
+        {VehicleProperty::SEAT_BELT_BUCKLED, 2},
+        {VehicleProperty::SEAT_BELT_HEIGHT_POS, 2},
+        {VehicleProperty::SEAT_BELT_HEIGHT_MOVE, 2},
+        {VehicleProperty::SEAT_FORE_AFT_POS, 2},
+        {VehicleProperty::SEAT_FORE_AFT_MOVE, 2},
+        {VehicleProperty::SEAT_BACKREST_ANGLE_1_POS, 2},
+        {VehicleProperty::SEAT_BACKREST_ANGLE_1_MOVE, 2},
+        {VehicleProperty::SEAT_BACKREST_ANGLE_2_POS, 2},
+        {VehicleProperty::SEAT_BACKREST_ANGLE_2_MOVE, 2},
+        {VehicleProperty::SEAT_HEIGHT_POS, 2},
+        {VehicleProperty::SEAT_HEIGHT_MOVE, 2},
+        {VehicleProperty::SEAT_DEPTH_POS, 2},
+        {VehicleProperty::SEAT_DEPTH_MOVE, 2},
+        {VehicleProperty::SEAT_TILT_POS, 2},
+        {VehicleProperty::SEAT_TILT_MOVE, 2},
+        {VehicleProperty::SEAT_LUMBAR_FORE_AFT_POS, 2},
+        {VehicleProperty::SEAT_LUMBAR_FORE_AFT_MOVE, 2},
+        {VehicleProperty::SEAT_LUMBAR_SIDE_SUPPORT_POS, 2},
+        {VehicleProperty::SEAT_LUMBAR_SIDE_SUPPORT_MOVE, 2},
+        {VehicleProperty::SEAT_HEADREST_HEIGHT_POS, 2},
+        {VehicleProperty::SEAT_HEADREST_HEIGHT_POS_V2, 2},
+        {VehicleProperty::SEAT_HEADREST_HEIGHT_MOVE, 2},
+        {VehicleProperty::SEAT_HEADREST_ANGLE_POS, 2},
+        {VehicleProperty::SEAT_HEADREST_ANGLE_MOVE, 2},
+        {VehicleProperty::SEAT_HEADREST_FORE_AFT_POS, 2},
+        {VehicleProperty::SEAT_HEADREST_FORE_AFT_MOVE, 2},
+        {VehicleProperty::SEAT_FOOTWELL_LIGHTS_STATE, 2},
+        {VehicleProperty::SEAT_FOOTWELL_LIGHTS_SWITCH, 2},
+        {VehicleProperty::SEAT_EASY_ACCESS_ENABLED, 2},
+        {VehicleProperty::SEAT_AIRBAG_ENABLED, 3},
+        {VehicleProperty::SEAT_AIRBAGS_DEPLOYED, 2},
+        {VehicleProperty::SEAT_CUSHION_SIDE_SUPPORT_POS, 2},
+        {VehicleProperty::SEAT_CUSHION_SIDE_SUPPORT_MOVE, 2},
+        {VehicleProperty::SEAT_LUMBAR_VERTICAL_POS, 2},
+        {VehicleProperty::SEAT_LUMBAR_VERTICAL_MOVE, 2},
+        {VehicleProperty::SEAT_WALK_IN_POS, 2},
+        {VehicleProperty::SEAT_BELT_PRETENSIONER_DEPLOYED, 3},
+        {VehicleProperty::SEAT_OCCUPANCY, 2},
+        {VehicleProperty::WINDOW_POS, 2},
+        {VehicleProperty::WINDOW_MOVE, 2},
+        {VehicleProperty::WINDOW_LOCK, 2},
+        {VehicleProperty::WINDSHIELD_WIPERS_PERIOD, 2},
+        {VehicleProperty::WINDSHIELD_WIPERS_STATE, 2},
+        {VehicleProperty::WINDSHIELD_WIPERS_SWITCH, 2},
+        {VehicleProperty::STEERING_WHEEL_DEPTH_POS, 2},
+        {VehicleProperty::STEERING_WHEEL_DEPTH_MOVE, 2},
+        {VehicleProperty::STEERING_WHEEL_HEIGHT_POS, 2},
+        {VehicleProperty::STEERING_WHEEL_HEIGHT_MOVE, 2},
+        {VehicleProperty::STEERING_WHEEL_THEFT_LOCK_ENABLED, 2},
+        {VehicleProperty::STEERING_WHEEL_LOCKED, 2},
+        {VehicleProperty::STEERING_WHEEL_EASY_ACCESS_ENABLED, 2},
+        {VehicleProperty::GLOVE_BOX_DOOR_POS, 2},
+        {VehicleProperty::GLOVE_BOX_LOCKED, 2},
+        {VehicleProperty::VEHICLE_MAP_SERVICE, 2},
+        {VehicleProperty::LOCATION_CHARACTERIZATION, 2},
+        {VehicleProperty::ULTRASONICS_SENSOR_POSITION, 3},
+        {VehicleProperty::ULTRASONICS_SENSOR_ORIENTATION, 3},
+        {VehicleProperty::ULTRASONICS_SENSOR_FIELD_OF_VIEW, 3},
+        {VehicleProperty::ULTRASONICS_SENSOR_DETECTION_RANGE, 3},
+        {VehicleProperty::ULTRASONICS_SENSOR_SUPPORTED_RANGES, 3},
+        {VehicleProperty::ULTRASONICS_SENSOR_MEASURED_DISTANCE, 3},
+        {VehicleProperty::OBD2_LIVE_FRAME, 2},
+        {VehicleProperty::OBD2_FREEZE_FRAME, 2},
+        {VehicleProperty::OBD2_FREEZE_FRAME_INFO, 2},
+        {VehicleProperty::OBD2_FREEZE_FRAME_CLEAR, 2},
+        {VehicleProperty::HEADLIGHTS_STATE, 2},
+        {VehicleProperty::HIGH_BEAM_LIGHTS_STATE, 2},
+        {VehicleProperty::FOG_LIGHTS_STATE, 2},
+        {VehicleProperty::HAZARD_LIGHTS_STATE, 2},
+        {VehicleProperty::HEADLIGHTS_SWITCH, 2},
+        {VehicleProperty::HIGH_BEAM_LIGHTS_SWITCH, 2},
+        {VehicleProperty::FOG_LIGHTS_SWITCH, 2},
+        {VehicleProperty::HAZARD_LIGHTS_SWITCH, 2},
+        {VehicleProperty::CABIN_LIGHTS_STATE, 2},
+        {VehicleProperty::CABIN_LIGHTS_SWITCH, 2},
+        {VehicleProperty::READING_LIGHTS_STATE, 2},
+        {VehicleProperty::READING_LIGHTS_SWITCH, 2},
+        {VehicleProperty::STEERING_WHEEL_LIGHTS_STATE, 2},
+        {VehicleProperty::STEERING_WHEEL_LIGHTS_SWITCH, 2},
+        {VehicleProperty::SUPPORT_CUSTOMIZE_VENDOR_PERMISSION, 2},
+        {VehicleProperty::DISABLED_OPTIONAL_FEATURES, 2},
+        {VehicleProperty::INITIAL_USER_INFO, 2},
+        {VehicleProperty::SWITCH_USER, 2},
+        {VehicleProperty::CREATE_USER, 2},
+        {VehicleProperty::REMOVE_USER, 2},
+        {VehicleProperty::USER_IDENTIFICATION_ASSOCIATION, 2},
+        {VehicleProperty::EVS_SERVICE_REQUEST, 2},
+        {VehicleProperty::POWER_POLICY_REQ, 2},
+        {VehicleProperty::POWER_POLICY_GROUP_REQ, 2},
+        {VehicleProperty::CURRENT_POWER_POLICY, 2},
+        {VehicleProperty::WATCHDOG_ALIVE, 2},
+        {VehicleProperty::WATCHDOG_TERMINATED_PROCESS, 2},
+        {VehicleProperty::VHAL_HEARTBEAT, 2},
+        {VehicleProperty::CLUSTER_SWITCH_UI, 2},
+        {VehicleProperty::CLUSTER_DISPLAY_STATE, 2},
+        {VehicleProperty::CLUSTER_REPORT_STATE, 2},
+        {VehicleProperty::CLUSTER_REQUEST_DISPLAY, 2},
+        {VehicleProperty::CLUSTER_NAVIGATION_STATE, 2},
+        {VehicleProperty::ELECTRONIC_TOLL_COLLECTION_CARD_TYPE, 2},
+        {VehicleProperty::ELECTRONIC_TOLL_COLLECTION_CARD_STATUS, 2},
+        {VehicleProperty::FRONT_FOG_LIGHTS_STATE, 2},
+        {VehicleProperty::FRONT_FOG_LIGHTS_SWITCH, 2},
+        {VehicleProperty::REAR_FOG_LIGHTS_STATE, 2},
+        {VehicleProperty::REAR_FOG_LIGHTS_SWITCH, 2},
+        {VehicleProperty::EV_CHARGE_CURRENT_DRAW_LIMIT, 2},
+        {VehicleProperty::EV_CHARGE_PERCENT_LIMIT, 2},
+        {VehicleProperty::EV_CHARGE_STATE, 2},
+        {VehicleProperty::EV_CHARGE_SWITCH, 2},
+        {VehicleProperty::EV_CHARGE_TIME_REMAINING, 2},
+        {VehicleProperty::EV_REGENERATIVE_BRAKING_STATE, 2},
+        {VehicleProperty::TRAILER_PRESENT, 2},
+        {VehicleProperty::VEHICLE_CURB_WEIGHT, 2},
+        {VehicleProperty::GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT, 2},
+        {VehicleProperty::SUPPORTED_PROPERTY_IDS, 2},
+        {VehicleProperty::SHUTDOWN_REQUEST, 2},
+        {VehicleProperty::VEHICLE_IN_USE, 2},
+        {VehicleProperty::CLUSTER_HEARTBEAT, 3},
+        {VehicleProperty::VEHICLE_DRIVING_AUTOMATION_CURRENT_LEVEL, 3},
+        {VehicleProperty::AUTOMATIC_EMERGENCY_BRAKING_ENABLED, 2},
+        {VehicleProperty::AUTOMATIC_EMERGENCY_BRAKING_STATE, 2},
+        {VehicleProperty::FORWARD_COLLISION_WARNING_ENABLED, 2},
+        {VehicleProperty::FORWARD_COLLISION_WARNING_STATE, 2},
+        {VehicleProperty::BLIND_SPOT_WARNING_ENABLED, 2},
+        {VehicleProperty::BLIND_SPOT_WARNING_STATE, 2},
+        {VehicleProperty::LANE_DEPARTURE_WARNING_ENABLED, 2},
+        {VehicleProperty::LANE_DEPARTURE_WARNING_STATE, 2},
+        {VehicleProperty::LANE_KEEP_ASSIST_ENABLED, 2},
+        {VehicleProperty::LANE_KEEP_ASSIST_STATE, 2},
+        {VehicleProperty::LANE_CENTERING_ASSIST_ENABLED, 2},
+        {VehicleProperty::LANE_CENTERING_ASSIST_COMMAND, 2},
+        {VehicleProperty::LANE_CENTERING_ASSIST_STATE, 2},
+        {VehicleProperty::EMERGENCY_LANE_KEEP_ASSIST_ENABLED, 2},
+        {VehicleProperty::EMERGENCY_LANE_KEEP_ASSIST_STATE, 2},
+        {VehicleProperty::CRUISE_CONTROL_ENABLED, 2},
+        {VehicleProperty::CRUISE_CONTROL_TYPE, 2},
+        {VehicleProperty::CRUISE_CONTROL_STATE, 2},
+        {VehicleProperty::CRUISE_CONTROL_COMMAND, 2},
+        {VehicleProperty::CRUISE_CONTROL_TARGET_SPEED, 2},
+        {VehicleProperty::ADAPTIVE_CRUISE_CONTROL_TARGET_TIME_GAP, 2},
+        {VehicleProperty::ADAPTIVE_CRUISE_CONTROL_LEAD_VEHICLE_MEASURED_DISTANCE, 2},
+        {VehicleProperty::HANDS_ON_DETECTION_ENABLED, 2},
+        {VehicleProperty::HANDS_ON_DETECTION_DRIVER_STATE, 2},
+        {VehicleProperty::HANDS_ON_DETECTION_WARNING, 2},
+        {VehicleProperty::DRIVER_DROWSINESS_ATTENTION_SYSTEM_ENABLED, 3},
+        {VehicleProperty::DRIVER_DROWSINESS_ATTENTION_STATE, 3},
+        {VehicleProperty::DRIVER_DROWSINESS_ATTENTION_WARNING_ENABLED, 3},
+        {VehicleProperty::DRIVER_DROWSINESS_ATTENTION_WARNING, 3},
+        {VehicleProperty::DRIVER_DISTRACTION_SYSTEM_ENABLED, 3},
+        {VehicleProperty::DRIVER_DISTRACTION_STATE, 3},
+        {VehicleProperty::DRIVER_DISTRACTION_WARNING_ENABLED, 2},
+        {VehicleProperty::DRIVER_DISTRACTION_WARNING, 3},
+        {VehicleProperty::LOW_SPEED_COLLISION_WARNING_ENABLED, 3},
+        {VehicleProperty::LOW_SPEED_COLLISION_WARNING_STATE, 3},
+        {VehicleProperty::CROSS_TRAFFIC_MONITORING_ENABLED, 3},
+        {VehicleProperty::CROSS_TRAFFIC_MONITORING_WARNING_STATE, 3},
+        {VehicleProperty::LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_ENABLED, 3},
+        {VehicleProperty::LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE, 3},
+};
+
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+}  // aidl
diff --git a/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java b/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java
index 758670d..e55f4dc 100644
--- a/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java
+++ b/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -60,9 +60,11 @@
         Map.entry(VehicleProperty.EV_CHARGE_PORT_CONNECTED, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.EV_BATTERY_INSTANTANEOUS_CHARGE_RATE, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.RANGE_REMAINING, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.EV_BATTERY_AVERAGE_TEMPERATURE, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.TIRE_PRESSURE, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.CRITICALLY_LOW_TIRE_PRESSURE, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.ENGINE_IDLE_AUTO_STOP_ENABLED, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.IMPACT_DETECTED, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.GEAR_SELECTION, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.CURRENT_GEAR, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.PARKING_BRAKE_ON, VehiclePropertyAccess.READ),
@@ -75,6 +77,8 @@
         Map.entry(VehicleProperty.ABS_ACTIVE, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.TRACTION_CONTROL_ACTIVE, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.EV_STOPPING_MODE, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.ELECTRONIC_STABILITY_CONTROL_ENABLED, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.ELECTRONIC_STABILITY_CONTROL_STATE, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.HVAC_FAN_SPEED, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.HVAC_FAN_DIRECTION, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.HVAC_TEMPERATURE_CURRENT, VehiclePropertyAccess.READ),
@@ -112,6 +116,8 @@
         Map.entry(VehicleProperty.AP_POWER_BOOTUP_REASON, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.DISPLAY_BRIGHTNESS, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.PER_DISPLAY_BRIGHTNESS, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.VALET_MODE_ENABLED, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.HEAD_UP_DISPLAY_ENABLED, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.HW_KEY_INPUT, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.HW_KEY_INPUT_V2, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.HW_MOTION_INPUT, VehiclePropertyAccess.READ),
@@ -161,11 +167,13 @@
         Map.entry(VehicleProperty.SEAT_FOOTWELL_LIGHTS_SWITCH, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.SEAT_EASY_ACCESS_ENABLED, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.SEAT_AIRBAG_ENABLED, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.SEAT_AIRBAGS_DEPLOYED, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.SEAT_CUSHION_SIDE_SUPPORT_POS, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.SEAT_CUSHION_SIDE_SUPPORT_MOVE, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.SEAT_LUMBAR_VERTICAL_POS, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.SEAT_LUMBAR_VERTICAL_MOVE, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.SEAT_WALK_IN_POS, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.SEAT_BELT_PRETENSIONER_DEPLOYED, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.SEAT_OCCUPANCY, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.WINDOW_POS, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.WINDOW_MOVE, VehiclePropertyAccess.READ_WRITE),
@@ -184,6 +192,12 @@
         Map.entry(VehicleProperty.GLOVE_BOX_LOCKED, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.VEHICLE_MAP_SERVICE, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.LOCATION_CHARACTERIZATION, VehiclePropertyAccess.READ),
+        Map.entry(VehicleProperty.ULTRASONICS_SENSOR_POSITION, VehiclePropertyAccess.READ),
+        Map.entry(VehicleProperty.ULTRASONICS_SENSOR_ORIENTATION, VehiclePropertyAccess.READ),
+        Map.entry(VehicleProperty.ULTRASONICS_SENSOR_FIELD_OF_VIEW, VehiclePropertyAccess.READ),
+        Map.entry(VehicleProperty.ULTRASONICS_SENSOR_DETECTION_RANGE, VehiclePropertyAccess.READ),
+        Map.entry(VehicleProperty.ULTRASONICS_SENSOR_SUPPORTED_RANGES, VehiclePropertyAccess.READ),
+        Map.entry(VehicleProperty.ULTRASONICS_SENSOR_MEASURED_DISTANCE, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.OBD2_LIVE_FRAME, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.OBD2_FREEZE_FRAME, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.OBD2_FREEZE_FRAME_INFO, VehiclePropertyAccess.READ),
@@ -239,6 +253,8 @@
         Map.entry(VehicleProperty.SUPPORTED_PROPERTY_IDS, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.SHUTDOWN_REQUEST, VehiclePropertyAccess.WRITE),
         Map.entry(VehicleProperty.VEHICLE_IN_USE, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.CLUSTER_HEARTBEAT, VehiclePropertyAccess.WRITE),
+        Map.entry(VehicleProperty.VEHICLE_DRIVING_AUTOMATION_CURRENT_LEVEL, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.AUTOMATIC_EMERGENCY_BRAKING_STATE, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.FORWARD_COLLISION_WARNING_ENABLED, VehiclePropertyAccess.READ_WRITE),
@@ -263,7 +279,21 @@
         Map.entry(VehicleProperty.ADAPTIVE_CRUISE_CONTROL_LEAD_VEHICLE_MEASURED_DISTANCE, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.HANDS_ON_DETECTION_ENABLED, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.HANDS_ON_DETECTION_DRIVER_STATE, VehiclePropertyAccess.READ),
-        Map.entry(VehicleProperty.HANDS_ON_DETECTION_WARNING, VehiclePropertyAccess.READ)
+        Map.entry(VehicleProperty.HANDS_ON_DETECTION_WARNING, VehiclePropertyAccess.READ),
+        Map.entry(VehicleProperty.DRIVER_DROWSINESS_ATTENTION_SYSTEM_ENABLED, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.DRIVER_DROWSINESS_ATTENTION_STATE, VehiclePropertyAccess.READ),
+        Map.entry(VehicleProperty.DRIVER_DROWSINESS_ATTENTION_WARNING_ENABLED, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.DRIVER_DROWSINESS_ATTENTION_WARNING, VehiclePropertyAccess.READ),
+        Map.entry(VehicleProperty.DRIVER_DISTRACTION_SYSTEM_ENABLED, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.DRIVER_DISTRACTION_STATE, VehiclePropertyAccess.READ),
+        Map.entry(VehicleProperty.DRIVER_DISTRACTION_WARNING_ENABLED, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.DRIVER_DISTRACTION_WARNING, VehiclePropertyAccess.READ),
+        Map.entry(VehicleProperty.LOW_SPEED_COLLISION_WARNING_ENABLED, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.LOW_SPEED_COLLISION_WARNING_STATE, VehiclePropertyAccess.READ),
+        Map.entry(VehicleProperty.CROSS_TRAFFIC_MONITORING_ENABLED, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.CROSS_TRAFFIC_MONITORING_WARNING_STATE, VehiclePropertyAccess.READ),
+        Map.entry(VehicleProperty.LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE, VehiclePropertyAccess.READ)
     );
 
 }
diff --git a/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java b/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java
index 29069f8..e351a3f 100644
--- a/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java
+++ b/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -60,9 +60,11 @@
         Map.entry(VehicleProperty.EV_CHARGE_PORT_CONNECTED, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.EV_BATTERY_INSTANTANEOUS_CHARGE_RATE, VehiclePropertyChangeMode.CONTINUOUS),
         Map.entry(VehicleProperty.RANGE_REMAINING, VehiclePropertyChangeMode.CONTINUOUS),
+        Map.entry(VehicleProperty.EV_BATTERY_AVERAGE_TEMPERATURE, VehiclePropertyChangeMode.CONTINUOUS),
         Map.entry(VehicleProperty.TIRE_PRESSURE, VehiclePropertyChangeMode.CONTINUOUS),
         Map.entry(VehicleProperty.CRITICALLY_LOW_TIRE_PRESSURE, VehiclePropertyChangeMode.STATIC),
         Map.entry(VehicleProperty.ENGINE_IDLE_AUTO_STOP_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.IMPACT_DETECTED, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.GEAR_SELECTION, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.CURRENT_GEAR, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.PARKING_BRAKE_ON, VehiclePropertyChangeMode.ON_CHANGE),
@@ -75,6 +77,8 @@
         Map.entry(VehicleProperty.ABS_ACTIVE, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.TRACTION_CONTROL_ACTIVE, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.EV_STOPPING_MODE, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.ELECTRONIC_STABILITY_CONTROL_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.ELECTRONIC_STABILITY_CONTROL_STATE, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.HVAC_FAN_SPEED, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.HVAC_FAN_DIRECTION, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.HVAC_TEMPERATURE_CURRENT, VehiclePropertyChangeMode.ON_CHANGE),
@@ -112,6 +116,8 @@
         Map.entry(VehicleProperty.AP_POWER_BOOTUP_REASON, VehiclePropertyChangeMode.STATIC),
         Map.entry(VehicleProperty.DISPLAY_BRIGHTNESS, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.PER_DISPLAY_BRIGHTNESS, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.VALET_MODE_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.HEAD_UP_DISPLAY_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.HW_KEY_INPUT, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.HW_KEY_INPUT_V2, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.HW_MOTION_INPUT, VehiclePropertyChangeMode.ON_CHANGE),
@@ -161,11 +167,13 @@
         Map.entry(VehicleProperty.SEAT_FOOTWELL_LIGHTS_SWITCH, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.SEAT_EASY_ACCESS_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.SEAT_AIRBAG_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.SEAT_AIRBAGS_DEPLOYED, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.SEAT_CUSHION_SIDE_SUPPORT_POS, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.SEAT_CUSHION_SIDE_SUPPORT_MOVE, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.SEAT_LUMBAR_VERTICAL_POS, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.SEAT_LUMBAR_VERTICAL_MOVE, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.SEAT_WALK_IN_POS, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.SEAT_BELT_PRETENSIONER_DEPLOYED, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.SEAT_OCCUPANCY, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.WINDOW_POS, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.WINDOW_MOVE, VehiclePropertyChangeMode.ON_CHANGE),
@@ -184,6 +192,12 @@
         Map.entry(VehicleProperty.GLOVE_BOX_LOCKED, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.VEHICLE_MAP_SERVICE, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.LOCATION_CHARACTERIZATION, VehiclePropertyChangeMode.STATIC),
+        Map.entry(VehicleProperty.ULTRASONICS_SENSOR_POSITION, VehiclePropertyChangeMode.STATIC),
+        Map.entry(VehicleProperty.ULTRASONICS_SENSOR_ORIENTATION, VehiclePropertyChangeMode.STATIC),
+        Map.entry(VehicleProperty.ULTRASONICS_SENSOR_FIELD_OF_VIEW, VehiclePropertyChangeMode.STATIC),
+        Map.entry(VehicleProperty.ULTRASONICS_SENSOR_DETECTION_RANGE, VehiclePropertyChangeMode.STATIC),
+        Map.entry(VehicleProperty.ULTRASONICS_SENSOR_SUPPORTED_RANGES, VehiclePropertyChangeMode.STATIC),
+        Map.entry(VehicleProperty.ULTRASONICS_SENSOR_MEASURED_DISTANCE, VehiclePropertyChangeMode.CONTINUOUS),
         Map.entry(VehicleProperty.OBD2_LIVE_FRAME, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.OBD2_FREEZE_FRAME, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.OBD2_FREEZE_FRAME_INFO, VehiclePropertyChangeMode.ON_CHANGE),
@@ -239,6 +253,8 @@
         Map.entry(VehicleProperty.SUPPORTED_PROPERTY_IDS, VehiclePropertyChangeMode.STATIC),
         Map.entry(VehicleProperty.SHUTDOWN_REQUEST, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.VEHICLE_IN_USE, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.CLUSTER_HEARTBEAT, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.VEHICLE_DRIVING_AUTOMATION_CURRENT_LEVEL, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.AUTOMATIC_EMERGENCY_BRAKING_STATE, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.FORWARD_COLLISION_WARNING_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
@@ -263,7 +279,21 @@
         Map.entry(VehicleProperty.ADAPTIVE_CRUISE_CONTROL_LEAD_VEHICLE_MEASURED_DISTANCE, VehiclePropertyChangeMode.CONTINUOUS),
         Map.entry(VehicleProperty.HANDS_ON_DETECTION_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.HANDS_ON_DETECTION_DRIVER_STATE, VehiclePropertyChangeMode.ON_CHANGE),
-        Map.entry(VehicleProperty.HANDS_ON_DETECTION_WARNING, VehiclePropertyChangeMode.ON_CHANGE)
+        Map.entry(VehicleProperty.HANDS_ON_DETECTION_WARNING, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.DRIVER_DROWSINESS_ATTENTION_SYSTEM_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.DRIVER_DROWSINESS_ATTENTION_STATE, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.DRIVER_DROWSINESS_ATTENTION_WARNING_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.DRIVER_DROWSINESS_ATTENTION_WARNING, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.DRIVER_DISTRACTION_SYSTEM_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.DRIVER_DISTRACTION_STATE, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.DRIVER_DISTRACTION_WARNING_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.DRIVER_DISTRACTION_WARNING, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.LOW_SPEED_COLLISION_WARNING_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.LOW_SPEED_COLLISION_WARNING_STATE, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.CROSS_TRAFFIC_MONITORING_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.CROSS_TRAFFIC_MONITORING_WARNING_STATE, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE, VehiclePropertyChangeMode.ON_CHANGE)
     );
 
 }
diff --git a/automotive/vehicle/aidl/generated_lib/java/EnumForVehicleProperty.java b/automotive/vehicle/aidl/generated_lib/java/EnumForVehicleProperty.java
new file mode 100644
index 0000000..4b8060f
--- /dev/null
+++ b/automotive/vehicle/aidl/generated_lib/java/EnumForVehicleProperty.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * DO NOT EDIT MANUALLY!!!
+ *
+ * Generated by tools/generate_annotation_enums.py.
+ */
+
+// clang-format off
+
+package android.hardware.automotive.vehicle;
+
+import java.util.List;
+import java.util.Map;
+
+public final class EnumForVehicleProperty {
+
+    public static final Map<Integer, List<Class<?>>> values = Map.ofEntries(
+        Map.entry(VehicleProperty.INFO_FUEL_TYPE, List.of(FuelType.class)),
+        Map.entry(VehicleProperty.INFO_EV_CONNECTOR_TYPE, List.of(EvConnectorType.class)),
+        Map.entry(VehicleProperty.INFO_FUEL_DOOR_LOCATION, List.of(PortLocationType.class)),
+        Map.entry(VehicleProperty.INFO_EV_PORT_LOCATION, List.of(PortLocationType.class)),
+        Map.entry(VehicleProperty.INFO_DRIVER_SEAT, List.of(VehicleAreaSeat.class)),
+        Map.entry(VehicleProperty.INFO_MULTI_EV_PORT_LOCATIONS, List.of(PortLocationType.class)),
+        Map.entry(VehicleProperty.ENGINE_OIL_LEVEL, List.of(VehicleOilLevel.class)),
+        Map.entry(VehicleProperty.IMPACT_DETECTED, List.of(ImpactSensorLocation.class)),
+        Map.entry(VehicleProperty.GEAR_SELECTION, List.of(VehicleGear.class)),
+        Map.entry(VehicleProperty.CURRENT_GEAR, List.of(VehicleGear.class)),
+        Map.entry(VehicleProperty.TURN_SIGNAL_STATE, List.of(VehicleTurnSignal.class)),
+        Map.entry(VehicleProperty.IGNITION_STATE, List.of(VehicleIgnitionState.class)),
+        Map.entry(VehicleProperty.EV_STOPPING_MODE, List.of(EvStoppingMode.class)),
+        Map.entry(VehicleProperty.ELECTRONIC_STABILITY_CONTROL_STATE, List.of(ElectronicStabilityControlState.class, ErrorState.class)),
+        Map.entry(VehicleProperty.HVAC_FAN_DIRECTION, List.of(VehicleHvacFanDirection.class)),
+        Map.entry(VehicleProperty.HVAC_TEMPERATURE_DISPLAY_UNITS, List.of(VehicleUnit.class)),
+        Map.entry(VehicleProperty.HVAC_FAN_DIRECTION_AVAILABLE, List.of(VehicleHvacFanDirection.class)),
+        Map.entry(VehicleProperty.DISTANCE_DISPLAY_UNITS, List.of(VehicleUnit.class)),
+        Map.entry(VehicleProperty.FUEL_VOLUME_DISPLAY_UNITS, List.of(VehicleUnit.class)),
+        Map.entry(VehicleProperty.TIRE_PRESSURE_DISPLAY_UNITS, List.of(VehicleUnit.class)),
+        Map.entry(VehicleProperty.EV_BATTERY_DISPLAY_UNITS, List.of(VehicleUnit.class)),
+        Map.entry(VehicleProperty.HW_ROTARY_INPUT, List.of(RotaryInputType.class)),
+        Map.entry(VehicleProperty.HW_CUSTOM_INPUT, List.of(CustomInputType.class)),
+        Map.entry(VehicleProperty.SEAT_FOOTWELL_LIGHTS_STATE, List.of(VehicleLightState.class)),
+        Map.entry(VehicleProperty.SEAT_FOOTWELL_LIGHTS_SWITCH, List.of(VehicleLightSwitch.class)),
+        Map.entry(VehicleProperty.SEAT_AIRBAGS_DEPLOYED, List.of(VehicleAirbagLocation.class)),
+        Map.entry(VehicleProperty.SEAT_OCCUPANCY, List.of(VehicleSeatOccupancyState.class)),
+        Map.entry(VehicleProperty.WINDSHIELD_WIPERS_STATE, List.of(WindshieldWipersState.class)),
+        Map.entry(VehicleProperty.WINDSHIELD_WIPERS_SWITCH, List.of(WindshieldWipersSwitch.class)),
+        Map.entry(VehicleProperty.HEADLIGHTS_STATE, List.of(VehicleLightState.class)),
+        Map.entry(VehicleProperty.HIGH_BEAM_LIGHTS_STATE, List.of(VehicleLightState.class)),
+        Map.entry(VehicleProperty.FOG_LIGHTS_STATE, List.of(VehicleLightState.class)),
+        Map.entry(VehicleProperty.HAZARD_LIGHTS_STATE, List.of(VehicleLightState.class)),
+        Map.entry(VehicleProperty.HEADLIGHTS_SWITCH, List.of(VehicleLightSwitch.class)),
+        Map.entry(VehicleProperty.HIGH_BEAM_LIGHTS_SWITCH, List.of(VehicleLightSwitch.class)),
+        Map.entry(VehicleProperty.FOG_LIGHTS_SWITCH, List.of(VehicleLightSwitch.class)),
+        Map.entry(VehicleProperty.HAZARD_LIGHTS_SWITCH, List.of(VehicleLightSwitch.class)),
+        Map.entry(VehicleProperty.CABIN_LIGHTS_STATE, List.of(VehicleLightState.class)),
+        Map.entry(VehicleProperty.CABIN_LIGHTS_SWITCH, List.of(VehicleLightSwitch.class)),
+        Map.entry(VehicleProperty.READING_LIGHTS_STATE, List.of(VehicleLightState.class)),
+        Map.entry(VehicleProperty.READING_LIGHTS_SWITCH, List.of(VehicleLightSwitch.class)),
+        Map.entry(VehicleProperty.STEERING_WHEEL_LIGHTS_STATE, List.of(VehicleLightState.class)),
+        Map.entry(VehicleProperty.STEERING_WHEEL_LIGHTS_SWITCH, List.of(VehicleLightSwitch.class)),
+        Map.entry(VehicleProperty.ELECTRONIC_TOLL_COLLECTION_CARD_TYPE, List.of(ElectronicTollCollectionCardType.class)),
+        Map.entry(VehicleProperty.ELECTRONIC_TOLL_COLLECTION_CARD_STATUS, List.of(ElectronicTollCollectionCardStatus.class)),
+        Map.entry(VehicleProperty.FRONT_FOG_LIGHTS_STATE, List.of(VehicleLightState.class)),
+        Map.entry(VehicleProperty.FRONT_FOG_LIGHTS_SWITCH, List.of(VehicleLightSwitch.class)),
+        Map.entry(VehicleProperty.REAR_FOG_LIGHTS_STATE, List.of(VehicleLightState.class)),
+        Map.entry(VehicleProperty.REAR_FOG_LIGHTS_SWITCH, List.of(VehicleLightSwitch.class)),
+        Map.entry(VehicleProperty.EV_CHARGE_STATE, List.of(EvChargeState.class)),
+        Map.entry(VehicleProperty.EV_REGENERATIVE_BRAKING_STATE, List.of(EvRegenerativeBrakingState.class)),
+        Map.entry(VehicleProperty.TRAILER_PRESENT, List.of(TrailerState.class)),
+        Map.entry(VehicleProperty.GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT, List.of(GsrComplianceRequirementType.class)),
+        Map.entry(VehicleProperty.SHUTDOWN_REQUEST, List.of(VehicleApPowerStateShutdownParam.class)),
+        Map.entry(VehicleProperty.VEHICLE_DRIVING_AUTOMATION_CURRENT_LEVEL, List.of(VehicleAutonomousState.class)),
+        Map.entry(VehicleProperty.AUTOMATIC_EMERGENCY_BRAKING_STATE, List.of(AutomaticEmergencyBrakingState.class, ErrorState.class)),
+        Map.entry(VehicleProperty.FORWARD_COLLISION_WARNING_STATE, List.of(ForwardCollisionWarningState.class, ErrorState.class)),
+        Map.entry(VehicleProperty.BLIND_SPOT_WARNING_STATE, List.of(BlindSpotWarningState.class, ErrorState.class)),
+        Map.entry(VehicleProperty.LANE_DEPARTURE_WARNING_STATE, List.of(LaneDepartureWarningState.class, ErrorState.class)),
+        Map.entry(VehicleProperty.LANE_KEEP_ASSIST_STATE, List.of(LaneKeepAssistState.class, ErrorState.class)),
+        Map.entry(VehicleProperty.LANE_CENTERING_ASSIST_COMMAND, List.of(LaneCenteringAssistCommand.class)),
+        Map.entry(VehicleProperty.LANE_CENTERING_ASSIST_STATE, List.of(LaneCenteringAssistState.class, ErrorState.class)),
+        Map.entry(VehicleProperty.EMERGENCY_LANE_KEEP_ASSIST_STATE, List.of(EmergencyLaneKeepAssistState.class, ErrorState.class)),
+        Map.entry(VehicleProperty.CRUISE_CONTROL_TYPE, List.of(CruiseControlType.class, ErrorState.class)),
+        Map.entry(VehicleProperty.CRUISE_CONTROL_STATE, List.of(CruiseControlState.class, ErrorState.class)),
+        Map.entry(VehicleProperty.CRUISE_CONTROL_COMMAND, List.of(CruiseControlCommand.class)),
+        Map.entry(VehicleProperty.HANDS_ON_DETECTION_DRIVER_STATE, List.of(HandsOnDetectionDriverState.class, ErrorState.class)),
+        Map.entry(VehicleProperty.HANDS_ON_DETECTION_WARNING, List.of(HandsOnDetectionWarning.class, ErrorState.class)),
+        Map.entry(VehicleProperty.DRIVER_DROWSINESS_ATTENTION_STATE, List.of(DriverDrowsinessAttentionState.class, ErrorState.class)),
+        Map.entry(VehicleProperty.DRIVER_DROWSINESS_ATTENTION_WARNING, List.of(DriverDrowsinessAttentionWarning.class, ErrorState.class)),
+        Map.entry(VehicleProperty.DRIVER_DISTRACTION_STATE, List.of(DriverDistractionState.class, ErrorState.class)),
+        Map.entry(VehicleProperty.DRIVER_DISTRACTION_WARNING, List.of(DriverDistractionWarning.class, ErrorState.class)),
+        Map.entry(VehicleProperty.LOW_SPEED_COLLISION_WARNING_STATE, List.of(LowSpeedCollisionWarningState.class, ErrorState.class)),
+        Map.entry(VehicleProperty.CROSS_TRAFFIC_MONITORING_WARNING_STATE, List.of(CrossTrafficMonitoringWarningState.class, ErrorState.class)),
+        Map.entry(VehicleProperty.LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE, List.of(LowSpeedAutomaticEmergencyBrakingState.class, ErrorState.class))
+    );
+
+}
diff --git a/automotive/vehicle/aidl/impl/README.md b/automotive/vehicle/aidl/impl/README.md
index 121ffd1..2cd3a3e 100644
--- a/automotive/vehicle/aidl/impl/README.md
+++ b/automotive/vehicle/aidl/impl/README.md
@@ -46,7 +46,7 @@
 use this library, along with their own implementation for `IVehicleHardware`
 interface.
 
-Also defines a binary `android.hardware.automotive.vehicle@V1-default-service`
+Also defines a binary `android.hardware.automotive.vehicle@V3-default-service`
 which is the reference VHAL implementation. It implements `IVehicle.aidl`
 interface. It uses `DefaultVehicleHal`, along with `FakeVehicleHardware`
 (in fake_impl). It simulates the vehicle bus interaction by using an
diff --git a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/Android.bp b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/Android.bp
index 6984d5e..75a3541 100644
--- a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/Android.bp
+++ b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/Android.bp
@@ -35,14 +35,17 @@
 cc_library {
     name: "VehicleHalJsonConfigLoaderEnableTestProperties",
     vendor: true,
-    srcs: ["src/*.cpp"],
+    srcs: [
+        "src/*.cpp",
+        ":VhalTestVendorProperties",
+    ],
     local_include_dirs: ["include"],
     export_include_dirs: ["include"],
     defaults: ["VehicleHalDefaults"],
     static_libs: ["VehicleHalUtils"],
     header_libs: [
-        "VehicleHalTestUtilHeaders",
         "IVehicleGeneratedHeaders",
+        "libbinder_headers",
     ],
     cflags: ["-DENABLE_VEHICLE_HAL_TEST_PROPERTIES"],
     shared_libs: ["libjsoncpp"],
diff --git a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
index 0a1f904..3e6e7dc 100644
--- a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
+++ b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
@@ -21,7 +21,7 @@
 #include <PropertyUtils.h>
 
 #ifdef ENABLE_VEHICLE_HAL_TEST_PROPERTIES
-#include <TestPropertyUtils.h>
+#include <android/hardware/automotive/vehicle/TestVendorProperty.h>
 #endif  // ENABLE_VEHICLE_HAL_TEST_PROPERTIES
 
 #include <android-base/strings.h>
@@ -38,9 +38,15 @@
 using ::aidl::android::hardware::automotive::vehicle::AutomaticEmergencyBrakingState;
 using ::aidl::android::hardware::automotive::vehicle::BlindSpotWarningState;
 using ::aidl::android::hardware::automotive::vehicle::ChangeModeForVehicleProperty;
+using ::aidl::android::hardware::automotive::vehicle::CrossTrafficMonitoringWarningState;
 using ::aidl::android::hardware::automotive::vehicle::CruiseControlCommand;
 using ::aidl::android::hardware::automotive::vehicle::CruiseControlState;
 using ::aidl::android::hardware::automotive::vehicle::CruiseControlType;
+using ::aidl::android::hardware::automotive::vehicle::DriverDistractionState;
+using ::aidl::android::hardware::automotive::vehicle::DriverDistractionWarning;
+using ::aidl::android::hardware::automotive::vehicle::DriverDrowsinessAttentionState;
+using ::aidl::android::hardware::automotive::vehicle::DriverDrowsinessAttentionWarning;
+using ::aidl::android::hardware::automotive::vehicle::ElectronicStabilityControlState;
 using ::aidl::android::hardware::automotive::vehicle::EmergencyLaneKeepAssistState;
 using ::aidl::android::hardware::automotive::vehicle::ErrorState;
 using ::aidl::android::hardware::automotive::vehicle::EvConnectorType;
@@ -51,17 +57,22 @@
 using ::aidl::android::hardware::automotive::vehicle::GsrComplianceRequirementType;
 using ::aidl::android::hardware::automotive::vehicle::HandsOnDetectionDriverState;
 using ::aidl::android::hardware::automotive::vehicle::HandsOnDetectionWarning;
+using ::aidl::android::hardware::automotive::vehicle::ImpactSensorLocation;
 using ::aidl::android::hardware::automotive::vehicle::LaneCenteringAssistCommand;
 using ::aidl::android::hardware::automotive::vehicle::LaneCenteringAssistState;
 using ::aidl::android::hardware::automotive::vehicle::LaneDepartureWarningState;
 using ::aidl::android::hardware::automotive::vehicle::LaneKeepAssistState;
 using ::aidl::android::hardware::automotive::vehicle::LocationCharacterization;
+using ::aidl::android::hardware::automotive::vehicle::LowSpeedAutomaticEmergencyBrakingState;
+using ::aidl::android::hardware::automotive::vehicle::LowSpeedCollisionWarningState;
 using ::aidl::android::hardware::automotive::vehicle::RawPropValues;
+using ::aidl::android::hardware::automotive::vehicle::VehicleAirbagLocation;
 using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateReport;
 using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateReq;
 using ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig;
 using ::aidl::android::hardware::automotive::vehicle::VehicleAreaMirror;
 using ::aidl::android::hardware::automotive::vehicle::VehicleAreaWindow;
+using ::aidl::android::hardware::automotive::vehicle::VehicleAutonomousState;
 using ::aidl::android::hardware::automotive::vehicle::VehicleGear;
 using ::aidl::android::hardware::automotive::vehicle::VehicleHvacFanDirection;
 using ::aidl::android::hardware::automotive::vehicle::VehicleIgnitionState;
@@ -91,10 +102,6 @@
         {"HVAC_ALL", HVAC_ALL},
         {"HVAC_LEFT", HVAC_LEFT},
         {"HVAC_RIGHT", HVAC_RIGHT},
-        {"VENDOR_EXTENSION_INT_PROPERTY", VENDOR_EXTENSION_INT_PROPERTY},
-        {"VENDOR_EXTENSION_BOOLEAN_PROPERTY", VENDOR_EXTENSION_BOOLEAN_PROPERTY},
-        {"VENDOR_EXTENSION_STRING_PROPERTY", VENDOR_EXTENSION_STRING_PROPERTY},
-        {"VENDOR_EXTENSION_FLOAT_PROPERTY", VENDOR_EXTENSION_FLOAT_PROPERTY},
         {"WINDOW_1_LEFT", WINDOW_1_LEFT},
         {"WINDOW_1_RIGHT", WINDOW_1_RIGHT},
         {"WINDOW_2_LEFT", WINDOW_2_LEFT},
@@ -133,24 +140,9 @@
         {"EV_STOPPING_MODE_HOLD", EV_STOPPING_MODE_HOLD},
         {"MIRROR_DRIVER_LEFT_RIGHT",
          toInt(VehicleAreaMirror::DRIVER_LEFT) | toInt(VehicleAreaMirror::DRIVER_RIGHT)},
-#ifdef ENABLE_VEHICLE_HAL_TEST_PROPERTIES
-        // Following are test properties:
-        {"ECHO_REVERSE_BYTES", ECHO_REVERSE_BYTES},
-        {"VENDOR_PROPERTY_ID", VENDOR_PROPERTY_ID},
-        {"kMixedTypePropertyForTest", kMixedTypePropertyForTest},
-        {"VENDOR_CLUSTER_NAVIGATION_STATE", VENDOR_CLUSTER_NAVIGATION_STATE},
-        {"VENDOR_CLUSTER_REQUEST_DISPLAY", VENDOR_CLUSTER_REQUEST_DISPLAY},
-        {"VENDOR_CLUSTER_SWITCH_UI", VENDOR_CLUSTER_SWITCH_UI},
-        {"VENDOR_CLUSTER_DISPLAY_STATE", VENDOR_CLUSTER_DISPLAY_STATE},
-        {"VENDOR_CLUSTER_REPORT_STATE", VENDOR_CLUSTER_REPORT_STATE},
-        {"PLACEHOLDER_PROPERTY_INT", PLACEHOLDER_PROPERTY_INT},
-        {"PLACEHOLDER_PROPERTY_FLOAT", PLACEHOLDER_PROPERTY_FLOAT},
-        {"PLACEHOLDER_PROPERTY_BOOLEAN", PLACEHOLDER_PROPERTY_BOOLEAN},
-        {"PLACEHOLDER_PROPERTY_STRING", PLACEHOLDER_PROPERTY_STRING}
-#endif  // ENABLE_VEHICLE_HAL_TEST_PROPERTIES
 };
 
-// A class to parse constant values for type T.
+// A class to parse constant values for type T where T is defined as an enum in NDK AIDL backend.
 template <class T>
 class ConstantParser final : public ConstantParserInterface {
   public:
@@ -181,6 +173,33 @@
     std::unordered_map<std::string, int> mValueByName;
 };
 
+#ifdef ENABLE_VEHICLE_HAL_TEST_PROPERTIES
+// A class to parse constant values for type T where T is defined as an enum in CPP AIDL backend.
+template <class T>
+class CppConstantParser final : public ConstantParserInterface {
+  public:
+    CppConstantParser() {
+        for (const T& v : android::enum_range<T>()) {
+            std::string name = android::hardware::automotive::vehicle::toString(v);
+            mValueByName[name] = toInt(v);
+        }
+    }
+
+    ~CppConstantParser() = default;
+
+    Result<int> parseValue(const std::string& name) const override {
+        auto it = mValueByName.find(name);
+        if (it == mValueByName.end()) {
+            return Error() << "Constant name: " << name << " is not defined";
+        }
+        return it->second;
+    }
+
+  private:
+    std::unordered_map<std::string, int> mValueByName;
+};
+#endif
+
 // A class to parse constant values defined in CONSTANTS_BY_NAME map.
 class LocalVariableParser final : public ConstantParserInterface {
   public:
@@ -232,6 +251,12 @@
             std::make_unique<ConstantParser<WindshieldWipersState>>();
     mConstantParsersByType["WindshieldWipersSwitch"] =
             std::make_unique<ConstantParser<WindshieldWipersSwitch>>();
+    mConstantParsersByType["VehicleAutonomousState"] =
+            std::make_unique<ConstantParser<VehicleAutonomousState>>();
+    mConstantParsersByType["VehicleAirbagLocation"] =
+            std::make_unique<ConstantParser<VehicleAirbagLocation>>();
+    mConstantParsersByType["ImpactSensorLocation"] =
+            std::make_unique<ConstantParser<ImpactSensorLocation>>();
     mConstantParsersByType["EmergencyLaneKeepAssistState"] =
             std::make_unique<ConstantParser<EmergencyLaneKeepAssistState>>();
     mConstantParsersByType["CruiseControlType"] =
@@ -244,6 +269,14 @@
             std::make_unique<ConstantParser<HandsOnDetectionDriverState>>();
     mConstantParsersByType["HandsOnDetectionWarning"] =
             std::make_unique<ConstantParser<HandsOnDetectionWarning>>();
+    mConstantParsersByType["DriverDrowsinessAttentionState"] =
+            std::make_unique<ConstantParser<DriverDrowsinessAttentionState>>();
+    mConstantParsersByType["DriverDrowsinessAttentionWarning"] =
+            std::make_unique<ConstantParser<DriverDrowsinessAttentionWarning>>();
+    mConstantParsersByType["DriverDistractionState"] =
+            std::make_unique<ConstantParser<DriverDistractionState>>();
+    mConstantParsersByType["DriverDistractionWarning"] =
+            std::make_unique<ConstantParser<DriverDistractionWarning>>();
     mConstantParsersByType["ErrorState"] = std::make_unique<ConstantParser<ErrorState>>();
     mConstantParsersByType["AutomaticEmergencyBrakingState"] =
             std::make_unique<ConstantParser<AutomaticEmergencyBrakingState>>();
@@ -259,7 +292,29 @@
             std::make_unique<ConstantParser<LaneCenteringAssistCommand>>();
     mConstantParsersByType["LaneCenteringAssistState"] =
             std::make_unique<ConstantParser<LaneCenteringAssistState>>();
+    mConstantParsersByType["LowSpeedCollisionWarningState"] =
+            std::make_unique<ConstantParser<LowSpeedCollisionWarningState>>();
+    mConstantParsersByType["ElectronicStabilityControlState"] =
+            std::make_unique<ConstantParser<ElectronicStabilityControlState>>();
+    mConstantParsersByType["CrossTrafficMonitoringWarningState"] =
+            std::make_unique<ConstantParser<CrossTrafficMonitoringWarningState>>();
+    mConstantParsersByType["LowSpeedAutomaticEmergencyBrakingState"] =
+            std::make_unique<ConstantParser<LowSpeedAutomaticEmergencyBrakingState>>();
     mConstantParsersByType["Constants"] = std::make_unique<LocalVariableParser>();
+#ifdef ENABLE_VEHICLE_HAL_TEST_PROPERTIES
+    mConstantParsersByType["TestVendorProperty"] =
+            std::make_unique<CppConstantParser<TestVendorProperty>>();
+#endif  // ENABLE_VEHICLE_HAL_TEST_PROPERTIES
+}
+
+template <>
+Result<bool> JsonValueParser::convertValueToType<bool>(const std::string& fieldName,
+                                                       const Json::Value& value) {
+    if (!value.isBool()) {
+        return Error() << "The value: " << value << " for field: " << fieldName
+                       << " is not in correct type, expect bool";
+    }
+    return value.asBool();
 }
 
 template <>
@@ -519,6 +574,12 @@
         tryParseJsonValueToVariable(jsonAreaConfig, "maxFloatValue", /*optional=*/true,
                                     &areaConfig.maxFloatValue, errors);
 
+        // By default we support variable update rate for all properties except it is explicitly
+        // disabled.
+        areaConfig.supportVariableUpdateRate = true;
+        tryParseJsonValueToVariable(jsonAreaConfig, "supportVariableUpdateRate", /*optional=*/true,
+                                    &areaConfig.supportVariableUpdateRate, errors);
+
         std::vector<int64_t> supportedEnumValues;
         tryParseJsonArrayToVariable(jsonAreaConfig, "supportedEnumValues", /*optional=*/true,
                                     &supportedEnumValues, errors);
@@ -573,6 +634,16 @@
     if (errors->size() != initialErrorCount) {
         return std::nullopt;
     }
+
+    // If there is no area config, by default we allow variable update rate, so we have to add
+    // a global area config.
+    if (configDecl.config.areaConfigs.size() == 0) {
+        VehicleAreaConfig areaConfig = {
+                .areaId = 0,
+                .supportVariableUpdateRate = true,
+        };
+        configDecl.config.areaConfigs.push_back(std::move(areaConfig));
+    }
     return configDecl;
 }
 
diff --git a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
index 5503de2..56d8b4b 100644
--- a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
+++ b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
@@ -1328,6 +1328,75 @@
             ]
         },
         {
+            "property": "VehicleProperty::SEAT_AIRBAGS_DEPLOYED",
+            "defaultValue": {
+                "int32Values": [
+                    0
+                ]
+            },
+            "areas": [
+                {
+                    "areaId": "Constants::SEAT_1_LEFT",
+                    "supportedEnumValues": [
+                        "VehicleAirbagLocation::FRONT",
+                        "VehicleAirbagLocation::KNEE",
+                        "VehicleAirbagLocation::LEFT_SIDE",
+                        "VehicleAirbagLocation::RIGHT_SIDE",
+                        "VehicleAirbagLocation::CURTAIN"
+                    ]
+                },
+                {
+                    "areaId": "Constants::SEAT_1_RIGHT",
+                    "supportedEnumValues": [
+                        "VehicleAirbagLocation::FRONT",
+                        "VehicleAirbagLocation::KNEE",
+                        "VehicleAirbagLocation::LEFT_SIDE",
+                        "VehicleAirbagLocation::RIGHT_SIDE",
+                        "VehicleAirbagLocation::CURTAIN"
+                    ]
+                },
+                {
+                    "areaId": "Constants::SEAT_2_LEFT",
+                    "supportedEnumValues": [
+                        "VehicleAirbagLocation::FRONT",
+                        "VehicleAirbagLocation::CURTAIN"
+                    ]
+                },
+                {
+                    "areaId": "Constants::SEAT_2_RIGHT",
+                    "supportedEnumValues": [
+                        "VehicleAirbagLocation::FRONT",
+                        "VehicleAirbagLocation::CURTAIN"
+                    ]
+                }
+            ]
+        },
+        {
+            "property": "VehicleProperty::SEAT_BELT_PRETENSIONER_DEPLOYED",
+            "defaultValue": {
+                "int32Values": [
+                    0
+                ]
+            },
+            "areas": [
+                {
+                    "areaId": "Constants::SEAT_1_LEFT"
+                },
+                {
+                    "areaId": "Constants::SEAT_1_RIGHT"
+                },
+                {
+                    "areaId": "Constants::SEAT_2_LEFT"
+                },
+                {
+                    "areaId": "Constants::SEAT_2_RIGHT"
+                },
+                {
+                    "areaId": "Constants::SEAT_2_CENTER"
+                }
+            ]
+        },
+        {
             "property": "VehicleProperty::SEAT_OCCUPANCY",
             "defaultValue": {
                 "int32Values": [
@@ -1560,6 +1629,16 @@
             "minSampleRate": 1.0
         },
         {
+            "property": "VehicleProperty::EV_BATTERY_AVERAGE_TEMPERATURE",
+            "defaultValue": {
+                "floatValues": [
+                    25.0
+                ]
+            },
+            "maxSampleRate": 2.0,
+            "minSampleRate": 1.0
+        },
+        {
             "property": "VehicleProperty::TIRE_PRESSURE",
             "defaultValue": {
                 "floatValues": [
@@ -1899,8 +1978,16 @@
                 }
             ],
             "configArray": [
+                "VehicleProperty::HVAC_ACTUAL_FAN_SPEED_RPM",
+                "VehicleProperty::HVAC_AC_ON",
+                "VehicleProperty::HVAC_AUTO_ON",
+                "VehicleProperty::HVAC_AUTO_RECIRC_ON",
+                "VehicleProperty::HVAC_FAN_DIRECTION",
                 "VehicleProperty::HVAC_FAN_SPEED",
-                "VehicleProperty::HVAC_FAN_DIRECTION"
+                "VehicleProperty::HVAC_MAX_AC_ON",
+                "VehicleProperty::HVAC_RECIRC_ON",
+                "VehicleProperty::HVAC_TEMPERATURE_CURRENT",
+                "VehicleProperty::HVAC_TEMPERATURE_SET"
             ]
         },
         {
@@ -2360,9 +2447,9 @@
                 160,
                 280,
                 5,
-                600,
-                840,
-                10
+                608,
+                824,
+                9
             ]
         },
         {
@@ -2372,7 +2459,7 @@
                     66.19999694824219,
                     "VehicleUnit::FAHRENHEIT",
                     19.0,
-                    66.0
+                    66.2
                 ]
             }
         },
@@ -2495,6 +2582,27 @@
             }
         },
         {
+            "property": "VehicleProperty::IMPACT_DETECTED",
+            "defaultValue": {
+                "int32Values": [
+                    0
+                ]
+            },
+            "areas": [
+                {
+                    "areaId": 0,
+                    "supportedEnumValues": [
+                        "ImpactSensorLocation::FRONT",
+                        "ImpactSensorLocation::FRONT_LEFT_DOOR_SIDE",
+                        "ImpactSensorLocation::FRONT_RIGHT_DOOR_SIDE",
+                        "ImpactSensorLocation::REAR_LEFT_DOOR_SIDE",
+                        "ImpactSensorLocation::REAR_RIGHT_DOOR_SIDE",
+                        "ImpactSensorLocation::REAR"
+                    ]
+                }
+            ]
+        },
+        {
             "property": "VehicleProperty::DOOR_LOCK",
             "areas": [
                 {
@@ -3103,6 +3211,27 @@
             ]
         },
         {
+            "property": "VehicleProperty::VALET_MODE_ENABLED",
+            "defaultValue": {
+                "int32Values": [
+                    0
+                ]
+            }
+        },
+        {
+            "property": "VehicleProperty::HEAD_UP_DISPLAY_ENABLED",
+            "defaultValue": {
+                "int32Values": [
+                    0
+                ]
+            },
+            "areas": [
+                {
+                    "areaId": "Constants::SEAT_1_LEFT"
+                }
+            ]
+        },
+        {
             "property": "VehicleProperty::OBD2_LIVE_FRAME",
             "configArray": [
                 0,
@@ -3387,7 +3516,7 @@
             "property": "VehicleProperty::CRUISE_CONTROL_TYPE",
             "defaultValue": {
                 "int32Values": [
-                    "CruiseControlType::STANDARD"
+                    "CruiseControlType::ADAPTIVE"
                 ]
             },
             "areas": [
@@ -3538,6 +3667,117 @@
             ]
         },
         {
+            "property": "VehicleProperty::DRIVER_DROWSINESS_ATTENTION_SYSTEM_ENABLED",
+            "defaultValue": {
+                "int32Values": [
+                    1
+                ]
+            }
+        },
+        {
+            "property": "VehicleProperty::DRIVER_DROWSINESS_ATTENTION_STATE",
+            "defaultValue": {
+                "int32Values": [
+                    "DriverDrowsinessAttentionState::KSS_RATING_3_ALERT"
+                ]
+            },
+            "areas": [
+                {
+                    "areaId": 0,
+                    "supportedEnumValues": [
+                        "ErrorState::NOT_AVAILABLE_DISABLED",
+                        "DriverDrowsinessAttentionState::KSS_RATING_1_EXTREMELY_ALERT",
+                        "DriverDrowsinessAttentionState::KSS_RATING_2_VERY_ALERT",
+                        "DriverDrowsinessAttentionState::KSS_RATING_3_ALERT",
+                        "DriverDrowsinessAttentionState::KSS_RATING_4_RATHER_ALERT",
+                        "DriverDrowsinessAttentionState::KSS_RATING_5_NEITHER_ALERT_NOR_SLEEPY",
+                        "DriverDrowsinessAttentionState::KSS_RATING_6_SOME_SLEEPINESS",
+                        "DriverDrowsinessAttentionState::KSS_RATING_7_SLEEPY_NO_EFFORT",
+                        "DriverDrowsinessAttentionState::KSS_RATING_8_SLEEPY_SOME_EFFORT",
+                        "DriverDrowsinessAttentionState::KSS_RATING_9_VERY_SLEEPY"
+                    ]
+                }
+            ]
+        },
+        {
+            "property": "VehicleProperty::DRIVER_DROWSINESS_ATTENTION_WARNING_ENABLED",
+            "defaultValue": {
+                "int32Values": [
+                    1
+                ]
+            }
+        },
+        {
+            "property": "VehicleProperty::DRIVER_DROWSINESS_ATTENTION_WARNING",
+            "defaultValue": {
+                "int32Values": [
+                    "DriverDrowsinessAttentionWarning::NO_WARNING"
+                ]
+            },
+            "areas": [
+                {
+                    "areaId": 0,
+                    "supportedEnumValues": [
+                        "ErrorState::NOT_AVAILABLE_DISABLED",
+                        "DriverDrowsinessAttentionWarning::NO_WARNING",
+                        "DriverDrowsinessAttentionWarning::WARNING"
+                    ]
+                }
+            ]
+        },
+        {
+            "property": "VehicleProperty::DRIVER_DISTRACTION_SYSTEM_ENABLED",
+            "defaultValue": {
+                "int32Values": [
+                    1
+                ]
+            }
+        },
+        {
+            "property": "VehicleProperty::DRIVER_DISTRACTION_STATE",
+            "defaultValue": {
+                "int32Values": [
+                    "DriverDistractionState::NOT_DISTRACTED"
+                ]
+            },
+            "areas": [
+                {
+                    "areaId": 0,
+                    "supportedEnumValues": [
+                        "ErrorState::NOT_AVAILABLE_DISABLED",
+                        "DriverDistractionState::NOT_DISTRACTED",
+                        "DriverDistractionState::DISTRACTED"
+                    ]
+                }
+            ]
+        },
+        {
+            "property": "VehicleProperty::DRIVER_DISTRACTION_WARNING_ENABLED",
+            "defaultValue": {
+                "int32Values": [
+                    1
+                ]
+            }
+        },
+        {
+            "property": "VehicleProperty::DRIVER_DISTRACTION_WARNING",
+            "defaultValue": {
+                "int32Values": [
+                    "DriverDistractionWarning::NO_WARNING"
+                ]
+            },
+            "areas": [
+                {
+                    "areaId": 0,
+                    "supportedEnumValues": [
+                        "ErrorState::NOT_AVAILABLE_DISABLED",
+                        "DriverDistractionWarning::NO_WARNING",
+                        "DriverDistractionWarning::WARNING"
+                    ]
+                }
+            ]
+        },
+        {
             "property": "VehicleProperty::INITIAL_USER_INFO"
         },
         {
@@ -3571,7 +3811,13 @@
             "property": "VehicleProperty::WATCHDOG_TERMINATED_PROCESS"
         },
         {
-            "property": "VehicleProperty::VHAL_HEARTBEAT"
+            "property": "VehicleProperty::VHAL_HEARTBEAT",
+            "areas": [
+                {
+                    "areaId": 0,
+                    "supportVariableUpdateRate": false
+                }
+            ]
         },
         {
             "property": "VehicleProperty::CLUSTER_SWITCH_UI",
@@ -3621,6 +3867,27 @@
             "property": "VehicleProperty::CLUSTER_NAVIGATION_STATE"
         },
         {
+            "property": "VehicleProperty::CLUSTER_HEARTBEAT",
+            "configArray": [
+                0,
+                0,
+                0,
+                0,
+                0,
+                2,
+                0,
+                0,
+                16
+            ],
+            "areas": [
+                {
+                    "areaId": 0,
+                    "supportVariableUpdateRate": false
+                }
+            ],
+            "comment": "configArray specifies it consists of int64[2] and byte[16]."
+        },
+        {
             "property": "VehicleProperty::GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT",
             "defaultValue": {
                 "int32Values": [
@@ -3629,6 +3896,25 @@
             }
         },
         {
+            "property": "VehicleProperty::SHUTDOWN_REQUEST"
+        },
+        {
+            "property": "VehicleProperty::VEHICLE_IN_USE",
+            "defaultValue": {
+                "int32Values": [
+                    1
+                ]
+            }
+        },
+        {
+            "property": "VehicleProperty::VEHICLE_DRIVING_AUTOMATION_CURRENT_LEVEL",
+            "defaultValue": {
+                "int32Values": [
+                    "VehicleAutonomousState::LEVEL_0"
+                ]
+            }
+        },
+        {
             "property": "VehicleProperty::AUTOMATIC_EMERGENCY_BRAKING_ENABLED",
             "defaultValue": {
                 "int32Values": [
@@ -3826,6 +4112,128 @@
                     ]
                 }
             ]
+        },
+        {
+            "property": "VehicleProperty::LOW_SPEED_COLLISION_WARNING_ENABLED",
+            "defaultValue": {
+                "int32Values": [
+                    1
+                ]
+            }
+        },
+        {
+            "property": "VehicleProperty::LOW_SPEED_COLLISION_WARNING_STATE",
+            "defaultValue": {
+                "int32Values": [
+                    "LowSpeedCollisionWarningState::NO_WARNING"
+                ]
+            },
+            "areas": [
+                {
+                    "areaId": 0,
+                    "supportedEnumValues": [
+                        "ErrorState::NOT_AVAILABLE_SAFETY",
+                        "ErrorState::NOT_AVAILABLE_POOR_VISIBILITY",
+                        "ErrorState::NOT_AVAILABLE_SPEED_HIGH",
+                        "ErrorState::NOT_AVAILABLE_DISABLED",
+                        "LowSpeedCollisionWarningState::NO_WARNING",
+                        "LowSpeedCollisionWarningState::WARNING"
+                    ]
+                }
+            ]
+        },
+        {
+            "property": "VehicleProperty::ELECTRONIC_STABILITY_CONTROL_ENABLED",
+            "defaultValue": {
+                "int32Values": [
+                    1
+                ]
+            }
+        },
+        {
+            "property": "VehicleProperty::ELECTRONIC_STABILITY_CONTROL_STATE",
+            "defaultValue": {
+                "int32Values": [
+                    "ElectronicStabilityControlState::ENABLED"
+                ]
+            },
+            "areas": [
+                {
+                    "areaId": 0,
+                    "supportedEnumValues": [
+                        "ErrorState::NOT_AVAILABLE_SAFETY",
+                        "ErrorState::NOT_AVAILABLE_SPEED_HIGH",
+                        "ErrorState::NOT_AVAILABLE_SPEED_LOW",
+                        "ErrorState::NOT_AVAILABLE_DISABLED",
+                        "ElectronicStabilityControlState::ENABLED",
+                        "ElectronicStabilityControlState::ACTIVATED"
+                    ]
+                }
+            ]
+        },
+        {
+            "property": "VehicleProperty::CROSS_TRAFFIC_MONITORING_ENABLED",
+            "defaultValue": {
+                "int32Values": [
+                    1
+                ]
+            }
+        },
+        {
+            "property": "VehicleProperty::CROSS_TRAFFIC_MONITORING_WARNING_STATE",
+            "defaultValue": {
+                "int32Values": [
+                    "CrossTrafficMonitoringWarningState::NO_WARNING"
+                ]
+            },
+            "areas": [
+                {
+                    "areaId": 0,
+                    "supportedEnumValues": [
+                        "ErrorState::NOT_AVAILABLE_SAFETY",
+                        "ErrorState::NOT_AVAILABLE_POOR_VISIBILITY",
+                        "ErrorState::NOT_AVAILABLE_SPEED_HIGH",
+                        "ErrorState::NOT_AVAILABLE_DISABLED",
+                        "CrossTrafficMonitoringWarningState::NO_WARNING",
+                        "CrossTrafficMonitoringWarningState::WARNING_FRONT_LEFT",
+                        "CrossTrafficMonitoringWarningState::WARNING_FRONT_RIGHT",
+                        "CrossTrafficMonitoringWarningState::WARNING_FRONT_BOTH",
+                        "CrossTrafficMonitoringWarningState::WARNING_REAR_LEFT",
+                        "CrossTrafficMonitoringWarningState::WARNING_REAR_RIGHT",
+                        "CrossTrafficMonitoringWarningState::WARNING_REAR_BOTH"
+                    ]
+                }
+            ]
+        },
+        {
+            "property": "VehicleProperty::LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_ENABLED",
+            "defaultValue": {
+                "int32Values": [
+                    1
+                ]
+            }
+        },
+        {
+            "property": "VehicleProperty::LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE",
+            "defaultValue": {
+                "int32Values": [
+                    "LowSpeedAutomaticEmergencyBrakingState::ENABLED"
+                ]
+            },
+            "areas": [
+                {
+                    "areaId": 0,
+                    "supportedEnumValues": [
+                        "ErrorState::NOT_AVAILABLE_SAFETY",
+                        "ErrorState::NOT_AVAILABLE_POOR_VISIBILITY",
+                        "ErrorState::NOT_AVAILABLE_SPEED_HIGH",
+                        "ErrorState::NOT_AVAILABLE_DISABLED",
+                        "LowSpeedAutomaticEmergencyBrakingState::ENABLED",
+                        "LowSpeedAutomaticEmergencyBrakingState::ACTIVATED",
+                        "LowSpeedAutomaticEmergencyBrakingState::USER_OVERRIDE"
+                    ]
+                }
+            ]
         }
     ]
 }
diff --git a/automotive/vehicle/aidl/impl/default_config/config/TestProperties.json b/automotive/vehicle/aidl/impl/default_config/config/TestProperties.json
index fd4b002..73e4d44 100644
--- a/automotive/vehicle/aidl/impl/default_config/config/TestProperties.json
+++ b/automotive/vehicle/aidl/impl/default_config/config/TestProperties.json
@@ -1,7 +1,7 @@
 {
     "properties": [
         {
-            "property": "Constants::kMixedTypePropertyForTest",
+            "property": "TestVendorProperty::MIXED_TYPE_PROPERTY_FOR_TEST",
             "defaultValue": {
                 "floatValues": [
                     4.5
@@ -28,7 +28,7 @@
             "changeMode": "VehiclePropertyChangeMode::ON_CHANGE"
         },
         {
-            "property": "Constants::VENDOR_EXTENSION_BOOLEAN_PROPERTY",
+            "property": "TestVendorProperty::VENDOR_EXTENSION_BOOLEAN_PROPERTY",
             "areas": [
                 {
                     "defaultValue": {
@@ -67,7 +67,7 @@
             "changeMode": "VehiclePropertyChangeMode::ON_CHANGE"
         },
         {
-            "property": "Constants::VENDOR_EXTENSION_FLOAT_PROPERTY",
+            "property": "TestVendorProperty::VENDOR_EXTENSION_FLOAT_PROPERTY",
             "areas": [
                 {
                     "defaultValue": {
@@ -94,7 +94,7 @@
             "changeMode": "VehiclePropertyChangeMode::ON_CHANGE"
         },
         {
-            "property": "Constants::VENDOR_EXTENSION_INT_PROPERTY",
+            "property": "TestVendorProperty::VENDOR_EXTENSION_INT_PROPERTY",
             "areas": [
                 {
                     "defaultValue": {
@@ -131,7 +131,7 @@
             "changeMode": "VehiclePropertyChangeMode::ON_CHANGE"
         },
         {
-            "property": "Constants::VENDOR_EXTENSION_STRING_PROPERTY",
+            "property": "TestVendorProperty::VENDOR_EXTENSION_STRING_PROPERTY",
             "defaultValue": {
                 "stringValue": "Vendor String Property"
             },
@@ -139,7 +139,7 @@
             "changeMode": "VehiclePropertyChangeMode::ON_CHANGE"
         },
         {
-            "property": "Constants::PLACEHOLDER_PROPERTY_INT",
+            "property": "TestVendorProperty::PLACEHOLDER_PROPERTY_INT",
             "defaultValue": {
                 "int32Values": [
                     0
@@ -149,7 +149,7 @@
             "changeMode": "VehiclePropertyChangeMode::ON_CHANGE"
         },
         {
-            "property": "Constants::PLACEHOLDER_PROPERTY_FLOAT",
+            "property": "TestVendorProperty::PLACEHOLDER_PROPERTY_FLOAT",
             "defaultValue": {
                 "floatValues": [
                     0.0
@@ -159,7 +159,7 @@
             "changeMode": "VehiclePropertyChangeMode::ON_CHANGE"
         },
         {
-            "property": "Constants::PLACEHOLDER_PROPERTY_BOOLEAN",
+            "property": "TestVendorProperty::PLACEHOLDER_PROPERTY_BOOLEAN",
             "defaultValue": {
                 "int32Values": [
                     0
@@ -169,7 +169,7 @@
             "changeMode": "VehiclePropertyChangeMode::ON_CHANGE"
         },
         {
-            "property": "Constants::PLACEHOLDER_PROPERTY_STRING",
+            "property": "TestVendorProperty::PLACEHOLDER_PROPERTY_STRING",
             "defaultValue": {
                 "stringValue": "Test"
             },
@@ -177,12 +177,12 @@
             "changeMode": "VehiclePropertyChangeMode::ON_CHANGE"
         },
         {
-            "property": "Constants::ECHO_REVERSE_BYTES",
+            "property": "TestVendorProperty::ECHO_REVERSE_BYTES",
             "access": "VehiclePropertyAccess::READ_WRITE",
             "changeMode": "VehiclePropertyChangeMode::ON_CHANGE"
         },
         {
-            "property": "Constants::VENDOR_PROPERTY_ID",
+            "property": "TestVendorProperty::VENDOR_PROPERTY_FOR_ERROR_CODE_TESTING",
             "access": "VehiclePropertyAccess::READ_WRITE",
             "changeMode": "VehiclePropertyChangeMode::ON_CHANGE"
         },
@@ -194,13 +194,13 @@
                 ]
             },
             "configArray": [
-                "Constants::kMixedTypePropertyForTest",
+                "TestVendorProperty::MIXED_TYPE_PROPERTY_FOR_TEST",
                 "VehicleVendorPermission::PERMISSION_GET_VENDOR_CATEGORY_INFO",
                 "VehicleVendorPermission::PERMISSION_SET_VENDOR_CATEGORY_INFO",
-                "Constants::VENDOR_EXTENSION_INT_PROPERTY",
+                "TestVendorProperty::VENDOR_EXTENSION_INT_PROPERTY",
                 "VehicleVendorPermission::PERMISSION_GET_VENDOR_CATEGORY_SEAT",
                 "VehicleVendorPermission::PERMISSION_NOT_ACCESSIBLE",
-                "Constants::VENDOR_EXTENSION_FLOAT_PROPERTY",
+                "TestVendorProperty::VENDOR_EXTENSION_FLOAT_PROPERTY",
                 "VehicleVendorPermission::PERMISSION_DEFAULT",
                 "VehicleVendorPermission::PERMISSION_DEFAULT"
             ]
diff --git a/automotive/vehicle/aidl/impl/default_config/config/VendorClusterTestProperties.json b/automotive/vehicle/aidl/impl/default_config/config/VendorClusterTestProperties.json
index 3a1a783..8c2bc93 100644
--- a/automotive/vehicle/aidl/impl/default_config/config/VendorClusterTestProperties.json
+++ b/automotive/vehicle/aidl/impl/default_config/config/VendorClusterTestProperties.json
@@ -1,17 +1,17 @@
 {
     "properties": [
         {
-            "property": "Constants::VENDOR_CLUSTER_SWITCH_UI",
+            "property": "TestVendorProperty::VENDOR_CLUSTER_SWITCH_UI",
             "access": "VehiclePropertyAccess::WRITE",
             "changeMode": "VehiclePropertyChangeMode::ON_CHANGE"
         },
         {
-            "property": "Constants::VENDOR_CLUSTER_DISPLAY_STATE",
+            "property": "TestVendorProperty::VENDOR_CLUSTER_DISPLAY_STATE",
             "access": "VehiclePropertyAccess::WRITE",
             "changeMode": "VehiclePropertyChangeMode::ON_CHANGE"
         },
         {
-            "property": "Constants::VENDOR_CLUSTER_REPORT_STATE",
+            "property": "TestVendorProperty::VENDOR_CLUSTER_REPORT_STATE",
             "defaultValue": {
                 "int32Values": [
                     0,
@@ -44,7 +44,7 @@
                     "Value means 0 /* Off */, -1, -1, -1, -1 /* Bounds */, -1, -1, -1, -1 /* Insets */, 0 /* ClusterHome */, -1 /* ClusterNone */"
         },
         {
-            "property": "Constants::VENDOR_CLUSTER_REQUEST_DISPLAY",
+            "property": "TestVendorProperty::VENDOR_CLUSTER_REQUEST_DISPLAY",
             "defaultValue": {
                 "int32Values": [
                     0
@@ -55,7 +55,7 @@
             "comment": "0 means ClusterHome"
         },
         {
-            "property": "Constants::VENDOR_CLUSTER_NAVIGATION_STATE",
+            "property": "TestVendorProperty::VENDOR_CLUSTER_NAVIGATION_STATE",
             "access": "VehiclePropertyAccess::READ",
             "changeMode": "VehiclePropertyChangeMode::ON_CHANGE"
         }
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp b/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp
index 4c17cde..e75f648 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp
@@ -21,7 +21,10 @@
 cc_library {
     name: "FakeVehicleHardware",
     vendor: true,
-    srcs: ["src/*.cpp"],
+    srcs: [
+        "src/*.cpp",
+        ":VhalTestVendorProperties",
+    ],
     local_include_dirs: ["include"],
     export_include_dirs: ["include"],
     cflags: ["-DENABLE_VEHICLE_HAL_TEST_PROPERTIES"],
@@ -35,7 +38,7 @@
     name: "FakeVehicleHardwareDefaults",
     header_libs: [
         "IVehicleHardware",
-        "VehicleHalTestUtilHeaders",
+        "libbinder_headers",
     ],
     export_header_lib_headers: ["IVehicleHardware"],
     static_libs: [
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
index c3ebd3b..1153217 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
@@ -36,6 +36,7 @@
 #include <memory>
 #include <mutex>
 #include <unordered_map>
+#include <unordered_set>
 #include <vector>
 
 namespace android {
@@ -90,21 +91,30 @@
     void registerOnPropertySetErrorEvent(
             std::unique_ptr<const PropertySetErrorCallback> callback) override;
 
-    // Update the sample rate for the [propId, areaId] pair.
-    aidl::android::hardware::automotive::vehicle::StatusCode updateSampleRate(
-            int32_t propId, int32_t areaId, float sampleRate) override;
+    // Subscribe to a new [propId, areaId] or change the update rate.
+    aidl::android::hardware::automotive::vehicle::StatusCode subscribe(
+            aidl::android::hardware::automotive::vehicle::SubscribeOptions options) override;
+
+    // Unsubscribe to a [propId, areaId].
+    aidl::android::hardware::automotive::vehicle::StatusCode unsubscribe(int32_t propId,
+                                                                         int32_t areaId) override;
 
   protected:
     // mValuePool is also used in mServerSidePropStore.
     const std::shared_ptr<VehiclePropValuePool> mValuePool;
     const std::shared_ptr<VehiclePropertyStore> mServerSidePropStore;
 
+    const std::string mDefaultConfigDir;
+    const std::string mOverrideConfigDir;
+
     ValueResultType getValue(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const;
 
     VhalResult<void> setValue(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value);
 
+    bool UseOverrideConfigDir();
+
   private:
     // Expose private methods to unit test.
     friend class FakeVehicleHardwareTestHelper;
@@ -132,6 +142,16 @@
         void handleRequestsOnce();
     };
 
+    struct RefreshInfo {
+        VehiclePropertyStore::EventMode eventMode;
+        int64_t intervalInNanos;
+    };
+
+    struct ActionForInterval {
+        std::unordered_set<PropIdAreaId, PropIdAreaIdHash> propIdAreaIdsToRefresh;
+        std::shared_ptr<RecurrentTimer::Callback> recurrentAction;
+    };
+
     const std::unique_ptr<obd2frame::FakeObd2Frame> mFakeObd2Frame;
     const std::unique_ptr<FakeUserHal> mFakeUserHal;
     // RecurrentTimer is thread-safe.
@@ -144,10 +164,12 @@
     std::unique_ptr<const PropertySetErrorCallback> mOnPropertySetErrorCallback;
 
     std::mutex mLock;
-    std::unordered_map<PropIdAreaId, std::shared_ptr<RecurrentTimer::Callback>, PropIdAreaIdHash>
-            mRecurrentActions GUARDED_BY(mLock);
+    std::unordered_map<PropIdAreaId, RefreshInfo, PropIdAreaIdHash> mRefreshInfoByPropIdAreaId
+            GUARDED_BY(mLock);
+    std::unordered_map<int64_t, ActionForInterval> mActionByIntervalInNanos GUARDED_BY(mLock);
     std::unordered_map<PropIdAreaId, VehiclePropValuePool::RecyclableType, PropIdAreaIdHash>
             mSavedProps GUARDED_BY(mLock);
+    std::unordered_set<PropIdAreaId, PropIdAreaIdHash> mSubOnChangePropIdAreaIds GUARDED_BY(mLock);
     // PendingRequestHandler is thread-safe.
     mutable PendingRequestHandler<GetValuesCallback,
                                   aidl::android::hardware::automotive::vehicle::GetValueRequest>
@@ -156,8 +178,9 @@
                                   aidl::android::hardware::automotive::vehicle::SetValueRequest>
             mPendingSetValueRequests;
 
-    const std::string mDefaultConfigDir;
-    const std::string mOverrideConfigDir;
+    // Set of HVAC properties dependent on HVAC_POWER_ON
+    std::unordered_set<int32_t> hvacPowerDependentProps;
+
     const bool mForceOverride;
     bool mAddExtraTestVendorConfigs;
 
@@ -169,7 +192,12 @@
     void storePropInitialValue(const ConfigDeclaration& config);
     // The callback that would be called when a vehicle property value change happens.
     void onValueChangeCallback(
-            const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value);
+            const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value)
+            EXCLUDES(mLock);
+    // The callback that would be called when multiple vehicle property value changes happen.
+    void onValuesChangeCallback(
+            std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue> values)
+            EXCLUDES(mLock);
     // Load the config files in format '*.json' from the directory and parse the config files
     // into a map from property ID to ConfigDeclarations.
     void loadPropConfigsFromDir(const std::string& dirPath,
@@ -189,11 +217,14 @@
     VhalResult<void> maybeSetSpecialValue(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value,
             bool* isSpecialValue);
+    VhalResult<bool> isCruiseControlTypeStandard() const;
     ValueResultType maybeGetSpecialValue(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value,
             bool* isSpecialValue) const;
     VhalResult<void> setApPowerStateReport(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value);
+    VhalResult<void> setApPowerStateReqShutdown(
+            const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value);
     VehiclePropValuePool::RecyclableType createApPowerStateReq(
             aidl::android::hardware::automotive::vehicle::VehicleApPowerStateReq state);
     VehiclePropValuePool::RecyclableType createAdasStateReq(int32_t propertyId, int32_t areaId,
@@ -206,6 +237,9 @@
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const;
     bool isHvacPropAndHvacNotAvailable(int32_t propId, int32_t areaId) const;
     VhalResult<void> isAdasPropertyAvailable(int32_t adasStatePropertyId) const;
+    VhalResult<void> synchronizeHvacTemp(int32_t hvacDualOnAreaId,
+                                         std::optional<float> newTempC) const;
+    std::optional<int32_t> getSyncedAreaIdIfHvacDualOn(int32_t hvacTemperatureSetAreaId) const;
 
     std::unordered_map<int32_t, ConfigDeclaration> loadConfigDeclarations();
 
@@ -222,6 +256,7 @@
     std::string dumpSaveProperty(const std::vector<std::string>& options);
     std::string dumpRestoreProperty(const std::vector<std::string>& options);
     std::string dumpInjectEvent(const std::vector<std::string>& options);
+    std::string dumpSubscriptions();
 
     template <typename T>
     android::base::Result<T> safelyParseInt(int index, const std::string& s) {
@@ -247,11 +282,21 @@
             const aidl::android::hardware::automotive::vehicle::SetValueRequest& request);
 
     std::string genFakeDataCommand(const std::vector<std::string>& options);
-    void sendHvacPropertiesCurrentValues(int32_t areaId);
+    void sendHvacPropertiesCurrentValues(int32_t areaId, int32_t hvacPowerOnVal);
     void sendAdasPropertiesState(int32_t propertyId, int32_t state);
     void generateVendorConfigs(
             std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropConfig>&) const;
 
+    aidl::android::hardware::automotive::vehicle::StatusCode subscribePropIdAreaIdLocked(
+            int32_t propId, int32_t areaId, float sampleRateHz, bool enableVariableUpdateRate,
+            const aidl::android::hardware::automotive::vehicle::VehiclePropConfig&
+                    vehiclePropConfig) REQUIRES(mLock);
+
+    void registerRefreshLocked(PropIdAreaId propIdAreaId, VehiclePropertyStore::EventMode eventMode,
+                               float sampleRateHz) REQUIRES(mLock);
+    void unregisterRefreshLocked(PropIdAreaId propIdAreaId) REQUIRES(mLock);
+    void refreshTimestampForInterval(int64_t intervalInNanos) EXCLUDES(mLock);
+
     static aidl::android::hardware::automotive::vehicle::VehiclePropValue createHwInputKeyProp(
             aidl::android::hardware::automotive::vehicle::VehicleHwKeyInputAction action,
             int32_t keyCode, int32_t targetDisplay);
@@ -265,6 +310,10 @@
 
     static std::string genFakeDataHelp();
     static std::string parseErrMsg(std::string fieldName, std::string value, std::string type);
+    static bool isVariableUpdateRateSupported(
+            const aidl::android::hardware::automotive::vehicle::VehiclePropConfig&
+                    vehiclePropConfig,
+            int32_t areaId);
 };
 
 }  // namespace fake
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
index b5b325c..bcc765c 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
@@ -24,7 +24,6 @@
 #include <JsonFakeValueGenerator.h>
 #include <LinearFakeValueGenerator.h>
 #include <PropertyUtils.h>
-#include <TestPropertyUtils.h>
 #include <VehicleHalTypes.h>
 #include <VehicleUtils.h>
 
@@ -32,6 +31,7 @@
 #include <android-base/parsedouble.h>
 #include <android-base/properties.h>
 #include <android-base/strings.h>
+#include <android/hardware/automotive/vehicle/TestVendorProperty.h>
 #include <utils/Log.h>
 #include <utils/SystemClock.h>
 #include <utils/Trace.h>
@@ -39,7 +39,6 @@
 #include <dirent.h>
 #include <inttypes.h>
 #include <sys/types.h>
-#include <fstream>
 #include <regex>
 #include <unordered_set>
 #include <vector>
@@ -52,6 +51,14 @@
 
 namespace {
 
+#define PROP_ID_TO_CSTR(A) (propIdToString(A).c_str())
+
+using ::aidl::android::hardware::automotive::vehicle::CruiseControlCommand;
+using ::aidl::android::hardware::automotive::vehicle::CruiseControlType;
+using ::aidl::android::hardware::automotive::vehicle::DriverDistractionState;
+using ::aidl::android::hardware::automotive::vehicle::DriverDistractionWarning;
+using ::aidl::android::hardware::automotive::vehicle::DriverDrowsinessAttentionState;
+using ::aidl::android::hardware::automotive::vehicle::DriverDrowsinessAttentionWarning;
 using ::aidl::android::hardware::automotive::vehicle::ErrorState;
 using ::aidl::android::hardware::automotive::vehicle::GetValueRequest;
 using ::aidl::android::hardware::automotive::vehicle::GetValueResult;
@@ -59,12 +66,16 @@
 using ::aidl::android::hardware::automotive::vehicle::SetValueRequest;
 using ::aidl::android::hardware::automotive::vehicle::SetValueResult;
 using ::aidl::android::hardware::automotive::vehicle::StatusCode;
+using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions;
+using ::aidl::android::hardware::automotive::vehicle::toString;
 using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateReport;
 using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateReq;
+using ::aidl::android::hardware::automotive::vehicle::VehicleArea;
 using ::aidl::android::hardware::automotive::vehicle::VehicleHwKeyInputAction;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
 using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyAccess;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyChangeMode;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyGroup;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyStatus;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyType;
@@ -85,14 +96,12 @@
 //  getPropertiesAsync, and setPropertiesAsync.
 // 0x21403000
 constexpr int32_t STARTING_VENDOR_CODE_PROPERTIES_FOR_TEST =
-        0x3000 | toInt(testpropertyutils_impl::VehiclePropertyGroup::VENDOR) |
-        toInt(testpropertyutils_impl::VehicleArea::GLOBAL) |
-        toInt(testpropertyutils_impl::VehiclePropertyType::INT32);
+        0x3000 | toInt(VehiclePropertyGroup::VENDOR) | toInt(VehicleArea::GLOBAL) |
+        toInt(VehiclePropertyType::INT32);
 // 0x21405000
 constexpr int32_t ENDING_VENDOR_CODE_PROPERTIES_FOR_TEST =
-        0x5000 | toInt(testpropertyutils_impl::VehiclePropertyGroup::VENDOR) |
-        toInt(testpropertyutils_impl::VehicleArea::GLOBAL) |
-        toInt(testpropertyutils_impl::VehiclePropertyType::INT32);
+        0x5000 | toInt(VehiclePropertyGroup::VENDOR) | toInt(VehicleArea::GLOBAL) |
+        toInt(VehiclePropertyType::INT32);
 // The directory for default property configuration file.
 // For config file format, see impl/default_config/config/README.md.
 constexpr char DEFAULT_CONFIG_DIR[] = "/vendor/etc/automotive/vhalconfig/";
@@ -103,7 +112,7 @@
 // overwrite the default configs.
 constexpr char OVERRIDE_PROPERTY[] = "persist.vendor.vhal_init_value_override";
 constexpr char POWER_STATE_REQ_CONFIG_PROPERTY[] = "ro.vendor.fake_vhal.ap_power_state_req.config";
-// The value to be returned if VENDOR_PROPERTY_ID is set as the property
+// The value to be returned if VENDOR_PROPERTY_FOR_ERROR_CODE_TESTING is set as the property
 constexpr int VENDOR_ERROR_CODE = 0x00ab0005;
 // A list of supported options for "--set" command.
 const std::unordered_set<std::string> SET_PROP_OPTIONS = {
@@ -189,6 +198,63 @@
                         toInt(VehicleProperty::HANDS_ON_DETECTION_WARNING),
                 },
         },
+        // Driver Drowsiness and Attention
+        {
+                toInt(VehicleProperty::DRIVER_DROWSINESS_ATTENTION_SYSTEM_ENABLED),
+                {
+                        toInt(VehicleProperty::DRIVER_DROWSINESS_ATTENTION_STATE),
+                },
+        },
+        // Driver Drowsiness and Attention Warning
+        {
+                toInt(VehicleProperty::DRIVER_DROWSINESS_ATTENTION_WARNING_ENABLED),
+                {
+                        toInt(VehicleProperty::DRIVER_DROWSINESS_ATTENTION_WARNING),
+                },
+        },
+        // Driver Distraction
+        {
+                toInt(VehicleProperty::DRIVER_DISTRACTION_SYSTEM_ENABLED),
+                {
+                        toInt(VehicleProperty::DRIVER_DISTRACTION_STATE),
+                        toInt(VehicleProperty::DRIVER_DISTRACTION_WARNING),
+                },
+        },
+        // Driver Distraction Warning
+        {
+                toInt(VehicleProperty::DRIVER_DISTRACTION_WARNING_ENABLED),
+                {
+                        toInt(VehicleProperty::DRIVER_DISTRACTION_WARNING),
+                },
+        },
+        // LSCW
+        {
+                toInt(VehicleProperty::LOW_SPEED_COLLISION_WARNING_ENABLED),
+                {
+                        toInt(VehicleProperty::LOW_SPEED_COLLISION_WARNING_STATE),
+                },
+        },
+        // ESC
+        {
+                toInt(VehicleProperty::ELECTRONIC_STABILITY_CONTROL_ENABLED),
+                {
+                        toInt(VehicleProperty::ELECTRONIC_STABILITY_CONTROL_STATE),
+                },
+        },
+        // CTMW
+        {
+                toInt(VehicleProperty::CROSS_TRAFFIC_MONITORING_ENABLED),
+                {
+                        toInt(VehicleProperty::CROSS_TRAFFIC_MONITORING_WARNING_STATE),
+                },
+        },
+        // LSAEB
+        {
+                toInt(VehicleProperty::LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_ENABLED),
+                {
+                        toInt(VehicleProperty::LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE),
+                },
+        },
 };
 }  // namespace
 
@@ -200,14 +266,20 @@
     bool globalProp = isGlobalProp(propId);
     size_t numAreas = globalProp ? 1 : vehiclePropConfig.areaConfigs.size();
 
+    if (propId == toInt(VehicleProperty::HVAC_POWER_ON)) {
+        const auto& configArray = vehiclePropConfig.configArray;
+        hvacPowerDependentProps.insert(configArray.begin(), configArray.end());
+    }
+
     for (size_t i = 0; i < numAreas; i++) {
         int32_t curArea = globalProp ? 0 : vehiclePropConfig.areaConfigs[i].areaId;
 
         // Create a separate instance for each individual zone
         VehiclePropValue prop = {
+                .timestamp = elapsedRealtimeNano(),
                 .areaId = curArea,
                 .prop = propId,
-                .timestamp = elapsedRealtimeNano(),
+                .value = {},
         };
 
         if (config.initialAreaValues.empty()) {
@@ -240,6 +312,8 @@
                                          std::string overrideConfigDir, bool forceOverride)
     : mValuePool(std::make_unique<VehiclePropValuePool>()),
       mServerSidePropStore(new VehiclePropertyStore(mValuePool)),
+      mDefaultConfigDir(defaultConfigDir),
+      mOverrideConfigDir(overrideConfigDir),
       mFakeObd2Frame(new obd2frame::FakeObd2Frame(mServerSidePropStore)),
       mFakeUserHal(new FakeUserHal(mValuePool)),
       mRecurrentTimer(new RecurrentTimer()),
@@ -247,8 +321,6 @@
               [this](const VehiclePropValue& value) { eventFromVehicleBus(value); })),
       mPendingGetValueRequests(this),
       mPendingSetValueRequests(this),
-      mDefaultConfigDir(defaultConfigDir),
-      mOverrideConfigDir(overrideConfigDir),
       mForceOverride(forceOverride) {
     init();
 }
@@ -259,11 +331,15 @@
     mGeneratorHub.reset();
 }
 
+bool FakeVehicleHardware::UseOverrideConfigDir() {
+    return mForceOverride ||
+           android::base::GetBoolProperty(OVERRIDE_PROPERTY, /*default_value=*/false);
+}
+
 std::unordered_map<int32_t, ConfigDeclaration> FakeVehicleHardware::loadConfigDeclarations() {
     std::unordered_map<int32_t, ConfigDeclaration> configsByPropId;
     loadPropConfigsFromDir(mDefaultConfigDir, &configsByPropId);
-    if (mForceOverride ||
-        android::base::GetBoolProperty(OVERRIDE_PROPERTY, /*default_value=*/false)) {
+    if (UseOverrideConfigDir()) {
         loadPropConfigsFromDir(mOverrideConfigDir, &configsByPropId);
     }
     return configsByPropId;
@@ -291,17 +367,18 @@
     }
 
     // OBD2_LIVE_FRAME and OBD2_FREEZE_FRAME must be configured in default configs.
-    auto maybeObd2LiveFrame = mServerSidePropStore->getConfig(OBD2_LIVE_FRAME);
+    auto maybeObd2LiveFrame = mServerSidePropStore->getPropConfig(OBD2_LIVE_FRAME);
     if (maybeObd2LiveFrame.has_value()) {
-        mFakeObd2Frame->initObd2LiveFrame(*maybeObd2LiveFrame.value());
+        mFakeObd2Frame->initObd2LiveFrame(maybeObd2LiveFrame.value());
     }
-    auto maybeObd2FreezeFrame = mServerSidePropStore->getConfig(OBD2_FREEZE_FRAME);
+    auto maybeObd2FreezeFrame = mServerSidePropStore->getPropConfig(OBD2_FREEZE_FRAME);
     if (maybeObd2FreezeFrame.has_value()) {
-        mFakeObd2Frame->initObd2FreezeFrame(*maybeObd2FreezeFrame.value());
+        mFakeObd2Frame->initObd2FreezeFrame(maybeObd2FreezeFrame.value());
     }
 
-    mServerSidePropStore->setOnValueChangeCallback(
-            [this](const VehiclePropValue& value) { return onValueChangeCallback(value); });
+    mServerSidePropStore->setOnValuesChangeCallback([this](std::vector<VehiclePropValue> values) {
+        return onValuesChangeCallback(std::move(values));
+    });
 }
 
 std::vector<VehiclePropConfig> FakeVehicleHardware::getAllPropertyConfigs() const {
@@ -337,6 +414,25 @@
     return req;
 }
 
+VhalResult<void> FakeVehicleHardware::setApPowerStateReqShutdown(const VehiclePropValue& value) {
+    if (value.value.int32Values.size() != 1) {
+        return StatusError(StatusCode::INVALID_ARG)
+               << "Failed to set SHUTDOWN_REQUEST, expect 1 int value: "
+               << "VehicleApPowerStateShutdownParam";
+    }
+    int powerStateShutdownParam = value.value.int32Values[0];
+    auto prop = createApPowerStateReq(VehicleApPowerStateReq::SHUTDOWN_PREPARE);
+    prop->value.int32Values[1] = powerStateShutdownParam;
+    if (auto writeResult = mServerSidePropStore->writeValue(
+                std::move(prop), /*updateStatus=*/true, VehiclePropertyStore::EventMode::ALWAYS);
+        !writeResult.ok()) {
+        return StatusError(getErrorCode(writeResult))
+               << "failed to write AP_POWER_STATE_REQ into property store, error: "
+               << getErrorMsg(writeResult);
+    }
+    return {};
+}
+
 VhalResult<void> FakeVehicleHardware::setApPowerStateReport(const VehiclePropValue& value) {
     auto updatedValue = mValuePool->obtain(value);
     updatedValue->timestamp = elapsedRealtimeNano();
@@ -402,7 +498,7 @@
                                                   int increment) {
     requestedTemp = std::max(requestedTemp, minTemp);
     requestedTemp = std::min(requestedTemp, maxTemp);
-    int numIncrements = (requestedTemp - minTemp) / increment;
+    int numIncrements = std::round((requestedTemp - minTemp) / static_cast<float>(increment));
     return numIncrements;
 }
 
@@ -440,7 +536,7 @@
 VhalResult<void> FakeVehicleHardware::setHvacTemperatureValueSuggestion(
         const VehiclePropValue& hvacTemperatureValueSuggestion) {
     auto hvacTemperatureSetConfigResult =
-            mServerSidePropStore->getConfig(toInt(VehicleProperty::HVAC_TEMPERATURE_SET));
+            mServerSidePropStore->getPropConfig(toInt(VehicleProperty::HVAC_TEMPERATURE_SET));
 
     if (!hvacTemperatureSetConfigResult.ok()) {
         return StatusError(getErrorCode(hvacTemperatureSetConfigResult)) << StringPrintf(
@@ -467,7 +563,7 @@
     }
 
     auto updatedValue = mValuePool->obtain(hvacTemperatureValueSuggestion);
-    const auto& hvacTemperatureSetConfigArray = hvacTemperatureSetConfigResult.value()->configArray;
+    const auto& hvacTemperatureSetConfigArray = hvacTemperatureSetConfigResult.value().configArray;
     auto& hvacTemperatureValueSuggestionInput = updatedValue->value.floatValues;
 
     updateHvacTemperatureValueSuggestionInput(hvacTemperatureSetConfigArray,
@@ -487,9 +583,7 @@
 }
 
 bool FakeVehicleHardware::isHvacPropAndHvacNotAvailable(int32_t propId, int32_t areaId) const {
-    std::unordered_set<int32_t> powerProps(std::begin(HVAC_POWER_PROPERTIES),
-                                           std::end(HVAC_POWER_PROPERTIES));
-    if (powerProps.count(propId)) {
+    if (hvacPowerDependentProps.count(propId)) {
         auto hvacPowerOnResults =
                 mServerSidePropStore->readValuesForProperty(toInt(VehicleProperty::HVAC_POWER_ON));
         if (!hvacPowerOnResults.ok()) {
@@ -571,10 +665,69 @@
     return {};
 }
 
+VhalResult<void> FakeVehicleHardware::synchronizeHvacTemp(int32_t hvacDualOnAreaId,
+                                                          std::optional<float> newTempC) const {
+    auto hvacTemperatureSetResults = mServerSidePropStore->readValuesForProperty(
+            toInt(VehicleProperty::HVAC_TEMPERATURE_SET));
+    if (!hvacTemperatureSetResults.ok()) {
+        return StatusError(StatusCode::NOT_AVAILABLE)
+               << "Failed to get HVAC_TEMPERATURE_SET, error: "
+               << getErrorMsg(hvacTemperatureSetResults);
+    }
+    auto& hvacTemperatureSetValues = hvacTemperatureSetResults.value();
+    std::optional<float> tempCToSynchronize = newTempC;
+    for (size_t i = 0; i < hvacTemperatureSetValues.size(); i++) {
+        int32_t areaId = hvacTemperatureSetValues[i]->areaId;
+        if ((hvacDualOnAreaId & areaId) != areaId) {
+            continue;
+        }
+        if (hvacTemperatureSetValues[i]->status != VehiclePropertyStatus::AVAILABLE) {
+            continue;
+        }
+        // When HVAC_DUAL_ON is initially enabled, synchronize all area IDs
+        // to the temperature of the first area ID, which is the driver's.
+        if (!tempCToSynchronize.has_value()) {
+            tempCToSynchronize = hvacTemperatureSetValues[i]->value.floatValues[0];
+            continue;
+        }
+        auto updatedValue = std::move(hvacTemperatureSetValues[i]);
+        updatedValue->value.floatValues[0] = tempCToSynchronize.value();
+        updatedValue->timestamp = elapsedRealtimeNano();
+        // This will trigger a property change event for the current hvac property value.
+        auto writeResult =
+                mServerSidePropStore->writeValue(std::move(updatedValue), /*updateStatus=*/true,
+                                                 VehiclePropertyStore::EventMode::ALWAYS);
+        if (!writeResult.ok()) {
+            return StatusError(getErrorCode(writeResult))
+                   << "Failed to write value into property store, error: "
+                   << getErrorMsg(writeResult);
+        }
+    }
+    return {};
+}
+
+std::optional<int32_t> FakeVehicleHardware::getSyncedAreaIdIfHvacDualOn(
+        int32_t hvacTemperatureSetAreaId) const {
+    auto hvacDualOnResults =
+            mServerSidePropStore->readValuesForProperty(toInt(VehicleProperty::HVAC_DUAL_ON));
+    if (!hvacDualOnResults.ok()) {
+        return std::nullopt;
+    }
+    auto& hvacDualOnValues = hvacDualOnResults.value();
+    for (size_t i = 0; i < hvacDualOnValues.size(); i++) {
+        if ((hvacDualOnValues[i]->areaId & hvacTemperatureSetAreaId) == hvacTemperatureSetAreaId &&
+            hvacDualOnValues[i]->value.int32Values.size() == 1 &&
+            hvacDualOnValues[i]->value.int32Values[0] == 1) {
+            return hvacDualOnValues[i]->areaId;
+        }
+    }
+    return std::nullopt;
+}
+
 FakeVehicleHardware::ValueResultType FakeVehicleHardware::getUserHalProp(
         const VehiclePropValue& value) const {
     auto propId = value.prop;
-    ALOGI("get(): getting value for prop %d from User HAL", propId);
+    ALOGI("get(): getting value for prop %s from User HAL", PROP_ID_TO_CSTR(propId));
 
     auto result = mFakeUserHal->onGetProperty(value);
     if (!result.ok()) {
@@ -592,6 +745,18 @@
     }
 }
 
+VhalResult<bool> FakeVehicleHardware::isCruiseControlTypeStandard() const {
+    auto isCruiseControlTypeAvailableResult =
+            isAdasPropertyAvailable(toInt(VehicleProperty::CRUISE_CONTROL_TYPE));
+    if (!isCruiseControlTypeAvailableResult.ok()) {
+        return isCruiseControlTypeAvailableResult.error();
+    }
+    auto cruiseControlTypeValue =
+            mServerSidePropStore->readValue(toInt(VehicleProperty::CRUISE_CONTROL_TYPE));
+    return cruiseControlTypeValue.value()->value.int32Values[0] ==
+           toInt(CruiseControlType::STANDARD);
+}
+
 FakeVehicleHardware::ValueResultType FakeVehicleHardware::maybeGetSpecialValue(
         const VehiclePropValue& value, bool* isSpecialValue) const {
     *isSpecialValue = false;
@@ -619,6 +784,7 @@
         return StatusError(StatusCode::NOT_AVAILABLE_DISABLED) << "hvac not available";
     }
 
+    VhalResult<void> isAdasPropertyAvailableResult;
     switch (propId) {
         case OBD2_FREEZE_FRAME:
             *isSpecialValue = true;
@@ -634,24 +800,41 @@
                 result.value()->timestamp = elapsedRealtimeNano();
             }
             return result;
-        case ECHO_REVERSE_BYTES:
+        case toInt(TestVendorProperty::ECHO_REVERSE_BYTES):
             *isSpecialValue = true;
             return getEchoReverseBytes(value);
-        case VENDOR_PROPERTY_ID:
+        case toInt(TestVendorProperty::VENDOR_PROPERTY_FOR_ERROR_CODE_TESTING):
             *isSpecialValue = true;
             return StatusError((StatusCode)VENDOR_ERROR_CODE);
         case toInt(VehicleProperty::CRUISE_CONTROL_TARGET_SPEED):
-            [[fallthrough]];
-        case toInt(VehicleProperty::ADAPTIVE_CRUISE_CONTROL_TARGET_TIME_GAP):
-            [[fallthrough]];
-        case toInt(VehicleProperty::ADAPTIVE_CRUISE_CONTROL_LEAD_VEHICLE_MEASURED_DISTANCE): {
-            auto isAdasPropertyAvailableResult =
+            isAdasPropertyAvailableResult =
                     isAdasPropertyAvailable(toInt(VehicleProperty::CRUISE_CONTROL_STATE));
             if (!isAdasPropertyAvailableResult.ok()) {
                 *isSpecialValue = true;
                 return isAdasPropertyAvailableResult.error();
             }
             return nullptr;
+        case toInt(VehicleProperty::ADAPTIVE_CRUISE_CONTROL_TARGET_TIME_GAP):
+            [[fallthrough]];
+        case toInt(VehicleProperty::ADAPTIVE_CRUISE_CONTROL_LEAD_VEHICLE_MEASURED_DISTANCE): {
+            isAdasPropertyAvailableResult =
+                    isAdasPropertyAvailable(toInt(VehicleProperty::CRUISE_CONTROL_STATE));
+            if (!isAdasPropertyAvailableResult.ok()) {
+                *isSpecialValue = true;
+                return isAdasPropertyAvailableResult.error();
+            }
+            auto isCruiseControlTypeStandardResult = isCruiseControlTypeStandard();
+            if (!isCruiseControlTypeStandardResult.ok()) {
+                *isSpecialValue = true;
+                return isCruiseControlTypeStandardResult.error();
+            }
+            if (isCruiseControlTypeStandardResult.value()) {
+                *isSpecialValue = true;
+                return StatusError(StatusCode::NOT_AVAILABLE_DISABLED)
+                       << "tried to get target time gap or lead vehicle measured distance value "
+                       << "while on a standard CC setting";
+            }
+            return nullptr;
         }
         default:
             // Do nothing.
@@ -677,9 +860,8 @@
     return std::move(gotValue);
 }
 
-void FakeVehicleHardware::sendHvacPropertiesCurrentValues(int32_t areaId) {
-    for (size_t i = 0; i < sizeof(HVAC_POWER_PROPERTIES) / sizeof(int32_t); i++) {
-        int powerPropId = HVAC_POWER_PROPERTIES[i];
+void FakeVehicleHardware::sendHvacPropertiesCurrentValues(int32_t areaId, int32_t hvacPowerOnVal) {
+    for (auto& powerPropId : hvacPowerDependentProps) {
         auto powerPropResults = mServerSidePropStore->readValuesForProperty(powerPropId);
         if (!powerPropResults.ok()) {
             ALOGW("failed to get power prop 0x%x, error: %s", powerPropId,
@@ -690,7 +872,8 @@
         for (size_t j = 0; j < powerPropValues.size(); j++) {
             auto powerPropValue = std::move(powerPropValues[j]);
             if ((powerPropValue->areaId & areaId) == powerPropValue->areaId) {
-                powerPropValue->status = VehiclePropertyStatus::AVAILABLE;
+                powerPropValue->status = hvacPowerOnVal ? VehiclePropertyStatus::AVAILABLE
+                                                        : VehiclePropertyStatus::UNAVAILABLE;
                 powerPropValue->timestamp = elapsedRealtimeNano();
                 // This will trigger a property change event for the current hvac property value.
                 mServerSidePropStore->writeValue(std::move(powerPropValue), /*updateStatus=*/true,
@@ -703,15 +886,21 @@
 void FakeVehicleHardware::sendAdasPropertiesState(int32_t propertyId, int32_t state) {
     auto& adasDependentPropIds = mAdasEnabledPropToAdasPropWithErrorState.find(propertyId)->second;
     for (auto dependentPropId : adasDependentPropIds) {
-        auto dependentPropConfigResult = mServerSidePropStore->getConfig(dependentPropId);
+        auto dependentPropConfigResult = mServerSidePropStore->getPropConfig(dependentPropId);
         if (!dependentPropConfigResult.ok()) {
             ALOGW("Failed to get config for ADAS property 0x%x, error: %s", dependentPropId,
                   getErrorMsg(dependentPropConfigResult).c_str());
             continue;
         }
         auto& dependentPropConfig = dependentPropConfigResult.value();
-        for (auto& areaConfig : dependentPropConfig->areaConfigs) {
-            auto propValue = createAdasStateReq(dependentPropId, areaConfig.areaId, state);
+        for (auto& areaConfig : dependentPropConfig.areaConfigs) {
+            int32_t hardcoded_state = state;
+            // TODO: restore old/initial values here instead of hardcoded value (b/295542701)
+            if (state == 1 && dependentPropId == toInt(VehicleProperty::CRUISE_CONTROL_TYPE)) {
+                hardcoded_state = toInt(CruiseControlType::ADAPTIVE);
+            }
+            auto propValue =
+                    createAdasStateReq(dependentPropId, areaConfig.areaId, hardcoded_state);
             // This will trigger a property change event for the current ADAS property value.
             mServerSidePropStore->writeValue(std::move(propValue), /*updateStatus=*/true,
                                              VehiclePropertyStore::EventMode::ALWAYS);
@@ -736,13 +925,6 @@
         return setUserHalProp(value);
     }
 
-    if (propId == toInt(VehicleProperty::HVAC_POWER_ON) && value.value.int32Values.size() == 1 &&
-        value.value.int32Values[0] == 1) {
-        // If we are turning HVAC power on, send current hvac property values through on change
-        // event.
-        sendHvacPropertiesCurrentValues(value.areaId);
-    }
-
     if (isHvacPropAndHvacNotAvailable(propId, value.areaId)) {
         *isSpecialValue = true;
         return StatusError(StatusCode::NOT_AVAILABLE_DISABLED) << "hvac not available";
@@ -758,10 +940,18 @@
         }
     }
 
+    VhalResult<void> isAdasPropertyAvailableResult;
+    VhalResult<bool> isCruiseControlTypeStandardResult;
     switch (propId) {
         case toInt(VehicleProperty::AP_POWER_STATE_REPORT):
             *isSpecialValue = true;
             return setApPowerStateReport(value);
+        case toInt(VehicleProperty::SHUTDOWN_REQUEST):
+            // If we receive SHUTDOWN_REQUEST, we should send this to an external component which
+            // should shutdown Android system via sending an AP_POWER_STATE_REQ event. Here we have
+            // no external components to notify, so we just send the event.
+            *isSpecialValue = true;
+            return setApPowerStateReqShutdown(value);
         case toInt(VehicleProperty::VEHICLE_MAP_SERVICE):
             // Placeholder for future implementation of VMS property in the default hal. For
             // now, just returns OK; otherwise, hal clients crash with property not supported.
@@ -770,14 +960,46 @@
         case OBD2_FREEZE_FRAME_CLEAR:
             *isSpecialValue = true;
             return mFakeObd2Frame->clearObd2FreezeFrames(value);
-        case VENDOR_PROPERTY_ID:
+        case toInt(TestVendorProperty::VENDOR_PROPERTY_FOR_ERROR_CODE_TESTING):
             *isSpecialValue = true;
             return StatusError((StatusCode)VENDOR_ERROR_CODE);
+        case toInt(VehicleProperty::HVAC_POWER_ON):
+            if (value.value.int32Values.size() != 1) {
+                *isSpecialValue = true;
+                return StatusError(StatusCode::INVALID_ARG)
+                       << "HVAC_POWER_ON requires only one int32 value";
+            }
+            // When changing HVAC power state, send current hvac property values
+            // through on change event.
+            sendHvacPropertiesCurrentValues(value.areaId, value.value.int32Values[0]);
+            return {};
         case toInt(VehicleProperty::HVAC_TEMPERATURE_VALUE_SUGGESTION):
             *isSpecialValue = true;
             return setHvacTemperatureValueSuggestion(value);
+        case toInt(VehicleProperty::HVAC_TEMPERATURE_SET):
+            if (value.value.floatValues.size() != 1) {
+                *isSpecialValue = true;
+                return StatusError(StatusCode::INVALID_ARG)
+                       << "HVAC_DUAL_ON requires only one float value";
+            }
+            if (auto hvacDualOnAreaId = getSyncedAreaIdIfHvacDualOn(value.areaId);
+                hvacDualOnAreaId.has_value()) {
+                *isSpecialValue = true;
+                return synchronizeHvacTemp(hvacDualOnAreaId.value(), value.value.floatValues[0]);
+            }
+            return {};
+        case toInt(VehicleProperty::HVAC_DUAL_ON):
+            if (value.value.int32Values.size() != 1) {
+                *isSpecialValue = true;
+                return StatusError(StatusCode::INVALID_ARG)
+                       << "HVAC_DUAL_ON requires only one int32 value";
+            }
+            if (value.value.int32Values[0] == 1) {
+                synchronizeHvacTemp(value.areaId, std::nullopt);
+            }
+            return {};
         case toInt(VehicleProperty::LANE_CENTERING_ASSIST_COMMAND): {
-            auto isAdasPropertyAvailableResult =
+            isAdasPropertyAvailableResult =
                     isAdasPropertyAvailable(toInt(VehicleProperty::LANE_CENTERING_ASSIST_STATE));
             if (!isAdasPropertyAvailableResult.ok()) {
                 *isSpecialValue = true;
@@ -785,14 +1007,47 @@
             return isAdasPropertyAvailableResult;
         }
         case toInt(VehicleProperty::CRUISE_CONTROL_COMMAND):
-            [[fallthrough]];
-        case toInt(VehicleProperty::ADAPTIVE_CRUISE_CONTROL_TARGET_TIME_GAP): {
-            auto isAdasPropertyAvailableResult =
+            isAdasPropertyAvailableResult =
                     isAdasPropertyAvailable(toInt(VehicleProperty::CRUISE_CONTROL_STATE));
             if (!isAdasPropertyAvailableResult.ok()) {
                 *isSpecialValue = true;
+                return isAdasPropertyAvailableResult;
             }
-            return isAdasPropertyAvailableResult;
+            isCruiseControlTypeStandardResult = isCruiseControlTypeStandard();
+            if (!isCruiseControlTypeStandardResult.ok()) {
+                *isSpecialValue = true;
+                return isCruiseControlTypeStandardResult.error();
+            }
+            if (isCruiseControlTypeStandardResult.value() &&
+                (value.value.int32Values[0] ==
+                         toInt(CruiseControlCommand::INCREASE_TARGET_TIME_GAP) ||
+                 value.value.int32Values[0] ==
+                         toInt(CruiseControlCommand::DECREASE_TARGET_TIME_GAP))) {
+                *isSpecialValue = true;
+                return StatusError(StatusCode::NOT_AVAILABLE_DISABLED)
+                       << "tried to use a change target time gap command while on a standard CC "
+                       << "setting";
+            }
+            return {};
+        case toInt(VehicleProperty::ADAPTIVE_CRUISE_CONTROL_TARGET_TIME_GAP): {
+            isAdasPropertyAvailableResult =
+                    isAdasPropertyAvailable(toInt(VehicleProperty::CRUISE_CONTROL_STATE));
+            if (!isAdasPropertyAvailableResult.ok()) {
+                *isSpecialValue = true;
+                return isAdasPropertyAvailableResult;
+            }
+            isCruiseControlTypeStandardResult = isCruiseControlTypeStandard();
+            if (!isCruiseControlTypeStandardResult.ok()) {
+                *isSpecialValue = true;
+                return isCruiseControlTypeStandardResult.error();
+            }
+            if (isCruiseControlTypeStandardResult.value()) {
+                *isSpecialValue = true;
+                return StatusError(StatusCode::NOT_AVAILABLE_DISABLED)
+                       << "tried to set target time gap or lead vehicle measured distance value "
+                       << "while on a standard CC setting";
+            }
+            return {};
         }
 
 #ifdef ENABLE_VEHICLE_HAL_TEST_PROPERTIES
@@ -802,9 +1057,9 @@
             [[fallthrough]];
         case toInt(VehicleProperty::CLUSTER_NAVIGATION_STATE):
             [[fallthrough]];
-        case VENDOR_CLUSTER_SWITCH_UI:
+        case toInt(TestVendorProperty::VENDOR_CLUSTER_SWITCH_UI):
             [[fallthrough]];
-        case VENDOR_CLUSTER_DISPLAY_STATE:
+        case toInt(TestVendorProperty::VENDOR_CLUSTER_DISPLAY_STATE):
             *isSpecialValue = true;
             updatedValue = mValuePool->obtain(getPropType(value.prop));
             updatedValue->prop = value.prop & ~toInt(VehiclePropertyGroup::MASK);
@@ -835,7 +1090,7 @@
                                           const std::vector<SetValueRequest>& requests) {
     for (auto& request : requests) {
         if (FAKE_VEHICLEHARDWARE_DEBUG) {
-            ALOGD("Set value for property ID: %d", request.value.prop);
+            ALOGD("Set value for property ID: %s", PROP_ID_TO_CSTR(request.value.prop));
         }
 
         // In a real VHAL implementation, you could either send the setValue request to vehicle bus
@@ -856,18 +1111,19 @@
     auto setSpecialValueResult = maybeSetSpecialValue(value, &isSpecialValue);
     if (isSpecialValue) {
         if (!setSpecialValueResult.ok()) {
-            return StatusError(getErrorCode(setSpecialValueResult))
-                   << StringPrintf("failed to set special value for property ID: %d, error: %s",
-                                   value.prop, getErrorMsg(setSpecialValueResult).c_str());
+            return StatusError(getErrorCode(setSpecialValueResult)) << StringPrintf(
+                           "failed to set special value for property ID: %s, error: %s",
+                           PROP_ID_TO_CSTR(value.prop), getErrorMsg(setSpecialValueResult).c_str());
         }
         return {};
     }
 
     auto updatedValue = mValuePool->obtain(value);
-    int64_t timestamp = elapsedRealtimeNano();
-    updatedValue->timestamp = timestamp;
 
-    auto writeResult = mServerSidePropStore->writeValue(std::move(updatedValue));
+    auto writeResult = mServerSidePropStore->writeValue(
+            std::move(updatedValue),
+            /*updateStatus=*/false, /*mode=*/VehiclePropertyStore::EventMode::ON_VALUE_CHANGE,
+            /*useCurrentTimestamp=*/true);
     if (!writeResult.ok()) {
         return StatusError(getErrorCode(writeResult))
                << StringPrintf("failed to write value into property store, error: %s",
@@ -896,7 +1152,7 @@
                                           const std::vector<GetValueRequest>& requests) const {
     for (auto& request : requests) {
         if (FAKE_VEHICLEHARDWARE_DEBUG) {
-            ALOGD("getValues(%d)", request.prop.prop);
+            ALOGD("getValues(%s)", PROP_ID_TO_CSTR(request.prop.prop));
         }
 
         // In a real VHAL implementation, you could either send the getValue request to vehicle bus
@@ -935,10 +1191,10 @@
     if (isSpecialValue) {
         if (!result.ok()) {
             return StatusError(getErrorCode(result))
-                   << StringPrintf("failed to get special value: %d, error: %s", value.prop,
-                                   getErrorMsg(result).c_str());
+                   << StringPrintf("failed to get special value: %s, error: %s",
+                                   PROP_ID_TO_CSTR(value.prop), getErrorMsg(result).c_str());
         } else {
-            return std::move(result);
+            return result;
         }
     }
 
@@ -953,7 +1209,7 @@
         }
     }
 
-    return std::move(readResult);
+    return readResult;
 }
 
 DumpResult FakeVehicleHardware::dump(const std::vector<std::string>& options) {
@@ -995,6 +1251,8 @@
         mAddExtraTestVendorConfigs = false;
         result.refreshPropertyConfigs = true;
         result.buffer = "successfully restored vendor configs";
+    } else if (EqualsIgnoreCase(option, "--dumpSub")) {
+        result.buffer = dumpSubscriptions();
     } else {
         result.buffer = StringPrintf("Invalid option: %s\n", option.c_str());
     }
@@ -1126,7 +1384,8 @@
         if (mGeneratorHub->unregisterGenerator(propId)) {
             return "Linear event generator stopped successfully";
         }
-        return StringPrintf("No linear event generator found for property: %d", propId);
+        return StringPrintf("No linear event generator found for property: %s",
+                            PROP_ID_TO_CSTR(propId));
     } else if (command == "--startjson") {
         // --genfakedata --startjson --path path repetition
         // or
@@ -1330,9 +1589,9 @@
 VehiclePropValue FakeVehicleHardware::createHwInputKeyProp(VehicleHwKeyInputAction action,
                                                            int32_t keyCode, int32_t targetDisplay) {
     VehiclePropValue value = {
-            .prop = toInt(VehicleProperty::HW_KEY_INPUT),
-            .areaId = 0,
             .timestamp = elapsedRealtimeNano(),
+            .areaId = 0,
+            .prop = toInt(VehicleProperty::HW_KEY_INPUT),
             .status = VehiclePropertyStatus::AVAILABLE,
             .value.int32Values = {toInt(action), keyCode, targetDisplay},
     };
@@ -1342,9 +1601,9 @@
 VehiclePropValue FakeVehicleHardware::createHwKeyInputV2Prop(int32_t area, int32_t targetDisplay,
                                                              int32_t keyCode, int32_t action,
                                                              int32_t repeatCount) {
-    VehiclePropValue value = {.prop = toInt(VehicleProperty::HW_KEY_INPUT_V2),
+    VehiclePropValue value = {.timestamp = elapsedRealtimeNano(),
                               .areaId = area,
-                              .timestamp = elapsedRealtimeNano(),
+                              .prop = toInt(VehicleProperty::HW_KEY_INPUT_V2),
                               .status = VehiclePropertyStatus::AVAILABLE,
                               .value.int32Values = {targetDisplay, keyCode, action, repeatCount},
                               .value.int64Values = {elapsedRealtimeNano()}};
@@ -1382,9 +1641,9 @@
         floatValues.push_back(size[i]);
     }
 
-    VehiclePropValue value = {.prop = toInt(VehicleProperty::HW_MOTION_INPUT),
+    VehiclePropValue value = {.timestamp = elapsedRealtimeNano(),
                               .areaId = area,
-                              .timestamp = elapsedRealtimeNano(),
+                              .prop = toInt(VehicleProperty::HW_MOTION_INPUT),
                               .status = VehiclePropertyStatus::AVAILABLE,
                               .value.int32Values = intValues,
                               .value.floatValues = floatValues,
@@ -1396,6 +1655,26 @@
     mServerSidePropStore->writeValue(mValuePool->obtain(value));
 }
 
+std::string FakeVehicleHardware::dumpSubscriptions() {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    std::string result = "Subscriptions: \n";
+    for (const auto& [interval, actionForInterval] : mActionByIntervalInNanos) {
+        for (const auto& propIdAreaId : actionForInterval.propIdAreaIdsToRefresh) {
+            const auto& refreshInfo = mRefreshInfoByPropIdAreaId[propIdAreaId];
+            bool vur = (refreshInfo.eventMode == VehiclePropertyStore::EventMode::ON_VALUE_CHANGE);
+            float sampleRateHz = 1'000'000'000. / refreshInfo.intervalInNanos;
+            result += StringPrintf("Continuous{property: %s, areaId: %d, rate: %lf hz, vur: %b}\n",
+                                   PROP_ID_TO_CSTR(propIdAreaId.propId), propIdAreaId.areaId,
+                                   sampleRateHz, vur);
+        }
+    }
+    for (const auto& propIdAreaId : mSubOnChangePropIdAreaIds) {
+        result += StringPrintf("OnChange{property: %s, areaId: %d}\n",
+                               PROP_ID_TO_CSTR(propIdAreaId.propId), propIdAreaId.areaId);
+    }
+    return result;
+}
+
 std::string FakeVehicleHardware::dumpHelp() {
     return "Usage: \n\n"
            "[no args]: dumps (id and value) all supported properties \n"
@@ -1453,8 +1732,9 @@
 
 std::string FakeVehicleHardware::dumpOnePropertyById(int32_t propId, int32_t areaId) {
     VehiclePropValue value = {
-            .prop = propId,
             .areaId = areaId,
+            .prop = propId,
+            .value = {},
     };
     bool isSpecialValue = false;
     auto result = maybeGetSpecialValue(value, &isSpecialValue);
@@ -1462,8 +1742,9 @@
         result = mServerSidePropStore->readValue(value);
     }
     if (!result.ok()) {
-        return StringPrintf("failed to read property value: %d, error: %s, code: %d\n", propId,
-                            getErrorMsg(result).c_str(), getIntErrorCode(result));
+        return StringPrintf("failed to read property value: %s, error: %s, code: %d\n",
+                            PROP_ID_TO_CSTR(propId), getErrorMsg(result).c_str(),
+                            getIntErrorCode(result));
 
     } else {
         return result.value()->toString() + "\n";
@@ -1478,7 +1759,7 @@
     int rowNumber = 1;
     std::string msg = StringPrintf("listing %zu properties\n", configs.size());
     for (const auto& config : configs) {
-        msg += StringPrintf("%d: %d\n", rowNumber++, config.prop);
+        msg += StringPrintf("%d: %s\n", rowNumber++, PROP_ID_TO_CSTR(config.prop));
     }
     return msg;
 }
@@ -1509,12 +1790,12 @@
             continue;
         }
         int32_t prop = propResult.value();
-        auto result = mServerSidePropStore->getConfig(prop);
+        auto result = mServerSidePropStore->getPropConfig(prop);
         if (!result.ok()) {
-            msg += StringPrintf("No property %d\n", prop);
+            msg += StringPrintf("No property %s\n", PROP_ID_TO_CSTR(prop));
             continue;
         }
-        msg += dumpOnePropertyByConfig(rowNumber++, *result.value());
+        msg += dumpOnePropertyByConfig(rowNumber++, result.value());
     }
     return msg;
 }
@@ -1525,12 +1806,12 @@
     while (*index < options.size()) {
         std::string option = options[*index];
         if (SET_PROP_OPTIONS.find(option) != SET_PROP_OPTIONS.end()) {
-            return std::move(values);
+            return values;
         }
         values.push_back(option);
         (*index)++;
     }
-    return std::move(values);
+    return values;
 }
 
 Result<VehiclePropValue> FakeVehicleHardware::parsePropOptions(
@@ -1697,8 +1978,9 @@
     }
 
     if (!result.ok()) {
-        return StringPrintf("failed to read property value: %d, error: %s, code: %d\n", prop.prop,
-                            getErrorMsg(result).c_str(), getIntErrorCode(result));
+        return StringPrintf("failed to read property value: %s, error: %s, code: %d\n",
+                            PROP_ID_TO_CSTR(prop.prop), getErrorMsg(result).c_str(),
+                            getIntErrorCode(result));
     }
     return StringPrintf("Get property result: %s\n", result.value()->toString().c_str());
 }
@@ -1791,7 +2073,7 @@
 
     eventFromVehicleBus(prop);
 
-    return StringPrintf("Event for property: %d injected", prop.prop);
+    return StringPrintf("Event for property: %s injected", PROP_ID_TO_CSTR(prop.prop));
 }
 
 StatusCode FakeVehicleHardware::checkHealth() {
@@ -1818,53 +2100,196 @@
     mOnPropertySetErrorCallback = std::move(callback);
 }
 
-StatusCode FakeVehicleHardware::updateSampleRate(int32_t propId, int32_t areaId, float sampleRate) {
-    // DefaultVehicleHal makes sure that sampleRate must be within minSampleRate and maxSampleRate.
-    // For fake implementation, we would write the same value with a new timestamp into propStore
-    // at sample rate.
-    std::scoped_lock<std::mutex> lockGuard(mLock);
+StatusCode FakeVehicleHardware::subscribe(SubscribeOptions options) {
+    int32_t propId = options.propId;
 
+    auto configResult = mServerSidePropStore->getPropConfig(propId);
+    if (!configResult.ok()) {
+        ALOGE("subscribe: property: %" PRId32 " is not supported", propId);
+        return StatusCode::INVALID_ARG;
+    }
+
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    for (int areaId : options.areaIds) {
+        if (StatusCode status = subscribePropIdAreaIdLocked(propId, areaId, options.sampleRate,
+                                                            options.enableVariableUpdateRate,
+                                                            configResult.value());
+            status != StatusCode::OK) {
+            return status;
+        }
+    }
+    return StatusCode::OK;
+}
+
+bool FakeVehicleHardware::isVariableUpdateRateSupported(const VehiclePropConfig& vehiclePropConfig,
+                                                        int32_t areaId) {
+    for (size_t i = 0; i < vehiclePropConfig.areaConfigs.size(); i++) {
+        const auto& areaConfig = vehiclePropConfig.areaConfigs[i];
+        if (areaConfig.areaId != areaId) {
+            continue;
+        }
+        if (areaConfig.supportVariableUpdateRate) {
+            return true;
+        }
+        break;
+    }
+    return false;
+}
+
+void FakeVehicleHardware::refreshTimestampForInterval(int64_t intervalInNanos) {
+    std::unordered_map<PropIdAreaId, VehiclePropertyStore::EventMode, PropIdAreaIdHash>
+            eventModeByPropIdAreaId;
+
+    {
+        std::scoped_lock<std::mutex> lockGuard(mLock);
+
+        if (mActionByIntervalInNanos.find(intervalInNanos) == mActionByIntervalInNanos.end()) {
+            ALOGE("No actions scheduled for the interval: %" PRId64 ", ignore the refresh request",
+                  intervalInNanos);
+            return;
+        }
+
+        ActionForInterval actionForInterval = mActionByIntervalInNanos[intervalInNanos];
+
+        // Make a copy so that we don't hold the lock while trying to refresh the timestamp.
+        // Refreshing the timestamp will inovke onValueChangeCallback which also requires lock, so
+        // we must not hold lock.
+        for (const PropIdAreaId& propIdAreaId : actionForInterval.propIdAreaIdsToRefresh) {
+            const RefreshInfo& refreshInfo = mRefreshInfoByPropIdAreaId[propIdAreaId];
+            eventModeByPropIdAreaId[propIdAreaId] = refreshInfo.eventMode;
+        }
+    }
+
+    mServerSidePropStore->refreshTimestamps(eventModeByPropIdAreaId);
+}
+
+void FakeVehicleHardware::registerRefreshLocked(PropIdAreaId propIdAreaId,
+                                                VehiclePropertyStore::EventMode eventMode,
+                                                float sampleRateHz) {
+    if (mRefreshInfoByPropIdAreaId.find(propIdAreaId) != mRefreshInfoByPropIdAreaId.end()) {
+        unregisterRefreshLocked(propIdAreaId);
+    }
+
+    int64_t intervalInNanos = static_cast<int64_t>(1'000'000'000. / sampleRateHz);
+    RefreshInfo refreshInfo = {
+            .eventMode = eventMode,
+            .intervalInNanos = intervalInNanos,
+    };
+    mRefreshInfoByPropIdAreaId[propIdAreaId] = refreshInfo;
+
+    if (mActionByIntervalInNanos.find(intervalInNanos) != mActionByIntervalInNanos.end()) {
+        // If we have already registered for this interval, then add the action info to the
+        // actions list.
+        mActionByIntervalInNanos[intervalInNanos].propIdAreaIdsToRefresh.insert(propIdAreaId);
+        return;
+    }
+
+    // This is the first action for the interval, register a timer callback for that interval.
+    auto action = std::make_shared<RecurrentTimer::Callback>(
+            [this, intervalInNanos] { refreshTimestampForInterval(intervalInNanos); });
+    mActionByIntervalInNanos[intervalInNanos] = ActionForInterval{
+            .propIdAreaIdsToRefresh = {propIdAreaId},
+            .recurrentAction = action,
+    };
+    mRecurrentTimer->registerTimerCallback(intervalInNanos, action);
+}
+
+void FakeVehicleHardware::unregisterRefreshLocked(PropIdAreaId propIdAreaId) {
+    if (mRefreshInfoByPropIdAreaId.find(propIdAreaId) == mRefreshInfoByPropIdAreaId.end()) {
+        ALOGW("PropId: %" PRId32 ", areaId: %" PRId32 " was not registered for refresh, ignore",
+              propIdAreaId.propId, propIdAreaId.areaId);
+        return;
+    }
+
+    int64_t intervalInNanos = mRefreshInfoByPropIdAreaId[propIdAreaId].intervalInNanos;
+    auto& actionForInterval = mActionByIntervalInNanos[intervalInNanos];
+    actionForInterval.propIdAreaIdsToRefresh.erase(propIdAreaId);
+    if (actionForInterval.propIdAreaIdsToRefresh.empty()) {
+        mRecurrentTimer->unregisterTimerCallback(actionForInterval.recurrentAction);
+        mActionByIntervalInNanos.erase(intervalInNanos);
+    }
+    mRefreshInfoByPropIdAreaId.erase(propIdAreaId);
+}
+
+StatusCode FakeVehicleHardware::subscribePropIdAreaIdLocked(
+        int32_t propId, int32_t areaId, float sampleRateHz, bool enableVariableUpdateRate,
+        const VehiclePropConfig& vehiclePropConfig) {
     PropIdAreaId propIdAreaId{
             .propId = propId,
             .areaId = areaId,
     };
-    if (mRecurrentActions.find(propIdAreaId) != mRecurrentActions.end()) {
-        mRecurrentTimer->unregisterTimerCallback(mRecurrentActions[propIdAreaId]);
+    switch (vehiclePropConfig.changeMode) {
+        case VehiclePropertyChangeMode::STATIC:
+            ALOGW("subscribe to a static property, do nothing.");
+            return StatusCode::OK;
+        case VehiclePropertyChangeMode::ON_CHANGE:
+            mSubOnChangePropIdAreaIds.insert(std::move(propIdAreaId));
+            return StatusCode::OK;
+        case VehiclePropertyChangeMode::CONTINUOUS:
+            if (sampleRateHz == 0.f) {
+                ALOGE("Must not use sample rate 0 for a continuous property");
+                return StatusCode::INVALID_ARG;
+            }
+            // For continuous properties, we must generate a new onPropertyChange event
+            // periodically according to the sample rate.
+            auto eventMode = VehiclePropertyStore::EventMode::ALWAYS;
+            if (isVariableUpdateRateSupported(vehiclePropConfig, areaId) &&
+                enableVariableUpdateRate) {
+                eventMode = VehiclePropertyStore::EventMode::ON_VALUE_CHANGE;
+            }
+
+            registerRefreshLocked(propIdAreaId, eventMode, sampleRateHz);
+            return StatusCode::OK;
     }
-    if (sampleRate == 0) {
-        return StatusCode::OK;
+}
+
+StatusCode FakeVehicleHardware::unsubscribe(int32_t propId, int32_t areaId) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    PropIdAreaId propIdAreaId{
+            .propId = propId,
+            .areaId = areaId,
+    };
+    if (mRefreshInfoByPropIdAreaId.find(propIdAreaId) != mRefreshInfoByPropIdAreaId.end()) {
+        unregisterRefreshLocked(propIdAreaId);
     }
-    int64_t interval = static_cast<int64_t>(1'000'000'000. / sampleRate);
-    auto action = std::make_shared<RecurrentTimer::Callback>([this, propId, areaId] {
-        // Refresh the property value. In real implementation, this should poll the latest value
-        // from vehicle bus. Here, we are just refreshing the existing value with a new timestamp.
-        auto result = getValue(VehiclePropValue{
-                .prop = propId,
-                .areaId = areaId,
-        });
-        if (!result.ok()) {
-            // Failed to read current value, skip refreshing.
-            return;
-        }
-        result.value()->timestamp = elapsedRealtimeNano();
-        // For continuous properties, we must generate a new onPropertyChange event periodically
-        // according to the sample rate.
-        mServerSidePropStore->writeValue(std::move(result.value()), /*updateStatus=*/true,
-                                         VehiclePropertyStore::EventMode::ALWAYS);
-    });
-    mRecurrentTimer->registerTimerCallback(interval, action);
-    mRecurrentActions[propIdAreaId] = action;
+    mSubOnChangePropIdAreaIds.erase(propIdAreaId);
     return StatusCode::OK;
 }
 
 void FakeVehicleHardware::onValueChangeCallback(const VehiclePropValue& value) {
-    if (mOnPropertyChangeCallback == nullptr) {
-        return;
+    ATRACE_CALL();
+    onValuesChangeCallback({value});
+}
+
+void FakeVehicleHardware::onValuesChangeCallback(std::vector<VehiclePropValue> values) {
+    ATRACE_CALL();
+    std::vector<VehiclePropValue> subscribedUpdatedValues;
+
+    {
+        std::scoped_lock<std::mutex> lockGuard(mLock);
+        if (mOnPropertyChangeCallback == nullptr) {
+            return;
+        }
+
+        for (const auto& value : values) {
+            PropIdAreaId propIdAreaId{
+                    .propId = value.prop,
+                    .areaId = value.areaId,
+            };
+            if (mRefreshInfoByPropIdAreaId.find(propIdAreaId) == mRefreshInfoByPropIdAreaId.end() &&
+                mSubOnChangePropIdAreaIds.find(propIdAreaId) == mSubOnChangePropIdAreaIds.end()) {
+                if (FAKE_VEHICLEHARDWARE_DEBUG) {
+                    ALOGD("The updated property value: %s is not subscribed, ignore",
+                          value.toString().c_str());
+                }
+                continue;
+            }
+
+            subscribedUpdatedValues.push_back(value);
+        }
     }
 
-    std::vector<VehiclePropValue> updatedValues;
-    updatedValues.push_back(value);
-    (*mOnPropertyChangeCallback)(std::move(updatedValues));
+    (*mOnPropertyChangeCallback)(std::move(subscribedUpdatedValues));
 }
 
 void FakeVehicleHardware::loadPropConfigsFromDir(
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp
index 8d8fcf5..b763d2f 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp
@@ -21,11 +21,14 @@
 cc_test {
     name: "FakeVehicleHardwareTest",
     vendor: true,
-    srcs: ["*.cpp"],
+    srcs: [
+        "*.cpp",
+        ":VhalTestVendorProperties",
+    ],
     cflags: ["-DENABLE_VEHICLE_HAL_TEST_PROPERTIES"],
     header_libs: [
         "IVehicleHardware",
-        "VehicleHalTestUtilHeaders",
+        "libbinder_headers",
     ],
     static_libs: [
         "VehicleHalJsonConfigLoaderEnableTestProperties",
@@ -47,7 +50,9 @@
         ":FakeVehicleHardwareTestOverrideJson",
         ":FakeVehicleHardwareTestPropJson",
     ],
-    defaults: ["VehicleHalDefaults"],
+    defaults: [
+        "VehicleHalDefaults",
+    ],
     test_suites: ["device-tests"],
 }
 
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
index 8d385dd..90643aa 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
@@ -19,7 +19,9 @@
 #include <FakeObd2Frame.h>
 #include <FakeUserHal.h>
 #include <PropertyUtils.h>
-#include <TestPropertyUtils.h>
+
+#include <aidl/android/hardware/automotive/vehicle/VehicleApPowerStateShutdownParam.h>
+#include <android/hardware/automotive/vehicle/TestVendorProperty.h>
 
 #include <android-base/expected.h>
 #include <android-base/file.h>
@@ -33,6 +35,7 @@
 #include <inttypes.h>
 #include <chrono>
 #include <condition_variable>
+#include <memory>
 #include <unordered_map>
 #include <unordered_set>
 #include <vector>
@@ -60,6 +63,8 @@
 namespace fake {
 namespace {
 
+using ::aidl::android::hardware::automotive::vehicle::CruiseControlCommand;
+using ::aidl::android::hardware::automotive::vehicle::CruiseControlType;
 using ::aidl::android::hardware::automotive::vehicle::ErrorState;
 using ::aidl::android::hardware::automotive::vehicle::GetValueRequest;
 using ::aidl::android::hardware::automotive::vehicle::GetValueResult;
@@ -67,13 +72,17 @@
 using ::aidl::android::hardware::automotive::vehicle::SetValueRequest;
 using ::aidl::android::hardware::automotive::vehicle::SetValueResult;
 using ::aidl::android::hardware::automotive::vehicle::StatusCode;
+using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions;
 using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateReport;
 using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateReq;
+using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateShutdownParam;
 using ::aidl::android::hardware::automotive::vehicle::VehicleAreaMirror;
 using ::aidl::android::hardware::automotive::vehicle::VehicleHwKeyInputAction;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
 using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyAccess;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyStatus;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyType;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
 using ::aidl::android::hardware::automotive::vehicle::VehicleUnit;
 using ::android::base::expected;
@@ -86,6 +95,7 @@
 using ::testing::Eq;
 using ::testing::HasSubstr;
 using ::testing::IsSubsetOf;
+using ::testing::UnorderedElementsAre;
 using ::testing::WhenSortedBy;
 
 using std::chrono::milliseconds;
@@ -104,6 +114,10 @@
         return mHardware->loadConfigDeclarations();
     }
 
+    std::unordered_set<int32_t> getHvacPowerDependentProps() {
+        return mHardware->hvacPowerDependentProps;
+    }
+
   private:
     FakeVehicleHardware* mHardware;
 };
@@ -137,6 +151,15 @@
         mHardware = std::move(hardware);
     }
 
+    static SubscribeOptions newSubscribeOptions(int32_t propId, int32_t areaId,
+                                                float sampleRateHz) {
+        SubscribeOptions options;
+        options.areaIds = {areaId};
+        options.propId = propId;
+        options.sampleRate = sampleRateHz;
+        return options;
+    }
+
     StatusCode setValues(const std::vector<SetValueRequest>& requests) {
         {
             std::scoped_lock<std::mutex> lockGuard(mLock);
@@ -324,6 +347,13 @@
         return mEventCount[propIdAreaId];
     }
 
+    void subscribe(int32_t propId, int32_t areaId, float sampleRateHz) {
+        ASSERT_EQ(StatusCode::OK,
+                  getHardware()->subscribe(newSubscribeOptions(propId, areaId, sampleRateHz)))
+                << "failed to subscribe to propId: " << propId << "areaId: " << areaId
+                << ", sampleRateHz: " << sampleRateHz;
+    }
+
     static void addSetValueRequest(std::vector<SetValueRequest>& requests,
                                    std::vector<SetValueResult>& expectedResults, int64_t requestId,
                                    const VehiclePropValue& value, StatusCode expectedStatus) {
@@ -358,24 +388,24 @@
     }
 
     std::vector<VehiclePropValue> getTestPropValues() {
-        VehiclePropValue fuelCapacity = {
-                .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
-                .value = {.floatValues = {1.0}},
+        VehiclePropValue oilLevel = {
+                .prop = toInt(VehicleProperty::ENGINE_OIL_LEVEL),
+                .value = {.int32Values = {1}},
         };
 
-        VehiclePropValue leftTirePressure = {
-                .prop = toInt(VehicleProperty::TIRE_PRESSURE),
+        VehiclePropValue leftHvacTemp = {
+                .prop = toInt(VehicleProperty::HVAC_TEMPERATURE_CURRENT),
                 .value = {.floatValues = {170.0}},
-                .areaId = WHEEL_FRONT_LEFT,
+                .areaId = SEAT_1_LEFT,
         };
 
-        VehiclePropValue rightTirePressure = {
-                .prop = toInt(VehicleProperty::TIRE_PRESSURE),
+        VehiclePropValue rightHvacTemp = {
+                .prop = toInt(VehicleProperty::HVAC_TEMPERATURE_CURRENT),
                 .value = {.floatValues = {180.0}},
-                .areaId = WHEEL_FRONT_RIGHT,
+                .areaId = SEAT_1_RIGHT,
         };
 
-        return {fuelCapacity, leftTirePressure, rightTirePressure};
+        return {oilLevel, leftHvacTemp, rightHvacTemp};
     }
 
     struct PropValueCmp {
@@ -385,6 +415,25 @@
         }
     } mPropValueCmp;
 
+    std::unique_ptr<VehiclePropConfig> getVehiclePropConfig(int32_t propertyId) {
+        auto configs = mHardware->getAllPropertyConfigs();
+        for (auto& config : configs) {
+            if (config.prop == propertyId) {
+                auto ptr = std::make_unique<VehiclePropConfig>();
+                ptr->prop = config.prop;
+                ptr->access = config.access;
+                ptr->changeMode = config.changeMode;
+                ptr->areaConfigs = config.areaConfigs;
+                ptr->configArray = config.configArray;
+                ptr->configString = config.configString;
+                ptr->minSampleRate = config.minSampleRate;
+                ptr->maxSampleRate = config.maxSampleRate;
+                return ptr;
+            }
+        }
+        return std::unique_ptr<VehiclePropConfig>(nullptr);
+    }
+
   private:
     std::unique_ptr<FakeVehicleHardware> mHardware;
     std::shared_ptr<IVehicleHardware::SetValuesCallback> mSetValuesCallback;
@@ -406,6 +455,29 @@
     ASSERT_EQ(configs.size(), helper.loadConfigDeclarations().size());
 }
 
+TEST_F(FakeVehicleHardwareTest, testGetAllPropertyConfigs_defaultSupportVUR) {
+    std::vector<VehiclePropConfig> configs = getHardware()->getAllPropertyConfigs();
+
+    for (const auto& config : configs) {
+        bool expectedSupportVUR = true;
+        if (config.prop == toInt(VehicleProperty::VHAL_HEARTBEAT) ||
+            config.prop == toInt(VehicleProperty::CLUSTER_HEARTBEAT)) {
+            expectedSupportVUR = false;
+        }
+        EXPECT_GE(config.areaConfigs.size(), 1u)
+                << "expect at least one area config, including global area config, propId: "
+                << config.prop;
+        if (config.areaConfigs.size() == 0) {
+            continue;
+        }
+        for (const auto& areaConfig : config.areaConfigs) {
+            EXPECT_EQ(areaConfig.supportVariableUpdateRate, expectedSupportVUR)
+                    << "unexpected supportVariableUpdateRate for propId: " << config.prop
+                    << ", areaId: " << areaConfig.areaId;
+        }
+    }
+}
+
 TEST_F(FakeVehicleHardwareTest, testGetDefaultValues) {
     std::vector<GetValueRequest> getValueRequests;
     std::vector<GetValueResult> expectedGetValueResults;
@@ -424,13 +496,13 @@
             continue;
         }
 
-        if (propId == ECHO_REVERSE_BYTES) {
+        if (propId == toInt(TestVendorProperty::ECHO_REVERSE_BYTES)) {
             // Ignore ECHO_REVERSE_BYTES, it has special logic.
             continue;
         }
 
-        if (propId == VENDOR_PROPERTY_ID) {
-            // Ignore VENDOR_PROPERTY_ID, it has special logic.
+        if (propId == toInt(TestVendorProperty::VENDOR_PROPERTY_FOR_ERROR_CODE_TESTING)) {
+            // Ignore VENDOR_PROPERTY_FOR_ERROR_CODE_TESTING, it has special logic.
             continue;
         }
 
@@ -528,17 +600,13 @@
     ASSERT_THAT(getSetValueResults(), ContainerEq(expectedResults));
 }
 
-TEST_F(FakeVehicleHardwareTest, testRegisterOnPropertyChangeEvent) {
-    // We have already registered this callback in Setup, here we are registering again.
-    auto callback = std::make_unique<IVehicleHardware::PropertyChangeCallback>(
-            [this](const std::vector<VehiclePropValue>& values) { onPropertyChangeEvent(values); });
-    getHardware()->registerOnPropertyChangeEvent(std::move(callback));
-
+TEST_F(FakeVehicleHardwareTest, testSetValues_getUpdateEvents) {
     auto testValues = getTestPropValues();
     std::vector<SetValueRequest> requests;
     std::vector<SetValueResult> expectedResults;
     int64_t requestId = 1;
     for (auto& value : testValues) {
+        subscribe(value.prop, value.areaId, /*sampleRateHz=*/0);
         addSetValueRequest(requests, expectedResults, requestId++, value, StatusCode::OK);
     }
     int64_t timestamp = elapsedRealtimeNano();
@@ -963,7 +1031,8 @@
                     .expectedValuesToGet =
                             {
                                     VehiclePropValue{
-                                            .prop = VENDOR_CLUSTER_REPORT_STATE,
+                                            .prop = toInt(TestVendorProperty::
+                                                                  VENDOR_CLUSTER_REPORT_STATE),
                                             .value.int32Values = {1},
                                     },
                             },
@@ -980,7 +1049,8 @@
                     .expectedValuesToGet =
                             {
                                     VehiclePropValue{
-                                            .prop = VENDOR_CLUSTER_REQUEST_DISPLAY,
+                                            .prop = toInt(TestVendorProperty::
+                                                                  VENDOR_CLUSTER_REQUEST_DISPLAY),
                                             .value.int32Values = {1},
                                     },
                             },
@@ -998,7 +1068,8 @@
                     .expectedValuesToGet =
                             {
                                     VehiclePropValue{
-                                            .prop = VENDOR_CLUSTER_NAVIGATION_STATE,
+                                            .prop = toInt(TestVendorProperty::
+                                                                  VENDOR_CLUSTER_NAVIGATION_STATE),
                                             .value.byteValues = {0x1},
                                     },
                             },
@@ -1008,7 +1079,8 @@
                     .valuesToSet =
                             {
                                     VehiclePropValue{
-                                            .prop = VENDOR_CLUSTER_SWITCH_UI,
+                                            .prop = toInt(
+                                                    TestVendorProperty::VENDOR_CLUSTER_SWITCH_UI),
                                             .value.int32Values = {1},
                                     },
                             },
@@ -1025,7 +1097,8 @@
                     .valuesToSet =
                             {
                                     VehiclePropValue{
-                                            .prop = VENDOR_CLUSTER_DISPLAY_STATE,
+                                            .prop = toInt(TestVendorProperty::
+                                                                  VENDOR_CLUSTER_DISPLAY_STATE),
                                             .value.int32Values = {1, 2},
                                     },
                             },
@@ -1451,7 +1524,7 @@
                                     },
                                     VehiclePropValue{
                                             .prop = toInt(VehicleProperty::CRUISE_CONTROL_TYPE),
-                                            .value.int32Values = {1},
+                                            .value.int32Values = {2},
                                     },
                                     VehiclePropValue{
                                             .prop = toInt(VehicleProperty::CRUISE_CONTROL_STATE),
@@ -1519,6 +1592,143 @@
                                     },
                             },
             },
+            SetSpecialValueTestCase{
+                    .name = "set_low_speed_collision_warning_enabled_false",
+                    .valuesToSet =
+                            {
+                                    VehiclePropValue{
+                                            .prop = toInt(
+                                                    VehicleProperty::
+                                                            LOW_SPEED_COLLISION_WARNING_ENABLED),
+                                            .value.int32Values = {0},
+                                    },
+                            },
+                    .expectedValuesToGet =
+                            {
+                                    VehiclePropValue{
+                                            .prop = toInt(
+                                                    VehicleProperty::
+                                                            LOW_SPEED_COLLISION_WARNING_ENABLED),
+                                            .value.int32Values = {0},
+                                    },
+                                    VehiclePropValue{
+                                            .prop = toInt(
+                                                    VehicleProperty::
+                                                            LOW_SPEED_COLLISION_WARNING_STATE),
+                                            .value.int32Values = {toInt(
+                                                    ErrorState::NOT_AVAILABLE_DISABLED)},
+                                    },
+                            },
+            },
+            SetSpecialValueTestCase{
+                    .name = "set_low_speed_collision_warning_enabled_true",
+                    .valuesToSet =
+                            {
+                                    VehiclePropValue{
+                                            .prop = toInt(
+                                                    VehicleProperty::
+                                                            LOW_SPEED_COLLISION_WARNING_ENABLED),
+                                            .value.int32Values = {1},
+                                    },
+                            },
+                    .expectedValuesToGet =
+                            {
+                                    VehiclePropValue{
+                                            .prop = toInt(
+                                                    VehicleProperty::
+                                                            LOW_SPEED_COLLISION_WARNING_ENABLED),
+                                            .value.int32Values = {1},
+                                    },
+                                    VehiclePropValue{
+                                            .prop = toInt(
+                                                    VehicleProperty::
+                                                            LOW_SPEED_COLLISION_WARNING_STATE),
+                                            .value.int32Values = {1},
+                                    },
+                            },
+            },
+            SetSpecialValueTestCase{
+                    .name = "set_electronic_stability_control_enabled_false",
+                    .valuesToSet =
+                            {
+                                    VehiclePropValue{
+                                            .prop = toInt(
+                                                    VehicleProperty::
+                                                            ELECTRONIC_STABILITY_CONTROL_ENABLED),
+                                            .value.int32Values = {0},
+                                    },
+                            },
+                    .expectedValuesToGet =
+                            {
+                                    VehiclePropValue{
+                                            .prop = toInt(
+                                                    VehicleProperty::
+                                                            ELECTRONIC_STABILITY_CONTROL_ENABLED),
+                                            .value.int32Values = {0},
+                                    },
+                                    VehiclePropValue{
+                                            .prop = toInt(
+                                                    VehicleProperty::
+                                                            ELECTRONIC_STABILITY_CONTROL_STATE),
+                                            .value.int32Values = {toInt(
+                                                    ErrorState::NOT_AVAILABLE_DISABLED)},
+                                    },
+                            },
+            },
+            SetSpecialValueTestCase{
+                    .name = "set_electronic_stability_control_enabled_true",
+                    .valuesToSet =
+                            {
+                                    VehiclePropValue{
+                                            .prop = toInt(
+                                                    VehicleProperty::
+                                                            ELECTRONIC_STABILITY_CONTROL_ENABLED),
+                                            .value.int32Values = {1},
+                                    },
+                            },
+                    .expectedValuesToGet =
+                            {
+                                    VehiclePropValue{
+                                            .prop = toInt(
+                                                    VehicleProperty::
+                                                            ELECTRONIC_STABILITY_CONTROL_ENABLED),
+                                            .value.int32Values = {1},
+                                    },
+                                    VehiclePropValue{
+                                            .prop = toInt(
+                                                    VehicleProperty::
+                                                            ELECTRONIC_STABILITY_CONTROL_STATE),
+                                            .value.int32Values = {1},
+                                    },
+                            },
+            },
+            SetSpecialValueTestCase{
+                    .name = "set_shutdown_request",
+                    .valuesToSet =
+                            {
+                                    VehiclePropValue{
+                                            .prop = toInt(VehicleProperty::SHUTDOWN_REQUEST),
+                                            .value.int32Values =
+                                                    {
+                                                            toInt(VehicleApPowerStateShutdownParam::
+                                                                          SHUTDOWN_ONLY),
+                                                    },
+                                    },
+                            },
+                    .expectedValuesToGet =
+                            {
+                                    VehiclePropValue{
+                                            .prop = toInt(VehicleProperty::AP_POWER_STATE_REQ),
+                                            .value.int32Values =
+                                                    {
+                                                            toInt(VehicleApPowerStateReq::
+                                                                          SHUTDOWN_PREPARE),
+                                                            toInt(VehicleApPowerStateShutdownParam::
+                                                                          SHUTDOWN_ONLY),
+                                                    },
+                                    },
+                            },
+            },
     };
 }
 
@@ -1561,27 +1771,30 @@
             return info.param.name;
         });
 
-TEST_F(FakeVehicleHardwareTest, testSetWaitForVhalAfterCarServiceCrash) {
-    int32_t propId = toInt(VehicleProperty::AP_POWER_STATE_REPORT);
+TEST_F(FakeVehicleHardwareTest, testSetWaitForVhal_alwaysTriggerEvents) {
+    int32_t powerReq = toInt(VehicleProperty::AP_POWER_STATE_REQ);
+    subscribe(powerReq, /*areaId*/ 0, /*sampleRateHz*/ 0);
+
+    int32_t powerReport = toInt(VehicleProperty::AP_POWER_STATE_REPORT);
     VehiclePropValue request = VehiclePropValue{
-            .prop = propId,
+            .prop = powerReport,
             .value.int32Values = {toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL)},
     };
-    ASSERT_EQ(setValue(request), StatusCode::OK) << "failed to set property " << propId;
+    ASSERT_EQ(setValue(request), StatusCode::OK) << "failed to set property " << powerReport;
 
     // Clear existing events.
     clearChangedProperties();
 
     // Simulate a Car Service crash, Car Service would restart and send the message again.
-    ASSERT_EQ(setValue(request), StatusCode::OK) << "failed to set property " << propId;
+    ASSERT_EQ(setValue(request), StatusCode::OK) << "failed to set property " << powerReport;
 
     std::vector<VehiclePropValue> events = getChangedProperties();
     // Even though the state is already ON, we should receive another ON event.
-    ASSERT_EQ(events.size(), 1u);
+    ASSERT_EQ(events.size(), 1u) << "failed to receive on-change events AP_POWER_STATE_REQ ON";
     // Erase the timestamp for comparison.
     events[0].timestamp = 0;
     auto expectedValue = VehiclePropValue{
-            .prop = toInt(VehicleProperty::AP_POWER_STATE_REQ),
+            .prop = powerReq,
             .status = VehiclePropertyStatus::AVAILABLE,
             .value.int32Values = {toInt(VehicleApPowerStateReq::ON), 0},
     };
@@ -1650,23 +1863,35 @@
 }
 
 TEST_F(FakeVehicleHardwareTest, testGetHvacPropNotAvailable) {
-    int seatAreaIds[5] = {SEAT_1_LEFT, SEAT_1_RIGHT, SEAT_2_LEFT, SEAT_2_CENTER, SEAT_2_RIGHT};
-    for (int areaId : seatAreaIds) {
+    FakeVehicleHardwareTestHelper helper(getHardware());
+    auto hvacPowerOnConfig = std::move(getVehiclePropConfig(toInt(VehicleProperty::HVAC_POWER_ON)));
+    EXPECT_NE(hvacPowerOnConfig, nullptr);
+    for (auto& hvacPowerOnAreaConfig : hvacPowerOnConfig->areaConfigs) {
+        int hvacPowerAreaId = hvacPowerOnAreaConfig.areaId;
+        // Turn off HVAC_POWER_ON for only 1 area ID
         StatusCode status = setValue(VehiclePropValue{.prop = toInt(VehicleProperty::HVAC_POWER_ON),
-                                                      .areaId = areaId,
+                                                      .areaId = hvacPowerAreaId,
                                                       .value.int32Values = {0}});
+        EXPECT_EQ(status, StatusCode::OK);
 
-        ASSERT_EQ(status, StatusCode::OK);
-
-        for (size_t i = 0; i < sizeof(HVAC_POWER_PROPERTIES) / sizeof(int32_t); i++) {
-            int powerPropId = HVAC_POWER_PROPERTIES[i];
-            for (int powerDependentAreaId : seatAreaIds) {
+        for (auto& powerPropId : helper.getHvacPowerDependentProps()) {
+            auto powerPropConfig = std::move(getVehiclePropConfig(powerPropId));
+            EXPECT_NE(powerPropConfig, nullptr);
+            if (powerPropConfig->access == VehiclePropertyAccess::WRITE) {
+                continue;
+            }
+            // Try getting a value at each area ID supported by the power dependent property
+            for (auto& powerPropAreaConfig : powerPropConfig->areaConfigs) {
+                int powerDependentAreaId = powerPropAreaConfig.areaId;
                 auto getValueResult = getValue(VehiclePropValue{
                         .prop = powerPropId,
                         .areaId = powerDependentAreaId,
                 });
 
-                if (areaId == powerDependentAreaId) {
+                // If the current area ID is contained within the HVAC_POWER_ON area ID
+                // turned off, then getValue should fail and a StatusCode error should be
+                // returned. Otherwise, a value should be returned.
+                if ((hvacPowerAreaId & powerDependentAreaId) == powerDependentAreaId) {
                     EXPECT_FALSE(getValueResult.ok());
                     EXPECT_EQ(getValueResult.error(), StatusCode::NOT_AVAILABLE_DISABLED);
                 } else {
@@ -1679,28 +1904,45 @@
         // on this value from any power dependent property values other than those with the same
         // areaId.
         setValue(VehiclePropValue{.prop = toInt(VehicleProperty::HVAC_POWER_ON),
-                                  .areaId = areaId,
+                                  .areaId = hvacPowerAreaId,
                                   .value.int32Values = {1}});
     }
 }
 
 TEST_F(FakeVehicleHardwareTest, testSetHvacPropNotAvailable) {
-    int seatAreaIds[5] = {SEAT_1_LEFT, SEAT_1_RIGHT, SEAT_2_LEFT, SEAT_2_CENTER, SEAT_2_RIGHT};
-    for (int areaId : seatAreaIds) {
+    FakeVehicleHardwareTestHelper helper(getHardware());
+    auto hvacPowerOnConfig = std::move(getVehiclePropConfig(toInt(VehicleProperty::HVAC_POWER_ON)));
+    EXPECT_NE(hvacPowerOnConfig, nullptr);
+    for (auto& hvacPowerOnAreaConfig : hvacPowerOnConfig->areaConfigs) {
+        int hvacPowerAreaId = hvacPowerOnAreaConfig.areaId;
+        // Turn off HVAC_POWER_ON for only 1 area ID
         StatusCode status = setValue(VehiclePropValue{.prop = toInt(VehicleProperty::HVAC_POWER_ON),
-                                                      .areaId = areaId,
+                                                      .areaId = hvacPowerAreaId,
                                                       .value.int32Values = {0}});
+        EXPECT_EQ(status, StatusCode::OK);
 
-        ASSERT_EQ(status, StatusCode::OK);
+        for (auto& powerPropId : helper.getHvacPowerDependentProps()) {
+            auto powerPropConfig = std::move(getVehiclePropConfig(powerPropId));
+            EXPECT_NE(powerPropConfig, nullptr);
+            if (powerPropConfig->access == VehiclePropertyAccess::READ) {
+                continue;
+            }
+            auto propType = getPropType(powerPropId);
+            // Try setting a value at each area ID supported by the power dependent property
+            for (auto& powerPropAreaConfig : powerPropConfig->areaConfigs) {
+                int powerDependentAreaId = powerPropAreaConfig.areaId;
+                auto val = VehiclePropValue{.prop = powerPropId, .areaId = powerDependentAreaId};
+                if (propType == VehiclePropertyType::FLOAT) {
+                    val.value.floatValues.emplace_back(20);
+                } else {
+                    val.value.int32Values.emplace_back(1);
+                }
+                status = setValue(val);
 
-        for (size_t i = 0; i < sizeof(HVAC_POWER_PROPERTIES) / sizeof(int32_t); i++) {
-            int powerPropId = HVAC_POWER_PROPERTIES[i];
-            for (int powerDependentAreaId : seatAreaIds) {
-                StatusCode status = setValue(VehiclePropValue{.prop = powerPropId,
-                                                              .areaId = powerDependentAreaId,
-                                                              .value.int32Values = {1}});
-
-                if (areaId == powerDependentAreaId) {
+                // If the current area ID is contained within the HVAC_POWER_ON area ID
+                // turned off, then setValue should fail and a StatusCode error should be
+                // returned. Otherwise, an ok StatusCode should be returned.
+                if ((hvacPowerAreaId & powerDependentAreaId) == powerDependentAreaId) {
                     EXPECT_EQ(status, StatusCode::NOT_AVAILABLE_DISABLED);
                 } else {
                     EXPECT_EQ(status, StatusCode::OK);
@@ -1712,37 +1954,142 @@
         // on this value from any power dependent property values other than those with the same
         // areaId.
         setValue(VehiclePropValue{.prop = toInt(VehicleProperty::HVAC_POWER_ON),
-                                  .areaId = areaId,
+                                  .areaId = hvacPowerAreaId,
                                   .value.int32Values = {1}});
     }
 }
 
 TEST_F(FakeVehicleHardwareTest, testHvacPowerOnSendCurrentHvacPropValues) {
-    int seatAreaIds[5] = {SEAT_1_LEFT, SEAT_1_RIGHT, SEAT_2_LEFT, SEAT_2_CENTER, SEAT_2_RIGHT};
-    for (int areaId : seatAreaIds) {
+    FakeVehicleHardwareTestHelper helper(getHardware());
+    auto hvacPowerOnConfig = std::move(getVehiclePropConfig(toInt(VehicleProperty::HVAC_POWER_ON)));
+    EXPECT_NE(hvacPowerOnConfig, nullptr);
+    for (auto& hvacPowerOnAreaConfig : hvacPowerOnConfig->areaConfigs) {
+        int hvacPowerAreaId = hvacPowerOnAreaConfig.areaId;
         StatusCode status = setValue(VehiclePropValue{.prop = toInt(VehicleProperty::HVAC_POWER_ON),
-                                                      .areaId = areaId,
+                                                      .areaId = hvacPowerAreaId,
                                                       .value.int32Values = {0}});
-
-        ASSERT_EQ(status, StatusCode::OK);
-
-        clearChangedProperties();
-        setValue(VehiclePropValue{.prop = toInt(VehicleProperty::HVAC_POWER_ON),
-                                  .areaId = areaId,
-                                  .value.int32Values = {1}});
-
+        EXPECT_EQ(status, StatusCode::OK);
         auto events = getChangedProperties();
-        // If we turn HVAC power on, we expect to receive one property event for every HVAC prop
-        // areas plus one event for HVAC_POWER_ON.
-        std::vector<int32_t> changedPropIds;
-        for (size_t i = 0; i < sizeof(HVAC_POWER_PROPERTIES) / sizeof(int32_t); i++) {
-            changedPropIds.push_back(HVAC_POWER_PROPERTIES[i]);
-        }
-        changedPropIds.push_back(toInt(VehicleProperty::HVAC_POWER_ON));
-
         for (const auto& event : events) {
-            EXPECT_EQ(event.areaId, areaId);
-            EXPECT_THAT(event.prop, AnyOfArray(changedPropIds));
+            // Ignore HVAC_POWER_ON event
+            if (event.prop == toInt(VehicleProperty::HVAC_POWER_ON)) {
+                continue;
+            }
+            EXPECT_THAT(event.prop, AnyOfArray(helper.getHvacPowerDependentProps()));
+            EXPECT_EQ((hvacPowerAreaId & event.areaId), hvacPowerAreaId);
+            EXPECT_EQ(event.status, VehiclePropertyStatus::UNAVAILABLE);
+        }
+        clearChangedProperties();
+
+        status = setValue(VehiclePropValue{.prop = toInt(VehicleProperty::HVAC_POWER_ON),
+                                           .areaId = hvacPowerAreaId,
+                                           .value.int32Values = {1}});
+        EXPECT_EQ(status, StatusCode::OK);
+        events = getChangedProperties();
+        for (const auto& event : events) {
+            // Ignore HVAC_POWER_ON event
+            if (event.prop == toInt(VehicleProperty::HVAC_POWER_ON)) {
+                continue;
+            }
+            EXPECT_THAT(event.prop, AnyOfArray(helper.getHvacPowerDependentProps()));
+            EXPECT_EQ((hvacPowerAreaId & event.areaId), hvacPowerAreaId);
+            EXPECT_EQ(event.status, VehiclePropertyStatus::AVAILABLE);
+        }
+        clearChangedProperties();
+    }
+}
+
+TEST_F(FakeVehicleHardwareTest, testHvacDualOnSynchronizesTemp) {
+    auto hvacDualOnConfig = std::move(getVehiclePropConfig(toInt(VehicleProperty::HVAC_DUAL_ON)));
+    auto hvacTemperatureSetConfig =
+            std::move(getVehiclePropConfig(toInt(VehicleProperty::HVAC_TEMPERATURE_SET)));
+    EXPECT_NE(hvacDualOnConfig, nullptr);
+    EXPECT_NE(hvacTemperatureSetConfig, nullptr);
+    for (auto& hvacTemperatureSetConfig : hvacTemperatureSetConfig->areaConfigs) {
+        int32_t hvacTemperatureSetAreaId = hvacTemperatureSetConfig.areaId;
+        subscribe(toInt(VehicleProperty::HVAC_TEMPERATURE_SET), hvacTemperatureSetAreaId,
+                  /*sampleRateHz*/ 0);
+    }
+    for (auto& hvacDualOnConfig : hvacDualOnConfig->areaConfigs) {
+        int32_t hvacDualOnAreaId = hvacDualOnConfig.areaId;
+        subscribe(toInt(VehicleProperty::HVAC_DUAL_ON), hvacDualOnAreaId, /*sampleRateHz*/ 0);
+        StatusCode status = setValue(VehiclePropValue{.prop = toInt(VehicleProperty::HVAC_DUAL_ON),
+                                                      .areaId = hvacDualOnAreaId,
+                                                      .value.int32Values = {1}});
+        EXPECT_EQ(status, StatusCode::OK);
+
+        // Verify there's an event for all HVAC_TEMPERATURE_SET
+        // area IDs covered by the HVAC_DUAL_ON area ID
+        auto events = getChangedProperties();
+        std::unordered_set<float> temperatureValues;
+        for (const auto& event : events) {
+            // Ignore HVAC_DUAL_ON event
+            if (event.prop == toInt(VehicleProperty::HVAC_DUAL_ON)) {
+                continue;
+            }
+            EXPECT_EQ(event.prop, toInt(VehicleProperty::HVAC_TEMPERATURE_SET));
+            EXPECT_EQ((hvacDualOnAreaId & event.areaId), event.areaId);
+            EXPECT_EQ(1u, event.value.floatValues.size());
+            temperatureValues.insert(event.value.floatValues[0]);
+        }
+        // Verify that the temperature value is the same for all events
+        // Ie the temperature in all area IDs are synchronized
+        EXPECT_EQ(1u, temperatureValues.size());
+        clearChangedProperties();
+
+        // Verify when any HVAC_TEMPERATURE_SET area ID is changed all
+        // area IDs covered by the HVAC_DUAL_ON area ID are also changed
+        for (auto& hvacTemperatureSetConfig : hvacTemperatureSetConfig->areaConfigs) {
+            int32_t hvacTemperatureSetAreaId = hvacTemperatureSetConfig.areaId;
+            if ((hvacDualOnAreaId & hvacTemperatureSetAreaId) != hvacTemperatureSetAreaId) {
+                continue;
+            }
+            float expectedValue = 25;
+            status = setValue(VehiclePropValue{.prop = toInt(VehicleProperty::HVAC_TEMPERATURE_SET),
+                                               .areaId = hvacTemperatureSetAreaId,
+                                               .value.floatValues = {expectedValue}});
+            EXPECT_EQ(status, StatusCode::OK);
+            events = getChangedProperties();
+            for (const auto& event : events) {
+                EXPECT_EQ(event.prop, toInt(VehicleProperty::HVAC_TEMPERATURE_SET));
+                EXPECT_EQ(1u, event.value.floatValues.size());
+                EXPECT_EQ(expectedValue, event.value.floatValues[0]);
+            }
+            clearChangedProperties();
+        }
+
+        status = setValue(VehiclePropValue{.prop = toInt(VehicleProperty::HVAC_DUAL_ON),
+                                           .areaId = hvacDualOnAreaId,
+                                           .value.int32Values = {0}});
+        EXPECT_EQ(status, StatusCode::OK);
+
+        // When HVAC_DUAL_ON is disabled, there should be no events created
+        // for HVAC_TEMPERATURE_SET ie no temperature synchronization.
+        events = getChangedProperties();
+        EXPECT_EQ(1u, events.size());
+        EXPECT_EQ(events[0].prop, toInt(VehicleProperty::HVAC_DUAL_ON));
+        EXPECT_EQ(events[0].areaId, hvacDualOnAreaId);
+        clearChangedProperties();
+
+        // Verify when any HVAC_TEMPERATURE_SET area ID is
+        // changed other area IDs do not change.
+        for (auto& hvacTemperatureSetConfig : hvacTemperatureSetConfig->areaConfigs) {
+            int32_t hvacTemperatureSetAreaId = hvacTemperatureSetConfig.areaId;
+            if ((hvacDualOnAreaId & hvacTemperatureSetAreaId) != hvacTemperatureSetAreaId) {
+                continue;
+            }
+            float expectedValue = 24;
+            status = setValue(VehiclePropValue{.prop = toInt(VehicleProperty::HVAC_TEMPERATURE_SET),
+                                               .areaId = hvacTemperatureSetAreaId,
+                                               .value.floatValues = {expectedValue}});
+            EXPECT_EQ(status, StatusCode::OK);
+            events = getChangedProperties();
+            EXPECT_EQ(1u, events.size());
+            EXPECT_EQ(events[0].prop, toInt(VehicleProperty::HVAC_TEMPERATURE_SET));
+            EXPECT_EQ(events[0].areaId, hvacTemperatureSetAreaId);
+            EXPECT_EQ(1u, events[0].value.floatValues.size());
+            EXPECT_EQ(expectedValue, events[0].value.floatValues[0]);
+            clearChangedProperties();
         }
     }
 }
@@ -1804,6 +2151,47 @@
     }
 }
 
+TEST_F(FakeVehicleHardwareTest, testGetAccPropertiesOnStandardCc) {
+    std::vector<int32_t> ccTypeDependentProperties = {
+            toInt(VehicleProperty::ADAPTIVE_CRUISE_CONTROL_TARGET_TIME_GAP),
+            toInt(VehicleProperty::ADAPTIVE_CRUISE_CONTROL_LEAD_VEHICLE_MEASURED_DISTANCE),
+    };
+
+    StatusCode status =
+            setValue(VehiclePropValue{.prop = toInt(VehicleProperty::CRUISE_CONTROL_TYPE),
+                                      .value.int32Values = {toInt(CruiseControlType::STANDARD)}});
+    EXPECT_EQ(status, StatusCode::OK);
+
+    for (int32_t dependentProp : ccTypeDependentProperties) {
+        auto getValueResult = getValue(VehiclePropValue{.prop = dependentProp});
+        EXPECT_FALSE(getValueResult.ok());
+        EXPECT_EQ(getValueResult.error(), StatusCode::NOT_AVAILABLE_DISABLED);
+    }
+}
+
+TEST_F(FakeVehicleHardwareTest, testSetAccPropertiesOnStandardCc) {
+    std::vector<VehiclePropValue> testVehiclePropValues = {
+            VehiclePropValue{
+                    .prop = toInt(VehicleProperty::ADAPTIVE_CRUISE_CONTROL_TARGET_TIME_GAP),
+                    .value.int32Values = {3}},
+            VehiclePropValue{
+                    .prop = toInt(VehicleProperty::CRUISE_CONTROL_COMMAND),
+                    .value.int32Values = {toInt(CruiseControlCommand::INCREASE_TARGET_TIME_GAP)}},
+            VehiclePropValue{
+                    .prop = toInt(VehicleProperty::CRUISE_CONTROL_COMMAND),
+                    .value.int32Values = {toInt(CruiseControlCommand::DECREASE_TARGET_TIME_GAP)}}};
+
+    StatusCode status =
+            setValue(VehiclePropValue{.prop = toInt(VehicleProperty::CRUISE_CONTROL_TYPE),
+                                      .value.int32Values = {toInt(CruiseControlType::STANDARD)}});
+    EXPECT_EQ(status, StatusCode::OK);
+
+    for (auto value : testVehiclePropValues) {
+        status = setValue(value);
+        EXPECT_EQ(status, StatusCode::NOT_AVAILABLE_DISABLED);
+    }
+}
+
 TEST_F(FakeVehicleHardwareTest, testSendAdasPropertiesState) {
     std::unordered_map<int32_t, std::vector<int32_t>> adasEnabledPropToAdasPropWithErrorState = {
             // AEB
@@ -1871,7 +2259,37 @@
                             toInt(VehicleProperty::HANDS_ON_DETECTION_WARNING),
                     },
             },
+            // LSCW
+            {
+                    toInt(VehicleProperty::LOW_SPEED_COLLISION_WARNING_ENABLED),
+                    {
+                            toInt(VehicleProperty::LOW_SPEED_COLLISION_WARNING_STATE),
+                    },
+            },
+            // ESC
+            {
+                    toInt(VehicleProperty::ELECTRONIC_STABILITY_CONTROL_ENABLED),
+                    {
+                            toInt(VehicleProperty::ELECTRONIC_STABILITY_CONTROL_STATE),
+                    },
+            },
     };
+
+    // First subscribe to all the properties that we will change.
+    for (auto& enabledToErrorStateProps : adasEnabledPropToAdasPropWithErrorState) {
+        std::unordered_set<int32_t> expectedChangedPropIds(enabledToErrorStateProps.second.begin(),
+                                                           enabledToErrorStateProps.second.end());
+        expectedChangedPropIds.insert(enabledToErrorStateProps.first);
+
+        for (int32_t propId : expectedChangedPropIds) {
+            int32_t areaId = 0;
+            if (propId == toInt(VehicleProperty::BLIND_SPOT_WARNING_STATE)) {
+                areaId = toInt(VehicleAreaMirror::DRIVER_LEFT);
+            }
+            subscribe(propId, areaId, /*sampleRateHz*/ 0);
+        }
+    }
+
     for (auto& enabledToErrorStateProps : adasEnabledPropToAdasPropWithErrorState) {
         int32_t adasEnabledPropertyId = enabledToErrorStateProps.first;
         StatusCode status =
@@ -1952,9 +2370,16 @@
 }
 
 TEST_F(FakeVehicleHardwareTest, testSwitchUser) {
+    SubscribeOptions options;
+    int32_t propSwitchUser = toInt(VehicleProperty::SWITCH_USER);
+    options.propId = propSwitchUser;
+    options.areaIds = {0, 1};
+    ASSERT_EQ(StatusCode::OK, getHardware()->subscribe(options))
+            << "failed to subscribe to propId: " << propSwitchUser;
+
     // This is the same example as used in User HAL Emulation doc.
     VehiclePropValue valueToSet = {
-            .prop = toInt(VehicleProperty::SWITCH_USER),
+            .prop = propSwitchUser,
             .areaId = 1,
             .value.int32Values = {666, 3, 2},
     };
@@ -1965,7 +2390,7 @@
 
     // Simulate a request from Android side.
     VehiclePropValue switchUserRequest = {
-            .prop = toInt(VehicleProperty::SWITCH_USER),
+            .prop = propSwitchUser,
             .areaId = 0,
             .value.int32Values = {666, 3},
     };
@@ -1995,7 +2420,7 @@
     events[0].timestamp = 0;
     auto expectedValue = VehiclePropValue{
             .areaId = 0,
-            .prop = toInt(VehicleProperty::SWITCH_USER),
+            .prop = propSwitchUser,
             .value.int32Values =
                     {
                             // Request ID
@@ -2010,6 +2435,13 @@
 }
 
 TEST_F(FakeVehicleHardwareTest, testCreateUser) {
+    SubscribeOptions options;
+    int32_t propCreateUser = toInt(VehicleProperty::CREATE_USER);
+    options.propId = propCreateUser;
+    options.areaIds = {0, 1};
+    ASSERT_EQ(StatusCode::OK, getHardware()->subscribe(options))
+            << "failed to subscribe to propId: " << propCreateUser;
+
     // This is the same example as used in User HAL Emulation doc.
     VehiclePropValue valueToSet = {
             .prop = toInt(VehicleProperty::CREATE_USER),
@@ -2023,7 +2455,7 @@
 
     // Simulate a request from Android side.
     VehiclePropValue createUserRequest = {
-            .prop = toInt(VehicleProperty::CREATE_USER),
+            .prop = propCreateUser,
             .areaId = 0,
             .value.int32Values = {666},
     };
@@ -2052,7 +2484,7 @@
     events[0].timestamp = 0;
     auto expectedValue = VehiclePropValue{
             .areaId = 0,
-            .prop = toInt(VehicleProperty::CREATE_USER),
+            .prop = propCreateUser,
             .value.int32Values =
                     {
                             // Request ID
@@ -2065,9 +2497,16 @@
 }
 
 TEST_F(FakeVehicleHardwareTest, testInitialUserInfo) {
+    SubscribeOptions options;
+    int32_t propInitialUserInfo = toInt(VehicleProperty::INITIAL_USER_INFO);
+    options.propId = propInitialUserInfo;
+    options.areaIds = {0, 1};
+    ASSERT_EQ(StatusCode::OK, getHardware()->subscribe(options))
+            << "failed to subscribe to propId: " << propInitialUserInfo;
+
     // This is the same example as used in User HAL Emulation doc.
     VehiclePropValue valueToSet = {
-            .prop = toInt(VehicleProperty::INITIAL_USER_INFO),
+            .prop = propInitialUserInfo,
             .areaId = 1,
             .value.int32Values = {666, 1, 11},
     };
@@ -2078,7 +2517,7 @@
 
     // Simulate a request from Android side.
     VehiclePropValue initialUserInfoRequest = {
-            .prop = toInt(VehicleProperty::INITIAL_USER_INFO),
+            .prop = propInitialUserInfo,
             .areaId = 0,
             .value.int32Values = {3},
     };
@@ -2095,7 +2534,7 @@
     events[0].timestamp = 0;
     auto expectedValue = VehiclePropValue{
             .areaId = 0,
-            .prop = toInt(VehicleProperty::INITIAL_USER_INFO),
+            .prop = propInitialUserInfo,
             .value.int32Values = {3, 1, 11},
     };
     EXPECT_EQ(events[0], expectedValue);
@@ -2110,7 +2549,7 @@
     events[0].timestamp = 0;
     expectedValue = VehiclePropValue{
             .areaId = 0,
-            .prop = toInt(VehicleProperty::INITIAL_USER_INFO),
+            .prop = propInitialUserInfo,
             .value.int32Values =
                     {
                             // Request ID
@@ -2178,8 +2617,8 @@
     DumpResult result = getHardware()->dump(options);
     ASSERT_FALSE(result.callerShouldDumpState);
     ASSERT_NE(result.buffer, "");
-    ASSERT_THAT(result.buffer, ContainsRegex(StringPrintf("1:.*prop: %s.*\nNo property %d\n",
-                                                          prop1.c_str(), INVALID_PROP_ID)));
+    ASSERT_THAT(result.buffer, ContainsRegex(StringPrintf("1:.*prop: %s.*\nNo property INVALID\n",
+                                                          prop1.c_str())));
 }
 
 TEST_F(FakeVehicleHardwareTest, testDumpSpecificPropertiesNoArg) {
@@ -2252,24 +2691,24 @@
 }
 
 TEST_F(FakeVehicleHardwareTest, testDumpInjectEvent) {
-    int32_t prop = toInt(VehicleProperty::PERF_VEHICLE_SPEED);
+    int32_t prop = toInt(VehicleProperty::ENGINE_OIL_LEVEL);
     std::string propIdStr = std::to_string(prop);
 
+    subscribe(prop, /*areaId*/ 0, /*sampleRateHz*/ 0);
+
     int64_t timestamp = elapsedRealtimeNano();
-    // Inject an event with float value 123.4 and timestamp.
     DumpResult result = getHardware()->dump(
-            {"--inject-event", propIdStr, "-f", "123.4", "-t", std::to_string(timestamp)});
+            {"--inject-event", propIdStr, "-i", "1234", "-t", std::to_string(timestamp)});
 
     ASSERT_FALSE(result.callerShouldDumpState);
-    ASSERT_THAT(result.buffer,
-                ContainsRegex(StringPrintf("Event for property: %d injected", prop)));
+    ASSERT_THAT(result.buffer, ContainsRegex("Event for property: ENGINE_OIL_LEVEL injected"));
     ASSERT_TRUE(waitForChangedProperties(prop, 0, /*count=*/1, milliseconds(1000)))
             << "No changed event received for injected event from vehicle bus";
     auto events = getChangedProperties();
     ASSERT_EQ(events.size(), 1u);
     auto event = events[0];
     ASSERT_EQ(event.timestamp, timestamp);
-    ASSERT_EQ(event.value.floatValues, std::vector<float>({123.4}));
+    ASSERT_EQ(event.value.int32Values, std::vector<int32_t>({1234}));
 }
 
 TEST_F(FakeVehicleHardwareTest, testDumpInvalidOptions) {
@@ -2612,9 +3051,13 @@
         });
 
 TEST_F(FakeVehicleHardwareTest, testDebugGenFakeDataLinear) {
-    // Start a fake linear data generator for vehicle speed at 0.1s interval.
+    // Start a fake linear data generator for engine oil level at 0.1s interval.
     // range: 0 - 100, current value: 30, step: 20.
-    std::string propIdString = StringPrintf("%d", toInt(VehicleProperty::PERF_VEHICLE_SPEED));
+    int32_t prop = toInt(VehicleProperty::ENGINE_OIL_LEVEL);
+
+    subscribe(prop, /*areaId*/ 0, /*sampleRateHz*/ 0);
+
+    std::string propIdString = StringPrintf("%d", prop);
     std::vector<std::string> options = {"--genfakedata",         "--startlinear", propIdString,
                                         /*middleValue=*/"50",
                                         /*currentValue=*/"30",
@@ -2627,15 +3070,14 @@
     ASSERT_FALSE(result.callerShouldDumpState);
     ASSERT_THAT(result.buffer, HasSubstr("successfully"));
 
-    ASSERT_TRUE(waitForChangedProperties(toInt(VehicleProperty::PERF_VEHICLE_SPEED), 0, /*count=*/5,
-                                         milliseconds(1000)))
+    ASSERT_TRUE(waitForChangedProperties(prop, 0, /*count=*/5, milliseconds(1000)))
             << "not enough events generated for linear data generator";
 
     int32_t value = 30;
     auto events = getChangedProperties();
     for (size_t i = 0; i < 5; i++) {
-        ASSERT_EQ(1u, events[i].value.floatValues.size());
-        EXPECT_EQ(static_cast<float>(value), events[i].value.floatValues[0]);
+        ASSERT_EQ(1u, events[i].value.int32Values.size());
+        EXPECT_EQ(value, events[i].value.int32Values[0]);
         value = (value + 20) % 100;
     }
 
@@ -2651,7 +3093,7 @@
     std::this_thread::sleep_for(std::chrono::milliseconds(200));
 
     // There should be no new events generated.
-    EXPECT_EQ(0u, getEventCount(toInt(VehicleProperty::PERF_VEHICLE_SPEED), 0));
+    EXPECT_EQ(0u, getEventCount(prop, 0));
 }
 
 std::string getTestFilePath(const char* filename) {
@@ -2660,6 +3102,8 @@
 }
 
 TEST_F(FakeVehicleHardwareTest, testDebugGenFakeDataJson) {
+    subscribe(toInt(VehicleProperty::GEAR_SELECTION), /*areaId*/ 0, /*sampleRateHz*/ 0);
+
     std::vector<std::string> options = {"--genfakedata", "--startjson", "--path",
                                         getTestFilePath("prop.json"), "2"};
 
@@ -2686,6 +3130,8 @@
 }
 
 TEST_F(FakeVehicleHardwareTest, testDebugGenFakeDataJsonByContent) {
+    subscribe(toInt(VehicleProperty::GEAR_SELECTION), /*areaId*/ 0, /*sampleRateHz*/ 0);
+
     std::vector<std::string> options = {
             "--genfakedata", "--startjson", "--content",
             "[{\"timestamp\":1000000,\"areaId\":0,\"value\":8,\"prop\":289408000}]", "1"};
@@ -2760,8 +3206,11 @@
 }
 
 TEST_F(FakeVehicleHardwareTest, testDebugGenFakeDataKeyPress) {
+    int32_t propHwKeyInput = toInt(VehicleProperty::HW_KEY_INPUT);
     std::vector<std::string> options = {"--genfakedata", "--keypress", "1", "2"};
 
+    subscribe(propHwKeyInput, /*areaId*/ 0, /*sampleRateHz*/ 0);
+
     DumpResult result = getHardware()->dump(options);
 
     ASSERT_FALSE(result.callerShouldDumpState);
@@ -2769,8 +3218,8 @@
 
     auto events = getChangedProperties();
     ASSERT_EQ(2u, events.size());
-    EXPECT_EQ(toInt(VehicleProperty::HW_KEY_INPUT), events[0].prop);
-    EXPECT_EQ(toInt(VehicleProperty::HW_KEY_INPUT), events[1].prop);
+    EXPECT_EQ(propHwKeyInput, events[0].prop);
+    EXPECT_EQ(propHwKeyInput, events[1].prop);
     ASSERT_EQ(3u, events[0].value.int32Values.size());
     ASSERT_EQ(3u, events[1].value.int32Values.size());
     EXPECT_EQ(toInt(VehicleHwKeyInputAction::ACTION_DOWN), events[0].value.int32Values[0]);
@@ -2782,8 +3231,11 @@
 }
 
 TEST_F(FakeVehicleHardwareTest, testDebugGenFakeDataKeyInputV2) {
+    int32_t propHwKeyInputV2 = toInt(VehicleProperty::HW_KEY_INPUT_V2);
     std::vector<std::string> options = {"--genfakedata", "--keyinputv2", "1", "2", "3", "4", "5"};
 
+    subscribe(propHwKeyInputV2, /*areaId*/ 1, /*sampleRateHz*/ 0);
+
     DumpResult result = getHardware()->dump(options);
 
     ASSERT_FALSE(result.callerShouldDumpState);
@@ -2801,6 +3253,7 @@
 }
 
 TEST_F(FakeVehicleHardwareTest, testDebugGenFakeDataMotionInput) {
+    int32_t propHwMotionInput = toInt(VehicleProperty::HW_MOTION_INPUT);
     std::vector<std::string> options = {"--genfakedata",
                                         "--motioninput",
                                         "1",
@@ -2823,6 +3276,8 @@
                                         "65.5",
                                         "76.6"};
 
+    subscribe(propHwMotionInput, /*areaId*/ 1, /*sampleRateHz*/ 0);
+
     DumpResult result = getHardware()->dump(options);
 
     ASSERT_FALSE(result.callerShouldDumpState);
@@ -2830,7 +3285,7 @@
 
     auto events = getChangedProperties();
     ASSERT_EQ(1u, events.size());
-    EXPECT_EQ(toInt(VehicleProperty::HW_MOTION_INPUT), events[0].prop);
+    EXPECT_EQ(propHwMotionInput, events[0].prop);
     ASSERT_EQ(9u, events[0].value.int32Values.size());
     EXPECT_EQ(2, events[0].value.int32Values[0]);
     EXPECT_EQ(3, events[0].value.int32Values[1]);
@@ -2855,7 +3310,7 @@
 
 TEST_F(FakeVehicleHardwareTest, testGetEchoReverseBytes) {
     ASSERT_EQ(setValue(VehiclePropValue{
-                      .prop = ECHO_REVERSE_BYTES,
+                      .prop = toInt(TestVendorProperty::ECHO_REVERSE_BYTES),
                       .value =
                               {
                                       .byteValues = {0x01, 0x02, 0x03, 0x04},
@@ -2864,30 +3319,34 @@
               StatusCode::OK);
 
     auto result = getValue(VehiclePropValue{
-            .prop = ECHO_REVERSE_BYTES,
+            .prop = toInt(TestVendorProperty::ECHO_REVERSE_BYTES),
     });
 
     ASSERT_TRUE(result.ok()) << "failed to get ECHO_REVERSE_BYTES value: " << getStatus(result);
     ASSERT_EQ(result.value().value.byteValues, std::vector<uint8_t>({0x04, 0x03, 0x02, 0x01}));
 }
 
-TEST_F(FakeVehicleHardwareTest, testUpdateSampleRate) {
+TEST_F(FakeVehicleHardwareTest, testSubscribeUnsubscribe_continuous) {
     int32_t propSpeed = toInt(VehicleProperty::PERF_VEHICLE_SPEED);
     int32_t propSteering = toInt(VehicleProperty::PERF_STEERING_ANGLE);
     int32_t areaId = 0;
-    getHardware()->updateSampleRate(propSpeed, areaId, 5);
+
+    auto status = getHardware()->subscribe(newSubscribeOptions(propSpeed, areaId, 5));
+    ASSERT_EQ(status, StatusCode::OK) << "failed to subscribe";
 
     ASSERT_TRUE(waitForChangedProperties(propSpeed, areaId, /*count=*/5, milliseconds(1500)))
             << "not enough events generated for speed";
 
-    getHardware()->updateSampleRate(propSteering, areaId, 10);
+    status = getHardware()->subscribe(newSubscribeOptions(propSteering, areaId, 10));
+    ASSERT_EQ(status, StatusCode::OK) << "failed to subscribe";
 
     ASSERT_TRUE(waitForChangedProperties(propSteering, areaId, /*count=*/10, milliseconds(1500)))
             << "not enough events generated for steering";
 
     int64_t timestamp = elapsedRealtimeNano();
     // Disable refreshing for propSpeed.
-    getHardware()->updateSampleRate(propSpeed, areaId, 0);
+    status = getHardware()->unsubscribe(propSpeed, areaId);
+    ASSERT_EQ(status, StatusCode::OK) << "failed to unsubscribe";
     clearChangedProperties();
 
     ASSERT_TRUE(waitForChangedProperties(propSteering, areaId, /*count=*/5, milliseconds(1500)))
@@ -2900,12 +3359,107 @@
     }
 }
 
+TEST_F(FakeVehicleHardwareTest, testSubscribe_enableVUR) {
+    int32_t propSpeed = toInt(VehicleProperty::PERF_VEHICLE_SPEED);
+    int32_t areaId = 0;
+    SubscribeOptions options;
+    options.propId = propSpeed;
+    options.areaIds = {areaId};
+    options.enableVariableUpdateRate = true;
+    options.sampleRate = 5;
+    int64_t timestamp = elapsedRealtimeNano();
+
+    auto status = getHardware()->subscribe(options);
+    ASSERT_EQ(status, StatusCode::OK) << "failed to subscribe";
+
+    status = setValue({
+            .prop = propSpeed,
+            .areaId = 0,
+            .value.floatValues = {1.1f},
+    });
+    ASSERT_EQ(status, StatusCode::OK) << "failed to set speed";
+
+    status = setValue({
+            .prop = propSpeed,
+            .areaId = 0,
+            .value.floatValues = {1.2f},
+    });
+    ASSERT_EQ(status, StatusCode::OK) << "failed to set speed";
+
+    ASSERT_TRUE(waitForChangedProperties(propSpeed, areaId, /*count=*/2, milliseconds(100)))
+            << "not enough events generated for speed";
+    auto updatedValues = getChangedProperties();
+    std::unordered_set<float> gotValues;
+    for (auto& value : updatedValues) {
+        EXPECT_GE(value.timestamp, timestamp) << "timestamp must be updated";
+        EXPECT_EQ(value.prop, propSpeed) << "propId must be correct";
+        EXPECT_EQ(value.areaId, areaId) << "areaId must be correct";
+        gotValues.insert(value.value.floatValues[0]);
+    }
+    EXPECT_THAT(gotValues, UnorderedElementsAre(1.1f, 1.2f))
+            << "must only receive property event for changed value";
+}
+
+TEST_F(FakeVehicleHardwareTest, testSubscribeUnusubscribe_onChange) {
+    int32_t propHvac = toInt(VehicleProperty::HVAC_TEMPERATURE_SET);
+    int32_t areaId = SEAT_1_LEFT;
+
+    auto status = getHardware()->subscribe(newSubscribeOptions(propHvac, areaId, 0));
+    ASSERT_EQ(status, StatusCode::OK) << "failed to subscribe";
+
+    status = setValue({
+            .prop = propHvac,
+            .areaId = areaId,
+            .value.floatValues = {20.0f},
+    });
+    ASSERT_EQ(status, StatusCode::OK) << "failed to set hvac value";
+
+    ASSERT_TRUE(waitForChangedProperties(propHvac, areaId, /*count=*/1, milliseconds(100)))
+            << "not enough on change events generated for hvac";
+    clearChangedProperties();
+
+    status = setValue({
+            .prop = propHvac,
+            .areaId = areaId,
+            .value.floatValues = {21.0f},
+    });
+    ASSERT_EQ(status, StatusCode::OK) << "failed to set hvac value";
+
+    ASSERT_TRUE(waitForChangedProperties(propHvac, areaId, /*count=*/1, milliseconds(100)))
+            << "not enough on change events generated for hvac";
+    clearChangedProperties();
+
+    status = getHardware()->unsubscribe(propHvac, areaId);
+    ASSERT_EQ(status, StatusCode::OK);
+
+    status = setValue({
+            .prop = propHvac,
+            .areaId = areaId,
+            .value.floatValues = {22.0f},
+    });
+    ASSERT_EQ(status, StatusCode::OK) << "failed to set hvac value";
+
+    ASSERT_FALSE(waitForChangedProperties(propHvac, areaId, /*count=*/1, milliseconds(100)))
+            << "must not receive on change events if the propId, areaId is unsubscribed";
+}
+
+TEST_F(FakeVehicleHardwareTest, testSubscribeContinuous_rate0_mustReturnInvalidArg) {
+    int32_t propSpeed = toInt(VehicleProperty::PERF_VEHICLE_SPEED);
+    int32_t areaId = 0;
+    auto status = getHardware()->subscribe(newSubscribeOptions(propSpeed, areaId, 0));
+
+    ASSERT_EQ(status, StatusCode::INVALID_ARG);
+}
+
 TEST_F(FakeVehicleHardwareTest, testSetHvacTemperatureValueSuggestion) {
     float CELSIUS = static_cast<float>(toInt(VehicleUnit::CELSIUS));
     float FAHRENHEIT = static_cast<float>(toInt(VehicleUnit::FAHRENHEIT));
+    int32_t propHvacTempValueSuggest = toInt(VehicleProperty::HVAC_TEMPERATURE_VALUE_SUGGESTION);
+
+    subscribe(propHvacTempValueSuggest, HVAC_ALL, /*sampleRateHz*/ 0);
 
     VehiclePropValue floatArraySizeFour = {
-            .prop = toInt(VehicleProperty::HVAC_TEMPERATURE_VALUE_SUGGESTION),
+            .prop = propHvacTempValueSuggest,
             .areaId = HVAC_ALL,
             .value.floatValues = {0, CELSIUS, 0, 0},
     };
@@ -2913,14 +3467,14 @@
     EXPECT_EQ(status, StatusCode::OK);
 
     VehiclePropValue floatArraySizeZero = {
-            .prop = toInt(VehicleProperty::HVAC_TEMPERATURE_VALUE_SUGGESTION),
+            .prop = propHvacTempValueSuggest,
             .areaId = HVAC_ALL,
     };
     status = setValue(floatArraySizeZero);
     EXPECT_EQ(status, StatusCode::INVALID_ARG);
 
     VehiclePropValue floatArraySizeFive = {
-            .prop = toInt(VehicleProperty::HVAC_TEMPERATURE_VALUE_SUGGESTION),
+            .prop = propHvacTempValueSuggest,
             .areaId = HVAC_ALL,
             .value.floatValues = {0, CELSIUS, 0, 0, 0},
     };
@@ -2928,7 +3482,7 @@
     EXPECT_EQ(status, StatusCode::INVALID_ARG);
 
     VehiclePropValue invalidUnit = {
-            .prop = toInt(VehicleProperty::HVAC_TEMPERATURE_VALUE_SUGGESTION),
+            .prop = propHvacTempValueSuggest,
             .areaId = HVAC_ALL,
             .value.floatValues = {0, 0, 0, 0},
     };
@@ -2938,13 +3492,8 @@
 
     // Config array values from HVAC_TEMPERATURE_SET in DefaultProperties.json
     auto configs = getHardware()->getAllPropertyConfigs();
-    VehiclePropConfig* hvacTemperatureSetConfig = nullptr;
-    for (auto& config : configs) {
-        if (config.prop == toInt(VehicleProperty::HVAC_TEMPERATURE_SET)) {
-            hvacTemperatureSetConfig = &config;
-            break;
-        }
-    }
+    auto hvacTemperatureSetConfig =
+            std::move(getVehiclePropConfig(toInt(VehicleProperty::HVAC_TEMPERATURE_SET)));
     EXPECT_NE(hvacTemperatureSetConfig, nullptr);
 
     auto& hvacTemperatureSetConfigArray = hvacTemperatureSetConfig->configArray;
@@ -2964,9 +3513,7 @@
                     .valuesToSet =
                             {
                                     VehiclePropValue{
-                                            .prop = toInt(
-                                                    VehicleProperty::
-                                                            HVAC_TEMPERATURE_VALUE_SUGGESTION),
+                                            .prop = propHvacTempValueSuggest,
                                             .areaId = HVAC_ALL,
                                             .value.floatValues = {minTempInCelsius, CELSIUS, 0, 0},
                                     },
@@ -2974,9 +3521,7 @@
                     .expectedValuesToGet =
                             {
                                     VehiclePropValue{
-                                            .prop = toInt(
-                                                    VehicleProperty::
-                                                            HVAC_TEMPERATURE_VALUE_SUGGESTION),
+                                            .prop = propHvacTempValueSuggest,
                                             .areaId = HVAC_ALL,
                                             .value.floatValues = {minTempInCelsius, CELSIUS,
                                                                   minTempInCelsius,
@@ -2989,9 +3534,7 @@
                     .valuesToSet =
                             {
                                     VehiclePropValue{
-                                            .prop = toInt(
-                                                    VehicleProperty::
-                                                            HVAC_TEMPERATURE_VALUE_SUGGESTION),
+                                            .prop = propHvacTempValueSuggest,
                                             .areaId = HVAC_ALL,
                                             .value.floatValues = {minTempInFahrenheit, FAHRENHEIT,
                                                                   0, 0},
@@ -3000,9 +3543,7 @@
                     .expectedValuesToGet =
                             {
                                     VehiclePropValue{
-                                            .prop = toInt(
-                                                    VehicleProperty::
-                                                            HVAC_TEMPERATURE_VALUE_SUGGESTION),
+                                            .prop = propHvacTempValueSuggest,
                                             .areaId = HVAC_ALL,
                                             .value.floatValues = {minTempInFahrenheit, FAHRENHEIT,
                                                                   minTempInCelsius,
@@ -3015,9 +3556,7 @@
                     .valuesToSet =
                             {
                                     VehiclePropValue{
-                                            .prop = toInt(
-                                                    VehicleProperty::
-                                                            HVAC_TEMPERATURE_VALUE_SUGGESTION),
+                                            .prop = propHvacTempValueSuggest,
                                             .areaId = HVAC_ALL,
                                             .value.floatValues = {maxTempInCelsius, CELSIUS, 0, 0},
                                     },
@@ -3025,9 +3564,7 @@
                     .expectedValuesToGet =
                             {
                                     VehiclePropValue{
-                                            .prop = toInt(
-                                                    VehicleProperty::
-                                                            HVAC_TEMPERATURE_VALUE_SUGGESTION),
+                                            .prop = propHvacTempValueSuggest,
                                             .areaId = HVAC_ALL,
                                             .value.floatValues = {maxTempInCelsius, CELSIUS,
                                                                   maxTempInCelsius,
@@ -3040,9 +3577,7 @@
                     .valuesToSet =
                             {
                                     VehiclePropValue{
-                                            .prop = toInt(
-                                                    VehicleProperty::
-                                                            HVAC_TEMPERATURE_VALUE_SUGGESTION),
+                                            .prop = propHvacTempValueSuggest,
                                             .areaId = HVAC_ALL,
                                             .value.floatValues = {maxTempInFahrenheit, FAHRENHEIT,
                                                                   0, 0},
@@ -3051,9 +3586,7 @@
                     .expectedValuesToGet =
                             {
                                     VehiclePropValue{
-                                            .prop = toInt(
-                                                    VehicleProperty::
-                                                            HVAC_TEMPERATURE_VALUE_SUGGESTION),
+                                            .prop = propHvacTempValueSuggest,
                                             .areaId = HVAC_ALL,
                                             .value.floatValues = {maxTempInFahrenheit, FAHRENHEIT,
                                                                   maxTempInCelsius,
@@ -3066,9 +3599,7 @@
                     .valuesToSet =
                             {
                                     VehiclePropValue{
-                                            .prop = toInt(
-                                                    VehicleProperty::
-                                                            HVAC_TEMPERATURE_VALUE_SUGGESTION),
+                                            .prop = propHvacTempValueSuggest,
                                             .areaId = HVAC_ALL,
                                             .value.floatValues = {minTempInCelsius - 1, CELSIUS, 0,
                                                                   0},
@@ -3077,9 +3608,7 @@
                     .expectedValuesToGet =
                             {
                                     VehiclePropValue{
-                                            .prop = toInt(
-                                                    VehicleProperty::
-                                                            HVAC_TEMPERATURE_VALUE_SUGGESTION),
+                                            .prop = propHvacTempValueSuggest,
                                             .areaId = HVAC_ALL,
                                             .value.floatValues = {minTempInCelsius - 1, CELSIUS,
                                                                   minTempInCelsius,
@@ -3092,9 +3621,7 @@
                     .valuesToSet =
                             {
                                     VehiclePropValue{
-                                            .prop = toInt(
-                                                    VehicleProperty::
-                                                            HVAC_TEMPERATURE_VALUE_SUGGESTION),
+                                            .prop = propHvacTempValueSuggest,
                                             .areaId = HVAC_ALL,
                                             .value.floatValues = {minTempInFahrenheit - 1,
                                                                   FAHRENHEIT, 0, 0},
@@ -3103,9 +3630,7 @@
                     .expectedValuesToGet =
                             {
                                     VehiclePropValue{
-                                            .prop = toInt(
-                                                    VehicleProperty::
-                                                            HVAC_TEMPERATURE_VALUE_SUGGESTION),
+                                            .prop = propHvacTempValueSuggest,
                                             .areaId = HVAC_ALL,
                                             .value.floatValues = {minTempInFahrenheit - 1,
                                                                   FAHRENHEIT, minTempInCelsius,
@@ -3118,9 +3643,7 @@
                     .valuesToSet =
                             {
                                     VehiclePropValue{
-                                            .prop = toInt(
-                                                    VehicleProperty::
-                                                            HVAC_TEMPERATURE_VALUE_SUGGESTION),
+                                            .prop = propHvacTempValueSuggest,
                                             .areaId = HVAC_ALL,
                                             .value.floatValues = {maxTempInCelsius + 1, CELSIUS, 0,
                                                                   0},
@@ -3129,9 +3652,7 @@
                     .expectedValuesToGet =
                             {
                                     VehiclePropValue{
-                                            .prop = toInt(
-                                                    VehicleProperty::
-                                                            HVAC_TEMPERATURE_VALUE_SUGGESTION),
+                                            .prop = propHvacTempValueSuggest,
                                             .areaId = HVAC_ALL,
                                             .value.floatValues = {maxTempInCelsius + 1, CELSIUS,
                                                                   maxTempInCelsius,
@@ -3144,9 +3665,7 @@
                     .valuesToSet =
                             {
                                     VehiclePropValue{
-                                            .prop = toInt(
-                                                    VehicleProperty::
-                                                            HVAC_TEMPERATURE_VALUE_SUGGESTION),
+                                            .prop = propHvacTempValueSuggest,
                                             .areaId = HVAC_ALL,
                                             .value.floatValues = {maxTempInFahrenheit + 1,
                                                                   FAHRENHEIT, 0, 0},
@@ -3155,9 +3674,7 @@
                     .expectedValuesToGet =
                             {
                                     VehiclePropValue{
-                                            .prop = toInt(
-                                                    VehicleProperty::
-                                                            HVAC_TEMPERATURE_VALUE_SUGGESTION),
+                                            .prop = propHvacTempValueSuggest,
                                             .areaId = HVAC_ALL,
                                             .value.floatValues = {maxTempInFahrenheit + 1,
                                                                   FAHRENHEIT, maxTempInCelsius,
@@ -3170,9 +3687,7 @@
                     .valuesToSet =
                             {
                                     VehiclePropValue{
-                                            .prop = toInt(
-                                                    VehicleProperty::
-                                                            HVAC_TEMPERATURE_VALUE_SUGGESTION),
+                                            .prop = propHvacTempValueSuggest,
                                             .areaId = HVAC_ALL,
                                             .value.floatValues = {minTempInCelsius +
                                                                           incrementInCelsius * 2.5f,
@@ -3182,9 +3697,7 @@
                     .expectedValuesToGet =
                             {
                                     VehiclePropValue{
-                                            .prop = toInt(
-                                                    VehicleProperty::
-                                                            HVAC_TEMPERATURE_VALUE_SUGGESTION),
+                                            .prop = propHvacTempValueSuggest,
                                             .areaId = HVAC_ALL,
                                             .value.floatValues =
                                                     {minTempInCelsius + incrementInCelsius * 2.5f,
@@ -3200,9 +3713,7 @@
                     .valuesToSet =
                             {
                                     VehiclePropValue{
-                                            .prop = toInt(
-                                                    VehicleProperty::
-                                                            HVAC_TEMPERATURE_VALUE_SUGGESTION),
+                                            .prop = propHvacTempValueSuggest,
                                             .areaId = HVAC_ALL,
                                             .value.floatValues = {minTempInFahrenheit +
                                                                           incrementInFahrenheit *
@@ -3213,9 +3724,7 @@
                     .expectedValuesToGet =
                             {
                                     VehiclePropValue{
-                                            .prop = toInt(
-                                                    VehicleProperty::
-                                                            HVAC_TEMPERATURE_VALUE_SUGGESTION),
+                                            .prop = propHvacTempValueSuggest,
                                             .areaId = HVAC_ALL,
                                             .value.floatValues =
                                                     {minTempInFahrenheit +
diff --git a/automotive/vehicle/aidl/impl/grpc/Android.bp b/automotive/vehicle/aidl/impl/grpc/Android.bp
index 06c9600..e5106f8 100644
--- a/automotive/vehicle/aidl/impl/grpc/Android.bp
+++ b/automotive/vehicle/aidl/impl/grpc/Android.bp
@@ -22,9 +22,11 @@
         "aprotoc",
         "protoc-gen-grpc-cpp-plugin",
     ],
-    cmd: "$(location aprotoc) -I$$(dirname $(in)) -Ihardware/interfaces/automotive/vehicle/aidl/impl/proto -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)",
+    cmd: "$(location aprotoc) -I$$(dirname $(location proto/VehicleServer.proto)) -Ihardware/interfaces/automotive/vehicle/aidl/impl/proto -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(location proto/VehicleServer.proto) --grpc_out=$(genDir) --cpp_out=$(genDir)",
     srcs: [
         "proto/VehicleServer.proto",
+        ":libprotobuf-internal-protos",
+        ":VehicleHalProtoFiles",
     ],
     out: [
         "VehicleServer.pb.h",
@@ -39,9 +41,11 @@
         "aprotoc",
         "protoc-gen-grpc-cpp-plugin",
     ],
-    cmd: "$(location aprotoc) -I$$(dirname $(in)) -Ihardware/interfaces/automotive/vehicle/aidl/impl/proto -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)",
+    cmd: "$(location aprotoc) -I$$(dirname $(location proto/VehicleServer.proto)) -Ihardware/interfaces/automotive/vehicle/aidl/impl/proto -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(location proto/VehicleServer.proto) --grpc_out=$(genDir) --cpp_out=$(genDir)",
     srcs: [
         "proto/VehicleServer.proto",
+        ":libprotobuf-internal-protos",
+        ":VehicleHalProtoFiles",
     ],
     out: [
         "VehicleServer.pb.cc",
diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h
index 90588aa..ddd620e 100644
--- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h
@@ -24,6 +24,8 @@
 #include "VehicleServer.grpc.pb.h"
 #include "VehicleServer.pb.h"
 
+#include <grpc++/grpc++.h>
+
 #include <atomic>
 #include <chrono>
 #include <condition_variable>
@@ -80,6 +82,10 @@
 
     bool waitForConnected(std::chrono::milliseconds waitTime);
 
+  protected:
+    std::shared_mutex mCallbackMutex;
+    std::unique_ptr<const PropertyChangeCallback> mOnPropChange;
+
   private:
     void ValuePollingLoop();
 
@@ -88,8 +94,6 @@
     std::unique_ptr<proto::VehicleServer::Stub> mGrpcStub;
     std::thread mValuePollingThread;
 
-    std::shared_mutex mCallbackMutex;
-    std::unique_ptr<const PropertyChangeCallback> mOnPropChange;
     std::unique_ptr<const PropertySetErrorCallback> mOnSetErr;
 
     std::mutex mShutdownMutex;
diff --git a/automotive/vehicle/aidl/impl/grpc/OWNERS b/automotive/vehicle/aidl/impl/grpc/OWNERS
deleted file mode 100644
index 7a96f23..0000000
--- a/automotive/vehicle/aidl/impl/grpc/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-shanyu@google.com
-chenhaosjtuacm@google.com
-egranata@google.com
diff --git a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/src/ProtoMessageConverter.cpp b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/src/ProtoMessageConverter.cpp
index 6cbc7e5..1ea0df4 100644
--- a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/src/ProtoMessageConverter.cpp
+++ b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/src/ProtoMessageConverter.cpp
@@ -67,12 +67,19 @@
     for (auto& areaConfig : in.areaConfigs) {
         auto* protoACfg = out->add_area_configs();
         protoACfg->set_area_id(areaConfig.areaId);
+        protoACfg->set_access(static_cast<proto::VehiclePropertyAccess>(toInt(areaConfig.access)));
         protoACfg->set_min_int64_value(areaConfig.minInt64Value);
         protoACfg->set_max_int64_value(areaConfig.maxInt64Value);
         protoACfg->set_min_float_value(areaConfig.minFloatValue);
         protoACfg->set_max_float_value(areaConfig.maxFloatValue);
         protoACfg->set_min_int32_value(areaConfig.minInt32Value);
         protoACfg->set_max_int32_value(areaConfig.maxInt32Value);
+        if (areaConfig.supportedEnumValues.has_value()) {
+            for (auto& supportedEnumValue : areaConfig.supportedEnumValues.value()) {
+                protoACfg->add_supported_enum_values(supportedEnumValue);
+            }
+        }
+        protoACfg->set_support_variable_update_rate(areaConfig.supportVariableUpdateRate);
     }
 }
 
@@ -87,15 +94,24 @@
     COPY_PROTOBUF_VEC_TO_VHAL_TYPE(in, config_array, out, configArray);
 
     auto cast_to_acfg = [](const proto::VehicleAreaConfig& protoAcfg) {
-        return aidl_vehicle::VehicleAreaConfig{
+        auto vehicleAreaConfig = aidl_vehicle::VehicleAreaConfig{
                 .areaId = protoAcfg.area_id(),
+                .access = static_cast<aidl_vehicle::VehiclePropertyAccess>(protoAcfg.access()),
                 .minInt32Value = protoAcfg.min_int32_value(),
                 .maxInt32Value = protoAcfg.max_int32_value(),
                 .minInt64Value = protoAcfg.min_int64_value(),
                 .maxInt64Value = protoAcfg.max_int64_value(),
                 .minFloatValue = protoAcfg.min_float_value(),
                 .maxFloatValue = protoAcfg.max_float_value(),
+                .supportVariableUpdateRate = protoAcfg.support_variable_update_rate(),
         };
+        if (protoAcfg.supported_enum_values().size() != 0) {
+            vehicleAreaConfig.supportedEnumValues = std::vector<int64_t>();
+            COPY_PROTOBUF_VEC_TO_VHAL_TYPE(protoAcfg, supported_enum_values, (&vehicleAreaConfig),
+                                           supportedEnumValues.value());
+        }
+
+        return vehicleAreaConfig;
     };
     CAST_COPY_PROTOBUF_VEC_TO_VHAL_TYPE(in, area_configs, out, areaConfigs, cast_to_acfg);
 }
diff --git a/automotive/vehicle/aidl/impl/hardware/include/IVehicleHardware.h b/automotive/vehicle/aidl/impl/hardware/include/IVehicleHardware.h
index e53947e..f49d91b 100644
--- a/automotive/vehicle/aidl/impl/hardware/include/IVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/hardware/include/IVehicleHardware.h
@@ -82,6 +82,117 @@
             const std::vector<aidl::android::hardware::automotive::vehicle::GetValueRequest>&
                     requests) const = 0;
 
+    // Dump debug information in the server.
+    virtual DumpResult dump(const std::vector<std::string>& options) = 0;
+
+    // Check whether the system is healthy, return {@code StatusCode::OK} for healthy.
+    virtual aidl::android::hardware::automotive::vehicle::StatusCode checkHealth() = 0;
+
+    // Register a callback that would be called when there is a property change event from vehicle.
+    // This function must only be called once during initialization.
+    virtual void registerOnPropertyChangeEvent(
+            std::unique_ptr<const PropertyChangeCallback> callback) = 0;
+
+    // Register a callback that would be called when there is a property set error event from
+    // vehicle. Must only be called once during initialization.
+    virtual void registerOnPropertySetErrorEvent(
+            std::unique_ptr<const PropertySetErrorCallback> callback) = 0;
+
+    // Gets the batching window used by DefaultVehicleHal for property change events.
+    //
+    // In DefaultVehicleHal, all the property change events generated within the batching window
+    // will be delivered through one callback to the VHAL client. This affects the maximum supported
+    // subscription rate. For example, if this returns 10ms, then only one callback for property
+    // change events will be called per 10ms, meaining that the max subscription rate for all
+    // continuous properties would be 100hz.
+    //
+    // A higher batching window means less callbacks to the VHAL client, causing a better
+    // performance. However, it also means a longer average latency for every property change
+    // events.
+    //
+    // 0 means no batching should be enabled in DefaultVehicleHal. In this case, batching can
+    // be optionally implemented in IVehicleHardware layer.
+    virtual std::chrono::nanoseconds getPropertyOnChangeEventBatchingWindow() {
+        // By default batching is disabled.
+        return std::chrono::nanoseconds(0);
+    }
+
+    // A [propId, areaId] is newly subscribed or the subscribe options are changed.
+    //
+    // The subscribe options contain sample rate in Hz or enable/disable variable update rate.
+    //
+    // For continuous properties:
+    //
+    // The sample rate is never 0 and indicates the desired polling rate for this property. The
+    // sample rate is guaranteed to be within supported {@code minSampleRate} and
+    // {@code maxSampleRate} as specified in {@code VehiclePropConfig}.
+    //
+    // If the specified sample rate is not supported, e.g. vehicle bus only supports 5hz and 10hz
+    // polling rate but the sample rate is 8hz, impl must choose the higher polling rate (10hz).
+    //
+    // Whether variable update rate is enabled is specified by {@code enableVariableUpdateRate} in
+    // {@code SubscribeOptions}. If variable update rate is not supported for the
+    // [propId, areaId], impl must ignore this option and always treat it as disabled.
+    //
+    // If variable update rate is disabled/not supported, impl must report all the property events
+    // for this [propId, areaId] through {@code propertyChangeCallback} according to the sample
+    // rate. E.g. a sample rate of 10hz must generate at least 10 property change events per second.
+    //
+    // If variable update rate is enabled AND supported, impl must only report property events
+    // when the [propId, areaId]'s value or status changes (a.k.a same as on-change property).
+    // The sample rate still guides the polling rate, but duplicate property events must be dropped
+    // and not reported via {@code propertyChangeCallback}.
+    //
+    // Async property set error events are not affected by variable update rate and must always
+    // be reported.
+    //
+    // If the impl is always polling at {@code maxSampleRate} for all continuous [propId, areaId]s,
+    // and do not support variable update rate for any [propId, areaId], then this function can be a
+    // no-op.
+    //
+    // For on-change properties:
+    //
+    // The sample rate is always 0 and must be ignored. If the impl is always subscribing to all
+    // on-change properties, then this function can be no-op.
+    //
+    // For all properties:
+    //
+    // It is recommended to only deliver the subscribed property events to DefaultVehicleHal to
+    // improve performance. However, even if unsubscribed property events are delivered, they
+    // will be filtered out by DefaultVehicleHal.
+    //
+    // A subscription from VHAL client might not necessarily trigger this function.
+    // DefaultVehicleHal will aggregate all the subscriptions from all the clients and notify
+    // IVehicleHardware if new subscriptions are required or subscribe options are updated.
+    //
+    // For example:
+    // 1. VHAL initially have no subscriber for speed.
+    // 2. A new subscriber is subscribing speed for 10 times/s, 'subscribe' is called
+    //    with sampleRate as 10. The impl is now polling vehicle speed from bus 10 times/s.
+    // 3. A new subscriber is subscribing speed for 5 times/s, because it is less than 10
+    //    times/sec, 'subscribe' is not called.
+    // 4. The initial subscriber is removed, 'subscribe' is called with sampleRate as
+    //    5, because now it only needs to report event 5times/sec. The impl can now poll vehicle
+    //    speed 5 times/s. If the impl is still polling at 10 times/s, that is okay as long as
+    //    the polling rate is larger than 5times/s. DefaultVehicleHal would ignore the additional
+    //    events.
+    // 5. The second subscriber is removed, 'unsubscribe' is called.
+    //    The impl can optionally disable the polling for vehicle speed.
+    //
+    virtual aidl::android::hardware::automotive::vehicle::StatusCode subscribe(
+            [[maybe_unused]] aidl::android::hardware::automotive::vehicle::SubscribeOptions
+                    options) {
+        return aidl::android::hardware::automotive::vehicle::StatusCode::OK;
+    }
+
+    // A [propId, areaId] is unsubscribed. This applies for both continuous or on-change property.
+    virtual aidl::android::hardware::automotive::vehicle::StatusCode unsubscribe(
+            [[maybe_unused]] int32_t propId, [[maybe_unused]] int32_t areaId) {
+        return aidl::android::hardware::automotive::vehicle::StatusCode::OK;
+    }
+
+    // This function is deprecated, subscribe/unsubscribe should be used instead.
+    //
     // Update the sampling rate for the specified property and the specified areaId (0 for global
     // property) if server supports it. The property must be a continuous property.
     // {@code sampleRate} means that for this specific property, the server must generate at least
@@ -91,7 +202,7 @@
     // This would be called if sample rate is updated for a subscriber, a new subscriber is added
     // or an existing subscriber is removed. For example:
     // 1. We have no subscriber for speed.
-    // 2. A new subscriber is subscribing speed for 10 times/s, updsateSampleRate would be called
+    // 2. A new subscriber is subscribing speed for 10 times/s, updateSampleRate would be called
     //    with sampleRate as 10. The impl is now polling vehicle speed from bus 10 times/s.
     // 3. A new subscriber is subscribing speed for 5 times/s, because it is less than 10
     //    times/sec, updateSampleRate would not be called.
@@ -110,22 +221,6 @@
             [[maybe_unused]] float sampleRate) {
         return aidl::android::hardware::automotive::vehicle::StatusCode::OK;
     }
-
-    // Dump debug information in the server.
-    virtual DumpResult dump(const std::vector<std::string>& options) = 0;
-
-    // Check whether the system is healthy, return {@code StatusCode::OK} for healthy.
-    virtual aidl::android::hardware::automotive::vehicle::StatusCode checkHealth() = 0;
-
-    // Register a callback that would be called when there is a property change event from vehicle.
-    // Must only be called once during initialization.
-    virtual void registerOnPropertyChangeEvent(
-            std::unique_ptr<const PropertyChangeCallback> callback) = 0;
-
-    // Register a callback that would be called when there is a property set error event from
-    // vehicle. Must only be called once during initialization.
-    virtual void registerOnPropertySetErrorEvent(
-            std::unique_ptr<const PropertySetErrorCallback> callback) = 0;
 };
 
 }  // namespace vehicle
diff --git a/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/StatusCode.proto b/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/StatusCode.proto
index 63d7933..95e766a 100644
--- a/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/StatusCode.proto
+++ b/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/StatusCode.proto
@@ -38,6 +38,37 @@
 
     /* Something unexpected has happened in Vehicle HAL */
     INTERNAL_ERROR = 5;
+
+    /**
+     * For features that are not available because the underlying feature is
+     * disabled.
+     */
+    NOT_AVAILABLE_DISABLED = 6;
+
+    /**
+     * For features that are not available because the vehicle speed is too low.
+     */
+    NOT_AVAILABLE_SPEED_LOW = 7;
+
+    /**
+     * For features that are not available because the vehicle speed is too
+     * high.
+     */
+    NOT_AVAILABLE_SPEED_HIGH = 8;
+
+    /**
+     * For features that are not available because of bad camera or sensor
+     * visibility. Examples might be bird poop blocking the camera or a bumper
+     * cover blocking an ultrasonic sensor.
+     */
+    NOT_AVAILABLE_POOR_VISIBILITY = 9;
+
+    /**
+     * The feature cannot be accessed due to safety reasons. Eg. System could be
+     * in a faulty state, an object or person could be blocking the requested
+     * operation such as closing a trunk door, etc.
+     */
+    NOT_AVAILABLE_SAFETY = 10;
 };
 
 message VehicleHalCallStatus {
diff --git a/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/VehicleAreaConfig.proto b/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/VehicleAreaConfig.proto
index b5b7e80..7ea8540 100644
--- a/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/VehicleAreaConfig.proto
+++ b/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/VehicleAreaConfig.proto
@@ -18,6 +18,8 @@
 
 package android.hardware.automotive.vehicle.proto;
 
+import "android/hardware/automotive/vehicle/VehiclePropertyAccess.proto";
+
 /* Must be in sync with VehicleAreaConfig.aidl. */
 message VehicleAreaConfig {
     /* Area id is ignored for VehiclePropertyGroup:GLOBAL properties. */
@@ -36,4 +38,13 @@
 
     float min_float_value = 6;
     float max_float_value = 7;
+
+    /**
+     * If the property has a @data_enum, then it is possible to specify a supported subset of the
+     * @data_enum. If the property has a @data_enum and supported_enum_values is null, then it is
+     * assumed all @data_enum values are supported unless specified through another mechanism.
+     */
+    repeated int64 supported_enum_values = 8;
+    VehiclePropertyAccess access = 9;
+    bool support_variable_update_rate = 10;
 };
diff --git a/automotive/vehicle/aidl/impl/utils/README.md b/automotive/vehicle/aidl/impl/utils/README.md
index 87bb7e3..255131d 100644
--- a/automotive/vehicle/aidl/impl/utils/README.md
+++ b/automotive/vehicle/aidl/impl/utils/README.md
@@ -57,6 +57,6 @@
 
 Defines many useful utility functions.
 
-## test
+## test_vendor_properties
 
-Defines utility libraries for test only.
+Contains vendor properties used for testing purpose in reference VHAL.
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/ConcurrentQueue.h b/automotive/vehicle/aidl/impl/utils/common/include/ConcurrentQueue.h
index 327c0dc..b636aa3 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/ConcurrentQueue.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/ConcurrentQueue.h
@@ -69,6 +69,19 @@
         mCond.notify_one();
     }
 
+    void push(std::vector<T>&& items) {
+        {
+            std::scoped_lock<std::mutex> lockGuard(mLock);
+            if (!mIsActive) {
+                return;
+            }
+            for (T& item : items) {
+                mQueue.push(std::move(item));
+            }
+        }
+        mCond.notify_one();
+    }
+
     // Deactivates the queue, thus no one can push items to it, also notifies all waiting thread.
     // The items already in the queue could still be flushed even after the queue is deactivated.
     void deactivate() {
@@ -92,6 +105,69 @@
     std::queue<T> mQueue GUARDED_BY(mLock);
 };
 
+template <typename T>
+class BatchingConsumer {
+  private:
+    enum class State {
+        INIT = 0,
+        RUNNING = 1,
+        STOP_REQUESTED = 2,
+        STOPPED = 3,
+    };
+
+  public:
+    BatchingConsumer() : mState(State::INIT) {}
+
+    BatchingConsumer(const BatchingConsumer&) = delete;
+    BatchingConsumer& operator=(const BatchingConsumer&) = delete;
+
+    using OnBatchReceivedFunc = std::function<void(std::vector<T> vec)>;
+
+    void run(ConcurrentQueue<T>* queue, std::chrono::nanoseconds batchInterval,
+             const OnBatchReceivedFunc& func) {
+        mQueue = queue;
+        mBatchInterval = batchInterval;
+
+        mWorkerThread = std::thread(&BatchingConsumer<T>::runInternal, this, func);
+    }
+
+    void requestStop() { mState = State::STOP_REQUESTED; }
+
+    void waitStopped() {
+        if (mWorkerThread.joinable()) {
+            mWorkerThread.join();
+        }
+    }
+
+  private:
+    void runInternal(const OnBatchReceivedFunc& onBatchReceived) {
+        if (mState.exchange(State::RUNNING) == State::INIT) {
+            while (State::RUNNING == mState) {
+                mQueue->waitForItems();
+                if (State::STOP_REQUESTED == mState) break;
+
+                std::this_thread::sleep_for(mBatchInterval);
+                if (State::STOP_REQUESTED == mState) break;
+
+                std::vector<T> items = mQueue->flush();
+
+                if (items.size() > 0) {
+                    onBatchReceived(std::move(items));
+                }
+            }
+        }
+
+        mState = State::STOPPED;
+    }
+
+  private:
+    std::thread mWorkerThread;
+
+    std::atomic<State> mState;
+    std::chrono::nanoseconds mBatchInterval;
+    ConcurrentQueue<T>* mQueue;
+};
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/PropertyUtils.h b/automotive/vehicle/aidl/impl/utils/common/include/PropertyUtils.h
index 7275ba3..78b61f7 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/PropertyUtils.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/PropertyUtils.h
@@ -77,22 +77,6 @@
 constexpr int SEAT_2_LEFT = toInt(propertyutils_impl::VehicleAreaSeat::ROW_2_LEFT);
 constexpr int SEAT_2_RIGHT = toInt(propertyutils_impl::VehicleAreaSeat::ROW_2_RIGHT);
 constexpr int SEAT_2_CENTER = toInt(propertyutils_impl::VehicleAreaSeat::ROW_2_CENTER);
-constexpr int VENDOR_EXTENSION_BOOLEAN_PROPERTY =
-        0x101 | toInt(propertyutils_impl::VehiclePropertyGroup::VENDOR) |
-        toInt(propertyutils_impl::VehiclePropertyType::BOOLEAN) |
-        toInt(propertyutils_impl::VehicleArea::DOOR);
-constexpr int VENDOR_EXTENSION_FLOAT_PROPERTY =
-        0x102 | toInt(propertyutils_impl::VehiclePropertyGroup::VENDOR) |
-        toInt(propertyutils_impl::VehiclePropertyType::FLOAT) |
-        toInt(propertyutils_impl::VehicleArea::SEAT);
-constexpr int VENDOR_EXTENSION_INT_PROPERTY =
-        0x103 | toInt(propertyutils_impl::VehiclePropertyGroup::VENDOR) |
-        toInt(propertyutils_impl::VehiclePropertyType::INT32) |
-        toInt(propertyutils_impl::VehicleArea::WINDOW);
-constexpr int VENDOR_EXTENSION_STRING_PROPERTY =
-        0x104 | toInt(propertyutils_impl::VehiclePropertyGroup::VENDOR) |
-        toInt(propertyutils_impl::VehiclePropertyType::STRING) |
-        toInt(propertyutils_impl::VehicleArea::GLOBAL);
 constexpr int FUEL_DOOR_REAR_LEFT = toInt(propertyutils_impl::PortLocationType::REAR_LEFT);
 constexpr int CHARGE_PORT_FRONT_LEFT = toInt(propertyutils_impl::PortLocationType::FRONT_LEFT);
 constexpr int CHARGE_PORT_REAR_LEFT = toInt(propertyutils_impl::PortLocationType::REAR_LEFT);
@@ -114,11 +98,6 @@
 constexpr int HVAC_RIGHT = SEAT_1_RIGHT | SEAT_2_RIGHT;
 constexpr int HVAC_ALL = HVAC_LEFT | HVAC_RIGHT;
 
-const int32_t HVAC_POWER_PROPERTIES[] = {
-        toInt(propertyutils_impl::VehicleProperty::HVAC_FAN_SPEED),
-        toInt(propertyutils_impl::VehicleProperty::HVAC_FAN_DIRECTION),
-};
-
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/RecurrentTimer.h b/automotive/vehicle/aidl/impl/utils/common/include/RecurrentTimer.h
index cd2b727..712359a 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/RecurrentTimer.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/RecurrentTimer.h
@@ -19,6 +19,8 @@
 
 #include <android-base/thread_annotations.h>
 
+#include <utils/Looper.h>
+#include <atomic>
 #include <memory>
 #include <mutex>
 #include <queue>
@@ -31,6 +33,9 @@
 namespace automotive {
 namespace vehicle {
 
+// Forward declaration
+class RecurrentMessageHandler;
+
 // A thread-safe recurrent timer.
 class RecurrentTimer final {
   public:
@@ -43,49 +48,44 @@
 
     // Registers a recurrent callback for a given interval.
     // Registering the same callback twice will override the interval provided before.
-    void registerTimerCallback(int64_t intervalInNano, std::shared_ptr<Callback> callback);
+    void registerTimerCallback(int64_t intervalInNanos, std::shared_ptr<Callback> callback);
 
     // Unregisters a previously registered recurrent callback.
     void unregisterTimerCallback(std::shared_ptr<Callback> callback);
 
   private:
-    // friend class for unit testing.
+    friend class RecurrentMessageHandler;
+
+    // For unit test
     friend class RecurrentTimerTest;
 
     struct CallbackInfo {
         std::shared_ptr<Callback> callback;
-        int64_t interval;
-        int64_t nextTime;
-        // A flag to indicate whether this CallbackInfo is already outdated and should be ignored.
-        // The reason we need this flag is because we cannot easily remove an element from a heap.
-        bool outdated = false;
-
-        static bool cmp(const std::unique_ptr<CallbackInfo>& lhs,
-                        const std::unique_ptr<CallbackInfo>& rhs);
+        int64_t intervalInNanos;
+        int64_t nextTimeInNanos;
     };
 
+    android::sp<Looper> mLooper;
+    android::sp<RecurrentMessageHandler> mHandler;
+
+    std::atomic<bool> mStopRequested = false;
+    std::atomic<int> mCallbackId = 0;
     std::mutex mLock;
     std::thread mThread;
-    std::condition_variable mCond;
-    bool mStopRequested GUARDED_BY(mLock) = false;
-    // A map to map each callback to its current active CallbackInfo in the mCallbackQueue.
-    std::unordered_map<std::shared_ptr<Callback>, CallbackInfo*> mCallbacks GUARDED_BY(mLock);
-    // A min-heap sorted by nextTime. Note that because we cannot remove arbitrary element from the
-    // heap, a single Callback can have multiple entries in this queue, all but one should be valid.
-    // The rest should be mark as outdated. The valid one is one stored in mCallbacks.
-    std::vector<std::unique_ptr<CallbackInfo>> mCallbackQueue GUARDED_BY(mLock);
+    std::unordered_map<std::shared_ptr<Callback>, int> mIdByCallback GUARDED_BY(mLock);
+    std::unordered_map<int, std::unique_ptr<CallbackInfo>> mCallbackInfoById GUARDED_BY(mLock);
 
-    void loop();
+    void handleMessage(const android::Message& message) EXCLUDES(mLock);
+    int getCallbackIdLocked(std::shared_ptr<Callback> callback) REQUIRES(mLock);
+};
 
-    // Mark the callbackInfo as outdated and should be ignored when popped from the heap.
-    void markOutdatedLocked(CallbackInfo* callback) REQUIRES(mLock);
-    // Remove all outdated callbackInfos from the top of the heap. This function must be called
-    // each time we might introduce outdated elements to the top. We must make sure the heap is
-    // always valid from the top.
-    void removeInvalidCallbackLocked() REQUIRES(mLock);
-    // Gets the next calblack to run (must be valid) from the heap, update its nextTime and put
-    // it back to the heap.
-    std::shared_ptr<Callback> getNextCallbackLocked(int64_t now) REQUIRES(mLock);
+class RecurrentMessageHandler final : public android::MessageHandler {
+  public:
+    RecurrentMessageHandler(RecurrentTimer* timer) { mTimer = timer; }
+    void handleMessage(const android::Message& message) override;
+
+  private:
+    RecurrentTimer* mTimer;
 };
 
 }  // namespace vehicle
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h b/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h
index e6d657d..0c8ebbd 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h
@@ -19,11 +19,17 @@
 
 #include <aidl/android/hardware/automotive/vehicle/AutomaticEmergencyBrakingState.h>
 #include <aidl/android/hardware/automotive/vehicle/BlindSpotWarningState.h>
+#include <aidl/android/hardware/automotive/vehicle/CrossTrafficMonitoringWarningState.h>
 #include <aidl/android/hardware/automotive/vehicle/CruiseControlCommand.h>
 #include <aidl/android/hardware/automotive/vehicle/CruiseControlState.h>
 #include <aidl/android/hardware/automotive/vehicle/CruiseControlType.h>
 #include <aidl/android/hardware/automotive/vehicle/DiagnosticFloatSensorIndex.h>
 #include <aidl/android/hardware/automotive/vehicle/DiagnosticIntegerSensorIndex.h>
+#include <aidl/android/hardware/automotive/vehicle/DriverDistractionState.h>
+#include <aidl/android/hardware/automotive/vehicle/DriverDistractionWarning.h>
+#include <aidl/android/hardware/automotive/vehicle/DriverDrowsinessAttentionState.h>
+#include <aidl/android/hardware/automotive/vehicle/DriverDrowsinessAttentionWarning.h>
+#include <aidl/android/hardware/automotive/vehicle/ElectronicStabilityControlState.h>
 #include <aidl/android/hardware/automotive/vehicle/EmergencyLaneKeepAssistState.h>
 #include <aidl/android/hardware/automotive/vehicle/ErrorState.h>
 #include <aidl/android/hardware/automotive/vehicle/EvConnectorType.h>
@@ -38,11 +44,14 @@
 #include <aidl/android/hardware/automotive/vehicle/GsrComplianceRequirementType.h>
 #include <aidl/android/hardware/automotive/vehicle/HandsOnDetectionDriverState.h>
 #include <aidl/android/hardware/automotive/vehicle/HandsOnDetectionWarning.h>
+#include <aidl/android/hardware/automotive/vehicle/ImpactSensorLocation.h>
 #include <aidl/android/hardware/automotive/vehicle/LaneCenteringAssistCommand.h>
 #include <aidl/android/hardware/automotive/vehicle/LaneCenteringAssistState.h>
 #include <aidl/android/hardware/automotive/vehicle/LaneDepartureWarningState.h>
 #include <aidl/android/hardware/automotive/vehicle/LaneKeepAssistState.h>
 #include <aidl/android/hardware/automotive/vehicle/LocationCharacterization.h>
+#include <aidl/android/hardware/automotive/vehicle/LowSpeedAutomaticEmergencyBrakingState.h>
+#include <aidl/android/hardware/automotive/vehicle/LowSpeedCollisionWarningState.h>
 #include <aidl/android/hardware/automotive/vehicle/Obd2CommonIgnitionMonitors.h>
 #include <aidl/android/hardware/automotive/vehicle/Obd2FuelSystemStatus.h>
 #include <aidl/android/hardware/automotive/vehicle/Obd2FuelType.h>
@@ -55,6 +64,7 @@
 #include <aidl/android/hardware/automotive/vehicle/SetValueResults.h>
 #include <aidl/android/hardware/automotive/vehicle/StatusCode.h>
 #include <aidl/android/hardware/automotive/vehicle/SubscribeOptions.h>
+#include <aidl/android/hardware/automotive/vehicle/VehicleAirbagLocation.h>
 #include <aidl/android/hardware/automotive/vehicle/VehicleApPowerStateReport.h>
 #include <aidl/android/hardware/automotive/vehicle/VehicleApPowerStateReq.h>
 #include <aidl/android/hardware/automotive/vehicle/VehicleArea.h>
@@ -63,6 +73,7 @@
 #include <aidl/android/hardware/automotive/vehicle/VehicleAreaSeat.h>
 #include <aidl/android/hardware/automotive/vehicle/VehicleAreaWheel.h>
 #include <aidl/android/hardware/automotive/vehicle/VehicleAreaWindow.h>
+#include <aidl/android/hardware/automotive/vehicle/VehicleAutonomousState.h>
 #include <aidl/android/hardware/automotive/vehicle/VehicleGear.h>
 #include <aidl/android/hardware/automotive/vehicle/VehicleHvacFanDirection.h>
 #include <aidl/android/hardware/automotive/vehicle/VehicleIgnitionState.h>
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/VehicleObjectPool.h b/automotive/vehicle/aidl/impl/utils/common/include/VehicleObjectPool.h
index 6e812d1..501ce40 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/VehicleObjectPool.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/VehicleObjectPool.h
@@ -235,7 +235,7 @@
 
     bool isDisposable(aidl::android::hardware::automotive::vehicle::VehiclePropertyType type,
                       size_t vectorSize) const {
-        return vectorSize > mMaxRecyclableVectorSize || isComplexType(type);
+        return vectorSize == 0 || vectorSize > mMaxRecyclableVectorSize || isComplexType(type);
     }
 
     RecyclableType obtainDisposable(
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/VehiclePropertyStore.h b/automotive/vehicle/aidl/impl/utils/common/include/VehiclePropertyStore.h
index 3d25cd3..d9599ed 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/VehiclePropertyStore.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/VehiclePropertyStore.h
@@ -48,21 +48,21 @@
 
     enum class EventMode : uint8_t {
         /**
-         * Only invoke OnValueChangeCallback if the new property value (ignoring timestamp) is
-         * different than the existing value.
+         * Only invoke OnValueChangeCallback or OnValuesChangeCallback if the new property value
+         * (ignoring timestamp) is different than the existing value.
          *
          * This should be used for regular cases.
          */
         ON_VALUE_CHANGE,
         /**
-         * Always invoke OnValueChangeCallback.
+         * Always invoke OnValueChangeCallback or OnValuesChangeCallback.
          *
          * This should be used for the special properties that are used for delivering event, e.g.
          * HW_KEY_INPUT.
          */
         ALWAYS,
         /**
-         * Never invoke OnValueChangeCallback.
+         * Never invoke OnValueChangeCallback or OnValuesChangeCalblack.
          *
          * This should be used for continuous property subscription when the sample rate for the
          * subscription is smaller than the refresh rate for the property. E.g., the vehicle speed
@@ -82,6 +82,10 @@
     using OnValueChangeCallback = std::function<void(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue&)>;
 
+    // Callback when one or more property values have been updated or new values added.
+    using OnValuesChangeCallback = std::function<void(
+            std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue>)>;
+
     // Function that used to calculate unique token for given VehiclePropValue.
     using TokenFunction = std::function<int64_t(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value)>;
@@ -92,54 +96,83 @@
     // used as the key.
     void registerProperty(
             const aidl::android::hardware::automotive::vehicle::VehiclePropConfig& config,
-            TokenFunction tokenFunc = nullptr);
+            TokenFunction tokenFunc = nullptr) EXCLUDES(mLock);
 
     // Stores provided value. Returns error if config wasn't registered. If 'updateStatus' is
     // true, the 'status' in 'propValue' would be stored. Otherwise, if this is a new value,
     // 'status' would be initialized to {@code VehiclePropertyStatus::AVAILABLE}, if this is to
     // override an existing value, the status for the existing value would be used for the
     // overridden value.
-    // 'EventMode' controls whether the 'OnValueChangeCallback' will be called for this operation.
+    // 'EventMode' controls whether the 'OnValueChangeCallback' or 'OnValuesChangeCallback' will be
+    // called for this operation.
+    // If 'useCurrentTimestamp' is true, the property value will be set to the current timestamp.
     VhalResult<void> writeValue(VehiclePropValuePool::RecyclableType propValue,
                                 bool updateStatus = false,
-                                EventMode mode = EventMode::ON_VALUE_CHANGE);
+                                EventMode mode = EventMode::ON_VALUE_CHANGE,
+                                bool useCurrentTimestamp = false) EXCLUDES(mLock);
+
+    // Refresh the timestamp for the stored property value for [propId, areaId]. If eventMode is
+    // always, generates the property update event, otherwise, only update the stored timestamp
+    // without generating event. This operation is atomic with other writeValue operations.
+    void refreshTimestamp(int32_t propId, int32_t areaId, EventMode eventMode) EXCLUDES(mLock);
+
+    // Refresh the timestamp for multiple [propId, areaId]s.
+    void refreshTimestamps(
+            std::unordered_map<PropIdAreaId, EventMode, PropIdAreaIdHash> eventModeByPropIdAreaId)
+            EXCLUDES(mLock);
 
     // Remove a given property value from the property store. The 'propValue' would be used to
     // generate the key for the value to remove.
     void removeValue(
-            const aidl::android::hardware::automotive::vehicle::VehiclePropValue& propValue);
+            const aidl::android::hardware::automotive::vehicle::VehiclePropValue& propValue)
+            EXCLUDES(mLock);
 
     // Remove all the values for the property.
-    void removeValuesForProperty(int32_t propId);
+    void removeValuesForProperty(int32_t propId) EXCLUDES(mLock);
 
     // Read all the stored values.
-    std::vector<VehiclePropValuePool::RecyclableType> readAllValues() const;
+    std::vector<VehiclePropValuePool::RecyclableType> readAllValues() const EXCLUDES(mLock);
 
     // Read all the values for the property.
-    ValuesResultType readValuesForProperty(int32_t propId) const;
+    ValuesResultType readValuesForProperty(int32_t propId) const EXCLUDES(mLock);
 
     // Read the value for the requested property. Returns {@code StatusCode::NOT_AVAILABLE} if the
     // value has not been set yet. Returns {@code StatusCode::INVALID_ARG} if the property is
     // not configured.
     ValueResultType readValue(
-            const aidl::android::hardware::automotive::vehicle::VehiclePropValue& request) const;
+            const aidl::android::hardware::automotive::vehicle::VehiclePropValue& request) const
+            EXCLUDES(mLock);
 
     // Read the value for the requested property. Returns {@code StatusCode::NOT_AVAILABLE} if the
     // value has not been set yet. Returns {@code StatusCode::INVALID_ARG} if the property is
     // not configured.
-    ValueResultType readValue(int32_t prop, int32_t area = 0, int64_t token = 0) const;
+    ValueResultType readValue(int32_t prop, int32_t area = 0, int64_t token = 0) const
+            EXCLUDES(mLock);
 
     // Get all property configs.
     std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropConfig> getAllConfigs()
-            const;
+            const EXCLUDES(mLock);
 
-    // Get the property config for the requested property.
+    // Deprecated, use getPropConfig instead. This is unsafe to use if registerProperty overwrites
+    // an existing config.
     android::base::Result<const aidl::android::hardware::automotive::vehicle::VehiclePropConfig*,
                           VhalError>
-    getConfig(int32_t propId) const;
+    getConfig(int32_t propId) const EXCLUDES(mLock);
+
+    // Get the property config for the requested property.
+    android::base::Result<aidl::android::hardware::automotive::vehicle::VehiclePropConfig,
+                          VhalError>
+    getPropConfig(int32_t propId) const EXCLUDES(mLock);
 
     // Set a callback that would be called when a property value has been updated.
-    void setOnValueChangeCallback(const OnValueChangeCallback& callback);
+    void setOnValueChangeCallback(const OnValueChangeCallback& callback) EXCLUDES(mLock);
+
+    // Set a callback that would be called when one or more property values have been updated.
+    // For backward compatibility, this is optional. If this is not set, then multiple property
+    // updates will be delivered through multiple OnValueChangeCallback instead.
+    // It is recommended to set this and batch the property update events for better performance.
+    // If this is set, then OnValueChangeCallback will not be used.
+    void setOnValuesChangeCallback(const OnValuesChangeCallback& callback) EXCLUDES(mLock);
 
     inline std::shared_ptr<VehiclePropValuePool> getValuePool() { return mValuePool; }
 
@@ -168,6 +201,7 @@
     mutable std::mutex mLock;
     std::unordered_map<int32_t, Record> mRecordsByPropId GUARDED_BY(mLock);
     OnValueChangeCallback mOnValueChangeCallback GUARDED_BY(mLock);
+    OnValuesChangeCallback mOnValuesChangeCallback GUARDED_BY(mLock);
 
     const Record* getRecordLocked(int32_t propId) const;
 
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h b/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
index c94bad6..523cac5 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
@@ -124,7 +124,6 @@
             break;  // Valid, but nothing to do.
         default:
             ALOGE("createVehiclePropValue: unknown type: %d", toInt(type));
-            val.reset(nullptr);
     }
     return val;
 }
@@ -329,6 +328,11 @@
     }
 };
 
+inline std::string propIdToString(int32_t propId) {
+    return toString(
+            static_cast<aidl::android::hardware::automotive::vehicle::VehicleProperty>(propId));
+}
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/utils/common/src/RecurrentTimer.cpp b/automotive/vehicle/aidl/impl/utils/common/src/RecurrentTimer.cpp
index c6d3687..8dec695 100644
--- a/automotive/vehicle/aidl/impl/utils/common/src/RecurrentTimer.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/src/RecurrentTimer.cpp
@@ -17,6 +17,7 @@
 #include "RecurrentTimer.h"
 
 #include <utils/Log.h>
+#include <utils/Looper.h>
 #include <utils/SystemClock.h>
 
 #include <inttypes.h>
@@ -27,153 +28,119 @@
 namespace automotive {
 namespace vehicle {
 
+namespace {
+
 using ::android::base::ScopedLockAssertion;
 
+constexpr int INVALID_ID = -1;
+
+}  // namespace
+
 RecurrentTimer::RecurrentTimer() {
-    mThread = std::thread(&RecurrentTimer::loop, this);
+    mHandler = sp<RecurrentMessageHandler>::make(this);
+    mLooper = sp<Looper>::make(/*allowNonCallbacks=*/false);
+    mThread = std::thread([this] {
+        Looper::setForThread(mLooper);
+
+        while (!mStopRequested) {
+            mLooper->pollOnce(/*timeoutMillis=*/-1);
+        }
+    });
 }
 
 RecurrentTimer::~RecurrentTimer() {
-    {
-        std::scoped_lock<std::mutex> lockGuard(mLock);
-        mStopRequested = true;
-    }
-    mCond.notify_one();
+    mStopRequested = true;
+    mLooper->removeMessages(mHandler);
+    mLooper->wake();
     if (mThread.joinable()) {
         mThread.join();
     }
 }
 
-void RecurrentTimer::registerTimerCallback(int64_t intervalInNano,
+int RecurrentTimer::getCallbackIdLocked(std::shared_ptr<RecurrentTimer::Callback> callback) {
+    const auto& it = mIdByCallback.find(callback);
+    if (it != mIdByCallback.end()) {
+        return it->second;
+    }
+    return INVALID_ID;
+}
+
+void RecurrentTimer::registerTimerCallback(int64_t intervalInNanos,
                                            std::shared_ptr<RecurrentTimer::Callback> callback) {
     {
         std::scoped_lock<std::mutex> lockGuard(mLock);
 
+        int callbackId = getCallbackIdLocked(callback);
+
+        if (callbackId == INVALID_ID) {
+            callbackId = mCallbackId++;
+            mIdByCallback.insert({callback, callbackId});
+        } else {
+            ALOGI("Replacing an existing timer callback with a new interval, current: %" PRId64
+                  " ns, new: %" PRId64 " ns",
+                  mCallbackInfoById[callbackId]->intervalInNanos, intervalInNanos);
+            mLooper->removeMessages(mHandler, callbackId);
+        }
+
         // Aligns the nextTime to multiply of interval.
-        int64_t nextTime = ceil(uptimeNanos() / intervalInNano) * intervalInNano;
+        int64_t nextTimeInNanos = ceil(uptimeNanos() / intervalInNanos) * intervalInNanos;
 
         std::unique_ptr<CallbackInfo> info = std::make_unique<CallbackInfo>();
         info->callback = callback;
-        info->interval = intervalInNano;
-        info->nextTime = nextTime;
+        info->intervalInNanos = intervalInNanos;
+        info->nextTimeInNanos = nextTimeInNanos;
+        mCallbackInfoById.insert({callbackId, std::move(info)});
 
-        auto it = mCallbacks.find(callback);
-        if (it != mCallbacks.end()) {
-            ALOGI("Replacing an existing timer callback with a new interval, current: %" PRId64
-                  " ns, new: %" PRId64 " ns",
-                  it->second->interval, intervalInNano);
-            markOutdatedLocked(it->second);
-        }
-        mCallbacks[callback] = info.get();
-        mCallbackQueue.push_back(std::move(info));
-        // Insert the last element into the heap.
-        std::push_heap(mCallbackQueue.begin(), mCallbackQueue.end(), CallbackInfo::cmp);
+        mLooper->sendMessageAtTime(nextTimeInNanos, mHandler, Message(callbackId));
     }
-    mCond.notify_one();
 }
 
 void RecurrentTimer::unregisterTimerCallback(std::shared_ptr<RecurrentTimer::Callback> callback) {
     {
         std::scoped_lock<std::mutex> lockGuard(mLock);
 
-        auto it = mCallbacks.find(callback);
-        if (it == mCallbacks.end()) {
+        int callbackId = getCallbackIdLocked(callback);
+
+        if (callbackId == INVALID_ID) {
             ALOGE("No event found to unregister");
             return;
         }
 
-        markOutdatedLocked(it->second);
-        mCallbacks.erase(it);
-    }
-
-    mCond.notify_one();
-}
-
-void RecurrentTimer::markOutdatedLocked(RecurrentTimer::CallbackInfo* info) {
-    info->outdated = true;
-    info->callback = nullptr;
-    // Make sure the first element is always valid.
-    removeInvalidCallbackLocked();
-}
-
-void RecurrentTimer::removeInvalidCallbackLocked() {
-    while (mCallbackQueue.size() != 0 && mCallbackQueue[0]->outdated) {
-        std::pop_heap(mCallbackQueue.begin(), mCallbackQueue.end(), CallbackInfo::cmp);
-        mCallbackQueue.pop_back();
+        mLooper->removeMessages(mHandler, callbackId);
+        mCallbackInfoById.erase(callbackId);
+        mIdByCallback.erase(callback);
     }
 }
 
-std::shared_ptr<RecurrentTimer::Callback> RecurrentTimer::getNextCallbackLocked(int64_t now) {
-    std::pop_heap(mCallbackQueue.begin(), mCallbackQueue.end(), CallbackInfo::cmp);
-    auto& callbackInfo = mCallbackQueue[mCallbackQueue.size() - 1];
-    auto nextCallback = callbackInfo->callback;
-    // intervalCount is the number of interval we have to advance until we pass now.
-    size_t intervalCount = (now - callbackInfo->nextTime) / callbackInfo->interval + 1;
-    callbackInfo->nextTime += intervalCount * callbackInfo->interval;
-    std::push_heap(mCallbackQueue.begin(), mCallbackQueue.end(), CallbackInfo::cmp);
+void RecurrentTimer::handleMessage(const Message& message) {
+    std::shared_ptr<RecurrentTimer::Callback> callback;
+    {
+        std::scoped_lock<std::mutex> lockGuard(mLock);
 
-    // Make sure the first element is always valid.
-    removeInvalidCallbackLocked();
+        int callbackId = message.what;
 
-    return nextCallback;
-}
-
-void RecurrentTimer::loop() {
-    std::vector<std::shared_ptr<Callback>> callbacksToRun;
-    while (true) {
-        {
-            std::unique_lock<std::mutex> uniqueLock(mLock);
-            ScopedLockAssertion lockAssertion(mLock);
-            // Wait until the timer exits or we have at least one recurrent callback.
-            mCond.wait(uniqueLock, [this] {
-                ScopedLockAssertion lockAssertion(mLock);
-                return mStopRequested || mCallbackQueue.size() != 0;
-            });
-
-            int64_t interval;
-            if (mStopRequested) {
-                return;
-            }
-            // The first element is the nearest next event.
-            int64_t nextTime = mCallbackQueue[0]->nextTime;
-            int64_t now = uptimeNanos();
-
-            if (nextTime > now) {
-                interval = nextTime - now;
-            } else {
-                interval = 0;
-            }
-
-            // Wait for the next event or the timer exits.
-            if (mCond.wait_for(uniqueLock, std::chrono::nanoseconds(interval), [this] {
-                    ScopedLockAssertion lockAssertion(mLock);
-                    return mStopRequested;
-                })) {
-                return;
-            }
-
-            now = uptimeNanos();
-            callbacksToRun.clear();
-            while (mCallbackQueue.size() > 0) {
-                int64_t nextTime = mCallbackQueue[0]->nextTime;
-                if (nextTime > now) {
-                    break;
-                }
-
-                callbacksToRun.push_back(getNextCallbackLocked(now));
-            }
+        auto it = mCallbackInfoById.find(callbackId);
+        if (it == mCallbackInfoById.end()) {
+            ALOGW("The event for callback ID: %d is outdated, ignore", callbackId);
+            return;
         }
 
-        // Do not execute the callback while holding the lock.
-        for (size_t i = 0; i < callbacksToRun.size(); i++) {
-            (*callbacksToRun[i])();
-        }
+        CallbackInfo* callbackInfo = it->second.get();
+        callback = callbackInfo->callback;
+        int64_t nowNanos = uptimeNanos();
+        // intervalCount is the number of interval we have to advance until we pass now.
+        size_t intervalCount =
+                (nowNanos - callbackInfo->nextTimeInNanos) / callbackInfo->intervalInNanos + 1;
+        callbackInfo->nextTimeInNanos += intervalCount * callbackInfo->intervalInNanos;
+
+        mLooper->sendMessageAtTime(callbackInfo->nextTimeInNanos, mHandler, Message(callbackId));
     }
+
+    (*callback)();
 }
 
-bool RecurrentTimer::CallbackInfo::cmp(const std::unique_ptr<RecurrentTimer::CallbackInfo>& lhs,
-                                       const std::unique_ptr<RecurrentTimer::CallbackInfo>& rhs) {
-    return lhs->nextTime > rhs->nextTime;
+void RecurrentMessageHandler::handleMessage(const Message& message) {
+    mTimer->handleMessage(message);
 }
 
 }  // namespace vehicle
diff --git a/automotive/vehicle/aidl/impl/utils/common/src/VehicleObjectPool.cpp b/automotive/vehicle/aidl/impl/utils/common/src/VehicleObjectPool.cpp
index 2480a73..7e02767 100644
--- a/automotive/vehicle/aidl/impl/utils/common/src/VehicleObjectPool.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/src/VehicleObjectPool.cpp
@@ -55,13 +55,6 @@
     int propId = src.prop;
     VehiclePropertyType type = getPropType(propId);
     size_t vectorSize = getVehicleRawValueVectorSize(src.value, type);
-    if (vectorSize == 0 && !isComplexType(type)) {
-        ALOGW("empty vehicle prop value, contains no content");
-        ALOGW("empty vehicle prop value, contains no content, prop: %d", propId);
-        // Return any empty VehiclePropValue.
-        return RecyclableType{new VehiclePropValue{}, mDisposableDeleter};
-    }
-
     auto dest = obtain(type, vectorSize);
 
     dest->prop = propId;
diff --git a/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp b/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
index 646dc0e..6a2a695 100644
--- a/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
@@ -16,6 +16,7 @@
 
 #define LOG_TAG "VehiclePropertyStore"
 #include <utils/Log.h>
+#include <utils/SystemClock.h>
 
 #include "VehiclePropertyStore.h"
 
@@ -107,56 +108,158 @@
 
 VhalResult<void> VehiclePropertyStore::writeValue(VehiclePropValuePool::RecyclableType propValue,
                                                   bool updateStatus,
-                                                  VehiclePropertyStore::EventMode eventMode) {
-    std::scoped_lock<std::mutex> g(mLock);
-
-    int32_t propId = propValue->prop;
-
-    VehiclePropertyStore::Record* record = getRecordLocked(propId);
-    if (record == nullptr) {
-        return StatusError(StatusCode::INVALID_ARG) << "property: " << propId << " not registered";
-    }
-
-    if (!isGlobalProp(propId) && getAreaConfig(*propValue, record->propConfig) == nullptr) {
-        return StatusError(StatusCode::INVALID_ARG)
-               << "no config for property: " << propId << " area: " << propValue->areaId;
-    }
-
-    VehiclePropertyStore::RecordId recId = getRecordIdLocked(*propValue, *record);
+                                                  VehiclePropertyStore::EventMode eventMode,
+                                                  bool useCurrentTimestamp) {
     bool valueUpdated = true;
-    if (auto it = record->values.find(recId); it != record->values.end()) {
-        const VehiclePropValue* valueToUpdate = it->second.get();
-        int64_t oldTimestamp = valueToUpdate->timestamp;
-        VehiclePropertyStatus oldStatus = valueToUpdate->status;
-        // propValue is outdated and drops it.
-        if (oldTimestamp > propValue->timestamp) {
-            return StatusError(StatusCode::INVALID_ARG)
-                   << "outdated timestamp: " << propValue->timestamp;
-        }
-        if (!updateStatus) {
-            propValue->status = oldStatus;
+    VehiclePropValue updatedValue;
+    OnValueChangeCallback onValueChangeCallback = nullptr;
+    OnValuesChangeCallback onValuesChangeCallback = nullptr;
+    int32_t propId;
+    int32_t areaId;
+    {
+        std::scoped_lock<std::mutex> g(mLock);
+
+        // Must set timestamp inside the lock to make sure no other writeValue will update the
+        // the timestamp to a newer one while we are writing this value.
+        if (useCurrentTimestamp) {
+            propValue->timestamp = elapsedRealtimeNano();
         }
 
-        valueUpdated = (valueToUpdate->value != propValue->value ||
-                        valueToUpdate->status != propValue->status ||
-                        valueToUpdate->prop != propValue->prop ||
-                        valueToUpdate->areaId != propValue->areaId);
-    } else if (!updateStatus) {
-        propValue->status = VehiclePropertyStatus::AVAILABLE;
+        propId = propValue->prop;
+        areaId = propValue->areaId;
+
+        VehiclePropertyStore::Record* record = getRecordLocked(propId);
+        if (record == nullptr) {
+            return StatusError(StatusCode::INVALID_ARG)
+                   << "property: " << propId << " not registered";
+        }
+
+        if (!isGlobalProp(propId) && getAreaConfig(*propValue, record->propConfig) == nullptr) {
+            return StatusError(StatusCode::INVALID_ARG)
+                   << "no config for property: " << propId << " area ID: " << propValue->areaId;
+        }
+
+        VehiclePropertyStore::RecordId recId = getRecordIdLocked(*propValue, *record);
+        if (auto it = record->values.find(recId); it != record->values.end()) {
+            const VehiclePropValue* valueToUpdate = it->second.get();
+            int64_t oldTimestampNanos = valueToUpdate->timestamp;
+            VehiclePropertyStatus oldStatus = valueToUpdate->status;
+            // propValue is outdated and drops it.
+            if (oldTimestampNanos > propValue->timestamp) {
+                return StatusError(StatusCode::INVALID_ARG)
+                       << "outdated timestampNanos: " << propValue->timestamp;
+            }
+            if (!updateStatus) {
+                propValue->status = oldStatus;
+            }
+
+            valueUpdated = (valueToUpdate->value != propValue->value ||
+                            valueToUpdate->status != propValue->status ||
+                            valueToUpdate->prop != propValue->prop ||
+                            valueToUpdate->areaId != propValue->areaId);
+        } else if (!updateStatus) {
+            propValue->status = VehiclePropertyStatus::AVAILABLE;
+        }
+
+        record->values[recId] = std::move(propValue);
+
+        if (eventMode == EventMode::NEVER) {
+            return {};
+        }
+        updatedValue = *(record->values[recId]);
+
+        onValuesChangeCallback = mOnValuesChangeCallback;
+        onValueChangeCallback = mOnValueChangeCallback;
     }
 
-    record->values[recId] = std::move(propValue);
-
-    if (eventMode == EventMode::NEVER) {
+    if (onValuesChangeCallback == nullptr && onValueChangeCallback == nullptr) {
+        ALOGW("No callback registered, ignoring property update for propId: %" PRId32
+              ", area ID: %" PRId32,
+              propId, areaId);
         return {};
     }
 
-    if ((eventMode == EventMode::ALWAYS || valueUpdated) && mOnValueChangeCallback != nullptr) {
-        mOnValueChangeCallback(*(record->values[recId]));
+    // Invoke the callback outside the lock to prevent dead-lock.
+    if (eventMode == EventMode::ALWAYS || valueUpdated) {
+        if (onValuesChangeCallback != nullptr) {
+            onValuesChangeCallback({updatedValue});
+        } else {
+            onValueChangeCallback(updatedValue);
+        }
     }
     return {};
 }
 
+void VehiclePropertyStore::refreshTimestamp(int32_t propId, int32_t areaId, EventMode eventMode) {
+    std::unordered_map<PropIdAreaId, EventMode, PropIdAreaIdHash> eventModeByPropIdAreaId;
+    PropIdAreaId propIdAreaId = {
+            .propId = propId,
+            .areaId = areaId,
+    };
+    eventModeByPropIdAreaId[propIdAreaId] = eventMode;
+    refreshTimestamps(eventModeByPropIdAreaId);
+}
+
+void VehiclePropertyStore::refreshTimestamps(
+        std::unordered_map<PropIdAreaId, EventMode, PropIdAreaIdHash> eventModeByPropIdAreaId) {
+    std::vector<VehiclePropValue> updatedValues;
+    OnValuesChangeCallback onValuesChangeCallback = nullptr;
+    OnValueChangeCallback onValueChangeCallback = nullptr;
+    {
+        std::scoped_lock<std::mutex> g(mLock);
+
+        onValuesChangeCallback = mOnValuesChangeCallback;
+        onValueChangeCallback = mOnValueChangeCallback;
+
+        for (const auto& [propIdAreaId, eventMode] : eventModeByPropIdAreaId) {
+            int32_t propId = propIdAreaId.propId;
+            int32_t areaId = propIdAreaId.areaId;
+            VehiclePropertyStore::Record* record = getRecordLocked(propId);
+            if (record == nullptr) {
+                continue;
+            }
+
+            VehiclePropValue propValue = {
+                    .areaId = areaId,
+                    .prop = propId,
+                    .value = {},
+            };
+
+            VehiclePropertyStore::RecordId recId = getRecordIdLocked(propValue, *record);
+            if (auto it = record->values.find(recId); it != record->values.end()) {
+                it->second->timestamp = elapsedRealtimeNano();
+                if (eventMode == EventMode::ALWAYS) {
+                    updatedValues.push_back(*(it->second));
+                }
+            } else {
+                continue;
+            }
+        }
+    }
+
+    // Invoke the callback outside the lock to prevent dead-lock.
+    if (updatedValues.empty()) {
+        return;
+    }
+    if (!onValuesChangeCallback && !onValueChangeCallback) {
+        // If no callback is set, then we don't have to do anything.
+        for (const auto& updateValue : updatedValues) {
+            ALOGW("No callback registered, ignoring property update for propId: %" PRId32
+                  ", area ID: %" PRId32,
+                  updateValue.prop, updateValue.areaId);
+        }
+        return;
+    }
+    if (onValuesChangeCallback != nullptr) {
+        onValuesChangeCallback(updatedValues);
+    } else {
+        // Fallback to use multiple onValueChangeCallback
+        for (const auto& updateValue : updatedValues) {
+            onValueChangeCallback(updateValue);
+        }
+    }
+}
+
 void VehiclePropertyStore::removeValue(const VehiclePropValue& propValue) {
     std::scoped_lock<std::mutex> g(mLock);
 
@@ -263,6 +366,17 @@
     return &record->propConfig;
 }
 
+VhalResult<VehiclePropConfig> VehiclePropertyStore::getPropConfig(int32_t propId) const {
+    std::scoped_lock<std::mutex> g(mLock);
+
+    const VehiclePropertyStore::Record* record = getRecordLocked(propId);
+    if (record == nullptr) {
+        return StatusError(StatusCode::INVALID_ARG) << "property: " << propId << " not registered";
+    }
+
+    return record->propConfig;
+}
+
 void VehiclePropertyStore::setOnValueChangeCallback(
         const VehiclePropertyStore::OnValueChangeCallback& callback) {
     std::scoped_lock<std::mutex> g(mLock);
@@ -270,6 +384,13 @@
     mOnValueChangeCallback = callback;
 }
 
+void VehiclePropertyStore::setOnValuesChangeCallback(
+        const VehiclePropertyStore::OnValuesChangeCallback& callback) {
+    std::scoped_lock<std::mutex> g(mLock);
+
+    mOnValuesChangeCallback = callback;
+}
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/utils/common/test/Android.bp b/automotive/vehicle/aidl/impl/utils/common/test/Android.bp
index 250b331..dd43712 100644
--- a/automotive/vehicle/aidl/impl/utils/common/test/Android.bp
+++ b/automotive/vehicle/aidl/impl/utils/common/test/Android.bp
@@ -27,7 +27,6 @@
         "libgtest",
         "libgmock",
     ],
-    header_libs: ["VehicleHalTestUtilHeaders"],
     defaults: ["VehicleHalDefaults"],
     test_suites: ["device-tests"],
 }
diff --git a/automotive/vehicle/aidl/impl/utils/common/test/RecurrentTimerTest.cpp b/automotive/vehicle/aidl/impl/utils/common/test/RecurrentTimerTest.cpp
index 141efc1..e8ac2a5 100644
--- a/automotive/vehicle/aidl/impl/utils/common/test/RecurrentTimerTest.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/test/RecurrentTimerTest.cpp
@@ -18,6 +18,7 @@
 
 #include <android-base/thread_annotations.h>
 #include <gtest/gtest.h>
+#include <condition_variable>
 
 #include <chrono>
 #include <memory>
@@ -28,6 +29,8 @@
 namespace automotive {
 namespace vehicle {
 
+using ::android::base::ScopedLockAssertion;
+
 class RecurrentTimerTest : public testing::Test {
   public:
     std::shared_ptr<RecurrentTimer::Callback> getCallback(size_t token) {
@@ -35,6 +38,15 @@
             std::scoped_lock<std::mutex> lockGuard(mLock);
 
             mCallbacks.push_back(token);
+            mCond.notify_all();
+        });
+    }
+
+    bool waitForCalledCallbacks(size_t count, size_t timeoutInMs) {
+        std::unique_lock<std::mutex> uniqueLock(mLock);
+        return mCond.wait_for(uniqueLock, std::chrono::milliseconds(timeoutInMs), [this, count] {
+            ScopedLockAssertion lockAssertion(mLock);
+            return mCallbacks.size() >= count;
         });
     }
 
@@ -48,12 +60,18 @@
         mCallbacks.clear();
     }
 
-    size_t countTimerCallbackQueue(RecurrentTimer* timer) {
+    size_t countCallbackInfoById(RecurrentTimer* timer) {
         std::scoped_lock<std::mutex> lockGuard(timer->mLock);
-        return timer->mCallbackQueue.size();
+        return timer->mCallbackInfoById.size();
+    }
+
+    size_t countIdByCallback(RecurrentTimer* timer) {
+        std::scoped_lock<std::mutex> lockGuard(timer->mLock);
+        return timer->mIdByCallback.size();
     }
 
   private:
+    std::condition_variable mCond;
     std::mutex mLock;
     std::vector<size_t> mCallbacks GUARDED_BY(mLock);
 };
@@ -66,12 +84,11 @@
     auto action = getCallback(0);
     timer.registerTimerCallback(interval, action);
 
-    std::this_thread::sleep_for(std::chrono::seconds(1));
+    // Should only takes 1s, use 5s as timeout to be safe.
+    ASSERT_TRUE(waitForCalledCallbacks(/* count= */ 10u, /* timeoutInMs= */ 5000))
+            << "Not enough callbacks called before timeout";
 
     timer.unregisterTimerCallback(action);
-
-    // Theoretically trigger 10 times, but check for at least 9 times to be stable.
-    ASSERT_GE(getCalledCallbacks().size(), static_cast<size_t>(9));
 }
 
 TEST_F(RecurrentTimerTest, testRegisterUnregisterRegister) {
@@ -92,10 +109,14 @@
 
     timer.registerTimerCallback(interval, action);
 
-    std::this_thread::sleep_for(std::chrono::seconds(1));
+    // Should only takes 1s, use 5s as timeout to be safe.
+    ASSERT_TRUE(waitForCalledCallbacks(/* count= */ 10u, /* timeoutInMs= */ 5000))
+            << "Not enough callbacks called before timeout";
 
-    // Theoretically trigger 10 times, but check for at least 9 times to be stable.
-    ASSERT_GE(getCalledCallbacks().size(), static_cast<size_t>(9));
+    timer.unregisterTimerCallback(action);
+
+    ASSERT_EQ(countCallbackInfoById(&timer), 0u);
+    ASSERT_EQ(countIdByCallback(&timer), 0u);
 }
 
 TEST_F(RecurrentTimerTest, testDestroyTimerWithCallback) {
@@ -114,7 +135,9 @@
 
     std::this_thread::sleep_for(std::chrono::milliseconds(200));
 
-    ASSERT_TRUE(getCalledCallbacks().empty());
+    // Should be 0, but in rare cases there might be 1 events in the queue while the timer is
+    // being destroyed.
+    ASSERT_LE(getCalledCallbacks().size(), 1u);
 }
 
 TEST_F(RecurrentTimerTest, testRegisterMultipleCallbacks) {
@@ -132,7 +155,11 @@
     auto action3 = getCallback(3);
     timer.registerTimerCallback(interval3, action3);
 
-    std::this_thread::sleep_for(std::chrono::seconds(1));
+    // In 1s, we should generate 10 + 20 + 33 = 63 events.
+    // Here we are waiting for more events to make sure we receive enough events for each actions.
+    // Use 5s as timeout to be safe.
+    ASSERT_TRUE(waitForCalledCallbacks(/* count= */ 70u, /* timeoutInMs= */ 5000))
+            << "Not enough callbacks called before timeout";
 
     timer.unregisterTimerCallback(action1);
     timer.unregisterTimerCallback(action2);
@@ -152,20 +179,18 @@
             action3Count++;
         }
     }
-    // Theoretically trigger 10 times, but check for at least 9 times to be stable.
-    ASSERT_GE(action1Count, static_cast<size_t>(9));
-    // Theoretically trigger 20 times, but check for at least 15 times to be stable.
-    ASSERT_GE(action2Count, static_cast<size_t>(15));
-    // Theoretically trigger 33 times, but check for at least 25 times to be stable.
-    ASSERT_GE(action3Count, static_cast<size_t>(25));
+
+    ASSERT_GE(action1Count, static_cast<size_t>(10));
+    ASSERT_GE(action2Count, static_cast<size_t>(20));
+    ASSERT_GE(action3Count, static_cast<size_t>(33));
 }
 
 TEST_F(RecurrentTimerTest, testRegisterSameCallbackMultipleTimes) {
     RecurrentTimer timer;
-    // 0.02s
-    int64_t interval1 = 20000000;
-    // 0.01s
-    int64_t interval2 = 10000000;
+    // 0.2s
+    int64_t interval1 = 200'000'000;
+    // 0.1s
+    int64_t interval2 = 100'000'000;
 
     auto action = getCallback(0);
     for (int i = 0; i < 10; i++) {
@@ -175,15 +200,14 @@
 
     clearCalledCallbacks();
 
-    std::this_thread::sleep_for(std::chrono::milliseconds(100));
-
-    // Theoretically trigger 10 times, but check for at least 9 times to be stable.
-    ASSERT_GE(getCalledCallbacks().size(), static_cast<size_t>(9));
+    // Should only takes 1s, use 5s as timeout to be safe.
+    ASSERT_TRUE(waitForCalledCallbacks(/* count= */ 10u, /* timeoutInMs= */ 5000))
+            << "Not enough callbacks called before timeout";
 
     timer.unregisterTimerCallback(action);
 
-    // Make sure there is no item in the callback queue.
-    ASSERT_EQ(countTimerCallbackQueue(&timer), static_cast<size_t>(0));
+    ASSERT_EQ(countCallbackInfoById(&timer), 0u);
+    ASSERT_EQ(countIdByCallback(&timer), 0u);
 }
 
 TEST_F(RecurrentTimerTest, testRegisterCallbackMultipleTimesNoDeadLock) {
diff --git a/automotive/vehicle/aidl/impl/utils/common/test/VehicleObjectPoolTest.cpp b/automotive/vehicle/aidl/impl/utils/common/test/VehicleObjectPoolTest.cpp
index a62532c..6226e89 100644
--- a/automotive/vehicle/aidl/impl/utils/common/test/VehicleObjectPoolTest.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/test/VehicleObjectPoolTest.cpp
@@ -267,6 +267,20 @@
     ASSERT_EQ(*gotValue, prop);
 }
 
+TEST_F(VehicleObjectPoolTest, testObtainCopyInt32ValuesEmptyArray) {
+    VehiclePropValue prop{
+            // INT32_VEC property.
+            .prop = toInt(VehicleProperty::INFO_FUEL_TYPE),
+            .areaId = 2,
+            .timestamp = 3,
+            .value = {.int32Values = {}},
+    };
+    auto gotValue = mValuePool->obtain(prop);
+
+    ASSERT_NE(gotValue, nullptr);
+    ASSERT_EQ(*gotValue, prop);
+}
+
 TEST_F(VehicleObjectPoolTest, testObtainCopyInt64Values) {
     VehiclePropValue prop{
             // INT64_VEC property.
diff --git a/automotive/vehicle/aidl/impl/utils/common/test/VehiclePropertyStoreTest.cpp b/automotive/vehicle/aidl/impl/utils/common/test/VehiclePropertyStoreTest.cpp
index fea5034..6646b7e 100644
--- a/automotive/vehicle/aidl/impl/utils/common/test/VehiclePropertyStoreTest.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/test/VehiclePropertyStoreTest.cpp
@@ -20,6 +20,7 @@
 #include <VehicleUtils.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
+#include <utils/SystemClock.h>
 
 namespace android {
 namespace hardware {
@@ -101,16 +102,16 @@
     ASSERT_EQ(configs.size(), static_cast<size_t>(2));
 }
 
-TEST_F(VehiclePropertyStoreTest, testGetConfig) {
-    VhalResult<const VehiclePropConfig*> result =
-            mStore->getConfig(toInt(VehicleProperty::INFO_FUEL_CAPACITY));
+TEST_F(VehiclePropertyStoreTest, testGetPropConfig) {
+    VhalResult<VehiclePropConfig> result =
+            mStore->getPropConfig(toInt(VehicleProperty::INFO_FUEL_CAPACITY));
 
     ASSERT_RESULT_OK(result);
-    ASSERT_EQ(*(result.value()), mConfigFuelCapacity);
+    ASSERT_EQ(result.value(), mConfigFuelCapacity);
 }
 
-TEST_F(VehiclePropertyStoreTest, testGetConfigWithInvalidPropId) {
-    VhalResult<const VehiclePropConfig*> result = mStore->getConfig(INVALID_PROP_ID);
+TEST_F(VehiclePropertyStoreTest, testGetPropConfigWithInvalidPropId) {
+    VhalResult<VehiclePropConfig> result = mStore->getPropConfig(INVALID_PROP_ID);
 
     EXPECT_FALSE(result.ok()) << "expect error when getting a config for an invalid property ID";
     EXPECT_EQ(result.error().code(), StatusCode::INVALID_ARG);
@@ -509,6 +510,151 @@
     ASSERT_EQ(updatedValue.prop, INVALID_PROP_ID);
 }
 
+TEST_F(VehiclePropertyStoreTest, testPropertyChangeCallbackUseVehiclePropertyStore_noDeadLock) {
+    VehiclePropValue fuelCapacity = {
+            .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
+            .value = {.floatValues = {1.0}},
+    };
+
+    std::vector<VehiclePropConfig> configs;
+
+    mStore->setOnValueChangeCallback(
+            [this, &configs]([[maybe_unused]] const VehiclePropValue& value) {
+                configs = mStore->getAllConfigs();
+            });
+
+    ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(fuelCapacity), /*updateStatus=*/true,
+                                        VehiclePropertyStore::EventMode::ALWAYS));
+    ASSERT_EQ(configs.size(), static_cast<size_t>(2));
+}
+
+TEST_F(VehiclePropertyStoreTest, testOnValuesChangeCallback) {
+    std::vector<VehiclePropValue> updatedValues;
+    VehiclePropValue fuelCapacity = {
+            .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
+            .value = {.floatValues = {1.0}},
+    };
+    ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(fuelCapacity)));
+
+    mStore->setOnValuesChangeCallback(
+            [&updatedValues](std::vector<VehiclePropValue> values) { updatedValues = values; });
+
+    fuelCapacity.value.floatValues[0] = 2.0;
+    fuelCapacity.timestamp = 1;
+
+    ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(fuelCapacity)));
+
+    ASSERT_THAT(updatedValues, ElementsAre(fuelCapacity));
+}
+
+TEST_F(VehiclePropertyStoreTest, testRefreshTimestamp) {
+    std::vector<VehiclePropValue> updatedValues;
+    mStore->setOnValuesChangeCallback(
+            [&updatedValues](std::vector<VehiclePropValue> values) { updatedValues = values; });
+
+    int64_t now = elapsedRealtimeNano();
+    int propId = toInt(VehicleProperty::TIRE_PRESSURE);
+    int areaId = WHEEL_FRONT_LEFT;
+    VehiclePropValue tirePressure = {
+            .prop = propId,
+            .areaId = areaId,
+            .value = {.floatValues = {1.0}},
+    };
+    ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(tirePressure)));
+    updatedValues.clear();
+
+    mStore->refreshTimestamp(propId, areaId, VehiclePropertyStore::EventMode::ALWAYS);
+
+    ASSERT_EQ(updatedValues.size(), 1u);
+    ASSERT_EQ(updatedValues[0].prop, propId);
+    ASSERT_EQ(updatedValues[0].areaId, areaId);
+    ASSERT_EQ(updatedValues[0].value.floatValues[0], 1.0);
+    int64_t timestamp = updatedValues[0].timestamp;
+    ASSERT_GE(timestamp, now);
+
+    auto result = mStore->readValue(tirePressure);
+
+    ASSERT_RESULT_OK(result);
+    ASSERT_EQ((result.value())->timestamp, timestamp);
+}
+
+TEST_F(VehiclePropertyStoreTest, testRefreshTimestamp_eventModeOnValueChange) {
+    std::vector<VehiclePropValue> updatedValues;
+    mStore->setOnValuesChangeCallback(
+            [&updatedValues](std::vector<VehiclePropValue> values) { updatedValues = values; });
+
+    int64_t now = elapsedRealtimeNano();
+    int propId = toInt(VehicleProperty::TIRE_PRESSURE);
+    int areaId = WHEEL_FRONT_LEFT;
+    VehiclePropValue tirePressure = {
+            .prop = propId,
+            .areaId = areaId,
+            .value = {.floatValues = {1.0}},
+    };
+    ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(tirePressure)));
+    updatedValues.clear();
+
+    mStore->refreshTimestamp(propId, areaId, VehiclePropertyStore::EventMode::ON_VALUE_CHANGE);
+
+    ASSERT_EQ(updatedValues.size(), 0u)
+            << "Must generate no property update events if only the timestamp is refreshed";
+
+    auto result = mStore->readValue(tirePressure);
+
+    ASSERT_RESULT_OK(result);
+    ASSERT_GE((result.value())->timestamp, now)
+            << "Even though event mode is on value change, the store timestamp must be updated";
+}
+
+TEST_F(VehiclePropertyStoreTest, testRefreshTimestamps) {
+    std::vector<VehiclePropValue> updatedValues;
+    mStore->setOnValuesChangeCallback(
+            [&updatedValues](std::vector<VehiclePropValue> values) { updatedValues = values; });
+
+    int64_t now = elapsedRealtimeNano();
+    int propId1 = toInt(VehicleProperty::INFO_FUEL_CAPACITY);
+    int areaId1 = 0;
+    VehiclePropValue fuelCapacity = {
+            .prop = propId1,
+            .areaId = areaId1,
+            .value = {.floatValues = {1.0}},
+    };
+    ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(fuelCapacity)));
+
+    int propId2 = toInt(VehicleProperty::TIRE_PRESSURE);
+    int areaId2 = WHEEL_FRONT_LEFT;
+    VehiclePropValue tirePressure = {
+            .prop = propId2,
+            .areaId = areaId2,
+            .value = {.floatValues = {2.0}},
+    };
+    ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(tirePressure)));
+    updatedValues.clear();
+
+    std::unordered_map<PropIdAreaId, VehiclePropertyStore::EventMode, PropIdAreaIdHash>
+            eventModeByPropIdAreaId;
+    eventModeByPropIdAreaId[PropIdAreaId{
+            .propId = propId1,
+            .areaId = areaId1,
+    }] = VehiclePropertyStore::EventMode::ALWAYS;
+    eventModeByPropIdAreaId[PropIdAreaId{
+            .propId = propId2,
+            .areaId = areaId2,
+    }] = VehiclePropertyStore::EventMode::ALWAYS;
+
+    mStore->refreshTimestamps(eventModeByPropIdAreaId);
+
+    ASSERT_EQ(updatedValues.size(), 2u);
+    ASSERT_EQ(updatedValues[0].prop, propId1);
+    ASSERT_EQ(updatedValues[0].areaId, areaId1);
+    ASSERT_EQ(updatedValues[0].value.floatValues[0], 1.0);
+    ASSERT_GE(updatedValues[0].timestamp, now);
+    ASSERT_EQ(updatedValues[1].prop, propId2);
+    ASSERT_EQ(updatedValues[1].areaId, areaId2);
+    ASSERT_EQ(updatedValues[1].value.floatValues[0], 2.0);
+    ASSERT_GE(updatedValues[1].timestamp, now);
+}
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/utils/common/test/VehicleUtilsTest.cpp b/automotive/vehicle/aidl/impl/utils/common/test/VehicleUtilsTest.cpp
index 411539b..9abb2a2 100644
--- a/automotive/vehicle/aidl/impl/utils/common/test/VehicleUtilsTest.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/test/VehicleUtilsTest.cpp
@@ -16,7 +16,6 @@
 
 #include <ConcurrentQueue.h>
 #include <PropertyUtils.h>
-#include <TestPropertyUtils.h>
 #include <VehicleUtils.h>
 
 #include <gtest/gtest.h>
@@ -56,6 +55,9 @@
 constexpr int32_t int64VecProp = toInt(VehicleProperty::WHEEL_TICK);
 constexpr int32_t floatProp = toInt(VehicleProperty::ENV_OUTSIDE_TEMPERATURE);
 constexpr int32_t floatVecProp = toInt(VehicleProperty::HVAC_TEMPERATURE_VALUE_SUGGESTION);
+constexpr int32_t kMixedTypePropertyForTest = 0x1111 | toInt(VehiclePropertyGroup::VENDOR) |
+                                              toInt(VehicleArea::GLOBAL) |
+                                              toInt(VehiclePropertyType::MIXED);
 
 std::vector<InvalidPropValueTestCase> getInvalidPropValuesTestCases() {
     return std::vector<InvalidPropValueTestCase>(
diff --git a/automotive/vehicle/aidl/impl/utils/test/Android.bp b/automotive/vehicle/aidl/impl/utils/test/Android.bp
deleted file mode 100644
index ad9954f..0000000
--- a/automotive/vehicle/aidl/impl/utils/test/Android.bp
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package {
-    default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-cc_library_headers {
-    name: "VehicleHalTestUtilHeaders",
-    vendor: true,
-    header_libs: ["VehicleHalUtilHeaders"],
-    export_include_dirs: ["include"],
-}
diff --git a/automotive/vehicle/aidl/impl/utils/test/include/TestPropertyUtils.h b/automotive/vehicle/aidl/impl/utils/test/include/TestPropertyUtils.h
deleted file mode 100644
index 1400288..0000000
--- a/automotive/vehicle/aidl/impl/utils/test/include/TestPropertyUtils.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef android_hardware_automotive_vehicle_utils_test_include_TestPropertyUtils_H_
-#define android_hardware_automotive_vehicle_utils_test_include_TestPropertyUtils_H_
-
-#include <VehicleHalTypes.h>
-#include <VehicleUtils.h>
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace vehicle {
-
-namespace testpropertyutils_impl {
-
-// These names are not part of the API since we only expose ints.
-using ::aidl::android::hardware::automotive::vehicle::VehicleArea;
-using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
-using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyGroup;
-using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyType;
-
-}  // namespace testpropertyutils_impl
-
-// Converts the system property to the vendor property.
-// WARNING: This is only for the end-to-end testing, Should NOT include in the user build.
-inline constexpr int32_t toVendor(
-        const aidl::android::hardware::automotive::vehicle::VehicleProperty& prop) {
-    return (toInt(prop) & ~toInt(testpropertyutils_impl::VehiclePropertyGroup::MASK)) |
-           toInt(testpropertyutils_impl::VehiclePropertyGroup::VENDOR);
-}
-
-// These properties are used for the end-to-end testing of ClusterHomeService.
-constexpr int32_t VENDOR_CLUSTER_SWITCH_UI =
-        toVendor(testpropertyutils_impl::VehicleProperty::CLUSTER_SWITCH_UI);
-constexpr int32_t VENDOR_CLUSTER_DISPLAY_STATE =
-        toVendor(testpropertyutils_impl::VehicleProperty::CLUSTER_DISPLAY_STATE);
-constexpr int32_t VENDOR_CLUSTER_REPORT_STATE =
-        toVendor(testpropertyutils_impl::VehicleProperty::CLUSTER_REPORT_STATE);
-constexpr int32_t VENDOR_CLUSTER_REQUEST_DISPLAY =
-        toVendor(testpropertyutils_impl::VehicleProperty::CLUSTER_REQUEST_DISPLAY);
-constexpr int32_t VENDOR_CLUSTER_NAVIGATION_STATE =
-        toVendor(testpropertyutils_impl::VehicleProperty::CLUSTER_NAVIGATION_STATE);
-
-// These properties are placeholder properties for developers to test new features without
-// implementing a real property.
-constexpr int32_t PLACEHOLDER_PROPERTY_INT =
-        0x2a11 | toInt(testpropertyutils_impl::VehiclePropertyGroup::VENDOR) |
-        toInt(testpropertyutils_impl::VehicleArea::GLOBAL) |
-        toInt(testpropertyutils_impl::VehiclePropertyType::INT32);
-constexpr int32_t PLACEHOLDER_PROPERTY_FLOAT =
-        0x2a11 | toInt(testpropertyutils_impl::VehiclePropertyGroup::VENDOR) |
-        toInt(testpropertyutils_impl::VehicleArea::GLOBAL) |
-        toInt(testpropertyutils_impl::VehiclePropertyType::FLOAT);
-constexpr int32_t PLACEHOLDER_PROPERTY_BOOLEAN =
-        0x2a11 | toInt(testpropertyutils_impl::VehiclePropertyGroup::VENDOR) |
-        toInt(testpropertyutils_impl::VehicleArea::GLOBAL) |
-        toInt(testpropertyutils_impl::VehiclePropertyType::BOOLEAN);
-constexpr int32_t PLACEHOLDER_PROPERTY_STRING =
-        0x2a11 | toInt(testpropertyutils_impl::VehiclePropertyGroup::VENDOR) |
-        toInt(testpropertyutils_impl::VehicleArea::GLOBAL) |
-        toInt(testpropertyutils_impl::VehiclePropertyType::STRING);
-
-// This property is used for testing LargeParcelable marshalling/unmarhsalling end to end.
-// It acts as an regular property that stores the property value when setting and return the value
-// when getting, except that all the byteValues used in the setValue response would be filled in
-// the reverse order.
-// 0x21702a12
-constexpr int32_t ECHO_REVERSE_BYTES = 0x2a12 |
-                                       toInt(testpropertyutils_impl::VehiclePropertyGroup::VENDOR) |
-                                       toInt(testpropertyutils_impl::VehicleArea::GLOBAL) |
-                                       toInt(testpropertyutils_impl::VehiclePropertyType::BYTES);
-
-// This property is used for testing vendor error codes end to end.
-// 0x21402a13
-constexpr int32_t VENDOR_PROPERTY_ID = 0x2a13 |
-                                       toInt(testpropertyutils_impl::VehiclePropertyGroup::VENDOR) |
-                                       toInt(testpropertyutils_impl::VehicleArea::GLOBAL) |
-                                       toInt(testpropertyutils_impl::VehiclePropertyType::INT32);
-
-// This property is used for test purpose. End to end tests use this property to test set and get
-// method for MIXED type properties.
-constexpr int32_t kMixedTypePropertyForTest =
-        0x1111 | toInt(testpropertyutils_impl::VehiclePropertyGroup::VENDOR) |
-        toInt(testpropertyutils_impl::VehicleArea::GLOBAL) |
-        toInt(testpropertyutils_impl::VehiclePropertyType::MIXED);
-}  // namespace vehicle
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
-
-#endif  // android_hardware_automotive_vehicle_utils_test_include_TestPropertyUtils_H_
diff --git a/automotive/vehicle/aidl/impl/utils/test_vendor_properties/Android.bp b/automotive/vehicle/aidl/impl/utils/test_vendor_properties/Android.bp
new file mode 100644
index 0000000..f7da7e0
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/utils/test_vendor_properties/Android.bp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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"],
+}
+
+filegroup {
+    name: "VhalTestVendorProperties",
+    srcs: [
+        "**/*.aidl",
+    ],
+    visibility: [
+        "//hardware/interfaces/automotive/vehicle/aidl:__subpackages__",
+        "//packages/services/Car:__subpackages__",
+        "//cts/tests/tests/car_permission_tests",
+    ],
+}
diff --git a/automotive/vehicle/aidl/impl/utils/test_vendor_properties/android/hardware/automotive/vehicle/TestVendorProperty.aidl b/automotive/vehicle/aidl/impl/utils/test_vendor_properties/android/hardware/automotive/vehicle/TestVendorProperty.aidl
new file mode 100644
index 0000000..3c877fa
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/utils/test_vendor_properties/android/hardware/automotive/vehicle/TestVendorProperty.aidl
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.vehicle;
+
+/**
+ * Test vendor properties used in reference VHAL implementation.
+ */
+@Backing(type="int")
+enum TestVendorProperty {
+
+    /**
+     * Vendor version of CLUSTER_SWITCH_UI, used for the end-to-end testing of ClusterHomeService.
+     *
+     * VehiclePropertyGroup.VENDOR | VehicleArea.GLOBAL | VehiclePropertyType.INT32,
+     */
+    VENDOR_CLUSTER_SWITCH_UI = 0x0F34 + 0x20000000 + 0x01000000 + 0x00400000,
+
+    /**
+     * Vendor version of CLUSTER_DISPLAY_STATE, used for the end-to-end testing of
+     * ClusterHomeService.
+     *
+     * VehiclePropertyGroup.VENDOR | VehicleArea.GLOBAL | VehiclePropertyType.INT32_VEC
+     */
+    VENDOR_CLUSTER_DISPLAY_STATE = 0x0F35 + 0x20000000 + 0x01000000 + 0x00410000,
+
+    /**
+     * Vendor version of CLUSTER_REPORT_STATE, used for the end-to-end testing of
+     * ClusterHomeService.
+     *
+     * VehiclePropertyGroup.VENDOR | VehicleArea.GLOBAL | VehiclePropertyGroup.MIXED
+     */
+    VENDOR_CLUSTER_REPORT_STATE = 0x0F36 + 0x20000000 + 0x01000000 + 0x00E00000,
+
+    /**
+     * Vendor version of CLUSTER_REQUEST_DISPLAY, used for the end-to-end testing of
+     * ClusterHomeService.
+     *
+     * VehiclePropertyGroup.VENDOR | VehicleArea.GLOBAL | VehiclePropertyType.INT32
+     */
+    VENDOR_CLUSTER_REQUEST_DISPLAY = 0x0F37 + 0x20000000 + 0x01000000 + 0x00400000,
+
+    /**
+     * Vendor version of CLUSTER_NAVIGATION_STATE, used for the end-to-end testing of
+     * ClusterHomeService.
+     *
+     * VehiclePropertyGroup.VENDOR | VehicleArea.GLOBAL | VehiclePropertyType.BYTES
+     */
+    VENDOR_CLUSTER_NAVIGATION_STATE = 0x0F38 + 0x20000000 + 0x01000000 + 0x00700000,
+
+    // These properties are placeholder properties for developers to test new features without
+    // implementing a real property.
+
+    /**
+     * VehiclePropertyGroup.VENDOR | VehicleArea.GLOBAL | VehiclePropertyType.INT32
+     */
+    PLACEHOLDER_PROPERTY_INT = 0x2A11 + 0x20000000 + 0x01000000 + 0x00400000,
+
+    /**
+     * VehiclePropertyGroup.VENDOR | VehicleArea.GLOBAL | VehiclePropertyType.FLOAT
+     */
+    PLACEHOLDER_PROPERTY_FLOAT = 0x2A11 + 0x20000000 + 0x01000000 + 0x00600000,
+
+    /**
+     * VehiclePropertyGroup.VENDOR | VehicleArea.GLOBAL | VehiclePropertyType.BOOLEAN
+     */
+    PLACEHOLDER_PROPERTY_BOOLEAN = 0x2A11 + 0x20000000 + 0x01000000 + 0x00200000,
+
+    /**
+     * VehiclePropertyGroup.VENDOR | VehicleArea.GLOBAL | VehiclePropertyType.STRING
+     */
+    PLACEHOLDER_PROPERTY_STRING = 0x2A11 + 0x20000000 + 0x01000000 + 0x00100000,
+
+    /**
+     * This property is used for testing LargeParcelable marshalling/unmarhsalling end to end.
+     * It acts as an regular property that stores the property value when setting and return the
+     * value when getting, except that all the byteValues used in the setValue response would be
+     * filled in the reverse order.
+     *
+     * This is used in {@code VehicleHalLargeParcelableTest}.
+     *
+     * VehiclePropertyGroup.VENDOR | VehicleArea.GLOBAL | VehiclePropertyType.BYTES
+     *
+     * 0x21702a12
+     */
+    ECHO_REVERSE_BYTES = 0x2A12 + 0x20000000 + 0x01000000 + 0x00700000,
+
+    /**
+     * This property is used for testing vendor error codes end to end.
+     *
+     * VehiclePropertyGroup.VENDOR | VehicleArea.GLOBAL | VehiclePropertyType.INT32
+     *
+     * 0x21402a13
+     */
+    VENDOR_PROPERTY_FOR_ERROR_CODE_TESTING = 0x2A13 + 0x20000000 + 0x01000000 + 0x00400000,
+
+    /**
+     * This property is used for test purpose. End to end tests use this property to test set and
+     * get method for MIXED type properties.
+     *
+     * VehiclePropertyGroup.VENDOR | VehicleArea.GLOBAL | VehiclePropertyGroup.MIXED
+     */
+    MIXED_TYPE_PROPERTY_FOR_TEST = 0x1111 + 0x20000000 + 0x01000000 + 0x00E00000,
+
+    /**
+     * Property used for {@code CarVendorPropertyCustomPermissionTest}.
+     *
+     * VehiclePropertyGroup.VENDOR | VehicleArea.DOOR | VehiclePropertyGroup.BOOLEAN
+     */
+    VENDOR_EXTENSION_BOOLEAN_PROPERTY = 0x0101 + 0x20000000 + 0x06000000 + 0x00200000,
+
+    /**
+     * Property used for {@code CarVendorPropertyCustomPermissionTest}.
+     *
+     * VehiclePropertyGroup.VENDOR | VehicleArea.SEAT | VehiclePropertyGroup.FLOAT
+     */
+    VENDOR_EXTENSION_FLOAT_PROPERTY = 0x102 + 0x20000000 + 0x05000000 + 0x00600000,
+
+    /**
+     * Property used for {@code CarVendorPropertyCustomPermissionTest}.
+     *
+     * VehiclePropertyGroup.VENDOR | VehicleArea.WINDOW | VehiclePropertyGroup.INT32
+     */
+    VENDOR_EXTENSION_INT_PROPERTY = 0x103 + 0x20000000 + 0x03000000 + 0x00400000,
+
+    /**
+     * Property used for {@code CarVendorPropertyCustomPermissionTest}.
+     *
+     * VehiclePropertyGroup.VENDOR | VehicleArea.GLOBAL | VehiclePropertyGroup.STRING
+     */
+    VENDOR_EXTENSION_STRING_PROPERTY = 0x103 + 0x20000000 + 0x01000000 + 0x00100000,
+}
diff --git a/automotive/vehicle/aidl/impl/vhal/Android.bp b/automotive/vehicle/aidl/impl/vhal/Android.bp
index 4feea79..20bba7f 100644
--- a/automotive/vehicle/aidl/impl/vhal/Android.bp
+++ b/automotive/vehicle/aidl/impl/vhal/Android.bp
@@ -19,7 +19,7 @@
 }
 
 cc_binary {
-    name: "android.hardware.automotive.vehicle@V1-default-service",
+    name: "android.hardware.automotive.vehicle@V3-default-service",
     vendor: true,
     defaults: [
         "FakeVehicleHardwareDefaults",
@@ -61,6 +61,7 @@
     ],
     header_libs: [
         "IVehicleHardware",
+        "IVehicleGeneratedHeaders",
     ],
     shared_libs: [
         "libbinder_ndk",
@@ -68,7 +69,7 @@
 }
 
 cc_fuzz {
-    name: "android.hardware.automotive.vehicle@V1-default-service_fuzzer",
+    name: "android.hardware.automotive.vehicle-default-service_fuzzer",
     vendor: true,
     defaults: [
         "FakeVehicleHardwareDefaults",
diff --git a/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h b/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h
index b3f4a0f..addc901 100644
--- a/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h
+++ b/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h
@@ -99,13 +99,10 @@
     std::shared_ptr<const std::function<void(std::vector<ResultType>)>> mResultCallback;
 };
 
-// A class to represent a client that calls {@code IVehicle.subscribe}.
-class SubscriptionClient final : public ConnectedClient {
+class SubscriptionClient {
   public:
-    SubscriptionClient(std::shared_ptr<PendingRequestPool> requestPool, CallbackType callback);
-
-    // Gets the callback to be called when the request for this client has finished.
-    std::shared_ptr<const IVehicleHardware::GetValuesCallback> getResultCallback();
+    using CallbackType =
+            std::shared_ptr<aidl::android::hardware::automotive::vehicle::IVehicleCallback>;
 
     // Marshals the updated values into largeParcelable and sends it through {@code onPropertyEvent}
     // callback.
@@ -119,21 +116,6 @@
             CallbackType callback,
             std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropError>&&
                     vehiclePropErrors);
-
-  protected:
-    // Gets the callback to be called when the request for this client has timeout.
-    std::shared_ptr<const PendingRequestPool::TimeoutCallbackFunc> getTimeoutCallback() override;
-
-  private:
-    // The following members are only initialized during construction.
-    std::shared_ptr<const PendingRequestPool::TimeoutCallbackFunc> mTimeoutCallback;
-    std::shared_ptr<const IVehicleHardware::GetValuesCallback> mResultCallback;
-    std::shared_ptr<const IVehicleHardware::PropertyChangeCallback> mPropertyChangeCallback;
-
-    static void onGetValueResults(
-            const void* clientId, CallbackType callback,
-            std::shared_ptr<PendingRequestPool> requestPool,
-            std::vector<aidl::android::hardware::automotive::vehicle::GetValueResult> results);
 };
 
 }  // namespace vehicle
diff --git a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
index 74ad7ea..250b30c 100644
--- a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
+++ b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
@@ -49,6 +49,9 @@
 
     explicit DefaultVehicleHal(std::unique_ptr<IVehicleHardware> hardware);
 
+    // Test-only
+    DefaultVehicleHal(std::unique_ptr<IVehicleHardware> hardware, int32_t testInterfaceVersion);
+
     ~DefaultVehicleHal();
 
     ndk::ScopedAStatus getAllPropConfigs(
@@ -90,39 +93,6 @@
             GetSetValuesClient<aidl::android::hardware::automotive::vehicle::SetValueResult,
                                aidl::android::hardware::automotive::vehicle::SetValueResults>;
 
-    // A thread safe class to maintain an increasing request ID for each subscribe client. This
-    // class is safe to pass to async callbacks.
-    class SubscribeIdByClient {
-      public:
-        int64_t getId(const CallbackType& callback);
-
-      private:
-        std::mutex mLock;
-        std::unordered_map<const AIBinder*, int64_t> mIds GUARDED_BY(mLock);
-    };
-
-    // A thread safe class to store all subscribe clients. This class is safe to pass to async
-    // callbacks.
-    class SubscriptionClients {
-      public:
-        SubscriptionClients(std::shared_ptr<PendingRequestPool> pool) : mPendingRequestPool(pool) {}
-
-        std::shared_ptr<SubscriptionClient> maybeAddClient(const CallbackType& callback);
-
-        std::shared_ptr<SubscriptionClient> getClient(const CallbackType& callback);
-
-        void removeClient(const AIBinder* clientId);
-
-        size_t countClients();
-
-      private:
-        std::mutex mLock;
-        std::unordered_map<const AIBinder*, std::shared_ptr<SubscriptionClient>> mClients
-                GUARDED_BY(mLock);
-        // PendingRequestPool is thread-safe.
-        std::shared_ptr<PendingRequestPool> mPendingRequestPool;
-    };
-
     // A wrapper for binder lifecycle operations to enable stubbing for test.
     class BinderLifecycleInterface {
       public:
@@ -177,6 +147,17 @@
     std::shared_ptr<PendingRequestPool> mPendingRequestPool;
     // SubscriptionManager is thread-safe.
     std::shared_ptr<SubscriptionManager> mSubscriptionManager;
+    // ConcurrentQueue is thread-safe.
+    std::shared_ptr<ConcurrentQueue<aidl::android::hardware::automotive::vehicle::VehiclePropValue>>
+            mBatchedEventQueue;
+    // BatchingConsumer is thread-safe.
+    std::shared_ptr<
+            BatchingConsumer<aidl::android::hardware::automotive::vehicle::VehiclePropValue>>
+            mPropertyChangeEventsBatchingConsumer;
+    // Only set once during initialization.
+    std::chrono::nanoseconds mEventBatchingWindow;
+    // Only used for testing.
+    int32_t mTestInterfaceVersion = 0;
 
     std::mutex mLock;
     std::unordered_map<const AIBinder*, std::unique_ptr<OnBinderDiedContext>> mOnBinderDiedContexts
@@ -185,8 +166,6 @@
             GUARDED_BY(mLock);
     std::unordered_map<const AIBinder*, std::shared_ptr<SetValuesClient>> mSetValuesClients
             GUARDED_BY(mLock);
-    // SubscriptionClients is thread-safe.
-    std::shared_ptr<SubscriptionClients> mSubscriptionClients;
     // mBinderLifecycleHandler is only going to be changed in test.
     std::unique_ptr<BinderLifecycleInterface> mBinderLifecycleHandler;
 
@@ -217,6 +196,10 @@
             const std::vector<aidl::android::hardware::automotive::vehicle::SubscribeOptions>&
                     options);
 
+    VhalResult<void> checkPermissionHelper(
+            const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value,
+            aidl::android::hardware::automotive::vehicle::VehiclePropertyAccess accessToTest) const;
+
     VhalResult<void> checkReadPermission(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const;
 
@@ -242,6 +225,23 @@
     // mBinderEvents.
     void onBinderDiedUnlinkedHandler();
 
+    size_t countSubscribeClients();
+
+    // Handles the property change events in batch.
+    void handleBatchedPropertyEvents(
+            std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue>&&
+                    batchedEvents);
+
+    int32_t getVhalInterfaceVersion();
+
+    // Puts the property change events into a queue so that they can handled in batch.
+    static void batchPropertyChangeEvent(
+            const std::weak_ptr<ConcurrentQueue<
+                    aidl::android::hardware::automotive::vehicle::VehiclePropValue>>&
+                    batchedEventQueue,
+            std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue>&&
+                    updatedValues);
+
     // Gets or creates a {@code T} object for the client to or from {@code clients}.
     template <class T>
     static std::shared_ptr<T> getOrCreateClient(
@@ -250,7 +250,7 @@
 
     static void onPropertyChangeEvent(
             const std::weak_ptr<SubscriptionManager>& subscriptionManager,
-            const std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue>&
+            std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue>&&
                     updatedValues);
 
     static void onPropertySetErrorEvent(
diff --git a/automotive/vehicle/aidl/impl/vhal/include/SubscriptionManager.h b/automotive/vehicle/aidl/impl/vhal/include/SubscriptionManager.h
index 301d56c..5053c96 100644
--- a/automotive/vehicle/aidl/impl/vhal/include/SubscriptionManager.h
+++ b/automotive/vehicle/aidl/impl/vhal/include/SubscriptionManager.h
@@ -36,20 +36,29 @@
 namespace automotive {
 namespace vehicle {
 
+// A structure to represent subscription config for one subscription client.
+struct SubConfig {
+    float sampleRateHz;
+    bool enableVur;
+};
+
 // A class to represent all the subscription configs for a continuous [propId, areaId].
 class ContSubConfigs final {
   public:
     using ClientIdType = const AIBinder*;
 
-    void addClient(const ClientIdType& clientId, float sampleRateHz);
+    void addClient(const ClientIdType& clientId, float sampleRateHz, bool enableVur);
     void removeClient(const ClientIdType& clientId);
     float getMaxSampleRateHz() const;
+    bool isVurEnabled() const;
+    bool isVurEnabledForClient(const ClientIdType& clientId);
 
   private:
     float mMaxSampleRateHz = 0.;
-    std::unordered_map<ClientIdType, float> mSampleRateHzByClient;
+    bool mEnableVur;
+    std::unordered_map<ClientIdType, SubConfig> mConfigByClient;
 
-    void refreshMaxSampleRateHz();
+    void refreshCombinedConfig();
 };
 
 // A thread-safe subscription manager that manages all VHAL subscriptions.
@@ -58,6 +67,7 @@
     using ClientIdType = const AIBinder*;
     using CallbackType =
             std::shared_ptr<aidl::android::hardware::automotive::vehicle::IVehicleCallback>;
+    using VehiclePropValue = aidl::android::hardware::automotive::vehicle::VehiclePropValue;
 
     explicit SubscriptionManager(IVehicleHardware* vehicleHardware);
     ~SubscriptionManager();
@@ -92,12 +102,8 @@
     // For a list of updated properties, returns a map that maps clients subscribing to
     // the updated properties to a list of updated values. This would only return on-change property
     // clients that should be informed for the given updated values.
-    std::unordered_map<
-            CallbackType,
-            std::vector<const aidl::android::hardware::automotive::vehicle::VehiclePropValue*>>
-    getSubscribedClients(
-            const std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue>&
-                    updatedValues);
+    std::unordered_map<CallbackType, std::vector<VehiclePropValue>> getSubscribedClients(
+            std::vector<VehiclePropValue>&& updatedValues);
 
     // For a list of set property error events, returns a map that maps clients subscribing to the
     // properties to a list of errors for each client.
@@ -105,6 +111,9 @@
                        std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropError>>
     getSubscribedClientsForErrorEvents(const std::vector<SetValueErrorEvent>& errorEvents);
 
+    // Returns the number of subscribed clients.
+    size_t countClients();
+
     // Checks whether the sample rate is valid.
     static bool checkSampleRateHz(float sampleRateHz);
 
@@ -114,28 +123,60 @@
 
     IVehicleHardware* mVehicleHardware;
 
+    struct VehiclePropValueHashPropIdAreaId {
+        inline size_t operator()(const VehiclePropValue& vehiclePropValue) const {
+            size_t res = 0;
+            hashCombine(res, vehiclePropValue.prop);
+            hashCombine(res, vehiclePropValue.areaId);
+            return res;
+        }
+    };
+
+    struct VehiclePropValueEqualPropIdAreaId {
+        inline bool operator()(const VehiclePropValue& left, const VehiclePropValue& right) const {
+            return left.prop == right.prop && left.areaId == right.areaId;
+        }
+    };
+
     mutable std::mutex mLock;
     std::unordered_map<PropIdAreaId, std::unordered_map<ClientIdType, CallbackType>,
                        PropIdAreaIdHash>
-            mClientsByPropIdArea GUARDED_BY(mLock);
+            mClientsByPropIdAreaId GUARDED_BY(mLock);
     std::unordered_map<ClientIdType, std::unordered_set<PropIdAreaId, PropIdAreaIdHash>>
             mSubscribedPropsByClient GUARDED_BY(mLock);
     std::unordered_map<PropIdAreaId, ContSubConfigs, PropIdAreaIdHash> mContSubConfigsByPropIdArea
             GUARDED_BY(mLock);
+    std::unordered_map<CallbackType,
+                       std::unordered_set<VehiclePropValue, VehiclePropValueHashPropIdAreaId,
+                                          VehiclePropValueEqualPropIdAreaId>>
+            mContSubValuesByCallback GUARDED_BY(mLock);
 
     VhalResult<void> addContinuousSubscriberLocked(const ClientIdType& clientId,
                                                    const PropIdAreaId& propIdAreaId,
-                                                   float sampleRateHz) REQUIRES(mLock);
+                                                   float sampleRateHz, bool enableVur)
+            REQUIRES(mLock);
+    VhalResult<void> addOnChangeSubscriberLocked(const PropIdAreaId& propIdAreaId) REQUIRES(mLock);
+    // Removes the subscription client for the continuous [propId, areaId].
     VhalResult<void> removeContinuousSubscriberLocked(const ClientIdType& clientId,
                                                       const PropIdAreaId& propIdAreaId)
             REQUIRES(mLock);
+    // Removes one subscription client for the on-change [propId, areaId].
+    VhalResult<void> removeOnChangeSubscriberLocked(const PropIdAreaId& propIdAreaId)
+            REQUIRES(mLock);
 
-    VhalResult<void> updateContSubConfigs(const PropIdAreaId& PropIdAreaId,
-                                          const ContSubConfigs& newConfig) REQUIRES(mLock);
+    VhalResult<void> updateContSubConfigsLocked(const PropIdAreaId& PropIdAreaId,
+                                                const ContSubConfigs& newConfig) REQUIRES(mLock);
+
+    VhalResult<void> unsubscribePropIdAreaIdLocked(SubscriptionManager::ClientIdType clientId,
+                                                   const PropIdAreaId& propIdAreaId)
+            REQUIRES(mLock);
 
     // Checks whether the manager is empty. For testing purpose.
     bool isEmpty();
 
+    bool isValueUpdatedLocked(const CallbackType& callback, const VehiclePropValue& value)
+            REQUIRES(mLock);
+
     // Get the interval in nanoseconds accroding to sample rate.
     static android::base::Result<int64_t> getIntervalNanos(float sampleRateHz);
 };
diff --git a/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp b/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp
index fb23a25..35b93d2 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp
@@ -250,36 +250,6 @@
 template class GetSetValuesClient<GetValueResult, GetValueResults>;
 template class GetSetValuesClient<SetValueResult, SetValueResults>;
 
-SubscriptionClient::SubscriptionClient(std::shared_ptr<PendingRequestPool> requestPool,
-                                       std::shared_ptr<IVehicleCallback> callback)
-    : ConnectedClient(requestPool, callback) {
-    mTimeoutCallback = std::make_shared<const PendingRequestPool::TimeoutCallbackFunc>(
-            [](std::unordered_set<int64_t> timeoutIds) {
-                for (int64_t id : timeoutIds) {
-                    ALOGW("subscribe: requests with IDs: %" PRId64
-                          " has timed-out, not client informed, "
-                          "possibly one of recurrent requests for this subscription failed",
-                          id);
-                }
-            });
-    auto requestPoolCopy = mRequestPool;
-    const void* clientId = reinterpret_cast<const void*>(this);
-    mResultCallback = std::make_shared<const IVehicleHardware::GetValuesCallback>(
-            [clientId, callback, requestPoolCopy](std::vector<GetValueResult> results) {
-                onGetValueResults(clientId, callback, requestPoolCopy, results);
-            });
-}
-
-std::shared_ptr<const std::function<void(std::vector<GetValueResult>)>>
-SubscriptionClient::getResultCallback() {
-    return mResultCallback;
-}
-
-std::shared_ptr<const PendingRequestPool::TimeoutCallbackFunc>
-SubscriptionClient::getTimeoutCallback() {
-    return mTimeoutCallback;
-}
-
 void SubscriptionClient::sendUpdatedValues(std::shared_ptr<IVehicleCallback> callback,
                                            std::vector<VehiclePropValue>&& updatedValues) {
     if (updatedValues.empty()) {
@@ -336,43 +306,6 @@
     }
 }
 
-void SubscriptionClient::onGetValueResults(const void* clientId,
-                                           std::shared_ptr<IVehicleCallback> callback,
-                                           std::shared_ptr<PendingRequestPool> requestPool,
-                                           std::vector<GetValueResult> results) {
-    std::unordered_set<int64_t> requestIds;
-    for (const auto& result : results) {
-        requestIds.insert(result.requestId);
-    }
-
-    auto finishedRequests = requestPool->tryFinishRequests(clientId, requestIds);
-    std::vector<VehiclePropValue> propValues;
-    for (auto& result : results) {
-        int64_t requestId = result.requestId;
-        if (finishedRequests.find(requestId) == finishedRequests.end()) {
-            ALOGE("subscribe[%" PRId64
-                  "]: no pending request for the result from hardware, "
-                  "possibly already time-out",
-                  requestId);
-            continue;
-        }
-        if (result.status != StatusCode::OK) {
-            ALOGE("subscribe[%" PRId64
-                  "]: hardware returns non-ok status for getValues, status: "
-                  "%d",
-                  requestId, toInt(result.status));
-            continue;
-        }
-        if (!result.prop.has_value()) {
-            ALOGE("subscribe[%" PRId64 "]: no prop value in getValues result", requestId);
-            continue;
-        }
-        propValues.push_back(std::move(result.prop.value()));
-    }
-
-    sendUpdatedValues(callback, std::move(propValues));
-}
-
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
index 0d5c070..cc5edcc 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
@@ -22,6 +22,7 @@
 #include <LargeParcelableBase.h>
 #include <VehicleHalTypes.h>
 #include <VehicleUtils.h>
+#include <VersionForVehicleProperty.h>
 
 #include <android-base/result.h>
 #include <android-base/stringprintf.h>
@@ -32,6 +33,7 @@
 #include <utils/Trace.h>
 
 #include <inttypes.h>
+#include <chrono>
 #include <set>
 #include <unordered_set>
 
@@ -60,6 +62,7 @@
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyChangeMode;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyStatus;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
+using ::aidl::android::hardware::automotive::vehicle::VersionForVehicleProperty;
 using ::android::automotive::car_binder_lib::LargeParcelableBase;
 using ::android::base::Error;
 using ::android::base::expected;
@@ -92,57 +95,46 @@
 
 }  // namespace
 
-std::shared_ptr<SubscriptionClient> DefaultVehicleHal::SubscriptionClients::maybeAddClient(
-        const CallbackType& callback) {
-    std::scoped_lock<std::mutex> lockGuard(mLock);
-    return getOrCreateClient(&mClients, callback, mPendingRequestPool);
-}
-
-std::shared_ptr<SubscriptionClient> DefaultVehicleHal::SubscriptionClients::getClient(
-        const CallbackType& callback) {
-    std::scoped_lock<std::mutex> lockGuard(mLock);
-    const AIBinder* clientId = callback->asBinder().get();
-    if (mClients.find(clientId) == mClients.end()) {
-        return nullptr;
-    }
-    return mClients[clientId];
-}
-
-int64_t DefaultVehicleHal::SubscribeIdByClient::getId(const CallbackType& callback) {
-    std::scoped_lock<std::mutex> lockGuard(mLock);
-    // This would be initialized to 0 if callback does not exist in the map.
-    int64_t subscribeId = (mIds[callback->asBinder().get()])++;
-    return subscribeId;
-}
-
-void DefaultVehicleHal::SubscriptionClients::removeClient(const AIBinder* clientId) {
-    std::scoped_lock<std::mutex> lockGuard(mLock);
-    mClients.erase(clientId);
-}
-
-size_t DefaultVehicleHal::SubscriptionClients::countClients() {
-    std::scoped_lock<std::mutex> lockGuard(mLock);
-    return mClients.size();
-}
-
 DefaultVehicleHal::DefaultVehicleHal(std::unique_ptr<IVehicleHardware> vehicleHardware)
+    : DefaultVehicleHal(std::move(vehicleHardware), /* testInterfaceVersion= */ 0){};
+
+DefaultVehicleHal::DefaultVehicleHal(std::unique_ptr<IVehicleHardware> vehicleHardware,
+                                     int32_t testInterfaceVersion)
     : mVehicleHardware(std::move(vehicleHardware)),
-      mPendingRequestPool(std::make_shared<PendingRequestPool>(TIMEOUT_IN_NANO)) {
+      mPendingRequestPool(std::make_shared<PendingRequestPool>(TIMEOUT_IN_NANO)),
+      mTestInterfaceVersion(testInterfaceVersion) {
     if (!getAllPropConfigsFromHardware()) {
         return;
     }
 
-    mSubscriptionClients = std::make_shared<SubscriptionClients>(mPendingRequestPool);
-
-    auto subscribeIdByClient = std::make_shared<SubscribeIdByClient>();
     IVehicleHardware* vehicleHardwarePtr = mVehicleHardware.get();
     mSubscriptionManager = std::make_shared<SubscriptionManager>(vehicleHardwarePtr);
+    mEventBatchingWindow = mVehicleHardware->getPropertyOnChangeEventBatchingWindow();
+    if (mEventBatchingWindow != std::chrono::nanoseconds(0)) {
+        mBatchedEventQueue = std::make_shared<ConcurrentQueue<VehiclePropValue>>();
+        mPropertyChangeEventsBatchingConsumer =
+                std::make_shared<BatchingConsumer<VehiclePropValue>>();
+        mPropertyChangeEventsBatchingConsumer->run(
+                mBatchedEventQueue.get(), mEventBatchingWindow,
+                [this](std::vector<VehiclePropValue> batchedEvents) {
+                    handleBatchedPropertyEvents(std::move(batchedEvents));
+                });
+    }
 
+    std::weak_ptr<ConcurrentQueue<VehiclePropValue>> batchedEventQueueCopy = mBatchedEventQueue;
+    std::chrono::nanoseconds eventBatchingWindow = mEventBatchingWindow;
     std::weak_ptr<SubscriptionManager> subscriptionManagerCopy = mSubscriptionManager;
     mVehicleHardware->registerOnPropertyChangeEvent(
             std::make_unique<IVehicleHardware::PropertyChangeCallback>(
-                    [subscriptionManagerCopy](std::vector<VehiclePropValue> updatedValues) {
-                        onPropertyChangeEvent(subscriptionManagerCopy, updatedValues);
+                    [subscriptionManagerCopy, batchedEventQueueCopy,
+                     eventBatchingWindow](std::vector<VehiclePropValue> updatedValues) {
+                        if (eventBatchingWindow != std::chrono::nanoseconds(0)) {
+                            batchPropertyChangeEvent(batchedEventQueueCopy,
+                                                     std::move(updatedValues));
+                        } else {
+                            onPropertyChangeEvent(subscriptionManagerCopy,
+                                                  std::move(updatedValues));
+                        }
                     }));
     mVehicleHardware->registerOnPropertySetErrorEvent(
             std::make_unique<IVehicleHardware::PropertySetErrorCallback>(
@@ -175,26 +167,48 @@
     // mRecurrentAction uses pointer to mVehicleHardware, so it has to be unregistered before
     // mVehicleHardware.
     mRecurrentTimer.unregisterTimerCallback(mRecurrentAction);
+
+    if (mBatchedEventQueue) {
+        // mPropertyChangeEventsBatchingConsumer uses mSubscriptionManager and mBatchedEventQueue.
+        mBatchedEventQueue->deactivate();
+        mPropertyChangeEventsBatchingConsumer->requestStop();
+        mPropertyChangeEventsBatchingConsumer->waitStopped();
+        mPropertyChangeEventsBatchingConsumer.reset();
+        mBatchedEventQueue.reset();
+    }
+
     // mSubscriptionManager uses pointer to mVehicleHardware, so it has to be destroyed before
     // mVehicleHardware.
     mSubscriptionManager.reset();
     mVehicleHardware.reset();
 }
 
+void DefaultVehicleHal::batchPropertyChangeEvent(
+        const std::weak_ptr<ConcurrentQueue<VehiclePropValue>>& batchedEventQueue,
+        std::vector<VehiclePropValue>&& updatedValues) {
+    auto batchedEventQueueStrong = batchedEventQueue.lock();
+    if (batchedEventQueueStrong == nullptr) {
+        ALOGW("the batched property events queue is destroyed, DefaultVehicleHal is ending");
+        return;
+    }
+    batchedEventQueueStrong->push(std::move(updatedValues));
+}
+
+void DefaultVehicleHal::handleBatchedPropertyEvents(std::vector<VehiclePropValue>&& batchedEvents) {
+    onPropertyChangeEvent(mSubscriptionManager, std::move(batchedEvents));
+}
+
 void DefaultVehicleHal::onPropertyChangeEvent(
         const std::weak_ptr<SubscriptionManager>& subscriptionManager,
-        const std::vector<VehiclePropValue>& updatedValues) {
+        std::vector<VehiclePropValue>&& updatedValues) {
+    ATRACE_CALL();
     auto manager = subscriptionManager.lock();
     if (manager == nullptr) {
         ALOGW("the SubscriptionManager is destroyed, DefaultVehicleHal is ending");
         return;
     }
-    auto updatedValuesByClients = manager->getSubscribedClients(updatedValues);
-    for (const auto& [callback, valuePtrs] : updatedValuesByClients) {
-        std::vector<VehiclePropValue> values;
-        for (const VehiclePropValue* valuePtr : valuePtrs) {
-            values.push_back(*valuePtr);
-        }
+    auto updatedValuesByClients = manager->getSubscribedClients(std::move(updatedValues));
+    for (auto& [callback, values] : updatedValuesByClients) {
         SubscriptionClient::sendUpdatedValues(callback, std::move(values));
     }
 }
@@ -262,7 +276,6 @@
     ALOGD("binder died, client ID: %p", clientId);
     mSetValuesClients.erase(clientId);
     mGetValuesClients.erase(clientId);
-    mSubscriptionClients->removeClient(clientId);
     mSubscriptionManager->unsubscribe(clientId);
 }
 
@@ -301,22 +314,51 @@
 DefaultVehicleHal::getOrCreateClient<DefaultVehicleHal::SetValuesClient>(
         std::unordered_map<const AIBinder*, std::shared_ptr<SetValuesClient>>* clients,
         const CallbackType& callback, std::shared_ptr<PendingRequestPool> pendingRequestPool);
-template std::shared_ptr<SubscriptionClient>
-DefaultVehicleHal::getOrCreateClient<SubscriptionClient>(
-        std::unordered_map<const AIBinder*, std::shared_ptr<SubscriptionClient>>* clients,
-        const CallbackType& callback, std::shared_ptr<PendingRequestPool> pendingRequestPool);
 
 void DefaultVehicleHal::setTimeout(int64_t timeoutInNano) {
     mPendingRequestPool = std::make_unique<PendingRequestPool>(timeoutInNano);
 }
 
+int32_t DefaultVehicleHal::getVhalInterfaceVersion() {
+    if (mTestInterfaceVersion != 0) {
+        return mTestInterfaceVersion;
+    }
+    int32_t myVersion = 0;
+    getInterfaceVersion(&myVersion);
+    return myVersion;
+}
+
 bool DefaultVehicleHal::getAllPropConfigsFromHardware() {
     auto configs = mVehicleHardware->getAllPropertyConfigs();
+    std::vector<VehiclePropConfig> filteredConfigs;
+    int32_t myVersion = getVhalInterfaceVersion();
     for (auto& config : configs) {
+        if (!isSystemProp(config.prop)) {
+            filteredConfigs.push_back(std::move(config));
+            continue;
+        }
+        VehicleProperty property = static_cast<VehicleProperty>(config.prop);
+        std::string propertyName = aidl::android::hardware::automotive::vehicle::toString(property);
+        auto it = VersionForVehicleProperty.find(property);
+        if (it == VersionForVehicleProperty.end()) {
+            ALOGE("The property: %s is not a supported system property, ignore",
+                  propertyName.c_str());
+            continue;
+        }
+        int requiredVersion = it->second;
+        if (myVersion < requiredVersion) {
+            ALOGE("The property: %s is not supported for current client VHAL version, "
+                  "require %d, current version: %d, ignore",
+                  propertyName.c_str(), requiredVersion, myVersion);
+            continue;
+        }
+        filteredConfigs.push_back(std::move(config));
+    }
+    for (auto& config : filteredConfigs) {
         mConfigsByPropId[config.prop] = config;
     }
     VehiclePropConfigs vehiclePropConfigs;
-    vehiclePropConfigs.payloads = std::move(configs);
+    vehiclePropConfigs.payloads = std::move(filteredConfigs);
     auto result = LargeParcelableBase::parcelableToStableLargeParcelable(vehiclePropConfigs);
     if (!result.ok()) {
         ALOGE("failed to convert configs to shared memory file, error: %s, code: %d",
@@ -411,9 +453,9 @@
                     .status = getErrorCode(result),
                     .prop = {},
             });
-        } else {
-            hardwareRequests.push_back(request);
+            continue;
         }
+        hardwareRequests.push_back(request);
     }
 
     // The set of request Ids that we would send to hardware.
@@ -604,6 +646,23 @@
     return vectorToStableLargeParcelable(std::move(configs), output);
 }
 
+bool hasRequiredAccess(VehiclePropertyAccess access, VehiclePropertyAccess requiredAccess) {
+    return access == requiredAccess || access == VehiclePropertyAccess::READ_WRITE;
+}
+
+bool areaConfigsHaveRequiredAccess(const std::vector<VehicleAreaConfig>& areaConfigs,
+                                   VehiclePropertyAccess requiredAccess) {
+    if (areaConfigs.empty()) {
+        return false;
+    }
+    for (VehicleAreaConfig areaConfig : areaConfigs) {
+        if (!hasRequiredAccess(areaConfig.access, requiredAccess)) {
+            return false;
+        }
+    }
+    return true;
+}
+
 VhalResult<void> DefaultVehicleHal::checkSubscribeOptions(
         const std::vector<SubscribeOptions>& options) {
     for (const auto& option : options) {
@@ -613,6 +672,26 @@
                    << StringPrintf("no config for property, ID: %" PRId32, propId);
         }
         const VehiclePropConfig& config = mConfigsByPropId[propId];
+        std::vector<VehicleAreaConfig> areaConfigs;
+        if (option.areaIds.empty()) {
+            areaConfigs = config.areaConfigs;
+        } else {
+            std::unordered_map<int, VehicleAreaConfig> areaConfigByAreaId;
+            for (const VehicleAreaConfig& areaConfig : config.areaConfigs) {
+                areaConfigByAreaId.emplace(areaConfig.areaId, areaConfig);
+            }
+            for (int areaId : option.areaIds) {
+                auto it = areaConfigByAreaId.find(areaId);
+                if (it != areaConfigByAreaId.end()) {
+                    areaConfigs.push_back(it->second);
+                } else if (areaId != 0 || !areaConfigByAreaId.empty()) {
+                    return StatusError(StatusCode::INVALID_ARG)
+                           << StringPrintf("invalid area ID: %" PRId32 " for prop ID: %" PRId32
+                                           ", not listed in config",
+                                           areaId, propId);
+                }
+            }
+        }
 
         if (config.changeMode != VehiclePropertyChangeMode::ON_CHANGE &&
             config.changeMode != VehiclePropertyChangeMode::CONTINUOUS) {
@@ -620,8 +699,9 @@
                    << "only support subscribing to ON_CHANGE or CONTINUOUS property";
         }
 
-        if (config.access != VehiclePropertyAccess::READ &&
-            config.access != VehiclePropertyAccess::READ_WRITE) {
+        // Either VehiclePropConfig.access or VehicleAreaConfig.access will be specified
+        if (!hasRequiredAccess(config.access, VehiclePropertyAccess::READ) &&
+            !areaConfigsHaveRequiredAccess(areaConfigs, VehiclePropertyAccess::READ)) {
             return StatusError(StatusCode::ACCESS_DENIED)
                    << StringPrintf("Property %" PRId32 " has no read access", propId);
         }
@@ -643,20 +723,6 @@
                        << "invalid sample rate: " << sampleRateHz << " HZ";
             }
         }
-
-        if (isGlobalProp(propId)) {
-            continue;
-        }
-
-        // Non-global property.
-        for (int32_t areaId : option.areaIds) {
-            if (auto areaConfig = getAreaConfig(propId, areaId, config); areaConfig == nullptr) {
-                return StatusError(StatusCode::INVALID_ARG)
-                       << StringPrintf("invalid area ID: %" PRId32 " for prop ID: %" PRId32
-                                       ", not listed in config",
-                                       areaId, propId);
-            }
-        }
     }
     return {};
 }
@@ -694,7 +760,39 @@
         if (config.changeMode == VehiclePropertyChangeMode::CONTINUOUS) {
             optionCopy.sampleRate = getDefaultSampleRateHz(
                     optionCopy.sampleRate, config.minSampleRate, config.maxSampleRate);
-            continuousSubscriptions.push_back(std::move(optionCopy));
+            if (!optionCopy.enableVariableUpdateRate) {
+                continuousSubscriptions.push_back(std::move(optionCopy));
+            } else {
+                // If clients enables to VUR, we need to check whether VUR is supported for the
+                // specific [propId, areaId] and overwrite the option to disable if not supported.
+                std::vector<int32_t> areasVurEnabled;
+                std::vector<int32_t> areasVurDisabled;
+                for (int32_t areaId : optionCopy.areaIds) {
+                    const VehicleAreaConfig* areaConfig = getAreaConfig(propId, areaId, config);
+                    if (areaConfig == nullptr) {
+                        areasVurDisabled.push_back(areaId);
+                        continue;
+                    }
+                    if (!areaConfig->supportVariableUpdateRate) {
+                        areasVurDisabled.push_back(areaId);
+                        continue;
+                    }
+                    areasVurEnabled.push_back(areaId);
+                }
+                if (!areasVurEnabled.empty()) {
+                    SubscribeOptions optionVurEnabled = optionCopy;
+                    optionVurEnabled.areaIds = areasVurEnabled;
+                    optionVurEnabled.enableVariableUpdateRate = true;
+                    continuousSubscriptions.push_back(std::move(optionVurEnabled));
+                }
+
+                if (!areasVurDisabled.empty()) {
+                    // We use optionCopy for areas with VUR disabled.
+                    optionCopy.areaIds = areasVurDisabled;
+                    optionCopy.enableVariableUpdateRate = false;
+                    continuousSubscriptions.push_back(std::move(optionCopy));
+                }
+            }
         } else {
             onChangeSubscriptions.push_back(std::move(optionCopy));
         }
@@ -708,9 +806,6 @@
                                                                "client died");
         }
 
-        // Create a new SubscriptionClient if there isn't an existing one.
-        mSubscriptionClients->maybeAddClient(callback);
-
         if (!onChangeSubscriptions.empty()) {
             auto result = mSubscriptionManager->subscribe(callback, onChangeSubscriptions,
                                                           /*isContinuousProperty=*/false);
@@ -746,36 +841,43 @@
     return mVehicleHardware.get();
 }
 
-VhalResult<void> DefaultVehicleHal::checkWritePermission(const VehiclePropValue& value) const {
+VhalResult<void> DefaultVehicleHal::checkPermissionHelper(
+        const VehiclePropValue& value, VehiclePropertyAccess accessToTest) const {
+    static const std::unordered_set<VehiclePropertyAccess> validAccesses = {
+            VehiclePropertyAccess::WRITE, VehiclePropertyAccess::READ,
+            VehiclePropertyAccess::READ_WRITE};
+    if (validAccesses.find(accessToTest) == validAccesses.end()) {
+        return StatusError(StatusCode::INVALID_ARG)
+               << "checkPermissionHelper parameter is an invalid access type";
+    }
+
     int32_t propId = value.prop;
     auto result = getConfig(propId);
     if (!result.ok()) {
         return StatusError(StatusCode::INVALID_ARG) << getErrorMsg(result);
     }
-    const VehiclePropConfig* config = result.value();
 
-    if (config->access != VehiclePropertyAccess::WRITE &&
-        config->access != VehiclePropertyAccess::READ_WRITE) {
+    const VehiclePropConfig* config = result.value();
+    const VehicleAreaConfig* areaConfig = getAreaConfig(value, *config);
+
+    if (areaConfig == nullptr && !isGlobalProp(propId)) {
+        return StatusError(StatusCode::INVALID_ARG) << "no config for area ID: " << value.areaId;
+    }
+    if (!hasRequiredAccess(config->access, accessToTest) &&
+        (areaConfig == nullptr || !hasRequiredAccess(areaConfig->access, accessToTest))) {
         return StatusError(StatusCode::ACCESS_DENIED)
-               << StringPrintf("Property %" PRId32 " has no write access", propId);
+               << StringPrintf("Property %" PRId32 " does not have the following access: %" PRId32,
+                               propId, accessToTest);
     }
     return {};
 }
 
-VhalResult<void> DefaultVehicleHal::checkReadPermission(const VehiclePropValue& value) const {
-    int32_t propId = value.prop;
-    auto result = getConfig(propId);
-    if (!result.ok()) {
-        return StatusError(StatusCode::INVALID_ARG) << getErrorMsg(result);
-    }
-    const VehiclePropConfig* config = result.value();
+VhalResult<void> DefaultVehicleHal::checkWritePermission(const VehiclePropValue& value) const {
+    return checkPermissionHelper(value, VehiclePropertyAccess::WRITE);
+}
 
-    if (config->access != VehiclePropertyAccess::READ &&
-        config->access != VehiclePropertyAccess::READ_WRITE) {
-        return StatusError(StatusCode::ACCESS_DENIED)
-               << StringPrintf("Property %" PRId32 " has no read access", propId);
-    }
-    return {};
+VhalResult<void> DefaultVehicleHal::checkReadPermission(const VehiclePropValue& value) const {
+    return checkPermissionHelper(value, VehiclePropertyAccess::READ);
 }
 
 void DefaultVehicleHal::checkHealth(IVehicleHardware* vehicleHardware,
@@ -786,12 +888,12 @@
         return;
     }
     std::vector<VehiclePropValue> values = {{
-            .prop = toInt(VehicleProperty::VHAL_HEARTBEAT),
             .areaId = 0,
+            .prop = toInt(VehicleProperty::VHAL_HEARTBEAT),
             .status = VehiclePropertyStatus::AVAILABLE,
             .value.int64Values = {uptimeMillis()},
     }};
-    onPropertyChangeEvent(subscriptionManager, values);
+    onPropertyChangeEvent(subscriptionManager, std::move(values));
     return;
 }
 
@@ -839,15 +941,19 @@
     dprintf(fd, "Vehicle HAL State: \n");
     {
         std::scoped_lock<std::mutex> lockGuard(mLock);
+        dprintf(fd, "Interface version: %" PRId32 "\n", getVhalInterfaceVersion());
         dprintf(fd, "Containing %zu property configs\n", mConfigsByPropId.size());
         dprintf(fd, "Currently have %zu getValues clients\n", mGetValuesClients.size());
         dprintf(fd, "Currently have %zu setValues clients\n", mSetValuesClients.size());
-        dprintf(fd, "Currently have %zu subscription clients\n",
-                mSubscriptionClients->countClients());
+        dprintf(fd, "Currently have %zu subscribe clients\n", countSubscribeClients());
     }
     return STATUS_OK;
 }
 
+size_t DefaultVehicleHal::countSubscribeClients() {
+    return mSubscriptionManager->countClients();
+}
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp b/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp
index 1f2690e..29d81a7 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp
@@ -16,6 +16,7 @@
 
 #include "SubscriptionManager.h"
 
+#include <VehicleUtils.h>
 #include <android-base/stringprintf.h>
 #include <utils/Log.h>
 #include <utils/SystemClock.h>
@@ -29,10 +30,6 @@
 
 namespace {
 
-constexpr float ONE_SECOND_IN_NANO = 1'000'000'000.;
-
-}  // namespace
-
 using ::aidl::android::hardware::automotive::vehicle::IVehicleCallback;
 using ::aidl::android::hardware::automotive::vehicle::StatusCode;
 using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions;
@@ -43,13 +40,28 @@
 using ::android::base::StringPrintf;
 using ::ndk::ScopedAStatus;
 
+constexpr float ONE_SECOND_IN_NANOS = 1'000'000'000.;
+
+SubscribeOptions newSubscribeOptions(int32_t propId, int32_t areaId, float sampleRateHz,
+                                     bool enableVur) {
+    SubscribeOptions subscribedOptions;
+    subscribedOptions.propId = propId;
+    subscribedOptions.areaIds = {areaId};
+    subscribedOptions.sampleRate = sampleRateHz;
+    subscribedOptions.enableVariableUpdateRate = enableVur;
+
+    return subscribedOptions;
+}
+
+}  // namespace
+
 SubscriptionManager::SubscriptionManager(IVehicleHardware* vehicleHardware)
     : mVehicleHardware(vehicleHardware) {}
 
 SubscriptionManager::~SubscriptionManager() {
     std::scoped_lock<std::mutex> lockGuard(mLock);
 
-    mClientsByPropIdArea.clear();
+    mClientsByPropIdAreaId.clear();
     mSubscribedPropsByClient.clear();
 }
 
@@ -62,45 +74,83 @@
     if (sampleRateHz <= 0) {
         return Error() << "invalid sample rate, must be a positive number";
     }
-    if (sampleRateHz <= (ONE_SECOND_IN_NANO / static_cast<float>(INT64_MAX))) {
+    if (sampleRateHz <= (ONE_SECOND_IN_NANOS / static_cast<float>(INT64_MAX))) {
         return Error() << "invalid sample rate: " << sampleRateHz << ", too small";
     }
-    intervalNanos = static_cast<int64_t>(ONE_SECOND_IN_NANO / sampleRateHz);
+    intervalNanos = static_cast<int64_t>(ONE_SECOND_IN_NANOS / sampleRateHz);
     return intervalNanos;
 }
 
-void ContSubConfigs::refreshMaxSampleRateHz() {
+void ContSubConfigs::refreshCombinedConfig() {
     float maxSampleRateHz = 0.;
+    bool enableVur = true;
     // This is not called frequently so a brute-focre is okay. More efficient way exists but this
     // is simpler.
-    for (const auto& [_, sampleRateHz] : mSampleRateHzByClient) {
-        if (sampleRateHz > maxSampleRateHz) {
-            maxSampleRateHz = sampleRateHz;
+    for (const auto& [_, subConfig] : mConfigByClient) {
+        if (subConfig.sampleRateHz > maxSampleRateHz) {
+            maxSampleRateHz = subConfig.sampleRateHz;
+        }
+        if (!subConfig.enableVur) {
+            // If one client does not enable variable update rate, we cannot enable variable update
+            // rate in IVehicleHardware.
+            enableVur = false;
         }
     }
     mMaxSampleRateHz = maxSampleRateHz;
+    mEnableVur = enableVur;
 }
 
-void ContSubConfigs::addClient(const ClientIdType& clientId, float sampleRateHz) {
-    mSampleRateHzByClient[clientId] = sampleRateHz;
-    refreshMaxSampleRateHz();
+void ContSubConfigs::addClient(const ClientIdType& clientId, float sampleRateHz, bool enableVur) {
+    mConfigByClient[clientId] = {
+            .sampleRateHz = sampleRateHz,
+            .enableVur = enableVur,
+    };
+    refreshCombinedConfig();
 }
 
 void ContSubConfigs::removeClient(const ClientIdType& clientId) {
-    mSampleRateHzByClient.erase(clientId);
-    refreshMaxSampleRateHz();
+    mConfigByClient.erase(clientId);
+    refreshCombinedConfig();
 }
 
 float ContSubConfigs::getMaxSampleRateHz() const {
     return mMaxSampleRateHz;
 }
 
+bool ContSubConfigs::isVurEnabled() const {
+    return mEnableVur;
+}
+
+bool ContSubConfigs::isVurEnabledForClient(const ClientIdType& clientId) {
+    return mConfigByClient[clientId].enableVur;
+}
+
+VhalResult<void> SubscriptionManager::addOnChangeSubscriberLocked(
+        const PropIdAreaId& propIdAreaId) {
+    if (mClientsByPropIdAreaId.find(propIdAreaId) != mClientsByPropIdAreaId.end()) {
+        // This propId, areaId is already subscribed, ignore the request.
+        return {};
+    }
+
+    int32_t propId = propIdAreaId.propId;
+    int32_t areaId = propIdAreaId.areaId;
+    if (auto status = mVehicleHardware->subscribe(
+                newSubscribeOptions(propId, areaId, /*updateRateHz=*/0, /*enableVur*/ false));
+        status != StatusCode::OK) {
+        return StatusError(status)
+               << StringPrintf("failed subscribe for prop: %s, areaId: %" PRId32,
+                               propIdToString(propId).c_str(), areaId);
+    }
+    return {};
+}
+
 VhalResult<void> SubscriptionManager::addContinuousSubscriberLocked(
-        const ClientIdType& clientId, const PropIdAreaId& propIdAreaId, float sampleRateHz) {
+        const ClientIdType& clientId, const PropIdAreaId& propIdAreaId, float sampleRateHz,
+        bool enableVur) {
     // Make a copy so that we don't modify 'mContSubConfigsByPropIdArea' on failure cases.
     ContSubConfigs newConfig = mContSubConfigsByPropIdArea[propIdAreaId];
-    newConfig.addClient(clientId, sampleRateHz);
-    return updateContSubConfigs(propIdAreaId, newConfig);
+    newConfig.addClient(clientId, sampleRateHz, enableVur);
+    return updateContSubConfigsLocked(propIdAreaId, newConfig);
 }
 
 VhalResult<void> SubscriptionManager::removeContinuousSubscriberLocked(
@@ -108,25 +158,62 @@
     // Make a copy so that we don't modify 'mContSubConfigsByPropIdArea' on failure cases.
     ContSubConfigs newConfig = mContSubConfigsByPropIdArea[propIdAreaId];
     newConfig.removeClient(clientId);
-    return updateContSubConfigs(propIdAreaId, newConfig);
+    return updateContSubConfigsLocked(propIdAreaId, newConfig);
 }
 
-VhalResult<void> SubscriptionManager::updateContSubConfigs(const PropIdAreaId& propIdAreaId,
-                                                           const ContSubConfigs& newConfig) {
-    if (newConfig.getMaxSampleRateHz() ==
-        mContSubConfigsByPropIdArea[propIdAreaId].getMaxSampleRateHz()) {
+VhalResult<void> SubscriptionManager::removeOnChangeSubscriberLocked(
+        const PropIdAreaId& propIdAreaId) {
+    if (mClientsByPropIdAreaId[propIdAreaId].size() > 1) {
+        // After unsubscribing this client, there is still client subscribed, so do nothing.
+        return {};
+    }
+
+    int32_t propId = propIdAreaId.propId;
+    int32_t areaId = propIdAreaId.areaId;
+    if (auto status = mVehicleHardware->unsubscribe(propId, areaId); status != StatusCode::OK) {
+        return StatusError(status)
+               << StringPrintf("failed unsubscribe for prop: %s, areaId: %" PRId32,
+                               propIdToString(propId).c_str(), areaId);
+    }
+    return {};
+}
+
+VhalResult<void> SubscriptionManager::updateContSubConfigsLocked(const PropIdAreaId& propIdAreaId,
+                                                                 const ContSubConfigs& newConfig) {
+    const auto& oldConfig = mContSubConfigsByPropIdArea[propIdAreaId];
+    float newRateHz = newConfig.getMaxSampleRateHz();
+    float oldRateHz = oldConfig.getMaxSampleRateHz();
+    if (newRateHz == oldRateHz && newConfig.isVurEnabled() == oldConfig.isVurEnabled()) {
         mContSubConfigsByPropIdArea[propIdAreaId] = newConfig;
         return {};
     }
-    float newRateHz = newConfig.getMaxSampleRateHz();
     int32_t propId = propIdAreaId.propId;
     int32_t areaId = propIdAreaId.areaId;
-    if (auto status = mVehicleHardware->updateSampleRate(propId, areaId, newRateHz);
-        status != StatusCode::OK) {
-        return StatusError(status) << StringPrintf("failed to update sample rate for prop: %" PRId32
-                                                   ", area"
-                                                   ": %" PRId32 ", sample rate: %f HZ",
-                                                   propId, areaId, newRateHz);
+    if (newRateHz != oldRateHz) {
+        if (auto status = mVehicleHardware->updateSampleRate(propId, areaId, newRateHz);
+            status != StatusCode::OK) {
+            return StatusError(status)
+                   << StringPrintf("failed to update sample rate for prop: %s, areaId: %" PRId32
+                                   ", sample rate: %f HZ",
+                                   propIdToString(propId).c_str(), areaId, newRateHz);
+        }
+    }
+    if (newRateHz != 0) {
+        if (auto status = mVehicleHardware->subscribe(
+                    newSubscribeOptions(propId, areaId, newRateHz, newConfig.isVurEnabled()));
+            status != StatusCode::OK) {
+            return StatusError(status) << StringPrintf(
+                           "failed subscribe for prop: %s, areaId"
+                           ": %" PRId32 ", sample rate: %f HZ",
+                           propIdToString(propId).c_str(), areaId, newRateHz);
+        }
+    } else {
+        if (auto status = mVehicleHardware->unsubscribe(propId, areaId); status != StatusCode::OK) {
+            return StatusError(status) << StringPrintf(
+                           "failed unsubscribe for prop: %s, areaId"
+                           ": %" PRId32,
+                           propIdToString(propId).c_str(), areaId);
+        }
     }
     mContSubConfigsByPropIdArea[propIdAreaId] = newConfig;
     return {};
@@ -163,21 +250,54 @@
                     .propId = propId,
                     .areaId = areaId,
             };
+            VhalResult<void> result;
             if (isContinuousProperty) {
-                if (auto result = addContinuousSubscriberLocked(clientId, propIdAreaId,
-                                                                option.sampleRate);
-                    !result.ok()) {
-                    return result;
-                }
+                result = addContinuousSubscriberLocked(clientId, propIdAreaId, option.sampleRate,
+                                                       option.enableVariableUpdateRate);
+            } else {
+                result = addOnChangeSubscriberLocked(propIdAreaId);
+            }
+
+            if (!result.ok()) {
+                return result;
             }
 
             mSubscribedPropsByClient[clientId].insert(propIdAreaId);
-            mClientsByPropIdArea[propIdAreaId][clientId] = callback;
+            mClientsByPropIdAreaId[propIdAreaId][clientId] = callback;
         }
     }
     return {};
 }
 
+VhalResult<void> SubscriptionManager::unsubscribePropIdAreaIdLocked(
+        SubscriptionManager::ClientIdType clientId, const PropIdAreaId& propIdAreaId) {
+    if (mContSubConfigsByPropIdArea.find(propIdAreaId) != mContSubConfigsByPropIdArea.end()) {
+        // This is a subscribed continuous property.
+        if (auto result = removeContinuousSubscriberLocked(clientId, propIdAreaId); !result.ok()) {
+            return result;
+        }
+    } else {
+        if (mClientsByPropIdAreaId.find(propIdAreaId) == mClientsByPropIdAreaId.end()) {
+            ALOGW("Unsubscribe: The property: %s, areaId: %" PRId32
+                  " was not previously subscribed, do nothing",
+                  propIdToString(propIdAreaId.propId).c_str(), propIdAreaId.areaId);
+            return {};
+        }
+        // This is an on-change property.
+        if (auto result = removeOnChangeSubscriberLocked(propIdAreaId); !result.ok()) {
+            return result;
+        }
+    }
+
+    auto& clients = mClientsByPropIdAreaId[propIdAreaId];
+    clients.erase(clientId);
+    if (clients.empty()) {
+        mClientsByPropIdAreaId.erase(propIdAreaId);
+        mContSubConfigsByPropIdArea.erase(propIdAreaId);
+    }
+    return {};
+}
+
 VhalResult<void> SubscriptionManager::unsubscribe(SubscriptionManager::ClientIdType clientId,
                                                   const std::vector<int32_t>& propIds) {
     std::scoped_lock<std::mutex> lockGuard(mLock);
@@ -186,39 +306,27 @@
         return StatusError(StatusCode::INVALID_ARG)
                << "No property was subscribed for the callback";
     }
-    std::unordered_set<int32_t> subscribedPropIds;
-    for (auto const& propIdAreaId : mSubscribedPropsByClient[clientId]) {
-        subscribedPropIds.insert(propIdAreaId.propId);
-    }
 
+    std::vector<PropIdAreaId> propIdAreaIdsToUnsubscribe;
+    std::unordered_set<int32_t> propIdSet;
     for (int32_t propId : propIds) {
-        if (subscribedPropIds.find(propId) == subscribedPropIds.end()) {
-            return StatusError(StatusCode::INVALID_ARG)
-                   << "property ID: " << propId << " is not subscribed";
+        propIdSet.insert(propId);
+    }
+    auto& subscribedPropIdsAreaIds = mSubscribedPropsByClient[clientId];
+    for (const auto& propIdAreaId : subscribedPropIdsAreaIds) {
+        if (propIdSet.find(propIdAreaId.propId) != propIdSet.end()) {
+            propIdAreaIdsToUnsubscribe.push_back(propIdAreaId);
         }
     }
 
-    auto& propIdAreaIds = mSubscribedPropsByClient[clientId];
-    auto it = propIdAreaIds.begin();
-    while (it != propIdAreaIds.end()) {
-        int32_t propId = it->propId;
-        if (std::find(propIds.begin(), propIds.end(), propId) != propIds.end()) {
-            if (auto result = removeContinuousSubscriberLocked(clientId, *it); !result.ok()) {
-                return result;
-            }
-
-            auto& clients = mClientsByPropIdArea[*it];
-            clients.erase(clientId);
-            if (clients.empty()) {
-                mClientsByPropIdArea.erase(*it);
-                mContSubConfigsByPropIdArea.erase(*it);
-            }
-            it = propIdAreaIds.erase(it);
-        } else {
-            it++;
+    for (const auto& propIdAreaId : propIdAreaIdsToUnsubscribe) {
+        if (auto result = unsubscribePropIdAreaIdLocked(clientId, propIdAreaId); !result.ok()) {
+            return result;
         }
+        subscribedPropIdsAreaIds.erase(propIdAreaId);
     }
-    if (propIdAreaIds.empty()) {
+
+    if (subscribedPropIdsAreaIds.empty()) {
         mSubscribedPropsByClient.erase(clientId);
     }
     return {};
@@ -233,38 +341,68 @@
 
     auto& subscriptions = mSubscribedPropsByClient[clientId];
     for (auto const& propIdAreaId : subscriptions) {
-        if (auto result = removeContinuousSubscriberLocked(clientId, propIdAreaId); !result.ok()) {
+        if (auto result = unsubscribePropIdAreaIdLocked(clientId, propIdAreaId); !result.ok()) {
             return result;
         }
-
-        auto& clients = mClientsByPropIdArea[propIdAreaId];
-        clients.erase(clientId);
-        if (clients.empty()) {
-            mClientsByPropIdArea.erase(propIdAreaId);
-            mContSubConfigsByPropIdArea.erase(propIdAreaId);
-        }
     }
     mSubscribedPropsByClient.erase(clientId);
     return {};
 }
 
-std::unordered_map<std::shared_ptr<IVehicleCallback>, std::vector<const VehiclePropValue*>>
-SubscriptionManager::getSubscribedClients(const std::vector<VehiclePropValue>& updatedValues) {
-    std::scoped_lock<std::mutex> lockGuard(mLock);
-    std::unordered_map<std::shared_ptr<IVehicleCallback>, std::vector<const VehiclePropValue*>>
-            clients;
+bool SubscriptionManager::isValueUpdatedLocked(const std::shared_ptr<IVehicleCallback>& callback,
+                                               const VehiclePropValue& value) {
+    const auto& it = mContSubValuesByCallback[callback].find(value);
+    if (it == mContSubValuesByCallback[callback].end()) {
+        mContSubValuesByCallback[callback].insert(value);
+        return true;
+    }
 
-    for (const auto& value : updatedValues) {
+    if (it->timestamp > value.timestamp) {
+        ALOGE("The updated property value: %s is outdated, ignored", value.toString().c_str());
+        return false;
+    }
+
+    if (it->value == value.value && it->status == value.status) {
+        // Even though the property value is the same, we need to store the new property event to
+        // update the timestamp.
+        mContSubValuesByCallback[callback].insert(value);
+        ALOGD("The updated property value for propId: %" PRId32 ", areaId: %" PRId32
+              " has the "
+              "same value and status, ignored if VUR is enabled",
+              it->prop, it->areaId);
+        return false;
+    }
+
+    mContSubValuesByCallback[callback].insert(value);
+    return true;
+}
+
+std::unordered_map<std::shared_ptr<IVehicleCallback>, std::vector<VehiclePropValue>>
+SubscriptionManager::getSubscribedClients(std::vector<VehiclePropValue>&& updatedValues) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    std::unordered_map<std::shared_ptr<IVehicleCallback>, std::vector<VehiclePropValue>> clients;
+
+    for (auto& value : updatedValues) {
         PropIdAreaId propIdAreaId{
                 .propId = value.prop,
                 .areaId = value.areaId,
         };
-        if (mClientsByPropIdArea.find(propIdAreaId) == mClientsByPropIdArea.end()) {
+        if (mClientsByPropIdAreaId.find(propIdAreaId) == mClientsByPropIdAreaId.end()) {
             continue;
         }
 
-        for (const auto& [_, client] : mClientsByPropIdArea[propIdAreaId]) {
-            clients[client].push_back(&value);
+        for (const auto& [client, callback] : mClientsByPropIdAreaId[propIdAreaId]) {
+            auto& subConfigs = mContSubConfigsByPropIdArea[propIdAreaId];
+            // If client wants VUR (and VUR is supported as checked in DefaultVehicleHal), it is
+            // possible that VUR is not enabled in IVehicleHardware because another client does not
+            // enable VUR. We will implement VUR filtering here for the client that enables it.
+            if (subConfigs.isVurEnabledForClient(client) && !subConfigs.isVurEnabled()) {
+                if (isValueUpdatedLocked(callback, value)) {
+                    clients[callback].push_back(value);
+                }
+            } else {
+                clients[callback].push_back(value);
+            }
         }
     }
     return clients;
@@ -281,11 +419,11 @@
                 .propId = errorEvent.propId,
                 .areaId = errorEvent.areaId,
         };
-        if (mClientsByPropIdArea.find(propIdAreaId) == mClientsByPropIdArea.end()) {
+        if (mClientsByPropIdAreaId.find(propIdAreaId) == mClientsByPropIdAreaId.end()) {
             continue;
         }
 
-        for (const auto& [_, client] : mClientsByPropIdArea[propIdAreaId]) {
+        for (const auto& [_, client] : mClientsByPropIdAreaId[propIdAreaId]) {
             clients[client].push_back({
                     .propId = errorEvent.propId,
                     .areaId = errorEvent.areaId,
@@ -298,7 +436,12 @@
 
 bool SubscriptionManager::isEmpty() {
     std::scoped_lock<std::mutex> lockGuard(mLock);
-    return mSubscribedPropsByClient.empty() && mClientsByPropIdArea.empty();
+    return mSubscribedPropsByClient.empty() && mClientsByPropIdAreaId.empty();
+}
+
+size_t SubscriptionManager::countClients() {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    return mSubscribedPropsByClient.size();
 }
 
 }  // namespace vehicle
diff --git a/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp b/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
index 96b71f0..bb82108 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
@@ -59,6 +59,7 @@
 using ::aidl::android::hardware::automotive::vehicle::SetValueResults;
 using ::aidl::android::hardware::automotive::vehicle::StatusCode;
 using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions;
+using ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig;
 using ::aidl::android::hardware::automotive::vehicle::VehicleAreaWindow;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfigs;
@@ -78,30 +79,45 @@
 using ::ndk::SpAIBinder;
 
 using ::testing::ContainsRegex;
+using ::testing::ElementsAre;
 using ::testing::Eq;
 using ::testing::UnorderedElementsAre;
 using ::testing::UnorderedElementsAreArray;
 using ::testing::WhenSortedBy;
 
 constexpr int32_t INVALID_PROP_ID = 0;
-// VehiclePropertyGroup:SYSTEM,VehicleArea:WINDOW,VehiclePropertyType:INT32
-constexpr int32_t INT32_WINDOW_PROP = 10001 + 0x10000000 + 0x03000000 + 0x00400000;
-// VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
-constexpr int32_t GLOBAL_ON_CHANGE_PROP = 10002 + 0x10000000 + 0x01000000 + 0x00400000;
-// VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
-constexpr int32_t GLOBAL_CONTINUOUS_PROP = 10003 + 0x10000000 + 0x01000000 + 0x00400000;
-// VehiclePropertyGroup:SYSTEM,VehicleArea:WINDOW,VehiclePropertyType:INT32
-constexpr int32_t AREA_ON_CHANGE_PROP = 10004 + 0x10000000 + 0x03000000 + 0x00400000;
-// VehiclePropertyGroup:SYSTEM,VehicleArea:WINDOW,VehiclePropertyType:INT32
-constexpr int32_t AREA_CONTINUOUS_PROP = 10005 + 0x10000000 + 0x03000000 + 0x00400000;
-// VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
-constexpr int32_t READ_ONLY_PROP = 10006 + 0x10000000 + 0x01000000 + 0x00400000;
-// VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
-constexpr int32_t WRITE_ONLY_PROP = 10007 + 0x10000000 + 0x01000000 + 0x00400000;
+// VehiclePropertyGroup:VENDOR,VehicleArea:WINDOW,VehiclePropertyType:INT32
+constexpr int32_t INT32_WINDOW_PROP = 10001 + 0x20000000 + 0x03000000 + 0x00400000;
+// VehiclePropertyGroup:VENDOR,VehicleArea:GLOBAL,VehiclePropertyType:INT32
+constexpr int32_t GLOBAL_ON_CHANGE_PROP = 10002 + 0x20000000 + 0x01000000 + 0x00400000;
+// VehiclePropertyGroup:VENDOR,VehicleArea:GLOBAL,VehiclePropertyType:INT32
+constexpr int32_t GLOBAL_CONTINUOUS_PROP = 10003 + 0x20000000 + 0x01000000 + 0x00400000;
+// VehiclePropertyGroup:VENDOR,VehicleArea:WINDOW,VehiclePropertyType:INT32
+constexpr int32_t AREA_ON_CHANGE_PROP = 10004 + 0x20000000 + 0x03000000 + 0x00400000;
+// VehiclePropertyGroup:VENDOR,VehicleArea:WINDOW,VehiclePropertyType:INT32
+constexpr int32_t AREA_CONTINUOUS_PROP = 10005 + 0x20000000 + 0x03000000 + 0x00400000;
+// VehiclePropertyGroup:VENDOR,VehicleArea:GLOBAL,VehiclePropertyType:INT32
+constexpr int32_t READ_ONLY_PROP = 10006 + 0x20000000 + 0x01000000 + 0x00400000;
+// VehiclePropertyGroup:VENDOR,VehicleArea:GLOBAL,VehiclePropertyType:INT32
+constexpr int32_t WRITE_ONLY_PROP = 10007 + 0x20000000 + 0x01000000 + 0x00400000;
+// VehiclePropertyGroup:VENDOR,VehicleArea:GLOBAL,VehiclePropertyType:INT32
+constexpr int32_t GLOBAL_CONTINUOUS_PROP_NO_VUR = 10008 + 0x20000000 + 0x01000000 + 0x00400000;
+// VehiclePropertyGroup:VENDOR,VehicleArea:GLOBAL,VehiclePropertyType:INT32
+constexpr int32_t GLOBAL_NONE_ACCESS_PROP = 10009 + 0x20000000 + 0x01000000 + 0x00400000;
+// VehiclePropertyGroup:VENDOR,VehicleArea:WINDOW,VehiclePropertyType:INT32
+constexpr int32_t AREA_NONE_ACCESS_PROP = 10010 + 0x20000000 + 0x03000000 + 0x00400000;
 
 int32_t testInt32VecProp(size_t i) {
-    // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
-    return static_cast<int32_t>(i) + 0x10000000 + 0x01000000 + 0x00410000;
+    // VehiclePropertyGroup:VENDOR,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
+    return static_cast<int32_t>(i) + 0x20000000 + 0x01000000 + 0x00410000;
+}
+
+std::string toString(const std::vector<SubscribeOptions>& options) {
+    std::string optionsStr;
+    for (const auto& option : options) {
+        optionsStr += option.toString() + "\n";
+    }
+    return optionsStr;
 }
 
 struct PropConfigCmp {
@@ -165,6 +181,26 @@
                                     .value.int32Values = {0},
                             },
                     .expectedStatus = StatusCode::ACCESS_DENIED,
+            },
+            {
+                    .name = "none_access",
+                    .request =
+                            {
+                                    .prop = GLOBAL_NONE_ACCESS_PROP,
+                                    .value.int32Values = {0},
+                            },
+                    .expectedStatus = StatusCode::ACCESS_DENIED,
+            },
+            {
+                    .name = "none_area_access",
+                    .request =
+                            {
+                                    .prop = AREA_NONE_ACCESS_PROP,
+                                    .value.int32Values = {0},
+                                    // Only ROW_1_LEFT is allowed.
+                                    .areaId = toInt(VehicleAreaWindow::ROW_1_RIGHT),
+                            },
+                    .expectedStatus = StatusCode::ACCESS_DENIED,
             }};
 }
 
@@ -211,17 +247,18 @@
 
 class DefaultVehicleHalTest : public testing::Test {
   public:
-    void SetUp() override {
-        auto hardware = std::make_unique<MockVehicleHardware>();
+    void SetUp() override { init(std::make_unique<MockVehicleHardware>()); }
+
+    void init(std::unique_ptr<MockVehicleHardware> hardware) {
         std::vector<VehiclePropConfig> testConfigs;
         for (size_t i = 0; i < 10000; i++) {
             testConfigs.push_back(VehiclePropConfig{
                     .prop = testInt32VecProp(i),
-                    .access = VehiclePropertyAccess::READ_WRITE,
                     .areaConfigs =
                             {
                                     {
                                             .areaId = 0,
+                                            .access = VehiclePropertyAccess::READ_WRITE,
                                             .minInt32Value = 0,
                                             .maxInt32Value = 100,
                                     },
@@ -231,9 +268,9 @@
         // A property with area config.
         testConfigs.push_back(
                 VehiclePropConfig{.prop = INT32_WINDOW_PROP,
-                                  .access = VehiclePropertyAccess::READ_WRITE,
                                   .areaConfigs = {{
                                           .areaId = toInt(VehicleAreaWindow::ROW_1_LEFT),
+                                          .access = VehiclePropertyAccess::READ_WRITE,
                                           .minInt32Value = 0,
                                           .maxInt32Value = 100,
                                   }}});
@@ -244,8 +281,18 @@
                 .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
         });
         // A global continuous property.
+        testConfigs.push_back(VehiclePropConfig{.prop = GLOBAL_CONTINUOUS_PROP,
+                                                .access = VehiclePropertyAccess::READ_WRITE,
+                                                .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+                                                .minSampleRate = 0.0,
+                                                .maxSampleRate = 100.0,
+                                                .areaConfigs = {{
+                                                        .areaId = 0,
+                                                        .supportVariableUpdateRate = true,
+                                                }}});
+        // A global continuous property that does not support VUR.
         testConfigs.push_back(VehiclePropConfig{
-                .prop = GLOBAL_CONTINUOUS_PROP,
+                .prop = GLOBAL_CONTINUOUS_PROP_NO_VUR,
                 .access = VehiclePropertyAccess::READ_WRITE,
                 .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
                 .minSampleRate = 0.0,
@@ -254,18 +301,19 @@
         // A per-area on-change property.
         testConfigs.push_back(VehiclePropConfig{
                 .prop = AREA_ON_CHANGE_PROP,
-                .access = VehiclePropertyAccess::READ_WRITE,
                 .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
                 .areaConfigs =
                         {
                                 {
 
                                         .areaId = toInt(VehicleAreaWindow::ROW_1_LEFT),
+                                        .access = VehiclePropertyAccess::READ_WRITE,
                                         .minInt32Value = 0,
                                         .maxInt32Value = 100,
                                 },
                                 {
                                         .areaId = toInt(VehicleAreaWindow::ROW_1_RIGHT),
+                                        .access = VehiclePropertyAccess::READ,
                                         .minInt32Value = 0,
                                         .maxInt32Value = 100,
                                 },
@@ -274,7 +322,6 @@
         // A per-area continuous property.
         testConfigs.push_back(VehiclePropConfig{
                 .prop = AREA_CONTINUOUS_PROP,
-                .access = VehiclePropertyAccess::READ_WRITE,
                 .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
                 .minSampleRate = 0.0,
                 .maxSampleRate = 1000.0,
@@ -283,13 +330,17 @@
                                 {
 
                                         .areaId = toInt(VehicleAreaWindow::ROW_1_LEFT),
+                                        .access = VehiclePropertyAccess::READ_WRITE,
                                         .minInt32Value = 0,
                                         .maxInt32Value = 100,
+                                        .supportVariableUpdateRate = true,
                                 },
                                 {
                                         .areaId = toInt(VehicleAreaWindow::ROW_1_RIGHT),
+                                        .access = VehiclePropertyAccess::READ_WRITE,
                                         .minInt32Value = 0,
                                         .maxInt32Value = 100,
+                                        .supportVariableUpdateRate = false,
                                 },
                         },
         });
@@ -309,6 +360,37 @@
                 .minSampleRate = 0.0,
                 .maxSampleRate = 1000.0,
         });
+        // Global access set to NONE
+        testConfigs.push_back(VehiclePropConfig{
+                .prop = GLOBAL_NONE_ACCESS_PROP,
+                .access = VehiclePropertyAccess::NONE,
+                .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+                .minSampleRate = 0.0,
+                .maxSampleRate = 100.0,
+        });
+        // Area access set to NONE
+        testConfigs.push_back(VehiclePropConfig{
+                .prop = AREA_NONE_ACCESS_PROP,
+                .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+                .minSampleRate = 0.0,
+                .maxSampleRate = 1000.0,
+                .areaConfigs =
+                        {
+                                {
+
+                                        .areaId = toInt(VehicleAreaWindow::ROW_1_LEFT),
+                                        .access = VehiclePropertyAccess::NONE,
+                                        .minInt32Value = 0,
+                                        .maxInt32Value = 100,
+                                },
+                                {
+                                        .areaId = toInt(VehicleAreaWindow::ROW_1_RIGHT),
+                                        .access = VehiclePropertyAccess::NONE,
+                                        .minInt32Value = 0,
+                                        .maxInt32Value = 100,
+                                },
+                        },
+        });
         // Register the heartbeat event property.
         testConfigs.push_back(VehiclePropConfig{
                 .prop = toInt(VehicleProperty::VHAL_HEARTBEAT),
@@ -350,7 +432,7 @@
     size_t countClients() {
         std::scoped_lock<std::mutex> lockGuard(mVhal->mLock);
         return mVhal->mGetValuesClients.size() + mVhal->mSetValuesClients.size() +
-               mVhal->mSubscriptionClients->countClients();
+               mVhal->countSubscribeClients();
     }
 
     std::shared_ptr<PendingRequestPool> getPool() { return mVhal->mPendingRequestPool; }
@@ -475,10 +557,10 @@
 TEST_F(DefaultVehicleHalTest, testGetAllPropConfigsSmall) {
     auto testConfigs = std::vector<VehiclePropConfig>({
             VehiclePropConfig{
-                    .prop = 1,
+                    .prop = testInt32VecProp(1),
             },
             VehiclePropConfig{
-                    .prop = 2,
+                    .prop = testInt32VecProp(2),
             },
     });
 
@@ -499,7 +581,7 @@
     // 5000 VehiclePropConfig exceeds 4k memory limit, so it would be sent through shared memory.
     for (size_t i = 0; i < 5000; i++) {
         testConfigs.push_back(VehiclePropConfig{
-                .prop = static_cast<int32_t>(i),
+                .prop = testInt32VecProp(i),
         });
     }
 
@@ -519,13 +601,42 @@
     ASSERT_EQ(result.value().getObject()->payloads, testConfigs);
 }
 
+TEST_F(DefaultVehicleHalTest, testGetAllPropConfigsFilterOutUnsupportedPropIdsForThisVersion) {
+    auto testConfigs = std::vector<VehiclePropConfig>({
+            // This is supported from V2.
+            VehiclePropConfig{
+                    .prop = toInt(VehicleProperty::PERF_VEHICLE_SPEED),
+            },
+            // This is supported from V3
+            VehiclePropConfig{
+                    .prop = toInt(VehicleProperty::ULTRASONICS_SENSOR_POSITION),
+            },
+    });
+
+    auto hardware = std::make_unique<MockVehicleHardware>();
+    hardware->setPropertyConfigs(testConfigs);
+    auto vhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware),
+                                                            /* testInterfaceVersion= */ 2);
+    std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
+
+    VehiclePropConfigs output;
+    auto status = client->getAllPropConfigs(&output);
+
+    ASSERT_TRUE(status.isOk()) << "getAllPropConfigs failed: " << status.getMessage();
+    ASSERT_THAT(output.payloads, ElementsAre(VehiclePropConfig{
+                                         .prop = toInt(VehicleProperty::PERF_VEHICLE_SPEED),
+                                 }));
+}
+
 TEST_F(DefaultVehicleHalTest, testGetPropConfigs) {
+    int32_t propId1 = testInt32VecProp(1);
+    int32_t propId2 = testInt32VecProp(2);
     auto testConfigs = std::vector<VehiclePropConfig>({
             VehiclePropConfig{
-                    .prop = 1,
+                    .prop = propId1,
             },
             VehiclePropConfig{
-                    .prop = 2,
+                    .prop = propId2,
             },
     });
 
@@ -535,7 +646,7 @@
     std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
 
     VehiclePropConfigs output;
-    auto status = client->getPropConfigs(std::vector<int32_t>({1, 2}), &output);
+    auto status = client->getPropConfigs(std::vector<int32_t>({propId1, propId2}), &output);
 
     ASSERT_TRUE(status.isOk()) << "getPropConfigs failed: " << status.getMessage();
     ASSERT_EQ(output.payloads, testConfigs);
@@ -544,10 +655,10 @@
 TEST_F(DefaultVehicleHalTest, testGetPropConfigsInvalidArg) {
     auto testConfigs = std::vector<VehiclePropConfig>({
             VehiclePropConfig{
-                    .prop = 1,
+                    .prop = testInt32VecProp(1),
             },
             VehiclePropConfig{
-                    .prop = 2,
+                    .prop = testInt32VecProp(2),
             },
     });
 
@@ -557,7 +668,9 @@
     std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
 
     VehiclePropConfigs output;
-    auto status = client->getPropConfigs(std::vector<int32_t>({1, 2, 3}), &output);
+    auto status = client->getPropConfigs(
+            std::vector<int32_t>({testInt32VecProp(1), testInt32VecProp(2), testInt32VecProp(3)}),
+            &output);
 
     ASSERT_FALSE(status.isOk()) << "getPropConfigs must fail with invalid prop ID";
     ASSERT_EQ(status.getServiceSpecificError(), toInt(StatusCode::INVALID_ARG));
@@ -650,6 +763,21 @@
                                                     .prop = WRITE_ONLY_PROP,
                                             },
                             },
+                            {
+                                    .requestId = 1,
+                                    .prop =
+                                            {
+                                                    .prop = GLOBAL_NONE_ACCESS_PROP,
+                                            },
+                            },
+                            {
+                                    .requestId = 2,
+                                    .prop =
+                                            {
+                                                    .prop = AREA_NONE_ACCESS_PROP,
+                                                    .areaId = toInt(VehicleAreaWindow::ROW_1_LEFT),
+                                            },
+                            },
                     },
     };
 
@@ -667,6 +795,14 @@
                                                             .requestId = 0,
                                                             .status = StatusCode::ACCESS_DENIED,
                                                     },
+                                                    {
+                                                            .requestId = 1,
+                                                            .status = StatusCode::ACCESS_DENIED,
+                                                    },
+                                                    {
+                                                            .requestId = 2,
+                                                            .status = StatusCode::ACCESS_DENIED,
+                                                    },
                                             }))
             << "expect to get ACCESS_DENIED status if no read permission";
 }
@@ -1293,8 +1429,8 @@
 
     auto maybeResults = getCallback()->nextOnPropertyEventResults();
     ASSERT_TRUE(maybeResults.has_value()) << "no results in callback";
-    ASSERT_THAT(maybeResults.value().payloads, UnorderedElementsAre(testValue1, testValue2))
-            << "results mismatch, expect two on-change events for all updated areas";
+    ASSERT_THAT(maybeResults.value().payloads, UnorderedElementsAre(testValue1))
+            << "results mismatch, expect one on-change events for all updated areas";
     ASSERT_FALSE(getCallback()->nextOnPropertyEventResults().has_value())
             << "more results than expected";
 }
@@ -1351,6 +1487,62 @@
     EXPECT_EQ(countClients(), static_cast<size_t>(1));
 }
 
+TEST_F(DefaultVehicleHalTest, testSubscribeContinuous_propNotSupportVur) {
+    std::vector<SubscribeOptions> options = {
+            {
+                    .propId = GLOBAL_CONTINUOUS_PROP,
+                    .sampleRate = 20.0,
+                    .enableVariableUpdateRate = true,
+            },
+            {
+                    .propId = GLOBAL_CONTINUOUS_PROP_NO_VUR,
+                    .sampleRate = 30.0,
+                    .enableVariableUpdateRate = true,
+            },
+    };
+
+    auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+
+    ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
+    auto receivedSubscribeOptions = getHardware()->getSubscribeOptions();
+    ASSERT_THAT(receivedSubscribeOptions, UnorderedElementsAre(
+                                                  SubscribeOptions{
+                                                          .propId = GLOBAL_CONTINUOUS_PROP,
+                                                          .areaIds = {0},
+                                                          .enableVariableUpdateRate = true,
+                                                          .sampleRate = 20.0,
+                                                  },
+                                                  SubscribeOptions{
+                                                          .propId = GLOBAL_CONTINUOUS_PROP_NO_VUR,
+                                                          .areaIds = {0},
+                                                          .enableVariableUpdateRate = false,
+                                                          .sampleRate = 30.0,
+                                                  }))
+            << "received unexpected subscribe options: " << toString(receivedSubscribeOptions);
+}
+
+TEST_F(DefaultVehicleHalTest, testSubscribeContinuous_propSupportVurNotEnabled) {
+    std::vector<SubscribeOptions> options = {
+            {
+                    .propId = GLOBAL_CONTINUOUS_PROP,
+                    .sampleRate = 20.0,
+                    .enableVariableUpdateRate = false,
+            },
+    };
+
+    auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+
+    ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
+    auto receivedSubscribeOptions = getHardware()->getSubscribeOptions();
+    ASSERT_THAT(receivedSubscribeOptions, UnorderedElementsAre(SubscribeOptions{
+                                                  .propId = GLOBAL_CONTINUOUS_PROP,
+                                                  .areaIds = {0},
+                                                  .enableVariableUpdateRate = false,
+                                                  .sampleRate = 20.0,
+                                          }))
+            << "received unexpected subscribe options: " << toString(receivedSubscribeOptions);
+}
+
 TEST_F(DefaultVehicleHalTest, testSubscribeAreaContinuous) {
     std::vector<SubscribeOptions> options = {
             {
@@ -1403,6 +1595,44 @@
     ASSERT_GE(rightCount, static_cast<size_t>(5));
 }
 
+TEST_F(DefaultVehicleHalTest, testAreaContinuous_areaNotSupportVur) {
+    std::vector<SubscribeOptions> options = {
+            {
+                    .propId = AREA_CONTINUOUS_PROP,
+                    .sampleRate = 20.0,
+                    .areaIds = {toInt(VehicleAreaWindow::ROW_1_LEFT)},
+                    .enableVariableUpdateRate = true,
+            },
+            {
+                    .propId = AREA_CONTINUOUS_PROP,
+                    .sampleRate = 10.0,
+                    .areaIds = {toInt(VehicleAreaWindow::ROW_1_RIGHT)},
+                    .enableVariableUpdateRate = true,
+            },
+    };
+
+    auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+
+    ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
+    auto receivedSubscribeOptions = getHardware()->getSubscribeOptions();
+    ASSERT_THAT(receivedSubscribeOptions,
+                UnorderedElementsAre(
+                        SubscribeOptions{
+                                .propId = AREA_CONTINUOUS_PROP,
+                                .sampleRate = 20.0,
+                                .areaIds = {toInt(VehicleAreaWindow::ROW_1_LEFT)},
+                                .enableVariableUpdateRate = true,
+                        },
+                        SubscribeOptions{
+                                .propId = AREA_CONTINUOUS_PROP,
+                                .sampleRate = 10.0,
+                                .areaIds = {toInt(VehicleAreaWindow::ROW_1_RIGHT)},
+                                // Area2 actually does not support VUR.
+                                .enableVariableUpdateRate = false,
+                        }))
+            << "received unexpected subscribe options: " << toString(receivedSubscribeOptions);
+}
+
 TEST_F(DefaultVehicleHalTest, testUnsubscribeOnChange) {
     std::vector<SubscribeOptions> options = {
             {
@@ -1510,6 +1740,27 @@
     ASSERT_EQ(status.getServiceSpecificError(), toInt(StatusCode::ACCESS_DENIED));
 }
 
+TEST_F(DefaultVehicleHalTest, testSubscribeGlobalNoneAccess) {
+    std::vector<SubscribeOptions> options = {{
+            .propId = GLOBAL_NONE_ACCESS_PROP,
+    }};
+
+    auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+
+    ASSERT_FALSE(status.isOk()) << "subscribe to a property with NONE global access must fail";
+    ASSERT_EQ(status.getServiceSpecificError(), toInt(StatusCode::ACCESS_DENIED));
+}
+
+TEST_F(DefaultVehicleHalTest, testSubscribeAreaNoneAccess) {
+    std::vector<SubscribeOptions> options = {
+            {.propId = AREA_NONE_ACCESS_PROP, .areaIds = {toInt(VehicleAreaWindow::ROW_1_LEFT)}}};
+
+    auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+
+    ASSERT_FALSE(status.isOk()) << "subscribe to a property with NONE area access must fail";
+    ASSERT_EQ(status.getServiceSpecificError(), toInt(StatusCode::ACCESS_DENIED));
+}
+
 TEST_F(DefaultVehicleHalTest, testUnsubscribeFailure) {
     auto status = getClient()->unsubscribe(getCallbackClient(),
                                            std::vector<int32_t>({GLOBAL_ON_CHANGE_PROP}));
@@ -1711,6 +1962,92 @@
     ASSERT_THAT(vehiclePropErrors.payloads, UnorderedElementsAreArray(expectedResults));
 }
 
+TEST_F(DefaultVehicleHalTest, testBatchOnPropertyChangeEvents) {
+    auto hardware = std::make_unique<MockVehicleHardware>();
+    hardware->setPropertyOnChangeEventBatchingWindow(std::chrono::milliseconds(10));
+    init(std::move(hardware));
+
+    std::vector<SubscribeOptions> options = {
+            {
+                    .propId = GLOBAL_ON_CHANGE_PROP,
+            },
+            {
+                    .propId = AREA_ON_CHANGE_PROP,
+                    // No areaIds means subscribing to all area IDs.
+                    .areaIds = {},
+            },
+    };
+
+    getClient()->subscribe(getCallbackClient(), options, 0);
+    VehiclePropValue testValue1 = {
+            .prop = GLOBAL_ON_CHANGE_PROP,
+            .value.int32Values = {0},
+    };
+    SetValueRequest request1 = {
+            .requestId = 1,
+            .value = testValue1,
+    };
+    SetValueResult result1 = {
+            .requestId = 1,
+            .status = StatusCode::OK,
+    };
+    VehiclePropValue testValue2 = {
+            .prop = AREA_ON_CHANGE_PROP,
+            .areaId = toInt(VehicleAreaWindow::ROW_1_LEFT),
+            .value.int32Values = {1},
+    };
+    SetValueRequest request2 = {
+            .requestId = 2,
+            .value = testValue2,
+    };
+    SetValueResult result2 = {
+            .requestId = 2,
+            .status = StatusCode::OK,
+    };
+    VehiclePropValue testValue3 = {
+            .prop = AREA_ON_CHANGE_PROP,
+            .areaId = toInt(VehicleAreaWindow::ROW_1_RIGHT),
+            .value.int32Values = {1},
+    };
+    SetValueRequest request3 = {
+            .requestId = 3,
+            .value = testValue3,
+    };
+    SetValueResult result3 = {
+            .requestId = 3,
+            .status = StatusCode::ACCESS_DENIED,
+    };
+    // Prepare the responses
+    for (int i = 0; i < 2; i++) {
+        getHardware()->addSetValueResponses({result1});
+        getHardware()->addSetValueResponses({result2, result3});
+    }
+
+    // Try to cause two batches, each with three on property change events.
+    // Set GLOBAL_ON_CHANGE_PROP causing one event.
+    // Set AREA_ON_CHANGE_PROP with two areas causing two events.
+    for (int i = 0; i < 2; i++) {
+        auto status = getClient()->setValues(getCallbackClient(),
+                                             SetValueRequests{.payloads = {request1}});
+        ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage();
+
+        status = getClient()->setValues(getCallbackClient(),
+                                        SetValueRequests{.payloads = {request2, request3}});
+        ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage();
+
+        ASSERT_TRUE(getCallback()->waitForOnPropertyEventResults(/*size=*/1,
+                                                                 /*timeoutInNano=*/1'000'000'000))
+                << "not received enough property change events before timeout";
+
+        auto maybeResults = getCallback()->nextOnPropertyEventResults();
+        ASSERT_TRUE(maybeResults.has_value()) << "no results in callback";
+        ASSERT_THAT(maybeResults.value().payloads, UnorderedElementsAre(testValue1, testValue2))
+                << "results mismatch, expect 2 batched on change events";
+        ASSERT_FALSE(getCallback()->nextOnPropertyEventResults().has_value())
+                << "more results than expected";
+    }
+}
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp
index 54fede1..c272123 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp
@@ -137,6 +137,14 @@
     });
 }
 
+bool MockVehicleCallback::waitForOnPropertyEventResults(size_t size, size_t timeoutInNano) {
+    std::unique_lock lk(mLock);
+    return mCond.wait_for(lk, std::chrono::nanoseconds(timeoutInNano), [this, size] {
+        ScopedLockAssertion lockAssertion(mLock);
+        return mOnPropertyEventResults.size() >= size;
+    });
+}
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h
index 1545eae..672ff4f 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h
+++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h
@@ -69,6 +69,7 @@
     size_t countOnPropertyEventResults();
     bool waitForSetValueResults(size_t size, size_t timeoutInNano);
     bool waitForGetValueResults(size_t size, size_t timeoutInNano);
+    bool waitForOnPropertyEventResults(size_t size, size_t timeoutInNano);
 
   private:
     std::mutex mLock;
diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp
index ba0d33d..db15c89 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp
@@ -29,6 +29,7 @@
 using ::aidl::android::hardware::automotive::vehicle::SetValueRequest;
 using ::aidl::android::hardware::automotive::vehicle::SetValueResult;
 using ::aidl::android::hardware::automotive::vehicle::StatusCode;
+using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
 
@@ -88,7 +89,40 @@
     return StatusCode::OK;
 }
 
-StatusCode MockVehicleHardware::updateSampleRate(int32_t propId, int32_t areaId, float sampleRate) {
+StatusCode MockVehicleHardware::subscribe(SubscribeOptions options) {
+    {
+        std::scoped_lock<std::mutex> lockGuard(mLock);
+        mSubscribeOptions.push_back(options);
+    }
+    for (int32_t areaId : options.areaIds) {
+        if (auto status = subscribePropIdAreaId(options.propId, areaId, options.sampleRate);
+            status != StatusCode::OK) {
+            return status;
+        }
+    }
+    return StatusCode::OK;
+}
+
+std::vector<SubscribeOptions> MockVehicleHardware::getSubscribeOptions() {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    return mSubscribeOptions;
+}
+
+void MockVehicleHardware::clearSubscribeOptions() {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    mSubscribeOptions.clear();
+}
+
+StatusCode MockVehicleHardware::subscribePropIdAreaId(int32_t propId, int32_t areaId,
+                                                      float sampleRateHz) {
+    if (sampleRateHz == 0) {
+        // on-change property.
+        std::scoped_lock<std::mutex> lockGuard(mLock);
+        mSubOnChangePropIdAreaIds.insert(std::pair<int32_t, int32_t>(propId, areaId));
+        return StatusCode::OK;
+    }
+
+    // continuous property.
     std::shared_ptr<std::function<void()>> action;
 
     {
@@ -97,9 +131,6 @@
             // Remove the previous action register for this [propId, areaId].
             mRecurrentTimer->unregisterTimerCallback(mRecurrentActions[propId][areaId]);
         }
-        if (sampleRate == 0) {
-            return StatusCode::OK;
-        }
 
         // We are sure 'propertyChangeCallback' would be alive because we would unregister timer
         // before destroying 'this' which owns mPropertyChangeCallback.
@@ -107,8 +138,8 @@
         action = std::make_shared<std::function<void()>>([propertyChangeCallback, propId, areaId] {
             std::vector<VehiclePropValue> values = {
                     {
-                            .prop = propId,
                             .areaId = areaId,
+                            .prop = propId,
                     },
             };
             (*propertyChangeCallback)(values);
@@ -119,11 +150,45 @@
 
     // In mock implementation, we generate a new property change event for this property at sample
     // rate.
-    int64_t interval = static_cast<int64_t>(1'000'000'000. / sampleRate);
+    int64_t interval = static_cast<int64_t>(1'000'000'000. / sampleRateHz);
     mRecurrentTimer->registerTimerCallback(interval, action);
     return StatusCode::OK;
 }
 
+StatusCode MockVehicleHardware::unsubscribe(int32_t propId, int32_t areaId) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    // For on-change property.
+    mSubOnChangePropIdAreaIds.erase(std::make_pair(propId, areaId));
+    // for continuous property.
+    if (mRecurrentActions[propId][areaId] != nullptr) {
+        // Remove the previous action register for this [propId, areaId].
+        mRecurrentTimer->unregisterTimerCallback(mRecurrentActions[propId][areaId]);
+        mRecurrentActions[propId].erase(areaId);
+        if (mRecurrentActions[propId].empty()) {
+            mRecurrentActions.erase(propId);
+        }
+    }
+    return StatusCode::OK;
+}
+
+std::set<std::pair<int32_t, int32_t>> MockVehicleHardware::getSubscribedOnChangePropIdAreaIds() {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    std::set<std::pair<int32_t, int32_t>> propIdAreaIds;
+    propIdAreaIds = mSubOnChangePropIdAreaIds;
+    return propIdAreaIds;
+}
+
+std::set<std::pair<int32_t, int32_t>> MockVehicleHardware::getSubscribedContinuousPropIdAreaIds() {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    std::set<std::pair<int32_t, int32_t>> propIdAreaIds;
+    for (const auto& [propId, actionByAreaId] : mRecurrentActions) {
+        for (const auto& [areaId, _] : actionByAreaId) {
+            propIdAreaIds.insert(std::make_pair(propId, areaId));
+        }
+    }
+    return propIdAreaIds;
+}
+
 void MockVehicleHardware::registerOnPropertyChangeEvent(
         std::unique_ptr<const PropertyChangeCallback> callback) {
     std::scoped_lock<std::mutex> lockGuard(mLock);
@@ -186,6 +251,16 @@
     mSleepTime = timeInNano;
 }
 
+void MockVehicleHardware::setPropertyOnChangeEventBatchingWindow(std::chrono::nanoseconds window) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    mEventBatchingWindow = window;
+}
+
+std::chrono::nanoseconds MockVehicleHardware::getPropertyOnChangeEventBatchingWindow() {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    return mEventBatchingWindow;
+}
+
 template <class ResultType>
 StatusCode MockVehicleHardware::returnResponse(
         std::shared_ptr<const std::function<void(std::vector<ResultType>)>> callback,
diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h
index 46b30b9..eeca582 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h
@@ -24,10 +24,12 @@
 #include <android-base/thread_annotations.h>
 
 #include <atomic>
+#include <chrono>
 #include <condition_variable>
 #include <list>
 #include <memory>
 #include <mutex>
+#include <set>
 #include <thread>
 #include <unordered_map>
 #include <vector>
@@ -58,8 +60,11 @@
     void registerOnPropertyChangeEvent(
             std::unique_ptr<const PropertyChangeCallback> callback) override;
     void registerOnPropertySetErrorEvent(std::unique_ptr<const PropertySetErrorCallback>) override;
-    aidl::android::hardware::automotive::vehicle::StatusCode updateSampleRate(
-            int32_t propId, int32_t areaId, float sampleRate) override;
+    aidl::android::hardware::automotive::vehicle::StatusCode subscribe(
+            aidl::android::hardware::automotive::vehicle::SubscribeOptions options) override;
+    aidl::android::hardware::automotive::vehicle::StatusCode unsubscribe(int32_t propId,
+                                                                         int32_t areaId) override;
+    std::chrono::nanoseconds getPropertyOnChangeEventBatchingWindow() override;
 
     // Test functions.
     void setPropertyConfigs(
@@ -86,6 +91,13 @@
     void setSleepTime(int64_t timeInNano);
     void setDumpResult(DumpResult result);
     void sendOnPropertySetErrorEvent(const std::vector<SetValueErrorEvent>& errorEvents);
+    void setPropertyOnChangeEventBatchingWindow(std::chrono::nanoseconds window);
+
+    std::set<std::pair<int32_t, int32_t>> getSubscribedOnChangePropIdAreaIds();
+    std::set<std::pair<int32_t, int32_t>> getSubscribedContinuousPropIdAreaIds();
+    std::vector<aidl::android::hardware::automotive::vehicle::SubscribeOptions>
+    getSubscribeOptions();
+    void clearSubscribeOptions();
 
   private:
     mutable std::mutex mLock;
@@ -110,6 +122,10 @@
             std::shared_ptr<const GetValuesCallback>,
             const std::vector<aidl::android::hardware::automotive::vehicle::GetValueRequest>&)>
             mGetValueResponder GUARDED_BY(mLock);
+    std::chrono::nanoseconds mEventBatchingWindow GUARDED_BY(mLock) = std::chrono::nanoseconds(0);
+    std::set<std::pair<int32_t, int32_t>> mSubOnChangePropIdAreaIds GUARDED_BY(mLock);
+    std::vector<aidl::android::hardware::automotive::vehicle::SubscribeOptions> mSubscribeOptions
+            GUARDED_BY(mLock);
 
     template <class ResultType>
     aidl::android::hardware::automotive::vehicle::StatusCode returnResponse(
@@ -122,6 +138,8 @@
             const std::vector<RequestType>& requests,
             std::list<std::vector<RequestType>>* storedRequests,
             std::list<std::vector<ResultType>>* storedResponses) const REQUIRES(mLock);
+    aidl::android::hardware::automotive::vehicle::StatusCode subscribePropIdAreaId(
+            int32_t propId, int32_t areaId, float sampleRateHz);
 
     DumpResult mDumpResult;
 
diff --git a/automotive/vehicle/aidl/impl/vhal/test/SubscriptionManagerTest.cpp b/automotive/vehicle/aidl/impl/vhal/test/SubscriptionManagerTest.cpp
index cb8c8d1..aa5f003 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/SubscriptionManagerTest.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/test/SubscriptionManagerTest.cpp
@@ -43,12 +43,14 @@
 using ::aidl::android::hardware::automotive::vehicle::SetValueResults;
 using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropErrors;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyStatus;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValues;
 using ::ndk::ScopedAStatus;
 using ::ndk::SpAIBinder;
+using ::testing::Contains;
 using ::testing::ElementsAre;
-using ::testing::WhenSorted;
+using ::testing::UnorderedElementsAre;
 
 class PropertyCallback final : public BnVehicleCallback {
   public:
@@ -114,6 +116,8 @@
 
     void clearEvents() { return getCallback()->clearEvents(); }
 
+    std::shared_ptr<MockVehicleHardware> getHardware() { return mHardware; }
+
   private:
     std::unique_ptr<SubscriptionManager> mManager;
     std::shared_ptr<PropertyCallback> mCallback;
@@ -132,6 +136,9 @@
     auto result = getManager()->subscribe(getCallbackClient(), options, true);
     ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message();
 
+    ASSERT_THAT(getHardware()->getSubscribedContinuousPropIdAreaIds(),
+                UnorderedElementsAre(std::pair<int32_t, int32_t>(0, 0)));
+
     std::this_thread::sleep_for(std::chrono::seconds(1));
 
     // Theoretically trigger 10 times, but check for at least 9 times to be stable.
@@ -240,6 +247,8 @@
     result = getManager()->unsubscribe(getCallbackClient()->asBinder().get());
     ASSERT_TRUE(result.ok()) << "failed to unsubscribe: " << result.error().message();
 
+    ASSERT_EQ(getHardware()->getSubscribedContinuousPropIdAreaIds().size(), 0u);
+
     // Wait for the last events to come.
     std::this_thread::sleep_for(std::chrono::milliseconds(100));
 
@@ -316,7 +325,7 @@
     EXPECT_TRUE(getEvents().empty());
 }
 
-TEST_F(SubscriptionManagerTest, testUnsubscribeFailure) {
+TEST_F(SubscriptionManagerTest, testUnsubscribeUnsubscribedPropId) {
     std::vector<SubscribeOptions> options = {
             {
                     .propId = 0,
@@ -334,14 +343,21 @@
     // Property ID: 2 was not subscribed.
     result = getManager()->unsubscribe(getCallbackClient()->asBinder().get(),
                                        std::vector<int32_t>({0, 1, 2}));
-    ASSERT_FALSE(result.ok()) << "unsubscribe an unsubscribed property must fail";
+    ASSERT_TRUE(result.ok()) << "unsubscribe an unsubscribed property must do nothing";
 
-    // Since property 0 and property 1 was not unsubscribed successfully, we should be able to
-    // unsubscribe them again.
-    result = getManager()->unsubscribe(getCallbackClient()->asBinder().get(),
-                                       std::vector<int32_t>({0, 1}));
-    ASSERT_TRUE(result.ok()) << "a failed unsubscription must not unsubscribe any properties"
-                             << result.error().message();
+    std::vector<VehiclePropValue> updatedValues = {
+            {
+                    .prop = 0,
+                    .areaId = 0,
+            },
+            {
+                    .prop = 1,
+                    .areaId = 0,
+            },
+    };
+    auto clients = getManager()->getSubscribedClients(std::vector<VehiclePropValue>(updatedValues));
+
+    ASSERT_EQ(clients.size(), 0u) << "all subscribed properties must be unsubscribed";
 }
 
 TEST_F(SubscriptionManagerTest, testSubscribeOnchange) {
@@ -370,6 +386,11 @@
     ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message();
     result = getManager()->subscribe(client2, options2, false);
     ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message();
+    ASSERT_THAT(getHardware()->getSubscribedOnChangePropIdAreaIds(),
+                UnorderedElementsAre(std::pair<int32_t, int32_t>(0, 0),
+                                     std::pair<int32_t, int32_t>(0, 1),
+                                     std::pair<int32_t, int32_t>(1, 0)));
+    ASSERT_EQ(getHardware()->getSubscribedContinuousPropIdAreaIds().size(), 0u);
 
     std::vector<VehiclePropValue> updatedValues = {
             {
@@ -389,11 +410,11 @@
                     .areaId = 1,
             },
     };
-    auto clients = getManager()->getSubscribedClients(updatedValues);
+    auto clients = getManager()->getSubscribedClients(std::vector<VehiclePropValue>(updatedValues));
 
     ASSERT_THAT(clients[client1],
-                WhenSorted(ElementsAre(&updatedValues[0], &updatedValues[1], &updatedValues[2])));
-    ASSERT_THAT(clients[client2], ElementsAre(&updatedValues[0]));
+                UnorderedElementsAre(updatedValues[0], updatedValues[1], updatedValues[2]));
+    ASSERT_THAT(clients[client2], ElementsAre(updatedValues[0]));
 }
 
 TEST_F(SubscriptionManagerTest, testSubscribeInvalidOption) {
@@ -480,9 +501,11 @@
                     .areaId = 0,
             },
     };
-    auto clients = getManager()->getSubscribedClients(updatedValues);
+    auto clients = getManager()->getSubscribedClients(std::vector<VehiclePropValue>(updatedValues));
 
-    ASSERT_THAT(clients[getCallbackClient()], ElementsAre(&updatedValues[1]));
+    ASSERT_THAT(clients[getCallbackClient()], ElementsAre(updatedValues[1]));
+    ASSERT_THAT(getHardware()->getSubscribedOnChangePropIdAreaIds(),
+                UnorderedElementsAre(std::pair<int32_t, int32_t>(1, 0)));
 }
 
 TEST_F(SubscriptionManagerTest, testCheckSampleRateHzValid) {
@@ -497,6 +520,257 @@
     ASSERT_FALSE(SubscriptionManager::checkSampleRateHz(0));
 }
 
+TEST_F(SubscriptionManagerTest, testSubscribe_enableVur) {
+    std::vector<SubscribeOptions> options = {{
+            .propId = 0,
+            .areaIds = {0},
+            .sampleRate = 10.0,
+            .enableVariableUpdateRate = true,
+    }};
+
+    auto result = getManager()->subscribe(getCallbackClient(), options, true);
+    ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message();
+
+    ASSERT_THAT(getHardware()->getSubscribeOptions(), ElementsAre(options[0]));
+}
+
+TEST_F(SubscriptionManagerTest, testSubscribe_VurStateChange) {
+    std::vector<SubscribeOptions> options = {{
+            .propId = 0,
+            .areaIds = {0},
+            .sampleRate = 10.0,
+            .enableVariableUpdateRate = true,
+    }};
+
+    auto result = getManager()->subscribe(getCallbackClient(), options, true);
+    ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message();
+
+    ASSERT_THAT(getHardware()->getSubscribeOptions(), ElementsAre(options[0]));
+
+    getHardware()->clearSubscribeOptions();
+    result = getManager()->subscribe(getCallbackClient(), options, true);
+    ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message();
+
+    ASSERT_TRUE(getHardware()->getSubscribeOptions().empty());
+
+    std::vector<SubscribeOptions> newOptions = {{
+            .propId = 0,
+            .areaIds = {0},
+            .sampleRate = 10.0,
+            .enableVariableUpdateRate = false,
+    }};
+    result = getManager()->subscribe(getCallbackClient(), newOptions, true);
+    ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message();
+
+    ASSERT_THAT(getHardware()->getSubscribeOptions(), ElementsAre(newOptions[0]));
+}
+
+TEST_F(SubscriptionManagerTest, testSubscribe_enableVur_filterUnchangedEvents) {
+    SpAIBinder binder1 = ndk::SharedRefBase::make<PropertyCallback>()->asBinder();
+    std::shared_ptr<IVehicleCallback> client1 = IVehicleCallback::fromBinder(binder1);
+    SpAIBinder binder2 = ndk::SharedRefBase::make<PropertyCallback>()->asBinder();
+    std::shared_ptr<IVehicleCallback> client2 = IVehicleCallback::fromBinder(binder2);
+    SubscribeOptions client1Option = {
+            .propId = 0,
+            .areaIds = {0},
+            .sampleRate = 10.0,
+            .enableVariableUpdateRate = false,
+    };
+    auto result = getManager()->subscribe(client1, {client1Option}, true);
+    ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message();
+
+    ASSERT_THAT(getHardware()->getSubscribeOptions(), UnorderedElementsAre(client1Option));
+
+    getHardware()->clearSubscribeOptions();
+    SubscribeOptions client2Option = {
+            .propId = 0,
+            .areaIds = {0, 1},
+            .sampleRate = 20.0,
+            .enableVariableUpdateRate = true,
+    };
+
+    result = getManager()->subscribe(client2, {client2Option}, true);
+    ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message();
+
+    ASSERT_THAT(getHardware()->getSubscribeOptions(),
+                UnorderedElementsAre(
+                        SubscribeOptions{
+                                .propId = 0,
+                                .areaIds = {0},
+                                .sampleRate = 20.0,
+                                // This is enabled for client2, but disabled for client1.
+                                .enableVariableUpdateRate = false,
+                        },
+                        SubscribeOptions{
+                                .propId = 0,
+                                .areaIds = {1},
+                                .sampleRate = 20.0,
+                                .enableVariableUpdateRate = true,
+                        }));
+
+    std::vector<VehiclePropValue> propertyEvents = {{
+                                                            .prop = 0,
+                                                            .areaId = 0,
+                                                            .value = {.int32Values = {0}},
+                                                            .timestamp = 1,
+                                                    },
+                                                    {
+                                                            .prop = 0,
+                                                            .areaId = 1,
+                                                            .value = {.int32Values = {1}},
+                                                            .timestamp = 1,
+                                                    }};
+    auto clients =
+            getManager()->getSubscribedClients(std::vector<VehiclePropValue>(propertyEvents));
+
+    ASSERT_THAT(clients[client1], UnorderedElementsAre(propertyEvents[0]));
+    ASSERT_THAT(clients[client2], UnorderedElementsAre(propertyEvents[0], propertyEvents[1]));
+
+    // If the same property events happen again with a new timestamp.
+    // VUR is disabled for client1, enabled for client2.
+    clients = getManager()->getSubscribedClients({{
+            .prop = 0,
+            .areaId = 0,
+            .value = {.int32Values = {0}},
+            .timestamp = 2,
+    }});
+
+    ASSERT_FALSE(clients.find(client1) == clients.end())
+            << "Must not filter out property events if VUR is not enabled";
+    ASSERT_TRUE(clients.find(client2) == clients.end())
+            << "Must filter out property events if VUR is enabled";
+}
+
+TEST_F(SubscriptionManagerTest, testSubscribe_enableVur_mustNotFilterStatusChange) {
+    SpAIBinder binder1 = ndk::SharedRefBase::make<PropertyCallback>()->asBinder();
+    std::shared_ptr<IVehicleCallback> client1 = IVehicleCallback::fromBinder(binder1);
+    SpAIBinder binder2 = ndk::SharedRefBase::make<PropertyCallback>()->asBinder();
+    std::shared_ptr<IVehicleCallback> client2 = IVehicleCallback::fromBinder(binder2);
+    SubscribeOptions client1Option = {
+            .propId = 0,
+            .areaIds = {0},
+            .sampleRate = 10.0,
+            .enableVariableUpdateRate = false,
+    };
+    auto result = getManager()->subscribe(client1, {client1Option}, true);
+    ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message();
+
+    ASSERT_THAT(getHardware()->getSubscribeOptions(), UnorderedElementsAre(client1Option));
+
+    getHardware()->clearSubscribeOptions();
+    SubscribeOptions client2Option = {
+            .propId = 0,
+            .areaIds = {0, 1},
+            .sampleRate = 20.0,
+            .enableVariableUpdateRate = true,
+    };
+
+    result = getManager()->subscribe(client2, {client2Option}, true);
+    ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message();
+
+    ASSERT_THAT(getHardware()->getSubscribeOptions(),
+                UnorderedElementsAre(
+                        SubscribeOptions{
+                                .propId = 0,
+                                .areaIds = {0},
+                                .sampleRate = 20.0,
+                                // This is enabled for client2, but disabled for client1.
+                                .enableVariableUpdateRate = false,
+                        },
+                        SubscribeOptions{
+                                .propId = 0,
+                                .areaIds = {1},
+                                .sampleRate = 20.0,
+                                .enableVariableUpdateRate = true,
+                        }));
+
+    VehiclePropValue propValue1 = {
+            .prop = 0,
+            .areaId = 0,
+            .value = {.int32Values = {0}},
+            .timestamp = 1,
+    };
+    auto clients = getManager()->getSubscribedClients(std::vector<VehiclePropValue>({propValue1}));
+
+    ASSERT_THAT(clients[client1], UnorderedElementsAre(propValue1));
+
+    // A new event with the same value, but different status must not be filtered out.
+    VehiclePropValue propValue2 = {
+            .prop = 0,
+            .areaId = 0,
+            .value = {.int32Values = {0}},
+            .status = VehiclePropertyStatus::UNAVAILABLE,
+            .timestamp = 2,
+    };
+    clients = getManager()->getSubscribedClients({propValue2});
+
+    ASSERT_THAT(clients[client1], UnorderedElementsAre(propValue2))
+            << "Must not filter out property events that has status change";
+}
+
+TEST_F(SubscriptionManagerTest, testSubscribe_enableVur_timestampUpdated_filterOutdatedEvent) {
+    SpAIBinder binder1 = ndk::SharedRefBase::make<PropertyCallback>()->asBinder();
+    std::shared_ptr<IVehicleCallback> client1 = IVehicleCallback::fromBinder(binder1);
+    SpAIBinder binder2 = ndk::SharedRefBase::make<PropertyCallback>()->asBinder();
+    std::shared_ptr<IVehicleCallback> client2 = IVehicleCallback::fromBinder(binder2);
+    std::vector<SubscribeOptions> options = {{
+            .propId = 0,
+            .areaIds = {0},
+            .sampleRate = 10.0,
+            .enableVariableUpdateRate = true,
+    }};
+
+    // client1 subscribe with VUR enabled.
+    auto result = getManager()->subscribe(client1, options, true);
+    ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message();
+
+    // Let client2 subscribe with VUR disabled so that we enabled VUR in DefaultVehicleHal layer.
+    result = getManager()->subscribe(client2,
+                                     {{
+                                             .propId = 0,
+                                             .areaIds = {0},
+                                             .sampleRate = 10.0,
+                                             .enableVariableUpdateRate = false,
+                                     }},
+                                     true);
+    ASSERT_TRUE(result.ok()) << "failed to subscribe: " << result.error().message();
+
+    VehiclePropValue value0 = {
+            .prop = 0,
+            .areaId = 0,
+            .value = {.int32Values = {0}},
+            .timestamp = 1,
+    };
+    auto clients = getManager()->getSubscribedClients({value0});
+
+    ASSERT_THAT(clients[client1], UnorderedElementsAre(value0));
+
+    // A new event with the same value arrived. This must update timestamp to 3.
+    VehiclePropValue value1 = {
+            .prop = 0,
+            .areaId = 0,
+            .value = {.int32Values = {0}},
+            .timestamp = 3,
+    };
+    clients = getManager()->getSubscribedClients({value1});
+
+    ASSERT_TRUE(clients.find(client1) == clients.end())
+            << "Must filter out duplicate property events if VUR is enabled";
+
+    // The latest timestamp is 3, so even though the value is not the same, this is outdated and
+    // must be ignored.
+    VehiclePropValue value2 = {
+            .prop = 0,
+            .areaId = 0,
+            .value = {.int32Values = {1}},
+            .timestamp = 2,
+    };
+    clients = getManager()->getSubscribedClients({value1});
+
+    ASSERT_TRUE(clients.find(client1) == clients.end())
+            << "Must filter out outdated property events if VUR is enabled";
+}
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/vhal/vhal-default-service.rc b/automotive/vehicle/aidl/impl/vhal/vhal-default-service.rc
index 19267cd..9fa7b98 100644
--- a/automotive/vehicle/aidl/impl/vhal/vhal-default-service.rc
+++ b/automotive/vehicle/aidl/impl/vhal/vhal-default-service.rc
@@ -1,4 +1,4 @@
-service vendor.vehicle-hal-default /vendor/bin/hw/android.hardware.automotive.vehicle@V1-default-service
+service vendor.vehicle-hal-default /vendor/bin/hw/android.hardware.automotive.vehicle@V3-default-service
     class early_hal
     user vehicle_network
     group system inet
diff --git a/automotive/vehicle/aidl/impl/vhal/vhal-default-service.xml b/automotive/vehicle/aidl/impl/vhal/vhal-default-service.xml
index 9834cdb..b0c6ae7 100644
--- a/automotive/vehicle/aidl/impl/vhal/vhal-default-service.xml
+++ b/automotive/vehicle/aidl/impl/vhal/vhal-default-service.xml
@@ -1,7 +1,7 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.automotive.vehicle</name>
-        <version>2</version>
+        <version>3</version>
         <fqname>IVehicle/default</fqname>
     </hal>
 </manifest>
diff --git a/automotive/vehicle/aidl_property/Android.bp b/automotive/vehicle/aidl_property/Android.bp
index 19fa4a3..345a2e6 100644
--- a/automotive/vehicle/aidl_property/Android.bp
+++ b/automotive/vehicle/aidl_property/Android.bp
@@ -28,7 +28,7 @@
         // This HAL was originally part of android.hardware.automotive.vehicle
         "android/hardware/automotive/vehicle/*.aidl",
     ],
-    frozen: true,
+    frozen: false,
     stability: "vintf",
     backend: {
         cpp: {
@@ -42,6 +42,9 @@
                 "com.android.car.framework",
             ],
         },
+        rust: {
+            enabled: true,
+        },
     },
     versions_with_info: [
         {
@@ -52,7 +55,6 @@
             version: "2",
             imports: [],
         },
-
     ],
 
 }
diff --git a/automotive/vehicle/aidl_property/OWNERS b/automotive/vehicle/aidl_property/OWNERS
deleted file mode 100644
index 73e45ca..0000000
--- a/automotive/vehicle/aidl_property/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-tylertrephan@google.com
diff --git a/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/CrossTrafficMonitoringWarningState.aidl b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/CrossTrafficMonitoringWarningState.aidl
new file mode 100644
index 0000000..90e2d8d
--- /dev/null
+++ b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/CrossTrafficMonitoringWarningState.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.vehicle;
+@Backing(type="int") @VintfStability
+enum CrossTrafficMonitoringWarningState {
+  OTHER = 0,
+  NO_WARNING = 1,
+  WARNING_FRONT_LEFT = 2,
+  WARNING_FRONT_RIGHT = 3,
+  WARNING_FRONT_BOTH = 4,
+  WARNING_REAR_LEFT = 5,
+  WARNING_REAR_RIGHT = 6,
+  WARNING_REAR_BOTH = 7,
+}
diff --git a/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/DriverDistractionState.aidl b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/DriverDistractionState.aidl
new file mode 100644
index 0000000..54c02d5
--- /dev/null
+++ b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/DriverDistractionState.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.vehicle;
+@Backing(type="int") @VintfStability
+enum DriverDistractionState {
+  OTHER = 0,
+  NOT_DISTRACTED = 1,
+  DISTRACTED = 2,
+}
diff --git a/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/DriverDistractionWarning.aidl b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/DriverDistractionWarning.aidl
new file mode 100644
index 0000000..9236b1c
--- /dev/null
+++ b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/DriverDistractionWarning.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.vehicle;
+@Backing(type="int") @VintfStability
+enum DriverDistractionWarning {
+  OTHER = 0,
+  NO_WARNING = 1,
+  WARNING = 2,
+}
diff --git a/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/DriverDrowsinessAttentionState.aidl b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/DriverDrowsinessAttentionState.aidl
new file mode 100644
index 0000000..22a90f3
--- /dev/null
+++ b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/DriverDrowsinessAttentionState.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.vehicle;
+@Backing(type="int") @VintfStability
+enum DriverDrowsinessAttentionState {
+  OTHER = 0,
+  KSS_RATING_1_EXTREMELY_ALERT = 1,
+  KSS_RATING_2_VERY_ALERT = 2,
+  KSS_RATING_3_ALERT = 3,
+  KSS_RATING_4_RATHER_ALERT = 4,
+  KSS_RATING_5_NEITHER_ALERT_NOR_SLEEPY = 5,
+  KSS_RATING_6_SOME_SLEEPINESS = 6,
+  KSS_RATING_7_SLEEPY_NO_EFFORT = 7,
+  KSS_RATING_8_SLEEPY_SOME_EFFORT = 8,
+  KSS_RATING_9_VERY_SLEEPY = 9,
+}
diff --git a/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/DriverDrowsinessAttentionWarning.aidl b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/DriverDrowsinessAttentionWarning.aidl
new file mode 100644
index 0000000..dbf2364
--- /dev/null
+++ b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/DriverDrowsinessAttentionWarning.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.vehicle;
+@Backing(type="int") @VintfStability
+enum DriverDrowsinessAttentionWarning {
+  OTHER = 0,
+  NO_WARNING = 1,
+  WARNING = 2,
+}
diff --git a/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/ElectronicStabilityControlState.aidl b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/ElectronicStabilityControlState.aidl
new file mode 100644
index 0000000..b061a25
--- /dev/null
+++ b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/ElectronicStabilityControlState.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.vehicle;
+@Backing(type="int") @VintfStability
+enum ElectronicStabilityControlState {
+  OTHER = 0,
+  ENABLED = 1,
+  ACTIVATED = 2,
+}
diff --git a/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/ImpactSensorLocation.aidl b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/ImpactSensorLocation.aidl
new file mode 100644
index 0000000..6b75d8c
--- /dev/null
+++ b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/ImpactSensorLocation.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.vehicle;
+@Backing(type="int") @VintfStability
+enum ImpactSensorLocation {
+  OTHER = 0x01,
+  FRONT = 0x02,
+  FRONT_LEFT_DOOR_SIDE = 0x04,
+  FRONT_RIGHT_DOOR_SIDE = 0x08,
+  REAR_LEFT_DOOR_SIDE = 0x10,
+  REAR_RIGHT_DOOR_SIDE = 0x20,
+  REAR = 0x40,
+}
diff --git a/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/LowSpeedAutomaticEmergencyBrakingState.aidl b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/LowSpeedAutomaticEmergencyBrakingState.aidl
new file mode 100644
index 0000000..70014e1
--- /dev/null
+++ b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/LowSpeedAutomaticEmergencyBrakingState.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.vehicle;
+@Backing(type="int") @VintfStability
+enum LowSpeedAutomaticEmergencyBrakingState {
+  OTHER = 0,
+  ENABLED = 1,
+  ACTIVATED = 2,
+  USER_OVERRIDE = 3,
+}
diff --git a/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/LowSpeedCollisionWarningState.aidl b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/LowSpeedCollisionWarningState.aidl
new file mode 100644
index 0000000..6f6338b
--- /dev/null
+++ b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/LowSpeedCollisionWarningState.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.vehicle;
+@Backing(type="int") @VintfStability
+enum LowSpeedCollisionWarningState {
+  OTHER = 0,
+  NO_WARNING = 1,
+  WARNING = 2,
+}
diff --git a/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleAirbagLocation.aidl b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleAirbagLocation.aidl
new file mode 100644
index 0000000..9b966d7
--- /dev/null
+++ b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleAirbagLocation.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.vehicle;
+@Backing(type="int") @VintfStability
+enum VehicleAirbagLocation {
+  OTHER = 0x01,
+  FRONT = 0x02,
+  KNEE = 0x04,
+  LEFT_SIDE = 0x08,
+  RIGHT_SIDE = 0x10,
+  CURTAIN = 0x20,
+}
diff --git a/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleApPowerBootupReason.aidl b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleApPowerBootupReason.aidl
index 9720aca..55af2ab 100644
--- a/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleApPowerBootupReason.aidl
+++ b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleApPowerBootupReason.aidl
@@ -37,4 +37,5 @@
   USER_POWER_ON = 0,
   SYSTEM_USER_DETECTION = 1,
   SYSTEM_REMOTE_ACCESS = 2,
+  SYSTEM_ENTER_GARAGE_MODE = 3,
 }
diff --git a/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleApPowerStateShutdownParam.aidl b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleApPowerStateShutdownParam.aidl
index 3fde1c7..8b345b2 100644
--- a/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleApPowerStateShutdownParam.aidl
+++ b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleApPowerStateShutdownParam.aidl
@@ -40,4 +40,5 @@
   SLEEP_IMMEDIATELY = 4,
   HIBERNATE_IMMEDIATELY = 5,
   CAN_HIBERNATE = 6,
+  EMERGENCY_SHUTDOWN = 7,
 }
diff --git a/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleArea.aidl b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleArea.aidl
index db867f4..b63003a 100644
--- a/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleArea.aidl
+++ b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleArea.aidl
@@ -40,5 +40,6 @@
   SEAT = 0x05000000,
   DOOR = 0x06000000,
   WHEEL = 0x07000000,
+  VENDOR = 0x08000000,
   MASK = 0x0f000000,
 }
diff --git a/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleAreaSeat.aidl b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleAreaSeat.aidl
index 44c9d54..a24f515 100644
--- a/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleAreaSeat.aidl
+++ b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleAreaSeat.aidl
@@ -34,6 +34,7 @@
 package android.hardware.automotive.vehicle;
 @Backing(type="int") @VintfStability
 enum VehicleAreaSeat {
+  UNKNOWN = 0x0000,
   ROW_1_LEFT = 0x0001,
   ROW_1_CENTER = 0x0002,
   ROW_1_RIGHT = 0x0004,
diff --git a/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleAutonomousState.aidl b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleAutonomousState.aidl
new file mode 100644
index 0000000..e15e71e
--- /dev/null
+++ b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleAutonomousState.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.vehicle;
+@Backing(type="int") @VintfStability
+enum VehicleAutonomousState {
+  LEVEL_0 = 0,
+  LEVEL_1 = 1,
+  LEVEL_2 = 2,
+  LEVEL_3 = 3,
+  LEVEL_4 = 4,
+  LEVEL_5 = 5,
+}
diff --git a/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleProperty.aidl b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleProperty.aidl
index ba75e7b..52876d1 100644
--- a/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleProperty.aidl
+++ b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleProperty.aidl
@@ -66,9 +66,11 @@
   EV_CHARGE_PORT_CONNECTED = (((0x030B + 0x10000000) + 0x01000000) + 0x00200000) /* 287310603 */,
   EV_BATTERY_INSTANTANEOUS_CHARGE_RATE = (((0x030C + 0x10000000) + 0x01000000) + 0x00600000) /* 291504908 */,
   RANGE_REMAINING = (((0x0308 + 0x10000000) + 0x01000000) + 0x00600000) /* 291504904 */,
+  EV_BATTERY_AVERAGE_TEMPERATURE = (((0x030E + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.FLOAT) /* 291504910 */,
   TIRE_PRESSURE = (((0x0309 + 0x10000000) + 0x07000000) + 0x00600000) /* 392168201 */,
   CRITICALLY_LOW_TIRE_PRESSURE = (((0x030A + 0x10000000) + 0x07000000) + 0x00600000) /* 392168202 */,
   ENGINE_IDLE_AUTO_STOP_ENABLED = (((0x0320 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.BOOLEAN) /* 287310624 */,
+  IMPACT_DETECTED = (((0x0330 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32) /* 289407792 */,
   GEAR_SELECTION = (((0x0400 + 0x10000000) + 0x01000000) + 0x00400000) /* 289408000 */,
   CURRENT_GEAR = (((0x0401 + 0x10000000) + 0x01000000) + 0x00400000) /* 289408001 */,
   PARKING_BRAKE_ON = (((0x0402 + 0x10000000) + 0x01000000) + 0x00200000) /* 287310850 */,
@@ -81,6 +83,8 @@
   ABS_ACTIVE = (((0x040A + 0x10000000) + 0x01000000) + 0x00200000) /* 287310858 */,
   TRACTION_CONTROL_ACTIVE = (((0x040B + 0x10000000) + 0x01000000) + 0x00200000) /* 287310859 */,
   EV_STOPPING_MODE = (((0x040D + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32) /* 289408013 */,
+  ELECTRONIC_STABILITY_CONTROL_ENABLED = (((0x040E + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.BOOLEAN) /* 287310862 */,
+  ELECTRONIC_STABILITY_CONTROL_STATE = (((0x040F + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32) /* 289408015 */,
   HVAC_FAN_SPEED = (((0x0500 + 0x10000000) + 0x05000000) + 0x00400000) /* 356517120 */,
   HVAC_FAN_DIRECTION = (((0x0501 + 0x10000000) + 0x05000000) + 0x00400000) /* 356517121 */,
   HVAC_TEMPERATURE_CURRENT = (((0x0502 + 0x10000000) + 0x05000000) + 0x00600000) /* 358614274 */,
@@ -118,6 +122,8 @@
   AP_POWER_BOOTUP_REASON = (((0x0A02 + 0x10000000) + 0x01000000) + 0x00400000) /* 289409538 */,
   DISPLAY_BRIGHTNESS = (((0x0A03 + 0x10000000) + 0x01000000) + 0x00400000) /* 289409539 */,
   PER_DISPLAY_BRIGHTNESS = (((0x0A04 + 0x10000000) + 0x01000000) + 0x00410000) /* 289475076 */,
+  VALET_MODE_ENABLED = (((0x0A05 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.BOOLEAN) /* 287312389 */,
+  HEAD_UP_DISPLAY_ENABLED = (((0x0A06 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.SEAT) + android.hardware.automotive.vehicle.VehiclePropertyType.BOOLEAN) /* 354421254 */,
   HW_KEY_INPUT = (((0x0A10 + 0x10000000) + 0x01000000) + 0x00410000) /* 289475088 */,
   HW_KEY_INPUT_V2 = (((0x0A11 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.SEAT) + android.hardware.automotive.vehicle.VehiclePropertyType.MIXED) /* 367004177 */,
   HW_MOTION_INPUT = (((0x0A12 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.SEAT) + android.hardware.automotive.vehicle.VehiclePropertyType.MIXED) /* 367004178 */,
@@ -167,11 +173,13 @@
   SEAT_FOOTWELL_LIGHTS_SWITCH = (((0x0B9C + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.SEAT) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32) /* 356518812 */,
   SEAT_EASY_ACCESS_ENABLED = (((0x0B9D + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.SEAT) + android.hardware.automotive.vehicle.VehiclePropertyType.BOOLEAN) /* 354421661 */,
   SEAT_AIRBAG_ENABLED = (((0x0B9E + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.SEAT) + android.hardware.automotive.vehicle.VehiclePropertyType.BOOLEAN) /* 354421662 */,
+  SEAT_AIRBAGS_DEPLOYED = (((0x0BA5 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.SEAT) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32) /* 356518821 */,
   SEAT_CUSHION_SIDE_SUPPORT_POS = (((0x0B9F + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.SEAT) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32) /* 356518815 */,
   SEAT_CUSHION_SIDE_SUPPORT_MOVE = (((0x0BA0 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.SEAT) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32) /* 356518816 */,
   SEAT_LUMBAR_VERTICAL_POS = (((0x0BA1 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.SEAT) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32) /* 356518817 */,
   SEAT_LUMBAR_VERTICAL_MOVE = (((0x0BA2 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.SEAT) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32) /* 356518818 */,
   SEAT_WALK_IN_POS = (((0x0BA3 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.SEAT) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32) /* 356518819 */,
+  SEAT_BELT_PRETENSIONER_DEPLOYED = (((0x0BA6 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.SEAT) + android.hardware.automotive.vehicle.VehiclePropertyType.BOOLEAN) /* 354421670 */,
   SEAT_OCCUPANCY = (((0x0BB0 + 0x10000000) + 0x05000000) + 0x00400000) /* 356518832 */,
   WINDOW_POS = (((0x0BC0 + 0x10000000) + 0x03000000) + 0x00400000) /* 322964416 */,
   WINDOW_MOVE = (((0x0BC1 + 0x10000000) + 0x03000000) + 0x00400000) /* 322964417 */,
@@ -190,6 +198,12 @@
   GLOVE_BOX_LOCKED = (((0x0BF1 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.SEAT) + android.hardware.automotive.vehicle.VehiclePropertyType.BOOLEAN) /* 354421745 */,
   VEHICLE_MAP_SERVICE = (((0x0C00 + 0x10000000) + 0x01000000) + 0x00e00000) /* 299895808 */,
   LOCATION_CHARACTERIZATION = (((0x0C10 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32) /* 289410064 */,
+  ULTRASONICS_SENSOR_POSITION = (((0x0C20 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.VENDOR) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32_VEC) /* 406916128 */,
+  ULTRASONICS_SENSOR_ORIENTATION = (((0x0C21 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.VENDOR) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32_VEC) /* 406916129 */,
+  ULTRASONICS_SENSOR_FIELD_OF_VIEW = (((0x0C22 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.VENDOR) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32_VEC) /* 406916130 */,
+  ULTRASONICS_SENSOR_DETECTION_RANGE = (((0x0C23 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.VENDOR) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32_VEC) /* 406916131 */,
+  ULTRASONICS_SENSOR_SUPPORTED_RANGES = (((0x0C24 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.VENDOR) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32_VEC) /* 406916132 */,
+  ULTRASONICS_SENSOR_MEASURED_DISTANCE = (((0x0C25 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.VENDOR) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32_VEC) /* 406916133 */,
   OBD2_LIVE_FRAME = (((0x0D00 + 0x10000000) + 0x01000000) + 0x00e00000) /* 299896064 */,
   OBD2_FREEZE_FRAME = (((0x0D01 + 0x10000000) + 0x01000000) + 0x00e00000) /* 299896065 */,
   OBD2_FREEZE_FRAME_INFO = (((0x0D02 + 0x10000000) + 0x01000000) + 0x00e00000) /* 299896066 */,
@@ -245,6 +259,8 @@
   SUPPORTED_PROPERTY_IDS = (((0x0F48 + 0x10000000) + 0x01000000) + 0x00410000) /* 289476424 */,
   SHUTDOWN_REQUEST = (((0x0F49 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32) /* 289410889 */,
   VEHICLE_IN_USE = (((0x0F4A + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.BOOLEAN) /* 287313738 */,
+  CLUSTER_HEARTBEAT = (((0x0F4B + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.MIXED) /* 299896651 */,
+  VEHICLE_DRIVING_AUTOMATION_CURRENT_LEVEL = (((0x0F4C + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32) /* 289410892 */,
   AUTOMATIC_EMERGENCY_BRAKING_ENABLED = (((0x1000 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.BOOLEAN) /* 287313920 */,
   AUTOMATIC_EMERGENCY_BRAKING_STATE = (((0x1001 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32) /* 289411073 */,
   FORWARD_COLLISION_WARNING_ENABLED = (((0x1002 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.BOOLEAN) /* 287313922 */,
@@ -270,4 +286,18 @@
   HANDS_ON_DETECTION_ENABLED = (((0x1016 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.BOOLEAN) /* 287313942 */,
   HANDS_ON_DETECTION_DRIVER_STATE = (((0x1017 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32) /* 289411095 */,
   HANDS_ON_DETECTION_WARNING = (((0x1018 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32) /* 289411096 */,
+  DRIVER_DROWSINESS_ATTENTION_SYSTEM_ENABLED = (((0x1019 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.BOOLEAN) /* 287313945 */,
+  DRIVER_DROWSINESS_ATTENTION_STATE = (((0x101A + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32) /* 289411098 */,
+  DRIVER_DROWSINESS_ATTENTION_WARNING_ENABLED = (((0x101B + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.BOOLEAN) /* 287313947 */,
+  DRIVER_DROWSINESS_ATTENTION_WARNING = (((0x101C + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32) /* 289411100 */,
+  DRIVER_DISTRACTION_SYSTEM_ENABLED = (((0x101D + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.BOOLEAN) /* 287313949 */,
+  DRIVER_DISTRACTION_STATE = (((0x101E + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32) /* 289411102 */,
+  DRIVER_DISTRACTION_WARNING_ENABLED = (((0x101F + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.BOOLEAN) /* 287313951 */,
+  DRIVER_DISTRACTION_WARNING = (((0x1020 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32) /* 289411104 */,
+  LOW_SPEED_COLLISION_WARNING_ENABLED = (((0x1021 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.BOOLEAN) /* 287313953 */,
+  LOW_SPEED_COLLISION_WARNING_STATE = (((0x1022 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32) /* 289411106 */,
+  CROSS_TRAFFIC_MONITORING_ENABLED = (((0x1023 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.BOOLEAN) /* 287313955 */,
+  CROSS_TRAFFIC_MONITORING_WARNING_STATE = (((0x1024 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32) /* 289411108 */,
+  LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_ENABLED = (((0x1025 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.BOOLEAN) /* 287313957 */,
+  LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE = (((0x1026 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32) /* 289411110 */,
 }
diff --git a/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehiclePropertyGroup.aidl b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehiclePropertyGroup.aidl
index 714d514..b4f6850 100644
--- a/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehiclePropertyGroup.aidl
+++ b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehiclePropertyGroup.aidl
@@ -36,5 +36,6 @@
 enum VehiclePropertyGroup {
   SYSTEM = 0x10000000,
   VENDOR = 0x20000000,
+  BACKPORTED = 0x30000000,
   MASK = 0xf0000000,
 }
diff --git a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/CrossTrafficMonitoringWarningState.aidl b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/CrossTrafficMonitoringWarningState.aidl
new file mode 100644
index 0000000..05be65d
--- /dev/null
+++ b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/CrossTrafficMonitoringWarningState.aidl
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.vehicle;
+
+/**
+ * Used to enumerate the state of Cross Traffic Monitoring Warning system.
+ */
+@VintfStability
+@Backing(type="int")
+enum CrossTrafficMonitoringWarningState {
+
+    /**
+     * This state is used as an alternative to any CrossTrafficMonitoringWarningState value that is
+     * not defined in the platform. Ideally, implementations of
+     * VehicleProperty#CROSS_TRAFFIC_MONITORING_WARNING_STATE should not use this state. The
+     * framework can use this field to remain backwards compatible if
+     * CrossTrafficMonitoringWarningState is extended to include additional states.
+     */
+    OTHER = 0,
+    /**
+     * Cross Traffic Monitoring Warning is enabled and monitoring safety, but no potential collision
+     * is detected.
+     */
+    NO_WARNING = 1,
+    /**
+     * Cross Traffic Monitoring Warning is enabled and is actively warning the user of incoming
+     * moving objects coming from the driver's left side in front of the vehicle.
+     */
+    WARNING_FRONT_LEFT = 2,
+    /**
+     * Cross Traffic Monitoring Warning is enabled and is actively warning the user of incoming
+     * moving objects coming from the driver's right side in front of the vehicle.
+     */
+    WARNING_FRONT_RIGHT = 3,
+    /**
+     * Cross Traffic Monitoring Warning is enabled and is actively warning the user of incoming
+     * moving objects coming from both the driver's left side and the driver's right side in front
+     * of the vehicle.
+     */
+    WARNING_FRONT_BOTH = 4,
+    /**
+     * Cross Traffic Monitoring Warning is enabled and is actively warning the user of incoming
+     * moving objects coming from the driver's left side behind the vehicle.
+     */
+    WARNING_REAR_LEFT = 5,
+    /**
+     * Cross Traffic Monitoring Warning is enabled and is actively warning the user of incoming
+     * moving objects coming from the driver's right side behind the vehicle.
+     */
+    WARNING_REAR_RIGHT = 6,
+    /**
+     * Cross Traffic Monitoring Warning is enabled and is actively warning the user of incoming
+     * moving objects coming from the driver's left side and the driver's right side behind the
+     * vehicle.
+     */
+    WARNING_REAR_BOTH = 7,
+}
diff --git a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/DriverDistractionState.aidl b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/DriverDistractionState.aidl
new file mode 100644
index 0000000..f350a6c
--- /dev/null
+++ b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/DriverDistractionState.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.vehicle;
+
+/**
+ * Used to enumerate the current state of driver distraction monitoring.
+ *
+ * This enum could be extended in future releases to include additional feature states.
+ */
+@VintfStability
+@Backing(type="int")
+enum DriverDistractionState {
+    /**
+     * This state is used as an alternative for any DriverDistractionState value that is not
+     * defined in the platform. Ideally, implementations of
+     * VehicleProperty#DRIVER_DISTRACTION_STATE should not use this state. The framework
+     * can use this field to remain backwards compatible if DriverDistractionState is
+     * extended to include additional states.
+     */
+    OTHER = 0,
+    /**
+     * The system detects that the driver is attentive / not distracted.
+     */
+    NOT_DISTRACTED = 1,
+    /**
+     * The system detects that the driver is distracted, which can be anything that reduces the
+     * driver's foucs on the primary task of driving/controlling the vehicle.
+     */
+    DISTRACTED = 2,
+}
diff --git a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/DriverDistractionWarning.aidl b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/DriverDistractionWarning.aidl
new file mode 100644
index 0000000..a4b1984
--- /dev/null
+++ b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/DriverDistractionWarning.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.vehicle;
+
+/**
+ * Used to enumerate the current warning state of the driver distraction monitoring system.
+ */
+@VintfStability
+@Backing(type="int")
+enum DriverDistractionWarning {
+    /**
+     * This state is used as an alternative for any DriverDistractionWarning value that is
+     * defined in the platform. Ideally, implementations of
+     * VehicleProperty#DRIVER_DISTRACTION_WARNING should not use this state. The framework
+     * can use this field to remain backwards compatible if DriverDistractionWarning is
+     * extended to include additional states.
+     */
+    OTHER = 0,
+    /**
+     * When the driver distraction warning is enabled and the driver's current distraction level
+     * does not warrant the system to send a warning.
+     */
+    NO_WARNING = 1,
+    /**
+     * When the driver distraction warning is enabled and the system is warning the driver based on
+     * its assessment of the driver's current distraction level.
+     */
+    WARNING = 2,
+}
diff --git a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/DriverDrowsinessAttentionState.aidl b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/DriverDrowsinessAttentionState.aidl
new file mode 100644
index 0000000..d2aec1f
--- /dev/null
+++ b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/DriverDrowsinessAttentionState.aidl
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.vehicle;
+
+/**
+ * Used to enumerate the current state of driver drowsiness and attention monitoring.
+ *
+ * This enum could be extended in future releases to include additional feature states.
+ */
+@VintfStability
+@Backing(type="int")
+enum DriverDrowsinessAttentionState {
+    /**
+     * This state is used as an alternative for any DriverDrowsinessAttentionState value that is not
+     * defined in the platform. Ideally, implementations of
+     * VehicleProperty#DRIVER_DROWSINESS_ATTENTION_STATE should not use this state. The framework
+     * can use this field to remain backwards compatible if DriverDrowsinessAttentionState is
+     * extended to include additional states.
+     */
+    OTHER = 0,
+    /**
+     * Karolinska Sleepiness Scale Rating 1 described as extermely alert.
+     */
+    KSS_RATING_1_EXTREMELY_ALERT = 1,
+    /**
+     * Karolinska Sleepiness Scale Rating 2 described as very alert.
+     */
+    KSS_RATING_2_VERY_ALERT = 2,
+    /**
+     * Karolinska Sleepiness Scale Rating 3 described as alert.
+     */
+    KSS_RATING_3_ALERT = 3,
+    /**
+     * Karolinska Sleepiness Scale Rating 4 described as rather alert.
+     */
+    KSS_RATING_4_RATHER_ALERT = 4,
+    /**
+     * Karolinska Sleepiness Scale Rating 5 described as neither alert nor sleepy.
+     */
+    KSS_RATING_5_NEITHER_ALERT_NOR_SLEEPY = 5,
+    /**
+     * Karolinska Sleepiness Scale Rating 6 described as some signs of sleepiness.
+     */
+    KSS_RATING_6_SOME_SLEEPINESS = 6,
+    /**
+     * Karolinska Sleepiness Scale Rating 7 described as sleepy with no effort to
+     * keep awake.
+     */
+    KSS_RATING_7_SLEEPY_NO_EFFORT = 7,
+    /**
+     * Karolinska Sleepiness Scale Rating 8 described as sleepy with some effort to
+     * keep awake.
+     */
+    KSS_RATING_8_SLEEPY_SOME_EFFORT = 8,
+    /**
+     * Karolinska Sleepiness Scale Rating 9 described as very sleepy, with great
+     * effort to keep away, and fighthing sleep.
+     */
+    KSS_RATING_9_VERY_SLEEPY = 9,
+}
diff --git a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/DriverDrowsinessAttentionWarning.aidl b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/DriverDrowsinessAttentionWarning.aidl
new file mode 100644
index 0000000..53b66b9
--- /dev/null
+++ b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/DriverDrowsinessAttentionWarning.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.vehicle;
+
+/**
+ * Used to enumerate the current warning state of the driver drowsiness and attention monitoring
+ * system.
+ */
+@VintfStability
+@Backing(type="int")
+enum DriverDrowsinessAttentionWarning {
+    /**
+     * This state is used as an alternative for any DriverDrowsinessAttentionWarning value that is
+     * defined in the platform. Ideally, implementations of
+     * VehicleProperty#DRIVER_DROWSINESS_ATTENTION_WARNING should not use this state. The framework
+     * can use this field to remain backwards compatible if DriverDrowsinessAttentionWarning is
+     * extended to include additional states.
+     */
+    OTHER = 0,
+    /**
+     * When the driver drowsiness and attention warning is enabled, and the driver's current
+     * drowsiness and attention level does not warrant the system to send a warning.
+     */
+    NO_WARNING = 1,
+    /**
+     * When the driver drowsiness and attention warning is enabled, and the system is warning the
+     * driver based on its assessment of the driver's current drowsiness and attention level.
+     */
+    WARNING = 2,
+}
diff --git a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/ElectronicStabilityControlState.aidl b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/ElectronicStabilityControlState.aidl
new file mode 100644
index 0000000..006bbf2
--- /dev/null
+++ b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/ElectronicStabilityControlState.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.vehicle;
+
+/**
+ * Used to enumerate the state of Electronic Stability Control (ESC).
+ */
+@VintfStability
+@Backing(type="int")
+enum ElectronicStabilityControlState {
+
+    /**
+     * This state is used as an alternative to any ElectronicStabilityControlState value that is not
+     * defined in the platform. Ideally, implementations of
+     * VehicleProperty#ELECTRONIC_STABILITY_CONTROL_STATE should not use this state. The framework
+     * can use this field to remain backwards compatible if ElectronicStabilityControlState is
+     * extended to include additional states.
+     */
+    OTHER = 0,
+    /**
+     * ESC is enabled and monitoring safety, but is not actively controlling the tires to prevent
+     * the car from skidding.
+     */
+    ENABLED = 1,
+    /**
+     * ESC is enabled and is actively controlling the tires to prevent the car from skidding.
+     */
+    ACTIVATED = 2,
+}
diff --git a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/ImpactSensorLocation.aidl b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/ImpactSensorLocation.aidl
new file mode 100644
index 0000000..0fc1a50
--- /dev/null
+++ b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/ImpactSensorLocation.aidl
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.vehicle;
+
+/**
+ * Used to enumerate the various impact sensor locations on the car.
+ */
+@VintfStability
+@Backing(type="int")
+enum ImpactSensorLocation {
+    /**
+     * Other impact sensor location. Ideally this should never be used.
+     */
+    OTHER = 0x01,
+    /**
+     * Frontal impact sensor. Used for the sensor that detects head-on impact.
+     */
+    FRONT = 0x02,
+    /**
+     * Front-left door side impact sensor. Used for the sensor that detects collisions from the
+     * side, in particular on the front-left door.
+     */
+    FRONT_LEFT_DOOR_SIDE = 0x04,
+    /**
+     * Front-right door side impact sensor. Used for the sensor that detects collisions from the
+     * side, in particular on the front-right door.
+     */
+    FRONT_RIGHT_DOOR_SIDE = 0x08,
+    /**
+     * Rear-left door side impact sensor. Used for the sensor that detects collisions from the
+     * side, in particular on the rear-left door.
+     */
+    REAR_LEFT_DOOR_SIDE = 0x10,
+    /**
+     * Rear-right door side impact sensor. Used for the sensor that detects collisions from the
+     * side, in particular on the rear-right door.
+     */
+    REAR_RIGHT_DOOR_SIDE = 0x20,
+    /**
+     * Rear impact sensor. Used for the sensor that detects collisions from the rear.
+     */
+    REAR = 0x40,
+}
diff --git a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/LowSpeedAutomaticEmergencyBrakingState.aidl b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/LowSpeedAutomaticEmergencyBrakingState.aidl
new file mode 100644
index 0000000..978da25
--- /dev/null
+++ b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/LowSpeedAutomaticEmergencyBrakingState.aidl
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.vehicle;
+
+/**
+ * Used to enumerate the state of Low Speed Automatic Emergency Braking.
+ */
+@VintfStability
+@Backing(type="int")
+enum LowSpeedAutomaticEmergencyBrakingState {
+
+    /**
+     * This state is used as an alternative to any LowSpeedAutomaticEmergencyBrakingState value that
+     * is not defined in the platform. Ideally, implementations of
+     * VehicleProperty#LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE should not use this state. The
+     * framework can use this field to remain backwards compatible if
+     * LowSpeedAutomaticEmergencyBrakingState is extended to include additional states.
+     */
+    OTHER = 0,
+    /**
+     * Low Speed Automatic Emergency Braking is enabled and monitoring safety, but brakes are not
+     * activated.
+     */
+    ENABLED = 1,
+    /**
+     * Low Speed Automatic Emergency Braking is enabled and currently has the brakes applied for the
+     * vehicle.
+     */
+    ACTIVATED = 2,
+    /**
+     * Many Low Speed Automatic Emergency Braking implementations allow the driver to override Low
+     * Speed Automatic Emergency Braking. This means that the car has determined it should brake,
+     * but a user decides to take over and do something else. This is often done for safety reasons
+     * and to ensure that the driver can always take control of the vehicle. This state should be
+     * set when the user is actively overriding the low speed automatic emergency braking system.
+     */
+    USER_OVERRIDE = 3,
+}
diff --git a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/LowSpeedCollisionWarningState.aidl b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/LowSpeedCollisionWarningState.aidl
new file mode 100644
index 0000000..028a2d9
--- /dev/null
+++ b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/LowSpeedCollisionWarningState.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.vehicle;
+
+/**
+ * Used to enumerate the state of Low Speed Collision Warning State.
+ */
+@VintfStability
+@Backing(type="int")
+enum LowSpeedCollisionWarningState {
+
+    /**
+     * This state is used as an alternative to any LowSpeedCollisionWarningState value that is not
+     * defined in the platform. Ideally, implementations of
+     * VehicleProperty#LOW_SPEED_COLLISION_WARNING_STATE should not use this state. The framework
+     * can use this field to remain backwards compatible if LowSpeedCollisionWarningState is
+     * extended to include additional states.
+     */
+    OTHER = 0,
+    /**
+     * Low Speed Collision Warning is enabled and monitoring for potential collision, but no
+     * potential collision is detected.
+     */
+    NO_WARNING = 1,
+    /**
+     * Low Speed Collision Warning is enabled, detects a potential collision, and is actively
+     * warning the user.
+     */
+    WARNING = 2,
+}
diff --git a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleAirbagLocation.aidl b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleAirbagLocation.aidl
new file mode 100644
index 0000000..e4c43f7
--- /dev/null
+++ b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleAirbagLocation.aidl
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.vehicle;
+
+/**
+ * Used to enumerate the various airbag locations per seat.
+ */
+@VintfStability
+@Backing(type="int")
+enum VehicleAirbagLocation {
+    /**
+     * This state is used as an alternative to any VehicleAirbagLocation value that is not defined
+     * in the platform. Ideally, implementations of VehicleProperty::SEAT_AIRBAGS_DEPLOYED should
+     * not use this state. The framework can use this field to remain backwards compatible if
+     * VehicleAirbagLocation is extended to include additional states.
+     */
+    OTHER = 0x01,
+    /**
+     * Front airbags. This enum is for the airbags that protect the seated person from the front,
+     * particularly the seated person's torso.
+     */
+    FRONT = 0x02,
+    /**
+     * Knee airbags. This enum is for the airbags that protect the seated person's knees.
+     */
+    KNEE = 0x04,
+    /**
+     * Left side airbags. This enum is for the side airbags that protect the left side of the seated
+     * person.
+     */
+    LEFT_SIDE = 0x08,
+    /**
+     * Right side airbags. This enum is for the side airbags that protect the right side of the
+     * seated person.
+     */
+    RIGHT_SIDE = 0x10,
+    /**
+     * Curtain airbags. This enum is for the airbags lined above the windows of the vehicle.
+     */
+    CURTAIN = 0x20,
+}
diff --git a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleApPowerBootupReason.aidl b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleApPowerBootupReason.aidl
index e325b38..8c8c2da 100644
--- a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleApPowerBootupReason.aidl
+++ b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleApPowerBootupReason.aidl
@@ -34,7 +34,24 @@
     SYSTEM_USER_DETECTION = 1,
     /**
      * Automatic power on to execute a remote task. This is triggered by
-     * receiving a wakeup message from TCU wakeup client.
+     * receiving a wakeup message from an external system in the vehicle.
      */
     SYSTEM_REMOTE_ACCESS = 2,
+    /**
+     * Automatic power on to enter garage mode. This is triggered by
+     * receiving a wakeup message from an external system in the vehicle.
+     *
+     * Note that this does not necessarily mean Android will enter
+     * the garage mode since user may enter the vehicle after this is set.
+     * The system will only enter garage mode if VEHICLE_IN_USE is not true
+     * upon check.
+     *
+     * To consider the Time-Of-Check-Time-Of-Use issue, there is a slight chance
+     * that the vehicle become in-use after car service does the VEHICLE_IN_USE
+     * check. The external power controller must also check whether the vehicle
+     * is in use upon receiving the SHUTDOWN_REQUEST, before sending out
+     * SHUTDOWN_PREPARE, to make sure the system does not enter garage mode or
+     * shutdown if the vehicle is currently in use.
+     */
+    SYSTEM_ENTER_GARAGE_MODE = 3,
 }
diff --git a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleApPowerStateShutdownParam.aidl b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleApPowerStateShutdownParam.aidl
index a863d14..538b905 100644
--- a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleApPowerStateShutdownParam.aidl
+++ b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleApPowerStateShutdownParam.aidl
@@ -20,29 +20,39 @@
 @Backing(type="int")
 enum VehicleApPowerStateShutdownParam {
     /**
-     * AP must shutdown immediately. Postponing is not allowed.
+     * AP must shutdown without Garage mode.
+     * If AP need to shutdown as soon as possible, EMERGENCY_SHUTDOWN shall be used.
      */
     SHUTDOWN_IMMEDIATELY = 1,
     /**
      * AP can enter deep sleep instead of shutting down completely.
+     * AP can postpone entering deep sleep to run Garage mode.
      */
     CAN_SLEEP = 2,
     /**
-     * AP can only shutdown with postponing allowed.
+     * AP can only shutdown.
+     * AP can postpone shutdown to run Garage mode.
      */
     SHUTDOWN_ONLY = 3,
     /**
-     * AP may enter deep sleep, but must either sleep or shut down immediately.
-     * Postponing is not allowed.
+     * AP can enter deep sleep, without Garage mode.
+     * Depending on the actual implementation, it may shut down immediately
      */
     SLEEP_IMMEDIATELY = 4,
     /**
-     * AP must hibernate (suspend to disk) immediately. Postponing is not allowed.
-     * Depending on the actual implementation, it may shut down immediately
+     * AP can hibernate (suspend to disk) without Garage mode.
+     * Depending on the actual implementation, it may shut down immediately.
      */
     HIBERNATE_IMMEDIATELY = 5,
     /**
      * AP can enter hibernation (suspend to disk) instead of shutting down completely.
+     * AP can postpone hibernation to run Garage mode.
      */
     CAN_HIBERNATE = 6,
+    /**
+     * AP must shutdown (gracefully) without a delay. AP cannot run Garage mode.
+     * This type must be used only in critical situations when AP must shutdown as soon as possible.
+     * CarService will only notify listeners, but will not wait for completion reports.
+     */
+    EMERGENCY_SHUTDOWN = 7,
 }
diff --git a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleArea.aidl b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleArea.aidl
index 6f7f783..259b231 100644
--- a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleArea.aidl
+++ b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleArea.aidl
@@ -49,6 +49,11 @@
     DOOR = 0x06000000,
     /** WHEEL maps to enum VehicleAreaWheel */
     WHEEL = 0x07000000,
+    /**
+     * A property with the VENDOR vehicle area contains area IDs that are vendor defined. Each area
+     * ID within this area type must be unique with no overlapping bits set.
+     */
+    VENDOR = 0x08000000,
 
     MASK = 0x0f000000,
 }
diff --git a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleAreaSeat.aidl b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleAreaSeat.aidl
index 89d50ea..e70fb22 100644
--- a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleAreaSeat.aidl
+++ b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleAreaSeat.aidl
@@ -22,6 +22,7 @@
 @VintfStability
 @Backing(type="int")
 enum VehicleAreaSeat {
+    UNKNOWN = 0x0000,
     ROW_1_LEFT = 0x0001,
     ROW_1_CENTER = 0x0002,
     ROW_1_RIGHT = 0x0004,
diff --git a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleAutonomousState.aidl b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleAutonomousState.aidl
new file mode 100644
index 0000000..3860e7f
--- /dev/null
+++ b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleAutonomousState.aidl
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.vehicle;
+
+/**
+ * Used to enumerate the various level of automation that can be expressed by the
+ * VEHICLE_DRIVING_AUTOMATION_CURRENT_LEVEL property.
+ */
+@VintfStability
+@Backing(type="int")
+enum VehicleAutonomousState {
+    /**
+     * No automation. ADAS systems are limited to providing warnings and momentary assistance. The
+     * driver is in constant supervision of all driving tasks and must steer, brake or accelerate as
+     * needed to maintain safety, and is still responsible for driving while the ADAS systems are
+     * engaged. Usage should be in accordance to Level 0 definition in J3016_202104 version of
+     * vehicle autonomy levels defined by SAE.
+     */
+    LEVEL_0 = 0,
+    /**
+     * Driver assistance. ADAS systems can provide steering or brake/acceleration support to the
+     * driver. The driver is in constant supervision of all driving tasks and must steer, brake or
+     * accelerate as needed to maintain safety, and is still responsible for driving while the ADAS
+     * systems are engaged. Usage should be in accordance to Level 1 definition in J3016_202104
+     * version of vehicle autonomy levels defined by SAE.
+     */
+    LEVEL_1 = 1,
+    /**
+     * Partial automation. ADAS systems can provide both steering and brake/acceleration support to
+     * the driver at the same time. The driver is in constant supervision of all driving tasks and
+     * must steer, brake or accelerate as needed to maintain safety, and is still responsible for
+     * driving while the ADAS systems are engaged. Usage should be in accordance to Level 2
+     * definition in J3016_202104 version of vehicle autonomy levels defined by SAE.
+     */
+    LEVEL_2 = 2,
+    /**
+     * Conditional automation. ADAS systems can drive the vehicle under limited conditions and will
+     * not operate unless all required conditions are met. The driver is required to take over
+     * control of the vehicle when requested to do so by the ADAS systems, however is not
+     * responsible for driving while the ADAS systems are engaged. Usage should be in accordance to
+     * Level 3 definition in J3016_202104 version of vehicle autonomy levels defined by SAE.
+     */
+    LEVEL_3 = 3,
+    /**
+     * High automation. ADAS systems can drive the vehicle under limited conditions and will not
+     * operate unless all required conditions are met. The driver is not required to take over
+     * control of the vehicle and is not responsible for driving while the ADAS systems are engaged.
+     * Usage should be in accordance to Level 4 definition in J3016_202104 version of vehicle
+     * autonomy levels defined by SAE.
+     */
+    LEVEL_4 = 4,
+    /**
+     * Full automation. ADAS systems can drive the vehicle under all conditions. The driver is not
+     * required to take over control of the vehicle and is not responsible for driving while the
+     * ADAS systems are engaged. Usage should be in accordance to Level 5 definition in J3016_202104
+     * version of vehicle autonomy levels defined by SAE.
+     */
+    LEVEL_5 = 5,
+}
diff --git a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl
index d9c6de7..026c040 100644
--- a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl
+++ b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl
@@ -52,6 +52,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     INFO_VIN = 0x0100 + 0x10000000 + 0x01000000
             + 0x00100000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:STRING
@@ -60,6 +61,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     INFO_MAKE = 0x0101 + 0x10000000 + 0x01000000
             + 0x00100000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:STRING
@@ -68,6 +70,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     INFO_MODEL = 0x0102 + 0x10000000 + 0x01000000
             + 0x00100000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:STRING
@@ -77,6 +80,7 @@
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:YEAR
+     * @version 2
      */
     INFO_MODEL_YEAR = 0x0103 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -86,6 +90,7 @@
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:MILLILITER
+     * @version 2
      */
     INFO_FUEL_CAPACITY = 0x0104 + 0x10000000 + 0x01000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:FLOAT
@@ -105,6 +110,7 @@
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
      * @data_enum FuelType
+     * @version 2
      */
     INFO_FUEL_TYPE = 0x0105 + 0x10000000 + 0x01000000
             + 0x00410000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
@@ -119,6 +125,7 @@
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:WH
+     * @version 2
      */
     INFO_EV_BATTERY_CAPACITY = 0x0106 + 0x10000000 + 0x01000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:FLOAT
@@ -128,6 +135,7 @@
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @data_enum EvConnectorType
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     INFO_EV_CONNECTOR_TYPE = 0x0107 + 0x10000000 + 0x01000000
             + 0x00410000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
@@ -137,6 +145,7 @@
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @data_enum PortLocationType
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     INFO_FUEL_DOOR_LOCATION = 0x0108 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -146,6 +155,7 @@
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
      * @data_enum PortLocationType
+     * @version 2
      */
     INFO_EV_PORT_LOCATION = 0x0109 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -156,6 +166,7 @@
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @data_enum VehicleAreaSeat
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     INFO_DRIVER_SEAT = 0x010A + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -169,11 +180,12 @@
      *  int32Values[4] = wheel base
      *  int32Values[5] = track width front
      *  int32Values[6] = track width rear
-     *  int32Values[7] = curb to curb turning radius
+     *  int32Values[7] = curb to curb turning diameter
      *
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:MILLIMETER
+     * @version 2
      */
     INFO_EXTERIOR_DIMENSIONS = 0x010B + 0x10000000 + 0x01000000
             + 0x00410000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
@@ -189,6 +201,7 @@
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
      * @data_enum PortLocationType
+     * @version 2
      */
     INFO_MULTI_EV_PORT_LOCATIONS = 0x010C + 0x10000000 + 0x01000000
             + 0x00410000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
@@ -198,6 +211,7 @@
      * @change_mode VehiclePropertyChangeMode.CONTINUOUS
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:KILOMETER
+     * @version 2
      */
     PERF_ODOMETER = 0x0204 + 0x10000000 + 0x01000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:FLOAT
@@ -213,6 +227,7 @@
      * @change_mode VehiclePropertyChangeMode.CONTINUOUS
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:METER_PER_SEC
+     * @version 2
      */
     PERF_VEHICLE_SPEED = 0x0207 + 0x10000000 + 0x01000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:FLOAT
@@ -225,6 +240,7 @@
      * @change_mode VehiclePropertyChangeMode.CONTINUOUS
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:METER_PER_SEC
+     * @version 2
      */
     PERF_VEHICLE_SPEED_DISPLAY = 0x0208 + 0x10000000 + 0x01000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:FLOAT
@@ -236,6 +252,7 @@
      * @change_mode VehiclePropertyChangeMode.CONTINUOUS
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:DEGREES
+     * @version 2
      */
     PERF_STEERING_ANGLE = 0x0209 + 0x10000000 + 0x01000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:FLOAT
@@ -247,6 +264,7 @@
      * @change_mode VehiclePropertyChangeMode.CONTINUOUS
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:DEGREES
+     * @version 2
      */
     PERF_REAR_STEERING_ANGLE = 0x0210 + 0x10000000 + 0x01000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:FLOAT
@@ -256,6 +274,7 @@
      * @change_mode VehiclePropertyChangeMode.CONTINUOUS
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:CELSIUS
+     * @version 2
      */
     ENGINE_COOLANT_TEMP = 0x0301 + 0x10000000 + 0x01000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:FLOAT
@@ -265,6 +284,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleOilLevel
+     * @version 2
      */
     ENGINE_OIL_LEVEL = 0x0303 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -274,6 +294,7 @@
      * @change_mode VehiclePropertyChangeMode.CONTINUOUS
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:CELSIUS
+     * @version 2
      */
     ENGINE_OIL_TEMP = 0x0304 + 0x10000000 + 0x01000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:FLOAT
@@ -283,6 +304,7 @@
      * @change_mode VehiclePropertyChangeMode.CONTINUOUS
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:RPM
+     * @version 2
      */
     ENGINE_RPM = 0x0305 + 0x10000000 + 0x01000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:FLOAT
@@ -323,6 +345,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.CONTINUOUS
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     WHEEL_TICK = 0x0306 + 0x10000000 + 0x01000000
             + 0x00510000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT64_VEC
@@ -334,6 +357,7 @@
      * @change_mode VehiclePropertyChangeMode.CONTINUOUS
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:MILLILITER
+     * @version 2
      */
     FUEL_LEVEL = 0x0307 + 0x10000000 + 0x01000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:FLOAT
@@ -345,6 +369,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     FUEL_DOOR_OPEN = 0x0308 + 0x10000000 + 0x01000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
@@ -358,6 +384,7 @@
      * @change_mode VehiclePropertyChangeMode.CONTINUOUS
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:WH
+     * @version 2
      */
     EV_BATTERY_LEVEL = 0x0309 + 0x10000000 + 0x01000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:FLOAT
@@ -372,6 +399,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:WH
+     * @version 2
      */
     EV_CURRENT_BATTERY_CAPACITY =
             0x030D + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.FLOAT,
@@ -383,6 +411,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     EV_CHARGE_PORT_OPEN = 0x030A + 0x10000000 + 0x01000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
@@ -391,6 +421,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     EV_CHARGE_PORT_CONNECTED = 0x030B + 0x10000000 + 0x01000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
@@ -403,6 +434,7 @@
      * @change_mode VehiclePropertyChangeMode.CONTINUOUS
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:MW
+     * @version 2
      */
     EV_BATTERY_INSTANTANEOUS_CHARGE_RATE = 0x030C + 0x10000000 + 0x01000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:FLOAT
@@ -419,11 +451,27 @@
      *
      * @change_mode VehiclePropertyChangeMode.CONTINUOUS
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:METER
+     * @version 2
      */
     RANGE_REMAINING = 0x0308 + 0x10000000 + 0x01000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:FLOAT
     /**
+     * EV battery average temperature
+     *
+     * Exposes the temperature of the battery in an EV. If multiple batteries exist in the EV, or
+     * multiple temperature sensors exist, this property should be set to the mean or a meaningful
+     * weighted average that best represents the overall temperature of the battery system.
+     *
+     * @change_mode VehiclePropertyChangeMode.CONTINUOUS
+     * @access VehiclePropertyAccess.READ
+     * @unit VehicleUnit:CELSIUS
+     * @version 3
+     */
+    EV_BATTERY_AVERAGE_TEMPERATURE =
+            0x030E + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.FLOAT,
+    /**
      * Tire pressure
      *
      * Each tires is identified by its areaConfig.areaId config and their
@@ -447,6 +495,7 @@
      * @change_mode VehiclePropertyChangeMode.CONTINUOUS
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:KILOPASCAL
+     * @version 2
      */
     TIRE_PRESSURE = 0x0309 + 0x10000000 + 0x07000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:WHEEL,VehiclePropertyType:FLOAT
@@ -462,6 +511,7 @@
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:KILOPASCAL
+     * @version 2
      */
     CRITICALLY_LOW_TIRE_PRESSURE = 0x030A + 0x10000000 + 0x07000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:WHEEL,VehiclePropertyType:FLOAT
@@ -476,10 +526,29 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     ENGINE_IDLE_AUTO_STOP_ENABLED =
             0x0320 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
     /**
+     * Impact detected.
+     *
+     * Bit flag property to relay information on whether an impact has occurred on a particular side
+     * of the vehicle as described through the ImpactSensorLocation enum. As a bit flag property,
+     * this property can be set to multiple ORed together values of the enum when necessary.
+     *
+     * For the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined
+     * unless all bit flags of ImpactSensorLocation are supported.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ
+     * @data_enum ImpactSensorLocation
+     * @version 3
+     */
+    IMPACT_DETECTED =
+            0x0330 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
+    /**
      * Currently selected gear
      *
      * This is the gear selected by the user.
@@ -496,6 +565,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleGear
+     * @version 2
      */
     GEAR_SELECTION = 0x0400 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -515,6 +585,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleGear
+     * @version 2
      */
     CURRENT_GEAR = 0x0401 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -526,6 +597,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     PARKING_BRAKE_ON = 0x0402 + 0x10000000 + 0x01000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
@@ -543,6 +615,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     PARKING_BRAKE_AUTO_APPLY = 0x0403 + 0x10000000 + 0x01000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
@@ -560,6 +633,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     EV_BRAKE_REGENERATION_LEVEL =
             0x040C + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -578,6 +653,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     FUEL_LEVEL_LOW = 0x0405 + 0x10000000 + 0x01000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
@@ -590,6 +666,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     NIGHT_MODE = 0x0407 + 0x10000000 + 0x01000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
@@ -599,6 +676,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleTurnSignal
+     * @version 2
      */
     TURN_SIGNAL_STATE = 0x0408 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -608,6 +686,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleIgnitionState
+     * @version 2
      */
     IGNITION_STATE = 0x0409 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -620,6 +699,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     ABS_ACTIVE = 0x040A + 0x10000000 + 0x01000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
@@ -632,6 +712,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     TRACTION_CONTROL_ACTIVE = 0x040B + 0x10000000 + 0x01000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
@@ -648,11 +729,54 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @data_enum EvStoppingMode
+     * @version 2
      */
     EV_STOPPING_MODE =
             0x040D + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
     /**
+     * Enable or disable Electronic Stability Control (ESC).
+     *
+     * Set true to enable ESC and false to disable ESC. When ESC is enabled, a system in the vehicle
+     * should be controlling the tires during instances with high risk of skidding to actively
+     * prevent the same from happening.
+     *
+     * In general, ELECTRONIC_STABILITY_CONTROL_ENABLED should always return true or false. If the
+     * feature is not available due to some temporary state, such as the vehicle speed being too
+     * high, that information must be conveyed through the ErrorState values in the
+     * ELECTRONIC_STABILITY_CONTROL_STATE property.
+     *
+     * This property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to
+     * implement it as VehiclePropertyAccess.READ only.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 3
+     */
+    ELECTRONIC_STABILITY_CONTROL_ENABLED =
+            0x040E + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+    /**
+     * Electronic Stability Control (ESC) state.
+     *
+     * Returns the current state of ESC. This property must always return a valid state defined in
+     * ElectronicStabilityControlState or ErrorState. It must not surface errors through StatusCode
+     * and must use the supported error states instead.
+     *
+     * For the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined
+     * unless all states of both ElectronicStabilityControlState (including OTHER, which is not
+     * recommended) and ErrorState are supported.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ
+     * @data_enum ElectronicStabilityControlState
+     * @data_enum ErrorState
+     * @version 2
+     */
+    ELECTRONIC_STABILITY_CONTROL_STATE =
+            0x040F + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
+    /**
      * HVAC Properties
      *
      * Additional rules for mapping non-GLOBAL VehicleArea type HVAC properties
@@ -696,8 +820,9 @@
      *     and passenger side, an alternative mapping would be:
      *      - ROW_1_LEFT
      *      - ROW_1_RIGHT
-     *
-     *
+     */
+
+    /**
      * Fan speed setting
      *
      * The maxInt32Value and minInt32Value in VehicleAreaConfig must be defined.
@@ -713,6 +838,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     HVAC_FAN_SPEED = 0x0500 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -724,7 +851,9 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @data_enum VehicleHvacFanDirection
+     * @version 2
      */
     HVAC_FAN_DIRECTION = 0x0501 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -734,6 +863,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:CELSIUS
+     * @version 2
      */
     HVAC_TEMPERATURE_CURRENT = 0x0502 + 0x10000000 + 0x05000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:FLOAT
@@ -763,7 +893,9 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:CELSIUS
+     * @version 2
      */
     HVAC_TEMPERATURE_SET = 0x0503 + 0x10000000 + 0x05000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:FLOAT
@@ -775,6 +907,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     HVAC_DEFROSTER = 0x0504 + 0x10000000 + 0x03000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:WINDOW,VehiclePropertyType:BOOLEAN
@@ -786,7 +920,9 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @config_flags Supported areaIds
+     * @version 2
      */
     HVAC_AC_ON = 0x0505 + 0x10000000 + 0x05000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:BOOLEAN
@@ -803,6 +939,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     HVAC_MAX_AC_ON = 0x0506 + 0x10000000 + 0x05000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:BOOLEAN
@@ -825,6 +963,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     HVAC_MAX_DEFROST_ON = 0x0507 + 0x10000000 + 0x05000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:BOOLEAN
@@ -841,6 +981,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     HVAC_RECIRC_ON = 0x0508 + 0x10000000 + 0x05000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:BOOLEAN
@@ -879,6 +1021,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     HVAC_DUAL_ON = 0x0509 + 0x10000000 + 0x05000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:BOOLEAN
@@ -900,6 +1044,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     HVAC_AUTO_ON = 0x050A + 0x10000000 + 0x05000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:BOOLEAN
@@ -921,6 +1067,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     HVAC_SEAT_TEMPERATURE = 0x050B + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -943,6 +1091,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     HVAC_SIDE_MIRROR_HEAT = 0x050C + 0x10000000 + 0x04000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:MIRROR,VehiclePropertyType:INT32
@@ -965,6 +1115,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     HVAC_STEERING_WHEEL_HEAT = 0x050D + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -989,7 +1141,9 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @data_enum VehicleUnit
+     * @version 2
      */
     HVAC_TEMPERATURE_DISPLAY_UNITS = 0x050E + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -998,6 +1152,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     HVAC_ACTUAL_FAN_SPEED_RPM = 0x050F + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -1043,6 +1198,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     HVAC_POWER_ON = 0x0510 + 0x10000000 + 0x05000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:BOOLEAN
@@ -1062,6 +1219,7 @@
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleHvacFanDirection
+     * @version 2
      */
     HVAC_FAN_DIRECTION_AVAILABLE = 0x0511 + 0x10000000 + 0x05000000
             + 0x00410000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32_VEC
@@ -1077,6 +1235,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     HVAC_AUTO_RECIRC_ON = 0x0512 + 0x10000000 + 0x05000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:BOOLEAN
@@ -1101,6 +1261,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     HVAC_SEAT_VENTILATION = 0x0513 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -1112,6 +1274,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     HVAC_ELECTRIC_DEFROSTER_ON = 0x0514 + 0x10000000 + 0x03000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:WINDOW,VehiclePropertyType:BOOLEAN
@@ -1152,6 +1316,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @version 2
      */
     HVAC_TEMPERATURE_VALUE_SUGGESTION = 0x0515 + 0x10000000 + 0x01000000
             + 0x00610000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:FLOAT_VEC
@@ -1175,7 +1340,9 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @data_enum VehicleUnit
+     * @version 2
      */
     DISTANCE_DISPLAY_UNITS = 0x0600 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -1198,7 +1365,9 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @data_enum VehicleUnit
+     * @version 2
      */
     FUEL_VOLUME_DISPLAY_UNITS = 0x0601 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -1222,7 +1391,9 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @data_enum VehicleUnit
+     * @version 2
      */
     TIRE_PRESSURE_DISPLAY_UNITS = 0x0602 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -1246,7 +1417,9 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @data_enum VehicleUnit
+     * @version 2
      */
     EV_BATTERY_DISPLAY_UNITS = 0x0603 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -1262,6 +1435,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     FUEL_CONSUMPTION_UNITS_DISTANCE_OVER_VOLUME = 0x0604 + 0x10000000 + 0x01000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
@@ -1284,6 +1459,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     VEHICLE_SPEED_DISPLAY_UNITS = 0x0605 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -1328,6 +1505,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:MILLI_SECS
+     * @version 2
      */
     EXTERNAL_CAR_TIME = 0x0608 + 0x10000000 // VehiclePropertyGroup:SYSTEM
             + 0x01000000 // VehicleArea:GLOBAL
@@ -1357,6 +1535,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.WRITE
      * @unit VehicleUnit:MILLI_SECS
+     * @version 2
      */
     ANDROID_EPOCH_TIME = 0x0606 + 0x10000000 + 0x01000000
             + 0x00500000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT64
@@ -1371,6 +1550,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @version 2
      */
     STORAGE_ENCRYPTION_BINDING_SEED = 0x0607 + 0x10000000 + 0x01000000
             + 0x00700000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BYTES
@@ -1380,6 +1560,7 @@
      * @change_mode VehiclePropertyChangeMode.CONTINUOUS
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:CELSIUS
+     * @version 2
      */
     ENV_OUTSIDE_TEMPERATURE = 0x0703 + 0x10000000 + 0x01000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:FLOAT
@@ -1398,6 +1579,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     AP_POWER_STATE_REQ = 0x0A00 + 0x10000000 + 0x01000000
             + 0x00410000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
@@ -1412,6 +1594,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @version 2
      */
     AP_POWER_STATE_REPORT = 0x0A01 + 0x10000000 + 0x01000000
             + 0x00410000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
@@ -1426,6 +1609,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     AP_POWER_BOOTUP_REASON = 0x0A02 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -1448,6 +1632,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @version 2
      */
     DISPLAY_BRIGHTNESS = 0x0A03 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -1471,10 +1656,45 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @version 2
      */
     PER_DISPLAY_BRIGHTNESS = 0x0A04 + 0x10000000 + 0x01000000
             + 0x00410000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
     /**
+     * Valet mode enabled
+     *
+     * This property allows the user to enable/disable valet mode in their vehicle. Valet mode is
+     * a privacy and security setting that prevents an untrusted driver to access more private areas
+     * in the vehicle, such as the glove box or the trunk(s).
+     *
+     * This property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to
+     * implement it as VehiclePropertyAccess.READ only.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 3
+     */
+    VALET_MODE_ENABLED =
+            0x0A05 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+    /**
+     * Head up display (HUD) enabled
+     *
+     * This property allows the user to turn on/off the HUD for their seat.
+     *
+     * Each HUD in the vehicle should be assigned to the seat that is intended to use it. For
+     * example, if there is a single HUD in the vehicle that is used by the driver so that they no
+     * longer need to continuously look at the instrument cluster, then this property should be
+     * defined with a single area ID equal to the driver's seat area value.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 3
+     */
+    HEAD_UP_DISPLAY_ENABLED =
+            0x0A06 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.BOOLEAN,
+    /**
      * Property to feed H/W input events to android
      *
      * int32Values[0] : action defined by VehicleHwKeyInputAction
@@ -1488,6 +1708,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @config_flags
+     * @version 2
      */
     HW_KEY_INPUT = 0x0A10 + 0x10000000 + 0x01000000
             + 0x00410000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
@@ -1510,6 +1731,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @config_flags
+     * @version 2
      */
     HW_KEY_INPUT_V2 =
             0x0A11 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.MIXED,
@@ -1544,6 +1766,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @config_flags
+     * @version 2
      */
     HW_MOTION_INPUT =
             0x0A12 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.MIXED,
@@ -1567,6 +1790,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @data_enum RotaryInputType
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     HW_ROTARY_INPUT = 0x0A20 + 0x10000000 + 0x01000000
             + 0x00410000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
@@ -1590,6 +1814,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @data_enum CustomInputType
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     HW_CUSTOM_INPUT = 0X0A30 + 0x10000000 + 0x01000000
             + 0x00410000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
@@ -1633,6 +1858,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     DOOR_POS = 0x0B00 + 0x10000000 + 0x06000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:DOOR,VehiclePropertyType:INT32
@@ -1657,6 +1884,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     DOOR_MOVE = 0x0B01 + 0x10000000 + 0x06000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:DOOR,VehiclePropertyType:INT32
@@ -1670,6 +1899,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     DOOR_LOCK = 0x0B02 + 0x10000000 + 0x06000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:DOOR,VehiclePropertyType:BOOLEAN
@@ -1685,6 +1916,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     DOOR_CHILD_LOCK_ENABLED =
             0x0B03 + VehiclePropertyGroup.SYSTEM + VehicleArea.DOOR + VehiclePropertyType.BOOLEAN,
@@ -1710,6 +1943,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     MIRROR_Z_POS = 0x0B40 + 0x10000000 + 0x04000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:MIRROR,VehiclePropertyType:INT32
@@ -1735,6 +1970,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     MIRROR_Z_MOVE = 0x0B41 + 0x10000000 + 0x04000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:MIRROR,VehiclePropertyType:INT32
@@ -1760,6 +1997,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     MIRROR_Y_POS = 0x0B42 + 0x10000000 + 0x04000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:MIRROR,VehiclePropertyType:INT32
@@ -1784,6 +2023,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     MIRROR_Y_MOVE = 0x0B43 + 0x10000000 + 0x04000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:MIRROR,VehiclePropertyType:INT32
@@ -1797,6 +2038,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     MIRROR_LOCK = 0x0B44 + 0x10000000 + 0x01000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
@@ -1810,6 +2053,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     MIRROR_FOLD = 0x0B45 + 0x10000000 + 0x01000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
@@ -1826,6 +2071,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
 
     MIRROR_AUTO_FOLD_ENABLED =
@@ -1843,6 +2090,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
 
     MIRROR_AUTO_TILT_ENABLED =
@@ -1862,6 +2111,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.WRITE
+     * @version 2
      */
     SEAT_MEMORY_SELECT = 0x0B80 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -1875,6 +2125,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.WRITE
+     * @version 2
      */
     SEAT_MEMORY_SET = 0x0B81 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -1891,6 +2142,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_BELT_BUCKLED = 0x0B82 + 0x10000000 + 0x05000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:BOOLEAN
@@ -1915,6 +2168,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_BELT_HEIGHT_POS = 0x0B83 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -1942,6 +2197,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_BELT_HEIGHT_MOVE = 0x0B84 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -1966,6 +2223,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_FORE_AFT_POS = 0x0B85 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -1992,6 +2251,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_FORE_AFT_MOVE = 0x0B86 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2018,6 +2279,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_BACKREST_ANGLE_1_POS = 0x0B87 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2044,6 +2307,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_BACKREST_ANGLE_1_MOVE = 0x0B88 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2072,6 +2337,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_BACKREST_ANGLE_2_POS = 0x0B89 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2098,6 +2365,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_BACKREST_ANGLE_2_MOVE = 0x0B8A + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2120,6 +2389,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_HEIGHT_POS = 0x0B8B + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2144,6 +2415,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_HEIGHT_MOVE = 0x0B8C + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2171,6 +2444,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_DEPTH_POS = 0x0B8D + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2196,6 +2471,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_DEPTH_MOVE = 0x0B8E + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2222,6 +2499,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_TILT_POS = 0x0B8F + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2248,6 +2527,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_TILT_MOVE = 0x0B90 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2272,6 +2553,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_LUMBAR_FORE_AFT_POS = 0x0B91 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2299,6 +2582,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_LUMBAR_FORE_AFT_MOVE = 0x0B92 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2323,6 +2608,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_LUMBAR_SIDE_SUPPORT_POS = 0x0B93 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2350,6 +2637,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_LUMBAR_SIDE_SUPPORT_MOVE = 0x0B94 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2369,6 +2658,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_HEADREST_HEIGHT_POS = 0x0B95 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -2395,6 +2686,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_HEADREST_HEIGHT_POS_V2 =
             0x0BA4 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
@@ -2423,6 +2716,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_HEADREST_HEIGHT_MOVE = 0x0B96 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2445,6 +2740,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_HEADREST_ANGLE_POS = 0x0B97 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2472,6 +2769,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_HEADREST_ANGLE_MOVE = 0x0B98 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2494,6 +2793,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_HEADREST_FORE_AFT_POS = 0x0B99 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2521,6 +2822,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_HEADREST_FORE_AFT_MOVE = 0x0B9A + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2542,6 +2845,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightState
+     * @version 2
      */
     SEAT_FOOTWELL_LIGHTS_STATE =
             0x0B9B + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
@@ -2565,7 +2869,9 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightSwitch
+     * @version 2
      */
     SEAT_FOOTWELL_LIGHTS_SWITCH =
             0x0B9C + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
@@ -2581,6 +2887,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_EASY_ACCESS_ENABLED =
             0x0B9D + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.BOOLEAN,
@@ -2600,10 +2908,35 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 3
      */
     SEAT_AIRBAG_ENABLED =
             0x0B9E + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.BOOLEAN,
     /**
+     * Seat airbags deployed
+     *
+     * Bit flag property to relay information on which airbags have been deployed in the vehicle at
+     * each seat, vs which ones are currently still armed. If SEAT_AIRBAG_ENABLED is set to false at
+     * a particular areaId, this property should return status code UNAVAILABLE at that areaId.
+     *
+     * Enums apply to each seat, not the global vehicle. For example, VehicleAirbagsLocation#CURTAIN
+     * at the driver seat areaId represents whether the driver side curtain airbag has been
+     * deployed. Multiple bit flags can be set to indicate that multiple different airbags have been
+     * deployed for the seat.
+     *
+     * For each seat area ID, the VehicleAreaConfig#supportedEnumValues array must be defined unless
+     * all states of VehicleAirbagLocation are supported (including OTHER, which is not
+     * recommended).
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ
+     * @data_enum VehicleAirbagLocation
+     * @version 2
+     */
+    SEAT_AIRBAGS_DEPLOYED =
+            0x0BA5 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
+    /**
      * Represents property for seat’s hipside (bottom cushion’s side) support position.
      *
      * The maxInt32Value and minInt32Value in each VehicleAreaConfig must be defined. All integers
@@ -2624,6 +2957,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_CUSHION_SIDE_SUPPORT_POS =
             0x0B9F + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
@@ -2651,6 +2986,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_CUSHION_SIDE_SUPPORT_MOVE =
             0x0BA0 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
@@ -2673,6 +3010,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_LUMBAR_VERTICAL_POS =
             0x0BA1 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
@@ -2698,6 +3037,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_LUMBAR_VERTICAL_MOVE =
             0x0BA2 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
@@ -2723,10 +3064,31 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SEAT_WALK_IN_POS =
             0x0BA3 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
     /**
+     * Seat belt pretensioner deployed.
+     *
+     * Property to relay information on whether the seat belt pretensioner has been deployed for a
+     * particular seat due to a collision. This is different from the regular seat belt tightening
+     * system that continuously adds tension to the seat belts so that they fit snugly around the
+     * person sitting in the seat, nor is it the seat belt retractor system that locks the seat belt
+     * in place during sudden brakes or when the user jerks the seat belt.
+     *
+     * If this property is dependant on the state of other properties, and those properties are
+     * currently in the state that doesn't support this property, this should return
+     * StatusCode#NOT_AVAILABLE
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ
+     * @version 3
+     */
+    SEAT_BELT_PRETENSIONER_DEPLOYED =
+            0x0BA6 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.BOOLEAN,
+    /**
      * Seat Occupancy
      *
      * Indicates whether a particular seat is occupied or not, to the best of the car's ability
@@ -2735,6 +3097,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleSeatOccupancyState
+     * @version 2
      */
     SEAT_OCCUPANCY = 0x0BB0 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2770,6 +3133,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     WINDOW_POS = 0x0BC0 + 0x10000000 + 0x03000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:WINDOW,VehiclePropertyType:INT32
@@ -2811,6 +3176,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     WINDOW_MOVE = 0x0BC1 + 0x10000000 + 0x03000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:WINDOW,VehiclePropertyType:INT32
@@ -2824,6 +3191,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     WINDOW_LOCK = 0x0BC4 + 0x10000000 + 0x03000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:WINDOW,VehiclePropertyType:BOOLEAN
@@ -2844,6 +3213,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:MILLI_SECS
+     * @version 2
      */
     WINDSHIELD_WIPERS_PERIOD =
             0x0BC5 + VehiclePropertyGroup.SYSTEM + VehicleArea.WINDOW + VehiclePropertyType.INT32,
@@ -2865,6 +3235,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum WindshieldWipersState
+     * @version 2
      */
     WINDSHIELD_WIPERS_STATE =
             0x0BC6 + VehiclePropertyGroup.SYSTEM + VehicleArea.WINDOW + VehiclePropertyType.INT32,
@@ -2889,7 +3260,9 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @data_enum WindshieldWipersSwitch
+     * @version 2
      */
     WINDSHIELD_WIPERS_SWITCH =
             0x0BC7 + VehiclePropertyGroup.SYSTEM + VehicleArea.WINDOW + VehiclePropertyType.INT32,
@@ -2915,6 +3288,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     STEERING_WHEEL_DEPTH_POS =
             0x0BE0 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -2940,6 +3315,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     STEERING_WHEEL_DEPTH_MOVE =
             0x0BE1 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -2962,6 +3339,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     STEERING_WHEEL_HEIGHT_POS =
             0x0BE2 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -2987,6 +3366,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     STEERING_WHEEL_HEIGHT_MOVE =
             0x0BE3 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -3001,6 +3382,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     STEERING_WHEEL_THEFT_LOCK_ENABLED =
             0x0BE4 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -3014,6 +3397,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     STEERING_WHEEL_LOCKED =
             0x0BE5 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -3028,6 +3413,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     STEERING_WHEEL_EASY_ACCESS_ENABLED =
             0x0BE6 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -3054,6 +3441,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     GLOVE_BOX_DOOR_POS =
             0x0BF0 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
@@ -3072,6 +3461,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     GLOVE_BOX_LOCKED =
             0x0BF1 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.BOOLEAN,
@@ -3091,6 +3482,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @version 2
      */
     VEHICLE_MAP_SERVICE = 0x0C00 + 0x10000000 + 0x01000000
             + 0x00e00000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:MIXED
@@ -3110,9 +3502,187 @@
      *
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     LOCATION_CHARACTERIZATION =
             0x0C10 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
+
+    /**
+     * Static data for the position of each ultrasonic sensor installed on the vehicle.
+     *
+     * Each individual sensor is identified by its unique VehicleAreaConfig#areaId and returns the
+     * sensor's position formatted as [x, y, z] where:
+     *
+     *     int32Values[0] = x, the position of the sensor along the x-axis relative to the origin of
+     *                      the Android Automotive sensor coordinate frame in millimeters
+     *     int32Values[1] = y, the position of the sensor along the y-axis relative to the origin of
+     *                      the Android Automotive sensor coordinate frame in millimeters.
+     *     int32Values[2] = z, the position of the sensor along the z-axis relative to the origin of
+     *                      the Android Automotive sensor coordinate frame in millimeters.
+     *
+     * If the data is aggregated by another ECU, then OEMs have the option of reporting the same
+     * reading across all included sensors or reporting a virtual representation of all the included
+     * sensors as if they were one sensor.
+     *
+     * @change_mode VehiclePropertyChangeMode.STATIC
+     * @access VehiclePropertyAccess.READ
+     * @version 3
+     */
+    ULTRASONICS_SENSOR_POSITION = 0x0C20 + VehiclePropertyGroup.SYSTEM + VehicleArea.VENDOR
+            + VehiclePropertyType.INT32_VEC,
+
+    /**
+     * Static data for the orientation of each ultrasonic sensor installed on the vehicle.
+     *
+     * Each individual sensor is identified by its VehicleAreaConfig#areaId and returns the sensor's
+     * orientation formatted as [qw, qx, qy, qz] where:
+     *
+     *     int32Values[0] = qw, the quaternion coefficient w within the quaterinion (w + xi + yj +
+     *                      zk) describing the rotation of the sensor relative to the Android
+     *                      Automotive sensor coordinate frame.
+     *     int32Values[1] = qx, the quaternion coefficient x within the quaterinion (w + xi + yj +
+     *                      zk) describing the rotation of the sensor relative to the Android
+     *                      Automotive sensor coordinate frame.
+     *     int32Values[2] = qy, the quaternion coefficient y within the quaterinion (w + xi + yj +
+     *                      zk) describing the rotation of the sensor relative to the Android
+     *                      Automotive sensor coordinate frame.
+     *     int32Values[3] = qz, the quaternion coefficient z within the quaterinion (w + xi + yj +
+     *                      zk) describing the rotation of the sensor relative to the Android
+     *                      Automotive sensor coordinate frame.
+     *
+     * This assumes each sensor uses the same axes conventions as Android Automotive.
+     *
+     * If the data is aggregated by another ECU, then OEMs have the option of reporting the same
+     * reading across all included sensors or reporting a virtual representation of all the included
+     * sensors as if they were one sensor.
+     *
+     * @change_mode VehiclePropertyChangeMode.STATIC
+     * @access VehiclePropertyAccess.READ
+     * @version 3
+     */
+    ULTRASONICS_SENSOR_ORIENTATION = 0x0C21 + VehiclePropertyGroup.SYSTEM + VehicleArea.VENDOR
+            + VehiclePropertyType.INT32_VEC,
+
+    /**
+     * Static data for the field of view of each ultrasonic sensor in degrees.
+     *
+     * Each individual sensor is identified by its VehicleAreaConfig#areaId and returns the sensor's
+     * field of view formatted as [horizontal, vertical] where:
+     *
+     *     int32Values[0] = horizontal, the horizontal field of view for the specified ultrasonic
+     *                      sensor in degrees.
+     *     int32Values[1] = vertical, the vertical field of view for the associated specified
+     *                      ultrasonic sensor in degrees.
+     *
+     * This assumes each sensor uses the same axes conventions as Android Automotive.
+     *
+     * If the data is aggregated by another ECU, then OEMs have the option of reporting the same
+     * reading across all included sensors or reporting a virtual representation of all the included
+     * sensors as if they were one sensor.
+     *
+     * @change_mode VehiclePropertyChangeMode.STATIC
+     * @access VehiclePropertyAccess.READ
+     * @version 3
+     */
+    ULTRASONICS_SENSOR_FIELD_OF_VIEW = 0x0C22 + VehiclePropertyGroup.SYSTEM + VehicleArea.VENDOR
+            + VehiclePropertyType.INT32_VEC,
+
+    /**
+     * Static data for the detection range of each ultrasonic sensor in millimeters.
+     *
+     * Each individual sensor is identified by its VehicleAreaConfig#areaId and returns the sensor's
+     * detection range formatted as [minimum, maximum] where:
+     *
+     *     int32Values[0] = minimum, the minimum range detectable by the ultrasonic sensor in
+     *                      millimeters.
+     *     int32Values[1] = maximum, the maximum range detectable by the ultrasonic sensor in
+     *                      millimeters.
+     *
+     * If the data is aggregated by another ECU, then OEMs have the option of reporting the same
+     * reading across all included sensors or reporting a virtual representation of all the included
+     * sensors as if they were one sensor.
+     *
+     * @change_mode VehiclePropertyChangeMode.STATIC
+     * @access VehiclePropertyAccess.READ
+     * @version 3
+     */
+    ULTRASONICS_SENSOR_DETECTION_RANGE = 0x0C23 + VehiclePropertyGroup.SYSTEM + VehicleArea.VENDOR
+            + VehiclePropertyType.INT32_VEC,
+
+    /**
+     * Static data for the supported ranges of each ultrasonic sensor in millimeters.
+     *
+     * For ultrasonic sensors that only support readings within a specific range. For example, if
+     * an ultrasonic sensor detects an object at 700mm, but can only report that an object has been
+     * detected between 500mm and 1000mm.
+     *
+     * Each individual sensor is identified by its VehicleAreaConfig#areaId and returns the sensor's
+     * supported ranges formatted as [range_min_1, range_max_1, range_min_2, range_max_2, ...]
+     * where:
+     *
+     *     int32Values[0] = range_min_1, the minimum of one supported range by the specified sensor
+     *                      in millimeters, inclusive.
+     *     int32Values[1] = range_max_1, the maximum of one supported range by the specified sensor
+     *                      in millimeters, inclusive.
+     *     int32Values[2] = range_min_2, the minimum of another supported range by the specified
+     *                      sensor in millimeters, inclusive.
+     *     int32Values[3] = range_max_2, the maximum of another supported range by the specified
+                            sensor in millimeters, inclusive.
+     *
+     * Example:
+     *     - Ultrasonic sensor supports the following ranges:
+     *           - 150mm to 499mm
+     *           - 500mm to 999mm
+     *           - 1000mm to 1500mm
+     *     - The associated supported ranges should be formatted as:
+     *           - int32Values[0] = 150
+     *           - int32Values[1] = 499
+     *           - int32Values[2] = 500
+     *           - int32Values[3] = 999
+     *           - int32Values[4] = 1000
+     *           - int32Values[5] = 1500
+     *
+     * If this property is not defined, all the values within the ULTRASONICS_SENSOR_DETECTION_RANGE
+     * for the specified sensor are assumed to be supported.
+     *
+     * If the data is aggregated by another ECU, then OEMs have the option of reporting the same
+     * reading across all included sensors or reporting a virtual representation of all the included
+     * sensors as if they were one sensor.
+     *
+     * @change_mode VehiclePropertyChangeMode.STATIC
+     * @access VehiclePropertyAccess.READ
+     * @version 3
+     */
+    ULTRASONICS_SENSOR_SUPPORTED_RANGES = 0x0C24 + VehiclePropertyGroup.SYSTEM + VehicleArea.VENDOR
+            + VehiclePropertyType.INT32_VEC,
+
+    /**
+     * The distance reading of the nearest detected object per sensor in millimeters.
+     *
+     * Each individual sensor is identified by its VehicleAreaConfig#areaId and returns the sensor's
+     * measured distance formatted as [distance, distance_error] where:
+     *
+     *     int32Values[0] = distance, the measured distance of the nearest object in millimeters.
+     *                      If only a range is supported, this value must be set to the minimum
+     *                      supported distance in the detected range as specified in
+     *                      ULTRASONICS_SENSOR_SUPPORTED_RANGES.
+     *     int32Values[1] = distance_error, the error of the measured distance value in
+     *                      millimeters.
+     *
+     * If no object is detected, an empty vector must be returned. If distance_error is not
+     * available then an array of only the measured distance must be returned.
+     *
+     * If the data is aggregated by another ECU, then OEMs have the option of reporting the same
+     * reading across all included sensors or reporting a virtual representation of all the included
+     * sensors as if they were one sensor.
+     *
+     * @change_mode VehiclePropertyChangeMode.CONTINUOUS
+     * @access VehiclePropertyAccess.READ
+     * @version 3
+     */
+    ULTRASONICS_SENSOR_MEASURED_DISTANCE = 0x0C25 + VehiclePropertyGroup.SYSTEM + VehicleArea.VENDOR
+            + VehiclePropertyType.INT32_VEC,
+
     /**
      * OBD2 Live Sensor Data
      *
@@ -3153,6 +3723,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     OBD2_LIVE_FRAME = 0x0D00 + 0x10000000 + 0x01000000
             + 0x00e00000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:MIXED
@@ -3179,6 +3750,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     OBD2_FREEZE_FRAME = 0x0D01 + 0x10000000 + 0x01000000
             + 0x00e00000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:MIXED
@@ -3196,6 +3768,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     OBD2_FREEZE_FRAME_INFO = 0x0D02 + 0x10000000 + 0x01000000
             + 0x00e00000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:MIXED
@@ -3218,6 +3791,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.WRITE
+     * @version 2
      */
     OBD2_FREEZE_FRAME_CLEAR = 0x0D03 + 0x10000000 + 0x01000000
             + 0x00e00000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:MIXED
@@ -3229,6 +3803,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightState
+     * @version 2
      */
     HEADLIGHTS_STATE = 0x0E00 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -3240,6 +3815,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightState
+     * @version 2
      */
     HIGH_BEAM_LIGHTS_STATE = 0x0E01 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -3267,6 +3843,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightState
+     * @version 2
      */
     FOG_LIGHTS_STATE = 0x0E02 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -3278,6 +3855,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightState
+     * @version 2
      */
     HAZARD_LIGHTS_STATE = 0x0E03 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -3291,7 +3869,9 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightSwitch
+     * @version 2
      */
     HEADLIGHTS_SWITCH = 0x0E10 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -3305,7 +3885,9 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightSwitch
+     * @version 2
      */
     HIGH_BEAM_LIGHTS_SWITCH = 0x0E11 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -3335,7 +3917,9 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightSwitch
+     * @version 2
      */
     FOG_LIGHTS_SWITCH = 0x0E12 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -3349,7 +3933,9 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightSwitch
+     * @version 2
      */
     HAZARD_LIGHTS_SWITCH = 0x0E13 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -3361,6 +3947,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightState
+     * @version 2
      */
     CABIN_LIGHTS_STATE = 0x0F01 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -3377,7 +3964,9 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightSwitch
+     * @version 2
      */
     CABIN_LIGHTS_SWITCH = 0x0F02 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -3389,6 +3978,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightState
+     * @version 2
      */
     READING_LIGHTS_STATE = 0x0F03 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -3405,7 +3995,9 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightSwitch
+     * @version 2
      */
     READING_LIGHTS_SWITCH = 0x0F04 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -3427,6 +4019,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightState
+     * @version 2
      */
     STEERING_WHEEL_LIGHTS_STATE =
             0x0F0C + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -3450,7 +4043,9 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightSwitch
+     * @version 2
      */
     STEERING_WHEEL_LIGHTS_SWITCH =
             0x0F0D + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -3479,6 +4074,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SUPPORT_CUSTOMIZE_VENDOR_PERMISSION = 0x0F05 + 0x10000000 + 0x01000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
@@ -3495,6 +4091,7 @@
      * ex) "com.android.car.user.CarUserNoticeService,storage_monitoring"
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     DISABLED_OPTIONAL_FEATURES = 0x0F06 + 0x10000000 + 0x01000000
             + 0x00100000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:STRING
@@ -3545,6 +4142,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @version 2
      */
     INITIAL_USER_INFO = 0x0F07 + 0x10000000 + 0x01000000
             + 0x00e00000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:MIXED
@@ -3711,6 +4309,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @version 2
      */
     SWITCH_USER = 0x0F08 + 0x10000000 + 0x01000000
             + 0x00e00000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:MIXED
@@ -3757,6 +4356,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @version 2
      */
     CREATE_USER = 0x0F09 + 0x10000000 + 0x01000000
             + 0x00e00000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:MIXED
@@ -3788,6 +4388,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.WRITE
+     * @version 2
      */
     REMOVE_USER = 0x0F0A + 0x10000000 + 0x01000000
             + 0x00e00000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:MIXED
@@ -3863,6 +4464,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @version 2
      */
     USER_IDENTIFICATION_ASSOCIATION = 0x0F0B + 0x10000000 + 0x01000000
             + 0x00e00000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:MIXED
@@ -3882,6 +4484,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     EVS_SERVICE_REQUEST = 0x0F10 + 0x10000000 + 0x01000000
             + 0x00410000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
@@ -3899,6 +4502,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     POWER_POLICY_REQ = 0x0F21 + 0x10000000 + 0x01000000
             + 0x00100000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:STRING
@@ -3918,6 +4522,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     POWER_POLICY_GROUP_REQ = 0x0F22 + 0x10000000 + 0x01000000
             + 0x00100000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:STRING
@@ -3930,6 +4535,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @version 2
      */
     CURRENT_POWER_POLICY = 0x0F23 + 0x10000000 + 0x01000000
             + 0x00100000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:STRING
@@ -3941,6 +4547,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.WRITE
+     * @version 2
      */
     WATCHDOG_ALIVE = 0xF31 + 0x10000000 + 0x01000000
             + 0x00500000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT64
@@ -3952,6 +4559,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.WRITE
+     * @version 2
      */
     WATCHDOG_TERMINATED_PROCESS = 0x0F32 + 0x10000000 + 0x01000000
             + 0x00e00000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:MIXED
@@ -3967,6 +4575,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     VHAL_HEARTBEAT = 0x0F33 + 0x10000000 + 0x01000000
             + 0x00500000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT64
@@ -3980,6 +4589,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     CLUSTER_SWITCH_UI = 0x0F34 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -4004,6 +4614,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     CLUSTER_DISPLAY_STATE = 0x0F35 + 0x10000000 + 0x01000000
             + 0x00410000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
@@ -4039,6 +4650,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.WRITE
+     * @version 2
      */
     CLUSTER_REPORT_STATE = 0x0F36 + 0x10000000 + 0x01000000
             + 0x00e00000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:MIXED
@@ -4053,6 +4665,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.WRITE
+     * @version 2
      */
     CLUSTER_REQUEST_DISPLAY = 0x0F37 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -4063,6 +4676,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.WRITE
+     * @version 2
      */
     CLUSTER_NAVIGATION_STATE = 0x0F38 + 0x10000000 + 0x01000000
             + 0x00700000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BYTES
@@ -4076,6 +4690,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum ElectronicTollCollectionCardType
+     * @version 2
      */
     ELECTRONIC_TOLL_COLLECTION_CARD_TYPE = 0x0F39 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -4090,6 +4705,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum ElectronicTollCollectionCardStatus
+     * @version 2
      */
     ELECTRONIC_TOLL_COLLECTION_CARD_STATUS = 0x0F3A + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -4103,6 +4719,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightState
+     * @version 2
      */
     FRONT_FOG_LIGHTS_STATE = 0x0F3B + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -4119,7 +4736,9 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightSwitch
+     * @version 2
      */
     FRONT_FOG_LIGHTS_SWITCH = 0x0F3C + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -4134,6 +4753,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightState
+     * @version 2
      */
     REAR_FOG_LIGHTS_STATE = 0x0F3D + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -4150,7 +4770,9 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightSwitch
+     * @version 2
      */
     REAR_FOG_LIGHTS_SWITCH = 0x0F3E + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -4166,7 +4788,9 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:AMPERE
+     * @version 2
      */
     EV_CHARGE_CURRENT_DRAW_LIMIT = 0x0F3F + 0x10000000 + 0x01000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:FLOAT
@@ -4187,6 +4811,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     EV_CHARGE_PERCENT_LIMIT = 0x0F40 + 0x10000000 + 0x01000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:FLOAT
@@ -4199,6 +4825,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum EvChargeState
+     * @version 2
      */
     EV_CHARGE_STATE = 0x0F41 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -4214,6 +4841,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     EV_CHARGE_SWITCH = 0x0F42 + 0x10000000 + 0x01000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
@@ -4226,6 +4855,7 @@
      * @change_mode VehiclePropertyChangeMode.CONTINUOUS
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:SECS
+     * @version 2
      */
     EV_CHARGE_TIME_REMAINING = 0x0F43 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -4239,6 +4869,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum EvRegenerativeBrakingState
+     * @version 2
      */
     EV_REGENERATIVE_BRAKING_STATE = 0x0F44 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -4251,6 +4882,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @data_enum TrailerState
+     * @version 2
      */
     TRAILER_PRESENT = 0x0F45 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -4274,6 +4906,7 @@
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:KILOGRAM
+     * @version 2
      */
 
     VEHICLE_CURB_WEIGHT = 0x0F46 + 0x10000000 + 0x01000000
@@ -4288,6 +4921,7 @@
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
      * @data_enum GsrComplianceRequirementType
+     * @version 2
      */
     GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT = 0x0F47 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -4312,6 +4946,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     SUPPORTED_PROPERTY_IDS = 0x0F48 + 0x10000000 + 0x01000000
             + 0x00410000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
@@ -4319,12 +4954,22 @@
     /**
      * Request the head unit to be shutdown.
      *
+     * <p>This is required for executing a task when the head unit is powered off (remote task
+     * feature). After the head unit is powered-on to execute the task, the head unit should
+     * be shutdown. The head unit will send this message once the task is finished.
+     *
+     * <p>This is not for the case when a user wants to shutdown the head unit.
+     *
      * <p>This usually involves telling a separate system outside the head unit (e.g. a power
      * controller) to prepare shutting down the head unit.
      *
-     * <p>This does not mean the head unit will shutdown immediately.
+     * <p>Note that the external system must validate whether this request is valid by checking
+     * whether the vehicle is currently in use. If a user enters the vehicle after a
+     * SHUTDOWN_REQUEST is sent, then the system must ignore this request. It
+     * is recommended to store a VehicleInUse property in the power controller and exposes it
+     * through VEHICLE_IN_USE property. A shutdown request must be ignored if VehicleInUse is true.
      *
-     * <p>This means that another system will start sending a shutdown signal to the head unit,
+     * <p>If allowed, the external system will start sending a shutdown signal to the head unit,
      * which will cause VHAL to send SHUTDOWN_PREPARE message to Android. Android will then start
      * the shut down process by handling the message.
      *
@@ -4349,6 +4994,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.WRITE
      * @data_enum VehicleApPowerStateShutdownParam
+     * @version 2
      */
     SHUTDOWN_REQUEST =
             0x0F49 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -4375,12 +5021,52 @@
      * powers on the vehicle. VEHICLE_IN_USE is set to true. After a driving session, user powers
      * off the vehicle, VEHICLE_IN_USE is set to false.
      *
+     * <p>This property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to
+     * implement it as VehiclePropertyAccess.READ only.
+     *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     VEHICLE_IN_USE =
             0x0F4A + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
 
+    /**
+     * Sends the heartbeat signal to ClusterOS.
+     *
+     * int64[0]: epochTimeNs
+     * int64[1]: the visibility of ClusterUI, 0 - invisible, 1 - visible
+     * bytes: the app specific metadata, this can be empty when ClusterHomeService use the heartbeat
+     *     to deliver the change of the visibility.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.WRITE
+     * @version 3
+     */
+    CLUSTER_HEARTBEAT =
+            0x0F4B + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.MIXED,
+
+    /**
+     * Current state of vehicle autonomy.
+     *
+     * Defines the level of autonomy currently engaged in the vehicle from the J3016_202104 revision
+     * of the SAE standard levels 0-5, with 0 representing no autonomy and 5 representing full
+     * driving automation. These levels should be used in accordance with the standards defined in
+     * https://www.sae.org/standards/content/j3016_202104/ and
+     * https://www.sae.org/blog/sae-j3016-update
+     *
+     * For the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined
+     * unless all states of VehicleAutonomousState are supported.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ
+     * @data_enum VehicleAutonomousState
+     * @version 3
+     */
+    VEHICLE_DRIVING_AUTOMATION_CURRENT_LEVEL =
+            0x0F4C + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
+
     /***********************************************************************************************
      * Start of ADAS Properties
      *
@@ -4391,7 +5077,9 @@
      * Enable or disable Automatic Emergency Braking (AEB).
      *
      * Set true to enable AEB and false to disable AEB. When AEB is enabled, the ADAS system in the
-     * vehicle should be turned on and monitoring to avoid potential collisions.
+     * vehicle should be turned on and monitoring to avoid potential collisions. This property
+     * should apply for higher speed applications only. For enabling low speed automatic emergency
+     * braking, LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_ENABLED should be used.
      *
      * In general, AUTOMATIC_EMERGENCY_BRAKING_ENABLED should always return true or false. If the
      * feature is not available due to some temporary state, such as the vehicle speed being too
@@ -4403,6 +5091,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     AUTOMATIC_EMERGENCY_BRAKING_ENABLED =
             0x1000 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -4412,7 +5102,9 @@
      *
      * Returns the current state of AEB. This property must always return a valid state defined in
      * AutomaticEmergencyBrakingState or ErrorState. It must not surface errors through StatusCode
-     * and must use the supported error states instead.
+     * and must use the supported error states instead. This property should apply for higher speed
+     * applications only. For representing the state of the low speed automatic emergency braking
+     * system, LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE should be used.
      *
      * If AEB includes forward collision warnings before activating the brakes, those warnings must
      * be surfaced through the Forward Collision Warning (FCW) properties.
@@ -4425,6 +5117,7 @@
      * @access VehiclePropertyAccess.READ
      * @data_enum AutomaticEmergencyBrakingState
      * @data_enum ErrorState
+     * @version 2
      */
     AUTOMATIC_EMERGENCY_BRAKING_STATE =
             0x1001 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -4445,6 +5138,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     FORWARD_COLLISION_WARNING_ENABLED =
             0x1002 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -4464,6 +5159,7 @@
      * @access VehiclePropertyAccess.READ
      * @data_enum ForwardCollisionWarningState
      * @data_enum ErrorState
+     * @version 2
      */
     FORWARD_COLLISION_WARNING_STATE =
             0x1003 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -4484,6 +5180,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     BLIND_SPOT_WARNING_ENABLED =
             0x1004 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -4503,6 +5201,7 @@
      * @access VehiclePropertyAccess.READ
      * @data_enum BlindSpotWarningState
      * @data_enum ErrorState
+     * @version 2
      */
     BLIND_SPOT_WARNING_STATE =
             0x1005 + VehiclePropertyGroup.SYSTEM + VehicleArea.MIRROR + VehiclePropertyType.INT32,
@@ -4524,6 +5223,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     LANE_DEPARTURE_WARNING_ENABLED =
             0x1006 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -4543,6 +5244,7 @@
      * @access VehiclePropertyAccess.READ
      * @data_enum LaneDepartureWarningState
      * @data_enum ErrorState
+     * @version 2
      */
     LANE_DEPARTURE_WARNING_STATE =
             0x1007 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -4568,6 +5270,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     LANE_KEEP_ASSIST_ENABLED =
             0x1008 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -4590,6 +5294,7 @@
      * @access VehiclePropertyAccess.READ
      * @data_enum LaneKeepAssistState
      * @data_enum ErrorState
+     * @version 2
      */
     LANE_KEEP_ASSIST_STATE =
             0x1009 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -4616,6 +5321,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     LANE_CENTERING_ASSIST_ENABLED =
             0x100A + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -4625,11 +5332,11 @@
      *
      * Commands to activate and suspend LCA.
      *
-     * When the command ACTIVATE from LaneCenteringAssistCommmand is sent,
+     * When the command ACTIVATE from LaneCenteringAssistCommand is sent,
      * LANE_CENTERING_ASSIST_STATE must be set to LaneCenteringAssistState#ACTIVATION_REQUESTED.
      * When the ACTIVATE command succeeds, LANE_CENTERING_ASSIST_STATE must be set to
      * LaneCenteringAssistState#ACTIVATED. When the command DEACTIVATE from
-     * LaneCenteringAssistCommmand succeeds, LANE_CENTERING_ASSIST_STATE must be set to
+     * LaneCenteringAssistCommand succeeds, LANE_CENTERING_ASSIST_STATE must be set to
      * LaneCenteringAssistState#ENABLED.
      *
      * For the global area ID (0), the VehicleAreaConfig#supportedEnumValues must be defined unless
@@ -4645,7 +5352,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.WRITE
-     * @data_enum LaneCenteringAssistCommmand
+     * @data_enum LaneCenteringAssistCommand
+     * @version 2
      */
     LANE_CENTERING_ASSIST_COMMAND =
             0x100B + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -4668,6 +5376,7 @@
      * @access VehiclePropertyAccess.READ
      * @data_enum LaneCenteringAssistState
      * @data_enum ErrorState
+     * @version 2
      */
     LANE_CENTERING_ASSIST_STATE =
             0x100C + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -4690,6 +5399,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     EMERGENCY_LANE_KEEP_ASSIST_ENABLED =
             0x100D + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -4710,6 +5421,7 @@
      * @access VehiclePropertyAccess.READ
      * @data_enum EmergencyLaneKeepAssistState
      * @data_enum ErrorState
+     * @version 2
      */
     EMERGENCY_LANE_KEEP_ASSIST_STATE =
             0x100E + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -4733,6 +5445,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     CRUISE_CONTROL_ENABLED =
             0x100F + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -4758,8 +5472,10 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @data_enum CruiseControlType
      * @data_enum ErrorState
+     * @version 2
      */
     CRUISE_CONTROL_TYPE =
             0x1010 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -4780,6 +5496,7 @@
      * @access VehiclePropertyAccess.READ
      * @data_enum CruiseControlState
      * @data_enum ErrorState
+     * @version 2
      */
     CRUISE_CONTROL_STATE =
             0x1011 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -4803,6 +5520,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.WRITE
      * @data_enum CruiseControlCommand
+     * @version 2
      */
     CRUISE_CONTROL_COMMAND =
             0x1012 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -4826,6 +5544,7 @@
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:METER_PER_SEC
+     * @version 2
      */
     CRUISE_CONTROL_TARGET_SPEED =
             0x1013 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.FLOAT,
@@ -4855,7 +5574,9 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:MILLI_SECS
+     * @version 2
      */
     ADAPTIVE_CRUISE_CONTROL_TARGET_TIME_GAP =
             0x1014 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -4886,6 +5607,7 @@
      * @change_mode VehiclePropertyChangeMode.CONTINUOUS
      * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:MILLIMETER
+     * @version 2
      */
     ADAPTIVE_CRUISE_CONTROL_LEAD_VEHICLE_MEASURED_DISTANCE =
             0x1015 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -4906,6 +5628,8 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
      */
     HANDS_ON_DETECTION_ENABLED =
             0x1016 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -4930,6 +5654,7 @@
      * @access VehiclePropertyAccess.READ
      * @data_enum HandsOnDetectionDriverState
      * @data_enum ErrorState
+     * @version 2
      */
     HANDS_ON_DETECTION_DRIVER_STATE =
             0x1017 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -4952,10 +5677,348 @@
      * @access VehiclePropertyAccess.READ
      * @data_enum HandsOnDetectionWarning
      * @data_enum ErrorState
+     * @version 2
      */
     HANDS_ON_DETECTION_WARNING =
             0x1018 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
 
+    /**
+     * Enable or disable driver drowsiness and attention monitoring.
+     *
+     * Set true to enable driver drowsiness and attention monitoring and false to disable driver
+     * drowsiness and attention monitoring. When driver drowsiness and attention monitoring is
+     * enabled, a system inside the vehicle should be monitoring the drowsiness and attention level
+     * of the driver and warn the driver if needed.
+     *
+     * In general, DRIVER_DROWSINESS_ATTENTION_SYSTEM_ENABLED should always return true or false.
+     * If the feature is not available due to some temporary state, that information must be
+     * conveyed through the ErrorState values in the DRIVER_DROWSINESS_ATTENTION_STATE property.
+     *
+     * This property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to
+     * implement it as VehiclePropertyAccess.READ only.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 3
+     */
+    DRIVER_DROWSINESS_ATTENTION_SYSTEM_ENABLED =
+            0x1019 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+
+    /**
+     * Driver drowsiness and attention level state.
+     *
+     * Returns the current detected state of driver drowiness and attention level based on the
+     * Karolinska Sleepiness scale. If alternative measurement methods are used, the value should be
+     * translated to the Karolinska Sleepiness Scale equivalent.
+     *
+     * Generally, this property should return a valid state defined in the
+     * DriverDrowsinessAttentionState or ErrorState. For example, if the feature is not available
+     * due to some temporary state, that information should be conveyed through ErrorState.
+     *
+     * If the vehicle is sending a warning to the user because the driver is too drowsy, the warning
+     * should be surfaced through {@link #DRIVER_DROWSINESS_ATTENTION_WARNING}.
+     *
+     * For the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined
+     * unless all states of both DriverDrowsinessAttentionState (including OTHER, which is not
+     * recommended) and ErrorState are supported.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ
+     * @data_enum DriverDrowsinessAttentionState
+     * @data_enum ErrorState
+     * @version 3
+     */
+    DRIVER_DROWSINESS_ATTENTION_STATE =
+            0x101A + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
+
+    /**
+     * Enable or disable driver drowsiness and attention warnings.
+     *
+     * Set true to enable driver drowsiness and attention warnings and false to disable driver
+     * drowsiness and attention warnings.
+     *
+     * When driver drowsiness and attention warnings are enabled, the driver drowsiness and
+     * attention monitoring system inside the vehicle should warn the driver when it detects the
+     * driver is drowsy or not attentive.
+     *
+     * In general, DRIVER_DROWSINESS_ATTENTION_WARNING_ENABLED should always return true or false.
+     * If the feature is not available due to some temporary state, that information must be
+     * conveyed through the ErrorState values in the DRIVER_DROWSINESS_ATTENTION_WARNING property.
+     *
+     * This property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to
+     * implement it as VehiclePropertyAccess.READ only.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 3
+     */
+    DRIVER_DROWSINESS_ATTENTION_WARNING_ENABLED =
+            0x101B + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+
+    /**
+     * Driver drowsiness and attention warning.
+     *
+     * Returns whether a warning is being sent to the driver for being drowsy or not attentive.
+     *
+     * Generally, this property should return a valid state defined in
+     * DriverDrowsinessAttentionWarning or ErrorState. For example, if the feature is not available
+     * due to some temporary state, that information should be conveyed through an ErrorState.
+     *
+     * For the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined
+     * unless all states of both DriverDrowsinessAttentionWarning (including OTHER, which is not
+     * recommended) and ErrorState are supported.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ
+     * @data_enum DriverDrowsinessAttentionWarning
+     * @data_enum ErrorState
+     * @version 3
+     */
+    DRIVER_DROWSINESS_ATTENTION_WARNING =
+            0x101C + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
+
+    /**
+     * Enable or disable driver distraction monitoring.
+     *
+     * Set true to enable driver distraction monitoring and false to disable driver
+     * distraction monitoring. When driver distraction monitoring is enabled, a system
+     * inside the vehicle should be monitoring the distraction level of the driver and
+     * warn the driver if needed.
+     *
+     * In general, DRIVER_DISTRACTION_SYSTEM_ENABLED should always return true or false. If the
+     * feature is not available due to some temporary state, that information must be conveyed
+     * through the ErrorState values in the DRIVER_DISTRACTION_STATE property.
+     *
+     * This property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to
+     * implement it as VehiclePropertyAccess.READ only.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 3
+     */
+    DRIVER_DISTRACTION_SYSTEM_ENABLED =
+            0x101D + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+
+    /**
+     * Driver distraction state.
+     *
+     * Returns the current detected driver distraction state.
+     *
+     * Generally, this property should return a valid state defined in the DriverDistractionState or
+     * ErrorState. For example, if the feature is not available due to some temporary state, that
+     * information should be conveyed through ErrorState.
+     *
+     * If the vehicle is sending a warning to the user because the driver is too distracted, the
+     * warning should be surfaced through {@link #DRIVER_DISTRACTION_WARNING}.
+     *
+     * For the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined
+     * unless all states of both DriverDistractionState (including OTHER, which is not
+     * recommended) and ErrorState are supported.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ
+     * @data_enum DriverDistractionState
+     * @data_enum ErrorState
+     * @version 3
+     */
+    DRIVER_DISTRACTION_STATE =
+            0x101E + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
+
+    /**
+     * Enable or disable driver distraction warnings.
+     *
+     * Set true to enable driver distraction warnings and false to disable driver distraction
+     * warnings.
+     *
+     * When driver distraction warnings are enabled, the driver distraction monitoring system inside
+     * the vehicle should warn the driver when it detects the driver is distracted.
+     *
+     * In general, DRIVER_DISTRACTION_WARNING_ENABLED should always return true or false. If the
+     * feature is not available due to some temporary state, that information must be conveyed
+     * through the ErrorState values in the DRIVER_DISTRACTION_WARNING property.
+     *
+     * This property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to
+     * implement it as VehiclePropertyAccess.READ only.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 2
+     */
+    DRIVER_DISTRACTION_WARNING_ENABLED =
+            0x101F + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+
+    /**
+     * Driver distraction warning.
+     *
+     * Returns whether a warning is being sent to the driver for being distracted.
+     *
+     * Generally, this property should return a valid state defined in DriverDistractionWarning or
+     * ErrorState. For example, if the feature is not available due to some temporary state, that
+     * information should be conveyed through an ErrorState.
+     *
+     * For the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined
+     * unless all states of both DriverDistractionWarning (including OTHER, which is not
+     * recommended) and ErrorState are supported.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ
+     * @data_enum DriverDistractionWarning
+     * @data_enum ErrorState
+     * @version 3
+     */
+    DRIVER_DISTRACTION_WARNING =
+            0x1020 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
+
+    /**
+     * Enable or disable Low Speed Collision Warning.
+     *
+     * Set true to enable low speed collision warning and false to disable low speed collision
+     * warning. When low speed collision warning is enabled, the ADAS system in the vehicle should
+     * warn the driver of potential collisions at low speeds. This property is different from the
+     * pre-existing FORWARD_COLLISION_WARNING_ENABLED, which should apply to higher speed
+     * applications only. If the vehicle doesn't have a separate collision detection system for low
+     * speed environments, this property should not be implemented.
+     *
+     * In general, LOW_SPEED_COLLISION_WARNING_ENABLED should always return true or false. If the
+     * feature is not available due to some temporary state, such as the vehicle speed being too
+     * high, that information must be conveyed through the ErrorState values in the
+     * LOW_SPEED_COLLISION_WARNING_STATE property.
+     *
+     * This property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to
+     * implement it as VehiclePropertyAccess.READ only.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 3
+     */
+    LOW_SPEED_COLLISION_WARNING_ENABLED =
+            0x1021 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+
+    /**
+     * Low Speed Collision Warning state.
+     *
+     * Returns the current state of Low Speed Collision Warning. This property must always return a
+     * valid state defined in LowSpeedCollisionWarningState or ErrorState. It must not surface
+     * errors through StatusCode and must use the supported error states instead. This property is
+     * different from the pre-existing FORWARD_COLLISION_WARNING_STATE, which should apply to higher
+     * speed applications only. If the vehicle doesn't have a separate collision detection system
+     * for low speed environments, this property should not be implemented.
+     *
+     * For the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined
+     * unless all states of both LowSpeedCollisionWarningState (including OTHER, which is not
+     * recommended) and ErrorState are supported.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ
+     * @data_enum LowSpeedCollisionWarningState
+     * @data_enum ErrorState
+     * @version 3
+     */
+    LOW_SPEED_COLLISION_WARNING_STATE =
+            0x1022 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
+
+    /**
+     * Enable or disable Cross Traffic Monitoring.
+     *
+     * Set true to enable Cross Traffic Monitoring and false to disable Cross Traffic Monitoring.
+     * When Cross Traffic Monitoring is enabled, the ADAS system in the vehicle should be turned on
+     * and monitoring for potential sideways collisions.
+     *
+     * In general, CROSS_TRAFFIC_MONITORING_ENABLED should always return true or false. If the
+     * feature is not available due to some temporary state, such as the vehicle speed being too
+     * high, that information must be conveyed through the ErrorState values in the
+     * CROSS_TRAFFIC_MONITORING_STATE property.
+     *
+     * This property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to
+     * implement it as VehiclePropertyAccess.READ only.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 3
+     */
+    CROSS_TRAFFIC_MONITORING_ENABLED =
+            0x1023 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+
+    /**
+     * Cross Traffic Monitoring warning state.
+     *
+     * Returns the current state of Cross Traffic Monitoring Warning. This property must always
+     * return a valid state defined in CrossTrafficMonitoringWarningState or ErrorState. It must not
+     * surface errors through StatusCode and must use the supported error states instead.
+     *
+     * For the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined
+     * unless all states of both CrossTrafficMonitoringWarningState (including OTHER, which is not
+     * recommended) and ErrorState are supported.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ
+     * @data_enum CrossTrafficMonitoringWarningState
+     * @data_enum ErrorState
+     * @version 3
+     */
+    CROSS_TRAFFIC_MONITORING_WARNING_STATE =
+            0x1024 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
+
+    /**
+     * Enable or disable Low Speed Automatic Emergency Braking.
+     *
+     * Set true to enable Low Speed Automatic Emergency Braking or false to disable Low Speed
+     * Automatic Emergency Braking. When Low Speed Automatic Emergency Braking is enabled, the ADAS
+     * system in the vehicle should be turned on and monitoring to avoid potential collisions in low
+     * speed conditions. This property is different from the pre-existing
+     * AUTOMATIC_EMERGENCY_BRAKING_ENABLED, which should apply to higher speed applications only. If
+     * the vehicle doesn't have a separate collision avoidance system for low speed environments,
+     * this property should not be implemented.
+     *
+     * In general, LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_ENABLED should always return true or false.
+     * If the feature is not available due to some temporary state, such as the vehicle speed being
+     * too low, that information must be conveyed through the ErrorState values in the
+     * LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE property.
+     *
+     * This property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to
+     * implement it as VehiclePropertyAccess.READ only.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
+     * @version 3
+     */
+    LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_ENABLED =
+            0x1025 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+
+    /**
+     * Low Speed Automatic Emergency Braking state.
+     *
+     * Returns the current state of Low Speed Automatic Emergency Braking. This property must always
+     * return a valid state defined in LowSpeedAutomaticEmergencyBrakingState or ErrorState. It must
+     * not surface errors through StatusCode and must use the supported error states instead. This
+     * property is different from the pre-existing AUTOMATIC_EMERGENCY_BRAKING_STATE, which should
+     * apply to higher speed applications only. If the vehicle doesn't have a separate collision
+     * avoidance system for low speed environments, this property should not be implemented.
+     *
+     * If Low Speed Automatic Emergency Braking includes collision warnings before activating the
+     * brakes, those warnings must be surfaced through use of LOW_SPEED_COLLISION_WARNING_ENABLED
+     * and LOW_SPEED_COLLISION_WARNING_STATE.
+     *
+     * For the global area ID (0), the VehicleAreaConfig#supportedEnumValues array must be defined
+     * unless all states of both LowSpeedAutomaticEmergencyBrakingState (including OTHER, which is
+     * not recommended) and ErrorState are supported.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ
+     * @data_enum LowSpeedAutomaticEmergencyBrakingState
+     * @data_enum ErrorState
+     * @version 3
+     */
+    LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE =
+            0x1026 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
+
     /***************************************************************************
      * End of ADAS Properties
      **************************************************************************/
diff --git a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehiclePropertyGroup.aidl b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehiclePropertyGroup.aidl
index a2cbdec..a417388 100644
--- a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehiclePropertyGroup.aidl
+++ b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehiclePropertyGroup.aidl
@@ -29,5 +29,34 @@
      */
     VENDOR = 0x20000000,
 
+    /**
+     * Group reserved for backporting system properties introduced in a newer Android
+     * release to an older Android release.
+     *
+     * It is recommended to map the system property ID to a backported property ID by replacing the
+     * VehiclePropertyGroup, e.g. backported PERF_VEHICLE_SPEED(0x11600207) would be 0x31600207.
+     *
+     * When updated to a newer Android release where the property is defined as system properties,
+     * the backported properties must be migrated to system properties.
+     *
+     * In Android system, the backported property is treated the same as a vendor defined property
+     * with the same vendor permission model, a.k.a. Default required permission is
+     * `android.car.Car.PERMISSION_VENDOR_EXTENSION`, or customized by
+     * `SUPPORT_CUSTOMIZE_VENDOR_PERMISSION` VHAL property.
+     *
+     * Only applications with vendor permissions may access these backported properties.
+     *
+     * Vendors must also make sure this property's behavior is consistent with what is expected for
+     * the backported system property, e.g. the access mode, the change mode and the config array
+     * must be correct.
+     *
+     * When vendors define custom properties, they must use {@code VENDOR} flag, instead of
+     * {@code BACKPORTED}
+     */
+    BACKPORTED = 0x30000000,
+
+    /**
+     * The bit mask for {@code VehiclePropertyGroup}. This is not a group by itself.
+     */
     MASK = 0xf0000000,
 }
diff --git a/automotive/vehicle/proto/Android.bp b/automotive/vehicle/proto/Android.bp
index 683f128..e7dabcf 100644
--- a/automotive/vehicle/proto/Android.bp
+++ b/automotive/vehicle/proto/Android.bp
@@ -27,6 +27,7 @@
     visibility: [
         "//hardware/interfaces/automotive/vehicle:__subpackages__",
         "//device/generic/car/emulator:__subpackages__",
+        "//system/software_defined_vehicle/core_services:__subpackages__",
     ],
     vendor: true,
     host_supported: true,
diff --git a/automotive/vehicle/tools/generate_annotation_enums.py b/automotive/vehicle/tools/generate_annotation_enums.py
old mode 100644
new mode 100755
index c36cbb0..93d408e
--- a/automotive/vehicle/tools/generate_annotation_enums.py
+++ b/automotive/vehicle/tools/generate_annotation_enums.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/python3
 
 # Copyright (C) 2022 The Android Open Source Project
 #
@@ -18,37 +18,48 @@
 
    Need ANDROID_BUILD_TOP environmental variable to be set. This script will update
    ChangeModeForVehicleProperty.h and AccessForVehicleProperty.h under generated_lib/cpp and
-   ChangeModeForVehicleProperty.java and AccessForVehicleProperty.java under generated_lib/java.
+   ChangeModeForVehicleProperty.java, AccessForVehicleProperty.java, EnumForVehicleProperty.java under generated_lib/java.
 
    Usage:
    $ python generate_annotation_enums.py
 """
+import argparse
+import filecmp
 import os
 import re
 import sys
+import tempfile
 
-PROP_AIDL_FILE_PATH = ("hardware/interfaces/automotive/vehicle/aidl_property/android/hardware/" +
-    "automotive/vehicle/VehicleProperty.aidl")
-CHANGE_MODE_CPP_FILE_PATH = ("hardware/interfaces/automotive/vehicle/aidl/generated_lib/cpp/" +
-    "ChangeModeForVehicleProperty.h")
-ACCESS_CPP_FILE_PATH = ("hardware/interfaces/automotive/vehicle/aidl/generated_lib/cpp/" +
-    "AccessForVehicleProperty.h")
-CHANGE_MODE_JAVA_FILE_PATH = ("hardware/interfaces/automotive/vehicle/aidl/generated_lib/java/" +
-    "ChangeModeForVehicleProperty.java")
-ACCESS_JAVA_FILE_PATH = ("hardware/interfaces/automotive/vehicle/aidl/generated_lib/java/" +
-    "AccessForVehicleProperty.java")
+PROP_AIDL_FILE_PATH = ('hardware/interfaces/automotive/vehicle/aidl_property/android/hardware/' +
+    'automotive/vehicle/VehicleProperty.aidl')
+CHANGE_MODE_CPP_FILE_PATH = ('hardware/interfaces/automotive/vehicle/aidl/generated_lib/cpp/' +
+    'ChangeModeForVehicleProperty.h')
+ACCESS_CPP_FILE_PATH = ('hardware/interfaces/automotive/vehicle/aidl/generated_lib/cpp/' +
+    'AccessForVehicleProperty.h')
+CHANGE_MODE_JAVA_FILE_PATH = ('hardware/interfaces/automotive/vehicle/aidl/generated_lib/java/' +
+    'ChangeModeForVehicleProperty.java')
+ACCESS_JAVA_FILE_PATH = ('hardware/interfaces/automotive/vehicle/aidl/generated_lib/java/' +
+    'AccessForVehicleProperty.java')
+ENUM_JAVA_FILE_PATH = ('hardware/interfaces/automotive/vehicle/aidl/generated_lib/java/' +
+                         'EnumForVehicleProperty.java')
+VERSION_CPP_FILE_PATH = ('hardware/interfaces/automotive/vehicle/aidl/generated_lib/cpp/' +
+    'VersionForVehicleProperty.h')
+SCRIPT_PATH = 'hardware/interfaces/automotive/vehicle/tools/generate_annotation_enums.py'
 
-TAB = "    "
-RE_ENUM_START = re.compile("\s*enum VehicleProperty \{")
-RE_ENUM_END = re.compile("\s*\}\;")
-RE_COMMENT_BEGIN = re.compile("\s*\/\*\*?")
-RE_COMMENT_END = re.compile("\s*\*\/")
-RE_CHANGE_MODE = re.compile("\s*\* @change_mode (\S+)\s*")
-RE_ACCESS = re.compile("\s*\* @access (\S+)\s*")
-RE_VALUE = re.compile("\s*(\w+)\s*=(.*)")
+TAB = '    '
+RE_ENUM_START = re.compile('\s*enum VehicleProperty \{')
+RE_ENUM_END = re.compile('\s*\}\;')
+RE_COMMENT_BEGIN = re.compile('\s*\/\*\*?')
+RE_COMMENT_END = re.compile('\s*\*\/')
+RE_CHANGE_MODE = re.compile('\s*\* @change_mode (\S+)\s*')
+RE_VERSION = re.compile('\s*\* @version (\S+)\s*')
+RE_ACCESS = re.compile('\s*\* @access (\S+)\s*')
+RE_DATA_ENUM = re.compile('\s*\* @data_enum (\S+)\s*')
+RE_UNIT = re.compile('\s*\* @unit (\S+)\s+')
+RE_VALUE = re.compile('\s*(\w+)\s*=(.*)')
 
 LICENSE = """/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -73,8 +84,7 @@
 
 """
 
-CHANGE_MODE_CPP_HEADER = """#ifndef android_hardware_automotive_vehicle_aidl_generated_lib_ChangeModeForVehicleProperty_H_
-#define android_hardware_automotive_vehicle_aidl_generated_lib_ChangeModeForVehicleProperty_H_
+CHANGE_MODE_CPP_HEADER = """#pragma once
 
 #include <aidl/android/hardware/automotive/vehicle/VehicleProperty.h>
 #include <aidl/android/hardware/automotive/vehicle/VehiclePropertyChangeMode.h>
@@ -90,7 +100,7 @@
 std::unordered_map<VehicleProperty, VehiclePropertyChangeMode> ChangeModeForVehicleProperty = {
 """
 
-CHANGE_MODE_CPP_FOOTER = """
+CPP_FOOTER = """
 };
 
 }  // namespace vehicle
@@ -98,12 +108,9 @@
 }  // namespace hardware
 }  // namespace android
 }  // aidl
-
-#endif  // android_hardware_automotive_vehicle_aidl_generated_lib_ChangeModeForVehicleProperty_H_
 """
 
-ACCESS_CPP_HEADER = """#ifndef android_hardware_automotive_vehicle_aidl_generated_lib_AccessForVehicleProperty_H_
-#define android_hardware_automotive_vehicle_aidl_generated_lib_AccessForVehicleProperty_H_
+ACCESS_CPP_HEADER = """#pragma once
 
 #include <aidl/android/hardware/automotive/vehicle/VehicleProperty.h>
 #include <aidl/android/hardware/automotive/vehicle/VehiclePropertyAccess.h>
@@ -119,16 +126,19 @@
 std::unordered_map<VehicleProperty, VehiclePropertyAccess> AccessForVehicleProperty = {
 """
 
-ACCESS_CPP_FOOTER = """
-};
+VERSION_CPP_HEADER = """#pragma once
 
-}  // namespace vehicle
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
-}  // aidl
+#include <aidl/android/hardware/automotive/vehicle/VehicleProperty.h>
 
-#endif  // android_hardware_automotive_vehicle_aidl_generated_lib_AccessForVehicleProperty_H_
+#include <unordered_map>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+
+std::unordered_map<VehicleProperty, int32_t> VersionForVehicleProperty = {
 """
 
 CHANGE_MODE_JAVA_HEADER = """package android.hardware.automotive.vehicle;
@@ -140,7 +150,7 @@
     public static final Map<Integer, Integer> values = Map.ofEntries(
 """
 
-CHANGE_MODE_JAVA_FOOTER = """
+JAVA_FOOTER = """
     );
 
 }
@@ -155,63 +165,173 @@
     public static final Map<Integer, Integer> values = Map.ofEntries(
 """
 
-ACCESS_JAVA_FOOTER = """
-    );
+ENUM_JAVA_HEADER = """package android.hardware.automotive.vehicle;
 
-}
+import java.util.List;
+import java.util.Map;
+
+public final class EnumForVehicleProperty {
+
+    public static final Map<Integer, List<Class<?>>> values = Map.ofEntries(
 """
 
 
-class Converter:
+class PropertyConfig:
+    """Represents one VHAL property definition in VehicleProperty.aidl."""
 
-    def __init__(self, name, annotation_re):
-        self.name = name
-        self.annotation_re = annotation_re
+    def __init__(self):
+        self.name = None
+        self.description = None
+        self.comment = None
+        self.change_mode = None
+        self.access_modes = []
+        self.enum_types = []
+        self.unit_type = None
+        self.version = None
 
-    def convert(self, input, output, header, footer, cpp):
+    def __repr__(self):
+        return self.__str__()
+
+    def __str__(self):
+        return ('PropertyConfig{{' +
+            'name: {}, description: {}, change_mode: {}, access_modes: {}, enum_types: {}' +
+            ', unit_type: {}, version: {}, comment: {}}}').format(self.name, self.description,
+                self.change_mode, self.access_modes, self.enum_types, self.unit_type,
+                self.version, self.comment)
+
+
+class FileParser:
+
+    def __init__(self):
+        self.configs = None
+
+    def parseFile(self, input_file):
+        """Parses the input VehicleProperty.aidl file into a list of property configs."""
         processing = False
         in_comment = False
-        content = LICENSE + header
-        annotation = None
-        id = 0
-        with open(input, 'r') as f:
+        configs = []
+        config = None
+        with open(input_file, 'r') as f:
             for line in f.readlines():
                 if RE_ENUM_START.match(line):
                     processing = True
-                    annotation = None
                 elif RE_ENUM_END.match(line):
                     processing = False
                 if not processing:
                     continue
                 if RE_COMMENT_BEGIN.match(line):
                     in_comment = True
+                    config = PropertyConfig()
+                    description = ''
+                    continue
+
                 if RE_COMMENT_END.match(line):
                     in_comment = False
                 if in_comment:
-                    match = self.annotation_re.match(line)
+                    match = RE_CHANGE_MODE.match(line)
                     if match:
-                        annotation = match.group(1)
+                        config.change_mode = match.group(1).replace('VehiclePropertyChangeMode.', '')
+                        continue
+                    match = RE_ACCESS.match(line)
+                    if match:
+                        config.access_modes.append(match.group(1).replace('VehiclePropertyAccess.', ''))
+                        continue
+                    match = RE_UNIT.match(line)
+                    if match:
+                        config.unit_type = match.group(1)
+                        continue
+                    match = RE_DATA_ENUM.match(line)
+                    if match:
+                        config.enum_types.append(match.group(1))
+                        continue
+                    match = RE_VERSION.match(line)
+                    if match:
+                        if config.version != None:
+                            raise Exception('Duplicate version annotation for property: ' + prop_name)
+                        config.version = match.group(1)
+                        continue
+
+                    sline = line.strip()
+                    if sline.startswith('*'):
+                        # Remove the '*'.
+                        sline = sline[1:].strip()
+
+                    if not config.description:
+                        # We reach an empty line of comment, the description part is ending.
+                        if sline == '':
+                            config.description = description
+                        else:
+                            if description != '':
+                                description += ' '
+                            description += sline
+                    else:
+                        if not config.comment:
+                            if sline != '':
+                                # This is the first line for comment.
+                                config.comment = sline
+                        else:
+                            if sline != '':
+                                # Concat this line with the previous line's comment with a space.
+                                config.comment += ' ' + sline
+                            else:
+                                # Treat empty line comment as a new line.
+                                config.comment += '\n'
                 else:
                     match = RE_VALUE.match(line)
                     if match:
                         prop_name = match.group(1)
-                        if prop_name == "INVALID":
+                        if prop_name == 'INVALID':
                             continue
-                        if not annotation:
-                            print("No @" + self.name + " annotation for property: " + prop_name)
-                            sys.exit(1)
-                        if id != 0:
-                            content += "\n"
-                        if cpp:
-                            annotation = annotation.replace(".", "::")
-                            content += (TAB + TAB + "{VehicleProperty::" + prop_name + ", " +
-                                        annotation + "},")
-                        else:
-                            content += (TAB + TAB + "Map.entry(VehicleProperty." + prop_name + ", " +
-                                        annotation + "),")
-                        id += 1
+                        if not config.change_mode:
+                            raise Exception(
+                                    'No change_mode annotation for property: ' + prop_name)
+                        if not config.access_modes:
+                            raise Exception(
+                                    'No access_mode annotation for property: ' + prop_name)
+                        if not config.version:
+                            raise Exception(
+                                    'no version annotation for property: ' + prop_name)
+                        config.name = prop_name
+                        configs.append(config)
 
-        # Remove the additional "," at the end for the Java file.
+        self.configs = configs
+
+    def convert(self, output, header, footer, cpp, field):
+        """Converts the property config file to C++/Java output file."""
+        counter = 0
+        content = LICENSE + header
+        for config in self.configs:
+            if field == 'change_mode':
+                if cpp:
+                    annotation = "VehiclePropertyChangeMode::" + config.change_mode
+                else:
+                    annotation = "VehiclePropertyChangeMode." + config.change_mode
+            elif field == 'access_mode':
+                if cpp:
+                    annotation = "VehiclePropertyAccess::" + config.access_modes[0]
+                else:
+                    annotation = "VehiclePropertyAccess." + config.access_modes[0]
+            elif field == 'enum_types':
+                if len(config.enum_types) < 1:
+                    continue;
+                if not cpp:
+                    annotation = "List.of(" + ', '.join([class_name + ".class" for class_name in config.enum_types]) + ")"
+            elif field == 'version':
+                if cpp:
+                    annotation = config.version
+            else:
+                raise Exception('Unknown field: ' + field)
+            if counter != 0:
+                content += '\n'
+            if cpp:
+                content += (TAB + TAB + '{VehicleProperty::' + config.name + ', ' +
+                            annotation + '},')
+            else:
+                content += (TAB + TAB + 'Map.entry(VehicleProperty.' + config.name + ', ' +
+                            annotation + '),')
+            counter += 1
+
+        # Remove the additional ',' at the end for the Java file.
         if not cpp:
             content = content[:-1]
 
@@ -220,26 +340,193 @@
         with open(output, 'w') as f:
             f.write(content)
 
+    def outputAsCsv(self, output):
+        content = 'name,description,change mode,access mode,enum type,unit type,comment\n'
+        for config in self.configs:
+            enum_types = None
+            if not config.enum_types:
+                enum_types = '/'
+            else:
+                enum_types = '/'.join(config.enum_types)
+            unit_type = config.unit_type
+            if not unit_type:
+                unit_type = '/'
+            access_modes = ''
+            comment = config.comment
+            if not comment:
+                comment = ''
+            content += '"{}","{}","{}","{}","{}","{}", "{}"\n'.format(
+                    config.name,
+                    # Need to escape quote as double quote.
+                    config.description.replace('"', '""'),
+                    config.change_mode,
+                    '/'.join(config.access_modes),
+                    enum_types,
+                    unit_type,
+                    comment.replace('"', '""'))
+
+        with open(output, 'w+') as f:
+            f.write(content)
+
+
+def createTempFile():
+    f = tempfile.NamedTemporaryFile(delete=False);
+    f.close();
+    return f.name
+
+
+class GeneratedFile:
+
+    def __init__(self, type):
+        self.type = type
+        self.cpp_file_path = None
+        self.java_file_path = None
+        self.cpp_header = None
+        self.java_header = None
+        self.cpp_footer = None
+        self.java_footer = None
+        self.cpp_output_file = None
+        self.java_output_file = None
+
+    def setCppFilePath(self, cpp_file_path):
+        self.cpp_file_path = cpp_file_path
+
+    def setJavaFilePath(self, java_file_path):
+        self.java_file_path = java_file_path
+
+    def setCppHeader(self, cpp_header):
+        self.cpp_header = cpp_header
+
+    def setCppFooter(self, cpp_footer):
+        self.cpp_footer = cpp_footer
+
+    def setJavaHeader(self, java_header):
+        self.java_header = java_header
+
+    def setJavaFooter(self, java_footer):
+        self.java_footer = java_footer
+
+    def convert(self, file_parser, check_only, temp_files):
+        if self.cpp_file_path:
+            output_file = GeneratedFile._getOutputFile(self.cpp_file_path, check_only, temp_files)
+            file_parser.convert(output_file, self.cpp_header, self.cpp_footer, True, self.type)
+            self.cpp_output_file = output_file
+
+        if self.java_file_path:
+            output_file = GeneratedFile._getOutputFile(self.java_file_path, check_only, temp_files)
+            file_parser.convert(output_file, self.java_header, self.java_footer, False, self.type)
+            self.java_output_file = output_file
+
+    def cmp(self):
+        if self.cpp_file_path:
+            if not filecmp.cmp(self.cpp_output_file, self.cpp_file_path):
+                return False
+
+        if self.java_file_path:
+            if not filecmp.cmp(self.java_output_file, self.java_file_path):
+                return False
+
+        return True
+
+    @staticmethod
+    def _getOutputFile(file_path, check_only, temp_files):
+        if not check_only:
+            return file_path
+
+        temp_file = createTempFile()
+        temp_files.append(temp_file)
+        return temp_file
+
 
 def main():
-    android_top = os.environ['ANDROID_BUILD_TOP']
+    parser = argparse.ArgumentParser(
+            description='Generate Java and C++ enums based on annotations in VehicleProperty.aidl')
+    parser.add_argument('--android_build_top', required=False, help='Path to ANDROID_BUILD_TOP')
+    parser.add_argument('--preupload_files', nargs='*', required=False, help='modified files')
+    parser.add_argument('--check_only', required=False, action='store_true',
+            help='only check whether the generated files need update')
+    parser.add_argument('--output_csv', required=False,
+            help='Path to the parsing result in CSV style, useful for doc generation')
+    args = parser.parse_args();
+    android_top = None
+    output_folder = None
+    if args.android_build_top:
+        android_top = args.android_build_top
+        vehiclePropertyUpdated = False
+        for preuload_file in args.preupload_files:
+            if preuload_file.endswith('VehicleProperty.aidl'):
+                vehiclePropertyUpdated = True
+                break
+        if not vehiclePropertyUpdated:
+            return
+    else:
+        android_top = os.environ['ANDROID_BUILD_TOP']
     if not android_top:
-        print("ANDROID_BUILD_TOP is not in envorinmental variable, please run source and lunch " +
-            "at the android root")
+        print('ANDROID_BUILD_TOP is not in environmental variable, please run source and lunch ' +
+            'at the android root')
 
     aidl_file = os.path.join(android_top, PROP_AIDL_FILE_PATH)
-    change_mode_cpp_output = os.path.join(android_top, CHANGE_MODE_CPP_FILE_PATH);
-    access_cpp_output = os.path.join(android_top, ACCESS_CPP_FILE_PATH);
-    change_mode_java_output = os.path.join(android_top, CHANGE_MODE_JAVA_FILE_PATH);
-    access_java_output = os.path.join(android_top, ACCESS_JAVA_FILE_PATH);
+    f = FileParser();
+    f.parseFile(aidl_file)
 
-    c = Converter("change_mode", RE_CHANGE_MODE);
-    c.convert(aidl_file, change_mode_cpp_output, CHANGE_MODE_CPP_HEADER, CHANGE_MODE_CPP_FOOTER, True)
-    c.convert(aidl_file, change_mode_java_output, CHANGE_MODE_JAVA_HEADER, CHANGE_MODE_JAVA_FOOTER, False)
-    c = Converter("access", RE_ACCESS)
-    c.convert(aidl_file, access_cpp_output, ACCESS_CPP_HEADER, ACCESS_CPP_FOOTER, True)
-    c.convert(aidl_file, access_java_output, ACCESS_JAVA_HEADER, ACCESS_JAVA_FOOTER, False)
+    if args.output_csv:
+        f.outputAsCsv(args.output_csv)
+        return
+
+    generated_files = []
+
+    change_mode = GeneratedFile('change_mode')
+    change_mode.setCppFilePath(os.path.join(android_top, CHANGE_MODE_CPP_FILE_PATH))
+    change_mode.setJavaFilePath(os.path.join(android_top, CHANGE_MODE_JAVA_FILE_PATH))
+    change_mode.setCppHeader(CHANGE_MODE_CPP_HEADER)
+    change_mode.setCppFooter(CPP_FOOTER)
+    change_mode.setJavaHeader(CHANGE_MODE_JAVA_HEADER)
+    change_mode.setJavaFooter(JAVA_FOOTER)
+    generated_files.append(change_mode)
+
+    access_mode = GeneratedFile('access_mode')
+    access_mode.setCppFilePath(os.path.join(android_top, ACCESS_CPP_FILE_PATH))
+    access_mode.setJavaFilePath(os.path.join(android_top, ACCESS_JAVA_FILE_PATH))
+    access_mode.setCppHeader(ACCESS_CPP_HEADER)
+    access_mode.setCppFooter(CPP_FOOTER)
+    access_mode.setJavaHeader(ACCESS_JAVA_HEADER)
+    access_mode.setJavaFooter(JAVA_FOOTER)
+    generated_files.append(access_mode)
+
+    enum_types = GeneratedFile('enum_types')
+    enum_types.setJavaFilePath(os.path.join(android_top, ENUM_JAVA_FILE_PATH))
+    enum_types.setJavaHeader(ENUM_JAVA_HEADER)
+    enum_types.setJavaFooter(JAVA_FOOTER)
+    generated_files.append(enum_types)
+
+    version = GeneratedFile('version')
+    version.setCppFilePath(os.path.join(android_top, VERSION_CPP_FILE_PATH))
+    version.setCppHeader(VERSION_CPP_HEADER)
+    version.setCppFooter(CPP_FOOTER)
+    generated_files.append(version)
+
+    temp_files = []
+
+    try:
+        for generated_file in generated_files:
+            generated_file.convert(f, args.check_only, temp_files)
+
+        if not args.check_only:
+            return
+
+        for generated_file in generated_files:
+            if not generated_file.cmp():
+                print('The generated enum files for VehicleProperty.aidl requires update, ')
+                print('Run \npython ' + android_top + '/' + SCRIPT_PATH)
+                sys.exit(1)
+    except Exception as e:
+        print('Error parsing VehicleProperty.aidl')
+        print(e)
+        sys.exit(1)
+    finally:
+        for file in temp_files:
+            os.remove(file)
 
 
-if __name__ == "__main__":
+if __name__ == '__main__':
     main()
\ No newline at end of file
diff --git a/automotive/vehicle/tools/translate_aidl_enums.py b/automotive/vehicle/tools/translate_aidl_enums.py
new file mode 100644
index 0000000..d224f6f
--- /dev/null
+++ b/automotive/vehicle/tools/translate_aidl_enums.py
@@ -0,0 +1,231 @@
+#!/usr/bin/python3
+
+# Copyright (C) 2023 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+"""A script to generate ENUM_NAME.java file and test files using ENUM_NAME.aidl file.
+
+   Need ANDROID_BUILD_TOP environmental variable to be set. This script will update ENUM_NAME.java
+   under packages/services/Car/car-lib/src/android/car/hardware/property, as well as the
+   ENUM_NAMETest.java files in cts/tests/tests/car/src/android/car/cts and
+   packages/services/Car/tests/android_car_api_test/src/android/car/apitest
+
+   Usage:
+   $ python translate_aidl_enums.py ENUM_NAME.aidl
+"""
+import os
+import sys
+
+LICENSE = """/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+"""
+
+class EnumParser:
+    def __init__(self, file_path, file_name):
+        self.filePath = file_path
+        self.fileName = file_name
+        self.lowerFileName = self.fileName[0].lower() + self.fileName[1:]
+        self.enums = []
+        self.outputMsg = []
+        self.outputMsg.append(LICENSE)
+        self.outputMsg.append("\npackage android.car.hardware.property;\n")
+        self.outputMsg.append("""
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+
+import com.android.car.internal.util.ConstantDebugUtils;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+""")
+
+        with open(self.filePath, 'r') as f:
+            for line in f.readlines()[16:]:
+                if line in ["package android.hardware.automotive.vehicle;\n",
+                            "@VintfStability\n",
+                            '@Backing(type="int")\n']:
+                    continue
+
+                msg = line
+                msgSplit = msg.strip().split()
+                if len(msgSplit) > 0 and msgSplit[0] == "enum":
+                    msgSplit[0] = "public final class"
+                    msg = " ".join(msgSplit) + "\n"
+                elif len(msgSplit) > 1 and msgSplit[1] == '=':
+                    msgSplit.insert(0, "    public static final int")
+                    self.enums.append(msgSplit[1])
+                    msgSplit[-1] = msgSplit[-1][:-1] + ";\n"
+                    msg = " ".join(msgSplit)
+                elif msg == "}\n":
+                    self.outputMsg.append("""
+    private {2}() {{}}
+
+    /**
+     * Returns a user-friendly representation of {{@code {2}}}.
+     */
+    @NonNull
+    public static String toString(@{2}Int int {0}) {{
+        String {0}String = ConstantDebugUtils.toName(
+                {2}.class, {0});
+        return ({0}String != null)
+                ? {0}String
+                : "0x" + Integer.toHexString({0});
+    }}
+
+    /** @hide */
+    @IntDef({1})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface {2}Int {{}}\n""".format(self.lowerFileName, "{" + ", ".join(self.enums) + "}",
+                                              self.fileName))
+                self.outputMsg.append(msg)
+        self.outputMsg.append("TODO: delete this line and manually update this file with app-facing documentation and necessary tags.\n")
+
+        self.outputMsgApiTest = []
+        self.outputMsgApiTest.append(LICENSE)
+        self.outputMsgApiTest.append("""package android.car.apitest;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+@SmallTest
+@RunWith(Parameterized.class)
+public class {0}Test {{
+    private final int mJavaConstantValue;
+    private final int mHalConstantValue;
+
+    public {0}Test(int javaConstantValue, int halConstantValue) {{
+        mJavaConstantValue = javaConstantValue;
+        mHalConstantValue = halConstantValue;
+    }}
+
+    @Parameterized.Parameters
+    public static Collection constantValues() {{
+        return Arrays.asList(
+                new Object[][] {{""".format(self.fileName))
+        for enum in self.enums:
+            self.outputMsgApiTest.append("""
+                        {{
+                                android.car.hardware.property.{0}.{1},
+                                android.hardware.automotive.vehicle.{0}.{1}
+                        }},""".format(self.fileName, enum))
+        self.outputMsgApiTest.append("""
+                });
+    }
+
+    @Test
+    public void testMatchWithVehicleHal() {
+        assertWithMessage("Java constant")
+                .that(mJavaConstantValue)
+                .isEqualTo(mHalConstantValue);
+    }
+}
+""")
+
+        self.outputMsgCtsTest = []
+        self.outputMsgCtsTest.append(LICENSE)
+        self.outputMsgCtsTest.append("""
+package android.car.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.car.cts.utils.VehiclePropertyUtils;
+import android.car.hardware.property.{0};
+
+import org.junit.Test;
+
+import java.util.List;
+
+public class {0}Test {{
+
+    @Test
+    public void testToString() {{""".format(self.fileName))
+        for enum in self.enums:
+            self.outputMsgCtsTest.append("""
+        assertThat({0}.toString(
+                {0}.{1}))
+                .isEqualTo("{1}");""".format(self.fileName, enum))
+        self.outputMsgCtsTest.append("""
+        assertThat({0}.toString({1})).isEqualTo("{2}");
+        assertThat({0}.toString(12)).isEqualTo("0xc");
+    }}
+
+    @Test
+    public void testAll{0}sAreMappedInToString() {{
+        List<Integer> {3}s =
+                VehiclePropertyUtils.getIntegersFromDataEnums({0}.class);
+        for (Integer {3} : {3}s) {{
+            String {3}String = {0}.toString(
+                    {3});
+            assertWithMessage("%s starts with 0x", {3}String).that(
+                    {3}String.startsWith("0x")).isFalse();
+        }}
+    }}
+}}
+""".format(self.fileName, len(self.enums), hex(len(self.enums)), self.lowerFileName))
+
+def main():
+    if len(sys.argv) != 2:
+        print("Usage: {} enum_aidl_file".format(sys.argv[0]))
+        sys.exit(1)
+    print("WARNING: This file only generates the base enum values in the framework layer. The "
+          + "generated files must be reviewed by you and edited if any additional changes are "
+          + "required. The java enum file should be updated with app-developer facing "
+          + "documentation, the @FlaggedApi tag for the new API, and with the @SystemApi tag if "
+          + "the new property is system API")
+    file_path = sys.argv[1]
+    file_name = file_path.split('/')[-1][:-5]
+    parser = EnumParser(file_path, file_name)
+
+    android_top = os.environ['ANDROID_BUILD_TOP']
+    if not android_top:
+        print('ANDROID_BUILD_TOP is not in environmental variable, please run source and lunch '
+              + 'at the android root')
+
+    with open(android_top + "/packages/services/Car/car-lib/src/android/car/hardware/property/"
+              + file_name + ".java", 'w') as f:
+        f.write("".join(parser.outputMsg))
+
+    with open(android_top
+              + "/packages/services/Car/tests/android_car_api_test/src/android/car/apitest/"
+              + file_name + "Test.java", 'w') as f:
+        f.write("".join(parser.outputMsgApiTest))
+
+    with open(android_top + "/cts/tests/tests/car/src/android/car/cts/" + file_name + "Test.java",
+              'w') as f:
+        f.write("".join(parser.outputMsgCtsTest))
+
+if __name__ == "__main__":
+    main()
\ No newline at end of file
diff --git a/automotive/vehicle/vhal_static_cpp_lib.mk b/automotive/vehicle/vhal_static_cpp_lib.mk
index 995589c..6b3d486 100644
--- a/automotive/vehicle/vhal_static_cpp_lib.mk
+++ b/automotive/vehicle/vhal_static_cpp_lib.mk
@@ -16,5 +16,5 @@
 # interface and VHAL properties.
 
 LOCAL_STATIC_LIBRARIES += \
-    android.hardware.automotive.vehicle-V2-ndk \
-    android.hardware.automotive.vehicle.property-V2-ndk
+    android.hardware.automotive.vehicle-V3-ndk \
+    android.hardware.automotive.vehicle.property-V3-ndk
diff --git a/automotive/vehicle/vts/Android.bp b/automotive/vehicle/vts/Android.bp
index 736787b..67d0d34 100644
--- a/automotive/vehicle/vts/Android.bp
+++ b/automotive/vehicle/vts/Android.bp
@@ -30,6 +30,7 @@
     ],
     static_libs: [
         "libgtest",
+        "libgmock",
         "libvhalclient",
     ],
     shared_libs: [
@@ -41,6 +42,9 @@
         "use_libaidlvintf_gtest_helper_static",
         "vhalclient_defaults",
     ],
+    header_libs: [
+        "IVehicleGeneratedHeaders",
+    ],
     test_suites: [
         "general-tests",
         "vts",
diff --git a/automotive/vehicle/vts/OWNERS b/automotive/vehicle/vts/OWNERS
index c93a843..0f88eec 100644
--- a/automotive/vehicle/vts/OWNERS
+++ b/automotive/vehicle/vts/OWNERS
@@ -1,3 +1,3 @@
 # Bug component: 533426
 shanyu@google.com
-kwangsudo@google.com
+tylertrephan@google.com
diff --git a/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
index 737be84..f8ddfaa 100644
--- a/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
+++ b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
@@ -19,12 +19,14 @@
 #include <IVhalClient.h>
 #include <VehicleHalTypes.h>
 #include <VehicleUtils.h>
+#include <VersionForVehicleProperty.h>
 #include <aidl/Gtest.h>
 #include <aidl/Vintf.h>
 #include <aidl/android/hardware/automotive/vehicle/IVehicle.h>
 #include <android-base/stringprintf.h>
 #include <android-base/thread_annotations.h>
 #include <android/binder_process.h>
+#include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include <hidl/GtestPrinter.h>
 #include <hidl/ServiceManagement.h>
@@ -47,6 +49,7 @@
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyChangeMode;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyGroup;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyType;
+using ::aidl::android::hardware::automotive::vehicle::VersionForVehicleProperty;
 using ::android::getAidlHalInstanceNames;
 using ::android::base::ScopedLockAssertion;
 using ::android::base::StringPrintf;
@@ -58,7 +61,10 @@
 using ::android::frameworks::automotive::vhal::IVhalClient;
 using ::android::hardware::getAllHalInstanceNames;
 using ::android::hardware::Sanitize;
+using ::android::hardware::automotive::vehicle::isSystemProp;
+using ::android::hardware::automotive::vehicle::propIdToString;
 using ::android::hardware::automotive::vehicle::toInt;
+using ::testing::Ge;
 
 constexpr int32_t kInvalidProp = 0x31600207;
 
@@ -166,9 +172,8 @@
 
     ASSERT_TRUE(result.ok()) << "Failed to get all property configs, error: "
                              << result.error().message();
-    ASSERT_GE(result.value().size(), 1u)
-          << StringPrintf("Expect to get at least 1 property config, got %zu",
-                          result.value().size());
+    ASSERT_GE(result.value().size(), 1u) << StringPrintf(
+            "Expect to get at least 1 property config, got %zu", result.value().size());
 }
 
 // Test getPropConfigs() can query properties returned by getAllPropConfigs.
@@ -188,9 +193,8 @@
 
     ASSERT_TRUE(result.ok()) << "Failed to get required property config, error: "
                              << result.error().message();
-    ASSERT_EQ(result.value().size(), properties.size())
-          << StringPrintf("Expect to get exactly %zu configs, got %zu",
-                          properties.size(), result.value().size());
+    ASSERT_EQ(result.value().size(), properties.size()) << StringPrintf(
+            "Expect to get exactly %zu configs, got %zu", properties.size(), result.value().size());
 }
 
 // Test getPropConfig() with an invalid propertyId returns an error code.
@@ -204,6 +208,41 @@
     ASSERT_NE(result.error().message(), "") << "Expect error message not to be empty";
 }
 
+// Test system property IDs returned by getPropConfigs() are defined in the VHAL property interface.
+TEST_P(VtsHalAutomotiveVehicleTargetTest, testPropConfigs_onlyDefinedSystemPropertyIdsReturned) {
+    if (!mVhalClient->isAidlVhal()) {
+        GTEST_SKIP() << "Skip for HIDL VHAL because HAL interface run-time version is only"
+                     << "introduced for AIDL";
+    }
+
+    auto result = mVhalClient->getAllPropConfigs();
+    ASSERT_TRUE(result.ok()) << "Failed to get all property configs, error: "
+                             << result.error().message();
+
+    int32_t vhalVersion = mVhalClient->getRemoteInterfaceVersion();
+    const auto& configs = result.value();
+    for (size_t i = 0; i < configs.size(); i++) {
+        int32_t propId = configs[i]->getPropId();
+        if (!isSystemProp(propId)) {
+            continue;
+        }
+
+        std::string propName = propIdToString(propId);
+        auto it = VersionForVehicleProperty.find(static_cast<VehicleProperty>(propId));
+        bool found = (it != VersionForVehicleProperty.end());
+        EXPECT_TRUE(found) << "System Property: " << propName
+                           << " is not defined in VHAL property interface";
+        if (!found) {
+            continue;
+        }
+        int32_t requiredVersion = it->second;
+        EXPECT_THAT(vhalVersion, Ge(requiredVersion))
+                << "System Property: " << propName << " requires VHAL version: " << requiredVersion
+                << ", but the current VHAL version"
+                << " is " << vhalVersion << ", must not be supported";
+    }
+}
+
 // Test get() return current value for properties.
 TEST_P(VtsHalAutomotiveVehicleTargetTest, get) {
     ALOGD("VtsHalAutomotiveVehicleTargetTest::get");
@@ -550,6 +589,44 @@
                    VehicleArea::GLOBAL, VehiclePropertyType::INT32);
 }
 
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyUltrasonicsSensorPositionConfig) {
+    verifyProperty(VehicleProperty::ULTRASONICS_SENSOR_POSITION, VehiclePropertyAccess::READ,
+                   VehiclePropertyChangeMode::STATIC, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::VENDOR, VehiclePropertyType::INT32_VEC);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyUltrasonicsSensorOrientationConfig) {
+    verifyProperty(VehicleProperty::ULTRASONICS_SENSOR_ORIENTATION, VehiclePropertyAccess::READ,
+                   VehiclePropertyChangeMode::STATIC, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::VENDOR, VehiclePropertyType::INT32_VEC);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyUltrasonicsSensorFieldOfViewConfig) {
+    verifyProperty(VehicleProperty::ULTRASONICS_SENSOR_FIELD_OF_VIEW, VehiclePropertyAccess::READ,
+                   VehiclePropertyChangeMode::STATIC, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::VENDOR, VehiclePropertyType::INT32_VEC);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyUltrasonicsSensorDetectionRangeConfig) {
+    verifyProperty(VehicleProperty::ULTRASONICS_SENSOR_DETECTION_RANGE, VehiclePropertyAccess::READ,
+                   VehiclePropertyChangeMode::STATIC, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::VENDOR, VehiclePropertyType::INT32_VEC);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyUltrasonicsSensorSupportedRangesConfig) {
+    verifyProperty(VehicleProperty::ULTRASONICS_SENSOR_SUPPORTED_RANGES,
+                   VehiclePropertyAccess::READ, VehiclePropertyChangeMode::STATIC,
+                   VehiclePropertyGroup::SYSTEM, VehicleArea::VENDOR,
+                   VehiclePropertyType::INT32_VEC);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyUltrasonicsSensorMeasuredDistanceConfig) {
+    verifyProperty(VehicleProperty::ULTRASONICS_SENSOR_MEASURED_DISTANCE,
+                   VehiclePropertyAccess::READ, VehiclePropertyChangeMode::CONTINUOUS,
+                   VehiclePropertyGroup::SYSTEM, VehicleArea::VENDOR,
+                   VehiclePropertyType::INT32_VEC);
+}
+
 TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyEmergencyLaneKeepAssistEnabledConfig) {
     verifyProperty(VehicleProperty::EMERGENCY_LANE_KEEP_ASSIST_ENABLED,
                    VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
@@ -623,6 +700,54 @@
                    VehicleArea::GLOBAL, VehiclePropertyType::INT32);
 }
 
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyDriverDrowsinessAttentionSystemEnabledConfig) {
+    verifyProperty(VehicleProperty::DRIVER_DROWSINESS_ATTENTION_SYSTEM_ENABLED,
+                   VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
+                   VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyDriverDrowsinessAttentionStateConfig) {
+    verifyProperty(VehicleProperty::DRIVER_DROWSINESS_ATTENTION_STATE, VehiclePropertyAccess::READ,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::GLOBAL, VehiclePropertyType::INT32);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyDriverDrowsinessAttentionWarningEnabledConfig) {
+    verifyProperty(VehicleProperty::DRIVER_DROWSINESS_ATTENTION_WARNING_ENABLED,
+                   VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
+                   VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyDriverDrowsinessAttentionWarningConfig) {
+    verifyProperty(VehicleProperty::DRIVER_DROWSINESS_ATTENTION_WARNING,
+                   VehiclePropertyAccess::READ, VehiclePropertyChangeMode::ON_CHANGE,
+                   VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::INT32);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyDriverDistractionSystemEnabledConfig) {
+    verifyProperty(VehicleProperty::DRIVER_DISTRACTION_SYSTEM_ENABLED,
+                   VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
+                   VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyDriverDistractionStateConfig) {
+    verifyProperty(VehicleProperty::DRIVER_DISTRACTION_STATE, VehiclePropertyAccess::READ,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::GLOBAL, VehiclePropertyType::INT32);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyDriverDistractionWarningEnabledConfig) {
+    verifyProperty(VehicleProperty::DRIVER_DISTRACTION_WARNING_ENABLED,
+                   VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
+                   VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyDriverDistractionWarningConfig) {
+    verifyProperty(VehicleProperty::DRIVER_DISTRACTION_WARNING, VehiclePropertyAccess::READ,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::GLOBAL, VehiclePropertyType::INT32);
+}
+
 TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyEvBrakeRegenerationLevelConfig) {
     verifyProperty(VehicleProperty::EV_BRAKE_REGENERATION_LEVEL,
                    VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
@@ -887,9 +1012,105 @@
                    VehicleArea::GLOBAL, VehiclePropertyType::INT32);
 }
 
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyClusterHeartbeatConfig) {
+    verifyProperty(VehicleProperty::CLUSTER_HEARTBEAT, VehiclePropertyAccess::WRITE,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::GLOBAL, VehiclePropertyType::MIXED);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyVehicleDrivingAutomationCurrentLevelConfig) {
+    verifyProperty(VehicleProperty::VEHICLE_DRIVING_AUTOMATION_CURRENT_LEVEL,
+                   VehiclePropertyAccess::READ, VehiclePropertyChangeMode::ON_CHANGE,
+                   VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::INT32);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySeatAirbagsDeployedConfig) {
+    verifyProperty(VehicleProperty::SEAT_AIRBAGS_DEPLOYED, VehiclePropertyAccess::READ,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::SEAT, VehiclePropertyType::INT32);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySeatBeltPretensionerDeployedConfig) {
+    verifyProperty(VehicleProperty::SEAT_BELT_PRETENSIONER_DEPLOYED, VehiclePropertyAccess::READ,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::SEAT, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyImpactDetectedConfig) {
+    verifyProperty(VehicleProperty::IMPACT_DETECTED, VehiclePropertyAccess::READ,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::GLOBAL, VehiclePropertyType::INT32);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyEvBatteryAverageTemperatureConfig) {
+    verifyProperty(VehicleProperty::EV_BATTERY_AVERAGE_TEMPERATURE, VehiclePropertyAccess::READ,
+                   VehiclePropertyChangeMode::CONTINUOUS, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::GLOBAL, VehiclePropertyType::FLOAT);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyLowSpeedCollisionWarningEnabledConfig) {
+    verifyProperty(VehicleProperty::LOW_SPEED_COLLISION_WARNING_ENABLED,
+                   VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
+                   VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyLowSpeedCollisionWarningStateConfig) {
+    verifyProperty(VehicleProperty::LOW_SPEED_COLLISION_WARNING_STATE, VehiclePropertyAccess::READ,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::GLOBAL, VehiclePropertyType::INT32);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyValetModeEnabledConfig) {
+    verifyProperty(VehicleProperty::VALET_MODE_ENABLED, VehiclePropertyAccess::READ_WRITE,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyElectronicStabilityControlEnabledConfig) {
+    verifyProperty(VehicleProperty::ELECTRONIC_STABILITY_CONTROL_ENABLED,
+                   VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
+                   VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyElectronicStabilityControlStateConfig) {
+    verifyProperty(VehicleProperty::ELECTRONIC_STABILITY_CONTROL_STATE, VehiclePropertyAccess::READ,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::GLOBAL, VehiclePropertyType::INT32);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyCrossTrafficMonitoringEnabledConfig) {
+    verifyProperty(VehicleProperty::CROSS_TRAFFIC_MONITORING_ENABLED,
+                   VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
+                   VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyCrossTrafficMonitoringWarningStateConfig) {
+    verifyProperty(VehicleProperty::CROSS_TRAFFIC_MONITORING_WARNING_STATE,
+                   VehiclePropertyAccess::READ, VehiclePropertyChangeMode::ON_CHANGE,
+                   VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::INT32);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyHeadUpDisplayEnabledConfig) {
+    verifyProperty(VehicleProperty::HEAD_UP_DISPLAY_ENABLED, VehiclePropertyAccess::READ_WRITE,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::SEAT, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyLowSpeedAutomaticEmergencyBrakingEnabledConfig) {
+    verifyProperty(VehicleProperty::LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_ENABLED,
+                   VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
+                   VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyLowSpeedAutomaticEmergencyBrakingStateConfig) {
+    verifyProperty(VehicleProperty::LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE,
+                   VehiclePropertyAccess::READ, VehiclePropertyChangeMode::ON_CHANGE,
+                   VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::INT32);
+}
+
 bool VtsHalAutomotiveVehicleTargetTest::checkIsSupported(int32_t propertyId) {
-  auto result = mVhalClient->getPropConfigs({propertyId});
-  return result.ok();
+    auto result = mVhalClient->getPropConfigs({propertyId});
+    return result.ok();
 }
 
 std::vector<ServiceDescriptor> getDescriptors() {
diff --git a/biometrics/common/aidl/Android.bp b/biometrics/common/aidl/Android.bp
index b41a937..8502a82 100644
--- a/biometrics/common/aidl/Android.bp
+++ b/biometrics/common/aidl/Android.bp
@@ -13,7 +13,7 @@
     srcs: [
         "android/hardware/biometrics/common/*.aidl",
     ],
-    frozen: true,
+    frozen: false,
     stability: "vintf",
     backend: {
         java: {
diff --git a/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/FoldState.aidl b/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/FoldState.aidl
new file mode 100644
index 0000000..06baf00
--- /dev/null
+++ b/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/FoldState.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.biometrics.common;
+/* @hide */
+@Backing(type="int") @VintfStability
+enum FoldState {
+  UNKNOWN,
+  HALF_OPENED,
+  FULLY_OPENED,
+  FULLY_CLOSED,
+}
diff --git a/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/OperationContext.aidl b/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/OperationContext.aidl
index 378017e..8d913c8 100644
--- a/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/OperationContext.aidl
+++ b/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/OperationContext.aidl
@@ -45,4 +45,6 @@
   android.hardware.biometrics.common.WakeReason wakeReason = android.hardware.biometrics.common.WakeReason.UNKNOWN;
   android.hardware.biometrics.common.DisplayState displayState = android.hardware.biometrics.common.DisplayState.UNKNOWN;
   @nullable android.hardware.biometrics.common.AuthenticateReason authenticateReason;
+  android.hardware.biometrics.common.FoldState foldState = android.hardware.biometrics.common.FoldState.UNKNOWN;
+  @nullable android.hardware.biometrics.common.OperationState operationState;
 }
diff --git a/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/OperationState.aidl b/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/OperationState.aidl
new file mode 100644
index 0000000..fca9525
--- /dev/null
+++ b/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/OperationState.aidl
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.biometrics.common;
+/* @hide */
+@VintfStability
+union OperationState {
+  android.hardware.biometrics.common.OperationState.FingerprintOperationState fingerprintOperationState;
+  android.hardware.biometrics.common.OperationState.FaceOperationState faceOperationState;
+  @VintfStability
+  parcelable FingerprintOperationState {
+    ParcelableHolder extension;
+    boolean isHardwareIgnoringTouches = false;
+  }
+  @VintfStability
+  parcelable FaceOperationState {
+    ParcelableHolder extension;
+  }
+}
diff --git a/biometrics/common/aidl/android/hardware/biometrics/common/FoldState.aidl b/biometrics/common/aidl/android/hardware/biometrics/common/FoldState.aidl
new file mode 100644
index 0000000..03e606a
--- /dev/null
+++ b/biometrics/common/aidl/android/hardware/biometrics/common/FoldState.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.biometrics.common;
+
+/**
+ * Fold/Unfold state during an operation.
+ *
+ * @hide
+ */
+@VintfStability
+@Backing(type="int")
+enum FoldState {
+    /** The fold state is unknown. */
+    UNKNOWN,
+
+    /** The fold state is half opened. */
+    HALF_OPENED,
+
+    /** The fold state is fully opened. */
+    FULLY_OPENED,
+
+    /** The fold state is fully closed. */
+    FULLY_CLOSED,
+}
diff --git a/biometrics/common/aidl/android/hardware/biometrics/common/OperationContext.aidl b/biometrics/common/aidl/android/hardware/biometrics/common/OperationContext.aidl
index f4191d7..5f9844f 100644
--- a/biometrics/common/aidl/android/hardware/biometrics/common/OperationContext.aidl
+++ b/biometrics/common/aidl/android/hardware/biometrics/common/OperationContext.aidl
@@ -18,7 +18,9 @@
 
 import android.hardware.biometrics.common.AuthenticateReason;
 import android.hardware.biometrics.common.DisplayState;
+import android.hardware.biometrics.common.FoldState;
 import android.hardware.biometrics.common.OperationReason;
+import android.hardware.biometrics.common.OperationState;
 import android.hardware.biometrics.common.WakeReason;
 
 /**
@@ -71,4 +73,10 @@
      * framework may choose to omit the reason at any time based on the device's policy.
      */
     @nullable AuthenticateReason authenticateReason;
+
+    /** The current fold/unfold state. */
+    FoldState foldState = FoldState.UNKNOWN;
+
+    /** An associated operation state for this operation. */
+    @nullable OperationState operationState;
 }
diff --git a/biometrics/common/aidl/android/hardware/biometrics/common/OperationState.aidl b/biometrics/common/aidl/android/hardware/biometrics/common/OperationState.aidl
new file mode 100644
index 0000000..40cf589
--- /dev/null
+++ b/biometrics/common/aidl/android/hardware/biometrics/common/OperationState.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.biometrics.common;
+
+/**
+ * Additional state associated with an operation
+ *
+ * @hide
+ */
+@VintfStability
+union OperationState {
+    /** Operation state related to fingerprint*/
+    @VintfStability
+    parcelable FingerprintOperationState {
+        ParcelableHolder extension;
+
+        /** Flag indicating if the HAL should ignore touches on the fingerprint sensor */
+        boolean isHardwareIgnoringTouches = false;
+    }
+
+    /** Operation state related to face*/
+    @VintfStability
+    parcelable FaceOperationState {
+        ParcelableHolder extension;
+    }
+
+    OperationState.FingerprintOperationState fingerprintOperationState;
+    OperationState.FaceOperationState faceOperationState;
+}
diff --git a/biometrics/common/util/Android.bp b/biometrics/common/util/Android.bp
index b990812..599c491 100644
--- a/biometrics/common/util/Android.bp
+++ b/biometrics/common/util/Android.bp
@@ -13,6 +13,6 @@
     shared_libs: [
         "libbase",
         "libbinder_ndk",
-        "android.hardware.biometrics.common-V3-ndk",
+        "android.hardware.biometrics.common-V4-ndk",
     ],
 }
diff --git a/biometrics/common/util/include/util/Util.h b/biometrics/common/util/include/util/Util.h
index da19dc6..efd66bc 100644
--- a/biometrics/common/util/include/util/Util.h
+++ b/biometrics/common/util/include/util/Util.h
@@ -23,6 +23,9 @@
 #include <thread>
 #include <vector>
 
+#include <android-base/parseint.h>
+using ::android::base::ParseInt;
+
 namespace aidl::android::hardware::biometrics {
 
 #define SLEEP_MS(x) \
@@ -64,6 +67,87 @@
                 std::sregex_token_iterator());
         return parts;
     }
+
+    // Returns a vector of integers for the string separated by comma,
+    // Empty vector is returned if there is any parsing error
+    static std::vector<int32_t> 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 + " seq:" + seq;
+                res.clear();
+                break;
+            }
+        }
+
+        return res;
+    }
+
+    // Parses a single enrollment stage string in the format of
+    //     enroll_stage_spec: <duration>[-acquiredInfos]
+    //                                      duration: integerInMs
+    //                                      acquiredInfos: [info1,info2,...]
+    //
+    // Returns false if there is parsing error
+    //
+    static bool parseEnrollmentCaptureSingle(const std::string& str,
+                                             std::vector<std::vector<int32_t>>& res) {
+        std::vector<int32_t> defaultAcquiredInfo = {1};
+        bool aborted = true;
+
+        do {
+            std::smatch sms;
+            // Parses strings like "1000-[5,1]" or "500"
+            std::regex ex("((\\d+)(-\\[([\\d|,]+)\\])?)");
+            if (!regex_match(str.cbegin(), str.cend(), sms, ex)) break;
+            int32_t duration;
+            if (!ParseInt(sms.str(2), &duration)) break;
+            res.push_back({duration});
+            if (!sms.str(4).empty()) {
+                auto acqv = parseIntSequence(sms.str(4));
+                if (acqv.empty()) break;
+                res.push_back(acqv);
+            } else
+                res.push_back(defaultAcquiredInfo);
+            aborted = false;
+        } while (0);
+
+        return !aborted;
+    }
+
+    // Parses enrollment string consisting of one or more stages in the formst of
+    //  <enroll_stage_spec>[,enroll_stage_spec,...]
+    // Empty vector is returned in case of parsing error
+    static std::vector<std::vector<int32_t>> parseEnrollmentCapture(const std::string& str) {
+        std::vector<std::vector<int32_t>> res;
+
+        std::string s(str);
+        s.erase(std::remove_if(s.begin(), s.end(), ::isspace), s.end());
+        bool aborted = false;
+        std::smatch sms;
+        // Parses strings like "1000-[5,1],500,800-[6,5,1]"
+        //                               -------------- ----- ---------------
+        //  into parts:                       A       B       C
+        while (regex_search(s, sms, std::regex("^(,)?(\\d+(-\\[[\\d|,]+\\])?)"))) {
+            if (!parseEnrollmentCaptureSingle(sms.str(2), res)) {
+                aborted = true;
+                break;
+            }
+            s = sms.suffix();
+        }
+        if (aborted || s.length() != 0) {
+            res.clear();
+            LOG(ERROR) << "Failed to parse enrollment captures:" + str;
+        }
+
+        return res;
+    }
 };
 
 }  // namespace aidl::android::hardware::biometrics
diff --git a/biometrics/face/aidl/Android.bp b/biometrics/face/aidl/Android.bp
index 79df9c6..7adf402 100644
--- a/biometrics/face/aidl/Android.bp
+++ b/biometrics/face/aidl/Android.bp
@@ -14,10 +14,13 @@
         "android/hardware/biometrics/face/**/*.aidl",
     ],
     imports: [
-        "android.hardware.biometrics.common-V3",
+        "android.hardware.biometrics.common-V4",
         "android.hardware.common-V2",
         "android.hardware.keymaster-V4",
     ],
+    include_dirs: [
+        "frameworks/native/aidl/gui",
+    ],
     stability: "vintf",
     backend: {
         java: {
@@ -26,6 +29,11 @@
         cpp: {
             enabled: false,
         },
+        ndk: {
+            additional_shared_libraries: [
+                "libnativewindow",
+            ],
+        },
     },
     versions_with_info: [
         {
@@ -52,6 +60,14 @@
                 "android.hardware.keymaster-V4",
             ],
         },
+        {
+            version: "4",
+            imports: [
+                "android.hardware.biometrics.common-V4",
+                "android.hardware.common-V2",
+                "android.hardware.keymaster-V4",
+            ],
+        },
 
     ],
     frozen: true,
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/.hash b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/.hash
new file mode 100644
index 0000000..e9a5aa3
--- /dev/null
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/.hash
@@ -0,0 +1 @@
+c43fbb9be4a662cc9ace640dba21cccdb84c6c21
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/AcquiredInfo.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/AcquiredInfo.aidl
new file mode 100644
index 0000000..1420cdc
--- /dev/null
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/AcquiredInfo.aidl
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.biometrics.face;
+/* @hide */
+@Backing(type="byte") @VintfStability
+enum AcquiredInfo {
+  UNKNOWN,
+  GOOD,
+  INSUFFICIENT,
+  TOO_BRIGHT,
+  TOO_DARK,
+  TOO_CLOSE,
+  TOO_FAR,
+  FACE_TOO_HIGH,
+  FACE_TOO_LOW,
+  FACE_TOO_RIGHT,
+  FACE_TOO_LEFT,
+  POOR_GAZE,
+  NOT_DETECTED,
+  TOO_MUCH_MOTION,
+  RECALIBRATE,
+  TOO_DIFFERENT,
+  TOO_SIMILAR,
+  PAN_TOO_EXTREME,
+  TILT_TOO_EXTREME,
+  ROLL_TOO_EXTREME,
+  FACE_OBSCURED,
+  START,
+  SENSOR_DIRTY,
+  VENDOR,
+  FIRST_FRAME_RECEIVED,
+  DARK_GLASSES_DETECTED,
+  MOUTH_COVERING_DETECTED,
+}
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/AuthenticationFrame.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/AuthenticationFrame.aidl
new file mode 100644
index 0000000..bbaca12
--- /dev/null
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/AuthenticationFrame.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.biometrics.face;
+/* @hide */
+@VintfStability
+parcelable AuthenticationFrame {
+  android.hardware.biometrics.face.BaseFrame data;
+}
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/BaseFrame.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/BaseFrame.aidl
new file mode 100644
index 0000000..1dd0a9c
--- /dev/null
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/BaseFrame.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.biometrics.face;
+/* @hide */
+@VintfStability
+parcelable BaseFrame {
+  android.hardware.biometrics.face.AcquiredInfo acquiredInfo = android.hardware.biometrics.face.AcquiredInfo.UNKNOWN;
+  int vendorCode;
+  float pan;
+  float tilt;
+  float distance;
+  boolean isCancellable;
+}
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/Cell.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/Cell.aidl
new file mode 100644
index 0000000..d423a69
--- /dev/null
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/Cell.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.biometrics.face;
+/* @hide */
+@VintfStability
+parcelable Cell {
+  int x;
+  int y;
+  int z;
+}
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/EnrollmentFrame.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/EnrollmentFrame.aidl
new file mode 100644
index 0000000..90be5d0
--- /dev/null
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/EnrollmentFrame.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.biometrics.face;
+/* @hide */
+@VintfStability
+parcelable EnrollmentFrame {
+  @nullable android.hardware.biometrics.face.Cell cell;
+  android.hardware.biometrics.face.EnrollmentStage stage = android.hardware.biometrics.face.EnrollmentStage.UNKNOWN;
+  android.hardware.biometrics.face.BaseFrame data;
+}
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/EnrollmentStage.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/EnrollmentStage.aidl
new file mode 100644
index 0000000..89b06ca
--- /dev/null
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/EnrollmentStage.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.biometrics.face;
+/* @hide */
+@Backing(type="byte") @VintfStability
+enum EnrollmentStage {
+  UNKNOWN,
+  FIRST_FRAME_RECEIVED,
+  WAITING_FOR_CENTERING,
+  HOLD_STILL_IN_CENTER,
+  ENROLLING_MOVEMENT_1,
+  ENROLLING_MOVEMENT_2,
+  ENROLLMENT_FINISHED,
+}
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/EnrollmentStageConfig.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/EnrollmentStageConfig.aidl
new file mode 100644
index 0000000..ee1c01a
--- /dev/null
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/EnrollmentStageConfig.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.biometrics.face;
+/* @hide */
+@VintfStability
+parcelable EnrollmentStageConfig {
+  android.hardware.biometrics.face.EnrollmentStage stage = android.hardware.biometrics.face.EnrollmentStage.UNKNOWN;
+  List<android.hardware.biometrics.face.Cell> cells;
+}
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/EnrollmentType.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/EnrollmentType.aidl
new file mode 100644
index 0000000..180ea5d
--- /dev/null
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/EnrollmentType.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.biometrics.face;
+/* @hide */
+@Backing(type="byte") @VintfStability
+enum EnrollmentType {
+  DEFAULT,
+  ACCESSIBILITY,
+}
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/Error.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/Error.aidl
new file mode 100644
index 0000000..5761e31
--- /dev/null
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/Error.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.biometrics.face;
+/* @hide */
+@Backing(type="byte") @VintfStability
+enum Error {
+  UNKNOWN,
+  HW_UNAVAILABLE,
+  UNABLE_TO_PROCESS,
+  TIMEOUT,
+  NO_SPACE,
+  CANCELED,
+  UNABLE_TO_REMOVE,
+  VENDOR,
+  REENROLL_REQUIRED,
+}
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/FaceEnrollOptions.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/FaceEnrollOptions.aidl
new file mode 100644
index 0000000..c961531
--- /dev/null
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/FaceEnrollOptions.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.biometrics.face;
+/* @hide */
+@VintfStability
+parcelable FaceEnrollOptions {
+  android.hardware.keymaster.HardwareAuthToken hardwareAuthToken;
+  android.hardware.biometrics.face.EnrollmentType enrollmentType;
+  android.hardware.biometrics.face.Feature[] features;
+  /**
+   * @deprecated use {@link surfacePreview} instead {@link NativeHandle} a handle used to render content from the face HAL. Note that only one of [{@link surfacePreview}, {@link nativeHandlePreview}] should be set at one time.
+   */
+  @nullable android.hardware.common.NativeHandle nativeHandlePreview;
+  @nullable android.view.Surface surfacePreview;
+  @nullable android.hardware.biometrics.common.OperationContext context;
+}
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/FaceSensorType.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/FaceSensorType.aidl
new file mode 100644
index 0000000..ec03733
--- /dev/null
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/FaceSensorType.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.biometrics.face;
+/* @hide */
+@Backing(type="byte") @VintfStability
+enum FaceSensorType {
+  UNKNOWN,
+  RGB,
+  IR,
+}
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/Feature.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/Feature.aidl
new file mode 100644
index 0000000..3337df8
--- /dev/null
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/Feature.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.biometrics.face;
+/* @hide */
+@Backing(type="byte") @VintfStability
+enum Feature {
+  REQUIRE_ATTENTION,
+  REQUIRE_DIVERSE_POSES,
+  DEBUG,
+}
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/IFace.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/IFace.aidl
new file mode 100644
index 0000000..1ae76de
--- /dev/null
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/IFace.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.biometrics.face;
+/* @hide */
+@VintfStability
+interface IFace {
+  android.hardware.biometrics.face.SensorProps[] getSensorProps();
+  android.hardware.biometrics.face.ISession createSession(in int sensorId, in int userId, in android.hardware.biometrics.face.ISessionCallback cb);
+}
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/ISession.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/ISession.aidl
new file mode 100644
index 0000000..b655d5f
--- /dev/null
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/ISession.aidl
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.biometrics.face;
+/* @hide */
+@VintfStability
+interface ISession {
+  void generateChallenge();
+  void revokeChallenge(in long challenge);
+  android.hardware.biometrics.face.EnrollmentStageConfig[] getEnrollmentConfig(in android.hardware.biometrics.face.EnrollmentType enrollmentType);
+  /**
+   * @deprecated use {@link enrollWithOptions} instead.
+   */
+  android.hardware.biometrics.common.ICancellationSignal enroll(in android.hardware.keymaster.HardwareAuthToken hat, in android.hardware.biometrics.face.EnrollmentType type, in android.hardware.biometrics.face.Feature[] features, in @nullable android.hardware.common.NativeHandle previewSurface);
+  android.hardware.biometrics.common.ICancellationSignal authenticate(in long operationId);
+  android.hardware.biometrics.common.ICancellationSignal detectInteraction();
+  void enumerateEnrollments();
+  void removeEnrollments(in int[] enrollmentIds);
+  void getFeatures();
+  void setFeature(in android.hardware.keymaster.HardwareAuthToken hat, in android.hardware.biometrics.face.Feature feature, boolean enabled);
+  void getAuthenticatorId();
+  void invalidateAuthenticatorId();
+  void resetLockout(in android.hardware.keymaster.HardwareAuthToken hat);
+  void close();
+  android.hardware.biometrics.common.ICancellationSignal authenticateWithContext(in long operationId, in android.hardware.biometrics.common.OperationContext context);
+  /**
+   * @deprecated use {@link enrollWithOptions} instead.
+   */
+  android.hardware.biometrics.common.ICancellationSignal enrollWithContext(in android.hardware.keymaster.HardwareAuthToken hat, in android.hardware.biometrics.face.EnrollmentType type, in android.hardware.biometrics.face.Feature[] features, in @nullable android.hardware.common.NativeHandle previewSurface, in android.hardware.biometrics.common.OperationContext context);
+  android.hardware.biometrics.common.ICancellationSignal detectInteractionWithContext(in android.hardware.biometrics.common.OperationContext context);
+  void onContextChanged(in android.hardware.biometrics.common.OperationContext context);
+  android.hardware.biometrics.common.ICancellationSignal enrollWithOptions(in android.hardware.biometrics.face.FaceEnrollOptions options);
+}
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/ISessionCallback.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/ISessionCallback.aidl
new file mode 100644
index 0000000..c6c035b
--- /dev/null
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/ISessionCallback.aidl
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.biometrics.face;
+/* @hide */
+@VintfStability
+interface ISessionCallback {
+  void onChallengeGenerated(in long challenge);
+  void onChallengeRevoked(in long challenge);
+  void onAuthenticationFrame(in android.hardware.biometrics.face.AuthenticationFrame frame);
+  void onEnrollmentFrame(in android.hardware.biometrics.face.EnrollmentFrame frame);
+  void onError(in android.hardware.biometrics.face.Error error, in int vendorCode);
+  void onEnrollmentProgress(in int enrollmentId, int remaining);
+  void onAuthenticationSucceeded(in int enrollmentId, in android.hardware.keymaster.HardwareAuthToken hat);
+  void onAuthenticationFailed();
+  void onLockoutTimed(in long durationMillis);
+  void onLockoutPermanent();
+  void onLockoutCleared();
+  void onInteractionDetected();
+  void onEnrollmentsEnumerated(in int[] enrollmentIds);
+  void onFeaturesRetrieved(in android.hardware.biometrics.face.Feature[] features);
+  void onFeatureSet(android.hardware.biometrics.face.Feature feature);
+  void onEnrollmentsRemoved(in int[] enrollmentIds);
+  void onAuthenticatorIdRetrieved(in long authenticatorId);
+  void onAuthenticatorIdInvalidated(in long newAuthenticatorId);
+  void onSessionClosed();
+}
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/SensorProps.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/SensorProps.aidl
new file mode 100644
index 0000000..918332b
--- /dev/null
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/4/android/hardware/biometrics/face/SensorProps.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.biometrics.face;
+/* @hide */
+@VintfStability
+parcelable SensorProps {
+  android.hardware.biometrics.common.CommonProps commonProps;
+  android.hardware.biometrics.face.FaceSensorType sensorType = android.hardware.biometrics.face.FaceSensorType.UNKNOWN;
+  boolean halControlsPreview;
+  int previewDisplayId;
+  int enrollPreviewWidth;
+  int enrollPreviewHeight;
+  float enrollTranslationX;
+  float enrollTranslationY;
+  float enrollPreviewScale;
+  boolean supportsDetectInteraction;
+}
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/AcquiredInfo.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/AcquiredInfo.aidl
index eaa43f3..1420cdc 100644
--- a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/AcquiredInfo.aidl
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/AcquiredInfo.aidl
@@ -32,33 +32,34 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.biometrics.face;
+/* @hide */
 @Backing(type="byte") @VintfStability
 enum AcquiredInfo {
-  UNKNOWN = 0,
-  GOOD = 1,
-  INSUFFICIENT = 2,
-  TOO_BRIGHT = 3,
-  TOO_DARK = 4,
-  TOO_CLOSE = 5,
-  TOO_FAR = 6,
-  FACE_TOO_HIGH = 7,
-  FACE_TOO_LOW = 8,
-  FACE_TOO_RIGHT = 9,
-  FACE_TOO_LEFT = 10,
-  POOR_GAZE = 11,
-  NOT_DETECTED = 12,
-  TOO_MUCH_MOTION = 13,
-  RECALIBRATE = 14,
-  TOO_DIFFERENT = 15,
-  TOO_SIMILAR = 16,
-  PAN_TOO_EXTREME = 17,
-  TILT_TOO_EXTREME = 18,
-  ROLL_TOO_EXTREME = 19,
-  FACE_OBSCURED = 20,
-  START = 21,
-  SENSOR_DIRTY = 22,
-  VENDOR = 23,
-  FIRST_FRAME_RECEIVED = 24,
-  DARK_GLASSES_DETECTED = 25,
-  MOUTH_COVERING_DETECTED = 26,
+  UNKNOWN,
+  GOOD,
+  INSUFFICIENT,
+  TOO_BRIGHT,
+  TOO_DARK,
+  TOO_CLOSE,
+  TOO_FAR,
+  FACE_TOO_HIGH,
+  FACE_TOO_LOW,
+  FACE_TOO_RIGHT,
+  FACE_TOO_LEFT,
+  POOR_GAZE,
+  NOT_DETECTED,
+  TOO_MUCH_MOTION,
+  RECALIBRATE,
+  TOO_DIFFERENT,
+  TOO_SIMILAR,
+  PAN_TOO_EXTREME,
+  TILT_TOO_EXTREME,
+  ROLL_TOO_EXTREME,
+  FACE_OBSCURED,
+  START,
+  SENSOR_DIRTY,
+  VENDOR,
+  FIRST_FRAME_RECEIVED,
+  DARK_GLASSES_DETECTED,
+  MOUTH_COVERING_DETECTED,
 }
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/AuthenticationFrame.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/AuthenticationFrame.aidl
index 20bc767..bbaca12 100644
--- a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/AuthenticationFrame.aidl
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/AuthenticationFrame.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.biometrics.face;
+/* @hide */
 @VintfStability
 parcelable AuthenticationFrame {
   android.hardware.biometrics.face.BaseFrame data;
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/BaseFrame.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/BaseFrame.aidl
index 67b5cf4..1dd0a9c 100644
--- a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/BaseFrame.aidl
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/BaseFrame.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.biometrics.face;
+/* @hide */
 @VintfStability
 parcelable BaseFrame {
   android.hardware.biometrics.face.AcquiredInfo acquiredInfo = android.hardware.biometrics.face.AcquiredInfo.UNKNOWN;
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/Cell.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/Cell.aidl
index 6be8c8e..d423a69 100644
--- a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/Cell.aidl
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/Cell.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.biometrics.face;
+/* @hide */
 @VintfStability
 parcelable Cell {
   int x;
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/EnrollmentFrame.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/EnrollmentFrame.aidl
index 0ea10d6..90be5d0 100644
--- a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/EnrollmentFrame.aidl
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/EnrollmentFrame.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.biometrics.face;
+/* @hide */
 @VintfStability
 parcelable EnrollmentFrame {
   @nullable android.hardware.biometrics.face.Cell cell;
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/EnrollmentStage.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/EnrollmentStage.aidl
index ce5679a..89b06ca 100644
--- a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/EnrollmentStage.aidl
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/EnrollmentStage.aidl
@@ -32,13 +32,14 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.biometrics.face;
+/* @hide */
 @Backing(type="byte") @VintfStability
 enum EnrollmentStage {
-  UNKNOWN = 0,
-  FIRST_FRAME_RECEIVED = 1,
-  WAITING_FOR_CENTERING = 2,
-  HOLD_STILL_IN_CENTER = 3,
-  ENROLLING_MOVEMENT_1 = 4,
-  ENROLLING_MOVEMENT_2 = 5,
-  ENROLLMENT_FINISHED = 6,
+  UNKNOWN,
+  FIRST_FRAME_RECEIVED,
+  WAITING_FOR_CENTERING,
+  HOLD_STILL_IN_CENTER,
+  ENROLLING_MOVEMENT_1,
+  ENROLLING_MOVEMENT_2,
+  ENROLLMENT_FINISHED,
 }
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/EnrollmentStageConfig.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/EnrollmentStageConfig.aidl
index 48db2cf..ee1c01a 100644
--- a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/EnrollmentStageConfig.aidl
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/EnrollmentStageConfig.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.biometrics.face;
+/* @hide */
 @VintfStability
 parcelable EnrollmentStageConfig {
   android.hardware.biometrics.face.EnrollmentStage stage = android.hardware.biometrics.face.EnrollmentStage.UNKNOWN;
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/EnrollmentType.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/EnrollmentType.aidl
index 8e99ad6..180ea5d 100644
--- a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/EnrollmentType.aidl
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/EnrollmentType.aidl
@@ -32,8 +32,9 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.biometrics.face;
+/* @hide */
 @Backing(type="byte") @VintfStability
 enum EnrollmentType {
-  DEFAULT = 0,
-  ACCESSIBILITY = 1,
+  DEFAULT,
+  ACCESSIBILITY,
 }
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/Error.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/Error.aidl
index 1a21661..5761e31 100644
--- a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/Error.aidl
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/Error.aidl
@@ -32,15 +32,16 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.biometrics.face;
+/* @hide */
 @Backing(type="byte") @VintfStability
 enum Error {
-  UNKNOWN = 0,
-  HW_UNAVAILABLE = 1,
-  UNABLE_TO_PROCESS = 2,
-  TIMEOUT = 3,
-  NO_SPACE = 4,
-  CANCELED = 5,
-  UNABLE_TO_REMOVE = 6,
-  VENDOR = 7,
-  REENROLL_REQUIRED = 8,
+  UNKNOWN,
+  HW_UNAVAILABLE,
+  UNABLE_TO_PROCESS,
+  TIMEOUT,
+  NO_SPACE,
+  CANCELED,
+  UNABLE_TO_REMOVE,
+  VENDOR,
+  REENROLL_REQUIRED,
 }
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/FaceEnrollOptions.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/FaceEnrollOptions.aidl
new file mode 100644
index 0000000..c961531
--- /dev/null
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/FaceEnrollOptions.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.biometrics.face;
+/* @hide */
+@VintfStability
+parcelable FaceEnrollOptions {
+  android.hardware.keymaster.HardwareAuthToken hardwareAuthToken;
+  android.hardware.biometrics.face.EnrollmentType enrollmentType;
+  android.hardware.biometrics.face.Feature[] features;
+  /**
+   * @deprecated use {@link surfacePreview} instead {@link NativeHandle} a handle used to render content from the face HAL. Note that only one of [{@link surfacePreview}, {@link nativeHandlePreview}] should be set at one time.
+   */
+  @nullable android.hardware.common.NativeHandle nativeHandlePreview;
+  @nullable android.view.Surface surfacePreview;
+  @nullable android.hardware.biometrics.common.OperationContext context;
+}
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/FaceSensorType.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/FaceSensorType.aidl
index a215b99..ec03733 100644
--- a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/FaceSensorType.aidl
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/FaceSensorType.aidl
@@ -32,9 +32,10 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.biometrics.face;
+/* @hide */
 @Backing(type="byte") @VintfStability
 enum FaceSensorType {
-  UNKNOWN = 0,
-  RGB = 1,
-  IR = 2,
+  UNKNOWN,
+  RGB,
+  IR,
 }
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/Feature.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/Feature.aidl
index 1875b97..3337df8 100644
--- a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/Feature.aidl
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/Feature.aidl
@@ -32,9 +32,10 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.biometrics.face;
+/* @hide */
 @Backing(type="byte") @VintfStability
 enum Feature {
-  REQUIRE_ATTENTION = 0,
-  REQUIRE_DIVERSE_POSES = 1,
-  DEBUG = 2,
+  REQUIRE_ATTENTION,
+  REQUIRE_DIVERSE_POSES,
+  DEBUG,
 }
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/IFace.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/IFace.aidl
index fc4a4d0..1ae76de 100644
--- a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/IFace.aidl
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/IFace.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.biometrics.face;
+/* @hide */
 @VintfStability
 interface IFace {
   android.hardware.biometrics.face.SensorProps[] getSensorProps();
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/ISession.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/ISession.aidl
index 3665534..b655d5f 100644
--- a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/ISession.aidl
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/ISession.aidl
@@ -32,11 +32,15 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.biometrics.face;
+/* @hide */
 @VintfStability
 interface ISession {
   void generateChallenge();
   void revokeChallenge(in long challenge);
   android.hardware.biometrics.face.EnrollmentStageConfig[] getEnrollmentConfig(in android.hardware.biometrics.face.EnrollmentType enrollmentType);
+  /**
+   * @deprecated use {@link enrollWithOptions} instead.
+   */
   android.hardware.biometrics.common.ICancellationSignal enroll(in android.hardware.keymaster.HardwareAuthToken hat, in android.hardware.biometrics.face.EnrollmentType type, in android.hardware.biometrics.face.Feature[] features, in @nullable android.hardware.common.NativeHandle previewSurface);
   android.hardware.biometrics.common.ICancellationSignal authenticate(in long operationId);
   android.hardware.biometrics.common.ICancellationSignal detectInteraction();
@@ -49,7 +53,11 @@
   void resetLockout(in android.hardware.keymaster.HardwareAuthToken hat);
   void close();
   android.hardware.biometrics.common.ICancellationSignal authenticateWithContext(in long operationId, in android.hardware.biometrics.common.OperationContext context);
+  /**
+   * @deprecated use {@link enrollWithOptions} instead.
+   */
   android.hardware.biometrics.common.ICancellationSignal enrollWithContext(in android.hardware.keymaster.HardwareAuthToken hat, in android.hardware.biometrics.face.EnrollmentType type, in android.hardware.biometrics.face.Feature[] features, in @nullable android.hardware.common.NativeHandle previewSurface, in android.hardware.biometrics.common.OperationContext context);
   android.hardware.biometrics.common.ICancellationSignal detectInteractionWithContext(in android.hardware.biometrics.common.OperationContext context);
   void onContextChanged(in android.hardware.biometrics.common.OperationContext context);
+  android.hardware.biometrics.common.ICancellationSignal enrollWithOptions(in android.hardware.biometrics.face.FaceEnrollOptions options);
 }
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/ISessionCallback.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/ISessionCallback.aidl
index bbace29..c6c035b 100644
--- a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/ISessionCallback.aidl
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/ISessionCallback.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.biometrics.face;
+/* @hide */
 @VintfStability
 interface ISessionCallback {
   void onChallengeGenerated(in long challenge);
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/SensorProps.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/SensorProps.aidl
index 8b3c51b..918332b 100644
--- a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/SensorProps.aidl
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/SensorProps.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.biometrics.face;
+/* @hide */
 @VintfStability
 parcelable SensorProps {
   android.hardware.biometrics.common.CommonProps commonProps;
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/AcquiredInfo.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/AcquiredInfo.aidl
index cf68421..48b3e8c 100644
--- a/biometrics/face/aidl/android/hardware/biometrics/face/AcquiredInfo.aidl
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/AcquiredInfo.aidl
@@ -15,7 +15,9 @@
  */
 
 package android.hardware.biometrics.face;
-
+/**
+ * @hide
+ */
 @VintfStability
 @Backing(type="byte")
 enum AcquiredInfo {
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/AuthenticationFrame.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/AuthenticationFrame.aidl
index be61a20..08ef973 100644
--- a/biometrics/face/aidl/android/hardware/biometrics/face/AuthenticationFrame.aidl
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/AuthenticationFrame.aidl
@@ -20,6 +20,7 @@
 
 /**
  * Describes an individual frame captured during authentication.
+ * @hide
  */
 @VintfStability
 parcelable AuthenticationFrame {
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/BaseFrame.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/BaseFrame.aidl
index 58ad01a..e407d91 100644
--- a/biometrics/face/aidl/android/hardware/biometrics/face/BaseFrame.aidl
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/BaseFrame.aidl
@@ -22,6 +22,7 @@
  * Metadata of an individual frame. Can be used by the framework to provide user feedback.
  * This parcelable is part of AuthenticationFrame and EnrollmentFrame, and shouldn't be used
  * independently of those parcelables.
+ * @hide
  */
 @VintfStability
 parcelable BaseFrame {
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/Cell.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/Cell.aidl
index 77f33b9..8960d57 100644
--- a/biometrics/face/aidl/android/hardware/biometrics/face/Cell.aidl
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/Cell.aidl
@@ -18,6 +18,7 @@
 
 /**
  * Coordinates of an enrollment UI cell in a vendor-defined coordinate system.
+ * @hide
  */
 @VintfStability
 parcelable Cell {
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/EnrollmentFrame.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/EnrollmentFrame.aidl
index ecb0e79..15f019c 100644
--- a/biometrics/face/aidl/android/hardware/biometrics/face/EnrollmentFrame.aidl
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/EnrollmentFrame.aidl
@@ -22,6 +22,7 @@
 
 /**
  * Describes an individual frame captured during enrollment.
+ * @hide
  */
 @VintfStability
 parcelable EnrollmentFrame {
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/EnrollmentStage.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/EnrollmentStage.aidl
index 5974838..1a3c029 100644
--- a/biometrics/face/aidl/android/hardware/biometrics/face/EnrollmentStage.aidl
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/EnrollmentStage.aidl
@@ -18,6 +18,7 @@
 
 /**
  * Enrollment stages that can be mapped to the enrollment UI actions in the framework.
+ * @hide
  */
 @VintfStability
 @Backing(type="byte")
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/EnrollmentStageConfig.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/EnrollmentStageConfig.aidl
index a8fa9ab..362d752 100644
--- a/biometrics/face/aidl/android/hardware/biometrics/face/EnrollmentStageConfig.aidl
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/EnrollmentStageConfig.aidl
@@ -19,6 +19,9 @@
 import android.hardware.biometrics.face.Cell;
 import android.hardware.biometrics.face.EnrollmentStage;
 
+/**
+ * @hide
+ */
 @VintfStability
 parcelable EnrollmentStageConfig {
     /**
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/EnrollmentType.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/EnrollmentType.aidl
index c960933..5d92087 100644
--- a/biometrics/face/aidl/android/hardware/biometrics/face/EnrollmentType.aidl
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/EnrollmentType.aidl
@@ -16,6 +16,9 @@
 
 package android.hardware.biometrics.face;
 
+/**
+ * @hide
+ */
 @VintfStability
 @Backing(type="byte")
 enum EnrollmentType {
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/Error.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/Error.aidl
index e99415a..77d4717 100644
--- a/biometrics/face/aidl/android/hardware/biometrics/face/Error.aidl
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/Error.aidl
@@ -15,7 +15,9 @@
  */
 
 package android.hardware.biometrics.face;
-
+/**
+ * @hide
+ */
 @VintfStability
 @Backing(type="byte")
 enum Error {
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/FaceEnrollOptions.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/FaceEnrollOptions.aidl
new file mode 100644
index 0000000..c57fb55
--- /dev/null
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/FaceEnrollOptions.aidl
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.biometrics.face;
+
+import android.hardware.biometrics.common.OperationContext;
+import android.hardware.biometrics.face.EnrollmentStageConfig;
+import android.hardware.biometrics.face.EnrollmentType;
+import android.hardware.biometrics.face.Feature;
+import android.hardware.common.NativeHandle;
+import android.hardware.keymaster.HardwareAuthToken;
+import android.view.Surface;
+
+/**
+ * Enroll options used to pass information to the HAL when requesting an enroll operation.
+ * @hide
+ */
+@VintfStability
+parcelable FaceEnrollOptions {
+    /**
+     * See {@link HardwareAuthToken}.
+     */
+    HardwareAuthToken hardwareAuthToken;
+
+    /**
+     * See {@link EnrollmentType}
+     */
+    EnrollmentType enrollmentType;
+
+    /**
+     * See {@link Feature}
+     */
+    Feature[] features;
+
+    /**
+     * @deprecated use {@link surfacePreview} instead
+     *
+     * {@link NativeHandle} a handle used to render content from the face HAL.
+     *
+     * Note that only one of [{@link surfacePreview}, {@link nativeHandlePreview}]
+     * should be set at one time.
+     */
+    @nullable NativeHandle nativeHandlePreview;
+
+    /**
+     * {@link Surface} a surface used to render content from the face HAL.
+     *
+     * Note that only one of [{@link surfacePreview}, {@link nativeHandlePreview}]
+     * should be set at one time.
+     */
+    @nullable Surface surfacePreview;
+
+    /**
+     * See {@link OperationContext}
+     */
+    @nullable OperationContext context;
+}
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/FaceSensorType.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/FaceSensorType.aidl
index a5ed2e8..bf315a5 100644
--- a/biometrics/face/aidl/android/hardware/biometrics/face/FaceSensorType.aidl
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/FaceSensorType.aidl
@@ -16,6 +16,9 @@
 
 package android.hardware.biometrics.face;
 
+/**
+ * @hide
+ */
 @VintfStability
 @Backing(type="byte")
 enum FaceSensorType {
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/Feature.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/Feature.aidl
index bff1a02..9cbab55 100644
--- a/biometrics/face/aidl/android/hardware/biometrics/face/Feature.aidl
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/Feature.aidl
@@ -16,6 +16,9 @@
 
 package android.hardware.biometrics.face;
 
+/**
+ * @hide
+ */
 @VintfStability
 @Backing(type="byte")
 enum Feature {
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/IFace.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/IFace.aidl
index 65c589f..0ead435 100644
--- a/biometrics/face/aidl/android/hardware/biometrics/face/IFace.aidl
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/IFace.aidl
@@ -20,6 +20,9 @@
 import android.hardware.biometrics.face.ISessionCallback;
 import android.hardware.biometrics.face.SensorProps;
 
+/**
+ * @hide
+ */
 @VintfStability
 interface IFace {
     /**
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl
index 2be76cb..26cb361 100644
--- a/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl
@@ -20,6 +20,7 @@
 import android.hardware.biometrics.common.OperationContext;
 import android.hardware.biometrics.face.EnrollmentStageConfig;
 import android.hardware.biometrics.face.EnrollmentType;
+import android.hardware.biometrics.face.FaceEnrollOptions;
 import android.hardware.biometrics.face.Feature;
 import android.hardware.common.NativeHandle;
 import android.hardware.keymaster.HardwareAuthToken;
@@ -41,6 +42,7 @@
  * ISession only supports execution of one operation at a time, regardless of whether it's
  * cancellable or not. The framework must wait for a corresponding callback indicating the end of
  * the current operation before a new operation can be started.
+ * @hide
  */
 
 @VintfStability
@@ -115,44 +117,7 @@
     EnrollmentStageConfig[] getEnrollmentConfig(in EnrollmentType enrollmentType);
 
     /**
-     * enroll:
-     *
-     * A request to add a face enrollment.
-     *
-     * At any point during enrollment, if a non-recoverable error occurs, the HAL must notify the
-     * framework via ISessionCallback#onError with the applicable enrollment-specific error.
-     *
-     * Before capturing face data, the HAL must first verify the authenticity and integrity of the
-     * provided HardwareAuthToken. In addition, it must check that the challenge within the provided
-     * HardwareAuthToken is valid. See ISession#generateChallenge. If any of the above checks fail,
-     * the framework must be notified using ISessionCallback#onError with Error::UNABLE_TO_PROCESS.
-     *
-     * During enrollment, the HAL may notify the framework via ISessionCallback#onAcquired with
-     * messages that may be used to guide the user. This callback can be invoked multiple times if
-     * necessary. Similarly, the framework may be notified of enrollment progress changes via
-     * ISessionCallback#onEnrollmentProgress. Once the framework is notified that there are 0
-     * "remaining" steps, the framework may cache the "enrollmentId". See
-     * ISessionCallback#onEnrollmentProgress for more info.
-     *
-     * When a face is successfully added and before the framework is notified of remaining=0, the
-     * HAL must update and associate this (sensorId, userId) pair with a new entropy-encoded random
-     * identifier. See ISession#getAuthenticatorId for more information.
-     *
-     * Callbacks that signify the end of this operation's lifecycle:
-     *   - ISessionCallback#onError
-     *   - ISessionCallback#onEnrollmentProgress(enrollmentId, remaining=0)
-     *
-     * Other applicable callbacks:
-     *   - ISessionCallback#onAcquired
-     *
-     * @param hat See above documentation.
-     * @param enrollmentType See the EnrollmentType enum.
-     * @param features See the Feature enum.
-     * @param previewSurface A surface provided by the framework if SensorProps#halControlsPreview
-     *                       is set to true. The HAL must send the preview frames to previewSurface
-     *                       if it's not null.
-     * @return ICancellationSignal An object that can be used by the framework to cancel this
-     * operation.
+     * @deprecated use {@link enrollWithOptions} instead.
      */
     ICancellationSignal enroll(in HardwareAuthToken hat, in EnrollmentType type,
             in Feature[] features, in @nullable NativeHandle previewSurface);
@@ -456,7 +421,9 @@
     /* See ISession#authenticateWithContext(long) */
     ICancellationSignal authenticateWithContext(in long operationId, in OperationContext context);
 
-    /* See ISession#enroll(HardwareAuthToken, EnrollmentType, Feature[], NativeHandle) */
+    /*
+     * @deprecated use {@link enrollWithOptions} instead.
+     */
     ICancellationSignal enrollWithContext(in HardwareAuthToken hat, in EnrollmentType type,
             in Feature[] features, in @nullable NativeHandle previewSurface,
             in OperationContext context);
@@ -469,4 +436,41 @@
      * running when the context changes.
      */
     void onContextChanged(in OperationContext context);
+
+    /**
+     * enrollWithOptions:
+     *
+     * A request to add a face enrollment.
+     *
+     * At any point during enrollment, if a non-recoverable error occurs, the HAL must notify the
+     * framework via ISessionCallback#onError with the applicable enrollment-specific error.
+     *
+     * Before capturing face data, the HAL must first verify the authenticity and integrity of the
+     * provided HardwareAuthToken. In addition, it must check that the challenge within the provided
+     * HardwareAuthToken is valid. See ISession#generateChallenge. If any of the above checks fail,
+     * the framework must be notified using ISessionCallback#onError with Error::UNABLE_TO_PROCESS.
+     *
+     * During enrollment, the HAL may notify the framework via ISessionCallback#onAcquired with
+     * messages that may be used to guide the user. This callback can be invoked multiple times if
+     * necessary. Similarly, the framework may be notified of enrollment progress changes via
+     * ISessionCallback#onEnrollmentProgress. Once the framework is notified that there are 0
+     * "remaining" steps, the framework may cache the "enrollmentId". See
+     * ISessionCallback#onEnrollmentProgress for more info.
+     *
+     * When a face is successfully added and before the framework is notified of remaining=0, the
+     * HAL must update and associate this (sensorId, userId) pair with a new entropy-encoded random
+     * identifier. See ISession#getAuthenticatorId for more information.
+     *
+     * Callbacks that signify the end of this operation's lifecycle:
+     *   - ISessionCallback#onError
+     *   - ISessionCallback#onEnrollmentProgress(enrollmentId, remaining=0)
+     *
+     * Other applicable callbacks:
+     *   - ISessionCallback#onAcquired
+     *
+     * @param FaceEnrollOptions See {@link FaceEnrollOptions} for more detail.
+     * @return ICancellationSignal An object that can be used by the framework to cancel this
+     * operation.
+     */
+    ICancellationSignal enrollWithOptions(in FaceEnrollOptions options);
 }
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/ISessionCallback.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/ISessionCallback.aidl
index 9eb575c..b38e366 100644
--- a/biometrics/face/aidl/android/hardware/biometrics/face/ISessionCallback.aidl
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/ISessionCallback.aidl
@@ -23,6 +23,9 @@
 import android.hardware.biometrics.face.Feature;
 import android.hardware.keymaster.HardwareAuthToken;
 
+/**
+ * @hide
+ */
 @VintfStability
 interface ISessionCallback {
     /**
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/SensorProps.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/SensorProps.aidl
index 5f881ca..09fd9e5 100644
--- a/biometrics/face/aidl/android/hardware/biometrics/face/SensorProps.aidl
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/SensorProps.aidl
@@ -19,6 +19,9 @@
 import android.hardware.biometrics.common.CommonProps;
 import android.hardware.biometrics.face.FaceSensorType;
 
+/**
+ * @hide
+ */
 @VintfStability
 parcelable SensorProps {
     /**
diff --git a/biometrics/face/aidl/default/Android.bp b/biometrics/face/aidl/default/Android.bp
index 876a91f..4e8390a 100644
--- a/biometrics/face/aidl/default/Android.bp
+++ b/biometrics/face/aidl/default/Android.bp
@@ -7,27 +7,49 @@
     default_applicable_licenses: ["hardware_interfaces_license"],
 }
 
+filegroup {
+    name: "face-example.rc",
+    srcs: ["face-example.rc"],
+}
+
+filegroup {
+    name: "face-example.xml",
+    srcs: ["face-example.xml"],
+}
+
 cc_binary {
     name: "android.hardware.biometrics.face-service.example",
     relative_install_path: "hw",
-    init_rc: ["face-default.rc"],
-    vintf_fragments: ["face-default.xml"],
+    init_rc: [":face-example.rc"],
+    vintf_fragments: [":face-example.xml"],
     vendor: true,
+
     shared_libs: [
-        "libbase",
         "libbinder_ndk",
-        "android.hardware.biometrics.face-V3-ndk",
-        "android.hardware.biometrics.common-V3-ndk",
-        "android.hardware.biometrics.common.thread",
-        "android.hardware.biometrics.common.util",
+        "liblog",
+        "libnativewindow",
     ],
     srcs: [
+        "FakeLockoutTracker.cpp",
         "main.cpp",
         "Face.cpp",
         "FakeFaceEngine.cpp",
         "Session.cpp",
     ],
-    static_libs: ["libandroid.hardware.biometrics.face.VirtualProps"],
+    include_dirs: [
+        "frameworks/native/aidl/gui",
+    ],
+    stl: "c++_static",
+    static_libs: [
+        "android.hardware.biometrics.common-V4-ndk",
+        "android.hardware.biometrics.common.thread",
+        "android.hardware.biometrics.common.util",
+        "android.hardware.biometrics.face-V4-ndk",
+        "android.hardware.common-V2-ndk",
+        "android.hardware.keymaster-V4-ndk",
+        "libandroid.hardware.biometrics.face.VirtualProps",
+        "libbase",
+    ],
 }
 
 sysprop_library {
@@ -42,15 +64,46 @@
     srcs: [
         "tests/FakeFaceEngineTest.cpp",
         "FakeFaceEngine.cpp",
+        "FakeLockoutTracker.cpp",
     ],
     shared_libs: [
         "libbase",
         "libbinder_ndk",
+        "libnativewindow",
+    ],
+    include_dirs: [
+        "frameworks/native/aidl/gui",
     ],
     static_libs: [
         "libandroid.hardware.biometrics.face.VirtualProps",
-        "android.hardware.biometrics.face-V3-ndk",
-        "android.hardware.biometrics.common-V3-ndk",
+        "android.hardware.biometrics.face-V4-ndk",
+        "android.hardware.biometrics.common-V4-ndk",
+        "android.hardware.keymaster-V4-ndk",
+        "android.hardware.biometrics.common.util",
+    ],
+    vendor: true,
+    test_suites: ["general-tests"],
+    require_root: true,
+}
+
+cc_test {
+    name: "android.hardware.biometrics.face.FakeLockoutTrackerTest",
+    srcs: [
+        "tests/FakeLockoutTrackerTest.cpp",
+        "FakeLockoutTracker.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "libnativewindow",
+    ],
+    include_dirs: [
+        "frameworks/native/aidl/gui",
+    ],
+    static_libs: [
+        "libandroid.hardware.biometrics.face.VirtualProps",
+        "android.hardware.biometrics.face-V4-ndk",
+        "android.hardware.biometrics.common-V4-ndk",
         "android.hardware.keymaster-V4-ndk",
         "android.hardware.biometrics.common.util",
     ],
diff --git a/biometrics/face/aidl/default/FakeFaceEngine.cpp b/biometrics/face/aidl/default/FakeFaceEngine.cpp
index 0f088f4..bdc13fd 100644
--- a/biometrics/face/aidl/default/FakeFaceEngine.cpp
+++ b/biometrics/face/aidl/default/FakeFaceEngine.cpp
@@ -1,3 +1,21 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "FaceVirtualHalEngine"
+
 #include "FakeFaceEngine.h"
 
 #include <android-base/logging.h>
@@ -52,16 +70,7 @@
                                 EnrollmentType /*enrollmentType*/,
                                 const std::vector<Feature>& /*features*/,
                                 const std::future<void>& cancel) {
-    BEGIN_OP(FaceHalProperties::operation_start_enroll_latency().value_or(0));
-    // format is "<id>,<bucket_id>:<delay>:<succeeds>,<bucket_id>:<delay>:<succeeds>...
-    auto nextEnroll = FaceHalProperties::next_enrollment().value_or("");
-    // Erase the next enrollment
-    FaceHalProperties::next_enrollment({});
-
-    AuthenticationFrame frame;
-    frame.data.acquiredInfo = AcquiredInfo::START;
-    frame.data.vendorCode = 0;
-    cb->onAuthenticationFrame(frame);
+    BEGIN_OP(getLatency(FaceHalProperties::operation_enroll_latency()));
 
     // Do proper HAT verification in the real implementation.
     if (hat.mac.empty()) {
@@ -70,32 +79,159 @@
         return;
     }
 
-    if (FaceHalProperties::operation_enroll_fails().value_or(false)) {
-        LOG(ERROR) << "Fail: operation_enroll_fails";
+    // Format: <id>:<progress_ms-[acquiredInfo,...],...:<success>
+    // ------:-----------------------------------------:--------------
+    //          |           |                              |--->enrollment success (true/false)
+    //          |           |--> progress_steps
+    //          |
+    //          |-->enrollment id
+    //
+    //
+    //   progress_steps
+    //        <progress_duration>-[acquiredInfo,...]+
+    //        ----------------------------  ---------------------
+    //                 |                            |-> sequence of acquiredInfo code
+    //                 | --> time duration of the step in ms
+    //
+    //        E.g.   1:2000-[21,1108,5,6,1],1000-[1113,4,1]:true
+    //              A success enrollement of id 1 by 2 steps
+    //                    1st step lasts 2000ms with acquiredInfo codes (21,1108,5,6,1)
+    //                    2nd step lasts 1000ms with acquiredInfo codes (1113,4,1)
+    //
+    std::string defaultNextEnrollment =
+            "1:1000-[21,7,1,1103],1500-[1108,1],2000-[1113,1],2500-[1118,1]:true";
+    auto nextEnroll = FaceHalProperties::next_enrollment().value_or(defaultNextEnrollment);
+    auto parts = Util::split(nextEnroll, ":");
+    if (parts.size() != 3) {
+        LOG(ERROR) << "Fail: invalid next_enrollment:" << nextEnroll;
         cb->onError(Error::VENDOR, 0 /* vendorError */);
         return;
     }
-
-    auto parts = Util::split(nextEnroll, ",");
-    if (parts.size() < 2) {
-        LOG(ERROR) << "Fail: invalid next_enrollment for : " << nextEnroll;
-        cb->onError(Error::VENDOR, 0 /* vendorError */);
-        return;
-    }
-
     auto enrollmentId = std::stoi(parts[0]);
-    const int numBuckets = parts.size() - 1;
-    for (size_t i = 1; i < parts.size(); i++) {
-        auto enrollHit = Util::split(parts[i], ":");
-        if (enrollHit.size() != 3) {
-            LOG(ERROR) << "Error when unpacking enrollment hit: " << parts[i];
-            cb->onError(Error::VENDOR, 0 /* vendorError */);
-        }
-        std::string bucket = enrollHit[0];
-        std::string delay = enrollHit[1];
-        std::string succeeds = enrollHit[2];
+    auto progress = Util::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();
 
-        SLEEP_MS(std::stoi(delay));
+        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;
+            }
+            EnrollmentFrame frame = {};
+            auto ac = convertAcquiredInfo(acquired[j]);
+            frame.data.acquiredInfo = ac.first;
+            frame.data.vendorCode = ac.second;
+            frame.stage = (i == 0 && j == 0) ? EnrollmentStage::FIRST_FRAME_RECEIVED
+                          : (i == progress.size() - 2 && j == N - 1)
+                                  ? EnrollmentStage::ENROLLMENT_FINISHED
+                                  : EnrollmentStage::WAITING_FOR_CENTERING;
+            cb->onEnrollmentFrame(frame);
+        }
+
+        if (left == 0 && !IS_TRUE(parts[2])) {  // end and failed
+            LOG(ERROR) << "Fail: requested by caller: " << nextEnroll;
+            FaceHalProperties::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 = FaceHalProperties::enrollments();
+                enrollments.emplace_back(enrollmentId);
+                FaceHalProperties::enrollments(enrollments);
+                FaceHalProperties::next_enrollment({});
+                // change authenticatorId after new enrollment
+                auto id = FaceHalProperties::authenticator_id().value_or(0);
+                auto newId = id + 1;
+                FaceHalProperties::authenticator_id(newId);
+                LOG(INFO) << "Enrolled: " << enrollmentId;
+            }
+            cb->onEnrollmentProgress(enrollmentId, left);
+        }
+    }
+}
+
+void FakeFaceEngine::authenticateImpl(ISessionCallback* cb, int64_t /*operationId*/,
+                                      const std::future<void>& cancel) {
+    BEGIN_OP(getLatency(FaceHalProperties::operation_authenticate_latency()));
+
+    auto id = FaceHalProperties::enrollment_hit().value_or(0);
+    auto enrolls = FaceHalProperties::enrollments();
+    auto isEnrolled = std::find(enrolls.begin(), enrolls.end(), id) != enrolls.end();
+
+    auto vec2str = [](std::vector<AcquiredInfo> va) {
+        std::stringstream ss;
+        bool isFirst = true;
+        for (auto ac : va) {
+            if (!isFirst) ss << ",";
+            ss << std::to_string((int8_t)ac);
+            isFirst = false;
+        }
+        return ss.str();
+    };
+
+    // default behavior mimic face sensor in U
+    int64_t defaultAuthDuration = 500;
+    std::string defaultAcquiredInfo =
+            vec2str({AcquiredInfo::START, AcquiredInfo::FIRST_FRAME_RECEIVED});
+    if (!isEnrolled) {
+        std::vector<AcquiredInfo> v;
+        for (int i = 0; i < 56; i++) v.push_back(AcquiredInfo::NOT_DETECTED);
+        defaultAcquiredInfo += "," + vec2str(v);
+        defaultAuthDuration = 2100;
+    } else {
+        defaultAcquiredInfo += "," + vec2str({AcquiredInfo::TOO_BRIGHT, AcquiredInfo::TOO_BRIGHT,
+                                              AcquiredInfo::TOO_BRIGHT, AcquiredInfo::TOO_BRIGHT,
+                                              AcquiredInfo::GOOD, AcquiredInfo::GOOD});
+    }
+
+    int64_t now = Util::getSystemNanoTime();
+    int64_t duration =
+            FaceHalProperties::operation_authenticate_duration().value_or(defaultAuthDuration);
+    auto acquired =
+            FaceHalProperties::operation_authenticate_acquired().value_or(defaultAcquiredInfo);
+    auto acquiredInfos = Util::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;
+    }
+
+    if (mLockoutTracker.checkIfLockout(cb)) {
+        return;
+    }
+
+    int i = 0;
+    do {
+        if (FaceHalProperties::lockout().value_or(false)) {
+            LOG(ERROR) << "Fail: lockout";
+            cb->onLockoutPermanent();
+            cb->onError(Error::HW_UNAVAILABLE, 0 /* vendorError */);
+            return;
+        }
+
+        if (FaceHalProperties::operation_authenticate_fails().value_or(false)) {
+            LOG(ERROR) << "Fail: operation_authenticate_fails";
+            mLockoutTracker.addFailedAttempt(cb);
+            cb->onAuthenticationFailed();
+            return;
+        }
+
+        auto err = FaceHalProperties::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; /* simply terminating current operation for any user inserted error,
+                            revisit if tests need*/
+        }
 
         if (shouldCancel(cancel)) {
             LOG(ERROR) << "Fail: cancel";
@@ -103,93 +239,59 @@
             return;
         }
 
-        if (!IS_TRUE(succeeds)) {  // end and failed
-            LOG(ERROR) << "Fail: requested by caller: " << parts[i];
-            cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
-            return;
+        if (i < N) {
+            auto ac = convertAcquiredInfo(acquiredInfos[i]);
+            AuthenticationFrame frame;
+            frame.data.acquiredInfo = ac.first;
+            frame.data.vendorCode = ac.second;
+            cb->onAuthenticationFrame(frame);
+            LOG(INFO) << "AcquiredInfo:" << i << ": (" << (int)ac.first << "," << (int)ac.second
+                      << ")";
+            i++;
         }
 
-        EnrollmentFrame frame;
+        SLEEP_MS(duration / N);
+    } while (!Util::hasElapsed(now, duration));
 
-        frame.data.acquiredInfo = AcquiredInfo::GOOD;
-        frame.data.vendorCode = 0;
-        cb->onEnrollmentFrame(frame);
-
-        frame.data.acquiredInfo = AcquiredInfo::VENDOR;
-        frame.data.vendorCode = std::stoi(bucket);
-        cb->onEnrollmentFrame(frame);
-
-        int remainingBuckets = numBuckets - i;
-        if (remainingBuckets > 0) {
-            cb->onEnrollmentProgress(enrollmentId, remainingBuckets);
-        }
+    if (id > 0 && isEnrolled) {
+        mLockoutTracker.reset();
+        cb->onAuthenticationSucceeded(id, {} /* hat */);
+        return;
+    } else {
+        LOG(ERROR) << "Fail: face not enrolled";
+        mLockoutTracker.addFailedAttempt(cb);
+        cb->onAuthenticationFailed();
+        cb->onError(Error::TIMEOUT, 0 /* vendorError*/);
+        return;
     }
-
-    auto enrollments = FaceHalProperties::enrollments();
-    enrollments.push_back(enrollmentId);
-    FaceHalProperties::enrollments(enrollments);
-    LOG(INFO) << "enrolled : " << enrollmentId;
-    cb->onEnrollmentProgress(enrollmentId, 0);
 }
 
-void FakeFaceEngine::authenticateImpl(ISessionCallback* cb, int64_t /*operationId*/,
-                                      const std::future<void>& cancel) {
-    BEGIN_OP(FaceHalProperties::operation_authenticate_latency().value_or(0));
-
-    // Signal to the framework that we have begun authenticating.
-    AuthenticationFrame frame;
-    frame.data.acquiredInfo = AcquiredInfo::START;
-    frame.data.vendorCode = 0;
-    cb->onAuthenticationFrame(frame);
-
-    // Also signal that we have opened the camera.
-    frame = {};
-    frame.data.acquiredInfo = AcquiredInfo::FIRST_FRAME_RECEIVED;
-    frame.data.vendorCode = 0;
-    cb->onAuthenticationFrame(frame);
-
-    auto now = Util::getSystemNanoTime();
-    int64_t duration = FaceHalProperties::operation_authenticate_duration().value_or(0);
-    if (duration > 0) {
-        do {
-            SLEEP_MS(5);
-        } while (!Util::hasElapsed(now, duration));
+std::pair<AcquiredInfo, int32_t> FakeFaceEngine::convertAcquiredInfo(int32_t code) {
+    std::pair<AcquiredInfo, int32_t> res;
+    if (code > FACE_ACQUIRED_VENDOR_BASE) {
+        res.first = AcquiredInfo::VENDOR;
+        res.second = code - FACE_ACQUIRED_VENDOR_BASE;
+    } else {
+        res.first = (AcquiredInfo)code;
+        res.second = 0;
     }
+    return res;
+}
 
-    if (FaceHalProperties::operation_authenticate_fails().value_or(false)) {
-        LOG(ERROR) << "Fail: operation_authenticate_fails";
-        cb->onError(Error::VENDOR, 0 /* vendorError */);
-        return;
+std::pair<Error, int32_t> FakeFaceEngine::convertError(int32_t code) {
+    std::pair<Error, int32_t> res;
+    if (code > FACE_ERROR_VENDOR_BASE) {
+        res.first = Error::VENDOR;
+        res.second = code - FACE_ERROR_VENDOR_BASE;
+    } else {
+        res.first = (Error)code;
+        res.second = 0;
     }
-
-    if (FaceHalProperties::lockout().value_or(false)) {
-        LOG(ERROR) << "Fail: lockout";
-        cb->onLockoutPermanent();
-        cb->onError(Error::HW_UNAVAILABLE, 0 /* vendorError */);
-        return;
-    }
-
-    if (shouldCancel(cancel)) {
-        LOG(ERROR) << "Fail: cancel";
-        cb->onError(Error::CANCELED, 0 /* vendorCode */);
-        return;
-    }
-
-    auto id = FaceHalProperties::enrollment_hit().value_or(0);
-    auto enrolls = FaceHalProperties::enrollments();
-    auto isEnrolled = std::find(enrolls.begin(), enrolls.end(), id) != enrolls.end();
-    if (id < 0 || !isEnrolled) {
-        LOG(ERROR) << (isEnrolled ? "invalid enrollment hit" : "Fail: not enrolled");
-        cb->onAuthenticationFailed();
-        cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
-        return;
-    }
-
-    cb->onAuthenticationSucceeded(id, {} /* hat */);
+    return res;
 }
 
 void FakeFaceEngine::detectInteractionImpl(ISessionCallback* cb, const std::future<void>& cancel) {
-    BEGIN_OP(FaceHalProperties::operation_detect_interaction_latency().value_or(0));
+    BEGIN_OP(getLatency(FaceHalProperties::operation_detect_interaction_latency()));
 
     if (FaceHalProperties::operation_detect_interaction_fails().value_or(false)) {
         LOG(ERROR) << "Fail: operation_detect_interaction_fails";
@@ -312,7 +414,37 @@
                                       const keymaster::HardwareAuthToken& /*hat*/) {
     BEGIN_OP(0);
     FaceHalProperties::lockout(false);
+    mLockoutTracker.reset();
     cb->onLockoutCleared();
 }
 
-}  // namespace aidl::android::hardware::biometrics::face
\ No newline at end of file
+int32_t FakeFaceEngine::getRandomInRange(int32_t bound1, int32_t bound2) {
+    std::uniform_int_distribution<int32_t> dist(std::min(bound1, bound2), std::max(bound1, bound2));
+    return dist(mRandom);
+}
+
+int32_t FakeFaceEngine::getLatency(const std::vector<std::optional<std::int32_t>>& latencyIn) {
+    int32_t res = DEFAULT_LATENCY;
+
+    std::vector<int32_t> latency;
+    for (auto x : latencyIn)
+        if (x.has_value()) latency.push_back(*x);
+
+    switch (latency.size()) {
+        case 0:
+            break;
+        case 1:
+            res = latency[0];
+            break;
+        case 2:
+            res = getRandomInRange(latency[0], latency[1]);
+            break;
+        default:
+            LOG(ERROR) << "ERROR: unexpected input of size " << latency.size();
+            break;
+    }
+
+    return res;
+}
+
+}  // namespace aidl::android::hardware::biometrics::face
diff --git a/biometrics/face/aidl/default/FakeFaceEngine.h b/biometrics/face/aidl/default/FakeFaceEngine.h
index edb54ce..b1e1388 100644
--- a/biometrics/face/aidl/default/FakeFaceEngine.h
+++ b/biometrics/face/aidl/default/FakeFaceEngine.h
@@ -21,11 +21,12 @@
 #include <aidl/android/hardware/biometrics/face/FaceSensorType.h>
 #include <aidl/android/hardware/biometrics/face/ISessionCallback.h>
 
-#include <random>
-
 #include <future>
+#include <random>
 #include <vector>
 
+#include "FakeLockoutTracker.h"
+
 namespace aidl::android::hardware::biometrics::face {
 
 namespace face = aidl::android::hardware::biometrics::face;
@@ -37,6 +38,7 @@
 class FakeFaceEngine {
   public:
     FakeFaceEngine() : mRandom(std::mt19937::default_seed) {}
+    virtual ~FakeFaceEngine() {}
 
     static face::FaceSensorType GetSensorType();
     static common::SensorStrength GetSensorStrength();
@@ -58,8 +60,24 @@
     void getAuthenticatorIdImpl(ISessionCallback* cb);
     void invalidateAuthenticatorIdImpl(ISessionCallback* cb);
     void resetLockoutImpl(ISessionCallback* cb, const keymaster::HardwareAuthToken& /*hat*/);
+    int32_t getLatency(const std::vector<std::optional<std::int32_t>>& latencyVec);
+
+    virtual std::string toString() const {
+        std::ostringstream os;
+        os << "----- FakeFaceEngine:: -----" << std::endl;
+        os << mLockoutTracker.toString();
+        return os.str();
+    }
 
     std::mt19937 mRandom;
+
+  private:
+    int32_t getRandomInRange(int32_t bound1, int32_t bound2);
+    static constexpr int32_t FACE_ACQUIRED_VENDOR_BASE = 1000;
+    static constexpr int32_t FACE_ERROR_VENDOR_BASE = 1000;
+    std::pair<AcquiredInfo, int32_t> convertAcquiredInfo(int32_t code);
+    std::pair<Error, int32_t> convertError(int32_t code);
+    FakeLockoutTracker mLockoutTracker;
 };
 
-}  // namespace aidl::android::hardware::biometrics::face
\ No newline at end of file
+}  // namespace aidl::android::hardware::biometrics::face
diff --git a/biometrics/face/aidl/default/FakeLockoutTracker.cpp b/biometrics/face/aidl/default/FakeLockoutTracker.cpp
new file mode 100644
index 0000000..70bf08e
--- /dev/null
+++ b/biometrics/face/aidl/default/FakeLockoutTracker.cpp
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "FaceVirtualHalLockoutTracker"
+
+#include "FakeLockoutTracker.h"
+#include <android-base/logging.h>
+#include <face.sysprop.h>
+#include "util/Util.h"
+
+using namespace ::android::face::virt;
+
+namespace aidl::android::hardware::biometrics::face {
+
+void FakeLockoutTracker::reset(bool dueToTimerExpire) {
+    if (!dueToTimerExpire) {
+        mFailedCount = 0;
+        mLastFailedTime = 0;
+    }
+    mTimedFailedCount = 0;
+    mCurrentMode = LockoutMode::kNone;
+    abortTimer();
+}
+
+void FakeLockoutTracker::addFailedAttempt(ISessionCallback* cb) {
+    bool lockoutEnabled = FaceHalProperties::lockout_enable().value_or(false);
+    bool timedLockoutenabled = FaceHalProperties::lockout_timed_enable().value_or(false);
+    if (lockoutEnabled) {
+        mFailedCount++;
+        mTimedFailedCount++;
+        mLastFailedTime = Util::getSystemNanoTime();
+        int32_t lockoutTimedThreshold = FaceHalProperties::lockout_timed_threshold().value_or(3);
+        int32_t lockoutPermanetThreshold =
+                FaceHalProperties::lockout_permanent_threshold().value_or(5);
+        if (mFailedCount >= lockoutPermanetThreshold) {
+            mCurrentMode = LockoutMode::kPermanent;
+            LOG(ERROR) << "FakeLockoutTracker: lockoutPermanent";
+            cb->onLockoutPermanent();
+            abortTimer();
+        } else if (timedLockoutenabled && mTimedFailedCount >= lockoutTimedThreshold) {
+            if (mCurrentMode == LockoutMode::kNone) {
+                mCurrentMode = LockoutMode::kTimed;
+                startLockoutTimer(getTimedLockoutDuration(), cb);
+            }
+            LOG(ERROR) << "FakeLockoutTracker: lockoutTimed";
+            cb->onLockoutTimed(getLockoutTimeLeft());
+        }
+    } else {
+        reset();
+    }
+}
+
+FakeLockoutTracker::LockoutMode FakeLockoutTracker::getMode() {
+    return mCurrentMode;
+}
+
+int32_t FakeLockoutTracker::getTimedLockoutDuration() {
+    return FaceHalProperties::lockout_timed_duration().value_or(10 * 1000);
+}
+
+int64_t FakeLockoutTracker::getLockoutTimeLeft() {
+    int64_t res = 0;
+
+    if (mLastFailedTime > 0) {
+        auto now = Util::getSystemNanoTime();
+        auto elapsed = (now - mLastFailedTime) / 1000000LL;
+        res = getTimedLockoutDuration() - elapsed;
+        LOG(INFO) << "elapsed=" << elapsed << " now = " << now
+                  << " mLastFailedTime=" << mLastFailedTime << " res=" << res;
+    }
+
+    return res;
+}
+
+bool FakeLockoutTracker::checkIfLockout(ISessionCallback* cb) {
+    if (mCurrentMode == LockoutMode::kPermanent) {
+        LOG(ERROR) << "Lockout permanent";
+        cb->onLockoutPermanent();
+        return true;
+    } else if (mCurrentMode == LockoutMode::kTimed) {
+        auto timeLeft = getLockoutTimeLeft();
+        LOG(ERROR) << "Lockout timed " << timeLeft;
+        cb->onLockoutTimed(timeLeft);
+        return true;
+    }
+    return false;
+}
+
+void FakeLockoutTracker::startLockoutTimer(int64_t timeout, ISessionCallback* cb) {
+    LOG(ERROR) << "startLockoutTimer: to=" << timeout;
+    if (mIsLockoutTimerStarted) return;
+    std::function<void(ISessionCallback*)> action =
+            std::bind(&FakeLockoutTracker::lockoutTimerExpired, this, std::placeholders::_1);
+    std::thread([timeout, action, cb]() {
+        std::this_thread::sleep_for(std::chrono::milliseconds(timeout));
+        action(cb);
+    }).detach();
+
+    mIsLockoutTimerStarted = true;
+}
+
+void FakeLockoutTracker::lockoutTimerExpired(ISessionCallback* cb) {
+    LOG(INFO) << "lockout timer expired";
+    mIsLockoutTimerStarted = false;
+
+    if (mIsLockoutTimerAborted) {
+        mIsLockoutTimerAborted = false;
+        return;
+    }
+
+    // if more failures seen since the timer started, need to restart timer again
+    auto deltaTime = getLockoutTimeLeft();
+    if (deltaTime <= 0) {
+        cb->onLockoutCleared();
+        reset(true);
+    } else {
+        startLockoutTimer(deltaTime, cb);
+    }
+}
+
+void FakeLockoutTracker::abortTimer() {
+    if (mIsLockoutTimerStarted) mIsLockoutTimerAborted = true;
+}
+
+}  // namespace aidl::android::hardware::biometrics::face
diff --git a/biometrics/face/aidl/default/FakeLockoutTracker.h b/biometrics/face/aidl/default/FakeLockoutTracker.h
new file mode 100644
index 0000000..82cc313
--- /dev/null
+++ b/biometrics/face/aidl/default/FakeLockoutTracker.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/biometrics/face/ISessionCallback.h>
+#include <android/binder_to_string.h>
+#include <stdint.h>
+#include <string>
+
+namespace aidl::android::hardware::biometrics::face {
+
+// Lockout implementation for Face Virtual HAL
+class FakeLockoutTracker {
+  public:
+    FakeLockoutTracker()
+        : mFailedCount(0),
+          mTimedFailedCount(0),
+          mLastFailedTime(0),
+          mCurrentMode(LockoutMode::kNone),
+          mIsLockoutTimerStarted(false),
+          mIsLockoutTimerAborted(false) {}
+    ~FakeLockoutTracker() {}
+
+    enum class LockoutMode : int8_t { kNone = 0, kTimed, kPermanent };
+
+    bool checkIfLockout(ISessionCallback*);
+    void addFailedAttempt(ISessionCallback*);
+    int64_t getLockoutTimeLeft();
+    LockoutMode getMode();
+    void reset(bool dueToTimerExpire = false);
+    inline std::string toString() const {
+        std::ostringstream os;
+        os << "----- FakeLockoutTracker:: -----" << std::endl;
+        os << "mFailedCount:" << mFailedCount;
+        os << ", mCurrentMode:" << (int)mCurrentMode;
+        os << ", mLastFailedTime:" << (int)(mLastFailedTime / 1000000LL);
+        os << ",  mIsLockoutTimerStarted:" << mIsLockoutTimerStarted;
+        os << ", mIsLockoutTimerAborted:" << mIsLockoutTimerAborted;
+        os << std::endl;
+        return os.str();
+    }
+
+  private:
+    void startLockoutTimer(int64_t timeout, ISessionCallback* cb);
+    void lockoutTimerExpired(ISessionCallback* cb);
+    int32_t getTimedLockoutDuration();
+    void abortTimer();
+
+  private:
+    int32_t mFailedCount;
+    int32_t mTimedFailedCount;
+    int64_t mLastFailedTime;
+    LockoutMode mCurrentMode;
+    bool mIsLockoutTimerStarted;
+    bool mIsLockoutTimerAborted;
+};
+
+}  // namespace aidl::android::hardware::biometrics::face
diff --git a/biometrics/face/aidl/default/README.md b/biometrics/face/aidl/default/README.md
index 1655973..c9a8cfe 100644
--- a/biometrics/face/aidl/default/README.md
+++ b/biometrics/face/aidl/default/README.md
@@ -1,77 +1,127 @@
-# Virtual Face HAL
+# Face Virtual HAL (VHAL)
 
-This is a virtual HAL implementation that is backed by system properties
-instead of actual hardware. It's intended for testing and UI development
-on debuggable builds to allow devices to masquerade as alternative device
-types and for emulators.
+This is a virtual HAL implementation that is backed by system properties instead
+of actual hardware. It's intended for testing and UI development on debuggable
+builds to allow devices to masquerade as alternative device types and for
+emulators. Note: The virtual face HAL feature development will be done in
+phases. Refer to this doc often for the latest supported features
 
-## Device Selection
+## Supported Devices
 
-You can either run the FakeFaceEngine on a [real device](#actual-device) or a [virtual device/cuttlefish](#getting-started-on-a-virtual-device-cuttlefish). This document should
-help you to get started on either one.
+The face virtual hal is automatically built in in all debug builds (userdebug<br/>
+and eng) for the latest pixel devices and CF. The instructions in this doc<br/>
+applies to all
 
-After setting up a device, go ahead and try out [enrolling](#enrolling) & [authenticating](#authenticating)
+## Enabling Face Virtual HAL
 
-### Getting started on a Virtual Device (cuttlefish)
+On pixel devicse (non-CF), by default (after manufacture reset), Face VHAL is <br/>
+not enabled. Therefore real Face HAL is used. Face VHAL enabling is gated by the<br/>
+following two AND conditions:<br/>
+1. The Face VHAL feature flag (as part ofTrunk-development strategy) must be<br/>
+   turned on until the flags life-cycle ends.
+2. The Face VHAL must be enabled via sysprop.
 
+See the adb commands below
 
-Note, I'm running this via a cloudtop virtual device.
+## Getting Stared
 
-1. Setup cuttlefish on cloudtop, See [this](https://g3doc.corp.google.com/company/teams/android/teampages/acloud/getting_started.md?cl=head) for more details.
-2. acloud create --local-image
-3. Enter in the shell command to disable hidl
+A basic use case for a successful authentication via Face VHAL is given as an
+exmple below.
+
+### Enabling VHAL
 
 ```shell
 $ adb root
-$ adb shell settings put secure com.android.server.biometrics.AuthService.hidlDisabled 1
-$ adb reboot
-```
-4. You should now be able to do fake enrollments and authentications (as seen down below)
-
-### Actual Device
-
-1. Modify your real devices make file (I.E. vendor/google/products/{YOUR_DEVICE}.mk)
-2. Ensure that there is no other face HAL that is being included by the device
-3. Add the following
-```
-PRODUCT_COPY_FILES += \
-    frameworks/native/data/etc/android.hardware.biometrics.face.xml:$(TARGET_COPY_OUT_PRODUCT)/etc/permissions/android.hardware.biometrics.face.xml
-
-PRODUCT_PACKAGES += \
-    android.hardware.biometrics.face-service.example \
-
-```
-4. Now build and flash m -j120 && flash
-5. Run the following commands
-
-```shell
-# This is a temporary workaround
-$ adb root
-$ adb shell setprop persist.vendor.face.virtual.type RGB
+$ adb shell device_config put biometrics_framework com.android.server.biometrics.face_vhal_feature true
+$ adb shell settings put secure biometric_virtual_enabled 1
 $ adb shell setprop persist.vendor.face.virtual.strength strong
-$ adb shell locksettings set-pin 0000
+$ adb shell setprop persist.vendor.face.virtual.type RGB
 $ adb reboot
 ```
 
-## Enrolling
+### Direct Enrollment
 
 ```shell
-# authenticar_id,bucket_id:duration:(true|false)....
-$ adb shell setprop vendor.face.virtual.next_enrollment 1,0:500:true,5:250:true,10:150:true,15:500:true
-$ adb shell am start -n com.android.settings/.biometrics.face.FaceEnrollIntroduction
-# If you would like to get rid of the enrollment, run the follwoing command
-$ adb shell setprop persist.vendor.face.virtual.enrollments \"\"
+$ adb shell locksettings set-pin 0000
+$ adb shell setprop persist.vendor.face.virtual.enrollments 1
+$ adb shell cmd face syncadb shell cmd face sync
 ```
 
 ## Authenticating
 
-```shell
-# If enrollment hasn't been setup
-$ adb shell setprop persist.vendor.face.virtual.enrollments 1
-$ adb shell cmd face sync
-# After enrollment has been setup
+To authenticate successfully, the captured (hit) must match the enrollment id<br/>
+set above. To trigger authentication failure, set the hit id to a different value.
+`shell
 $ adb shell setprop vendor.face.virtual.operation_authenticate_duration 800
-$ adb shell setprop vendor.face.virtual.enrollment_hit 1
-# Power button press to simulate auth
-$ adb shell input keyevent 26
+$ adb shell setprop vendor.face.virtual.enrollment_hit 1`
+
+### AcquiredInfo
+
+AcquiredInfo codes can be sent during authentication by specifying the sysprop.<br/>
+The codes is sent in sequence and in the interval of operation_authentication_duration/numberOfAcquiredInfoCode
+`shell
+$ adb shell setprop vendor.face.virtual.operation_authenticate_acquired 6,9,1013`
+Refer to [AcquiredInfo.aidl](https://source.corp.google.com/h/googleplex-android/platform/superproject/main/+/main:hardware/interfaces/biometrics/face/aidl/android/hardware/biometrics/face/AcquiredInfo.aidl) for full face acquiredInfo codes.
+Note: For vendor specific acquired info, acquiredInfo = 1000 + vendorCode.
+
+### Error Insertion
+
+Error can be inserted during authentction by specifying the authenticate_error
+sysprop. `shell $ adb shell setprop
+vendor.face.virtual.operation_authenticate_error 4` Refer to
+[Error.aidl](https://source.corp.google.com/h/googleplex-android/platform/superproject/main/+/main:hardware/interfaces/biometrics/face/aidl/android/hardware/biometrics/face/Error.aidl)
+for full face error codes
+
+## Enrollment via Settings
+
+Enrollment process is specified by sysprop `next_enrollment` in the following
+format
+
+```shell
+Format: <id>:<progress_ms-[acquiredInfo,...],...:<success>
+        ----:-----------------------------------:---------
+        |           |                               |--->sucess (true/false)
+        |           |--> progress_step(s)
+        |
+        |-->enrollment_id
+
+E.g.
+$ adb shell setprop vendor.face.virtual.next_enrollment 1:6000-[21,8,1,1108,1,10,1113,1,1118,1124]:true
 ```
+
+If next_enrollment prop is not set, the following default value is used:<br/>
+&nbsp;&nbsp;defaultNextEnrollment="1:1000-[21,7,1,1103],1500-[1108,1],2000-[1113,1],2500-[1118,1]:true"<br/>
+Note: Enrollment data and configuration can be supported upon request in case of needs
+
+## Lockout
+
+Device lockout is based on the number of consecutive failed authentication attempts. There are a few
+flavors of lockout mechanisms that are supported by virtula HAL <br/>
+
+### Permanent Lockout
+
+There are two sysprop to control permanent lockout <br/>
+1. general lockout feature enable <br/>
+2. threshold of failed attempts <br/>
+`shell
+$ adb shell setprop persist.vendor.face.virtual.lockout_enable true
+$ adb shell setprop persist.vendor.face.virtual.lockout_permanent_threshold 3`
+
+### Temporary Lockout
+
+There are a few parameters to control temporary lockout (aka timed lockout): <br/>
+1. enable lockout (general lockout feature enable, and timed lcokout enable) <br/>
+2. threshold of failed attempts <br/>
+3. timeout in ms <br/>
+`shell
+$ adb shell setprop persist.vendor.face.virtual.lockout_enable true
+$ adb shell setprop persist.vendor.face.virtual.lockout_timed_enable true
+$ adb shell setprop persist.vendor.face.virtual.lockout_timed_threshold 5
+$ adb shell setprop persist.vendor.face.virtual.lockout_timed_duration 10000`
+
+### Forced Lockout
+
+A permanent lockout can be inserted on next authentication attempt independent of the failed <br/>
+attempt count. This is a feature purely for test purpose.
+`shell
+$ adb shell setprop persist.vendor.face.virtual.lockout true`
diff --git a/biometrics/face/aidl/default/Session.cpp b/biometrics/face/aidl/default/Session.cpp
index 1188459..6f3f2fc 100644
--- a/biometrics/face/aidl/default/Session.cpp
+++ b/biometrics/face/aidl/default/Session.cpp
@@ -18,6 +18,9 @@
 
 #include "Session.h"
 
+#undef LOG_TAG
+#define LOG_TAG "FaceVirtualHalSession"
+
 namespace aidl::android::hardware::biometrics::face {
 
 constexpr size_t MAX_WORKER_QUEUE_SIZE = 5;
@@ -172,4 +175,10 @@
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus Session::enrollWithOptions(const FaceEnrollOptions& options,
+                                              std::shared_ptr<common::ICancellationSignal>* out) {
+    return enroll(options.hardwareAuthToken, options.enrollmentType, options.features,
+                  options.nativeHandlePreview, out);
+}
+
 }  // namespace aidl::android::hardware::biometrics::face
diff --git a/biometrics/face/aidl/default/Session.h b/biometrics/face/aidl/default/Session.h
index 7ca6a1f..ce6e7f1 100644
--- a/biometrics/face/aidl/default/Session.h
+++ b/biometrics/face/aidl/default/Session.h
@@ -19,6 +19,7 @@
 #include <random>
 
 #include <aidl/android/hardware/biometrics/face/BnSession.h>
+#include <aidl/android/hardware/biometrics/face/FaceEnrollOptions.h>
 #include <aidl/android/hardware/biometrics/face/ISessionCallback.h>
 
 #include "FakeFaceEngine.h"
@@ -88,6 +89,10 @@
 
     ndk::ScopedAStatus onContextChanged(const common::OperationContext& context) override;
 
+    ndk::ScopedAStatus enrollWithOptions(
+            const FaceEnrollOptions& options,
+            std::shared_ptr<common::ICancellationSignal>* out) override;
+
   private:
     std::unique_ptr<FakeFaceEngine> mEngine;
     std::shared_ptr<ISessionCallback> mCb;
diff --git a/biometrics/face/aidl/default/apex/Android.bp b/biometrics/face/aidl/default/apex/Android.bp
new file mode 100644
index 0000000..86c4e12
--- /dev/null
+++ b/biometrics/face/aidl/default/apex/Android.bp
@@ -0,0 +1,62 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES 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"],
+}
+
+apex {
+    name: "com.android.hardware.biometrics.face.virtual",
+    manifest: "manifest.json",
+    file_contexts: "file_contexts",
+    key: "com.android.hardware.key",
+    certificate: ":com.android.hardware.certificate",
+    updatable: false,
+    vendor: true,
+
+    binaries: [
+        // hal
+        "android.hardware.biometrics.face-service.example",
+    ],
+    prebuilts: [
+        // init_rc
+        "face-example-apex.rc",
+        // vintf_fragment
+        "face-example-apex.xml",
+    ],
+
+    overrides: [
+        "android.hardware.biometrics.face-service.example",
+    ],
+}
+
+prebuilt_etc {
+    name: "face-example-apex.rc",
+    src: ":gen-face-example-apex.rc",
+    installable: false,
+}
+
+genrule {
+    name: "gen-face-example-apex.rc",
+    srcs: [":face-example.rc"],
+    out: ["face-example-apex.rc"],
+    cmd: "sed -e 's@/vendor/bin/@/apex/com.android.hardware.biometrics.face.virtual/bin/@' $(in) > $(out)",
+}
+
+prebuilt_etc {
+    name: "face-example-apex.xml",
+    src: ":face-example.xml",
+    sub_dir: "vintf",
+    installable: false,
+}
diff --git a/biometrics/face/aidl/default/apex/file_contexts b/biometrics/face/aidl/default/apex/file_contexts
new file mode 100644
index 0000000..4f935c1
--- /dev/null
+++ b/biometrics/face/aidl/default/apex/file_contexts
@@ -0,0 +1,3 @@
+(/.*)?                                          u:object_r:vendor_file:s0
+/etc(/.*)?                                      u:object_r:vendor_configs_file:s0
+/bin/hw/android\.hardware\.biometrics\.face-service\.example u:object_r:hal_face_default_exec:s0
\ No newline at end of file
diff --git a/biometrics/face/aidl/default/apex/manifest.json b/biometrics/face/aidl/default/apex/manifest.json
new file mode 100644
index 0000000..e7d177b
--- /dev/null
+++ b/biometrics/face/aidl/default/apex/manifest.json
@@ -0,0 +1,4 @@
+{
+    "name": "com.android.hardware.biometrics.face.virtual",
+    "version": 2
+}
diff --git a/biometrics/face/aidl/default/api/android.hardware.biometrics.face.VirtualProps-current.txt b/biometrics/face/aidl/default/api/android.hardware.biometrics.face.VirtualProps-current.txt
index 9548920..e69de29 100644
--- a/biometrics/face/aidl/default/api/android.hardware.biometrics.face.VirtualProps-current.txt
+++ b/biometrics/face/aidl/default/api/android.hardware.biometrics.face.VirtualProps-current.txt
@@ -1,98 +0,0 @@
-props {
-  owner: Vendor
-  module: "android.face.virt.FaceHalProperties"
-  prop {
-    api_name: "authenticator_id"
-    type: Long
-    access: ReadWrite
-    prop_name: "vendor.face.virtual.authenticator_id"
-  }
-  prop {
-    api_name: "challenge"
-    type: Long
-    access: ReadWrite
-    prop_name: "vendor.face.virtual.challenge"
-  }
-  prop {
-    api_name: "enrollment_hit"
-    type: Integer
-    access: ReadWrite
-    prop_name: "vendor.face.virtual.enrollment_hit"
-  }
-  prop {
-    api_name: "enrollments"
-    type: IntegerList
-    access: ReadWrite
-    prop_name: "persist.vendor.face.virtual.enrollments"
-  }
-  prop {
-    api_name: "features"
-    type: IntegerList
-    access: ReadWrite
-    prop_name: "persist.vendor.face.virtual.features"
-  }
-  prop {
-    api_name: "lockout"
-    access: ReadWrite
-    prop_name: "vendor.face.virtual.lockout"
-  }
-  prop {
-    api_name: "next_enrollment"
-    type: String
-    access: ReadWrite
-    prop_name: "vendor.face.virtual.next_enrollment"
-  }
-  prop {
-    api_name: "operation_authenticate_duration"
-    type: Integer
-    access: ReadWrite
-    prop_name: "vendor.face.virtual.operation_authenticate_duration"
-  }
-  prop {
-    api_name: "operation_authenticate_fails"
-    access: ReadWrite
-    prop_name: "vendor.face.virtual.operation_authenticate_fails"
-  }
-  prop {
-    api_name: "operation_authenticate_latency"
-    type: Integer
-    access: ReadWrite
-    prop_name: "vendor.face.virtual.operation_authenticate_latency"
-  }
-  prop {
-    api_name: "operation_detect_interaction_fails"
-    access: ReadWrite
-    prop_name: "vendor.face.virtual.operation_detect_interaction_fails"
-  }
-  prop {
-    api_name: "operation_detect_interaction_latency"
-    type: Integer
-    access: ReadWrite
-    prop_name: "vendor.face.virtual.operation_detect_interaction_latency"
-  }
-  prop {
-    api_name: "operation_enroll_fails"
-    access: ReadWrite
-    prop_name: "vendor.face.virtual.operation_enroll_fails"
-  }
-  prop {
-    api_name: "operation_start_enroll_latency"
-    type: Integer
-    access: ReadWrite
-    prop_name: "vendor.face.virtual.operation_start_enroll_latency"
-  }
-  prop {
-    api_name: "strength"
-    type: String
-    access: ReadWrite
-    prop_name: "persist.vendor.face.virtual.strength"
-    enum_values: "convenience|weak|strong"
-  }
-  prop {
-    api_name: "type"
-    type: String
-    access: ReadWrite
-    prop_name: "persist.vendor.face.virtual.type"
-    enum_values: "IR|RGB"
-  }
-}
diff --git a/biometrics/face/aidl/default/face-default.rc b/biometrics/face/aidl/default/face-default.rc
deleted file mode 100644
index f6499f0..0000000
--- a/biometrics/face/aidl/default/face-default.rc
+++ /dev/null
@@ -1,5 +0,0 @@
-service vendor.face-default /vendor/bin/hw/android.hardware.biometrics.face-service.example
-    class hal
-    user nobody
-    group nobody
-
diff --git a/biometrics/face/aidl/default/face-default.xml b/biometrics/face/aidl/default/face-default.xml
deleted file mode 100644
index 8f2fbb8..0000000
--- a/biometrics/face/aidl/default/face-default.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<manifest version="1.0" type="device">
-    <hal format="aidl">
-        <name>android.hardware.biometrics.face</name>
-        <version>3</version>
-        <fqname>IFace/default</fqname>
-    </hal>
-</manifest>
diff --git a/biometrics/face/aidl/default/face-example.rc b/biometrics/face/aidl/default/face-example.rc
new file mode 100644
index 0000000..b0d82c6
--- /dev/null
+++ b/biometrics/face/aidl/default/face-example.rc
@@ -0,0 +1,8 @@
+service vendor.face-example /vendor/bin/hw/android.hardware.biometrics.face-service.example
+    class hal
+    user nobody
+    group nobody
+    interface aidl android.hardware.biometrics.face.IFace/virtual
+    oneshot
+    disabled
+
diff --git a/biometrics/face/aidl/default/face-example.xml b/biometrics/face/aidl/default/face-example.xml
new file mode 100644
index 0000000..2b39b3d
--- /dev/null
+++ b/biometrics/face/aidl/default/face-example.xml
@@ -0,0 +1,7 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.biometrics.face</name>
+        <version>4</version>
+        <fqname>IFace/virtual</fqname>
+    </hal>
+</manifest>
diff --git a/biometrics/face/aidl/default/face.sysprop b/biometrics/face/aidl/default/face.sysprop
index 6b0f37f..997fd67 100644
--- a/biometrics/face/aidl/default/face.sysprop
+++ b/biometrics/face/aidl/default/face.sysprop
@@ -7,7 +7,7 @@
 prop {
     prop_name: "persist.vendor.face.virtual.type"
     type: String
-    scope: Public
+    scope: Internal
     access: ReadWrite
     enum_values: "IR|RGB"
     api_name: "type"
@@ -17,7 +17,7 @@
 prop {
     prop_name: "persist.vendor.face.virtual.strength"
     type: String
-    scope: Public
+    scope: Internal
     access: ReadWrite
     enum_values: "convenience|weak|strong"
     api_name: "strength"
@@ -27,7 +27,7 @@
 prop {
     prop_name: "persist.vendor.face.virtual.enrollments"
     type: IntegerList
-    scope: Public
+    scope: Internal
     access: ReadWrite
     api_name: "enrollments"
 }
@@ -36,7 +36,7 @@
 prop {
     prop_name: "persist.vendor.face.virtual.features"
     type: IntegerList
-    scope: Public
+    scope: Internal
     access: ReadWrite
     api_name: "features"
 }
@@ -46,20 +46,11 @@
 prop {
     prop_name: "vendor.face.virtual.enrollment_hit"
     type: Integer
-    scope: Public
+    scope: Internal
     access: ReadWrite
     api_name: "enrollment_hit"
 }
 
-# The initial latency for enrollment
-prop {
-    prop_name: "vendor.face.virtual.operation_start_enroll_latency"
-    type: Integer
-    scope: Public
-    access: ReadWrite
-    api_name: "operation_start_enroll_latency"
-}
-
 # the next enrollment in the format:
 # "<id>,<bucket_id>:<delay>:<succeeds>,<bucket_id>..."
 # for example: "0:1,0:100:1,1:200:1" indicating that bucket 0 took
@@ -69,7 +60,7 @@
 prop {
     prop_name: "vendor.face.virtual.next_enrollment"
     type: String
-    scope: Public
+    scope: Internal
     access: ReadWrite
     api_name: "next_enrollment"
 }
@@ -78,7 +69,7 @@
 prop {
     prop_name: "vendor.face.virtual.authenticator_id"
     type: Long
-    scope: Public
+    scope: Internal
     access: ReadWrite
     api_name: "authenticator_id"
 }
@@ -87,16 +78,16 @@
 prop {
     prop_name: "vendor.face.virtual.challenge"
     type: Long
-    scope: Public
+    scope: Internal
     access: ReadWrite
     api_name: "challenge"
 }
 
-# if locked out
+# if forced to lock out (Default to false)
 prop {
     prop_name: "vendor.face.virtual.lockout"
     type: Boolean
-    scope: Public
+    scope: Internal
     access: ReadWrite
     api_name: "lockout"
 }
@@ -105,7 +96,7 @@
 prop {
     prop_name: "vendor.face.virtual.operation_authenticate_fails"
     type: Boolean
-    scope: Public
+    scope: Internal
     access: ReadWrite
     api_name: "operation_authenticate_fails"
 }
@@ -114,7 +105,7 @@
 prop {
     prop_name: "vendor.face.virtual.operation_detect_interaction_fails"
     type: Boolean
-    scope: Public
+    scope: Internal
     access: ReadWrite
     api_name: "operation_detect_interaction_fails"
 }
@@ -123,7 +114,7 @@
 prop {
     prop_name: "vendor.face.virtual.operation_enroll_fails"
     type: Boolean
-    scope: Public
+    scope: Internal
     access: ReadWrite
     api_name: "operation_enroll_fails"
 }
@@ -133,8 +124,8 @@
 # the HAL will send AcquiredInfo::START and AcquiredInfo::FIRST_FRAME_RECEIVED
 prop {
     prop_name: "vendor.face.virtual.operation_authenticate_latency"
-    type: Integer
-    scope: Public
+    type: IntegerList
+    scope: Internal
     access: ReadWrite
     api_name: "operation_authenticate_latency"
 }
@@ -142,18 +133,90 @@
 # add a latency to detectInteraction operations
 prop {
     prop_name: "vendor.face.virtual.operation_detect_interaction_latency"
-    type: Integer
-    scope: Public
+    type: IntegerList
+    scope: Internal
     access: ReadWrite
     api_name: "operation_detect_interaction_latency"
 }
 
+# add a latency to enroll operations
+prop {
+    prop_name: "vendor.face.virtual.operation_enroll_latency"
+    type: IntegerList
+    scope: Internal
+    access: ReadWrite
+    api_name: "operation_enroll_latency"
+}
+
 # millisecond duration for authenticate operations
 # (waits for changes to enrollment_hit)
 prop {
     prop_name: "vendor.face.virtual.operation_authenticate_duration"
     type: Integer
-    scope: Public
+    scope: Internal
     access: ReadWrite
     api_name: "operation_authenticate_duration"
 }
+
+# insert error for authenticate operations
+prop {
+    prop_name: "vendor.face.virtual.operation_authenticate_error"
+    type: Integer
+    scope: Internal
+    access: ReadWrite
+    api_name: "operation_authenticate_error"
+}
+
+# acquired info during authentication in format of sequence
+prop {
+    prop_name: "vendor.face.virtual.operation_authenticate_acquired"
+    type: String
+    scope: Internal
+    access: ReadWrite
+    api_name: "operation_authenticate_acquired"
+}
+
+# whether support lockout based on the failed auth attempts (default: false)
+prop {
+    prop_name: "persist.vendor.face.virtual.lockout_enable"
+    type: Boolean
+    scope: Internal
+    access: ReadWrite
+    api_name: "lockout_enable"
+}
+
+# whether support timed_lockout based on the failed auth attempts (default: false)
+prop {
+    prop_name: "persist.vendor.face.virtual.lockout_timed_enable"
+    type: Boolean
+    scope: Internal
+    access: ReadWrite
+    api_name: "lockout_timed_enable"
+}
+
+# temperory lockout threshold  in number of consecutive failed auth attempts
+prop {
+    prop_name: "persist.vendor.face.virtual.lockout_timed_threshold"
+    type: Integer
+    scope: Internal
+    access: ReadWrite
+    api_name: "lockout_timed_threshold"
+}
+
+# temporary lockout duration in ms (default: 10000ms)
+prop {
+    prop_name: "persist.vendor.face.virtual.lockout_timed_duration"
+    type: Integer
+    scope: Internal
+    access: ReadWrite
+    api_name: "lockout_timed_duration"
+}
+
+# permanently lockout threshold  in number of consecutive failed auth attempts
+prop {
+    prop_name: "persist.vendor.face.virtual.lockout_permanent_threshold"
+    type: Integer
+    scope: Internal
+    access: ReadWrite
+    api_name: "lockout_permanent_threshold"
+}
diff --git a/biometrics/face/aidl/default/main.cpp b/biometrics/face/aidl/default/main.cpp
index b7274e3..38e1c63 100644
--- a/biometrics/face/aidl/default/main.cpp
+++ b/biometrics/face/aidl/default/main.cpp
@@ -27,9 +27,11 @@
     ABinderProcess_setThreadPoolMaxThreadCount(0);
     std::shared_ptr<Face> hal = ndk::SharedRefBase::make<Face>();
 
-    const std::string instance = std::string(Face::descriptor) + "/default";
-    binder_status_t status = AServiceManager_addService(hal->asBinder().get(), instance.c_str());
+    const std::string instance = std::string(Face::descriptor) + "/virtual";
+    binder_status_t status =
+            AServiceManager_registerLazyService(hal->asBinder().get(), instance.c_str());
     CHECK_EQ(status, STATUS_OK);
+    AServiceManager_forceLazyServicesPersist(true);
 
     ABinderProcess_joinThreadPool();
     return EXIT_FAILURE;  // should not reach
diff --git a/biometrics/face/aidl/default/tests/FakeFaceEngineTest.cpp b/biometrics/face/aidl/default/tests/FakeFaceEngineTest.cpp
index c8ad6b7..8c39b58 100644
--- a/biometrics/face/aidl/default/tests/FakeFaceEngineTest.cpp
+++ b/biometrics/face/aidl/default/tests/FakeFaceEngineTest.cpp
@@ -22,6 +22,7 @@
 #include <android-base/logging.h>
 
 #include "FakeFaceEngine.h"
+#include "util/Util.h"
 
 using namespace ::android::face::virt;
 using namespace ::aidl::android::hardware::biometrics::face;
@@ -45,6 +46,7 @@
     };
     ::ndk::ScopedAStatus onEnrollmentProgress(int32_t enrollmentId, int32_t remaining) override {
         if (remaining == 0) mLastEnrolled = enrollmentId;
+        mRemaining = remaining;
         return ndk::ScopedAStatus::ok();
     };
 
@@ -128,6 +130,7 @@
     bool mAuthenticatorIdInvalidated = false;
     bool mLockoutPermanent = false;
     int mInteractionDetectedCount = 0;
+    int mRemaining = -1;
 };
 
 class FakeFaceEngineTest : public ::testing::Test {
@@ -135,11 +138,15 @@
     void SetUp() override {
         LOG(ERROR) << "JRM SETUP";
         mCallback = ndk::SharedRefBase::make<TestSessionCallback>();
+    }
+
+    void TearDown() override {
         FaceHalProperties::enrollments({});
         FaceHalProperties::challenge({});
         FaceHalProperties::features({});
         FaceHalProperties::authenticator_id({});
         FaceHalProperties::strength("");
+        FaceHalProperties::operation_detect_interaction_latency({});
     }
 
     FakeFaceEngine mEngine;
@@ -193,7 +200,7 @@
 }
 
 TEST_F(FakeFaceEngineTest, Enroll) {
-    FaceHalProperties::next_enrollment("1,0:30:true,1:0:true,2:0:true,3:0:true,4:0:true");
+    FaceHalProperties::next_enrollment("1,0:1000-[21,5,6,7,1],1100-[1118,1108,1]:true");
     keymaster::HardwareAuthToken hat{.mac = {2, 4}};
     mEngine.enrollImpl(mCallback.get(), hat, {} /*enrollmentType*/, {} /*features*/,
                        mCancel.get_future());
@@ -201,10 +208,11 @@
     ASSERT_EQ(1, FaceHalProperties::enrollments().size());
     ASSERT_EQ(1, FaceHalProperties::enrollments()[0].value());
     ASSERT_EQ(1, mCallback->mLastEnrolled);
+    ASSERT_EQ(0, mCallback->mRemaining);
 }
 
 TEST_F(FakeFaceEngineTest, EnrollFails) {
-    FaceHalProperties::next_enrollment("1,0:30:true,1:0:true,2:0:true,3:0:true,4:0:false");
+    FaceHalProperties::next_enrollment("1,0:1000-[21,5,6,7,1],1100-[1118,1108,1]:false");
     keymaster::HardwareAuthToken hat{.mac = {2, 4}};
     mEngine.enrollImpl(mCallback.get(), hat, {} /*enrollmentType*/, {} /*features*/,
                        mCancel.get_future());
@@ -213,7 +221,7 @@
 }
 
 TEST_F(FakeFaceEngineTest, EnrollCancel) {
-    FaceHalProperties::next_enrollment("1,0:30:true,1:0:true,2:0:true,3:0:true,4:0:false");
+    FaceHalProperties::next_enrollment("1:2000-[21,8,9],300:false");
     keymaster::HardwareAuthToken hat{.mac = {2, 4}};
     mCancel.set_value();
     mEngine.enrollImpl(mCallback.get(), hat, {} /*enrollmentType*/, {} /*features*/,
@@ -221,7 +229,7 @@
     ASSERT_EQ(Error::CANCELED, mCallback->mError);
     ASSERT_EQ(-1, mCallback->mLastEnrolled);
     ASSERT_EQ(0, FaceHalProperties::enrollments().size());
-    ASSERT_FALSE(FaceHalProperties::next_enrollment().has_value());
+    ASSERT_TRUE(FaceHalProperties::next_enrollment().has_value());
 }
 
 TEST_F(FakeFaceEngineTest, Authenticate) {
@@ -245,7 +253,7 @@
     FaceHalProperties::enrollments({3});
     FaceHalProperties::enrollment_hit(100);
     mEngine.authenticateImpl(mCallback.get(), 0 /* operationId*/, mCancel.get_future());
-    ASSERT_EQ(Error::UNABLE_TO_PROCESS, mCallback->mError);
+    ASSERT_EQ(Error::TIMEOUT, mCallback->mError);
     ASSERT_TRUE(mCallback->mAuthenticateFailed);
 }
 
@@ -380,4 +388,26 @@
     ASSERT_FALSE(mCallback->mAuthenticateFailed);
 }
 
-}  // namespace aidl::android::hardware::biometrics::face
\ No newline at end of file
+TEST_F(FakeFaceEngineTest, LatencyDefault) {
+    FaceHalProperties::operation_detect_interaction_latency({});
+    ASSERT_EQ(DEFAULT_LATENCY,
+              mEngine.getLatency(FaceHalProperties::operation_detect_interaction_latency()));
+}
+
+TEST_F(FakeFaceEngineTest, LatencyFixed) {
+    FaceHalProperties::operation_detect_interaction_latency({10});
+    ASSERT_EQ(10, mEngine.getLatency(FaceHalProperties::operation_detect_interaction_latency()));
+}
+
+TEST_F(FakeFaceEngineTest, LatencyRandom) {
+    FaceHalProperties::operation_detect_interaction_latency({1, 1000});
+    std::set<int32_t> latencySet;
+    for (int i = 0; i < 100; i++) {
+        auto x = mEngine.getLatency(FaceHalProperties::operation_detect_interaction_latency());
+        ASSERT_TRUE(x >= 1 && x <= 1000);
+        latencySet.insert(x);
+    }
+    ASSERT_TRUE(latencySet.size() > 95);  // unique values
+}
+
+}  // namespace aidl::android::hardware::biometrics::face
diff --git a/biometrics/face/aidl/default/tests/FakeLockoutTrackerTest.cpp b/biometrics/face/aidl/default/tests/FakeLockoutTrackerTest.cpp
new file mode 100644
index 0000000..fa07d1d
--- /dev/null
+++ b/biometrics/face/aidl/default/tests/FakeLockoutTrackerTest.cpp
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/android/hardware/biometrics/face/BnSessionCallback.h>
+#include <android/binder_process.h>
+#include <face.sysprop.h>
+#include <gtest/gtest.h>
+
+#include <android-base/logging.h>
+
+#include "FakeLockoutTracker.h"
+#include "util/Util.h"
+
+using namespace ::android::face::virt;
+using namespace ::aidl::android::hardware::biometrics::face;
+
+namespace aidl::android::hardware::biometrics::face {
+
+class TestSessionCallback : public BnSessionCallback {
+  public:
+    ndk::ScopedAStatus onChallengeGenerated(int64_t /*challenge*/) override {
+        return ndk::ScopedAStatus::ok();
+    };
+    ::ndk::ScopedAStatus onChallengeRevoked(int64_t /*challenge*/) override {
+        return ndk::ScopedAStatus::ok();
+    };
+    ::ndk::ScopedAStatus onError(face::Error, int32_t /*vendorCode*/) override {
+        return ndk::ScopedAStatus::ok();
+    };
+    ::ndk::ScopedAStatus onEnrollmentProgress(int32_t /*enrollmentId*/,
+                                              int32_t /*remaining*/) override {
+        return ndk::ScopedAStatus::ok();
+    };
+    ::ndk::ScopedAStatus onAuthenticationSucceeded(int32_t /*enrollmentId*/,
+                                                   const keymaster::HardwareAuthToken&) override {
+        return ndk::ScopedAStatus::ok();
+    };
+    ::ndk::ScopedAStatus onAuthenticationFailed() override { return ndk::ScopedAStatus::ok(); };
+    ::ndk::ScopedAStatus onInteractionDetected() override { return ndk::ScopedAStatus::ok(); };
+    ::ndk::ScopedAStatus onEnrollmentsEnumerated(const std::vector<int32_t>&) override {
+        return ndk::ScopedAStatus::ok();
+    };
+    ::ndk::ScopedAStatus onEnrollmentsRemoved(
+            const std::vector<int32_t>& /*enrollmentIds*/) override {
+        return ndk::ScopedAStatus::ok();
+    };
+    ::ndk::ScopedAStatus onAuthenticatorIdRetrieved(int64_t /*authenticatorId*/) override {
+        return ndk::ScopedAStatus::ok();
+    };
+    ::ndk::ScopedAStatus onAuthenticatorIdInvalidated(int64_t /*authenticatorId*/) override {
+        return ndk::ScopedAStatus::ok();
+    };
+    ::ndk::ScopedAStatus onEnrollmentFrame(const EnrollmentFrame&) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onFeaturesRetrieved(const std::vector<Feature>&) {
+        return ndk::ScopedAStatus::ok();
+    };
+    ::ndk::ScopedAStatus onFeatureSet(Feature) override { return ndk::ScopedAStatus::ok(); }
+    ::ndk::ScopedAStatus onSessionClosed() override { return ndk::ScopedAStatus::ok(); }
+    ::ndk::ScopedAStatus onAuthenticationFrame(const AuthenticationFrame&) override {
+        return ndk::ScopedAStatus::ok();
+    }
+
+    ndk::ScopedAStatus onLockoutTimed(int64_t timeLeft) override {
+        mLockoutTimed++;
+        mTimeLeft = timeLeft;
+        return ndk::ScopedAStatus::ok();
+    };
+    ::ndk::ScopedAStatus onLockoutPermanent() override {
+        mLockoutPermanent++;
+        return ndk::ScopedAStatus::ok();
+    };
+    ::ndk::ScopedAStatus onLockoutCleared() override {
+        mTimeLeft = 0;
+        mLockoutTimed = 0;
+        mLockoutPermanent = 0;
+        return ndk::ScopedAStatus::ok();
+    };
+
+    int64_t mTimeLeft = 0;
+    int mLockoutTimed = 0;
+    int mLockoutPermanent = 0;
+};
+
+class FakeLockoutTrackerTest : public ::testing::Test {
+  protected:
+    static constexpr int32_t LOCKOUT_TIMED_THRESHOLD = 3;
+    static constexpr int32_t LOCKOUT_PERMANENT_THRESHOLD = 5;
+    static constexpr int32_t LOCKOUT_TIMED_DURATION = 100;
+
+    void SetUp() override {
+        FaceHalProperties::lockout_timed_threshold(LOCKOUT_TIMED_THRESHOLD);
+        FaceHalProperties::lockout_timed_duration(LOCKOUT_TIMED_DURATION);
+        FaceHalProperties::lockout_permanent_threshold(LOCKOUT_PERMANENT_THRESHOLD);
+        mCallback = ndk::SharedRefBase::make<TestSessionCallback>();
+    }
+
+    void TearDown() override {
+        // reset to default
+        FaceHalProperties::lockout_timed_threshold(5);
+        FaceHalProperties::lockout_timed_duration(20);
+        FaceHalProperties::lockout_permanent_threshold(10000);
+        FaceHalProperties::lockout_enable(false);
+        FaceHalProperties::lockout(false);
+    }
+
+    FakeLockoutTracker mLockoutTracker;
+    std::shared_ptr<TestSessionCallback> mCallback;
+};
+
+TEST_F(FakeLockoutTrackerTest, addFailedAttemptDisable) {
+    FaceHalProperties::lockout_enable(false);
+    for (int i = 0; i < LOCKOUT_TIMED_THRESHOLD + 1; i++)
+        mLockoutTracker.addFailedAttempt(mCallback.get());
+    ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kNone);
+    ASSERT_EQ(0, mCallback->mLockoutTimed);
+}
+
+TEST_F(FakeLockoutTrackerTest, addFailedAttemptPermanent) {
+    FaceHalProperties::lockout_enable(true);
+    ASSERT_FALSE(mLockoutTracker.checkIfLockout(mCallback.get()));
+    for (int i = 0; i < LOCKOUT_PERMANENT_THRESHOLD - 1; i++)
+        mLockoutTracker.addFailedAttempt(mCallback.get());
+    ASSERT_NE(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kPermanent);
+    ASSERT_EQ(0, mCallback->mLockoutPermanent);
+    mLockoutTracker.addFailedAttempt(mCallback.get());
+    ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kPermanent);
+    ASSERT_EQ(1, mCallback->mLockoutPermanent);
+    ASSERT_TRUE(mLockoutTracker.checkIfLockout(mCallback.get()));
+    ASSERT_EQ(2, mCallback->mLockoutPermanent);
+}
+
+TEST_F(FakeLockoutTrackerTest, addFailedAttemptLockoutTimed) {
+    FaceHalProperties::lockout_enable(true);
+    FaceHalProperties::lockout_timed_enable(true);
+    ASSERT_FALSE(mLockoutTracker.checkIfLockout(mCallback.get()));
+    for (int i = 0; i < LOCKOUT_TIMED_THRESHOLD; i++)
+        mLockoutTracker.addFailedAttempt(mCallback.get());
+    ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kTimed);
+    ASSERT_EQ(1, mCallback->mLockoutTimed);
+    ASSERT_TRUE(mLockoutTracker.checkIfLockout(mCallback.get()));
+    ASSERT_EQ(2, mCallback->mLockoutTimed);
+    // time left
+    int N = 5;
+    int64_t prevTimeLeft = INT_MAX;
+    for (int i = 0; i < N; i++) {
+        SLEEP_MS(LOCKOUT_TIMED_DURATION / N + 1);
+        int64_t currTimeLeft = mLockoutTracker.getLockoutTimeLeft();
+        ASSERT_TRUE(currTimeLeft < prevTimeLeft);
+        prevTimeLeft = currTimeLeft;
+    }
+    SLEEP_MS(LOCKOUT_TIMED_DURATION / N);
+    ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kNone);
+}
+
+TEST_F(FakeLockoutTrackerTest, addFailedAttemptLockout_TimedThenPermanent) {
+    FaceHalProperties::lockout_enable(true);
+    FaceHalProperties::lockout_timed_enable(true);
+    ASSERT_FALSE(mLockoutTracker.checkIfLockout(mCallback.get()));
+    for (int i = 0; i < LOCKOUT_TIMED_THRESHOLD; i++)
+        mLockoutTracker.addFailedAttempt(mCallback.get());
+    ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kTimed);
+    SLEEP_MS(LOCKOUT_TIMED_DURATION + 20);
+    ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kNone);
+    for (int i = 0; i < LOCKOUT_PERMANENT_THRESHOLD - LOCKOUT_TIMED_THRESHOLD; i++)
+        mLockoutTracker.addFailedAttempt(mCallback.get());
+    ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kPermanent);
+}
+
+TEST_F(FakeLockoutTrackerTest, addFailedAttemptLockoutTimedTwice) {
+    FaceHalProperties::lockout_enable(true);
+    FaceHalProperties::lockout_timed_enable(true);
+    ASSERT_FALSE(mLockoutTracker.checkIfLockout(mCallback.get()));
+    ASSERT_EQ(0, mCallback->mLockoutTimed);
+    for (int i = 0; i < LOCKOUT_TIMED_THRESHOLD; i++)
+        mLockoutTracker.addFailedAttempt(mCallback.get());
+    SLEEP_MS(LOCKOUT_TIMED_DURATION / 2);
+    mLockoutTracker.addFailedAttempt(mCallback.get());
+    SLEEP_MS(LOCKOUT_TIMED_DURATION);
+    ASSERT_EQ(2, mCallback->mLockoutTimed);
+    ASSERT_TRUE(mLockoutTracker.checkIfLockout(mCallback.get()));
+    SLEEP_MS(LOCKOUT_TIMED_DURATION);
+    ASSERT_FALSE(mLockoutTracker.checkIfLockout(mCallback.get()));
+}
+
+TEST_F(FakeLockoutTrackerTest, resetLockout) {
+    FaceHalProperties::lockout_enable(true);
+    ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kNone);
+    for (int i = 0; i < LOCKOUT_PERMANENT_THRESHOLD; i++)
+        mLockoutTracker.addFailedAttempt(mCallback.get());
+    ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kPermanent);
+    mLockoutTracker.reset();
+    ASSERT_FALSE(mLockoutTracker.checkIfLockout(mCallback.get()));
+}
+
+}  // namespace aidl::android::hardware::biometrics::face
+
+int main(int argc, char** argv) {
+    testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/biometrics/fingerprint/aidl/Android.bp b/biometrics/fingerprint/aidl/Android.bp
index c543a93..1a099a5 100644
--- a/biometrics/fingerprint/aidl/Android.bp
+++ b/biometrics/fingerprint/aidl/Android.bp
@@ -14,7 +14,7 @@
         "android/hardware/biometrics/fingerprint/**/*.aidl",
     ],
     imports: [
-        "android.hardware.biometrics.common-V3",
+        "android.hardware.biometrics.common-V4",
         "android.hardware.keymaster-V4",
     ],
     stability: "vintf",
@@ -50,5 +50,5 @@
         },
 
     ],
-    frozen: true,
+    frozen: false,
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISession.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISession.aidl
index 4fdcefc..feb6ba3 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISession.aidl
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISession.aidl
@@ -62,5 +62,8 @@
   void onPointerUpWithContext(in android.hardware.biometrics.fingerprint.PointerContext context);
   void onContextChanged(in android.hardware.biometrics.common.OperationContext context);
   void onPointerCancelWithContext(in android.hardware.biometrics.fingerprint.PointerContext context);
+  /**
+   * @deprecated use isHardwareIgnoringTouches in OperationContext from onContextChanged instead
+   */
   void setIgnoreDisplayTouches(in boolean shouldIgnore);
 }
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISession.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISession.aidl
index 83e7bbc..07e22c2 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISession.aidl
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISession.aidl
@@ -544,6 +544,8 @@
      * whenever it's appropriate.
      *
      * @param shouldIgnore whether the display touches should be ignored.
+
+     * @deprecated use isHardwareIgnoringTouches in OperationContext from onContextChanged instead
      */
     void setIgnoreDisplayTouches(in boolean shouldIgnore);
 }
diff --git a/biometrics/fingerprint/aidl/default/Android.bp b/biometrics/fingerprint/aidl/default/Android.bp
index 16302eb..c3ec4d0 100644
--- a/biometrics/fingerprint/aidl/default/Android.bp
+++ b/biometrics/fingerprint/aidl/default/Android.bp
@@ -11,8 +11,6 @@
     name: "android.hardware.biometrics.fingerprint-service.example",
     vendor: true,
     relative_install_path: "hw",
-    init_rc: ["fingerprint-example.rc"],
-    vintf_fragments: ["fingerprint-example.xml"],
     local_include_dirs: ["include"],
     srcs: [
         "FakeLockoutTracker.cpp",
@@ -24,15 +22,21 @@
         "Session.cpp",
         "main.cpp",
     ],
+    stl: "c++_static",
     shared_libs: [
-        "libbase",
         "libbinder_ndk",
-        "android.hardware.biometrics.fingerprint-V3-ndk",
-        "android.hardware.biometrics.common-V3-ndk",
+        "liblog",
+    ],
+    static_libs: [
+        "libandroid.hardware.biometrics.fingerprint.VirtualProps",
+        "libbase",
+        "android.hardware.biometrics.fingerprint-V4-ndk",
+        "android.hardware.biometrics.common-V4-ndk",
         "android.hardware.biometrics.common.thread",
         "android.hardware.biometrics.common.util",
+        "android.hardware.keymaster-V4-ndk",
     ],
-    static_libs: ["libandroid.hardware.biometrics.fingerprint.VirtualProps"],
+    installable: false, // install APEX instead
 }
 
 cc_test {
@@ -50,8 +54,8 @@
     ],
     static_libs: [
         "libandroid.hardware.biometrics.fingerprint.VirtualProps",
-        "android.hardware.biometrics.fingerprint-V3-ndk",
-        "android.hardware.biometrics.common-V3-ndk",
+        "android.hardware.biometrics.fingerprint-V4-ndk",
+        "android.hardware.biometrics.common-V4-ndk",
         "android.hardware.keymaster-V4-ndk",
         "android.hardware.biometrics.common.util",
     ],
@@ -76,8 +80,8 @@
     ],
     static_libs: [
         "libandroid.hardware.biometrics.fingerprint.VirtualProps",
-        "android.hardware.biometrics.fingerprint-V3-ndk",
-        "android.hardware.biometrics.common-V3-ndk",
+        "android.hardware.biometrics.fingerprint-V4-ndk",
+        "android.hardware.biometrics.common-V4-ndk",
         "android.hardware.keymaster-V4-ndk",
         "android.hardware.biometrics.common.util",
     ],
@@ -100,8 +104,8 @@
     ],
     static_libs: [
         "libandroid.hardware.biometrics.fingerprint.VirtualProps",
-        "android.hardware.biometrics.fingerprint-V3-ndk",
-        "android.hardware.biometrics.common-V3-ndk",
+        "android.hardware.biometrics.fingerprint-V4-ndk",
+        "android.hardware.biometrics.common-V4-ndk",
         "android.hardware.keymaster-V4-ndk",
         "android.hardware.biometrics.common.util",
     ],
@@ -126,8 +130,8 @@
     ],
     static_libs: [
         "libandroid.hardware.biometrics.fingerprint.VirtualProps",
-        "android.hardware.biometrics.fingerprint-V3-ndk",
-        "android.hardware.biometrics.common-V3-ndk",
+        "android.hardware.biometrics.fingerprint-V4-ndk",
+        "android.hardware.biometrics.common-V4-ndk",
         "android.hardware.keymaster-V4-ndk",
         "android.hardware.biometrics.common.util",
     ],
@@ -142,3 +146,36 @@
     property_owner: "Vendor",
     vendor: true,
 }
+
+prebuilt_etc {
+    name: "fingerprint-example.rc",
+    src: "fingerprint-example.rc",
+    installable: false,
+}
+
+prebuilt_etc {
+    name: "fingerprint-example.xml",
+    src: "fingerprint-example.xml",
+    sub_dir: "vintf",
+    installable: false,
+}
+
+apex {
+    name: "com.android.hardware.biometrics.fingerprint.virtual",
+    manifest: "apex_manifest.json",
+    file_contexts: "apex_file_contexts",
+    key: "com.android.hardware.key",
+    certificate: ":com.android.hardware.certificate",
+    updatable: false,
+    vendor: true,
+
+    binaries: [
+        "android.hardware.biometrics.fingerprint-service.example",
+    ],
+    prebuilts: [
+        // init_rc
+        "fingerprint-example.rc",
+        // vintf_fragment
+        "fingerprint-example.xml",
+    ],
+}
diff --git a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
index 54076c8..a7acf3d 100644
--- a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
+++ b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
@@ -32,7 +32,9 @@
 namespace aidl::android::hardware::biometrics::fingerprint {
 
 FakeFingerprintEngine::FakeFingerprintEngine()
-    : mRandom(std::mt19937::default_seed), mWorkMode(WorkMode::kIdle) {}
+    : mRandom(std::mt19937::default_seed),
+      mWorkMode(WorkMode::kIdle),
+      isLockoutTimerSupported(true) {}
 
 void FakeFingerprintEngine::generateChallengeImpl(ISessionCallback* cb) {
     BEGIN_OP(0);
@@ -60,12 +62,17 @@
         return;
     }
 
+    waitForFingerDown(cb, cancel);
+
     updateContext(WorkMode::kEnroll, cb, const_cast<std::future<void>&>(cancel), 0, hat);
 }
 
 void FakeFingerprintEngine::authenticateImpl(ISessionCallback* cb, int64_t operationId,
                                              const std::future<void>& cancel) {
     BEGIN_OP(0);
+
+    waitForFingerDown(cb, cancel);
+
     updateContext(WorkMode::kAuthenticate, cb, const_cast<std::future<void>&>(cancel), operationId,
                   keymaster::HardwareAuthToken());
 }
@@ -82,6 +89,8 @@
         return;
     }
 
+    waitForFingerDown(cb, cancel);
+
     updateContext(WorkMode::kDetectInteract, cb, const_cast<std::future<void>&>(cancel), 0,
                   keymaster::HardwareAuthToken());
 }
@@ -142,7 +151,7 @@
         return true;
     }
     auto enrollmentId = std::stoi(parts[0]);
-    auto progress = parseEnrollmentCapture(parts[1]);
+    auto progress = Util::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];
@@ -193,7 +202,7 @@
     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);
+    auto acquiredInfos = Util::parseIntSequence(acquired);
     int N = acquiredInfos.size();
 
     if (N == 0) {
@@ -271,7 +280,7 @@
             FingerprintHalProperties::operation_detect_interaction_duration().value_or(10);
 
     auto acquired = FingerprintHalProperties::operation_detect_interaction_acquired().value_or("1");
-    auto acquiredInfos = parseIntSequence(acquired);
+    auto acquiredInfos = Util::parseIntSequence(acquired);
     int N = acquiredInfos.size();
     int64_t now = Util::getSystemNanoTime();
 
@@ -305,15 +314,6 @@
         SLEEP_MS(duration / N);
     } while (!Util::hasElapsed(now, duration));
 
-    auto id = FingerprintHalProperties::enrollment_hit().value_or(0);
-    auto enrolls = FingerprintHalProperties::enrollments();
-    auto isEnrolled = std::find(enrolls.begin(), enrolls.end(), id) != enrolls.end();
-    if (id <= 0 || !isEnrolled) {
-        LOG(ERROR) << "Fail: not enrolled";
-        cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
-        return true;
-    }
-
     cb->onInteractionDetected();
 
     return true;
@@ -386,7 +386,7 @@
         return;
     }
     clearLockout(cb);
-    isLockoutTimerAborted = true;
+    if (isLockoutTimerStarted) isLockoutTimerAborted = true;
 }
 
 void FakeFingerprintEngine::clearLockout(ISessionCallback* cb) {
@@ -405,6 +405,7 @@
 
 ndk::ScopedAStatus FakeFingerprintEngine::onPointerUpImpl(int32_t /*pointerId*/) {
     BEGIN_OP(0);
+    mFingerIsDown = false;
     return ndk::ScopedAStatus::ok();
 }
 
@@ -450,76 +451,6 @@
     return SensorLocation();
 }
 
-std::vector<int32_t> FakeFingerprintEngine::parseIntSequence(const std::string& str,
-                                                             const std::string& sep) {
-    std::vector<std::string> seqs = Util::split(str, sep);
-    std::vector<int32_t> res;
-
-    for (const auto& seq : seqs) {
-        int32_t val;
-        if (ParseInt(seq, &val)) {
-            res.push_back(val);
-        } else {
-            LOG(WARNING) << "Invalid int sequence:" + str;
-            res.clear();
-            break;
-        }
-    }
-
-    return res;
-}
-
-bool FakeFingerprintEngine::parseEnrollmentCaptureSingle(const std::string& str,
-                                                         std::vector<std::vector<int32_t>>& res) {
-    std::vector<int32_t> defaultAcquiredInfo = {(int32_t)AcquiredInfo::GOOD};
-    bool aborted = true;
-
-    do {
-        std::smatch sms;
-        // Parses strings like "1000-[5,1]" or "500"
-        std::regex ex("((\\d+)(-\\[([\\d|,]+)\\])?)");
-        if (!regex_match(str.cbegin(), str.cend(), sms, ex)) break;
-        int32_t duration;
-        if (!ParseInt(sms.str(2), &duration)) break;
-        res.push_back({duration});
-        if (!sms.str(4).empty()) {
-            auto acqv = parseIntSequence(sms.str(4));
-            if (acqv.empty()) break;
-            res.push_back(acqv);
-        } else
-            res.push_back(defaultAcquiredInfo);
-        aborted = false;
-    } while (0);
-
-    return !aborted;
-}
-
-std::vector<std::vector<int32_t>> FakeFingerprintEngine::parseEnrollmentCapture(
-        const std::string& str) {
-    std::vector<std::vector<int32_t>> res;
-
-    std::string s(str);
-    s.erase(std::remove_if(s.begin(), s.end(), ::isspace), s.end());
-    bool aborted = false;
-    std::smatch sms;
-    // Parses strings like "1000-[5,1],500,800-[6,5,1]"
-    //                      ---------- --- -----------
-    //  into parts:             A       B       C
-    while (regex_search(s, sms, std::regex("^(,)?(\\d+(-\\[[\\d|,]+\\])?)"))) {
-        if (!parseEnrollmentCaptureSingle(sms.str(2), res)) {
-            aborted = true;
-            break;
-        }
-        s = sms.suffix();
-    }
-    if (aborted || s.length() != 0) {
-        res.clear();
-        LOG(ERROR) << "Failed to parse enrollment captures:" + str;
-    }
-
-    return res;
-}
-
 std::pair<AcquiredInfo, int32_t> FakeFingerprintEngine::convertAcquiredInfo(int32_t code) {
     std::pair<AcquiredInfo, int32_t> res;
     if (code > FINGERPRINT_ACQUIRED_VENDOR_BASE) {
@@ -603,10 +534,24 @@
     isLockoutTimerStarted = true;
 }
 void FakeFingerprintEngine::lockoutTimerExpired(ISessionCallback* cb) {
+    BEGIN_OP(0);
     if (!isLockoutTimerAborted) {
         clearLockout(cb);
     }
     isLockoutTimerStarted = false;
     isLockoutTimerAborted = false;
 }
+
+void FakeFingerprintEngine::waitForFingerDown(ISessionCallback* cb,
+                                              const std::future<void>& cancel) {
+    while (!mFingerIsDown) {
+        if (shouldCancel(cancel)) {
+            LOG(ERROR) << "waitForFingerDown, Fail: cancel";
+            cb->onError(Error::CANCELED, 0 /* vendorCode */);
+            return;
+        }
+        SLEEP_MS(10);
+    }
+}
+
 }  // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/FakeFingerprintEngineSide.cpp b/biometrics/fingerprint/aidl/default/FakeFingerprintEngineSide.cpp
index a78cdcd..acb792d 100644
--- a/biometrics/fingerprint/aidl/default/FakeFingerprintEngineSide.cpp
+++ b/biometrics/fingerprint/aidl/default/FakeFingerprintEngineSide.cpp
@@ -27,9 +27,7 @@
 
 namespace aidl::android::hardware::biometrics::fingerprint {
 
-FakeFingerprintEngineSide::FakeFingerprintEngineSide() : FakeFingerprintEngine() {
-    isLockoutTimerSupported = true;
-}
+FakeFingerprintEngineSide::FakeFingerprintEngineSide() : FakeFingerprintEngine() {}
 
 SensorLocation FakeFingerprintEngineSide::defaultSensorLocation() {
     return SensorLocation{.sensorLocationX = defaultSensorLocationX,
diff --git a/biometrics/fingerprint/aidl/default/README.md b/biometrics/fingerprint/aidl/default/README.md
index 49b6c9d..4b4533a 100644
--- a/biometrics/fingerprint/aidl/default/README.md
+++ b/biometrics/fingerprint/aidl/default/README.md
@@ -11,7 +11,7 @@
 following to your device's `.mk` file to include it:
 
 ```
-PRODUCT_PACKAGES_DEBUG += android.hardware.biometrics.fingerprint-service.example
+PRODUCT_PACKAGES_DEBUG += com.android.hardware.biometrics.fingerprint.virtual
 ```
 
 The virtual HAL will be ignored if a real HAL is also installed on the target
diff --git a/biometrics/fingerprint/aidl/default/Session.cpp b/biometrics/fingerprint/aidl/default/Session.cpp
index c06c931..0dd6603 100644
--- a/biometrics/fingerprint/aidl/default/Session.cpp
+++ b/biometrics/fingerprint/aidl/default/Session.cpp
@@ -249,6 +249,7 @@
 ndk::ScopedAStatus Session::onPointerDown(int32_t pointerId, int32_t x, int32_t y, float minor,
                                           float major) {
     LOG(INFO) << "onPointerDown";
+    mEngine->notifyFingerdown();
     mWorker->schedule(Callable::from([this, pointerId, x, y, minor, major] {
         mEngine->onPointerDownImpl(pointerId, x, y, minor, major);
         enterIdling();
diff --git a/biometrics/fingerprint/aidl/default/apex_file_contexts b/biometrics/fingerprint/aidl/default/apex_file_contexts
new file mode 100644
index 0000000..1c189fc
--- /dev/null
+++ b/biometrics/fingerprint/aidl/default/apex_file_contexts
@@ -0,0 +1,3 @@
+(/.*)?                                          u:object_r:vendor_file:s0
+/etc(/.*)?                                      u:object_r:vendor_configs_file:s0
+/bin/hw/android\.hardware\.biometrics\.fingerprint-service\.example u:object_r:hal_fingerprint_default_exec:s0
\ No newline at end of file
diff --git a/biometrics/fingerprint/aidl/default/apex_manifest.json b/biometrics/fingerprint/aidl/default/apex_manifest.json
new file mode 100644
index 0000000..bbd2c69
--- /dev/null
+++ b/biometrics/fingerprint/aidl/default/apex_manifest.json
@@ -0,0 +1,4 @@
+{
+    "name": "com.android.hardware.biometrics.fingerprint.virtual",
+    "version": 1
+}
diff --git a/biometrics/fingerprint/aidl/default/fingerprint-example.rc b/biometrics/fingerprint/aidl/default/fingerprint-example.rc
index ee4713c..da4ea45 100644
--- a/biometrics/fingerprint/aidl/default/fingerprint-example.rc
+++ b/biometrics/fingerprint/aidl/default/fingerprint-example.rc
@@ -1,4 +1,4 @@
-service vendor.fingerprint-example /vendor/bin/hw/android.hardware.biometrics.fingerprint-service.example
+service vendor.fingerprint-example /apex/com.android.hardware.biometrics.fingerprint.virtual/bin/hw/android.hardware.biometrics.fingerprint-service.example
     class hal
     user nobody
     group nobody
diff --git a/biometrics/fingerprint/aidl/default/fingerprint-example.xml b/biometrics/fingerprint/aidl/default/fingerprint-example.xml
index e977b98..827813f 100644
--- a/biometrics/fingerprint/aidl/default/fingerprint-example.xml
+++ b/biometrics/fingerprint/aidl/default/fingerprint-example.xml
@@ -1,7 +1,7 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.biometrics.fingerprint</name>
-        <version>3</version>
+        <version>4</version>
         <fqname>IFingerprint/virtual</fqname>
     </hal>
 </manifest>
diff --git a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
index 2450115..0d53575 100644
--- a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
+++ b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
@@ -68,10 +68,6 @@
 
     virtual void fingerDownAction();
 
-    std::vector<int32_t> parseIntSequence(const std::string& str, const std::string& sep = ",");
-
-    std::vector<std::vector<int32_t>> parseEnrollmentCapture(const std::string& str);
-
     int32_t getLatency(const std::vector<std::optional<std::int32_t>>& latencyVec);
 
     std::mt19937 mRandom;
@@ -79,6 +75,7 @@
     enum class WorkMode : int8_t { kIdle = 0, kAuthenticate, kEnroll, kDetectInteract };
 
     WorkMode getWorkMode() { return mWorkMode; }
+    void notifyFingerdown() { mFingerIsDown = true; }
 
     virtual std::string toString() const {
         std::ostringstream os;
@@ -104,17 +101,17 @@
     keymaster::HardwareAuthToken mHat;
     std::future<void> mCancel;
     int64_t mOperationId;
+    bool mFingerIsDown;
 
   private:
     static constexpr int32_t FINGERPRINT_ACQUIRED_VENDOR_BASE = 1000;
     static constexpr int32_t FINGERPRINT_ERROR_VENDOR_BASE = 1000;
     std::pair<AcquiredInfo, int32_t> convertAcquiredInfo(int32_t code);
     std::pair<Error, int32_t> convertError(int32_t code);
-    bool parseEnrollmentCaptureSingle(const std::string& str,
-                                      std::vector<std::vector<int32_t>>& res);
     int32_t getRandomInRange(int32_t bound1, int32_t bound2);
     bool checkSensorLockout(ISessionCallback*);
     void clearLockout(ISessionCallback* cb);
+    void waitForFingerDown(ISessionCallback* cb, const std::future<void>& cancel);
 
     FakeLockoutTracker mLockoutTracker;
 
diff --git a/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp b/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp
index fe405f4..8b06c8e 100644
--- a/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp
+++ b/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp
@@ -185,6 +185,7 @@
     FingerprintHalProperties::enrollments({});
     FingerprintHalProperties::next_enrollment("4:0,0:true");
     keymaster::HardwareAuthToken hat{.mac = {2, 4}};
+    mEngine.notifyFingerdown();
     mEngine.enrollImpl(mCallback.get(), hat, mCancel.get_future());
     ASSERT_EQ(mEngine.getWorkMode(), FakeFingerprintEngine::WorkMode::kEnroll);
     mEngine.fingerDownAction();
@@ -202,6 +203,7 @@
     FingerprintHalProperties::next_enrollment(next);
     keymaster::HardwareAuthToken hat{.mac = {2, 4}};
     mCancel.set_value();
+    mEngine.notifyFingerdown();
     mEngine.enrollImpl(mCallback.get(), hat, mCancel.get_future());
     mEngine.fingerDownAction();
     ASSERT_EQ(Error::CANCELED, mCallback->mError);
@@ -215,6 +217,7 @@
     auto next = "2:0,0:false";
     FingerprintHalProperties::next_enrollment(next);
     keymaster::HardwareAuthToken hat{.mac = {2, 4}};
+    mEngine.notifyFingerdown();
     mEngine.enrollImpl(mCallback.get(), hat, mCancel.get_future());
     mEngine.fingerDownAction();
     ASSERT_EQ(Error::UNABLE_TO_PROCESS, mCallback->mError);
@@ -228,6 +231,7 @@
     FingerprintHalProperties::next_enrollment("4:0,5-[12,1013]:true");
     keymaster::HardwareAuthToken hat{.mac = {2, 4}};
     int32_t prevCnt = mCallback->mLastAcquiredCount;
+    mEngine.notifyFingerdown();
     mEngine.enrollImpl(mCallback.get(), hat, mCancel.get_future());
     mEngine.fingerDownAction();
     ASSERT_FALSE(FingerprintHalProperties::next_enrollment().has_value());
@@ -242,6 +246,7 @@
 TEST_F(FakeFingerprintEngineTest, Authenticate) {
     FingerprintHalProperties::enrollments({1, 2});
     FingerprintHalProperties::enrollment_hit(2);
+    mEngine.notifyFingerdown();
     mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
     ASSERT_EQ(mEngine.getWorkMode(), FakeFingerprintEngine::WorkMode::kAuthenticate);
     mEngine.fingerDownAction();
@@ -255,6 +260,7 @@
     FingerprintHalProperties::enrollments({2});
     FingerprintHalProperties::enrollment_hit(2);
     mCancel.set_value();
+    mEngine.notifyFingerdown();
     mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
     mEngine.fingerDownAction();
     ASSERT_EQ(Error::CANCELED, mCallback->mError);
@@ -264,6 +270,7 @@
 TEST_F(FakeFingerprintEngineTest, AuthenticateNotSet) {
     FingerprintHalProperties::enrollments({1, 2});
     FingerprintHalProperties::enrollment_hit({});
+    mEngine.notifyFingerdown();
     mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
     mEngine.fingerDownAction();
     ASSERT_TRUE(mCallback->mAuthenticateFailed);
@@ -272,6 +279,7 @@
 TEST_F(FakeFingerprintEngineTest, AuthenticateNotEnrolled) {
     FingerprintHalProperties::enrollments({1, 2});
     FingerprintHalProperties::enrollment_hit(3);
+    mEngine.notifyFingerdown();
     mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
     mEngine.fingerDownAction();
     ASSERT_TRUE(mCallback->mAuthenticateFailed);
@@ -282,6 +290,7 @@
     FingerprintHalProperties::enrollments({22, 2});
     FingerprintHalProperties::enrollment_hit(2);
     FingerprintHalProperties::lockout(true);
+    mEngine.notifyFingerdown();
     mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
     mEngine.fingerDownAction();
     ASSERT_TRUE(mCallback->mLockoutPermanent);
@@ -290,6 +299,7 @@
 
 TEST_F(FakeFingerprintEngineTest, AuthenticateError8) {
     FingerprintHalProperties::operation_authenticate_error(8);
+    mEngine.notifyFingerdown();
     mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
     mEngine.fingerDownAction();
     ASSERT_EQ(mCallback->mError, (Error)8);
@@ -298,6 +308,7 @@
 
 TEST_F(FakeFingerprintEngineTest, AuthenticateError9) {
     FingerprintHalProperties::operation_authenticate_error(1009);
+    mEngine.notifyFingerdown();
     mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
     mEngine.fingerDownAction();
     ASSERT_EQ(mCallback->mError, (Error)7);
@@ -306,6 +317,7 @@
 
 TEST_F(FakeFingerprintEngineTest, AuthenticateFails) {
     FingerprintHalProperties::operation_authenticate_fails(true);
+    mEngine.notifyFingerdown();
     mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
     mEngine.fingerDownAction();
     ASSERT_TRUE(mCallback->mAuthenticateFailed);
@@ -318,6 +330,7 @@
     FingerprintHalProperties::enrollment_hit(2);
     FingerprintHalProperties::operation_authenticate_acquired("4,1009");
     int32_t prevCount = mCallback->mLastAcquiredCount;
+    mEngine.notifyFingerdown();
     mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
     mEngine.fingerDownAction();
     ASSERT_FALSE(mCallback->mAuthenticateFailed);
@@ -332,6 +345,7 @@
     FingerprintHalProperties::enrollments({1, 2});
     FingerprintHalProperties::enrollment_hit(2);
     FingerprintHalProperties::operation_detect_interaction_acquired("");
+    mEngine.notifyFingerdown();
     mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
     ASSERT_EQ(mEngine.getWorkMode(), FakeFingerprintEngine::WorkMode::kDetectInteract);
     mEngine.fingerDownAction();
@@ -345,6 +359,7 @@
     FingerprintHalProperties::enrollments({1, 2});
     FingerprintHalProperties::enrollment_hit(2);
     mCancel.set_value();
+    mEngine.notifyFingerdown();
     mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
     mEngine.fingerDownAction();
     ASSERT_EQ(Error::CANCELED, mCallback->mError);
@@ -355,22 +370,25 @@
     FingerprintHalProperties::detect_interaction(true);
     FingerprintHalProperties::enrollments({1, 2});
     FingerprintHalProperties::enrollment_hit({});
+    mEngine.notifyFingerdown();
     mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
     mEngine.fingerDownAction();
-    ASSERT_EQ(0, mCallback->mInteractionDetectedCount);
+    ASSERT_EQ(1, mCallback->mInteractionDetectedCount);
 }
 
 TEST_F(FakeFingerprintEngineTest, InteractionDetectNotEnrolled) {
     FingerprintHalProperties::enrollments({1, 2});
     FingerprintHalProperties::enrollment_hit(25);
+    mEngine.notifyFingerdown();
     mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
     mEngine.fingerDownAction();
-    ASSERT_EQ(0, mCallback->mInteractionDetectedCount);
+    ASSERT_EQ(1, mCallback->mInteractionDetectedCount);
 }
 
 TEST_F(FakeFingerprintEngineTest, InteractionDetectError) {
     FingerprintHalProperties::detect_interaction(true);
     FingerprintHalProperties::operation_detect_interaction_error(8);
+    mEngine.notifyFingerdown();
     mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
     mEngine.fingerDownAction();
     ASSERT_EQ(0, mCallback->mInteractionDetectedCount);
@@ -384,6 +402,7 @@
     FingerprintHalProperties::enrollment_hit(2);
     FingerprintHalProperties::operation_detect_interaction_acquired("4,1013");
     int32_t prevCount = mCallback->mLastAcquiredCount;
+    mEngine.notifyFingerdown();
     mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
     mEngine.fingerDownAction();
     ASSERT_EQ(1, mCallback->mInteractionDetectedCount);
@@ -421,29 +440,29 @@
 
 TEST_F(FakeFingerprintEngineTest, parseIntSequence) {
     std::vector<int32_t> seqV;
-    seqV = mEngine.parseIntSequence("");
+    seqV = Util::parseIntSequence("");
     ASSERT_EQ(0, seqV.size());
-    seqV = mEngine.parseIntSequence("2");
+    seqV = Util::parseIntSequence("2");
     ASSERT_EQ(1, seqV.size());
     ASSERT_EQ(2, seqV[0]);
-    seqV = mEngine.parseIntSequence("2,3,4");
+    seqV = Util::parseIntSequence("2,3,4");
     std::vector<int32_t> expV{2, 3, 4};
     ASSERT_EQ(expV, seqV);
-    seqV = mEngine.parseIntSequence("2,3,a");
+    seqV = Util::parseIntSequence("2,3,a");
     ASSERT_EQ(0, seqV.size());
-    seqV = mEngine.parseIntSequence("2, 3, 4");
+    seqV = Util::parseIntSequence("2, 3, 4");
     ASSERT_EQ(expV, seqV);
-    seqV = mEngine.parseIntSequence("123,456");
+    seqV = Util::parseIntSequence("123,456");
     ASSERT_EQ(2, seqV.size());
     std::vector<int32_t> expV1{123, 456};
     ASSERT_EQ(expV1, seqV);
-    seqV = mEngine.parseIntSequence("12f3,456");
+    seqV = Util::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");
+    ecV = Util::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};
@@ -451,26 +470,26 @@
         ASSERT_EQ(expE[i / 2], ecV[i]);
         ASSERT_EQ(defC, ecV[i + 1]);
     }
-    ecV = mEngine.parseEnrollmentCapture("100");
+    ecV = Util::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]");
+    ecV = Util::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]");
+    ecV = Util::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]");
+    ecV = Util::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) {
@@ -484,7 +503,7 @@
                                     "100,2x0,300", "200-[f]", "a,b"};
     std::vector<std::vector<int32_t>> ecV;
     for (const auto& s : badStr) {
-        ecV = mEngine.parseEnrollmentCapture(s);
+        ecV = Util::parseEnrollmentCapture(s);
         ASSERT_EQ(ecV.size(), 0);
     }
 }
@@ -508,7 +527,7 @@
 TEST_F(FakeFingerprintEngineTest, lockoutTimer) {
     mEngine.startLockoutTimer(200, mCallback.get());
     ASSERT_TRUE(mEngine.getLockoutTimerStarted());
-    std::this_thread::sleep_for(std::chrono::milliseconds(210));
+    std::this_thread::sleep_for(std::chrono::milliseconds(250));
     ASSERT_FALSE(mEngine.getLockoutTimerStarted());
     ASSERT_TRUE(mCallback->mLockoutCleared);
 }
diff --git a/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineUdfpsTest.cpp b/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineUdfpsTest.cpp
index f551899..5a30db1 100644
--- a/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineUdfpsTest.cpp
+++ b/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineUdfpsTest.cpp
@@ -145,6 +145,7 @@
 TEST_F(FakeFingerprintEngineUdfpsTest, authenticate) {
     std::shared_ptr<TestSessionCallback> cb = ndk::SharedRefBase::make<TestSessionCallback>();
     std::promise<void> cancel;
+    mEngine.notifyFingerdown();
     mEngine.authenticateImpl(cb.get(), 1, cancel.get_future());
     ASSERT_TRUE(mEngine.getWorkMode() == FakeFingerprintEngineUdfps::WorkMode::kAuthenticate);
     mEngine.onPointerDownImpl(1, 2, 3, 4.0, 5.0);
@@ -158,6 +159,7 @@
     std::promise<void> cancel;
     keymaster::HardwareAuthToken hat{.mac = {5, 6}};
     FingerprintHalProperties::next_enrollment("5:0,0:true");
+    mEngine.notifyFingerdown();
     mEngine.enrollImpl(cb.get(), hat, cancel.get_future());
     ASSERT_TRUE(mEngine.getWorkMode() == FakeFingerprintEngineUdfps::WorkMode::kEnroll);
     mEngine.onPointerDownImpl(1, 2, 3, 4.0, 5.0);
@@ -173,6 +175,7 @@
     FingerprintHalProperties::operation_detect_interaction_acquired("");
     std::shared_ptr<TestSessionCallback> cb = ndk::SharedRefBase::make<TestSessionCallback>();
     std::promise<void> cancel;
+    mEngine.notifyFingerdown();
     mEngine.detectInteractionImpl(cb.get(), cancel.get_future());
     ASSERT_TRUE(mEngine.getWorkMode() == FakeFingerprintEngineUdfps::WorkMode::kDetectInteract);
     mEngine.onPointerDownImpl(1, 2, 3, 4.0, 5.0);
diff --git a/bluetooth/1.0/default/bluetooth_address.cc b/bluetooth/1.0/default/bluetooth_address.cc
index 93a5469..df3e84a 100644
--- a/bluetooth/1.0/default/bluetooth_address.cc
+++ b/bluetooth/1.0/default/bluetooth_address.cc
@@ -67,7 +67,7 @@
       const uint8_t zero_bdaddr[kBytes] = {0, 0, 0, 0, 0, 0};
       if ((string_to_bytes(address, local_addr)) &&
           (memcmp(local_addr, zero_bdaddr, kBytes) != 0)) {
-        ALOGD("%s: Got Factory BDA %s", __func__, address);
+        ALOGD("%s: Got Factory BDA", __func__);
         return true;
       } else {
         ALOGE("%s: Got Invalid BDA '%s' from %s", __func__, address, property);
@@ -78,12 +78,14 @@
   // No BDADDR found in the file. Look for BDA in a factory property.
   if (property_get(FACTORY_BDADDR_PROPERTY, property, NULL) &&
       string_to_bytes(property, local_addr)) {
+    ALOGD("%s: Using FACTORY_BDADDR_PROPERTY", __func__);
     return true;
   }
 
   // No factory BDADDR found. Look for a previously stored BDA.
   if (property_get(PERSIST_BDADDR_PROPERTY, property, NULL) &&
       string_to_bytes(property, local_addr)) {
+    ALOGD("%s: Using PERSIST_BDADDR_PROPERTY", __func__);
     return true;
   }
 
diff --git a/bluetooth/1.0/default/bluetooth_hci.cc b/bluetooth/1.0/default/bluetooth_hci.cc
index 869c723..a2211f4 100644
--- a/bluetooth/1.0/default/bluetooth_hci.cc
+++ b/bluetooth/1.0/default/bluetooth_hci.cc
@@ -33,8 +33,7 @@
 
 class BluetoothDeathRecipient : public hidl_death_recipient {
  public:
-  BluetoothDeathRecipient(const sp<IBluetoothHci> hci)
-    : mHci(hci), has_died_(false) {}
+  BluetoothDeathRecipient(const sp<IBluetoothHci> hci) : mHci(hci) {}
 
   virtual void serviceDied(
       uint64_t /*cookie*/,
@@ -52,7 +51,7 @@
 };
 
 BluetoothHci::BluetoothHci()
-    : death_recipient_(new BluetoothDeathRecipient(this)) {bt_enabled = 0;}
+    : death_recipient_(new BluetoothDeathRecipient(this)) {}
 
 Return<void> BluetoothHci::initialize(
     const ::android::sp<IBluetoothHciCallbacks>& cb) {
@@ -62,19 +61,8 @@
     return Void();
   }
 
-  if (bt_enabled == 1) {
-    ALOGE("initialize was called!");
-    return Void();
-  }
-  bt_enabled = 1;
   death_recipient_->setHasDied(false);
   cb->linkToDeath(death_recipient_, 0);
-  unlink_cb_ = [cb](sp<BluetoothDeathRecipient>& death_recipient) {
-    if (death_recipient->getHasDied())
-      ALOGI("Skipping unlink call, service died.");
-    else
-      cb->unlinkToDeath(death_recipient);
-  };
 
   bool rc = VendorInterface::Initialize(
       [cb](bool status) {
@@ -124,12 +112,6 @@
 
 Return<void> BluetoothHci::close() {
   ALOGI("BluetoothHci::close()");
-
-  if (bt_enabled != 1) {
-    ALOGE("should initialize first!");
-    return Void();
-  }
-  bt_enabled = 0;
   unlink_cb_(death_recipient_);
   VendorInterface::Shutdown();
   return Void();
@@ -152,11 +134,6 @@
 
 void BluetoothHci::sendDataToController(const uint8_t type,
                                         const hidl_vec<uint8_t>& data) {
-  if (bt_enabled != 1) {
-    ALOGE("should initialize first!");
-    return;
-  }
-
   VendorInterface::get()->Send(type, data.data(), data.size());
 }
 
diff --git a/bluetooth/1.0/default/bluetooth_hci.h b/bluetooth/1.0/default/bluetooth_hci.h
index 5130c87..c966990 100644
--- a/bluetooth/1.0/default/bluetooth_hci.h
+++ b/bluetooth/1.0/default/bluetooth_hci.h
@@ -48,7 +48,6 @@
   void sendDataToController(const uint8_t type, const hidl_vec<uint8_t>& data);
   ::android::sp<BluetoothDeathRecipient> death_recipient_;
   std::function<void(sp<BluetoothDeathRecipient>&)> unlink_cb_;
-  int bt_enabled;
 };
 
 extern "C" IBluetoothHci* HIDL_FETCH_IBluetoothHci(const char* name);
diff --git a/bluetooth/1.0/default/vendor_interface.cc b/bluetooth/1.0/default/vendor_interface.cc
index c23d667..1d15dd6 100644
--- a/bluetooth/1.0/default/vendor_interface.cc
+++ b/bluetooth/1.0/default/vendor_interface.cc
@@ -36,8 +36,6 @@
     "BLUETOOTH_VENDOR_LIB_INTERFACE";
 
 static const int INVALID_FD = -1;
-std::mutex vendor_mutex_;
-std::mutex initcb_mutex_;
 
 namespace {
 
@@ -49,25 +47,13 @@
   uint16_t opcode;
 } internal_command;
 
-enum {
-  VENDOR_STATE_INIT = 1,
-  VENDOR_STATE_OPENING,	/* during opening */
-  VENDOR_STATE_OPENED,	/* open in fops_open */
-  VENDOR_STATE_CLOSING,	/* during closing */
-  VENDOR_STATE_CLOSED,	/* closed */
-
-  VENDOR_STATE_MSG_NUM
-} ;
-
-uint8_t vstate = VENDOR_STATE_INIT;
-
 // True when LPM is not enabled yet or wake is not asserted.
 bool lpm_wake_deasserted;
 uint32_t lpm_timeout_ms;
 bool recent_activity_flag;
 
 VendorInterface* g_vendor_interface = nullptr;
-static VendorInterface vendor_interface;
+std::mutex wakeup_mutex_;
 
 HC_BT_HDR* WrapPacketAndCopy(uint16_t event, const hidl_vec<uint8_t>& data) {
   size_t packet_size = data.size() + sizeof(HC_BT_HDR);
@@ -181,8 +167,11 @@
     InitializeCompleteCallback initialize_complete_cb,
     PacketReadCallback event_cb, PacketReadCallback acl_cb,
     PacketReadCallback sco_cb, PacketReadCallback iso_cb) {
-  ALOGI("%s: VendorInterface::Initialize", __func__);
-  g_vendor_interface = &vendor_interface;
+  if (g_vendor_interface) {
+    ALOGE("%s: No previous Shutdown()?", __func__);
+    return false;
+  }
+  g_vendor_interface = new VendorInterface();
   return g_vendor_interface->Open(initialize_complete_cb, event_cb, acl_cb,
                                   sco_cb, iso_cb);
 }
@@ -190,8 +179,9 @@
 void VendorInterface::Shutdown() {
   LOG_ALWAYS_FATAL_IF(!g_vendor_interface, "%s: No Vendor interface!",
                       __func__);
-  ALOGI("%s: VendorInterface::Shutdown", __func__);
   g_vendor_interface->Close();
+  delete g_vendor_interface;
+  g_vendor_interface = nullptr;
 }
 
 VendorInterface* VendorInterface::get() { return g_vendor_interface; }
@@ -201,189 +191,144 @@
                            PacketReadCallback acl_cb,
                            PacketReadCallback sco_cb,
                            PacketReadCallback iso_cb) {
-  {
-    std::unique_lock<std::mutex> guard(vendor_mutex_);
-    if (vstate == VENDOR_STATE_OPENED) {
-      ALOGW("VendorInterface opened!");
-      return true;
-    }
+  initialize_complete_cb_ = initialize_complete_cb;
 
-    if ((vstate == VENDOR_STATE_CLOSING) ||
-        (vstate == VENDOR_STATE_OPENING)) {
-      ALOGW("VendorInterface open/close is on-going !");
-      return true;
-    }
+  // Initialize vendor interface
 
-    vstate = VENDOR_STATE_OPENING;
-    ALOGI("%s: VendorInterface::Open", __func__);
+  lib_handle_ = dlopen(VENDOR_LIBRARY_NAME, RTLD_NOW);
+  if (!lib_handle_) {
+    ALOGE("%s unable to open %s (%s)", __func__, VENDOR_LIBRARY_NAME,
+          dlerror());
+    return false;
+  }
 
-    initialize_complete_cb_ = initialize_complete_cb;
-    // Initialize vendor interface
-
-    lib_handle_ = dlopen(VENDOR_LIBRARY_NAME, RTLD_NOW);
-    if (!lib_handle_) {
-      ALOGE("%s unable to open %s (%s)", __func__, VENDOR_LIBRARY_NAME,
-            dlerror());
-      return false;
-    }
-
-    lib_interface_ = reinterpret_cast<bt_vendor_interface_t*>(
-        dlsym(lib_handle_, VENDOR_LIBRARY_SYMBOL_NAME));
-    if (!lib_interface_) {
-      ALOGE("%s unable to find symbol %s in %s (%s)", __func__,
-            VENDOR_LIBRARY_SYMBOL_NAME, VENDOR_LIBRARY_NAME, dlerror());
-      return false;
-    }
+  lib_interface_ = reinterpret_cast<bt_vendor_interface_t*>(
+      dlsym(lib_handle_, VENDOR_LIBRARY_SYMBOL_NAME));
+  if (!lib_interface_) {
+    ALOGE("%s unable to find symbol %s in %s (%s)", __func__,
+          VENDOR_LIBRARY_SYMBOL_NAME, VENDOR_LIBRARY_NAME, dlerror());
+    return false;
+  }
 
   // Get the local BD address
 
-    uint8_t local_bda[BluetoothAddress::kBytes] = {0, 0, 0, 0, 0, 0};
-    if (!BluetoothAddress::get_local_address(local_bda)) {
-      // BT driver will get BD address from NVRAM for MTK solution
-      ALOGW("%s: No pre-set Bluetooth Address!", __func__);
-    }
-    int status = lib_interface_->init(&lib_callbacks, (unsigned char*)local_bda);
-    if (status) {
-      ALOGE("%s unable to initialize vendor library: %d", __func__, status);
-      return false;
-    }
+  uint8_t local_bda[BluetoothAddress::kBytes];
+  if (!BluetoothAddress::get_local_address(local_bda)) {
+    LOG_ALWAYS_FATAL("%s: No Bluetooth Address!", __func__);
+  }
+  int status = lib_interface_->init(&lib_callbacks, (unsigned char*)local_bda);
+  if (status) {
+    ALOGE("%s unable to initialize vendor library: %d", __func__, status);
+    return false;
+  }
 
-    ALOGD("%s vendor library loaded", __func__);
+  ALOGD("%s vendor library loaded", __func__);
 
   // Power on the controller
 
-    int power_state = BT_VND_PWR_ON;
-    lib_interface_->op(BT_VND_OP_POWER_CTRL, &power_state);
+  int power_state = BT_VND_PWR_ON;
+  lib_interface_->op(BT_VND_OP_POWER_CTRL, &power_state);
 
   // Get the UART socket(s)
 
-    int fd_list[CH_MAX] = {0};
-    int fd_count = lib_interface_->op(BT_VND_OP_USERIAL_OPEN, &fd_list);
+  int fd_list[CH_MAX] = {0};
+  int fd_count = lib_interface_->op(BT_VND_OP_USERIAL_OPEN, &fd_list);
 
-    if (fd_count < 1 || fd_count > CH_MAX - 1) {
-      ALOGE("%s: fd_count %d is invalid!", __func__, fd_count);
+  if (fd_count < 1 || fd_count > CH_MAX - 1) {
+    ALOGE("%s: fd_count %d is invalid!", __func__, fd_count);
+    return false;
+  }
+
+  for (int i = 0; i < fd_count; i++) {
+    if (fd_list[i] == INVALID_FD) {
+      ALOGE("%s: fd %d is invalid!", __func__, fd_list[i]);
       return false;
     }
+  }
 
-    for (int i = 0; i < fd_count; i++) {
-      if (fd_list[i] == INVALID_FD) {
-        ALOGE("%s: fd %d is invalid!", __func__, fd_list[i]);
-        return false;
-      }
-    }
+  event_cb_ = event_cb;
+  PacketReadCallback intercept_events = [this](const hidl_vec<uint8_t>& event) {
+    HandleIncomingEvent(event);
+  };
 
-    event_cb_ = event_cb;
-    PacketReadCallback intercept_events = [this](const hidl_vec<uint8_t>& event) {
-      HandleIncomingEvent(event);
-    };
-
-    if (fd_count == 1) {
-      hci::H4Protocol* h4_hci =
-          new hci::H4Protocol(fd_list[0], intercept_events, acl_cb, sco_cb, iso_cb);
-      fd_watcher_.WatchFdForNonBlockingReads(
-          fd_list[0], [h4_hci](int fd) { h4_hci->OnDataReady(fd); });
-      hci_ = h4_hci;
-    } else {
-      hci::MctProtocol* mct_hci =
-          new hci::MctProtocol(fd_list, intercept_events, acl_cb);
-      fd_watcher_.WatchFdForNonBlockingReads(
-          fd_list[CH_EVT], [mct_hci](int fd) { mct_hci->OnEventDataReady(fd); });
-      fd_watcher_.WatchFdForNonBlockingReads(
-          fd_list[CH_ACL_IN],
-          [mct_hci](int fd) { mct_hci->OnAclDataReady(fd); });
-      hci_ = mct_hci;
-    }
+  if (fd_count == 1) {
+    hci::H4Protocol* h4_hci =
+        new hci::H4Protocol(fd_list[0], intercept_events, acl_cb, sco_cb, iso_cb);
+    fd_watcher_.WatchFdForNonBlockingReads(
+        fd_list[0], [h4_hci](int fd) { h4_hci->OnDataReady(fd); });
+    hci_ = h4_hci;
+  } else {
+    hci::MctProtocol* mct_hci =
+        new hci::MctProtocol(fd_list, intercept_events, acl_cb);
+    fd_watcher_.WatchFdForNonBlockingReads(
+        fd_list[CH_EVT], [mct_hci](int fd) { mct_hci->OnEventDataReady(fd); });
+    fd_watcher_.WatchFdForNonBlockingReads(
+        fd_list[CH_ACL_IN], [mct_hci](int fd) { mct_hci->OnAclDataReady(fd); });
+    hci_ = mct_hci;
+  }
 
   // Initially, the power management is off.
-    lpm_wake_deasserted = true;
+  lpm_wake_deasserted = true;
 
   // Start configuring the firmware
-    firmware_startup_timer_ = new FirmwareStartupTimer();
-    lib_interface_->op(BT_VND_OP_FW_CFG, nullptr);
+  firmware_startup_timer_ = new FirmwareStartupTimer();
+  lib_interface_->op(BT_VND_OP_FW_CFG, nullptr);
 
-    vstate = VENDOR_STATE_OPENED;
-    ALOGI("%s: VendorInterface::Open done!!!", __func__);
-  }  // vendor_mutex_ done
   return true;
 }
 
 void VendorInterface::Close() {
   // These callbacks may send HCI events (vendor-dependent), so make sure to
   // StopWatching the file descriptor after this.
-
-  if (vstate != VENDOR_STATE_OPENED) {
-    ALOGW("VendorInterface is not allow close(%d)", vstate);
-    return;
-  }
-  vstate = VENDOR_STATE_CLOSING;
-  ALOGI("%s: VendorInterface::Close", __func__);
-
   if (lib_interface_ != nullptr) {
-    lib_interface_->cleanup();
     bt_vendor_lpm_mode_t mode = BT_VND_LPM_DISABLE;
     lib_interface_->op(BT_VND_OP_LPM_SET_MODE, &mode);
   }
 
-  {
-    std::unique_lock<std::mutex> guard(vendor_mutex_);
+  fd_watcher_.StopWatchingFileDescriptors();
 
-    fd_watcher_.StopWatchingFileDescriptors();
-    if (hci_ != nullptr) {
-      delete hci_;
-      hci_ = nullptr;
-    }
+  if (hci_ != nullptr) {
+    delete hci_;
+    hci_ = nullptr;
+  }
 
-    if (lib_interface_ != nullptr) {
-      lib_interface_->op(BT_VND_OP_USERIAL_CLOSE, nullptr);
+  if (lib_interface_ != nullptr) {
+    lib_interface_->op(BT_VND_OP_USERIAL_CLOSE, nullptr);
 
-      int power_state = BT_VND_PWR_OFF;
-      lib_interface_->op(BT_VND_OP_POWER_CTRL, &power_state);
+    int power_state = BT_VND_PWR_OFF;
+    lib_interface_->op(BT_VND_OP_POWER_CTRL, &power_state);
 
-      lib_interface_ = nullptr;
-    }
+    lib_interface_->cleanup();
+    lib_interface_ = nullptr;
+  }
 
-    if (lib_handle_ != nullptr) {
-      dlclose(lib_handle_);
-      lib_handle_ = nullptr;
-    }
+  if (lib_handle_ != nullptr) {
+    dlclose(lib_handle_);
+    lib_handle_ = nullptr;
+  }
 
-    if (firmware_startup_timer_ != nullptr) {
-      delete firmware_startup_timer_;
-      firmware_startup_timer_ = nullptr;
-    }
-    vstate = VENDOR_STATE_CLOSED;
-  }  // vendor_mutex_ done
-  ALOGI("%s: VendorInterface::Close done!!!", __func__);
+  if (firmware_startup_timer_ != nullptr) {
+    delete firmware_startup_timer_;
+    firmware_startup_timer_ = nullptr;
+  }
 }
 
 size_t VendorInterface::Send(uint8_t type, const uint8_t* data, size_t length) {
-  {
-    std::unique_lock<std::mutex> guard(vendor_mutex_);
+  std::unique_lock<std::mutex> lock(wakeup_mutex_);
+  recent_activity_flag = true;
 
-    if (vstate != VENDOR_STATE_OPENED) {
-      ALOGW("VendorInterface is not open yet(%d)!", vstate);
-      return 0;
-    }
-    ALOGI("%s: VendorInterface::Send", __func__);
-
-    if (lib_interface_ == nullptr) {
-      ALOGE("lib_interface_ is null");
-      return 0;
-    }
-    recent_activity_flag = true;
-    if (lpm_wake_deasserted == true) {
-      // Restart the timer.
-      fd_watcher_.ConfigureTimeout(std::chrono::milliseconds(lpm_timeout_ms),
+  if (lpm_wake_deasserted == true) {
+    // Restart the timer.
+    fd_watcher_.ConfigureTimeout(std::chrono::milliseconds(lpm_timeout_ms),
                                  [this]() { OnTimeout(); });
-      // Assert wake.
-      lpm_wake_deasserted = false;
-      bt_vendor_lpm_wake_state_t wakeState = BT_VND_LPM_WAKE_ASSERT;
-      lib_interface_->op(BT_VND_OP_LPM_WAKE_SET_STATE, &wakeState);
-      ALOGV("%s: Sent wake before (%02x)", __func__, data[0] | (data[1] << 8));
-    }
+    // Assert wake.
+    lpm_wake_deasserted = false;
+    bt_vendor_lpm_wake_state_t wakeState = BT_VND_LPM_WAKE_ASSERT;
+    lib_interface_->op(BT_VND_OP_LPM_WAKE_SET_STATE, &wakeState);
+    ALOGV("%s: Sent wake before (%02x)", __func__, data[0] | (data[1] << 8));
+  }
 
-    return hci_ ? hci_->Send(type, data, length) : 0;
-  }  // vendor_mutex_ done
+  return hci_->Send(type, data, length);
 }
 
 void VendorInterface::OnFirmwareConfigured(uint8_t result) {
@@ -394,36 +339,25 @@
     firmware_startup_timer_ = nullptr;
   }
 
-  {
-    std::unique_lock<std::mutex> guard(initcb_mutex_);
-    ALOGD("%s OnFirmwareConfigured get lock", __func__);
-    if (initialize_complete_cb_ != nullptr) {
-      LOG_ALWAYS_FATAL_IF((result != 0),
-          "%s: Failed to init firmware!", __func__);
-      initialize_complete_cb_(result == 0);
-    }
-  }  // initcb_mutex_ done
-
-  if (lib_interface_ != nullptr) {
-    lib_interface_->op(BT_VND_OP_GET_LPM_IDLE_TIMEOUT, &lpm_timeout_ms);
-    ALOGI("%s: lpm_timeout_ms %d", __func__, lpm_timeout_ms);
-
-    bt_vendor_lpm_mode_t mode = BT_VND_LPM_ENABLE;
-    lib_interface_->op(BT_VND_OP_LPM_SET_MODE, &mode);
-
-    ALOGD("%s Calling StartLowPowerWatchdog()", __func__);
-    fd_watcher_.ConfigureTimeout(std::chrono::milliseconds(lpm_timeout_ms),
-                                 [this]() { OnTimeout(); });
-  }
-  else {
-    ALOGE("lib_interface_ is null");
+  if (initialize_complete_cb_ != nullptr) {
+    initialize_complete_cb_(result == 0);
+    initialize_complete_cb_ = nullptr;
   }
 
-  initialize_complete_cb_ = nullptr;
+  lib_interface_->op(BT_VND_OP_GET_LPM_IDLE_TIMEOUT, &lpm_timeout_ms);
+  ALOGI("%s: lpm_timeout_ms %d", __func__, lpm_timeout_ms);
+
+  bt_vendor_lpm_mode_t mode = BT_VND_LPM_ENABLE;
+  lib_interface_->op(BT_VND_OP_LPM_SET_MODE, &mode);
+
+  ALOGD("%s Calling StartLowPowerWatchdog()", __func__);
+  fd_watcher_.ConfigureTimeout(std::chrono::milliseconds(lpm_timeout_ms),
+                               [this]() { OnTimeout(); });
 }
 
 void VendorInterface::OnTimeout() {
   ALOGV("%s", __func__);
+  std::unique_lock<std::mutex> lock(wakeup_mutex_);
   if (recent_activity_flag == false) {
     lpm_wake_deasserted = true;
     bt_vendor_lpm_wake_state_t wakeState = BT_VND_LPM_WAKE_DEASSERT;
diff --git a/bluetooth/1.0/default/vendor_interface.h b/bluetooth/1.0/default/vendor_interface.h
index 2df3946..040f31a 100644
--- a/bluetooth/1.0/default/vendor_interface.h
+++ b/bluetooth/1.0/default/vendor_interface.h
@@ -22,8 +22,6 @@
 #include "bt_vendor_lib.h"
 #include "hci_protocol.h"
 
-extern std::mutex initcb_mutex_;
-
 namespace android {
 namespace hardware {
 namespace bluetooth {
@@ -47,9 +45,10 @@
   size_t Send(uint8_t type, const uint8_t* data, size_t length);
 
   void OnFirmwareConfigured(uint8_t result);
-  virtual ~VendorInterface() = default;
 
  private:
+  virtual ~VendorInterface() = default;
+
   bool Open(InitializeCompleteCallback initialize_complete_cb,
             PacketReadCallback event_cb, PacketReadCallback acl_cb,
             PacketReadCallback sco_cb, PacketReadCallback iso_cb);
diff --git a/bluetooth/aidl/TEST_MAPPING b/bluetooth/aidl/TEST_MAPPING
index 41a508e..18958d2 100644
--- a/bluetooth/aidl/TEST_MAPPING
+++ b/bluetooth/aidl/TEST_MAPPING
@@ -1,24 +1,12 @@
 {
   "presubmit" : [
     {
-      "name" : "VtsHalBluetoothTargetTest",
-      "options": [
-        {
-          // TODO(b/275847929)
-          "exclude-filter": "VtsHalBluetoothTargetTest.PerInstance/BluetoothAidlTest#Vsr_Bluetooth5Requirements/0_android_hardware_bluetooth_IBluetoothHci_default"
-        }
-      ]
+      "name" : "VtsHalBluetoothTargetTest"
     }
   ],
   "hwasan-presubmit" : [
     {
-      "name" : "VtsHalBluetoothTargetTest",
-      "options": [
-        {
-          // TODO(b/275847929)
-          "exclude-filter": "VtsHalBluetoothTargetTest.PerInstance/BluetoothAidlTest#Vsr_Bluetooth5Requirements/0_android_hardware_bluetooth_IBluetoothHci_default"
-        }
-      ]
+      "name" : "VtsHalBluetoothTargetTest"
     }
   ]
 }
diff --git a/bluetooth/aidl/default/Android.bp b/bluetooth/aidl/default/Android.bp
index 32d1a13..3f4ba99 100644
--- a/bluetooth/aidl/default/Android.bp
+++ b/bluetooth/aidl/default/Android.bp
@@ -30,15 +30,8 @@
     defaults: ["android.hardware.bluetooth-service-build-defaults"],
     srcs: [
         "BluetoothHci.cpp",
-        ":BluetoothPacketSources",
         "net_bluetooth_mgmt.cpp",
     ],
-    generated_headers: [
-        "BluetoothGeneratedPackets_h",
-    ],
-    include_dirs: [
-        "packages/modules/Bluetooth/system/gd",
-    ],
 }
 
 cc_binary {
diff --git a/bluetooth/aidl/default/BluetoothHci.cpp b/bluetooth/aidl/default/BluetoothHci.cpp
index ac2eabc..a247cb0 100644
--- a/bluetooth/aidl/default/BluetoothHci.cpp
+++ b/bluetooth/aidl/default/BluetoothHci.cpp
@@ -29,11 +29,6 @@
 
 #include "log/log.h"
 
-// TODO: Remove custom logging defines from PDL packets.
-#undef LOG_INFO
-#undef LOG_DEBUG
-#include "hci/hci_packets.h"
-
 namespace {
 int SetTerminalRaw(int fd) {
   termios terminal_settings;
@@ -55,6 +50,19 @@
 
 void OnDeath(void* cookie);
 
+std::optional<std::string> GetSystemProperty(const std::string& property) {
+  std::array<char, PROPERTY_VALUE_MAX> value_array{0};
+  auto value_len = property_get(property.c_str(), value_array.data(), nullptr);
+  if (value_len <= 0) {
+    return std::nullopt;
+  }
+  return std::string(value_array.data(), value_len);
+}
+
+bool starts_with(const std::string& str, const std::string& prefix) {
+  return str.compare(0, prefix.length(), prefix) == 0;
+}
+
 class BluetoothDeathRecipient {
  public:
   BluetoothDeathRecipient(BluetoothHci* hci) : mHci(hci) {}
@@ -127,9 +135,7 @@
 void BluetoothHci::reset() {
   // Send a reset command and wait until the command complete comes back.
 
-  std::vector<uint8_t> reset;
-  ::bluetooth::packet::BitInserter bi{reset};
-  ::bluetooth::hci::ResetBuilder::Create()->Serialize(bi);
+  std::vector<uint8_t> reset = {0x03, 0x0c, 0x00};
 
   auto resetPromise = std::make_shared<std::promise<void>>();
   auto resetFuture = resetPromise->get_future();
@@ -149,13 +155,15 @@
               static_cast<int>(raw_sco.size()));
       },
       [resetPromise](const std::vector<uint8_t>& raw_event) {
-        bool valid = ::bluetooth::hci::ResetCompleteView::Create(
-                         ::bluetooth::hci::CommandCompleteView::Create(
-                             ::bluetooth::hci::EventView::Create(
-                                 ::bluetooth::hci::PacketView<true>(
-                                     std::make_shared<std::vector<uint8_t>>(
-                                         raw_event)))))
-                         .IsValid();
+        std::vector<uint8_t> reset_complete = {0x0e, 0x04, 0x01,
+                                               0x03, 0x0c, 0x00};
+        bool valid = raw_event.size() == 6 &&
+                     raw_event[0] == reset_complete[0] &&
+                     raw_event[1] == reset_complete[1] &&
+                     // Don't compare the number of packets field.
+                     raw_event[3] == reset_complete[3] &&
+                     raw_event[4] == reset_complete[4] &&
+                     raw_event[5] == reset_complete[5];
         if (valid) {
           resetPromise->set_value();
         } else {
@@ -174,7 +182,10 @@
   mFdWatcher.WatchFdForNonBlockingReads(mFd,
                                         [this](int) { mH4->OnDataReady(); });
 
-  send(PacketType::COMMAND, reset);
+  ndk::ScopedAStatus result = send(PacketType::COMMAND, reset);
+  if (!result.isOk()) {
+    ALOGE("Error sending reset command");
+  }
   auto status = resetFuture.wait_for(std::chrono::seconds(1));
   mFdWatcher.StopWatchingFileDescriptors();
   if (status == std::future_status::ready) {
@@ -221,6 +232,7 @@
     ALOGI("Unable to open Linux interface, trying default path.");
     mFd = getFdFromDevPath();
     if (mFd < 0) {
+      mState = HalState::READY;
       cb->initializationComplete(Status::UNABLE_TO_OPEN_INTERFACE);
       return ndk::ScopedAStatus::ok();
     }
@@ -228,8 +240,19 @@
 
   mDeathRecipient->LinkToDeath(mCb);
 
-  // TODO: This should not be necessary when the device implements rfkill.
-  reset();
+  // TODO: HCI Reset on emulators since the bluetooth controller
+  // cannot be powered on/off during the HAL setup; and the stack
+  // might received spurious packets/events during boottime.
+  // Proper solution would be to use bt-virtio or vsock to better
+  // control the link to rootcanal and the controller lifetime.
+  const std::string kBoardProperty = "ro.product.board";
+  const std::string kCuttlefishBoard = "cutf";
+  auto board_name = GetSystemProperty(kBoardProperty);
+  if (board_name.has_value() && (
+        starts_with(board_name.value(), "cutf") ||
+        starts_with(board_name.value(), "goldfish"))) {
+    reset();
+  }
 
   mH4 = std::make_shared<H4Protocol>(
       mFd,
@@ -278,6 +301,8 @@
   {
     std::lock_guard<std::mutex> guard(mStateMutex);
     if (mState != HalState::ONE_CLIENT) {
+      LOG_ALWAYS_FATAL_IF(mState == HalState::INITIALIZING,
+                          "mState is INITIALIZING");
       ALOGI("Already closed");
       return ndk::ScopedAStatus::ok();
     }
@@ -295,36 +320,45 @@
   {
     std::lock_guard<std::mutex> guard(mStateMutex);
     mState = HalState::READY;
+    mH4 = nullptr;
   }
   return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus BluetoothHci::sendHciCommand(
     const std::vector<uint8_t>& packet) {
-  send(PacketType::COMMAND, packet);
-  return ndk::ScopedAStatus::ok();
+  return send(PacketType::COMMAND, packet);
 }
 
 ndk::ScopedAStatus BluetoothHci::sendAclData(
     const std::vector<uint8_t>& packet) {
-  send(PacketType::ACL_DATA, packet);
-  return ndk::ScopedAStatus::ok();
+  return send(PacketType::ACL_DATA, packet);
 }
 
 ndk::ScopedAStatus BluetoothHci::sendScoData(
     const std::vector<uint8_t>& packet) {
-  send(PacketType::SCO_DATA, packet);
-  return ndk::ScopedAStatus::ok();
+  return send(PacketType::SCO_DATA, packet);
 }
 
 ndk::ScopedAStatus BluetoothHci::sendIsoData(
     const std::vector<uint8_t>& packet) {
-  send(PacketType::ISO_DATA, packet);
-  return ndk::ScopedAStatus::ok();
+  return send(PacketType::ISO_DATA, packet);
 }
 
-void BluetoothHci::send(PacketType type, const std::vector<uint8_t>& v) {
+ndk::ScopedAStatus BluetoothHci::send(PacketType type,
+    const std::vector<uint8_t>& v) {
+  if (v.empty()) {
+    ALOGE("Packet is empty, no data was found to be sent");
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+  }
+
+  std::lock_guard<std::mutex> guard(mStateMutex);
+  if (mH4 == nullptr) {
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+  }
+
   mH4->Send(type, v);
+  return ndk::ScopedAStatus::ok();
 }
 
 }  // namespace aidl::android::hardware::bluetooth::impl
diff --git a/bluetooth/aidl/default/BluetoothHci.h b/bluetooth/aidl/default/BluetoothHci.h
index 85aafc8..477cc5c 100644
--- a/bluetooth/aidl/default/BluetoothHci.h
+++ b/bluetooth/aidl/default/BluetoothHci.h
@@ -66,8 +66,9 @@
   ::android::hardware::bluetooth::async::AsyncFdWatcher mFdWatcher;
 
   int getFdFromDevPath();
-  void send(::android::hardware::bluetooth::hci::PacketType type,
-            const std::vector<uint8_t>& packet);
+  [[nodiscard]] ndk::ScopedAStatus send(
+      ::android::hardware::bluetooth::hci::PacketType type,
+      const std::vector<uint8_t>& packet);
   std::unique_ptr<NetBluetoothMgmt> management_{};
 
   // Send a reset command and discard all packets until a reset is received.
diff --git a/bluetooth/aidl/default/net_bluetooth_mgmt.cpp b/bluetooth/aidl/default/net_bluetooth_mgmt.cpp
index 937cd57..0699781 100644
--- a/bluetooth/aidl/default/net_bluetooth_mgmt.cpp
+++ b/bluetooth/aidl/default/net_bluetooth_mgmt.cpp
@@ -162,9 +162,9 @@
           (struct mgmt_ev_read_index_list*)ev.data;
 
       for (int i = 0; i < data->num_controllers; i++) {
-        if (data->index[i] == hci_interface) {
-          ALOGI("hci interface %d found", hci_interface);
-          ret = 0;
+        if (data->index[i] >= hci_interface) {
+          ALOGI("hci interface %d found", data->index[i]);
+          ret = data->index[i];
           goto end;
         }
       }
@@ -253,8 +253,9 @@
   rfkill(1);
 
   // Wait for the HCI interface to complete initialization or to come online.
-  if (waitHciDev(hci_interface)) {
-    ALOGE("hci interface %d not found", hci_interface);
+  hci_interface = waitHciDev(hci_interface);
+  if (hci_interface < 0) {
+    ALOGE("hci interface not found");
     return -1;
   }
 
diff --git a/bluetooth/aidl/vts/Android.bp b/bluetooth/aidl/vts/Android.bp
index 5fc0b2e..ade3bef 100644
--- a/bluetooth/aidl/vts/Android.bp
+++ b/bluetooth/aidl/vts/Android.bp
@@ -16,10 +16,6 @@
     srcs: [
         "VtsHalBluetoothTargetTest.cpp",
         ":BluetoothPacketSources",
-        ":BluetoothHciPacketSources",
-    ],
-    generated_headers: [
-        "BluetoothGeneratedPackets_h",
     ],
     include_dirs: [
         "packages/modules/Bluetooth/system/gd",
@@ -31,7 +27,7 @@
     ],
     static_libs: [
         "android.hardware.bluetooth-V1-ndk",
-        "libbluetooth-types",
+        "libbluetooth_hci_pdl",
     ],
     test_config: "VtsHalBluetoothTargetTest.xml",
     test_suites: [
@@ -57,6 +53,5 @@
     ],
     tidy_disabled_srcs: [
         ":BluetoothPacketSources",
-        ":BluetoothHciPacketSources",
     ],
 }
diff --git a/bluetooth/audio/aidl/Android.bp b/bluetooth/audio/aidl/Android.bp
index 1028fae..feed6f5 100644
--- a/bluetooth/audio/aidl/Android.bp
+++ b/bluetooth/audio/aidl/Android.bp
@@ -27,10 +27,12 @@
     host_supported: true,
     srcs: ["android/hardware/bluetooth/audio/*.aidl"],
     stability: "vintf",
+    defaults: [
+        "latest_android_hardware_audio_common_import_interface",
+    ],
     imports: [
         "android.hardware.common-V2",
         "android.hardware.common.fmq-V1",
-        "android.hardware.audio.common-V2",
     ],
     backend: {
         cpp: {
@@ -75,6 +77,23 @@
         },
 
     ],
-    frozen: true,
+    frozen: false,
 
 }
+
+// Note: This should always be one version ahead of the last frozen version
+latest_android_hardware_bluetooth_audio = "android.hardware.bluetooth.audio-V4"
+
+cc_defaults {
+    name: "latest_android_hardware_bluetooth_audio_ndk_shared",
+    shared_libs: [
+        latest_android_hardware_bluetooth_audio + "-ndk",
+    ],
+}
+
+cc_defaults {
+    name: "latest_android_hardware_bluetooth_audio_ndk_static",
+    static_libs: [
+        latest_android_hardware_bluetooth_audio + "-ndk",
+    ],
+}
diff --git a/bluetooth/audio/aidl/TEST_MAPPING b/bluetooth/audio/aidl/TEST_MAPPING
new file mode 100644
index 0000000..0c853f8
--- /dev/null
+++ b/bluetooth/audio/aidl/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "VtsHalBluetoothAudioTargetTest"
+    }
+  ],
+  "kernel-presubmit": [
+    {
+      "name": "VtsHalBluetoothAudioTargetTest"
+    }
+  ]
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/A2dpConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/A2dpConfiguration.aidl
new file mode 100644
index 0000000..9e67b15
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/A2dpConfiguration.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable A2dpConfiguration {
+  int remoteSeid;
+  android.hardware.bluetooth.audio.CodecId id;
+  android.hardware.bluetooth.audio.CodecParameters parameters;
+  byte[] configuration;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/A2dpConfigurationHint.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/A2dpConfigurationHint.aidl
new file mode 100644
index 0000000..0a5b489
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/A2dpConfigurationHint.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable A2dpConfigurationHint {
+  byte[6] bdAddr;
+  android.hardware.bluetooth.audio.AudioContext audioContext;
+  @nullable android.hardware.bluetooth.audio.CodecId codecId;
+  @nullable android.hardware.bluetooth.audio.CodecParameters codecParameters;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/A2dpRemoteCapabilities.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/A2dpRemoteCapabilities.aidl
new file mode 100644
index 0000000..9c1e971
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/A2dpRemoteCapabilities.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable A2dpRemoteCapabilities {
+  int seid;
+  android.hardware.bluetooth.audio.CodecId id;
+  byte[] capabilities;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/A2dpStatus.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/A2dpStatus.aidl
new file mode 100644
index 0000000..ac22e25
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/A2dpStatus.aidl
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@Backing(type="byte") @VintfStability
+enum A2dpStatus {
+  OK = 0,
+  BAD_LENGTH = 0x11u8,
+  BAD_PAYLOAD_FORMAT = 0x18u8,
+  INVALID_CODEC_TYPE = 0xC1u8,
+  NOT_SUPPORTED_CODEC_TYPE = 0xC2u8,
+  INVALID_SAMPLING_FREQUENCY = 0xC3u8,
+  NOT_SUPPORTED_SAMPLING_FREQUENCY = 0xC4u8,
+  INVALID_CHANNEL_MODE = 0xC5u8,
+  NOT_SUPPORTED_CHANNEL_MODE = 0xC6u8,
+  INVALID_SUBBANDS = 0xC7u8,
+  NOT_SUPPORTED_SUBBANDS = 0xC8u8,
+  INVALID_ALLOCATION_METHOD = 0xC9u8,
+  NOT_SUPPORTED_ALLOCATION_METHOD = 0xCAu8,
+  INVALID_MINIMUM_BITPOOL_VALUE = 0xCBu8,
+  NOT_SUPPORTED_MINIMUM_BITPOOL_VALUE = 0xCCu8,
+  INVALID_MAXIMUM_BITPOOL_VALUE = 0xCDu8,
+  NOT_SUPPORTED_MAXIMUM_BITPOOL_VALUE = 0xCEu8,
+  NOT_SUPPORTED_VBR = 0xD3u8,
+  NOT_SUPPORTED_BIT_RATE = 0xD5u8,
+  INVALID_OBJECT_TYPE = 0xD6u8,
+  NOT_SUPPORTED_OBJECT_TYPE = 0xD7u8,
+  INVALID_CHANNELS = 0xD8u8,
+  NOT_SUPPORTED_CHANNELS = 0xD9u8,
+  INVALID_BLOCK_LENGTH = 0xDDu8,
+  INVALID_CODEC_PARAMETER = 0xE2u8,
+  NOT_SUPPORTED_CODEC_PARAMETER = 0xE3u8,
+  INVALID_DRC = 0xE4u8,
+  NOT_SUPPORTED_DRC = 0xE5u8,
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/A2dpStreamConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/A2dpStreamConfiguration.aidl
new file mode 100644
index 0000000..ff5a1bc
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/A2dpStreamConfiguration.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable A2dpStreamConfiguration {
+  int peerMtu;
+  @nullable byte[1] cpHeaderScmst;
+  android.hardware.bluetooth.audio.CodecId codecId;
+  byte[] configuration;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AacObjectType.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AacObjectType.aidl
index 2148244..418dd7a 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AacObjectType.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AacObjectType.aidl
@@ -34,8 +34,8 @@
 package android.hardware.bluetooth.audio;
 @Backing(type="byte") @VintfStability
 enum AacObjectType {
-  MPEG2_LC = 0,
-  MPEG4_LC = 1,
-  MPEG4_LTP = 2,
-  MPEG4_SCALABLE = 3,
+  MPEG2_LC,
+  MPEG4_LC,
+  MPEG4_LTP,
+  MPEG4_SCALABLE,
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxAdaptiveChannelMode.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxAdaptiveChannelMode.aidl
index 0499b70..675f9f2 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxAdaptiveChannelMode.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxAdaptiveChannelMode.aidl
@@ -38,5 +38,5 @@
   MONO = 1,
   DUAL_MONO = 2,
   TWS_STEREO = 4,
-  UNKNOWN = 255,
+  UNKNOWN = 0xFF,
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxAdaptiveInputMode.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxAdaptiveInputMode.aidl
index f702939..a18303e 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxAdaptiveInputMode.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxAdaptiveInputMode.aidl
@@ -34,6 +34,6 @@
 package android.hardware.bluetooth.audio;
 @Backing(type="int") @VintfStability
 enum AptxAdaptiveInputMode {
-  STEREO = 0,
-  DUAL_MONO = 1,
+  STEREO = 0x00,
+  DUAL_MONO = 0x01,
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxMode.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxMode.aidl
index d5dd9d9..dd8cf08 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxMode.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxMode.aidl
@@ -34,8 +34,8 @@
 package android.hardware.bluetooth.audio;
 @Backing(type="int") @VintfStability
 enum AptxMode {
-  UNKNOWN = 0,
-  HIGH_QUALITY = 4096,
-  LOW_LATENCY = 8192,
-  ULTRA_LOW_LATENCY = 16384,
+  UNKNOWN = 0x00,
+  HIGH_QUALITY = 0x1000,
+  LOW_LATENCY = 0x2000,
+  ULTRA_LOW_LATENCY = 0x4000,
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AudioConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AudioConfiguration.aidl
index 3abfb31..2c40267 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AudioConfiguration.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AudioConfiguration.aidl
@@ -38,4 +38,6 @@
   android.hardware.bluetooth.audio.CodecConfiguration a2dpConfig;
   android.hardware.bluetooth.audio.LeAudioConfiguration leAudioConfig;
   android.hardware.bluetooth.audio.LeAudioBroadcastConfiguration leAudioBroadcastConfig;
+  android.hardware.bluetooth.audio.HfpConfiguration hfpConfig;
+  android.hardware.bluetooth.audio.A2dpStreamConfiguration a2dp;
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AudioContext.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AudioContext.aidl
new file mode 100644
index 0000000..5aafeb7
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AudioContext.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable AudioContext {
+  int bitmask;
+  const int UNSPECIFIED = 0x0001;
+  const int CONVERSATIONAL = 0x0002;
+  const int MEDIA = 0x0004;
+  const int GAME = 0x0008;
+  const int INSTRUCTIONAL = 0x0010;
+  const int VOICE_ASSISTANTS = 0x0020;
+  const int LIVE_AUDIO = 0x0040;
+  const int SOUND_EFFECTS = 0x0080;
+  const int NOTIFICATIONS = 0x0100;
+  const int RINGTONE_ALERTS = 0x0200;
+  const int ALERTS = 0x0400;
+  const int EMERGENCY_ALARM = 0x0800;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AudioLocation.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AudioLocation.aidl
index 319a5e2..941344c 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AudioLocation.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AudioLocation.aidl
@@ -35,6 +35,6 @@
 @Backing(type="int") @VintfStability
 enum AudioLocation {
   UNKNOWN = 1,
-  FRONT_LEFT = 2,
-  FRONT_RIGHT = 4,
+  FRONT_LEFT = (1 << 1) /* 2 */,
+  FRONT_RIGHT = (1 << 2) /* 4 */,
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/ChannelMode.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/ChannelMode.aidl
index feacb80..2bb5cd8 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/ChannelMode.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/ChannelMode.aidl
@@ -34,8 +34,8 @@
 package android.hardware.bluetooth.audio;
 @Backing(type="byte") @VintfStability
 enum ChannelMode {
-  UNKNOWN = 0,
-  MONO = 1,
-  STEREO = 2,
-  DUALMONO = 3,
+  UNKNOWN,
+  MONO,
+  STEREO,
+  DUALMONO,
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecId.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecId.aidl
new file mode 100644
index 0000000..f3b4102
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecId.aidl
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+union CodecId {
+  android.hardware.bluetooth.audio.CodecId.A2dp a2dp = android.hardware.bluetooth.audio.CodecId.A2dp.SBC;
+  android.hardware.bluetooth.audio.CodecId.Core core;
+  android.hardware.bluetooth.audio.CodecId.Vendor vendor;
+  enum A2dp {
+    SBC = 0,
+    AAC = 2,
+  }
+  enum Core {
+    CVSD = 2,
+    MSBC = 5,
+    LC3 = 6,
+  }
+  parcelable Vendor {
+    int id;
+    int codecId;
+  }
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecInfo.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecInfo.aidl
new file mode 100644
index 0000000..2727d6e
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecInfo.aidl
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable CodecInfo {
+  android.hardware.bluetooth.audio.CodecId id;
+  String name;
+  android.hardware.bluetooth.audio.CodecInfo.Transport transport;
+  parcelable A2dp {
+    byte[] capabilities;
+    android.hardware.bluetooth.audio.ChannelMode[] channelMode;
+    int[] samplingFrequencyHz;
+    int[] bitdepth;
+    boolean lossless;
+  }
+  parcelable Hfp {
+    int inputDataPath = 1;
+    int outputDataPath = 1;
+    boolean useControllerCodec = true;
+  }
+  parcelable LeAudio {
+    android.hardware.bluetooth.audio.ChannelMode[] channelMode;
+    int[] samplingFrequencyHz;
+    int[] frameDurationUs;
+    int[] bitdepth;
+    @nullable android.hardware.bluetooth.audio.ConfigurationFlags flags;
+  }
+  union Transport {
+    android.hardware.bluetooth.audio.CodecInfo.LeAudio leAudio;
+    android.hardware.bluetooth.audio.CodecInfo.A2dp a2dp;
+    android.hardware.bluetooth.audio.CodecInfo.Hfp hfp;
+  }
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecParameters.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecParameters.aidl
new file mode 100644
index 0000000..60cf82a
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecParameters.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable CodecParameters {
+  android.hardware.bluetooth.audio.ChannelMode channelMode;
+  int samplingFrequencyHz;
+  int bitdepth;
+  int minBitrate;
+  int maxBitrate;
+  boolean lowLatency;
+  boolean lossless;
+  byte[] vendorSpecificParameters;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecSpecificCapabilitiesLtv.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecSpecificCapabilitiesLtv.aidl
new file mode 100644
index 0000000..60c276b
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecSpecificCapabilitiesLtv.aidl
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+union CodecSpecificCapabilitiesLtv {
+  android.hardware.bluetooth.audio.CodecSpecificCapabilitiesLtv.SupportedSamplingFrequencies supportedSamplingFrequencies;
+  android.hardware.bluetooth.audio.CodecSpecificCapabilitiesLtv.SupportedFrameDurations supportedFrameDurations;
+  android.hardware.bluetooth.audio.CodecSpecificCapabilitiesLtv.SupportedAudioChannelCounts supportedAudioChannelCounts;
+  android.hardware.bluetooth.audio.CodecSpecificCapabilitiesLtv.SupportedOctetsPerCodecFrame supportedOctetsPerCodecFrame;
+  android.hardware.bluetooth.audio.CodecSpecificCapabilitiesLtv.SupportedMaxCodecFramesPerSDU supportedMaxCodecFramesPerSDU;
+  parcelable SupportedSamplingFrequencies {
+    int bitmask;
+    const int HZ8000 = 0x0001;
+    const int HZ11025 = 0x0002;
+    const int HZ16000 = 0x0004;
+    const int HZ22050 = 0x0008;
+    const int HZ24000 = 0x0010;
+    const int HZ32000 = 0x0020;
+    const int HZ44100 = 0x0040;
+    const int HZ48000 = 0x0080;
+    const int HZ88200 = 0x0100;
+    const int HZ96000 = 0x0200;
+    const int HZ176400 = 0x0400;
+    const int HZ192000 = 0x0800;
+    const int HZ384000 = 0x1000;
+  }
+  parcelable SupportedFrameDurations {
+    int bitmask;
+    const int US7500 = 0x01;
+    const int US10000 = 0x02;
+    const int US7500PREFERRED = 0x10;
+    const int US10000PREFERRED = 0x20;
+  }
+  parcelable SupportedAudioChannelCounts {
+    int bitmask;
+    const int ONE = 0x01;
+    const int TWO = 0x02;
+    const int THREE = 0x04;
+    const int FOUR = 0x08;
+    const int FIVE = 0x10;
+    const int SIX = 0x20;
+    const int SEVEN = 0x40;
+    const int EIGHT = 0x80;
+  }
+  parcelable SupportedOctetsPerCodecFrame {
+    int min;
+    int max;
+  }
+  parcelable SupportedMaxCodecFramesPerSDU {
+    int value;
+  }
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecSpecificConfigurationLtv.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecSpecificConfigurationLtv.aidl
new file mode 100644
index 0000000..943d396
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecSpecificConfigurationLtv.aidl
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+union CodecSpecificConfigurationLtv {
+  android.hardware.bluetooth.audio.CodecSpecificConfigurationLtv.CodecFrameBlocksPerSDU codecFrameBlocksPerSDU;
+  android.hardware.bluetooth.audio.CodecSpecificConfigurationLtv.SamplingFrequency samplingFrequency;
+  android.hardware.bluetooth.audio.CodecSpecificConfigurationLtv.FrameDuration frameDuration;
+  android.hardware.bluetooth.audio.CodecSpecificConfigurationLtv.AudioChannelAllocation audioChannelAllocation;
+  android.hardware.bluetooth.audio.CodecSpecificConfigurationLtv.OctetsPerCodecFrame octetsPerCodecFrame;
+  @Backing(type="byte")
+  enum SamplingFrequency {
+    HZ8000 = 0x01,
+    HZ11025 = 0x02,
+    HZ16000 = 0x03,
+    HZ22050 = 0x04,
+    HZ24000 = 0x05,
+    HZ32000 = 0x06,
+    HZ44100 = 0x07,
+    HZ48000 = 0x08,
+    HZ88200 = 0x09,
+    HZ96000 = 0x0A,
+    HZ176400 = 0x0B,
+    HZ192000 = 0x0C,
+    HZ384000 = 0x0D,
+  }
+  @Backing(type="byte")
+  enum FrameDuration {
+    US7500 = 0x00,
+    US10000 = 0x01,
+  }
+  parcelable AudioChannelAllocation {
+    int bitmask;
+    const int NOT_ALLOWED = 0x00000000;
+    const int FRONT_LEFT = 0x00000001;
+    const int FRONT_RIGHT = 0x00000002;
+    const int FRONT_CENTER = 0x00000004;
+    const int LOW_FREQUENCY_EFFECTS_1 = 0x00000008;
+    const int BACK_LEFT = 0x00000010;
+    const int BACK_RIGHT = 0x00000020;
+    const int FRONT_LEFT_OF_CENTER = 0x00000040;
+    const int FRONT_RIGHT_OF_CENTER = 0x00000080;
+    const int BACK_CENTER = 0x00000100;
+    const int LOW_FREQUENCY_EFFECTS_2 = 0x00000200;
+    const int SIDE_LEFT = 0x00000400;
+    const int SIDE_RIGHT = 0x00000800;
+    const int TOP_FRONT_LEFT = 0x00001000;
+    const int TOP_FRONT_RIGHT = 0x00002000;
+    const int TOP_FRONT_CENTER = 0x00004000;
+    const int TOP_CENTER = 0x00008000;
+    const int TOP_BACK_LEFT = 0x00010000;
+    const int TOP_BACK_RIGHT = 0x00020000;
+    const int TOP_SIDE_LEFT = 0x00040000;
+    const int TOP_SIDE_RIGHT = 0x00080000;
+    const int TOP_BACK_CENTER = 0x00100000;
+    const int BOTTOM_FRONT_CENTER = 0x00200000;
+    const int BOTTOM_FRONT_LEFT = 0x00400000;
+    const int BOTTOM_FRONT_RIGHT = 0x00800000;
+    const int FRONT_LEFT_WIDE = 0x01000000;
+    const int FRONT_RIGHT_WIDE = 0x02000000;
+    const int LEFT_SURROUND = 0x04000000;
+    const int RIGHT_SURROUND = 0x08000000;
+  }
+  parcelable OctetsPerCodecFrame {
+    int value;
+  }
+  parcelable CodecFrameBlocksPerSDU {
+    int value;
+  }
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecType.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecType.aidl
index 3e204f9..d4f205e 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecType.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecType.aidl
@@ -34,16 +34,16 @@
 package android.hardware.bluetooth.audio;
 @Backing(type="int") @VintfStability
 enum CodecType {
-  UNKNOWN = 0,
-  SBC = 1,
-  AAC = 2,
-  APTX = 3,
-  APTX_HD = 4,
-  LDAC = 5,
-  LC3 = 6,
-  VENDOR = 7,
-  APTX_ADAPTIVE = 8,
-  OPUS = 9,
-  APTX_ADAPTIVE_LE = 10,
-  APTX_ADAPTIVE_LEX = 11,
+  UNKNOWN,
+  SBC,
+  AAC,
+  APTX,
+  APTX_HD,
+  LDAC,
+  LC3,
+  VENDOR,
+  APTX_ADAPTIVE,
+  OPUS,
+  APTX_ADAPTIVE_LE,
+  APTX_ADAPTIVE_LEX,
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/ConfigurationFlags.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/ConfigurationFlags.aidl
new file mode 100644
index 0000000..6b3cf72
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/ConfigurationFlags.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable ConfigurationFlags {
+  int bitmask;
+  const int NONE = 0x0000;
+  const int LOSSLESS = 0x0001;
+  const int LOW_LATENCY = 0x0002;
+  const int ALLOW_ASYMMETRIC_CONFIGURATIONS = 0x0004;
+  const int SPATIAL_AUDIO = 0x0008;
+  const int PROVIDE_ASE_METADATA = 0x0010;
+  const int MONO_MIC_CONFIGURATION = 0x0020;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/HfpConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/HfpConfiguration.aidl
new file mode 100644
index 0000000..490a05d
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/HfpConfiguration.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable HfpConfiguration {
+  android.hardware.bluetooth.audio.CodecId codecId;
+  int connectionHandle;
+  boolean nrec;
+  boolean controllerCodec;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/IBluetoothAudioProvider.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/IBluetoothAudioProvider.aidl
index 267af0f..3a2dcef 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/IBluetoothAudioProvider.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/IBluetoothAudioProvider.aidl
@@ -40,4 +40,160 @@
   void streamSuspended(in android.hardware.bluetooth.audio.BluetoothAudioStatus status);
   void updateAudioConfiguration(in android.hardware.bluetooth.audio.AudioConfiguration audioConfig);
   void setLowLatencyModeAllowed(in boolean allowed);
+  android.hardware.bluetooth.audio.A2dpStatus parseA2dpConfiguration(in android.hardware.bluetooth.audio.CodecId codecId, in byte[] configuration, out android.hardware.bluetooth.audio.CodecParameters codecParameters);
+  @nullable android.hardware.bluetooth.audio.A2dpConfiguration getA2dpConfiguration(in List<android.hardware.bluetooth.audio.A2dpRemoteCapabilities> remoteA2dpCapabilities, in android.hardware.bluetooth.audio.A2dpConfigurationHint hint);
+  void setCodecPriority(in android.hardware.bluetooth.audio.CodecId codecId, int priority);
+  android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioAseConfigurationSetting[] getLeAudioAseConfiguration(in @nullable android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioDeviceCapabilities[] remoteSinkAudioCapabilities, in @nullable android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioDeviceCapabilities[] remoteSourceAudioCapabilities, in android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioConfigurationRequirement[] requirements);
+  android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioAseQosConfigurationPair getLeAudioAseQosConfiguration(in android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioAseQosConfigurationRequirement qosRequirement);
+  android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioDataPathConfigurationPair getLeAudioAseDatapathConfiguration(in @nullable android.hardware.bluetooth.audio.IBluetoothAudioProvider.StreamConfig sinkConfig, in @nullable android.hardware.bluetooth.audio.IBluetoothAudioProvider.StreamConfig sourceConfig);
+  void onSinkAseMetadataChanged(in android.hardware.bluetooth.audio.IBluetoothAudioProvider.AseState state, int cigId, int cisId, in @nullable android.hardware.bluetooth.audio.MetadataLtv[] metadata);
+  void onSourceAseMetadataChanged(in android.hardware.bluetooth.audio.IBluetoothAudioProvider.AseState state, int cigId, int cisId, in @nullable android.hardware.bluetooth.audio.MetadataLtv[] metadata);
+  android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioBroadcastConfigurationSetting getLeAudioBroadcastConfiguration(in @nullable android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioDeviceCapabilities[] remoteSinkAudioCapabilities, in android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioBroadcastConfigurationRequirement requirement);
+  android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioDataPathConfiguration getLeAudioBroadcastDatapathConfiguration(in android.hardware.bluetooth.audio.AudioContext audioContext, in android.hardware.bluetooth.audio.LeAudioBroadcastConfiguration.BroadcastStreamMap[] streamMap);
+  const int CODEC_PRIORITY_DISABLED = (-1) /* -1 */;
+  const int CODEC_PRIORITY_NONE = 0;
+  @VintfStability
+  parcelable LeAudioDeviceCapabilities {
+    android.hardware.bluetooth.audio.CodecId codecId;
+    android.hardware.bluetooth.audio.CodecSpecificCapabilitiesLtv[] codecSpecificCapabilities;
+    @nullable byte[] vendorCodecSpecificCapabilities;
+    @nullable android.hardware.bluetooth.audio.MetadataLtv[] metadata;
+  }
+  @VintfStability
+  parcelable LeAudioDataPathConfiguration {
+    int dataPathId;
+    android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioDataPathConfiguration.DataPathConfiguration dataPathConfiguration;
+    android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioDataPathConfiguration.IsoDataPathConfiguration isoDataPathConfiguration;
+    @VintfStability
+    parcelable IsoDataPathConfiguration {
+      android.hardware.bluetooth.audio.CodecId codecId;
+      boolean isTransparent;
+      int controllerDelayUs;
+      @nullable byte[] configuration;
+    }
+    @VintfStability
+    parcelable DataPathConfiguration {
+      @nullable byte[] configuration;
+    }
+  }
+  @VintfStability
+  parcelable LeAudioAseQosConfiguration {
+    int sduIntervalUs;
+    android.hardware.bluetooth.audio.IBluetoothAudioProvider.Framing framing;
+    android.hardware.bluetooth.audio.Phy[] phy;
+    int maxTransportLatencyMs;
+    int maxSdu;
+    int retransmissionNum;
+  }
+  @Backing(type="byte") @VintfStability
+  enum Packing {
+    SEQUENTIAL = 0x00,
+    INTERLEAVED = 0x01,
+  }
+  @Backing(type="byte") @VintfStability
+  enum Framing {
+    UNFRAMED = 0x00,
+    FRAMED = 0x01,
+  }
+  @VintfStability
+  parcelable LeAudioAseConfigurationSetting {
+    android.hardware.bluetooth.audio.AudioContext audioContext;
+    android.hardware.bluetooth.audio.IBluetoothAudioProvider.Packing packing;
+    @nullable android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioAseConfigurationSetting.AseDirectionConfiguration[] sinkAseConfiguration;
+    @nullable android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioAseConfigurationSetting.AseDirectionConfiguration[] sourceAseConfiguration;
+    @nullable android.hardware.bluetooth.audio.ConfigurationFlags flags;
+    @VintfStability
+    parcelable AseDirectionConfiguration {
+      android.hardware.bluetooth.audio.LeAudioAseConfiguration aseConfiguration;
+      @nullable android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioAseQosConfiguration qosConfiguration;
+      @nullable android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioDataPathConfiguration dataPathConfiguration;
+    }
+  }
+  @VintfStability
+  parcelable LeAudioConfigurationRequirement {
+    android.hardware.bluetooth.audio.AudioContext audioContext;
+    @nullable android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioConfigurationRequirement.AseDirectionRequirement[] sinkAseRequirement;
+    @nullable android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioConfigurationRequirement.AseDirectionRequirement[] sourceAseRequirement;
+    @nullable android.hardware.bluetooth.audio.ConfigurationFlags flags;
+    @VintfStability
+    parcelable AseDirectionRequirement {
+      android.hardware.bluetooth.audio.LeAudioAseConfiguration aseConfiguration;
+    }
+  }
+  @VintfStability
+  parcelable LeAudioAseQosConfigurationRequirement {
+    android.hardware.bluetooth.audio.AudioContext audioContext;
+    @nullable android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioAseQosConfigurationRequirement.AseQosDirectionRequirement sinkAseQosRequirement;
+    @nullable android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioAseQosConfigurationRequirement.AseQosDirectionRequirement sourceAseQosRequirement;
+    @nullable android.hardware.bluetooth.audio.ConfigurationFlags flags;
+    @VintfStability
+    parcelable AseQosDirectionRequirement {
+      android.hardware.bluetooth.audio.IBluetoothAudioProvider.Framing framing;
+      android.hardware.bluetooth.audio.Phy[] preferredPhy;
+      int preferredRetransmissionNum;
+      int maxTransportLatencyMs;
+      int presentationDelayMinUs;
+      int presentationDelayMaxUs;
+      int preferredPresentationDelayMinUs;
+      int preferredPresentationDelayMaxUs;
+      android.hardware.bluetooth.audio.LeAudioAseConfiguration aseConfiguration;
+    }
+  }
+  @VintfStability
+  parcelable LeAudioAseQosConfigurationPair {
+    @nullable android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioAseQosConfiguration sinkQosConfiguration;
+    @nullable android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioAseQosConfiguration sourceQosConfiguration;
+  }
+  parcelable LeAudioDataPathConfigurationPair {
+    @nullable android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioDataPathConfiguration inputConfig;
+    @nullable android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioDataPathConfiguration outputConfig;
+  }
+  parcelable StreamConfig {
+    android.hardware.bluetooth.audio.AudioContext audioContext;
+    android.hardware.bluetooth.audio.LeAudioConfiguration.StreamMap[] streamMap;
+  }
+  @Backing(type="byte") @VintfStability
+  enum AseState {
+    ENABLING = 0x00,
+    STREAMING = 0x01,
+    DISABLING = 0x02,
+  }
+  @Backing(type="byte") @VintfStability
+  enum BroadcastQuality {
+    STANDARD,
+    HIGH,
+  }
+  @VintfStability
+  parcelable LeAudioBroadcastSubgroupConfigurationRequirement {
+    android.hardware.bluetooth.audio.AudioContext audioContext;
+    android.hardware.bluetooth.audio.IBluetoothAudioProvider.BroadcastQuality quality;
+    int bisNumPerSubgroup;
+  }
+  @VintfStability
+  parcelable LeAudioBroadcastConfigurationRequirement {
+    android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioBroadcastSubgroupConfigurationRequirement[] subgroupConfigurationRequirements;
+  }
+  @VintfStability
+  parcelable LeAudioSubgroupBisConfiguration {
+    int numBis;
+    android.hardware.bluetooth.audio.LeAudioBisConfiguration bisConfiguration;
+  }
+  @VintfStability
+  parcelable LeAudioBroadcastSubgroupConfiguration {
+    android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioSubgroupBisConfiguration[] bisConfigurations;
+    @nullable byte[] vendorCodecConfiguration;
+  }
+  @VintfStability
+  parcelable LeAudioBroadcastConfigurationSetting {
+    int sduIntervalUs;
+    int numBis;
+    int maxSduOctets;
+    int maxTransportLatencyMs;
+    int retransmitionNum;
+    android.hardware.bluetooth.audio.Phy[] phy;
+    android.hardware.bluetooth.audio.IBluetoothAudioProvider.Packing packing;
+    android.hardware.bluetooth.audio.IBluetoothAudioProvider.Framing framing;
+    @nullable android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioDataPathConfiguration dataPathConfiguration;
+    android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioBroadcastSubgroupConfiguration[] subgroupsConfigurations;
+  }
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/IBluetoothAudioProviderFactory.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/IBluetoothAudioProviderFactory.aidl
index 5e33deb..edb79a3 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/IBluetoothAudioProviderFactory.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/IBluetoothAudioProviderFactory.aidl
@@ -36,4 +36,11 @@
 interface IBluetoothAudioProviderFactory {
   android.hardware.bluetooth.audio.AudioCapabilities[] getProviderCapabilities(in android.hardware.bluetooth.audio.SessionType sessionType);
   android.hardware.bluetooth.audio.IBluetoothAudioProvider openProvider(in android.hardware.bluetooth.audio.SessionType sessionType);
+  @nullable android.hardware.bluetooth.audio.IBluetoothAudioProviderFactory.ProviderInfo getProviderInfo(in android.hardware.bluetooth.audio.SessionType sessionType);
+  @VintfStability
+  parcelable ProviderInfo {
+    String name;
+    android.hardware.bluetooth.audio.CodecInfo[] codecInfos;
+    boolean supportsMultidirectionalCapabilities;
+  }
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacChannelMode.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacChannelMode.aidl
index 88d6faf..3d80c4b 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacChannelMode.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacChannelMode.aidl
@@ -34,8 +34,8 @@
 package android.hardware.bluetooth.audio;
 @Backing(type="byte") @VintfStability
 enum LdacChannelMode {
-  UNKNOWN = 0,
-  STEREO = 1,
-  DUAL = 2,
-  MONO = 3,
+  UNKNOWN,
+  STEREO,
+  DUAL,
+  MONO,
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacQualityIndex.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacQualityIndex.aidl
index 35e4358..a332dc5 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacQualityIndex.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacQualityIndex.aidl
@@ -34,8 +34,8 @@
 package android.hardware.bluetooth.audio;
 @Backing(type="byte") @VintfStability
 enum LdacQualityIndex {
-  HIGH = 0,
-  MID = 1,
-  LOW = 2,
-  ABR = 3,
+  HIGH,
+  MID,
+  LOW,
+  ABR,
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioAseConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioAseConfiguration.aidl
new file mode 100644
index 0000000..bffc88b
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioAseConfiguration.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable LeAudioAseConfiguration {
+  android.hardware.bluetooth.audio.LeAudioAseConfiguration.TargetLatency targetLatency;
+  android.hardware.bluetooth.audio.Phy targetPhy;
+  @nullable android.hardware.bluetooth.audio.CodecId codecId;
+  android.hardware.bluetooth.audio.CodecSpecificConfigurationLtv[] codecConfiguration;
+  @nullable byte[] vendorCodecConfiguration;
+  @nullable android.hardware.bluetooth.audio.MetadataLtv[] metadata;
+  @Backing(type="byte") @VintfStability
+  enum TargetLatency {
+    UNDEFINED = 0x00,
+    LOWER = 0x01,
+    BALANCED_LATENCY_RELIABILITY = 0x02,
+    HIGHER_RELIABILITY = 0x03,
+  }
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioBisConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioBisConfiguration.aidl
new file mode 100644
index 0000000..b09d34f
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioBisConfiguration.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable LeAudioBisConfiguration {
+  android.hardware.bluetooth.audio.CodecId codecId;
+  android.hardware.bluetooth.audio.CodecSpecificConfigurationLtv[] codecConfiguration;
+  byte[] vendorCodecConfiguration;
+  @nullable android.hardware.bluetooth.audio.MetadataLtv[] metadata;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioBroadcastConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioBroadcastConfiguration.aidl
index 2945710..efd3b02 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioBroadcastConfiguration.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioBroadcastConfiguration.aidl
@@ -42,5 +42,7 @@
     int audioChannelAllocation;
     android.hardware.bluetooth.audio.LeAudioCodecConfiguration leAudioCodecConfig;
     char pcmStreamId;
+    @nullable android.hardware.bluetooth.audio.LeAudioBisConfiguration bisConfiguration;
+    @nullable android.hardware.bluetooth.audio.ConfigurationFlags flags;
   }
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioConfiguration.aidl
index 2d9ebae..25a9797 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioConfiguration.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LeAudioConfiguration.aidl
@@ -44,5 +44,16 @@
     char streamHandle;
     int audioChannelAllocation;
     boolean isStreamActive;
+    @nullable android.hardware.bluetooth.audio.LeAudioAseConfiguration aseConfiguration;
+    @nullable android.hardware.bluetooth.audio.ConfigurationFlags flags;
+    @nullable android.hardware.bluetooth.audio.LeAudioConfiguration.StreamMap.BluetoothDeviceAddress bluetoothDeviceAddress;
+    parcelable BluetoothDeviceAddress {
+      byte[6] deviceAddress;
+      android.hardware.bluetooth.audio.LeAudioConfiguration.StreamMap.BluetoothDeviceAddress.DeviceAddressType deviceAddressType;
+      enum DeviceAddressType {
+        BLE_ADDRESS_PUBLIC = 0x00,
+        BLE_ADDRESS_RANDOM = 0x01,
+      }
+    }
   }
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/MetadataLtv.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/MetadataLtv.aidl
new file mode 100644
index 0000000..5e8a2ae
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/MetadataLtv.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+union MetadataLtv {
+  android.hardware.bluetooth.audio.MetadataLtv.PreferredAudioContexts preferredAudioContexts;
+  android.hardware.bluetooth.audio.MetadataLtv.StreamingAudioContexts streamingAudioContexts;
+  android.hardware.bluetooth.audio.MetadataLtv.VendorSpecific vendorSpecific;
+  parcelable PreferredAudioContexts {
+    android.hardware.bluetooth.audio.AudioContext values;
+  }
+  parcelable StreamingAudioContexts {
+    android.hardware.bluetooth.audio.AudioContext values;
+  }
+  parcelable VendorSpecific {
+    int companyId;
+    byte[] opaqueValue;
+  }
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/Phy.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/Phy.aidl
new file mode 100644
index 0000000..bfeabcd
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/Phy.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@Backing(type="byte") @VintfStability
+enum Phy {
+  UNDEFINED = 0x00,
+  ONE_M = 0x01,
+  TWO_M = 0x02,
+  CODED = 0x03,
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcAllocMethod.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcAllocMethod.aidl
index 091f6d7..9cf65d5 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcAllocMethod.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcAllocMethod.aidl
@@ -34,6 +34,6 @@
 package android.hardware.bluetooth.audio;
 @Backing(type="byte") @VintfStability
 enum SbcAllocMethod {
-  ALLOC_MD_S = 0,
-  ALLOC_MD_L = 1,
+  ALLOC_MD_S,
+  ALLOC_MD_L,
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcChannelMode.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcChannelMode.aidl
index 6441a99..7779aa0 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcChannelMode.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcChannelMode.aidl
@@ -34,9 +34,9 @@
 package android.hardware.bluetooth.audio;
 @Backing(type="byte") @VintfStability
 enum SbcChannelMode {
-  UNKNOWN = 0,
-  JOINT_STEREO = 1,
-  STEREO = 2,
-  DUAL = 3,
-  MONO = 4,
+  UNKNOWN,
+  JOINT_STEREO,
+  STEREO,
+  DUAL,
+  MONO,
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SessionType.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SessionType.aidl
index 33a3187..71cca53 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SessionType.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SessionType.aidl
@@ -34,16 +34,19 @@
 package android.hardware.bluetooth.audio;
 @Backing(type="byte") @VintfStability
 enum SessionType {
-  UNKNOWN = 0,
-  A2DP_SOFTWARE_ENCODING_DATAPATH = 1,
-  A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH = 2,
-  HEARING_AID_SOFTWARE_ENCODING_DATAPATH = 3,
-  LE_AUDIO_SOFTWARE_ENCODING_DATAPATH = 4,
-  LE_AUDIO_SOFTWARE_DECODING_DATAPATH = 5,
-  LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH = 6,
-  LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH = 7,
-  LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH = 8,
-  LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH = 9,
-  A2DP_SOFTWARE_DECODING_DATAPATH = 10,
-  A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH = 11,
+  UNKNOWN,
+  A2DP_SOFTWARE_ENCODING_DATAPATH,
+  A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
+  HEARING_AID_SOFTWARE_ENCODING_DATAPATH,
+  LE_AUDIO_SOFTWARE_ENCODING_DATAPATH,
+  LE_AUDIO_SOFTWARE_DECODING_DATAPATH,
+  LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
+  LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH,
+  LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH,
+  LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
+  A2DP_SOFTWARE_DECODING_DATAPATH,
+  A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH,
+  HFP_SOFTWARE_ENCODING_DATAPATH,
+  HFP_SOFTWARE_DECODING_DATAPATH,
+  HFP_HARDWARE_OFFLOAD_DATAPATH,
 }
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/A2dpConfiguration.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/A2dpConfiguration.aidl
new file mode 100644
index 0000000..a7fd9ff
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/A2dpConfiguration.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.CodecId;
+import android.hardware.bluetooth.audio.CodecParameters;
+
+/**
+ * A2DP Service Configuration
+ */
+@VintfStability
+parcelable A2dpConfiguration {
+    /**
+     * Remote Stream Endpoint Identifier
+     */
+    int remoteSeid;
+
+    /**
+     * Codec Selection and configuration, in a generic way with `parameters`
+     * and as defined by A2DP for codec interoperability requirements, with
+     * `configuration`. Using `id.a2dp`, the format is given by the `Codec
+     * Specific Information Elements` [A2DP - 4.3-6.2], and using `id.vendor`,
+     * by `Vendor Specific Value` [A2DP - 4.7.2].
+     * In any case, this byte array is limited by the framework to 128 Bytes.
+     */
+    CodecId id;
+    CodecParameters parameters;
+    byte[] configuration;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/A2dpConfigurationHint.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/A2dpConfigurationHint.aidl
new file mode 100644
index 0000000..f707a8a
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/A2dpConfigurationHint.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.AudioContext;
+import android.hardware.bluetooth.audio.CodecId;
+import android.hardware.bluetooth.audio.CodecParameters;
+
+/**
+ * A2DP Configuration Hints
+ */
+@VintfStability
+parcelable A2dpConfigurationHint {
+    /**
+     * Bluetooth Device Address, intended to be used for interoperabilities.
+     */
+    byte[6] bdAddr;
+
+    /**
+     * Audio configuration hints:
+     * - The starting audio context of the session
+     * - An optional preference of codec and / or parameters
+     */
+
+    AudioContext audioContext;
+    @nullable CodecId codecId;
+    @nullable CodecParameters codecParameters;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/A2dpRemoteCapabilities.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/A2dpRemoteCapabilities.aidl
new file mode 100644
index 0000000..87277f1
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/A2dpRemoteCapabilities.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.CodecId;
+
+/**
+ * A2DP Remote Capabilites
+ */
+@VintfStability
+parcelable A2dpRemoteCapabilities {
+    /**
+     * Remote Stream Endpoint identifier
+     */
+    int seid;
+
+    /**
+     * Codec Identifier and `capabilities` as defined by A2DP for codec
+     * interoperability requirements. Using `id.a2dp`, the format is given
+     * by the `Codec Specific Information Elements` [A2DP - 4.3-6.2], and
+     * using `id.vendor`, by `Vendor Specific Value` [A2DP - 4.7.2].
+     */
+    CodecId id;
+    byte[] capabilities;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/A2dpStatus.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/A2dpStatus.aidl
new file mode 100644
index 0000000..8eba3c9
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/A2dpStatus.aidl
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+@VintfStability
+@Backing(type="byte")
+enum A2dpStatus {
+
+    OK = 0,
+
+    /**
+     * Error codes defined by AVDTP [AVDTP - 8.20.6.2]
+     */
+
+    BAD_LENGTH = 0x11u8,
+    BAD_PAYLOAD_FORMAT = 0x18u8,
+
+    /**
+     * Error codecs defined by A2DP for AVDTP Interoperability [A2DP - 5.1.3]
+     */
+
+    INVALID_CODEC_TYPE = 0xC1u8,
+    NOT_SUPPORTED_CODEC_TYPE = 0xC2u8,
+    INVALID_SAMPLING_FREQUENCY = 0xC3u8,
+    NOT_SUPPORTED_SAMPLING_FREQUENCY = 0xC4u8,
+    INVALID_CHANNEL_MODE = 0xC5u8,
+    NOT_SUPPORTED_CHANNEL_MODE = 0xC6u8,
+    INVALID_SUBBANDS = 0xC7u8,
+    NOT_SUPPORTED_SUBBANDS = 0xC8u8,
+    INVALID_ALLOCATION_METHOD = 0xC9u8,
+    NOT_SUPPORTED_ALLOCATION_METHOD = 0xCAu8,
+    INVALID_MINIMUM_BITPOOL_VALUE = 0xCBu8,
+    NOT_SUPPORTED_MINIMUM_BITPOOL_VALUE = 0xCCu8,
+    INVALID_MAXIMUM_BITPOOL_VALUE = 0xCDu8,
+    NOT_SUPPORTED_MAXIMUM_BITPOOL_VALUE = 0xCEu8,
+    NOT_SUPPORTED_VBR = 0xD3u8,
+    NOT_SUPPORTED_BIT_RATE = 0xD5u8,
+    INVALID_OBJECT_TYPE = 0xD6u8,
+    NOT_SUPPORTED_OBJECT_TYPE = 0xD7u8,
+    INVALID_CHANNELS = 0xD8u8,
+    NOT_SUPPORTED_CHANNELS = 0xD9u8,
+    INVALID_BLOCK_LENGTH = 0xDDu8,
+    INVALID_CODEC_PARAMETER = 0xE2u8,
+    NOT_SUPPORTED_CODEC_PARAMETER = 0xE3u8,
+    INVALID_DRC = 0xE4u8,
+    NOT_SUPPORTED_DRC = 0xE5u8,
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/A2dpStreamConfiguration.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/A2dpStreamConfiguration.aidl
new file mode 100644
index 0000000..2a0c4d8
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/A2dpStreamConfiguration.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.CodecId;
+
+@VintfStability
+parcelable A2dpStreamConfiguration {
+    /**
+     * Peer MTU (16 bits)
+     */
+    int peerMtu;
+
+    /**
+     * Optional SCMS-T Content Protection header
+     * that precedes audio content when enabled [A2DP - 3.2.1-2].
+     * The content protection byte is defined by [Assigned Number - 6.3.2].
+     */
+    @nullable byte[1] cpHeaderScmst;
+
+    /**
+     * Codec Identifier and `configuration` as defined by A2DP for codec
+     * interoperability requirements. Using `codecId.a2dp`, the format is given
+     * by the `Codec Specific Information Elements` [A2DP - 4.3-6.2], and
+     * using `codecId.vendor`, by `Vendor Specific Value` [A2DP - 4.7.2].
+     */
+    CodecId codecId;
+    byte[] configuration;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AudioConfiguration.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AudioConfiguration.aidl
index a06337e..5317dfb 100644
--- a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AudioConfiguration.aidl
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AudioConfiguration.aidl
@@ -16,7 +16,9 @@
 
 package android.hardware.bluetooth.audio;
 
+import android.hardware.bluetooth.audio.A2dpStreamConfiguration;
 import android.hardware.bluetooth.audio.CodecConfiguration;
+import android.hardware.bluetooth.audio.HfpConfiguration;
 import android.hardware.bluetooth.audio.LeAudioBroadcastConfiguration;
 import android.hardware.bluetooth.audio.LeAudioConfiguration;
 import android.hardware.bluetooth.audio.PcmConfiguration;
@@ -30,4 +32,6 @@
     CodecConfiguration a2dpConfig;
     LeAudioConfiguration leAudioConfig;
     LeAudioBroadcastConfiguration leAudioBroadcastConfig;
+    HfpConfiguration hfpConfig;
+    A2dpStreamConfiguration a2dp;
 }
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AudioContext.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AudioContext.aidl
new file mode 100644
index 0000000..306e897
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AudioContext.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+/**
+ * Context of the audio configuration.
+ * Defined by PACS (Le Audio) and used either by A2DP or LE Audio.
+ * The `bitmask` is any combination of BT Sig standardized values
+ * [Assigned Numbers - 6.12.3], defined in this scope.
+ */
+@VintfStability
+parcelable AudioContext {
+    const int UNSPECIFIED = 0x0001;
+    const int CONVERSATIONAL = 0x0002;
+    const int MEDIA = 0x0004;
+    const int GAME = 0x0008;
+    const int INSTRUCTIONAL = 0x0010;
+    const int VOICE_ASSISTANTS = 0x0020;
+    const int LIVE_AUDIO = 0x0040;
+    const int SOUND_EFFECTS = 0x0080;
+    const int NOTIFICATIONS = 0x0100;
+    const int RINGTONE_ALERTS = 0x0200;
+    const int ALERTS = 0x0400;
+    const int EMERGENCY_ALARM = 0x0800;
+
+    int bitmask;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecId.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecId.aidl
new file mode 100644
index 0000000..2243957
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecId.aidl
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+@VintfStability
+union CodecId {
+    /**
+     * Codec Identifier defined for A2DP
+     * The values are assigned by BT Sig [Assigned Numbers - 6.5.1]
+     */
+    enum A2dp { SBC = 0, AAC = 2 }
+
+    /**
+     * Codec Identifier defined for the Bluetooth Core Specification
+     * The values are assigned by BT Sig [Assigned Numbers - 2.11]
+     */
+    enum Core { CVSD = 2, MSBC = 5, LC3 = 6 }
+
+    /**
+     * Vendor Codec:
+     * id       16 bits - Vendor identifier, assigned by BT Sig [Assigned Numbers - 7.1]
+     * codecId  16 bits - Assigned by the vendor
+     */
+    parcelable Vendor {
+        int id;
+        int codecId;
+    }
+
+    /**
+     * Standard (A2DP or Core numbering space) or vendor
+     */
+    A2dp a2dp = A2dp.SBC;
+    Core core;
+    Vendor vendor;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecInfo.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecInfo.aidl
new file mode 100644
index 0000000..b60d70f
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecInfo.aidl
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.ChannelMode;
+import android.hardware.bluetooth.audio.CodecId;
+import android.hardware.bluetooth.audio.ConfigurationFlags;
+
+/**
+ * General information about a Codec
+ */
+@VintfStability
+parcelable CodecInfo {
+    /**
+     * Codec identifier
+     */
+    CodecId id;
+    /**
+     * Human readable name used to present codec to the user and for debug logs
+     */
+    String name;
+
+    /**
+     * A2DP Context
+     */
+    parcelable A2dp {
+        /**
+         * The capabilities as defined by A2DP for codec interoperability
+         * requirements. With `id.a2dp`, the format is given by the `Codec
+         * Specific Information Elements` [A2DP - 4.3-6.2], and with `id.vendor`,
+         * by `Vendor Specific Value` [A2DP - 4.7.2].
+         */
+        byte[] capabilities;
+
+        /**
+         * PCM characteristics:
+         * - Mono, Dual-Mono or Stereo
+         * - Supported sampling frequencies, in Hz.
+         * - Fixed point resolution, basically 16, 24 or 32 bits by samples.
+         *   The value 32 should be used for floating point representation.
+         *
+         * When the bitdepth is not an encoding/decoding parameter (don't take part
+         * in the interoperability), the `bitdepth` list shall have a single element
+         * indicating the bitdepth selected for the platform.
+         */
+        ChannelMode[] channelMode;
+        int[] samplingFrequencyHz;
+        int[] bitdepth;
+
+        /**
+         * Lossless capable characteristic
+         */
+        boolean lossless;
+    }
+
+    /**
+     * HFP Context
+     */
+    parcelable Hfp {
+        /**
+         * Vendor-specific identifiers of stream data paths, set in the
+         * HCI Command Enhanced Setup Synchronous Connection [Core - 4.E.7.1.45],
+         * in the command parameters respectively `Input_Data_Path` and
+         * `Output_Data_Path`. The value range from 0x01 to 0xFE.
+         * The stack operates as a pass-through; the client SHALL NOT
+         * interpret the values.
+         */
+        int inputDataPath = 1;
+        int outputDataPath = 1;
+
+        /**
+         * Whether the audio stream is encoded and decoded in the controller or
+         * locally; enable the controller transparent mode when the audio
+         * stream is locally processed.
+         */
+        boolean useControllerCodec = true;
+    }
+
+    /**
+     * LE Audio Context
+     */
+    parcelable LeAudio {
+        /**
+         * List of independently supported channel modes: Mono, Dual-Mono, or
+         * Stereo.
+         */
+        ChannelMode[] channelMode;
+
+        /**
+         * List of supported sampling frequencies, in Hz.
+         */
+        int[] samplingFrequencyHz;
+
+        /**
+         * List of supported FrameDurations in microseconds.
+         */
+        int[] frameDurationUs;
+
+        /**
+         * - Fixed point resolution, basically 16, 24 or 32 bits by samples.
+         *   The value 32 should be used for floating point representation.
+         *
+         * When the bitdepth is not an encoding/decoding parameter (don't take
+         * part in the interoperability), the `bitdepth` list shall have a
+         * single element indicating the bitdepth selected for the platform.
+         */
+        int[] bitdepth;
+
+        /**
+         * Additional configuration flags
+         */
+        @nullable ConfigurationFlags flags;
+    }
+
+    /**
+     * Specific informations,
+     * depending on transport.
+     */
+    union Transport {
+        LeAudio leAudio;
+        A2dp a2dp;
+        Hfp hfp;
+    }
+
+    Transport transport;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecParameters.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecParameters.aidl
new file mode 100644
index 0000000..b6f8a94
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecParameters.aidl
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.ChannelMode;
+
+/**
+ * Used to exchange generic codec parameters between the stack and the provider.
+ */
+@VintfStability
+parcelable CodecParameters {
+    /**
+     * PCM related parameters:
+     * - Mono, Dual-Mono or Stereo
+     * - Sampling frequencies, in Hz.
+     * - Fixed point resolution, basically 16, 24 or 32 bits by samples.
+     *   The value 32 should be used for floating point representation..
+     */
+    ChannelMode channelMode;
+    int samplingFrequencyHz;
+    int bitdepth;
+
+    /**
+     * Encoding parameters:
+     *
+     * - Bitrate limits on a frame basis, defined in bits per second.
+     *   The encoder bitrate mode can be encoded following this rule:
+     *     . minBitrate equals to maxBitrate for constant bitrate
+     *     . minBitrate set to 0, for VBR with peak bitrate at maxBitratre value.
+     *     . minBitrate greater than 0, for ABR, the bitrate of the stream varies
+     *       between minBitrate to maxBitrate according to link quality.
+     *   The 0 value for both means "undefined" or "don't care".
+     *
+     * - Low-latency configuration privileged
+     * - Lossless effort indication. The 'False' value can be used as "don't care"
+     */
+    int minBitrate;
+    int maxBitrate;
+
+    boolean lowLatency;
+    boolean lossless;
+
+    /**
+     * Vendor specific parameters, inserted in the Vendor Specific HCI Command
+     * `Start A2DP Offload` as it is. The stack operates as a pass-through;
+     * the data SHALL NOT be inspected nor written by the client.
+     * The size is limited to 128 bytes by the client; a larger size is
+     * interpreted as a zero-sized buffer.
+     */
+    byte[] vendorSpecificParameters;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecSpecificCapabilitiesLtv.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecSpecificCapabilitiesLtv.aidl
new file mode 100644
index 0000000..fa302e3
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecSpecificCapabilitiesLtv.aidl
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+/**
+ * Used to exchange generic remote device codec specific capabilities between
+ * the stack and the provider. As defined in Bluetooth Assigned Numbers,
+ * Sec. 6.12.4.
+ */
+@VintfStability
+union CodecSpecificCapabilitiesLtv {
+    /**
+     * Supported sampling frequencies in Hertz
+     */
+    parcelable SupportedSamplingFrequencies {
+        const int HZ8000 = 0x0001;
+        const int HZ11025 = 0x0002;
+        const int HZ16000 = 0x0004;
+        const int HZ22050 = 0x0008;
+        const int HZ24000 = 0x0010;
+        const int HZ32000 = 0x0020;
+        const int HZ44100 = 0x0040;
+        const int HZ48000 = 0x0080;
+        const int HZ88200 = 0x0100;
+        const int HZ96000 = 0x0200;
+        const int HZ176400 = 0x0400;
+        const int HZ192000 = 0x0800;
+        const int HZ384000 = 0x1000;
+
+        /* 16 bits wide bit mask */
+        int bitmask;
+    }
+    /**
+     * Supported frame durations in microseconds
+     */
+    parcelable SupportedFrameDurations {
+        const int US7500 = 0x01;
+        const int US10000 = 0x02;
+        /* Bits 2-3 are RFU */
+        const int US7500PREFERRED = 0x10;
+        const int US10000PREFERRED = 0x20;
+
+        /* 8 bit wide bit mask */
+        int bitmask;
+    }
+    parcelable SupportedAudioChannelCounts {
+        const int ONE = 0x01;
+        const int TWO = 0x02;
+        const int THREE = 0x04;
+        const int FOUR = 0x08;
+        const int FIVE = 0x10;
+        const int SIX = 0x20;
+        const int SEVEN = 0x40;
+        const int EIGHT = 0x80;
+
+        /* 8 bit wide bit mask */
+        int bitmask;
+    }
+    parcelable SupportedOctetsPerCodecFrame {
+        int min;
+        int max;
+    }
+    parcelable SupportedMaxCodecFramesPerSDU {
+        int value;
+    }
+
+    SupportedSamplingFrequencies supportedSamplingFrequencies;
+    SupportedFrameDurations supportedFrameDurations;
+    SupportedAudioChannelCounts supportedAudioChannelCounts;
+    SupportedOctetsPerCodecFrame supportedOctetsPerCodecFrame;
+    SupportedMaxCodecFramesPerSDU supportedMaxCodecFramesPerSDU;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecSpecificConfigurationLtv.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecSpecificConfigurationLtv.aidl
new file mode 100644
index 0000000..c099ebe
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecSpecificConfigurationLtv.aidl
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+/**
+ * Used to exchange generic remote device configuration between the stack and
+ * the provider. As defined in Bluetooth Assigned Numbers, Sec. 6.12.5.
+ */
+@VintfStability
+union CodecSpecificConfigurationLtv {
+    @Backing(type="byte")
+    enum SamplingFrequency {
+        HZ8000 = 0x01,
+        HZ11025 = 0x02,
+        HZ16000 = 0x03,
+        HZ22050 = 0x04,
+        HZ24000 = 0x05,
+        HZ32000 = 0x06,
+        HZ44100 = 0x07,
+        HZ48000 = 0x08,
+        HZ88200 = 0x09,
+        HZ96000 = 0x0A,
+        HZ176400 = 0x0B,
+        HZ192000 = 0x0C,
+        HZ384000 = 0x0D,
+    }
+
+    @Backing(type="byte")
+    enum FrameDuration {
+        US7500 = 0x00,
+        US10000 = 0x01,
+    }
+
+    parcelable AudioChannelAllocation {
+        const int NOT_ALLOWED = 0x00000000;
+        const int FRONT_LEFT = 0x00000001;
+        const int FRONT_RIGHT = 0x00000002;
+        const int FRONT_CENTER = 0x00000004;
+        const int LOW_FREQUENCY_EFFECTS_1 = 0x00000008;
+        const int BACK_LEFT = 0x00000010;
+        const int BACK_RIGHT = 0x00000020;
+        const int FRONT_LEFT_OF_CENTER = 0x00000040;
+        const int FRONT_RIGHT_OF_CENTER = 0x00000080;
+        const int BACK_CENTER = 0x00000100;
+        const int LOW_FREQUENCY_EFFECTS_2 = 0x00000200;
+        const int SIDE_LEFT = 0x00000400;
+        const int SIDE_RIGHT = 0x00000800;
+        const int TOP_FRONT_LEFT = 0x00001000;
+        const int TOP_FRONT_RIGHT = 0x00002000;
+        const int TOP_FRONT_CENTER = 0x00004000;
+        const int TOP_CENTER = 0x00008000;
+        const int TOP_BACK_LEFT = 0x00010000;
+        const int TOP_BACK_RIGHT = 0x00020000;
+        const int TOP_SIDE_LEFT = 0x00040000;
+        const int TOP_SIDE_RIGHT = 0x00080000;
+        const int TOP_BACK_CENTER = 0x00100000;
+        const int BOTTOM_FRONT_CENTER = 0x00200000;
+        const int BOTTOM_FRONT_LEFT = 0x00400000;
+        const int BOTTOM_FRONT_RIGHT = 0x00800000;
+        const int FRONT_LEFT_WIDE = 0x01000000;
+        const int FRONT_RIGHT_WIDE = 0x02000000;
+        const int LEFT_SURROUND = 0x04000000;
+        const int RIGHT_SURROUND = 0x08000000;
+
+        // Bit mask of Audio Locations
+        int bitmask;
+    }
+
+    parcelable OctetsPerCodecFrame {
+        int value;
+    }
+
+    parcelable CodecFrameBlocksPerSDU {
+        int value;
+    }
+
+    CodecFrameBlocksPerSDU codecFrameBlocksPerSDU;
+    SamplingFrequency samplingFrequency;
+    FrameDuration frameDuration;
+    AudioChannelAllocation audioChannelAllocation;
+    OctetsPerCodecFrame octetsPerCodecFrame;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/ConfigurationFlags.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/ConfigurationFlags.aidl
new file mode 100644
index 0000000..a12af49
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/ConfigurationFlags.aidl
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+/**
+ * Coding fetures
+ */
+@VintfStability
+parcelable ConfigurationFlags {
+    const int NONE = 0x0000;
+    /**
+     * Set for the lossless configurations
+     */
+    const int LOSSLESS = 0x0001;
+    /**
+     * Set for the low latency configurations
+     */
+    const int LOW_LATENCY = 0x0002;
+    /**
+     * When set, asymmetric configuration for SINK and SOURCE can be used.
+     * e.g. in GAMING mode stream for 32kHz and back channel for 16 kHz
+     */
+    const int ALLOW_ASYMMETRIC_CONFIGURATIONS = 0x0004;
+    /**
+     * Set for the spatial audio configurations
+     */
+    const int SPATIAL_AUDIO = 0x0008;
+    /**
+     * When set, BluetoothAudioProvider requests to receive ASE metadata.
+     * In such case onSinkAseMetadataChanged() and onSourceAseMetadataChanged
+     * will be called.
+     */
+    const int PROVIDE_ASE_METADATA = 0x0010;
+    /**
+     * Set for mono microphone configurations
+     */
+    const int MONO_MIC_CONFIGURATION = 0x0020;
+
+    int bitmask;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/HfpConfiguration.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/HfpConfiguration.aidl
new file mode 100644
index 0000000..9494bb9
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/HfpConfiguration.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.CodecId;
+
+@VintfStability
+parcelable HfpConfiguration {
+    /**
+     * Codec identifier.
+     */
+    CodecId codecId;
+
+    /**
+     * The connection handle used for SCO connection.
+     * Range: 0x0000 to 0x0EFF.
+     */
+    int connectionHandle;
+
+    /**
+     *  Echo canceling and noise reduction functions resident in the AG.
+     */
+    boolean nrec;
+
+    /**
+     *  Indicate whether the codec is encoded and decoded in the controller.
+     *  If the codec is inside the DSP, then it would be transparent mode.
+     */
+    boolean controllerCodec;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/IBluetoothAudioProvider.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/IBluetoothAudioProvider.aidl
index d5c051e..1424431 100644
--- a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/IBluetoothAudioProvider.aidl
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/IBluetoothAudioProvider.aidl
@@ -16,10 +16,26 @@
 
 package android.hardware.bluetooth.audio;
 
+import android.hardware.bluetooth.audio.A2dpConfiguration;
+import android.hardware.bluetooth.audio.A2dpConfigurationHint;
+import android.hardware.bluetooth.audio.A2dpRemoteCapabilities;
+import android.hardware.bluetooth.audio.A2dpStatus;
 import android.hardware.bluetooth.audio.AudioConfiguration;
+import android.hardware.bluetooth.audio.AudioContext;
 import android.hardware.bluetooth.audio.BluetoothAudioStatus;
+import android.hardware.bluetooth.audio.CodecId;
+import android.hardware.bluetooth.audio.CodecParameters;
+import android.hardware.bluetooth.audio.CodecSpecificCapabilitiesLtv;
+import android.hardware.bluetooth.audio.CodecSpecificConfigurationLtv;
+import android.hardware.bluetooth.audio.ConfigurationFlags;
 import android.hardware.bluetooth.audio.IBluetoothAudioPort;
 import android.hardware.bluetooth.audio.LatencyMode;
+import android.hardware.bluetooth.audio.LeAudioAseConfiguration;
+import android.hardware.bluetooth.audio.LeAudioBisConfiguration;
+import android.hardware.bluetooth.audio.LeAudioBroadcastConfiguration.BroadcastStreamMap;
+import android.hardware.bluetooth.audio.LeAudioConfiguration.StreamMap;
+import android.hardware.bluetooth.audio.MetadataLtv;
+import android.hardware.bluetooth.audio.Phy;
 import android.hardware.common.fmq.MQDescriptor;
 import android.hardware.common.fmq.SynchronizedReadWrite;
 
@@ -59,9 +75,8 @@
      *    audioConfig.pcmConfig parameter. Invalid if streaming is offloaded
      *    from/to hardware or on failure
      */
-    MQDescriptor<byte, SynchronizedReadWrite> startSession(
-            in IBluetoothAudioPort hostIf, in AudioConfiguration audioConfig,
-            in LatencyMode[] supportedLatencyModes);
+    MQDescriptor<byte, SynchronizedReadWrite> startSession(in IBluetoothAudioPort hostIf,
+            in AudioConfiguration audioConfig, in LatencyMode[] supportedLatencyModes);
     /**
      * Callback for IBluetoothAudioPort.startStream()
      *
@@ -93,4 +108,724 @@
      * mode, the API will be called with supported is false.
      */
     void setLowLatencyModeAllowed(in boolean allowed);
+
+    /**
+     * Validate and parse an A2DP Configuration,
+     * shall be used with A2DP session types
+     *
+     * @param codecId Identify the codec
+     * @param The configuration as defined by the A2DP's `Codec Specific
+     *        Information Elements`, or `Vendor Specific Value` when CodecId
+     *        format is set to `VENDOR`.
+     * @param codecParameters result of parsing, when the validation succeeded.
+     * @return A2DP Status of the parsing
+     */
+    A2dpStatus parseA2dpConfiguration(
+            in CodecId codecId, in byte[] configuration, out CodecParameters codecParameters);
+
+    /**
+     * Return a configuration, from a list of remote Capabilites,
+     * shall be used with A2DP session types
+     *
+     * @param remoteCapabilities The capabilities of the remote device
+     * @param hint Hint on selection (audio context and/or codec)
+     * @return The requested configuration. A null value value is returned
+     *         when no suitable configuration has been found.
+     */
+    @nullable A2dpConfiguration getA2dpConfiguration(
+            in List<A2dpRemoteCapabilities> remoteA2dpCapabilities, in A2dpConfigurationHint hint);
+
+    /**
+     * Predefined values for the codec priority, used by `setCodecPriority()`.
+     * Besides these special values, the codec priority can be set to 1 for
+     * the highest possible priority, or to any other 4 bytes wide integer N,
+     * where N has the higher priority than N + 1.
+     */
+    const int CODEC_PRIORITY_DISABLED = -1;
+    const int CODEC_PRIORITY_NONE = 0;
+
+    /**
+     * Set specific codec priority
+     *
+     *  It should be assumed that the external module will start with all its
+     *  integrated codecs priority set to `CODEC_PRIORITY_NONE` by default.
+     *
+     * Note: If the BT stack sets a particular codec priority to
+     *       CODEC_PRIORITY_DISABLED, the configuration provider shal not return
+     *       a particular codec when asked for the configuration. Other priority
+     *       levels and the prioritization mechanism details are not specified
+     *       and the vendor can implement them as desired.
+     *
+     * @param codecId:  codecId
+     * @param priority: `CODEC_PRIORITY_NONE` for no priority,
+     *        `CODEC_PRIORITY_DISABLED` for the disabled codec, or priority
+     *        level from 1 to N, where the priority of N + 1 is lower than N,
+     *        and N equal to 1 is the highest possible codec priority.
+     */
+    void setCodecPriority(in CodecId codecId, int priority);
+
+    /**
+     * LE Audio device Capabilities - as defined in Bluetooth Published Audio
+     * Capabilities Service specification, v1.0.1, Sec. 3.1: "Sink PAC", and
+     * Sec. 3.3: "Source PAC".
+     */
+    @VintfStability
+    parcelable LeAudioDeviceCapabilities {
+        /**
+         * Codec Identifier
+         */
+        CodecId codecId;
+        /**
+         * Codec capabilities, packed as LTV.
+         */
+        CodecSpecificCapabilitiesLtv[] codecSpecificCapabilities;
+        /**
+         * Vendor codec specific capabilities.
+         *
+         * This will not be parsed by the BT stack, but passed to the vendor
+         * module who can interpret this and based on that select the proper
+         * vendor specific codec configuration.
+         */
+        @nullable byte[] vendorCodecSpecificCapabilities;
+        /**
+         * Audio capabilities metadata, packed as LTV.
+         */
+        @nullable MetadataLtv[] metadata;
+    }
+
+    @VintfStability
+    parcelable LeAudioDataPathConfiguration {
+        /**
+         * Vendor specific data path identifier
+         */
+        int dataPathId;
+
+        /**
+         * Used in the HCI_LE_Setup_ISO_Data_Path (0x006E).
+         * As defined in Bluetooth Core Specification Version
+         * 5.3, Vol 4, Part E, Sec. 7.8.109: "LE Setup ISO Data Path command".
+         */
+        @VintfStability
+        parcelable IsoDataPathConfiguration {
+            /**
+             * Codec ID - Valid Codec Identifier matching the selected codec
+             */
+            CodecId codecId;
+            /**
+             * Whether the transparent air mode should be set as a coding format
+             * in the HCI_LE_Setup_ISO_Data_Path command, indicating that the
+             * codec is not in the controller.
+             *
+             * If set to true, 0x03 (transparent air mode) will be used as a
+             * Codec_ID coding format and the `byte[] configuration` field shall
+             * remain empty. Otherwise the Codec_ID field will be set to
+             * according to BT specification (0xFF coding format, company ID,
+             * codec ID for vendor codecs, or according to Codec_ID identifiers
+             * defined in the Assigned Numbers for the non-vendor codecs).
+             */
+            boolean isTransparent;
+            /**
+             * Controller delay (in microseconds)
+             */
+            int controllerDelayUs;
+            /**
+             * Codec specific LE Audio ISO data path configuration
+             * must be null when codec ID is 0x03 transparent
+             */
+            @nullable byte[] configuration;
+        }
+
+        /**
+         * Used in HCI_Configure_Data_Path (0x0083)
+         * As defined in Bluetooth Core Specification Version
+         * 5.3, Vol 4, Part E, Sec. 7.3.101: "Configure Data Path command".
+         */
+        @VintfStability
+        parcelable DataPathConfiguration {
+            /**
+             * Vendor specific data path configuration
+             */
+            @nullable byte[] configuration;
+        }
+        /**
+         * Data path configuration
+         */
+        DataPathConfiguration dataPathConfiguration;
+        /**
+         * ISO data path configuration
+         */
+        IsoDataPathConfiguration isoDataPathConfiguration;
+    }
+
+    /**
+     * All the LeAudioAseQosConfiguration parameters are defined by the
+     * Bluetooth Audio Stream Control Service specification v.1.0, Sec. 5: "ASE
+     * Control Operations".
+     */
+    @VintfStability
+    parcelable LeAudioAseQosConfiguration {
+        /**
+         * SDU Interval (in microseconds) used in Set CIG Parameters command and
+         * Configure QoS.
+         */
+        int sduIntervalUs;
+        /**
+         * Framing used in Set CIG Parameters command and Configure QoS
+         */
+        Framing framing;
+        /**
+         * Phy used in Set CIG Parameters command and Configure QoS
+         */
+        Phy[] phy;
+        /**
+         * Max transport latency (in milliseconds) used in Set CIG Parameters
+         * command and Configure QoS.
+         */
+        int maxTransportLatencyMs;
+        /**
+         * Max SDU used in Set CIG Parameters command and Configure QoS
+         */
+        int maxSdu;
+        /**
+         * Retransmission number used in Set CIG Parameters command and
+         * Configure QoS
+         */
+        int retransmissionNum;
+    }
+
+    /**
+     * Connected Isochronous Channel arrangement within the Connected
+     * Isochronous Group. As defined in Bluetooth Core Specification Version
+     * 5.3, Vol 4, Part E, Sec. 7.8.97.
+     */
+    @VintfStability
+    @Backing(type="byte")
+    enum Packing {
+        SEQUENTIAL = 0x00,
+        INTERLEAVED = 0x01,
+    }
+
+    /**
+     * Isochronous Data PDU framing parameter. As defined in Bluetooth Core
+     * Specification Version 5.3, Vol 4, Part E, Sec. 7.8.97.
+     */
+    @VintfStability
+    @Backing(type="byte")
+    enum Framing {
+        UNFRAMED = 0x00,
+        FRAMED = 0x01,
+    }
+
+    @VintfStability
+    parcelable LeAudioAseConfigurationSetting {
+        /**
+         * Audio Context that this configuration apply to
+         */
+        AudioContext audioContext;
+        /**
+         * Sequential or interleave packing used in Set CIG Parameters command
+         */
+        Packing packing;
+
+        @VintfStability
+        parcelable AseDirectionConfiguration {
+            /**
+             * ASE configuration
+             */
+            LeAudioAseConfiguration aseConfiguration;
+            /**
+             * QoS Configuration
+             */
+            @nullable LeAudioAseQosConfiguration qosConfiguration;
+            /**
+             * Data path configuration
+             * If not provided, getLeAudioAseDatapathConfiguration() will be
+             * called during the configuration, increasing the stream
+             * establishment time (not recommended).
+             */
+            @nullable LeAudioDataPathConfiguration dataPathConfiguration;
+        }
+        /**
+         * Sink ASEs configuration
+         */
+        @nullable AseDirectionConfiguration[] sinkAseConfiguration;
+        /**
+         * Source ASEs configuration
+         */
+        @nullable AseDirectionConfiguration[] sourceAseConfiguration;
+        /**
+         * Additional flags, used for configurations with special features
+         */
+        @nullable ConfigurationFlags flags;
+    }
+
+    /**
+     * ASE configuration requirements set by the BT stack.
+     */
+    @VintfStability
+    parcelable LeAudioConfigurationRequirement {
+        /**
+         * Audio Contect that this requirements apply to
+         */
+        AudioContext audioContext;
+
+        @VintfStability
+        parcelable AseDirectionRequirement {
+            /**
+             * Optional ASE configurations requirements
+             *
+             * Note that the Host can set as many or as little parameters in
+             * the `aseConfiguration.codecConfiguration` field as needed, to
+             * closely or loosely specify the requirements. If any parameter
+             * is not specified, the offloader can choose it freely. The
+             * offloader should put all the specified parameters into the
+             * `aseConfiguration.codecConfiguration` field of the returned
+             * configuration to let the BT stack verify if the requirements
+             * were met. The mandatory requirement set by the BT stack will be
+             * the Audio Location.
+             */
+            LeAudioAseConfiguration aseConfiguration;
+        }
+        /**
+         * Sink ASEs configuration setting
+         */
+        @nullable AseDirectionRequirement[] sinkAseRequirement;
+        /**
+         * Source ASEs configuration setting
+         */
+        @nullable AseDirectionRequirement[] sourceAseRequirement;
+        /**
+         * Additional flags, used to request configurations with special
+         * features
+         */
+        @nullable ConfigurationFlags flags;
+    }
+
+    /**
+     * Method that returns a proposed ASE configuration settings for each
+     * requested audio context type
+     *
+     * Note: _ENCODING session provides SINK ASE configuration
+     *       and _DECODING session provides SOURCE ASE configuration unless
+     *       BluetoothAudioProvider sets supportsMultidirectionalCapabilities to
+     *       true in ProviderInfo.
+     *       If supportsMultidirectionalCapabilities is set to true then the
+     *       BluetoothStack expects to get configuration list for SINK and SOURCE
+     *       on either _ENCODING or _DECODING session.
+     *
+     * Note: When the requirements are not met, either for one or both
+     *       directions, the corresponding returned AseDirectionConfiguration
+     *       can be set to null. Otherwise it shall contain an ASE configuration
+     *       array with the number of configurations equal to the number of ASEs
+     *       which should be configured by the BT stack for this particular
+     *       direction.
+     *       The provider shall match all the requirements set by the Bluetooth
+     *       stack or return a null configuration for the direction when these
+     *       requirements are not met. In response, the BT Stack may decide to
+     *       reduce the requirements to the minimum, which is the `audioContext`
+     *       and the `LeAudioAseConfiguration.codecConfiguration` with the
+     *       mandatory `CodecSpecificConfigurationLtv.SamplingFrequency` and
+     *       `CodecSpecificConfigurationLtv.AudioChannelAllocation` fields set.
+     *       When these minimum requirements are not met as well, the Bt stack
+     *       may set either `sinkAseRequirement` or `sourceAseRequirement`, or
+     *       both to null. In such case the provider has the freedom of
+     *       providing a configuration for the null-ed direction requirements or
+     *       not for the particular audio context. However returning neither of
+     *       the direction configurations (both nulled) is considered as an
+     *       invalid behavior.
+     *       If the returned configurations are not complete (either
+     *       `qosConfiguration` or `dataPathConfiguration` are null), the BT
+     *       stack will ask for these dynamically during the stream
+     *       establishment, using the corresponding
+     *       `getLeAudioAseQosConfiguration()` and
+     *       `getLeAudioAseDatapathConfiguration()` API calls. This behavior
+     *       is not desired as it slows down the stream establishment, and
+     *       should be implemented only if really needed (e.g. when the provider
+     *       needs to monitor the remote device ASE states, using the
+     *       `onSinkAseMetadataChanged()` and `onSourceAseMetadataChanged()`
+     *       callbacks to derive the valid QoS and/or data path configuration).
+     *
+     * @param remoteSinkAudioCapabilities Array of remote sink capabilities
+     *        supported by an active group devices.
+     * @param remoteSourceAudioCapabilities Array of remote source capabilities
+     *        supported by an active group devices.
+     * @param requirements ASE configuration requirements
+     *
+     * @return LeAudioAseConfigurationSetting[]
+     */
+    LeAudioAseConfigurationSetting[] getLeAudioAseConfiguration(
+            in @nullable LeAudioDeviceCapabilities[] remoteSinkAudioCapabilities,
+            in @nullable LeAudioDeviceCapabilities[] remoteSourceAudioCapabilities,
+            in LeAudioConfigurationRequirement[] requirements);
+
+    @VintfStability
+    parcelable LeAudioAseQosConfigurationRequirement {
+        /**
+         * Audio Contect Type that this requirements apply to
+         */
+        AudioContext audioContext;
+
+        /**
+         * QoS preferences received in Codec Configured ASE state. As defined in
+         * bluetooth service specification: Audio Stream Control Service" V1.0,
+         * Sec. 4.1 Audio Stream Endpoints, Table 4.3:"Additional_ASE_Parameters
+         * format when ASE_State = 0x01 (Codec Configured)".
+         */
+        @VintfStability
+        parcelable AseQosDirectionRequirement {
+            /**
+             * Support for unframed Isochronous Adaptation Layer PDUs.
+             * When set to FRAMED, the unframed PDUs are not supported.
+             */
+            Framing framing;
+            /**
+             * Preferred value for the PHY parameter to be written by the client
+             * for this ASE in the Config QoS operation
+             */
+            Phy[] preferredPhy;
+            /**
+             * Preferred value for the Retransmission Number parameter to be
+             * written by the client for this ASE in the Config QoS operation.
+             */
+            int preferredRetransmissionNum;
+            /**
+             * Preferred value for the Max Transport Latency parameter to be
+             * written by the client for this ASE in the Config QoS operation.
+             */
+            int maxTransportLatencyMs;
+            /**
+             * Minimum server supported Presentation Delay (in microseconds) for
+             * an ASE.
+             */
+            int presentationDelayMinUs;
+            /**
+             * Maximum server supported Presentation Delay (in microseconds) for
+             * an ASE.
+             */
+            int presentationDelayMaxUs;
+            /**
+             * Preferred minimum Presentation Delay (in microseconds) for an
+             * ASE.
+             */
+            int preferredPresentationDelayMinUs;
+            /**
+             * Preferred maximum Presentation Delay (in microseconds) for an
+             * ASE.
+             */
+            int preferredPresentationDelayMaxUs;
+
+            /**
+             * ASE configuration
+             */
+            LeAudioAseConfiguration aseConfiguration;
+        }
+        /**
+         * Sink ASEs configuration setting
+         */
+        @nullable AseQosDirectionRequirement sinkAseQosRequirement;
+        /**
+         * Source ASEs configuration setting
+         */
+        @nullable AseQosDirectionRequirement sourceAseQosRequirement;
+        /**
+         * Additional configuration flags requirements
+         */
+        @nullable ConfigurationFlags flags;
+    }
+
+    /**
+     * A directional pair for QoS configuration. Either one or both directions
+     * can be set, depending on the audio context and the requirements provided
+     * to getLeAudioAseQosConfiguration().
+     */
+    @VintfStability
+    parcelable LeAudioAseQosConfigurationPair {
+        @nullable LeAudioAseQosConfiguration sinkQosConfiguration;
+        @nullable LeAudioAseQosConfiguration sourceQosConfiguration;
+    }
+
+    /**
+     * Method that returns an ASE QoS configuration settings for the given ASE
+     * configuration,taking an ASE preferenced QoS parameters. It should be used
+     * to negotiaite the QoS parameters, when the initialy received QoS
+     * parameters are not within the boundaries received from the remote device
+     * after configuring the ASEs.
+     *
+     * Note: When the requirements are not met, either for one or both
+     *       directions, the corresponding configurations in the returned
+     *       LeAudioAseQosConfigurationPair can be set to null. The minimum
+     *       requirement can have only the `audioContext` field set and just a
+     *       single (either sink or source) AseQosDirectionRequirement, where
+     *       only the preferred parameter fields are not specified. The
+     *       configuration provider should always be able to satisfy such
+     *       requirement for all the audio contexts specified by Bluetooth SIG.
+     *       The Bluetooth stack can reduce the requirements to the minimum,
+     *       when more precisely specified requirements are not met by the
+     *       configuration provider.
+     *
+     * @param qosRequirement ASE QoS configurations requirements
+     *
+     * @return LeAudioAseQosConfigurationPair
+     */
+    LeAudioAseQosConfigurationPair getLeAudioAseQosConfiguration(
+            in LeAudioAseQosConfigurationRequirement qosRequirement);
+
+    /**
+     * Audio data path configuration.
+     */
+    parcelable LeAudioDataPathConfigurationPair {
+        /* Host to Controller data path */
+        @nullable LeAudioDataPathConfiguration inputConfig;
+        /* Controller to Host data path */
+        @nullable LeAudioDataPathConfiguration outputConfig;
+    }
+
+    /**
+     * Stream Configuration
+     */
+    parcelable StreamConfig {
+        /**
+         * Streaming Audio Context.
+         * This can serve as a hint for selecting the proper configuration by
+         * the offloader.
+         */
+        AudioContext audioContext;
+        /**
+         * Stream configuration, including connection handles and audio channel
+         * allocations.
+         */
+        StreamMap[] streamMap;
+    }
+
+    /**
+     * Used to get a data path configuration which dynamically depends on CIS
+     * connection handles in StreamMap. This is used if non-dynamic data path
+     * was not provided in LeAudioAseConfigurationSetting. Calling this during
+     * the unicast audio stream establishment might slightly delay the stream
+     * start.
+     *
+     * @param sinkConfig - remote sink device stream configuration
+     * @param sourceConfig - remote source device stream configuration
+     *
+     * Note: The provider shall provide a data path configuration for each
+     *       of the non-null configurations passed to this function if these
+     *       configurations are supported by the configuration provider.
+     *       The Bluetooth stack can set either only sink or source
+     *       configuration if it expects just a single direction data path
+     *       configuration. Not providing a valid data path configuration for
+     *       the stream configured with the codec parameters provided by the
+     *       configuration provider will be considered an invalid behavior.
+     *       The BT stack can pass asymmetric sink and source configurations
+     *       if `ALLOW_ASYMMETRIC_CONFIGURATIONS` flag was set by the provider
+     *       in the `CodecInfo` information for the particular codec.
+     *
+     * @return LeAudioDataPathConfigurationPair
+     */
+    LeAudioDataPathConfigurationPair getLeAudioAseDatapathConfiguration(
+            in @nullable StreamConfig sinkConfig,
+            in @nullable StreamConfig sourceConfig);
+
+    /**
+     * Audio Stream Endpoint state used to report Metadata changes on the remote
+     * device audio endpoints.
+     */
+    @VintfStability
+    @Backing(type="byte")
+    enum AseState {
+        ENABLING = 0x00,
+        STREAMING = 0x01,
+        DISABLING = 0x02,
+    }
+
+    /**
+     * Used to report sink endpoint metadata changes to the provider. This
+     * allows for a pseudo communication channel between the remote device and
+     * the provider, using the vendor specific metadata of the changing ASE
+     * state. It is used only when Audio Stream Endpoint (ASE) is using
+     * configurations marked with the `PROVIDE_ASE_METADATA` flag.
+     *
+     * @param state - current Audio Stream Endpoint state of the remote device
+     * @param cigId - Coordinate Isochronous Group identifier
+     * @param cisId - Coordinate Isochronous Stream identifier
+     * @param metadata - remote sink device metadata for the given ASE
+     */
+    void onSinkAseMetadataChanged(
+            in AseState state, int cigId, int cisId, in @nullable MetadataLtv[] metadata);
+
+    /**
+     * Used to report source endpoint metadata changes to the provider. This
+     * allows for a pseudo communication channel between the remote device and
+     * the provider, using the vendor specific metadata of the changing ASE
+     * state. It is used only when Audio Stream Endpoint (ASE) is using
+     * configurations marked with the `PROVIDE_ASE_METADATA` flag.
+     *
+     * @param state - current Audio Stream Endpoint state of the remote device
+     * @param cigId - Coordinate Isochronous Group identifier
+     * @param cisId - Coordinate Isochronous Stream identifier
+     * @param metadata - remote source device metadata for the given ASE
+     */
+    void onSourceAseMetadataChanged(
+            in AseState state, int cigId, int cisId, in @nullable MetadataLtv[] metadata);
+
+    /**
+     * Broadcast quality index
+     */
+    @VintfStability
+    @Backing(type="byte")
+    enum BroadcastQuality {
+        STANDARD,
+        HIGH,
+    }
+
+    /**
+     * It is used in LeAudioBroadcastConfigurationRequirement
+     */
+    @VintfStability
+    parcelable LeAudioBroadcastSubgroupConfigurationRequirement {
+        /**
+         * Streaming Audio Context for the given subgroup.
+         * This can serve as a hint for selecting the proper configuration by
+         * the offloader.
+         */
+        AudioContext audioContext;
+        /**
+         * Streaming Broadcast Audio Quality
+         */
+        BroadcastQuality quality;
+        /**
+         * Number of BISes for the given subgroup
+         */
+        int bisNumPerSubgroup;
+    }
+
+    /**
+     * It is used in getLeAudioBroadcastConfiguration method
+     * If any group id is provided, the Provider should check Pacs capabilities
+     * of the group(s) and provide Broadcast configuration supported by the
+     * group.
+     */
+    @VintfStability
+    parcelable LeAudioBroadcastConfigurationRequirement {
+        LeAudioBroadcastSubgroupConfigurationRequirement[] subgroupConfigurationRequirements;
+    }
+
+    /**
+     * Subgroup BIS configuration
+     *
+     */
+    @VintfStability
+    parcelable LeAudioSubgroupBisConfiguration {
+        /**
+         * The number of BISes with the given configuration
+         */
+        int numBis;
+        /**
+         * LE Audio BIS configuration for the `numBis` number of BISes
+         */
+        LeAudioBisConfiguration bisConfiguration;
+    }
+
+    /**
+     * Subgroup configuration with a list of BIS configurations
+     */
+    @VintfStability
+    parcelable LeAudioBroadcastSubgroupConfiguration {
+        LeAudioSubgroupBisConfiguration[] bisConfigurations;
+
+        /**
+         * Vendor specific codec configuration for all the BISes inside this
+         * subgroup. Only the vendor specific part is needed, since the BT stack
+         * can derive the common subgroup configuration by intersecting the LTV
+         * formatted configuration of every BIS inside the subgroup.
+         * This will not be parsed by the BT stack but will be set as the codec
+         * specific configuration for the ongoing audio stream at the subgroup
+         * level of the audio announcement,The remote device will receive this
+         * information when being configured for receiveing a brodcast audio
+         * stream.
+         */
+        @nullable byte[] vendorCodecConfiguration;
+    }
+
+    /**
+     * LeAudioBroadcastConfigurationSetting is a result of
+     * getLeAudioBroadcastConfiguration. It is used in HCI_LE_Create_BIG command
+     * and for creating the Broadcast Announcements.
+     */
+    @VintfStability
+    parcelable LeAudioBroadcastConfigurationSetting {
+        /**
+         * SDU Interval (in microseconds) used in LE Create BIG command
+         */
+        int sduIntervalUs;
+        /**
+         * Total number of BISes in the BIG
+         */
+        int numBis;
+        /**
+         *  Maximum size of an SDU in octets
+         */
+        int maxSduOctets;
+        /**
+         * Maximum transport latency (in milliseconds)
+         */
+        int maxTransportLatencyMs;
+        /**
+         * The number of times every PDU should be retransmitted
+         */
+        int retransmitionNum;
+        /**
+         * A list of PHYs used for transmission of PDUs of BISes in the BIG.
+         */
+        Phy[] phy;
+        /**
+         * The preferred method of arranging subevents of multiple BISes
+         */
+        Packing packing;
+        /**
+         * format for sending BIS Data PDUs
+         */
+        Framing framing;
+
+        /**
+         * Data path configuration
+         * If not provided, getLeAudioBroadcastDatapathConfiguration() will be
+         * called during the configuration, increasing the stream establishment
+         * time (not recommended).
+         */
+        @nullable LeAudioDataPathConfiguration dataPathConfiguration;
+
+        /**
+         * An array of subgroup configurations in the broadcast.
+         */
+        LeAudioBroadcastSubgroupConfiguration[] subgroupsConfigurations;
+    }
+
+    /**
+     * Get Broadcast configuration. Output of this function will be used
+     * in HCI_LE_Create_BIG  (0x0068) command and also to create BIG INFO
+     *
+     * @param remoteSinkAudioCapabilities - remote device sink endpoint
+     *        capabilities
+     * @param requirement - requested configuration requirements
+     *
+     * @return the whole broadcast audio stream configuration
+     */
+    LeAudioBroadcastConfigurationSetting getLeAudioBroadcastConfiguration(
+            in @nullable LeAudioDeviceCapabilities[] remoteSinkAudioCapabilities,
+            in LeAudioBroadcastConfigurationRequirement requirement);
+
+    /**
+     * Used to get a data path configuration which dynamically depends on BIS
+     * handles in BroadcastStreamMap. This is used if non-dynamic data path was
+     * not provided in LeAudioBroadcastConfigurationSetting. Calling this during
+     * the broadcast audio stream establishment might slightly delay the stream
+     * start.
+     *
+     * @param audioContext - audio stream context for the given stream map
+     * @param streamMap - channel map with BIS configurations
+     *
+     * @return broadcast audio stream data path configuration
+     */
+    LeAudioDataPathConfiguration getLeAudioBroadcastDatapathConfiguration(
+            in AudioContext audioContext, in BroadcastStreamMap[] streamMap);
 }
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/IBluetoothAudioProviderFactory.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/IBluetoothAudioProviderFactory.aidl
index 3cde22c..ea9c4e1 100644
--- a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/IBluetoothAudioProviderFactory.aidl
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/IBluetoothAudioProviderFactory.aidl
@@ -17,8 +17,10 @@
 package android.hardware.bluetooth.audio;
 
 import android.hardware.bluetooth.audio.AudioCapabilities;
+import android.hardware.bluetooth.audio.CodecInfo;
 import android.hardware.bluetooth.audio.IBluetoothAudioProvider;
 import android.hardware.bluetooth.audio.SessionType;
+
 /**
  * This factory allows a HAL implementation to be split into multiple
  * independent providers.
@@ -62,4 +64,38 @@
      * @return provider The provider of the specified session type
      */
     IBluetoothAudioProvider openProvider(in SessionType sessionType);
+
+    /**
+     * General information relative to a provider
+     * - An optional name
+     * - A list of codec information
+     * - supportsMultidirectionalCapabilities if is set to false it means each
+     * session i.e. _ENCODING and _DECODING is responsible to provide
+     * configuration for a single direction:
+     *    _ENCODING for SINK ASE
+     *    _DECODING for SOURCE ASE
+     *
+     * If supportsMultidirectionalCapabilities is set to true, then either
+     * _ENCODING or _DECODING session can provide the configurations for either
+     * direction.
+     */
+    @VintfStability
+    parcelable ProviderInfo {
+        String name;
+        CodecInfo[] codecInfos;
+        boolean supportsMultidirectionalCapabilities;
+    }
+
+    /**
+     * Get general information relative to a provider.
+     *
+     * This can be called at any time, or just once during the BT stack
+     * initialization.
+     *
+     * @param sessionType Hardware Offload provider (*_HARDWARE_OFFLOAD_*)
+     * @return General information relative to the provider.
+     *         The `null` value can be returned when the provider is not
+     *         available
+     */
+    @nullable ProviderInfo getProviderInfo(in SessionType sessionType);
 }
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioAseConfiguration.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioAseConfiguration.aidl
new file mode 100644
index 0000000..9fb2ecf
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioAseConfiguration.aidl
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.CodecId;
+import android.hardware.bluetooth.audio.CodecSpecificConfigurationLtv;
+import android.hardware.bluetooth.audio.MetadataLtv;
+import android.hardware.bluetooth.audio.Phy;
+
+/**
+ * All the LeAudioAseConfiguration parameters are defined by the Bluetooth Audio
+ * Stream Control Service specification v.1.0, Sec. 5: "ASE Control Operations".
+ */
+@VintfStability
+parcelable LeAudioAseConfiguration {
+    @VintfStability
+    @Backing(type="byte")
+    enum TargetLatency {
+        UNDEFINED = 0x00,
+        LOWER = 0x01,
+        BALANCED_LATENCY_RELIABILITY = 0x02,
+        HIGHER_RELIABILITY = 0x03,
+    }
+
+    /**
+     * Target latency used in Configure Codec command - Can be UNDEFINED when
+     * used inside the AseDirectionRequirement, but shall not be UNDEFINED when
+     * used inside LeAudioAseConfigurationSetting.
+     */
+    TargetLatency targetLatency;
+
+    /**
+     * Target PHY used in Configure Codec command - Can be UNDEFINED when used
+     * inside the AseDirectionRequirement, but shall not be UNDEFINED when used
+     * inside LeAudioAseConfigurationSetting.
+     */
+    Phy targetPhy;
+
+    /**
+     * Codec ID - Can be Null when used inside the AseDirectionRequirement, but
+     * shall not be Null when used inside LeAudioAseConfigurationSetting.
+     */
+    @nullable CodecId codecId;
+
+    /**
+     * Codec configuration for ASE represented in the LTV types defined by
+     * Bluetooth SIG. Regardless of vendor specific configuration being used or
+     * not, this shall contain Bluetooth LTV types describing the common stream
+     * parameters, at least CodecSpecificConfigurationLtv.SamplingFrequency and
+     * CodecSpecificConfigurationLtv.AudioChannelAllocation. In addition, it
+     * should match aseConfiguration provided in LeAudioConfigurationRequirement
+     * as this will also be used to verify the requirements on the known LTV
+     * types.
+     */
+    CodecSpecificConfigurationLtv[] codecConfiguration;
+
+    /**
+     * Vendor specific codec configuration for ASE.
+     *
+     * This will not be parsed by the BT stack but will be written to the remote
+     * device as the codec specific configuration as part of the codec configure
+     * control point operation. If this is populated, only the
+     * `vendorCodecConfiguration` will be used for the ASE configuration,
+     * otherwise `codecConfiguration` will be used. The BT stack will not merge
+     * it with the codecConfiguration for any purpose.
+     */
+    @nullable byte[] vendorCodecConfiguration;
+
+    /**
+     * Metadata, packed as LTV - used to enable ASE. This is optional
+     */
+    @nullable MetadataLtv[] metadata;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioBisConfiguration.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioBisConfiguration.aidl
new file mode 100644
index 0000000..4d6cfde
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioBisConfiguration.aidl
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.CodecId;
+import android.hardware.bluetooth.audio.CodecSpecificConfigurationLtv;
+import android.hardware.bluetooth.audio.MetadataLtv;
+
+/**
+ * LE Audio BIS configuration. This will be part of the streaming broadcast
+ * audio announcement advertised by the BT stack during the broadcast audio
+ * stream to inform the remote devices about the broadcast audio configuration.
+ * It will also be passed back to the vendor module as part of the currently
+ * active LeAudioBroadcastConfiguration for the encoder setup.
+ * As defined in Bluetooth Basic Audio Profile Specification, v.1.0.1,
+ * Sec. 3.7.2.2, Table 3.15, Level 3.
+ */
+@VintfStability
+parcelable LeAudioBisConfiguration {
+    /**
+     * Codec ID
+     */
+    CodecId codecId;
+
+    /**
+     * Codec configuration for BIS or group of BISes represented in the LTV
+     * types defined by Bluetooht SIG. Regardless of vendor specific
+     * configuration being used or not, this shall contain Bluetooth LTV types
+     * describing the common stream parameters, at least
+     * CodecSpecificConfigurationLtv.SamplingFrequency and
+     * CodecSpecificConfigurationLtv.AudioChannelAllocation.
+     * This will also be used to verify the requirements on the known LTV types.
+     */
+    CodecSpecificConfigurationLtv[] codecConfiguration;
+
+    /**
+     * Vendor specific codec configuration.
+     * This will not be parsed by the BT stack but will be set as the codec
+     * specific configuration for the ongoing audio stream, encoded by the
+     * vendor module. The remote device will receive this information when being
+     * configured for receiveing a brodcast audio stream. If this is populated,
+     * only the `vendorCodecConfiguration` will be used when configuring the
+     * remote device, otherwise `codecConfiguration` will be used.
+     */
+    byte[] vendorCodecConfiguration;
+
+    /**
+     * Metadata for the particular BIS or group of BISes. This is optional.
+     */
+    @nullable MetadataLtv[] metadata;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioBroadcastConfiguration.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioBroadcastConfiguration.aidl
index 16503fb..da90373 100644
--- a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioBroadcastConfiguration.aidl
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioBroadcastConfiguration.aidl
@@ -17,6 +17,8 @@
 package android.hardware.bluetooth.audio;
 
 import android.hardware.bluetooth.audio.CodecType;
+import android.hardware.bluetooth.audio.ConfigurationFlags;
+import android.hardware.bluetooth.audio.LeAudioBisConfiguration;
 import android.hardware.bluetooth.audio.LeAudioCodecConfiguration;
 
 @VintfStability
@@ -39,6 +41,15 @@
          * Pcm stream id to identify the source for given streamHandle.
          */
         char pcmStreamId;
+        /*
+         * LE Audio BIS configuration
+         */
+        @nullable LeAudioBisConfiguration bisConfiguration;
+        /*
+         * Additional flags, used to request configurations with special
+         * features
+         */
+        @nullable ConfigurationFlags flags;
     }
     CodecType codecType;
     BroadcastStreamMap[] streamMap;
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioConfiguration.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioConfiguration.aidl
index 7302aea..db753ad 100644
--- a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioConfiguration.aidl
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/LeAudioConfiguration.aidl
@@ -17,6 +17,8 @@
 package android.hardware.bluetooth.audio;
 
 import android.hardware.bluetooth.audio.CodecType;
+import android.hardware.bluetooth.audio.ConfigurationFlags;
+import android.hardware.bluetooth.audio.LeAudioAseConfiguration;
 import android.hardware.bluetooth.audio.LeAudioCodecConfiguration;
 
 @VintfStability
@@ -29,16 +31,40 @@
          */
         char streamHandle;
         /*
-         * Audio channel allocation is  a bit field, each enabled bit means that given audio
-         * direction, i.e. "left", or "right" is used. Ordering of audio channels comes from the
-         * least significant bit to the most significant bit. The valus follows the Bluetooth SIG
-         * Audio Location assigned number.
+         * Audio channel allocation is a bit field, each enabled bit means that
+         * given audio direction, i.e. "left", or "right" is used. Ordering of
+         * audio channels comes from the least significant bit to the most
+         * significant bit. The valus follows the Bluetooth SIG Audio Location
+         * assigned number.
          */
         int audioChannelAllocation;
         /*
          * The stream handle status
          */
         boolean isStreamActive;
+        /*
+         * LE Audio device ASE configuration
+         */
+        @nullable LeAudioAseConfiguration aseConfiguration;
+        /*
+         * Additional flags, used for configurations with special features
+         */
+        @nullable ConfigurationFlags flags;
+        parcelable BluetoothDeviceAddress {
+            enum DeviceAddressType {
+                BLE_ADDRESS_PUBLIC = 0x00,
+                BLE_ADDRESS_RANDOM = 0x01,
+            }
+            /**
+             * Peer device address. It should be non zero when isStreamActive is true
+             */
+            byte[6] deviceAddress;
+            /**
+             * Peer device address type.
+             */
+            DeviceAddressType deviceAddressType;
+        }
+        @nullable BluetoothDeviceAddress bluetoothDeviceAddress;
     }
     CodecType codecType;
     StreamMap[] streamMap;
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/MetadataLtv.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/MetadataLtv.aidl
new file mode 100644
index 0000000..afe76ce
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/MetadataLtv.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.AudioContext;
+
+/**
+ * Used to exchange generic metadata between the stack and the provider.
+ * As defined in Bluetooth Assigned Numbers, Sec. 6.12.6.
+ */
+@VintfStability
+union MetadataLtv {
+    parcelable PreferredAudioContexts {
+        AudioContext values;
+    }
+    parcelable StreamingAudioContexts {
+        AudioContext values;
+    }
+    /**
+     * This is an opaque container for passing metadata between the provider and
+     * the remote device. It shall not be inspected by the BT stack.
+     */
+    parcelable VendorSpecific {
+        int companyId;
+        byte[] opaqueValue;
+    }
+
+    PreferredAudioContexts preferredAudioContexts;
+    StreamingAudioContexts streamingAudioContexts;
+    VendorSpecific vendorSpecific;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/Phy.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/Phy.aidl
new file mode 100644
index 0000000..cbffdd5
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/Phy.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+/**
+ * Used to exchange generic Phy parameter between the stack and the provider.
+ */
+@VintfStability
+@Backing(type="byte")
+enum Phy {
+    UNDEFINED = 0x00,
+    ONE_M = 0x01,
+    TWO_M = 0x02,
+    CODED = 0x03,
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/SessionType.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/SessionType.aidl
index 7acb5c6..35292a1 100644
--- a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/SessionType.aidl
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/SessionType.aidl
@@ -70,4 +70,17 @@
      * The decoding of AVDTP media is done by HW and there is control only
      */
     A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH,
+    /**
+     * Used when audio is encoded by Bluetooth Stack and is streaming to HFP device.
+     */
+    HFP_SOFTWARE_ENCODING_DATAPATH,
+    /**
+     * Used when audio is decoded by Bluetooth Stack and is streaming to HFP device.
+     */
+    HFP_SOFTWARE_DECODING_DATAPATH,
+    /**
+     * Used when encoded and decoded by hardware offload and is streamed to HFP device.
+     * This is a control path only.
+     */
+    HFP_HARDWARE_OFFLOAD_DATAPATH,
 }
diff --git a/bluetooth/audio/aidl/default/A2dpBits.h b/bluetooth/audio/aidl/default/A2dpBits.h
new file mode 100644
index 0000000..fb7587c
--- /dev/null
+++ b/bluetooth/audio/aidl/default/A2dpBits.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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
+
+namespace aidl::android::hardware::bluetooth::audio {
+
+class A2dpBits {
+  const uint8_t* cdata_;
+  uint8_t* data_;
+
+ public:
+  A2dpBits(const std::vector<uint8_t>& vector)
+      : cdata_(vector.data()), data_(nullptr) {}
+
+  A2dpBits(std::vector<uint8_t>& vector)
+      : cdata_(vector.data()), data_(vector.data()) {}
+
+  struct Range {
+    const int first, len;
+    constexpr Range(int first, int last)
+        : first(first), len(last - first + 1) {}
+    constexpr Range(int index) : first(index), len(1) {}
+  };
+
+  constexpr bool get(int bit) const {
+    return (cdata_[bit >> 3] >> (7 - (bit & 7))) & 1;
+  }
+
+  constexpr unsigned get(const Range& range) const {
+    unsigned v(0);
+    for (int i = 0; i < range.len; i++)
+      v |= get(range.first + i) << ((range.len - 1) - i);
+    return v;
+  }
+
+  constexpr void set(int bit, int value = 1) {
+    uint8_t m = 1 << (7 - (bit & 7));
+    if (value)
+      data_[bit >> 3] |= m;
+    else
+      data_[bit >> 3] &= ~m;
+  }
+
+  constexpr void set(const Range& range, int value) {
+    for (int i = 0; i < range.len; i++)
+      set(range.first + i, (value >> ((range.len - 1) - i)) & 1);
+  }
+
+  constexpr int find_active_bit(const Range& range) const {
+    unsigned v = get(range);
+    int i = 0;
+    for (; i < range.len && ((v >> i) & 1) == 0; i++)
+      ;
+    return i < range.len && (v ^ (1 << i)) == 0
+               ? range.first + (range.len - 1) - i
+               : -1;
+  }
+};
+
+}  // namespace aidl::android::hardware::bluetooth::audio
diff --git a/bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.cpp b/bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.cpp
index 2d0d8c9..ba7a89d 100644
--- a/bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.cpp
+++ b/bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.cpp
@@ -22,6 +22,10 @@
 #include <BluetoothAudioSessionReport.h>
 #include <android-base/logging.h>
 
+#include "A2dpOffloadCodecAac.h"
+#include "A2dpOffloadCodecFactory.h"
+#include "A2dpOffloadCodecSbc.h"
+
 namespace aidl {
 namespace android {
 namespace hardware {
@@ -48,19 +52,44 @@
     const std::shared_ptr<IBluetoothAudioPort>& host_if,
     const AudioConfiguration& audio_config,
     const std::vector<LatencyMode>& latency_modes, DataMQDesc* _aidl_return) {
-  if (audio_config.getTag() != AudioConfiguration::a2dpConfig) {
+  if (audio_config.getTag() == AudioConfiguration::Tag::a2dp) {
+    auto a2dp_config = audio_config.get<AudioConfiguration::Tag::a2dp>();
+    A2dpStatus a2dp_status = A2dpStatus::NOT_SUPPORTED_CODEC_TYPE;
+
+    if (a2dp_config.codecId ==
+        A2dpOffloadCodecSbc::GetInstance()->GetCodecId()) {
+      SbcParameters sbc_parameters;
+      a2dp_status = A2dpOffloadCodecSbc::GetInstance()->ParseConfiguration(
+          a2dp_config.configuration, &sbc_parameters);
+
+    } else if (a2dp_config.codecId ==
+               A2dpOffloadCodecAac::GetInstance()->GetCodecId()) {
+      AacParameters aac_parameters;
+      a2dp_status = A2dpOffloadCodecAac::GetInstance()->ParseConfiguration(
+          a2dp_config.configuration, &aac_parameters);
+    }
+    if (a2dp_status != A2dpStatus::OK) {
+      LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
+                   << audio_config.toString();
+      *_aidl_return = DataMQDesc();
+      return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+  } else if (audio_config.getTag() == AudioConfiguration::Tag::a2dpConfig) {
+    if (!BluetoothAudioCodecs::IsOffloadCodecConfigurationValid(
+            session_type_,
+            audio_config.get<AudioConfiguration::a2dpConfig>())) {
+      LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
+                   << audio_config.toString();
+      *_aidl_return = DataMQDesc();
+      return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+  } else {
     LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
                  << audio_config.toString();
     *_aidl_return = DataMQDesc();
     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
   }
-  if (!BluetoothAudioCodecs::IsOffloadCodecConfigurationValid(
-          session_type_, audio_config.get<AudioConfiguration::a2dpConfig>())) {
-    LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
-                 << audio_config.toString();
-    *_aidl_return = DataMQDesc();
-    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
-  }
+
   return BluetoothAudioProvider::startSession(
       host_if, audio_config, latency_modes, _aidl_return);
 }
@@ -73,6 +102,36 @@
   return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus A2dpOffloadAudioProvider::parseA2dpConfiguration(
+    const CodecId& codec_id, const std::vector<uint8_t>& configuration,
+    CodecParameters* codec_parameters, A2dpStatus* _aidl_return) {
+  auto codec = A2dpOffloadCodecFactory::GetInstance()->GetCodec(codec_id);
+  if (!codec) {
+    LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+              << " - CodecId=" << codec_id.toString() << " is not found";
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+  }
+
+  *_aidl_return = codec->ParseConfiguration(configuration, codec_parameters);
+
+  return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus A2dpOffloadAudioProvider::getA2dpConfiguration(
+    const std::vector<A2dpRemoteCapabilities>& remote_a2dp_capabilities,
+    const A2dpConfigurationHint& hint,
+    std::optional<audio::A2dpConfiguration>* _aidl_return) {
+  *_aidl_return = std::nullopt;
+  A2dpConfiguration avdtp_configuration;
+
+  if (A2dpOffloadCodecFactory::GetInstance()->GetConfiguration(
+          remote_a2dp_capabilities, hint, &avdtp_configuration))
+    *_aidl_return =
+        std::make_optional<A2dpConfiguration>(std::move(avdtp_configuration));
+
+  return ndk::ScopedAStatus::ok();
+}
+
 }  // namespace audio
 }  // namespace bluetooth
 }  // namespace hardware
diff --git a/bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.h b/bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.h
index e6f188b..7cc6dee 100644
--- a/bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.h
+++ b/bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.h
@@ -34,7 +34,16 @@
       const std::shared_ptr<IBluetoothAudioPort>& host_if,
       const AudioConfiguration& audio_config,
       const std::vector<LatencyMode>& latency_modes,
-      DataMQDesc* _aidl_return);
+      DataMQDesc* _aidl_return) override;
+
+  ndk::ScopedAStatus parseA2dpConfiguration(
+      const CodecId& codec_id, const std::vector<uint8_t>& configuration,
+      CodecParameters* codec_parameters, A2dpStatus* _aidl_return) override;
+
+  ndk::ScopedAStatus getA2dpConfiguration(
+      const std::vector<A2dpRemoteCapabilities>& remote_a2dp_capabilities,
+      const A2dpConfigurationHint& hint,
+      std::optional<audio::A2dpConfiguration>* _aidl_return) override;
 
  private:
   ndk::ScopedAStatus onSessionReady(DataMQDesc* _aidl_return) override;
diff --git a/bluetooth/audio/aidl/default/A2dpOffloadCodec.h b/bluetooth/audio/aidl/default/A2dpOffloadCodec.h
new file mode 100644
index 0000000..7ed5872
--- /dev/null
+++ b/bluetooth/audio/aidl/default/A2dpOffloadCodec.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/bluetooth/audio/A2dpStatus.h>
+#include <aidl/android/hardware/bluetooth/audio/ChannelMode.h>
+#include <aidl/android/hardware/bluetooth/audio/CodecParameters.h>
+
+#include "BluetoothAudioProviderFactory.h"
+
+namespace aidl::android::hardware::bluetooth::audio {
+
+class A2dpOffloadCodec {
+ protected:
+  A2dpOffloadCodec(const CodecInfo& info) : info(info) {}
+  virtual ~A2dpOffloadCodec() {}
+
+ public:
+  const CodecInfo& info;
+
+  const CodecId& GetCodecId() const { return info.id; }
+
+  virtual A2dpStatus ParseConfiguration(
+      const std::vector<uint8_t>& configuration,
+      CodecParameters* codec_parameters) const = 0;
+
+  virtual bool BuildConfiguration(
+      const std::vector<uint8_t>& remote_capabilities,
+      const std::optional<CodecParameters>& hint,
+      std::vector<uint8_t>* configuration) const = 0;
+};
+
+}  // namespace aidl::android::hardware::bluetooth::audio
diff --git a/bluetooth/audio/aidl/default/A2dpOffloadCodecAac.cpp b/bluetooth/audio/aidl/default/A2dpOffloadCodecAac.cpp
new file mode 100644
index 0000000..0f5533a
--- /dev/null
+++ b/bluetooth/audio/aidl/default/A2dpOffloadCodecAac.cpp
@@ -0,0 +1,378 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "A2dpOffloadCodecAac.h"
+
+#include "A2dpBits.h"
+
+namespace aidl::android::hardware::bluetooth::audio {
+
+/**
+ * AAC Local Capabilities
+ */
+
+enum : bool {
+  kEnableObjectTypeMpeg2AacLc = true,
+  kEnableObjectTypeMpeg4AacLc = true,
+};
+
+enum : bool {
+  kEnableSamplingFrequency44100 = true,
+  kEnableSamplingFrequency48000 = true,
+  kEnableSamplingFrequency88200 = false,
+  kEnableSamplingFrequency96000 = false,
+};
+
+enum : bool {
+  kEnableChannels1 = true,
+  kEnableChannels2 = true,
+};
+
+enum : bool {
+  kEnableVbrSupported = true,
+};
+
+enum : int {
+  kBitdepth = 24,
+};
+
+/**
+ * AAC Signaling format [A2DP - 4.5]
+ */
+
+// clang-format off
+
+constexpr A2dpBits::Range kObjectType        (  0,  6 );
+constexpr A2dpBits::Range kDrcEnable         (  7     );
+constexpr A2dpBits::Range kSamplingFrequency (  8, 19 );
+constexpr A2dpBits::Range kChannels          ( 20, 23 );
+constexpr A2dpBits::Range kVbrSupported      ( 24     );
+constexpr A2dpBits::Range kBitrate           ( 25, 47 );
+constexpr size_t kCapabilitiesSize = 48/8;
+
+// clang-format on
+
+enum {
+  kObjectTypeMpeg2AacLc = kObjectType.first,
+  kObjectTypeMpeg4AacLc,
+  kObjectTypeMpeg4AacLtp,
+  kObjectTypeMpeg4AacScalable,
+  kObjectTypeMpeg4AacHeV1,
+  kObjectTypeMpeg4AacHeV2,
+  kObjectTypeMpeg4AacEldV2
+};
+
+enum {
+  kSamplingFrequency8000 = kSamplingFrequency.first,
+  kSamplingFrequency11025,
+  kSamplingFrequency12000,
+  kSamplingFrequency16000,
+  kSamplingFrequency22050,
+  kSamplingFrequency24000,
+  kSamplingFrequency32000,
+  kSamplingFrequency44100,
+  kSamplingFrequency48000,
+  kSamplingFrequency64000,
+  kSamplingFrequency88200,
+  kSamplingFrequency96000
+};
+
+enum { kChannels1 = kChannels.first, kChannels2, kChannels51, kChannels71 };
+
+/**
+ * AAC Conversion functions
+ */
+
+static AacParameters::ObjectType GetObjectTypeEnum(int object_type) {
+  switch (object_type) {
+    case kObjectTypeMpeg2AacLc:
+      return AacParameters::ObjectType::MPEG2_AAC_LC;
+    case kObjectTypeMpeg4AacLc:
+    default:
+      return AacParameters::ObjectType::MPEG4_AAC_LC;
+  }
+}
+
+static int GetSamplingFrequencyBit(int32_t sampling_frequency) {
+  switch (sampling_frequency) {
+    case 8000:
+      return kSamplingFrequency8000;
+    case 11025:
+      return kSamplingFrequency11025;
+    case 12000:
+      return kSamplingFrequency12000;
+    case 16000:
+      return kSamplingFrequency16000;
+    case 22050:
+      return kSamplingFrequency22050;
+    case 24000:
+      return kSamplingFrequency24000;
+    case 32000:
+      return kSamplingFrequency32000;
+    case 44100:
+      return kSamplingFrequency44100;
+    case 48000:
+      return kSamplingFrequency48000;
+    case 64000:
+      return kSamplingFrequency64000;
+    case 88200:
+      return kSamplingFrequency88200;
+    case 96000:
+      return kSamplingFrequency96000;
+    default:
+      return -1;
+  }
+}
+
+static int32_t GetSamplingFrequencyValue(int sampling_frequency) {
+  switch (sampling_frequency) {
+    case kSamplingFrequency8000:
+      return 8000;
+    case kSamplingFrequency11025:
+      return 11025;
+    case kSamplingFrequency12000:
+      return 12000;
+    case kSamplingFrequency16000:
+      return 16000;
+    case kSamplingFrequency22050:
+      return 22050;
+    case kSamplingFrequency24000:
+      return 24000;
+    case kSamplingFrequency32000:
+      return 32000;
+    case kSamplingFrequency44100:
+      return 44100;
+    case kSamplingFrequency48000:
+      return 48000;
+    case kSamplingFrequency64000:
+      return 64000;
+    case kSamplingFrequency88200:
+      return 88200;
+    case kSamplingFrequency96000:
+      return 96000;
+    default:
+      return 0;
+  }
+}
+
+static int GetChannelsBit(ChannelMode channel_mode) {
+  switch (channel_mode) {
+    case ChannelMode::MONO:
+      return kChannels1;
+    case ChannelMode::STEREO:
+      return kChannels2;
+    default:
+      return -1;
+  }
+}
+
+static ChannelMode GetChannelModeEnum(int channel_mode) {
+  switch (channel_mode) {
+    case kChannels1:
+      return ChannelMode::MONO;
+    case kChannels2:
+      return ChannelMode::STEREO;
+    default:
+      return ChannelMode::UNKNOWN;
+  }
+}
+
+/**
+ * AAC Class implementation
+ */
+
+const A2dpOffloadCodecAac* A2dpOffloadCodecAac::GetInstance() {
+  static A2dpOffloadCodecAac instance;
+  return &instance;
+}
+
+A2dpOffloadCodecAac::A2dpOffloadCodecAac()
+    : A2dpOffloadCodec(info_),
+      info_({.id = CodecId(CodecId::A2dp::AAC), .name = "AAC"}) {
+  info_.transport.set<CodecInfo::Transport::Tag::a2dp>();
+  auto& a2dp_info = info_.transport.get<CodecInfo::Transport::Tag::a2dp>();
+
+  /* --- Setup Capabilities --- */
+
+  a2dp_info.capabilities.resize(kCapabilitiesSize);
+  std::fill(begin(a2dp_info.capabilities), end(a2dp_info.capabilities), 0);
+
+  auto capabilities = A2dpBits(a2dp_info.capabilities);
+
+  capabilities.set(kObjectTypeMpeg2AacLc, kEnableObjectTypeMpeg2AacLc);
+  capabilities.set(kObjectTypeMpeg4AacLc, kEnableObjectTypeMpeg4AacLc);
+
+  capabilities.set(kSamplingFrequency44100, kEnableSamplingFrequency44100);
+  capabilities.set(kSamplingFrequency48000, kEnableSamplingFrequency48000);
+  capabilities.set(kSamplingFrequency88200, kEnableSamplingFrequency88200);
+  capabilities.set(kSamplingFrequency96000, kEnableSamplingFrequency96000);
+
+  capabilities.set(kChannels1, kEnableChannels1);
+  capabilities.set(kChannels2, kEnableChannels2);
+
+  capabilities.set(kVbrSupported, kEnableVbrSupported);
+
+  /* --- Setup Sampling Frequencies --- */
+
+  auto& sampling_frequency = a2dp_info.samplingFrequencyHz;
+
+  for (auto v : {8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
+                 64000, 88200, 96000})
+    if (capabilities.get(GetSamplingFrequencyBit(int32_t(v))))
+      sampling_frequency.push_back(v);
+
+  /* --- Setup Channel Modes --- */
+
+  auto& channel_modes = a2dp_info.channelMode;
+
+  for (auto v : {ChannelMode::MONO, ChannelMode::STEREO})
+    if (capabilities.get(GetChannelsBit(v))) channel_modes.push_back(v);
+
+  /* --- Setup Bitdepth --- */
+
+  a2dp_info.bitdepth.push_back(kBitdepth);
+}
+
+A2dpStatus A2dpOffloadCodecAac::ParseConfiguration(
+    const std::vector<uint8_t>& configuration,
+    CodecParameters* codec_parameters, AacParameters* aac_parameters) const {
+  auto& a2dp_info = info.transport.get<CodecInfo::Transport::Tag::a2dp>();
+
+  if (configuration.size() != a2dp_info.capabilities.size())
+    return A2dpStatus::BAD_LENGTH;
+
+  auto config = A2dpBits(configuration);
+  auto lcaps = A2dpBits(a2dp_info.capabilities);
+
+  /* --- Check Object Type --- */
+
+  int object_type = config.find_active_bit(kObjectType);
+  if (object_type < 0) return A2dpStatus::INVALID_OBJECT_TYPE;
+  if (!lcaps.get(object_type)) return A2dpStatus::NOT_SUPPORTED_OBJECT_TYPE;
+
+  /* --- Check Sampling Frequency --- */
+
+  int sampling_frequency = config.find_active_bit(kSamplingFrequency);
+  if (sampling_frequency < 0) return A2dpStatus::INVALID_SAMPLING_FREQUENCY;
+  if (!lcaps.get(sampling_frequency))
+    return A2dpStatus::NOT_SUPPORTED_SAMPLING_FREQUENCY;
+
+  /* --- Check Channels --- */
+
+  int channels = config.find_active_bit(kChannels);
+  if (channels < 0) return A2dpStatus::INVALID_CHANNELS;
+  if (!lcaps.get(channels)) return A2dpStatus::NOT_SUPPORTED_CHANNELS;
+
+  /* --- Check Bitrate --- */
+
+  bool vbr = config.get(kVbrSupported);
+  if (vbr && !lcaps.get(kVbrSupported)) return A2dpStatus::NOT_SUPPORTED_VBR;
+
+  int bitrate = config.get(kBitrate);
+  if (vbr && lcaps.get(kBitrate) && bitrate > lcaps.get(kBitrate))
+    return A2dpStatus::NOT_SUPPORTED_BIT_RATE;
+
+  /* --- Return --- */
+
+  codec_parameters->channelMode = GetChannelModeEnum(channels);
+  codec_parameters->samplingFrequencyHz =
+      GetSamplingFrequencyValue(sampling_frequency);
+  codec_parameters->bitdepth = kBitdepth;
+
+  codec_parameters->minBitrate = vbr ? 0 : bitrate;
+  codec_parameters->maxBitrate = bitrate;
+
+  if (aac_parameters)
+    aac_parameters->object_type = GetObjectTypeEnum(object_type);
+
+  return A2dpStatus::OK;
+}
+
+bool A2dpOffloadCodecAac::BuildConfiguration(
+    const std::vector<uint8_t>& remote_capabilities,
+    const std::optional<CodecParameters>& hint,
+    std::vector<uint8_t>* configuration) const {
+  auto& a2dp_info = info_.transport.get<CodecInfo::Transport::Tag::a2dp>();
+
+  if (remote_capabilities.size() != a2dp_info.capabilities.size()) return false;
+
+  auto lcaps = A2dpBits(a2dp_info.capabilities);
+  auto rcaps = A2dpBits(remote_capabilities);
+
+  configuration->resize(a2dp_info.capabilities.size());
+  std::fill(begin(*configuration), end(*configuration), 0);
+  auto config = A2dpBits(*configuration);
+
+  /* --- Select Object Type --- */
+
+  if (lcaps.get(kObjectTypeMpeg2AacLc) && rcaps.get(kObjectTypeMpeg2AacLc))
+    config.set(kObjectTypeMpeg2AacLc);
+  else if (lcaps.get(kObjectTypeMpeg4AacLc) && rcaps.get(kObjectTypeMpeg4AacLc))
+    config.set(kObjectTypeMpeg4AacLc);
+  else
+    return false;
+
+  /* --- Select Sampling Frequency --- */
+
+  auto sf_hint = hint ? GetSamplingFrequencyBit(hint->samplingFrequencyHz) : -1;
+
+  if (sf_hint >= 0 && lcaps.get(sf_hint) && rcaps.get(sf_hint))
+    config.set(sf_hint);
+  else if (lcaps.get(kSamplingFrequency96000) &&
+           rcaps.get(kSamplingFrequency96000))
+    config.set(kSamplingFrequency96000);
+  else if (lcaps.get(kSamplingFrequency88200) &&
+           rcaps.get(kSamplingFrequency88200))
+    config.set(kSamplingFrequency88200);
+  else if (lcaps.get(kSamplingFrequency48000) &&
+           rcaps.get(kSamplingFrequency48000))
+    config.set(kSamplingFrequency48000);
+  else if (lcaps.get(kSamplingFrequency44100) &&
+           rcaps.get(kSamplingFrequency44100))
+    config.set(kSamplingFrequency44100);
+  else
+    return false;
+
+  /* --- Select Channels --- */
+
+  auto ch_hint = hint ? GetChannelsBit(hint->channelMode) : -1;
+
+  if (ch_hint >= 0 && lcaps.get(ch_hint) && rcaps.get(ch_hint))
+    config.set(ch_hint);
+  else if (lcaps.get(kChannels2) && rcaps.get(kChannels2))
+    config.set(kChannels2);
+  else if (lcaps.get(kChannels1) && rcaps.get(kChannels1))
+    config.set(kChannels1);
+  else
+    return false;
+
+  /* --- Select Bitrate --- */
+
+  if (!hint || hint->minBitrate == 0)
+    config.set(kVbrSupported,
+               lcaps.get(kVbrSupported) && rcaps.get(kVbrSupported));
+
+  int32_t bitrate = lcaps.get(kBitrate);
+  if (hint && hint->maxBitrate > 0 && bitrate)
+    bitrate = std::min(hint->maxBitrate, bitrate);
+  else if (hint && hint->maxBitrate > 0)
+    bitrate = hint->maxBitrate;
+  config.set(kBitrate, bitrate);
+
+  return true;
+}
+
+}  // namespace aidl::android::hardware::bluetooth::audio
diff --git a/bluetooth/audio/aidl/default/A2dpOffloadCodecAac.h b/bluetooth/audio/aidl/default/A2dpOffloadCodecAac.h
new file mode 100644
index 0000000..eefa89b
--- /dev/null
+++ b/bluetooth/audio/aidl/default/A2dpOffloadCodecAac.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "A2dpOffloadCodec.h"
+
+namespace aidl::android::hardware::bluetooth::audio {
+
+struct AacParameters : public CodecParameters {
+  enum class ObjectType { MPEG2_AAC_LC, MPEG4_AAC_LC };
+
+  ObjectType object_type;
+};
+
+class A2dpOffloadCodecAac : public A2dpOffloadCodec {
+  CodecInfo info_;
+
+  A2dpOffloadCodecAac();
+
+  A2dpStatus ParseConfiguration(const std::vector<uint8_t>& configuration,
+                                CodecParameters* codec_parameters,
+                                AacParameters* aac_parameters) const;
+
+ public:
+  static const A2dpOffloadCodecAac* GetInstance();
+
+  A2dpStatus ParseConfiguration(
+      const std::vector<uint8_t>& configuration,
+      CodecParameters* codec_parameters) const override {
+    return ParseConfiguration(configuration, codec_parameters, nullptr);
+  }
+
+  A2dpStatus ParseConfiguration(const std::vector<uint8_t>& configuration,
+                                AacParameters* aac_parameters) const {
+    return ParseConfiguration(configuration, aac_parameters, aac_parameters);
+  }
+
+  bool BuildConfiguration(const std::vector<uint8_t>& remote_capabilities,
+                          const std::optional<CodecParameters>& hint,
+                          std::vector<uint8_t>* configuration) const override;
+};
+
+}  // namespace aidl::android::hardware::bluetooth::audio
diff --git a/bluetooth/audio/aidl/default/A2dpOffloadCodecFactory.cpp b/bluetooth/audio/aidl/default/A2dpOffloadCodecFactory.cpp
new file mode 100644
index 0000000..73d8fb1
--- /dev/null
+++ b/bluetooth/audio/aidl/default/A2dpOffloadCodecFactory.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "A2dpOffloadCodecFactory.h"
+
+#include <algorithm>
+#include <cassert>
+
+#include "A2dpOffloadCodecAac.h"
+#include "A2dpOffloadCodecSbc.h"
+
+namespace aidl::android::hardware::bluetooth::audio {
+
+/**
+ * Local Capabilities Configuration
+ */
+
+enum : bool {
+  kEnableAac = true,
+  kEnableSbc = true,
+};
+
+/**
+ * Class implementation
+ */
+
+const A2dpOffloadCodecFactory* A2dpOffloadCodecFactory::GetInstance() {
+  static A2dpOffloadCodecFactory instance;
+  return &instance;
+}
+
+A2dpOffloadCodecFactory::A2dpOffloadCodecFactory()
+    : name("Offload"), codecs(ranked_codecs_) {
+  ranked_codecs_.reserve(kEnableAac + kEnableSbc);
+
+  if (kEnableAac) ranked_codecs_.push_back(A2dpOffloadCodecAac::GetInstance());
+  if (kEnableSbc) ranked_codecs_.push_back(A2dpOffloadCodecSbc::GetInstance());
+}
+
+const A2dpOffloadCodec* A2dpOffloadCodecFactory::GetCodec(CodecId id) const {
+  auto codec = std::find_if(begin(ranked_codecs_), end(ranked_codecs_),
+                            [&](auto c) { return id == c->info.id; });
+
+  return codec != end(ranked_codecs_) ? *codec : nullptr;
+}
+
+bool A2dpOffloadCodecFactory::GetConfiguration(
+    const std::vector<A2dpRemoteCapabilities>& remote_capabilities,
+    const A2dpConfigurationHint& hint, A2dpConfiguration* configuration) const {
+  decltype(ranked_codecs_) codecs;
+
+  codecs.reserve(ranked_codecs_.size());
+
+  auto hinted_codec =
+      std::find_if(begin(ranked_codecs_), end(ranked_codecs_),
+                   [&](auto c) { return hint.codecId == c->info.id; });
+
+  if (hinted_codec != end(ranked_codecs_)) codecs.push_back(*hinted_codec);
+
+  std::copy_if(begin(ranked_codecs_), end(ranked_codecs_),
+               std::back_inserter(codecs),
+               [&](auto c) { return c != *hinted_codec; });
+
+  for (auto codec : codecs) {
+    auto rc =
+        std::find_if(begin(remote_capabilities), end(remote_capabilities),
+                     [&](auto& rc__) { return codec->info.id == rc__.id; });
+
+    if ((rc == end(remote_capabilities)) ||
+        !codec->BuildConfiguration(rc->capabilities, hint.codecParameters,
+                                   &configuration->configuration))
+      continue;
+
+    configuration->id = codec->info.id;
+    A2dpStatus status = codec->ParseConfiguration(configuration->configuration,
+                                                  &configuration->parameters);
+    assert(status == A2dpStatus::OK);
+
+    configuration->remoteSeid = rc->seid;
+
+    return true;
+  }
+
+  return false;
+}
+
+}  // namespace aidl::android::hardware::bluetooth::audio
diff --git a/bluetooth/audio/aidl/default/A2dpOffloadCodecFactory.h b/bluetooth/audio/aidl/default/A2dpOffloadCodecFactory.h
new file mode 100644
index 0000000..3fb5b1d
--- /dev/null
+++ b/bluetooth/audio/aidl/default/A2dpOffloadCodecFactory.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "A2dpOffloadCodec.h"
+
+namespace aidl::android::hardware::bluetooth::audio {
+
+class A2dpOffloadCodecFactory {
+  std::vector<const A2dpOffloadCodec*> ranked_codecs_;
+
+  A2dpOffloadCodecFactory();
+
+ public:
+  const std::string name;
+  const std::vector<const A2dpOffloadCodec*>& codecs;
+
+  static const A2dpOffloadCodecFactory* GetInstance();
+
+  const A2dpOffloadCodec* GetCodec(CodecId id) const;
+
+  bool GetConfiguration(const std::vector<A2dpRemoteCapabilities>&,
+                        const A2dpConfigurationHint& hint,
+                        A2dpConfiguration* configuration) const;
+};
+
+}  // namespace aidl::android::hardware::bluetooth::audio
diff --git a/bluetooth/audio/aidl/default/A2dpOffloadCodecSbc.cpp b/bluetooth/audio/aidl/default/A2dpOffloadCodecSbc.cpp
new file mode 100644
index 0000000..36d8f72
--- /dev/null
+++ b/bluetooth/audio/aidl/default/A2dpOffloadCodecSbc.cpp
@@ -0,0 +1,510 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "A2dpOffloadCodecSbc.h"
+
+#include <algorithm>
+
+#include "A2dpBits.h"
+
+namespace aidl::android::hardware::bluetooth::audio {
+
+/**
+ * SBC Local Capabilities
+ */
+
+enum : bool {
+  kEnableSamplingFrequency44100 = true,
+  kEnableSamplingFrequency48000 = true,
+};
+
+enum : bool {
+  kEnableChannelModeMono = true,
+  kEnableChannelModeDualChannel = true,
+  kEnableChannelModeStereo = true,
+  kEnableChannelModeJointStereo = true,
+};
+
+enum : bool {
+  kEnableBlockLength4 = true,
+  kEnableBlockLength8 = true,
+  kEnableBlockLength12 = true,
+  kEnableBlockLength16 = true,
+};
+
+enum : bool {
+  kEnableSubbands4 = true,
+  kEnableSubbands8 = true,
+};
+
+enum : bool {
+  kEnableAllocationMethodSnr = true,
+  kEnableAllocationMethodLoudness = true,
+};
+
+enum : uint8_t {
+  kDefaultMinimumBitpool = 2,
+  kDefaultMaximumBitpool = 250,
+};
+
+enum : int {
+  kBitdepth = 16,
+};
+
+/**
+ * SBC Signaling format [A2DP - 4.3]
+ */
+
+// clang-format off
+
+constexpr A2dpBits::Range kSamplingFrequency (  0,  3 );
+constexpr A2dpBits::Range kChannelMode       (  4,  7 );
+constexpr A2dpBits::Range kBlockLength       (  8, 11 );
+constexpr A2dpBits::Range kSubbands          ( 12, 13 );
+constexpr A2dpBits::Range kAllocationMethod  ( 14, 15 );
+constexpr A2dpBits::Range kMinimumBitpool    ( 16, 23 );
+constexpr A2dpBits::Range kMaximumBitpool    ( 24, 31 );
+constexpr size_t kCapabilitiesSize = 32/8;
+
+// clang-format on
+
+enum {
+  kSamplingFrequency16000 = kSamplingFrequency.first,
+  kSamplingFrequency32000,
+  kSamplingFrequency44100,
+  kSamplingFrequency48000
+};
+
+enum {
+  kChannelModeMono = kChannelMode.first,
+  kChannelModeDualChannel,
+  kChannelModeStereo,
+  kChannelModeJointStereo
+};
+
+enum {
+  kBlockLength4 = kBlockLength.first,
+  kBlockLength8,
+  kBlockLength12,
+  kBlockLength16
+};
+
+enum { kSubbands8 = kSubbands.first, kSubbands4 };
+
+enum {
+  kAllocationMethodSnr = kAllocationMethod.first,
+  kAllocationMethodLoudness
+};
+
+/**
+ * SBC Conversion functions
+ */
+
+static int GetSamplingFrequencyBit(int32_t sampling_frequency) {
+  switch (sampling_frequency) {
+    case 16000:
+      return kSamplingFrequency16000;
+    case 32000:
+      return kSamplingFrequency32000;
+    case 44100:
+      return kSamplingFrequency44100;
+    case 48000:
+      return kSamplingFrequency48000;
+    default:
+      return -1;
+  }
+}
+
+static int32_t GetSamplingFrequencyValue(int sampling_frequency) {
+  switch (sampling_frequency) {
+    case kSamplingFrequency16000:
+      return 16000;
+    case kSamplingFrequency32000:
+      return 32000;
+    case kSamplingFrequency44100:
+      return 44100;
+    case kSamplingFrequency48000:
+      return 48000;
+    default:
+      return 0;
+  }
+}
+
+static int GetChannelModeBit(ChannelMode channel_mode) {
+  switch (channel_mode) {
+    case ChannelMode::STEREO:
+      return kChannelModeJointStereo | kChannelModeStereo;
+    case ChannelMode::DUALMONO:
+      return kChannelModeDualChannel;
+    case ChannelMode::MONO:
+      return kChannelModeMono;
+    default:
+      return -1;
+  }
+}
+
+static ChannelMode GetChannelModeEnum(int channel_mode) {
+  switch (channel_mode) {
+    case kChannelModeMono:
+      return ChannelMode::MONO;
+    case kChannelModeDualChannel:
+      return ChannelMode::DUALMONO;
+    case kChannelModeStereo:
+    case kChannelModeJointStereo:
+      return ChannelMode::STEREO;
+    default:
+      return ChannelMode::UNKNOWN;
+  }
+}
+
+static int32_t GetBlockLengthValue(int block_length) {
+  switch (block_length) {
+    case kBlockLength4:
+      return 4;
+    case kBlockLength8:
+      return 8;
+    case kBlockLength12:
+      return 12;
+    case kBlockLength16:
+      return 16;
+    default:
+      return 0;
+  }
+}
+
+static int32_t GetSubbandsValue(int subbands) {
+  switch (subbands) {
+    case kSubbands4:
+      return 4;
+    case kSubbands8:
+      return 8;
+    default:
+      return 0;
+  }
+}
+
+static SbcParameters::AllocationMethod GetAllocationMethodEnum(
+    int allocation_method) {
+  switch (allocation_method) {
+    case kAllocationMethodSnr:
+      return SbcParameters::AllocationMethod::SNR;
+    case kAllocationMethodLoudness:
+    default:
+      return SbcParameters::AllocationMethod::LOUDNESS;
+  }
+}
+
+static int32_t GetSamplingFrequencyValue(const A2dpBits& configuration) {
+  return GetSamplingFrequencyValue(
+      configuration.find_active_bit(kSamplingFrequency));
+}
+
+static int32_t GetBlockLengthValue(const A2dpBits& configuration) {
+  return GetBlockLengthValue(configuration.find_active_bit(kBlockLength));
+}
+
+static int32_t GetSubbandsValue(const A2dpBits& configuration) {
+  return GetSubbandsValue(configuration.find_active_bit(kSubbands));
+}
+
+static int GetFrameSize(const A2dpBits& configuration, int bitpool) {
+  const int kSbcHeaderSize = 4;
+  int subbands = GetSubbandsValue(configuration);
+  int blocks = GetBlockLengthValue(configuration);
+
+  unsigned bits =
+      ((4 * subbands) << !configuration.get(kChannelModeMono)) +
+      ((blocks * bitpool) << configuration.get(kChannelModeDualChannel)) +
+      ((configuration.get(kChannelModeJointStereo) ? subbands : 0));
+
+  return kSbcHeaderSize + ((bits + 7) >> 3);
+}
+
+static int GetBitrate(const A2dpBits& configuration, int bitpool) {
+  int sampling_frequency = GetSamplingFrequencyValue(configuration);
+  int subbands = GetSubbandsValue(configuration);
+  int blocks = GetBlockLengthValue(configuration);
+  int bits = 8 * GetFrameSize(configuration, bitpool);
+
+  return (bits * sampling_frequency) / (blocks * subbands);
+}
+
+static uint8_t GetBitpool(const A2dpBits& configuration, int bitrate) {
+  int bitpool = 0;
+
+  for (int i = 128; i; i >>= 1)
+    if (bitrate > GetBitrate(configuration, bitpool + i)) {
+      bitpool += i;
+    }
+
+  return std::clamp(bitpool, 2, 250);
+}
+
+/**
+ * SBC Class implementation
+ */
+
+const A2dpOffloadCodecSbc* A2dpOffloadCodecSbc::GetInstance() {
+  static A2dpOffloadCodecSbc instance;
+  return &instance;
+}
+
+A2dpOffloadCodecSbc::A2dpOffloadCodecSbc()
+    : A2dpOffloadCodec(info_),
+      info_({.id = CodecId(CodecId::A2dp::SBC), .name = "SBC"}) {
+  info_.transport.set<CodecInfo::Transport::Tag::a2dp>();
+  auto& a2dp_info = info_.transport.get<CodecInfo::Transport::Tag::a2dp>();
+
+  /* --- Setup Capabilities --- */
+
+  a2dp_info.capabilities.resize(kCapabilitiesSize);
+  std::fill(begin(a2dp_info.capabilities), end(a2dp_info.capabilities), 0);
+
+  auto capabilities = A2dpBits(a2dp_info.capabilities);
+
+  capabilities.set(kSamplingFrequency44100, kEnableSamplingFrequency44100);
+  capabilities.set(kSamplingFrequency48000, kEnableSamplingFrequency48000);
+
+  capabilities.set(kChannelModeMono, kEnableChannelModeMono);
+  capabilities.set(kChannelModeDualChannel, kEnableChannelModeDualChannel);
+  capabilities.set(kChannelModeStereo, kEnableChannelModeStereo);
+  capabilities.set(kChannelModeJointStereo, kEnableChannelModeJointStereo);
+
+  capabilities.set(kBlockLength4, kEnableBlockLength4);
+  capabilities.set(kBlockLength8, kEnableBlockLength8);
+  capabilities.set(kBlockLength12, kEnableBlockLength12);
+  capabilities.set(kBlockLength16, kEnableBlockLength16);
+
+  capabilities.set(kSubbands4, kEnableSubbands4);
+  capabilities.set(kSubbands8, kEnableSubbands8);
+
+  capabilities.set(kSubbands4, kEnableSubbands4);
+  capabilities.set(kSubbands8, kEnableSubbands8);
+
+  capabilities.set(kAllocationMethodSnr, kEnableAllocationMethodSnr);
+  capabilities.set(kAllocationMethodLoudness, kEnableAllocationMethodLoudness);
+
+  capabilities.set(kMinimumBitpool, kDefaultMinimumBitpool);
+  capabilities.set(kMaximumBitpool, kDefaultMaximumBitpool);
+
+  /* --- Setup Sampling Frequencies --- */
+
+  auto& sampling_frequency = a2dp_info.samplingFrequencyHz;
+
+  for (auto v : {16000, 32000, 44100, 48000})
+    if (capabilities.get(GetSamplingFrequencyBit(int32_t(v))))
+      sampling_frequency.push_back(v);
+
+  /* --- Setup Channel Modes --- */
+
+  auto& channel_modes = a2dp_info.channelMode;
+
+  for (auto v : {ChannelMode::MONO, ChannelMode::DUALMONO, ChannelMode::STEREO})
+    if (capabilities.get(GetChannelModeBit(v))) channel_modes.push_back(v);
+
+  /* --- Setup Bitdepth --- */
+
+  a2dp_info.bitdepth.push_back(kBitdepth);
+}
+
+A2dpStatus A2dpOffloadCodecSbc::ParseConfiguration(
+    const std::vector<uint8_t>& configuration,
+    CodecParameters* codec_parameters, SbcParameters* sbc_parameters) const {
+  auto& a2dp_info = info.transport.get<CodecInfo::Transport::Tag::a2dp>();
+
+  if (configuration.size() != a2dp_info.capabilities.size())
+    return A2dpStatus::BAD_LENGTH;
+
+  auto config = A2dpBits(configuration);
+  auto lcaps = A2dpBits(a2dp_info.capabilities);
+
+  /* --- Check Sampling Frequency --- */
+
+  int sampling_frequency = config.find_active_bit(kSamplingFrequency);
+  if (sampling_frequency < 0) return A2dpStatus::INVALID_SAMPLING_FREQUENCY;
+  if (!lcaps.get(sampling_frequency))
+    return A2dpStatus::NOT_SUPPORTED_SAMPLING_FREQUENCY;
+
+  /* --- Check Channel Mode --- */
+
+  int channel_mode = config.find_active_bit(kChannelMode);
+  if (channel_mode < 0) return A2dpStatus::INVALID_CHANNEL_MODE;
+  if (!lcaps.get(channel_mode)) return A2dpStatus::NOT_SUPPORTED_CHANNEL_MODE;
+
+  /* --- Check Block Length --- */
+
+  int block_length = config.find_active_bit(kBlockLength);
+  if (block_length < 0) return A2dpStatus::INVALID_BLOCK_LENGTH;
+
+  /* --- Check Subbands --- */
+
+  int subbands = config.find_active_bit(kSubbands);
+  if (subbands < 0) return A2dpStatus::INVALID_SUBBANDS;
+  if (!lcaps.get(subbands)) return A2dpStatus::NOT_SUPPORTED_SUBBANDS;
+
+  /* --- Check Allocation Method --- */
+
+  int allocation_method = config.find_active_bit(kAllocationMethod);
+  if (allocation_method < 0) return A2dpStatus::INVALID_ALLOCATION_METHOD;
+  if (!lcaps.get(allocation_method))
+    return A2dpStatus::NOT_SUPPORTED_ALLOCATION_METHOD;
+
+  /* --- Check Bitpool --- */
+
+  uint8_t min_bitpool = config.get(kMinimumBitpool);
+  if (min_bitpool < 2 || min_bitpool > 250)
+    return A2dpStatus::INVALID_MINIMUM_BITPOOL_VALUE;
+  if (min_bitpool < lcaps.get(kMinimumBitpool))
+    return A2dpStatus::NOT_SUPPORTED_MINIMUM_BITPOOL_VALUE;
+
+  uint8_t max_bitpool = config.get(kMaximumBitpool);
+  if (max_bitpool < 2 || max_bitpool > 250)
+    return A2dpStatus::INVALID_MAXIMUM_BITPOOL_VALUE;
+  if (max_bitpool > lcaps.get(kMaximumBitpool))
+    return A2dpStatus::NOT_SUPPORTED_MAXIMUM_BITPOOL_VALUE;
+
+  /* --- Return --- */
+
+  codec_parameters->channelMode = GetChannelModeEnum(channel_mode);
+  codec_parameters->samplingFrequencyHz =
+      GetSamplingFrequencyValue(sampling_frequency);
+  codec_parameters->bitdepth = kBitdepth;
+
+  codec_parameters->minBitrate = GetBitrate(config, min_bitpool);
+  codec_parameters->maxBitrate = GetBitrate(config, max_bitpool);
+
+  if (sbc_parameters) {
+    sbc_parameters->block_length = GetBlockLengthValue(block_length);
+    sbc_parameters->subbands = GetSubbandsValue(subbands);
+    sbc_parameters->allocation_method =
+        GetAllocationMethodEnum(allocation_method);
+    sbc_parameters->min_bitpool = min_bitpool;
+    sbc_parameters->max_bitpool = max_bitpool;
+  }
+
+  return A2dpStatus::OK;
+}
+
+bool A2dpOffloadCodecSbc::BuildConfiguration(
+    const std::vector<uint8_t>& remote_capabilities,
+    const std::optional<CodecParameters>& hint,
+    std::vector<uint8_t>* configuration) const {
+  auto& a2dp_info = info.transport.get<CodecInfo::Transport::Tag::a2dp>();
+
+  if (remote_capabilities.size() != a2dp_info.capabilities.size()) return false;
+
+  auto lcaps = A2dpBits(a2dp_info.capabilities);
+  auto rcaps = A2dpBits(remote_capabilities);
+
+  configuration->resize(a2dp_info.capabilities.size());
+  std::fill(begin(*configuration), end(*configuration), 0);
+  auto config = A2dpBits(*configuration);
+
+  /* --- Select Sampling Frequency --- */
+
+  auto sf_hint = hint ? GetSamplingFrequencyBit(hint->samplingFrequencyHz) : -1;
+
+  if (sf_hint >= 0 && lcaps.get(sf_hint) && rcaps.get(sf_hint))
+    config.set(sf_hint);
+  else if (lcaps.get(kSamplingFrequency44100) &&
+           rcaps.get(kSamplingFrequency44100))
+    config.set(kSamplingFrequency44100);
+  else if (lcaps.get(kSamplingFrequency48000) &&
+           rcaps.get(kSamplingFrequency48000))
+    config.set(kSamplingFrequency48000);
+  else
+    return false;
+
+  /* --- Select Channel Mode --- */
+
+  auto cm_hint = hint ? GetChannelModeBit(hint->channelMode) : -1;
+
+  if (cm_hint >= 0 && lcaps.get(cm_hint) && rcaps.get(cm_hint))
+    config.set(cm_hint);
+  else if (lcaps.get(kChannelModeJointStereo) &&
+           rcaps.get(kChannelModeJointStereo))
+    config.set(kChannelModeJointStereo);
+  else if (lcaps.get(kChannelModeStereo) && rcaps.get(kChannelModeStereo))
+    config.set(kChannelModeStereo);
+  else if (lcaps.get(kChannelModeDualChannel) &&
+           rcaps.get(kChannelModeDualChannel))
+    config.set(kChannelModeDualChannel);
+  else if (lcaps.get(kChannelModeMono) && rcaps.get(kChannelModeMono))
+    config.set(kChannelModeMono);
+  else
+    return false;
+
+  /* --- Select Block Length --- */
+
+  if (lcaps.get(kBlockLength16) && rcaps.get(kBlockLength16))
+    config.set(kBlockLength16);
+  else if (lcaps.get(kBlockLength12) && rcaps.get(kBlockLength12))
+    config.set(kBlockLength12);
+  else if (lcaps.get(kBlockLength8) && rcaps.get(kBlockLength8))
+    config.set(kBlockLength8);
+  else if (lcaps.get(kBlockLength4) && rcaps.get(kBlockLength4))
+    config.set(kBlockLength4);
+  else
+    return false;
+
+  /* --- Select Subbands --- */
+
+  if (lcaps.get(kSubbands8) && rcaps.get(kSubbands8))
+    config.set(kSubbands8);
+  else if (lcaps.get(kSubbands4) && rcaps.get(kSubbands4))
+    config.set(kSubbands4);
+  else
+    return false;
+
+  /* --- Select Allocation method --- */
+
+  if (lcaps.get(kAllocationMethodLoudness) &&
+      rcaps.get(kAllocationMethodLoudness))
+    config.set(kAllocationMethodLoudness);
+  else if (lcaps.get(kAllocationMethodSnr) && rcaps.get(kAllocationMethodSnr))
+    config.set(kAllocationMethodSnr);
+  else
+    return false;
+
+  /* --- Select Bitpool --- */
+
+  uint8_t min_bitpool = rcaps.get(kMinimumBitpool);
+  uint8_t max_bitpool = rcaps.get(kMaximumBitpool);
+
+  if (min_bitpool < 2 || min_bitpool > 250 || max_bitpool < 2 ||
+      max_bitpool > 250 || min_bitpool > max_bitpool) {
+    min_bitpool = 2;
+    max_bitpool = 250;
+  }
+
+  min_bitpool = std::max(min_bitpool, uint8_t(lcaps.get(kMinimumBitpool)));
+  max_bitpool = std::max(max_bitpool, uint8_t(lcaps.get(kMaximumBitpool)));
+
+  if (hint) {
+    min_bitpool =
+        std::max(min_bitpool, GetBitpool(*configuration, hint->minBitrate));
+    if (hint->maxBitrate && hint->maxBitrate >= hint->minBitrate)
+      max_bitpool =
+          std::min(max_bitpool, GetBitpool(*configuration, hint->maxBitrate));
+  }
+
+  config.set(kMinimumBitpool, min_bitpool);
+  config.set(kMaximumBitpool, max_bitpool);
+
+  return true;
+}
+
+}  // namespace aidl::android::hardware::bluetooth::audio
diff --git a/bluetooth/audio/aidl/default/A2dpOffloadCodecSbc.h b/bluetooth/audio/aidl/default/A2dpOffloadCodecSbc.h
new file mode 100644
index 0000000..c380850
--- /dev/null
+++ b/bluetooth/audio/aidl/default/A2dpOffloadCodecSbc.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "A2dpOffloadCodec.h"
+
+namespace aidl::android::hardware::bluetooth::audio {
+
+struct SbcParameters : public CodecParameters {
+  enum class AllocationMethod { SNR, LOUDNESS };
+
+  AllocationMethod allocation_method;
+  int block_length;
+  int subbands;
+  int min_bitpool;
+  int max_bitpool;
+};
+
+class A2dpOffloadCodecSbc : public A2dpOffloadCodec {
+  CodecInfo info_;
+
+  A2dpOffloadCodecSbc();
+
+  A2dpStatus ParseConfiguration(const std::vector<uint8_t>& configuration,
+                                CodecParameters* codec_parameters,
+                                SbcParameters* sbc_parameters) const;
+
+ public:
+  static const A2dpOffloadCodecSbc* GetInstance();
+
+  A2dpStatus ParseConfiguration(
+      const std::vector<uint8_t>& configuration,
+      CodecParameters* codec_parameters) const override {
+    return ParseConfiguration(configuration, codec_parameters, nullptr);
+  }
+
+  A2dpStatus ParseConfiguration(const std::vector<uint8_t>& configuration,
+                                SbcParameters* sbc_parameters) const {
+    return ParseConfiguration(configuration, sbc_parameters, sbc_parameters);
+  }
+
+  bool BuildConfiguration(const std::vector<uint8_t>& remote_capabilities,
+                          const std::optional<CodecParameters>& hint,
+                          std::vector<uint8_t>* configuration) const override;
+};
+
+}  // namespace aidl::android::hardware::bluetooth::audio
diff --git a/bluetooth/audio/aidl/default/Android.bp b/bluetooth/audio/aidl/default/Android.bp
index e4c2844..69db1b3 100644
--- a/bluetooth/audio/aidl/default/Android.bp
+++ b/bluetooth/audio/aidl/default/Android.bp
@@ -11,12 +11,20 @@
     name: "android.hardware.bluetooth.audio-impl",
     vendor: true,
     vintf_fragments: ["bluetooth_audio.xml"],
+    defaults: [
+        "latest_android_hardware_bluetooth_audio_ndk_shared",
+    ],
     srcs: [
         "BluetoothAudioProvider.cpp",
         "BluetoothAudioProviderFactory.cpp",
         "A2dpOffloadAudioProvider.cpp",
+        "A2dpOffloadCodecAac.cpp",
+        "A2dpOffloadCodecFactory.cpp",
+        "A2dpOffloadCodecSbc.cpp",
         "A2dpSoftwareAudioProvider.cpp",
         "HearingAidAudioProvider.cpp",
+        "HfpOffloadAudioProvider.cpp",
+        "HfpSoftwareAudioProvider.cpp",
         "LeAudioOffloadAudioProvider.cpp",
         "LeAudioSoftwareAudioProvider.cpp",
         "service.cpp",
@@ -29,7 +37,6 @@
         "libcutils",
         "libfmq",
         "liblog",
-        "android.hardware.bluetooth.audio-V3-ndk",
         "libbluetooth_audio_session_aidl",
     ],
 }
diff --git a/bluetooth/audio/aidl/default/BluetoothAudioProvider.cpp b/bluetooth/audio/aidl/default/BluetoothAudioProvider.cpp
index 9c72e19..8d03fae 100644
--- a/bluetooth/audio/aidl/default/BluetoothAudioProvider.cpp
+++ b/bluetooth/audio/aidl/default/BluetoothAudioProvider.cpp
@@ -21,6 +21,8 @@
 #include <BluetoothAudioSessionReport.h>
 #include <android-base/logging.h>
 
+#include "A2dpOffloadCodecFactory.h"
+
 namespace aidl {
 namespace android {
 namespace hardware {
@@ -164,8 +166,146 @@
   return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus BluetoothAudioProvider::parseA2dpConfiguration(
+    [[maybe_unused]] const CodecId& codec_id,
+    [[maybe_unused]] const std::vector<uint8_t>& configuration,
+    [[maybe_unused]] CodecParameters* codec_parameters,
+    [[maybe_unused]] A2dpStatus* _aidl_return) {
+  LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+            << " is illegal";
+  return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+}
+
+ndk::ScopedAStatus BluetoothAudioProvider::getA2dpConfiguration(
+    [[maybe_unused]] const std::vector<A2dpRemoteCapabilities>&
+        remote_a2dp_capabilities,
+    [[maybe_unused]] const A2dpConfigurationHint& hint,
+    [[maybe_unused]] std::optional<audio::A2dpConfiguration>* _aidl_return) {
+  LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+            << " is illegal";
+
+  return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+}
+
+ndk::ScopedAStatus BluetoothAudioProvider::setCodecPriority(
+    const ::aidl::android::hardware::bluetooth::audio::CodecId& in_codecId,
+    int32_t in_priority) {
+  /* TODO: Implement */
+  (void)in_codecId;
+  (void)in_priority;
+  return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+};
+
+ndk::ScopedAStatus BluetoothAudioProvider::getLeAudioAseConfiguration(
+    const std::optional<std::vector<std::optional<
+        ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+            LeAudioDeviceCapabilities>>>& in_remoteSinkAudioCapabilities,
+    const std::optional<std::vector<std::optional<
+        ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+            LeAudioDeviceCapabilities>>>& in_remoteSourceAudioCapabilities,
+    const std::vector<
+        ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+            LeAudioConfigurationRequirement>& in_requirements,
+    std::vector<::aidl::android::hardware::bluetooth::audio::
+                    IBluetoothAudioProvider::LeAudioAseConfigurationSetting>*
+        _aidl_return) {
+  /* TODO: Implement */
+  (void)in_remoteSinkAudioCapabilities;
+  (void)in_remoteSourceAudioCapabilities;
+  (void)in_requirements;
+  (void)_aidl_return;
+  return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+};
+
+ndk::ScopedAStatus BluetoothAudioProvider::getLeAudioAseQosConfiguration(
+    const ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+        LeAudioAseQosConfigurationRequirement& in_qosRequirement,
+    ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+        LeAudioAseQosConfigurationPair* _aidl_return) {
+  /* TODO: Implement */
+  (void)in_qosRequirement;
+  (void)_aidl_return;
+  return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+};
+
+ndk::ScopedAStatus BluetoothAudioProvider::getLeAudioAseDatapathConfiguration(
+    const std::optional<::aidl::android::hardware::bluetooth::audio::
+                            IBluetoothAudioProvider::StreamConfig>&
+        in_sinkConfig,
+    const std::optional<::aidl::android::hardware::bluetooth::audio::
+                            IBluetoothAudioProvider::StreamConfig>&
+        in_sourceConfig,
+    ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+        LeAudioDataPathConfigurationPair* _aidl_return) {
+  /* TODO: Implement */
+  (void)in_sinkConfig;
+  (void)in_sourceConfig;
+  (void)_aidl_return;
+  return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus BluetoothAudioProvider::onSinkAseMetadataChanged(
+    ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+        AseState in_state,
+    int32_t cigId, int32_t cisId,
+    const std::optional<std::vector<std::optional<
+        ::aidl::android::hardware::bluetooth::audio::MetadataLtv>>>&
+        in_metadata) {
+  /* TODO: Implement */
+  (void)in_state;
+  (void)cigId;
+  (void)cisId;
+  (void)in_metadata;
+  return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+};
+
+ndk::ScopedAStatus BluetoothAudioProvider::onSourceAseMetadataChanged(
+    ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+        AseState in_state,
+    int32_t cigId, int32_t cisId,
+    const std::optional<std::vector<std::optional<
+        ::aidl::android::hardware::bluetooth::audio::MetadataLtv>>>&
+        in_metadata) {
+  /* TODO: Implement */
+  (void)in_state;
+  (void)cigId;
+  (void)cisId;
+  (void)in_metadata;
+  return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+};
+
+ndk::ScopedAStatus BluetoothAudioProvider::getLeAudioBroadcastConfiguration(
+    const std::optional<std::vector<std::optional<
+        ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+            LeAudioDeviceCapabilities>>>& in_remoteSinkAudioCapabilities,
+    const ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+        LeAudioBroadcastConfigurationRequirement& in_requirement,
+    ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+        LeAudioBroadcastConfigurationSetting* _aidl_return) {
+  /* TODO: Implement */
+  (void)in_remoteSinkAudioCapabilities;
+  (void)in_requirement;
+  (void)_aidl_return;
+  return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+};
+
+ndk::ScopedAStatus
+BluetoothAudioProvider::getLeAudioBroadcastDatapathConfiguration(
+    const ::aidl::android::hardware::bluetooth::audio::AudioContext& in_context,
+    const std::vector<::aidl::android::hardware::bluetooth::audio::
+                          LeAudioBroadcastConfiguration::BroadcastStreamMap>&
+        in_streamMap,
+    ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+        LeAudioDataPathConfiguration* _aidl_return) {
+  /* TODO: Implement */
+  (void)in_context;
+  (void)in_streamMap;
+  (void)_aidl_return;
+  return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
 }  // namespace audio
 }  // namespace bluetooth
 }  // namespace hardware
 }  // namespace android
-}  // namespace aidl
\ No newline at end of file
+}  // namespace aidl
diff --git a/bluetooth/audio/aidl/default/BluetoothAudioProvider.h b/bluetooth/audio/aidl/default/BluetoothAudioProvider.h
index b6e07a1..2c21440 100644
--- a/bluetooth/audio/aidl/default/BluetoothAudioProvider.h
+++ b/bluetooth/audio/aidl/default/BluetoothAudioProvider.h
@@ -41,14 +41,83 @@
   ndk::ScopedAStatus startSession(
       const std::shared_ptr<IBluetoothAudioPort>& host_if,
       const AudioConfiguration& audio_config,
-      const std::vector<LatencyMode>& latency_modes,
-      DataMQDesc* _aidl_return);
+      const std::vector<LatencyMode>& latency_modes, DataMQDesc* _aidl_return);
   ndk::ScopedAStatus endSession();
   ndk::ScopedAStatus streamStarted(BluetoothAudioStatus status);
   ndk::ScopedAStatus streamSuspended(BluetoothAudioStatus status);
   ndk::ScopedAStatus updateAudioConfiguration(
       const AudioConfiguration& audio_config);
   ndk::ScopedAStatus setLowLatencyModeAllowed(bool allowed);
+  ndk::ScopedAStatus setCodecPriority(
+      const ::aidl::android::hardware::bluetooth::audio::CodecId& in_codecId,
+      int32_t in_priority) override;
+  ndk::ScopedAStatus getLeAudioAseConfiguration(
+      const std::optional<std::vector<std::optional<
+          ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+              LeAudioDeviceCapabilities>>>& in_remoteSinkAudioCapabilities,
+      const std::optional<std::vector<std::optional<
+          ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+              LeAudioDeviceCapabilities>>>& in_remoteSourceAudioCapabilities,
+      const std::vector<
+          ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+              LeAudioConfigurationRequirement>& in_requirements,
+      std::vector<::aidl::android::hardware::bluetooth::audio::
+                      IBluetoothAudioProvider::LeAudioAseConfigurationSetting>*
+          _aidl_return) override;
+  ndk::ScopedAStatus getLeAudioAseQosConfiguration(
+      const ::aidl::android::hardware::bluetooth::audio::
+          IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement&
+              in_qosRequirement,
+      ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+          LeAudioAseQosConfigurationPair* _aidl_return) override;
+  ndk::ScopedAStatus getLeAudioAseDatapathConfiguration(
+      const std::optional<::aidl::android::hardware::bluetooth::audio::
+                              IBluetoothAudioProvider::StreamConfig>&
+          in_sinkConfig,
+      const std::optional<::aidl::android::hardware::bluetooth::audio::
+                              IBluetoothAudioProvider::StreamConfig>&
+          in_sourceConfig,
+      ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+          LeAudioDataPathConfigurationPair* _aidl_return) override;
+  ndk::ScopedAStatus onSinkAseMetadataChanged(
+      ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+          AseState in_state,
+      int32_t cigId, int32_t cisId,
+      const std::optional<std::vector<std::optional<
+          ::aidl::android::hardware::bluetooth::audio::MetadataLtv>>>&
+          in_metadata) override;
+  ndk::ScopedAStatus onSourceAseMetadataChanged(
+      ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+          AseState in_state,
+      int32_t cigId, int32_t cisId,
+      const std::optional<std::vector<std::optional<
+          ::aidl::android::hardware::bluetooth::audio::MetadataLtv>>>&
+          in_metadata) override;
+  ndk::ScopedAStatus getLeAudioBroadcastConfiguration(
+      const std::optional<std::vector<std::optional<
+          ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+              LeAudioDeviceCapabilities>>>& in_remoteSinkAudioCapabilities,
+      const ::aidl::android::hardware::bluetooth::audio::
+          IBluetoothAudioProvider::LeAudioBroadcastConfigurationRequirement&
+              in_requirement,
+      ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+          LeAudioBroadcastConfigurationSetting* _aidl_return) override;
+  ndk::ScopedAStatus getLeAudioBroadcastDatapathConfiguration(
+      const ::aidl::android::hardware::bluetooth::audio::AudioContext&
+          in_context,
+      const std::vector<::aidl::android::hardware::bluetooth::audio::
+                            LeAudioBroadcastConfiguration::BroadcastStreamMap>&
+          in_streamMap,
+      ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+          LeAudioDataPathConfiguration* _aidl_return) override;
+
+  ndk::ScopedAStatus parseA2dpConfiguration(
+      const CodecId& codec_id, const std::vector<uint8_t>& configuration,
+      CodecParameters* codec_parameters, A2dpStatus* _aidl_return);
+  ndk::ScopedAStatus getA2dpConfiguration(
+      const std::vector<A2dpRemoteCapabilities>& remote_a2dp_capabilities,
+      const A2dpConfigurationHint& hint,
+      std::optional<audio::A2dpConfiguration>* _aidl_return);
 
   virtual bool isValid(const SessionType& sessionType) = 0;
 
diff --git a/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.cpp b/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.cpp
index 91731d4..e55a434 100644
--- a/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.cpp
+++ b/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.cpp
@@ -22,9 +22,12 @@
 #include <android-base/logging.h>
 
 #include "A2dpOffloadAudioProvider.h"
+#include "A2dpOffloadCodecFactory.h"
 #include "A2dpSoftwareAudioProvider.h"
 #include "BluetoothAudioProvider.h"
 #include "HearingAidAudioProvider.h"
+#include "HfpOffloadAudioProvider.h"
+#include "HfpSoftwareAudioProvider.h"
 #include "LeAudioOffloadAudioProvider.h"
 #include "LeAudioSoftwareAudioProvider.h"
 
@@ -34,6 +37,9 @@
 namespace bluetooth {
 namespace audio {
 
+static const std::string kLeAudioOffloadProviderName =
+    "LE_AUDIO_OFFLOAD_HARDWARE_OFFLOAD_PROVIDER";
+
 BluetoothAudioProviderFactory::BluetoothAudioProviderFactory() {}
 
 ndk::ScopedAStatus BluetoothAudioProviderFactory::openProvider(
@@ -78,6 +84,15 @@
     case SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH:
       provider = ndk::SharedRefBase::make<A2dpOffloadDecodingAudioProvider>();
       break;
+    case SessionType::HFP_SOFTWARE_ENCODING_DATAPATH:
+      provider = ndk::SharedRefBase::make<HfpSoftwareOutputAudioProvider>();
+      break;
+    case SessionType::HFP_SOFTWARE_DECODING_DATAPATH:
+      provider = ndk::SharedRefBase::make<HfpSoftwareInputAudioProvider>();
+      break;
+    case SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH:
+      provider = ndk::SharedRefBase::make<HfpOffloadAudioProvider>();
+      break;
     default:
       provider = nullptr;
       break;
@@ -135,8 +150,43 @@
   return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus BluetoothAudioProviderFactory::getProviderInfo(
+    SessionType session_type, std::optional<ProviderInfo>* _aidl_return) {
+  *_aidl_return = std::nullopt;
+
+  LOG(INFO) << __func__ << " - SessionType=" << toString(session_type);
+
+  if (session_type == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
+      session_type == SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
+    auto& provider_info = _aidl_return->emplace();
+
+    provider_info.name = A2dpOffloadCodecFactory::GetInstance()->name;
+    for (auto codec : A2dpOffloadCodecFactory::GetInstance()->codecs)
+      provider_info.codecInfos.push_back(codec->info);
+  }
+
+  if (session_type ==
+          SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
+      session_type ==
+          SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH ||
+      session_type ==
+          SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
+    std::vector<CodecInfo> db_codec_info =
+        BluetoothAudioCodecs::GetLeAudioOffloadCodecInfo(session_type);
+    if (!db_codec_info.empty()) {
+      auto& provider_info = _aidl_return->emplace();
+      provider_info.name = kLeAudioOffloadProviderName;
+      provider_info.codecInfos = db_codec_info;
+      *_aidl_return = provider_info;
+      return ndk::ScopedAStatus::ok();
+    }
+  }
+
+  return ndk::ScopedAStatus::ok();
+}
+
 }  // namespace audio
 }  // namespace bluetooth
 }  // namespace hardware
 }  // namespace android
-}  // namespace aidl
\ No newline at end of file
+}  // namespace aidl
diff --git a/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.h b/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.h
index b38cfd2..1afae64 100644
--- a/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.h
+++ b/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.h
@@ -35,6 +35,10 @@
   ndk::ScopedAStatus getProviderCapabilities(
       const SessionType session_type,
       std::vector<AudioCapabilities>* _aidl_return) override;
+
+  ndk::ScopedAStatus getProviderInfo(
+      SessionType in_sessionType,
+      std::optional<ProviderInfo>* _aidl_return) override;
 };
 
 }  // namespace audio
diff --git a/bluetooth/audio/aidl/default/HfpOffloadAudioProvider.cpp b/bluetooth/audio/aidl/default/HfpOffloadAudioProvider.cpp
new file mode 100644
index 0000000..7196bb6
--- /dev/null
+++ b/bluetooth/audio/aidl/default/HfpOffloadAudioProvider.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "BTAudioProviderHfpHW"
+
+#include "HfpOffloadAudioProvider.h"
+
+#include <BluetoothAudioCodecs.h>
+#include <BluetoothAudioSessionReport.h>
+#include <android-base/logging.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+HfpOffloadAudioProvider::HfpOffloadAudioProvider() {
+  session_type_ = SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH;
+}
+
+bool HfpOffloadAudioProvider::isValid(const SessionType& session_type) {
+  return (session_type == session_type_);
+}
+
+ndk::ScopedAStatus HfpOffloadAudioProvider::startSession(
+    const std::shared_ptr<IBluetoothAudioPort>& host_if,
+    const AudioConfiguration& audio_config,
+    const std::vector<LatencyMode>& latency_modes, DataMQDesc* _aidl_return) {
+  if (audio_config.getTag() != AudioConfiguration::hfpConfig) {
+    LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
+                 << audio_config.toString();
+    *_aidl_return = DataMQDesc();
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+  }
+  return BluetoothAudioProvider::startSession(host_if, audio_config,
+                                              latency_modes, _aidl_return);
+}
+
+ndk::ScopedAStatus HfpOffloadAudioProvider::onSessionReady(
+    DataMQDesc* _aidl_return) {
+  *_aidl_return = DataMQDesc();
+  BluetoothAudioSessionReport::OnSessionStarted(
+      session_type_, stack_iface_, nullptr, *audio_config_, latency_modes_);
+  return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/bluetooth/audio/aidl/default/HfpOffloadAudioProvider.h b/bluetooth/audio/aidl/default/HfpOffloadAudioProvider.h
new file mode 100644
index 0000000..5526b46
--- /dev/null
+++ b/bluetooth/audio/aidl/default/HfpOffloadAudioProvider.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "BluetoothAudioProvider.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+class HfpOffloadAudioProvider : public BluetoothAudioProvider {
+ public:
+  HfpOffloadAudioProvider();
+
+  bool isValid(const SessionType& sessionType) override;
+
+  ndk::ScopedAStatus startSession(
+      const std::shared_ptr<IBluetoothAudioPort>& host_if,
+      const AudioConfiguration& audio_config,
+      const std::vector<LatencyMode>& latency_modes, DataMQDesc* _aidl_return);
+
+ private:
+  ndk::ScopedAStatus onSessionReady(DataMQDesc* _aidl_return) override;
+};
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/bluetooth/audio/aidl/default/HfpSoftwareAudioProvider.cpp b/bluetooth/audio/aidl/default/HfpSoftwareAudioProvider.cpp
new file mode 100644
index 0000000..0f96046
--- /dev/null
+++ b/bluetooth/audio/aidl/default/HfpSoftwareAudioProvider.cpp
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "BTAudioProviderHfpSW"
+
+#include "HfpSoftwareAudioProvider.h"
+
+#include <BluetoothAudioCodecs.h>
+#include <BluetoothAudioSessionReport.h>
+#include <android-base/logging.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+static constexpr uint32_t kBufferCount = 2;  // two frame buffer
+
+HfpSoftwareOutputAudioProvider::HfpSoftwareOutputAudioProvider()
+    : HfpSoftwareAudioProvider() {
+  session_type_ = SessionType::HFP_SOFTWARE_ENCODING_DATAPATH;
+}
+
+HfpSoftwareInputAudioProvider::HfpSoftwareInputAudioProvider()
+    : HfpSoftwareAudioProvider() {
+  session_type_ = SessionType::HFP_SOFTWARE_DECODING_DATAPATH;
+}
+
+HfpSoftwareAudioProvider::HfpSoftwareAudioProvider()
+    : BluetoothAudioProvider(), data_mq_(nullptr) {
+}
+
+bool HfpSoftwareAudioProvider::isValid(const SessionType& sessionType) {
+  return (sessionType == session_type_);
+}
+
+ndk::ScopedAStatus HfpSoftwareAudioProvider::startSession(
+    const std::shared_ptr<IBluetoothAudioPort>& host_if,
+    const AudioConfiguration& audio_config,
+    const std::vector<LatencyMode>& latency_modes, DataMQDesc* _aidl_return) {
+  if (audio_config.getTag() != AudioConfiguration::pcmConfig) {
+    LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
+                 << audio_config.toString();
+    *_aidl_return = DataMQDesc();
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+  }
+  const PcmConfiguration& pcm_config =
+      audio_config.get<AudioConfiguration::pcmConfig>();
+  if (!BluetoothAudioCodecs::IsSoftwarePcmConfigurationValid(pcm_config)) {
+    LOG(WARNING) << __func__ << " - Unsupported PCM Configuration="
+                 << pcm_config.toString();
+    *_aidl_return = DataMQDesc();
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+  }
+
+  bool isValidConfig = true;
+
+  if (pcm_config.bitsPerSample != 16) {
+    isValidConfig = false;
+  }
+
+  if (pcm_config.sampleRateHz != 8000 && pcm_config.sampleRateHz != 16000 &&
+      pcm_config.sampleRateHz != 32000) {
+    isValidConfig = false;
+  }
+
+  if (pcm_config.channelMode != ChannelMode::MONO) {
+    isValidConfig = false;
+  }
+
+  if (pcm_config.dataIntervalUs != 7500) {
+    isValidConfig = false;
+  }
+
+  int bytes_per_sample = pcm_config.bitsPerSample / 8;
+
+  uint32_t data_mq_size = kBufferCount * bytes_per_sample *
+                          (pcm_config.sampleRateHz / 1000) *
+                          pcm_config.dataIntervalUs / 1000;
+  if (!isValidConfig) {
+    LOG(ERROR) << __func__ << "Unexpected audio buffer size: " << data_mq_size
+               << ", SampleRateHz: " << pcm_config.sampleRateHz
+               << ", ChannelMode: " << toString(pcm_config.channelMode)
+               << ", BitsPerSample: "
+               << static_cast<int>(pcm_config.bitsPerSample)
+               << ", BytesPerSample: " << bytes_per_sample
+               << ", DataIntervalUs: " << pcm_config.dataIntervalUs
+               << ", SessionType: " << toString(session_type_);
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+  }
+
+  LOG(INFO) << __func__ << " - size of audio buffer " << data_mq_size
+            << " byte(s)";
+
+  std::unique_ptr<DataMQ> temp_data_mq(
+      new DataMQ(data_mq_size, /* EventFlag */ true));
+  if (temp_data_mq == nullptr || !temp_data_mq->isValid()) {
+    ALOGE_IF(!temp_data_mq, "failed to allocate data MQ");
+    ALOGE_IF(temp_data_mq && !temp_data_mq->isValid(), "data MQ is invalid");
+    *_aidl_return = DataMQDesc();
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+  }
+  data_mq_ = std::move(temp_data_mq);
+
+  return BluetoothAudioProvider::startSession(host_if, audio_config,
+                                              latency_modes, _aidl_return);
+}
+
+ndk::ScopedAStatus HfpSoftwareAudioProvider::onSessionReady(
+    DataMQDesc* _aidl_return) {
+  if (data_mq_ == nullptr || !data_mq_->isValid()) {
+    *_aidl_return = DataMQDesc();
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+  }
+  *_aidl_return = data_mq_->dupeDesc();
+  auto desc = data_mq_->dupeDesc();
+  BluetoothAudioSessionReport::OnSessionStarted(
+      session_type_, stack_iface_, &desc, *audio_config_, latency_modes_);
+  return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/bluetooth/audio/aidl/default/HfpSoftwareAudioProvider.h b/bluetooth/audio/aidl/default/HfpSoftwareAudioProvider.h
new file mode 100644
index 0000000..ef51065
--- /dev/null
+++ b/bluetooth/audio/aidl/default/HfpSoftwareAudioProvider.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "BluetoothAudioProvider.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+class HfpSoftwareAudioProvider : public BluetoothAudioProvider {
+ public:
+  HfpSoftwareAudioProvider();
+
+  bool isValid(const SessionType& sessionType) override;
+
+  ndk::ScopedAStatus startSession(
+      const std::shared_ptr<IBluetoothAudioPort>& host_if,
+      const AudioConfiguration& audio_config,
+      const std::vector<LatencyMode>& latency_modes, DataMQDesc* _aidl_return);
+
+ private:
+  // audio data queue for software encoding
+  std::unique_ptr<DataMQ> data_mq_;
+
+  ndk::ScopedAStatus onSessionReady(DataMQDesc* _aidl_return) override;
+};
+
+class HfpSoftwareOutputAudioProvider : public HfpSoftwareAudioProvider {
+ public:
+  HfpSoftwareOutputAudioProvider();
+};
+
+class HfpSoftwareInputAudioProvider : public HfpSoftwareAudioProvider {
+ public:
+  HfpSoftwareInputAudioProvider();
+};
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
index 7f610ef..a692d84 100644
--- a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
+++ b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
@@ -28,6 +28,73 @@
 namespace bluetooth {
 namespace audio {
 
+constexpr uint8_t kLeAudioDirectionSink = 0x01;
+constexpr uint8_t kLeAudioDirectionSource = 0x02;
+
+const std::map<CodecSpecificConfigurationLtv::SamplingFrequency, uint32_t>
+    freq_to_support_bitmask_map = {
+        {CodecSpecificConfigurationLtv::SamplingFrequency::HZ8000,
+         CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ8000},
+        {CodecSpecificConfigurationLtv::SamplingFrequency::HZ11025,
+         CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ11025},
+        {CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000,
+         CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ16000},
+        {CodecSpecificConfigurationLtv::SamplingFrequency::HZ22050,
+         CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ22050},
+        {CodecSpecificConfigurationLtv::SamplingFrequency::HZ24000,
+         CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ24000},
+        {CodecSpecificConfigurationLtv::SamplingFrequency::HZ32000,
+         CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ32000},
+        {CodecSpecificConfigurationLtv::SamplingFrequency::HZ48000,
+         CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ48000},
+        {CodecSpecificConfigurationLtv::SamplingFrequency::HZ88200,
+         CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ88200},
+        {CodecSpecificConfigurationLtv::SamplingFrequency::HZ96000,
+         CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ96000},
+        {CodecSpecificConfigurationLtv::SamplingFrequency::HZ176400,
+         CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ176400},
+        {CodecSpecificConfigurationLtv::SamplingFrequency::HZ192000,
+         CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ192000},
+        {CodecSpecificConfigurationLtv::SamplingFrequency::HZ384000,
+         CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ384000},
+};
+
+// Helper map from capability's tag to configuration's tag
+std::map<CodecSpecificCapabilitiesLtv::Tag, CodecSpecificConfigurationLtv::Tag>
+    cap_to_cfg_tag_map = {
+        {CodecSpecificCapabilitiesLtv::Tag::supportedSamplingFrequencies,
+         CodecSpecificConfigurationLtv::Tag::samplingFrequency},
+        {CodecSpecificCapabilitiesLtv::Tag::supportedMaxCodecFramesPerSDU,
+         CodecSpecificConfigurationLtv::Tag::codecFrameBlocksPerSDU},
+        {CodecSpecificCapabilitiesLtv::Tag::supportedFrameDurations,
+         CodecSpecificConfigurationLtv::Tag::frameDuration},
+        {CodecSpecificCapabilitiesLtv::Tag::supportedAudioChannelCounts,
+         CodecSpecificConfigurationLtv::Tag::audioChannelAllocation},
+        {CodecSpecificCapabilitiesLtv::Tag::supportedOctetsPerCodecFrame,
+         CodecSpecificConfigurationLtv::Tag::octetsPerCodecFrame},
+};
+
+const std::map<CodecSpecificConfigurationLtv::FrameDuration, uint32_t>
+    fduration_to_support_fduration_map = {
+        {CodecSpecificConfigurationLtv::FrameDuration::US7500,
+         CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US7500},
+        {CodecSpecificConfigurationLtv::FrameDuration::US10000,
+         CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US10000},
+};
+
+std::map<int32_t, CodecSpecificConfigurationLtv::SamplingFrequency>
+    sampling_freq_map = {
+        {16000, CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000},
+        {48000, CodecSpecificConfigurationLtv::SamplingFrequency::HZ48000},
+        {96000, CodecSpecificConfigurationLtv::SamplingFrequency::HZ96000},
+};
+
+std::map<int32_t, CodecSpecificConfigurationLtv::FrameDuration>
+    frame_duration_map = {
+        {7500, CodecSpecificConfigurationLtv::FrameDuration::US7500},
+        {10000, CodecSpecificConfigurationLtv::FrameDuration::US10000},
+};
+
 LeAudioOffloadOutputAudioProvider::LeAudioOffloadOutputAudioProvider()
     : LeAudioOffloadAudioProvider() {
   session_type_ = SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH;
@@ -70,8 +137,8 @@
     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
   }
 
-  return BluetoothAudioProvider::startSession(
-      host_if, audio_config, latency_modes, _aidl_return);
+  return BluetoothAudioProvider::startSession(host_if, audio_config,
+                                              latency_modes, _aidl_return);
 }
 
 ndk::ScopedAStatus LeAudioOffloadAudioProvider::onSessionReady(
@@ -81,6 +148,647 @@
   *_aidl_return = DataMQDesc();
   return ndk::ScopedAStatus::ok();
 }
+ndk::ScopedAStatus LeAudioOffloadAudioProvider::setCodecPriority(
+    const CodecId& in_codecId, int32_t in_priority) {
+  codec_priority_map_[in_codecId] = in_priority;
+  return ndk::ScopedAStatus::ok();
+};
+
+bool LeAudioOffloadAudioProvider::isMatchedValidCodec(CodecId cfg_codec,
+                                                      CodecId req_codec) {
+  auto priority = codec_priority_map_.find(cfg_codec);
+  if (priority != codec_priority_map_.end() &&
+      priority->second ==
+          LeAudioOffloadAudioProvider::CODEC_PRIORITY_DISABLED) {
+    return false;
+  }
+  return cfg_codec == req_codec;
+}
+
+bool LeAudioOffloadAudioProvider::isCapabilitiesMatchedContext(
+    AudioContext setting_context,
+    const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities) {
+  // If has no metadata, assume match
+  if (!capabilities.metadata.has_value()) return true;
+
+  for (auto metadata : capabilities.metadata.value()) {
+    if (!metadata.has_value()) continue;
+    if (metadata.value().getTag() == MetadataLtv::Tag::preferredAudioContexts) {
+      // Check all pref audio context to see if anything matched
+      auto& context = metadata.value()
+                          .get<MetadataLtv::Tag::preferredAudioContexts>()
+                          .values;
+      if (setting_context.bitmask & context.bitmask) return true;
+    }
+  }
+
+  return false;
+}
+
+bool LeAudioOffloadAudioProvider::isMatchedSamplingFreq(
+    CodecSpecificConfigurationLtv::SamplingFrequency& cfg_freq,
+    CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies&
+        capability_freq) {
+  for (auto [freq, bitmask] : freq_to_support_bitmask_map)
+    if (cfg_freq == freq) return (capability_freq.bitmask & bitmask);
+  return false;
+}
+
+bool LeAudioOffloadAudioProvider::isMatchedFrameDuration(
+    CodecSpecificConfigurationLtv::FrameDuration& cfg_fduration,
+    CodecSpecificCapabilitiesLtv::SupportedFrameDurations&
+        capability_fduration) {
+  for (auto [fduration, bitmask] : fduration_to_support_fduration_map)
+    if (cfg_fduration == fduration)
+      return (capability_fduration.bitmask & bitmask);
+  return false;
+}
+
+bool LeAudioOffloadAudioProvider::isMatchedAudioChannel(
+    CodecSpecificConfigurationLtv::AudioChannelAllocation&
+    /*cfg_channel*/,
+    CodecSpecificCapabilitiesLtv::SupportedAudioChannelCounts&
+    /*capability_channel*/) {
+  bool isMatched = true;
+  // TODO: how to match?
+  return isMatched;
+}
+
+bool LeAudioOffloadAudioProvider::isMatchedCodecFramesPerSDU(
+    CodecSpecificConfigurationLtv::CodecFrameBlocksPerSDU& cfg_frame_sdu,
+    CodecSpecificCapabilitiesLtv::SupportedMaxCodecFramesPerSDU&
+        capability_frame_sdu) {
+  return cfg_frame_sdu.value <= capability_frame_sdu.value;
+}
+
+bool LeAudioOffloadAudioProvider::isMatchedOctetsPerCodecFrame(
+    CodecSpecificConfigurationLtv::OctetsPerCodecFrame& cfg_octets,
+    CodecSpecificCapabilitiesLtv::SupportedOctetsPerCodecFrame&
+        capability_octets) {
+  return cfg_octets.value >= capability_octets.min &&
+         cfg_octets.value <= capability_octets.max;
+}
+
+bool LeAudioOffloadAudioProvider::isCapabilitiesMatchedCodecConfiguration(
+    std::vector<CodecSpecificConfigurationLtv>& codec_cfg,
+    std::vector<CodecSpecificCapabilitiesLtv> codec_capabilities) {
+  // Convert all codec_cfg into a map of tags -> correct data
+  std::map<CodecSpecificConfigurationLtv::Tag, CodecSpecificConfigurationLtv>
+      cfg_tag_map;
+  for (auto codec_cfg_data : codec_cfg)
+    cfg_tag_map[codec_cfg_data.getTag()] = codec_cfg_data;
+
+  for (auto& codec_capability : codec_capabilities) {
+    auto cfg = cfg_tag_map.find(cap_to_cfg_tag_map[codec_capability.getTag()]);
+    // Cannot find tag for the capability:
+    if (cfg == cfg_tag_map.end()) return false;
+
+    // Matching logic for sampling frequency
+    if (codec_capability.getTag() ==
+        CodecSpecificCapabilitiesLtv::Tag::supportedSamplingFrequencies) {
+      if (!isMatchedSamplingFreq(
+              cfg->second
+                  .get<CodecSpecificConfigurationLtv::Tag::samplingFrequency>(),
+              codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
+                                       supportedSamplingFrequencies>()))
+        return false;
+    } else if (codec_capability.getTag() ==
+               CodecSpecificCapabilitiesLtv::Tag::supportedFrameDurations) {
+      if (!isMatchedFrameDuration(
+              cfg->second
+                  .get<CodecSpecificConfigurationLtv::Tag::frameDuration>(),
+              codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
+                                       supportedFrameDurations>()))
+        return false;
+    } else if (codec_capability.getTag() ==
+               CodecSpecificCapabilitiesLtv::Tag::supportedAudioChannelCounts) {
+      if (!isMatchedAudioChannel(
+              cfg->second.get<
+                  CodecSpecificConfigurationLtv::Tag::audioChannelAllocation>(),
+              codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
+                                       supportedAudioChannelCounts>()))
+        return false;
+    } else if (codec_capability.getTag() == CodecSpecificCapabilitiesLtv::Tag::
+                                                supportedMaxCodecFramesPerSDU) {
+      if (!isMatchedCodecFramesPerSDU(
+              cfg->second.get<
+                  CodecSpecificConfigurationLtv::Tag::codecFrameBlocksPerSDU>(),
+              codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
+                                       supportedMaxCodecFramesPerSDU>()))
+        return false;
+    } else if (codec_capability.getTag() == CodecSpecificCapabilitiesLtv::Tag::
+                                                supportedOctetsPerCodecFrame) {
+      if (!isMatchedOctetsPerCodecFrame(
+              cfg->second.get<
+                  CodecSpecificConfigurationLtv::Tag::octetsPerCodecFrame>(),
+              codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
+                                       supportedOctetsPerCodecFrame>()))
+        return false;
+    }
+  }
+
+  return true;
+}
+
+bool LeAudioOffloadAudioProvider::isMatchedAseConfiguration(
+    LeAudioAseConfiguration setting_cfg,
+    LeAudioAseConfiguration requirement_cfg) {
+  // Check matching for codec configuration <=> requirement ASE codec
+  // Also match if no CodecId requirement
+  if (requirement_cfg.codecId.has_value()) {
+    if (!setting_cfg.codecId.has_value()) return false;
+    if (!isMatchedValidCodec(setting_cfg.codecId.value(),
+                             requirement_cfg.codecId.value()))
+      return false;
+  }
+
+  if (setting_cfg.targetLatency != requirement_cfg.targetLatency) return false;
+  // Ignore PHY requirement
+
+  // Check all codec configuration
+  std::map<CodecSpecificConfigurationLtv::Tag, CodecSpecificConfigurationLtv>
+      cfg_tag_map;
+  for (auto cfg : setting_cfg.codecConfiguration)
+    cfg_tag_map[cfg.getTag()] = cfg;
+
+  for (auto requirement_cfg : requirement_cfg.codecConfiguration) {
+    // Directly compare CodecSpecificConfigurationLtv
+    auto cfg = cfg_tag_map.find(requirement_cfg.getTag());
+    if (cfg == cfg_tag_map.end()) return false;
+
+    if (cfg->second != requirement_cfg) return false;
+  }
+  // Ignore vendor configuration and metadata requirement
+
+  return true;
+}
+
+bool LeAudioOffloadAudioProvider::isMatchedBISConfiguration(
+    LeAudioBisConfiguration bis_cfg,
+    const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities) {
+  if (!isMatchedValidCodec(bis_cfg.codecId, capabilities.codecId)) return false;
+  if (!isCapabilitiesMatchedCodecConfiguration(
+          bis_cfg.codecConfiguration, capabilities.codecSpecificCapabilities))
+    return false;
+  return true;
+}
+
+void LeAudioOffloadAudioProvider::filterCapabilitiesAseDirectionConfiguration(
+    std::vector<std::optional<AseDirectionConfiguration>>&
+        direction_configurations,
+    const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities,
+    std::vector<std::optional<AseDirectionConfiguration>>&
+        valid_direction_configurations) {
+  for (auto direction_configuration : direction_configurations) {
+    if (!direction_configuration.has_value()) continue;
+    if (!direction_configuration.value().aseConfiguration.codecId.has_value())
+      continue;
+    if (!isMatchedValidCodec(
+            direction_configuration.value().aseConfiguration.codecId.value(),
+            capabilities.codecId))
+      continue;
+    // Check matching for codec configuration <=> codec capabilities
+    if (!isCapabilitiesMatchedCodecConfiguration(
+            direction_configuration.value().aseConfiguration.codecConfiguration,
+            capabilities.codecSpecificCapabilities))
+      continue;
+    valid_direction_configurations.push_back(direction_configuration);
+  }
+}
+
+void LeAudioOffloadAudioProvider::filterRequirementAseDirectionConfiguration(
+    std::vector<std::optional<AseDirectionConfiguration>>&
+        direction_configurations,
+    const std::optional<std::vector<std::optional<AseDirectionRequirement>>>&
+        requirements,
+    std::vector<std::optional<AseDirectionConfiguration>>&
+        valid_direction_configurations) {
+  for (auto direction_configuration : direction_configurations) {
+    if (!requirements.has_value()) {
+      // If there's no requirement, all are valid
+      valid_direction_configurations.push_back(direction_configuration);
+      continue;
+    }
+    if (!direction_configuration.has_value()) continue;
+
+    for (auto& requirement : requirements.value()) {
+      if (!requirement.has_value()) continue;
+      if (!isMatchedAseConfiguration(
+              direction_configuration.value().aseConfiguration,
+              requirement.value().aseConfiguration))
+        continue;
+      // Valid if match any requirement.
+      valid_direction_configurations.push_back(direction_configuration);
+      break;
+    }
+  }
+}
+
+/* Get a new LeAudioAseConfigurationSetting by matching a setting with a
+ * capabilities. The new setting will have a filtered list of
+ * AseDirectionConfiguration that matched the capabilities */
+std::optional<LeAudioAseConfigurationSetting>
+LeAudioOffloadAudioProvider::getCapabilitiesMatchedAseConfigurationSettings(
+    IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting,
+    const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities,
+    uint8_t direction) {
+  // Try to match context in metadata.
+  if (!isCapabilitiesMatchedContext(setting.audioContext, capabilities))
+    return std::nullopt;
+
+  // Get a list of all matched AseDirectionConfiguration
+  // for the input direction
+  std::vector<std::optional<AseDirectionConfiguration>>*
+      direction_configuration = nullptr;
+  if (direction == kLeAudioDirectionSink) {
+    if (!setting.sinkAseConfiguration.has_value()) return std::nullopt;
+    direction_configuration = &setting.sinkAseConfiguration.value();
+  } else {
+    if (!setting.sourceAseConfiguration.has_value()) return std::nullopt;
+    direction_configuration = &setting.sourceAseConfiguration.value();
+  }
+  std::vector<std::optional<AseDirectionConfiguration>>
+      valid_direction_configuration;
+  filterCapabilitiesAseDirectionConfiguration(
+      *direction_configuration, capabilities, valid_direction_configuration);
+  if (valid_direction_configuration.empty()) return std::nullopt;
+
+  // Create a new LeAudioAseConfigurationSetting and return
+  LeAudioAseConfigurationSetting filtered_setting;
+  filtered_setting.audioContext = setting.audioContext;
+  filtered_setting.packing = setting.packing;
+  if (direction == kLeAudioDirectionSink) {
+    filtered_setting.sinkAseConfiguration = valid_direction_configuration;
+  } else {
+    filtered_setting.sourceAseConfiguration = valid_direction_configuration;
+  }
+  filtered_setting.flags = setting.flags;
+
+  return filtered_setting;
+}
+
+/* Get a new LeAudioAseConfigurationSetting by matching a setting with a
+ * requirement. The new setting will have a filtered list of
+ * AseDirectionConfiguration that matched the requirement */
+std::optional<LeAudioAseConfigurationSetting>
+LeAudioOffloadAudioProvider::getRequirementMatchedAseConfigurationSettings(
+    IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting,
+    const IBluetoothAudioProvider::LeAudioConfigurationRequirement&
+        requirement) {
+  // Try to match context in metadata.
+  if (setting.audioContext != requirement.audioContext) return std::nullopt;
+
+  // Check requirement for the correct direction
+  const std::optional<std::vector<std::optional<AseDirectionRequirement>>>*
+      direction_requirement;
+  std::vector<std::optional<AseDirectionConfiguration>>*
+      direction_configuration;
+  if (setting.sinkAseConfiguration.has_value()) {
+    direction_configuration = &setting.sinkAseConfiguration.value();
+    direction_requirement = &requirement.sinkAseRequirement;
+  } else {
+    direction_configuration = &setting.sourceAseConfiguration.value();
+    direction_requirement = &requirement.sourceAseRequirement;
+  }
+
+  std::vector<std::optional<AseDirectionConfiguration>>
+      valid_direction_configuration;
+  filterRequirementAseDirectionConfiguration(*direction_configuration,
+                                             *direction_requirement,
+                                             valid_direction_configuration);
+  if (valid_direction_configuration.empty()) return std::nullopt;
+
+  // Create a new LeAudioAseConfigurationSetting and return
+  LeAudioAseConfigurationSetting filtered_setting;
+  filtered_setting.audioContext = setting.audioContext;
+  filtered_setting.packing = setting.packing;
+  if (setting.sinkAseConfiguration.has_value())
+    filtered_setting.sinkAseConfiguration = valid_direction_configuration;
+  else
+    filtered_setting.sourceAseConfiguration = valid_direction_configuration;
+  filtered_setting.flags = setting.flags;
+
+  return filtered_setting;
+}
+
+ndk::ScopedAStatus LeAudioOffloadAudioProvider::getLeAudioAseConfiguration(
+    const std::optional<std::vector<
+        std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>>&
+        in_remoteSinkAudioCapabilities,
+    const std::optional<std::vector<
+        std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>>&
+        in_remoteSourceAudioCapabilities,
+    const std::vector<IBluetoothAudioProvider::LeAudioConfigurationRequirement>&
+        in_requirements,
+    std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>*
+        _aidl_return) {
+  // Get all configuration settings
+  std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
+      ase_configuration_settings =
+          BluetoothAudioCodecs::GetLeAudioAseConfigurationSettings();
+
+  // Currently won't handle case where both sink and source capabilities
+  // are passed in. Only handle one of them.
+  const std::optional<std::vector<
+      std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>>*
+      in_remoteAudioCapabilities;
+  uint8_t direction = 0;
+  if (in_remoteSinkAudioCapabilities.has_value()) {
+    direction = kLeAudioDirectionSink;
+    in_remoteAudioCapabilities = &in_remoteSinkAudioCapabilities;
+  } else {
+    direction = kLeAudioDirectionSource;
+    in_remoteAudioCapabilities = &in_remoteSourceAudioCapabilities;
+  }
+
+  std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
+      capability_matched_ase_configuration_settings;
+  // Matching with remote capabilities
+  for (auto& setting : ase_configuration_settings) {
+    for (auto& capability : in_remoteAudioCapabilities->value()) {
+      if (!capability.has_value()) continue;
+      auto filtered_ase_configuration_setting =
+          getCapabilitiesMatchedAseConfigurationSettings(
+              setting, capability.value(), direction);
+      if (filtered_ase_configuration_setting.has_value()) {
+        capability_matched_ase_configuration_settings.push_back(
+            filtered_ase_configuration_setting.value());
+      }
+    }
+  }
+
+  // Matching with requirements
+  std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting> result;
+  for (auto& setting : capability_matched_ase_configuration_settings) {
+    for (auto& requirement : in_requirements) {
+      auto filtered_ase_configuration_setting =
+          getRequirementMatchedAseConfigurationSettings(setting, requirement);
+      if (filtered_ase_configuration_setting.has_value()) {
+        result.push_back(filtered_ase_configuration_setting.value());
+      }
+    }
+  }
+
+  *_aidl_return = result;
+  return ndk::ScopedAStatus::ok();
+};
+
+bool LeAudioOffloadAudioProvider::isMatchedQosRequirement(
+    LeAudioAseQosConfiguration setting_qos,
+    AseQosDirectionRequirement requirement_qos) {
+  if (setting_qos.retransmissionNum !=
+      requirement_qos.preferredRetransmissionNum)
+    return false;
+  if (setting_qos.maxTransportLatencyMs > requirement_qos.maxTransportLatencyMs)
+    return false;
+  // Ignore other parameters, as they are not populated in the setting_qos
+  return true;
+}
+
+ndk::ScopedAStatus LeAudioOffloadAudioProvider::getLeAudioAseQosConfiguration(
+    const IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement&
+        in_qosRequirement,
+    IBluetoothAudioProvider::LeAudioAseQosConfigurationPair* _aidl_return) {
+  IBluetoothAudioProvider::LeAudioAseQosConfigurationPair result;
+  // Get all configuration settings
+  std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
+      ase_configuration_settings =
+          BluetoothAudioCodecs::GetLeAudioAseConfigurationSettings();
+
+  // Direction QoS matching
+  // Only handle one direction input case
+  uint8_t direction = 0;
+  std::optional<AseQosDirectionRequirement> direction_qos_requirement =
+      std::nullopt;
+  if (in_qosRequirement.sinkAseQosRequirement.has_value()) {
+    direction_qos_requirement = in_qosRequirement.sinkAseQosRequirement.value();
+    direction = kLeAudioDirectionSink;
+  } else if (in_qosRequirement.sourceAseQosRequirement.has_value()) {
+    direction_qos_requirement =
+        in_qosRequirement.sourceAseQosRequirement.value();
+    direction = kLeAudioDirectionSource;
+  }
+
+  for (auto& setting : ase_configuration_settings) {
+    // Context matching
+    if (setting.audioContext != in_qosRequirement.audioContext) continue;
+
+    // Match configuration flags
+    // Currently configuration flags are not populated, ignore.
+
+    // Get a list of all matched AseDirectionConfiguration
+    // for the input direction
+    std::vector<std::optional<AseDirectionConfiguration>>*
+        direction_configuration = nullptr;
+    if (direction == kLeAudioDirectionSink) {
+      if (!setting.sinkAseConfiguration.has_value()) continue;
+      direction_configuration = &setting.sinkAseConfiguration.value();
+    } else {
+      if (!setting.sourceAseConfiguration.has_value()) continue;
+      direction_configuration = &setting.sourceAseConfiguration.value();
+    }
+
+    for (auto cfg : *direction_configuration) {
+      if (!cfg.has_value()) continue;
+      // If no requirement, return the first QoS
+      if (!direction_qos_requirement.has_value()) {
+        result.sinkQosConfiguration = cfg.value().qosConfiguration;
+        result.sourceQosConfiguration = cfg.value().qosConfiguration;
+        *_aidl_return = result;
+        return ndk::ScopedAStatus::ok();
+      }
+
+      // If has requirement, return the first matched QoS
+      // Try to match the ASE configuration
+      // and QoS with requirement
+      if (!cfg.value().qosConfiguration.has_value()) continue;
+      if (isMatchedAseConfiguration(
+              cfg.value().aseConfiguration,
+              direction_qos_requirement.value().aseConfiguration) &&
+          isMatchedQosRequirement(cfg.value().qosConfiguration.value(),
+                                  direction_qos_requirement.value())) {
+        if (direction == kLeAudioDirectionSink)
+          result.sinkQosConfiguration = cfg.value().qosConfiguration;
+        else
+          result.sourceQosConfiguration = cfg.value().qosConfiguration;
+        *_aidl_return = result;
+        return ndk::ScopedAStatus::ok();
+      }
+    }
+  }
+
+  // No match, return empty QoS
+  *_aidl_return = result;
+  return ndk::ScopedAStatus::ok();
+};
+
+ndk::ScopedAStatus LeAudioOffloadAudioProvider::onSinkAseMetadataChanged(
+    IBluetoothAudioProvider::AseState in_state, int32_t /*in_cigId*/,
+    int32_t /*in_cisId*/,
+    const std::optional<std::vector<std::optional<MetadataLtv>>>& in_metadata) {
+  (void)in_state;
+  (void)in_metadata;
+  return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+};
+
+ndk::ScopedAStatus LeAudioOffloadAudioProvider::onSourceAseMetadataChanged(
+    IBluetoothAudioProvider::AseState in_state, int32_t /*in_cigId*/,
+    int32_t /*in_cisId*/,
+    const std::optional<std::vector<std::optional<MetadataLtv>>>& in_metadata) {
+  (void)in_state;
+  (void)in_metadata;
+  return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+};
+
+void LeAudioOffloadAudioProvider::getBroadcastSettings() {
+  if (!broadcast_settings.empty()) return;
+
+  LOG(INFO) << __func__ << ": Loading broadcast settings from provider info";
+
+  std::vector<CodecInfo> db_codec_info =
+      BluetoothAudioCodecs::GetLeAudioOffloadCodecInfo(
+          SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH);
+  broadcast_settings.clear();
+  CodecSpecificConfigurationLtv::AudioChannelAllocation default_allocation;
+  default_allocation.bitmask =
+      CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_CENTER;
+
+  for (auto& codec_info : db_codec_info) {
+    if (codec_info.transport.getTag() != CodecInfo::Transport::leAudio)
+      continue;
+    auto& transport = codec_info.transport.get<CodecInfo::Transport::leAudio>();
+    LeAudioBroadcastConfigurationSetting setting;
+    // Default setting
+    setting.numBis = 1;
+    setting.phy = {Phy::TWO_M};
+    // Populate BIS configuration info using codec_info
+    LeAudioBisConfiguration bis_cfg;
+    bis_cfg.codecId = codec_info.id;
+
+    CodecSpecificConfigurationLtv::OctetsPerCodecFrame octets;
+    octets.value = transport.bitdepth[0];
+
+    bis_cfg.codecConfiguration = {
+        sampling_freq_map[transport.samplingFrequencyHz[0]], octets,
+        frame_duration_map[transport.frameDurationUs[0]], default_allocation};
+
+    // Add information to structure
+    IBluetoothAudioProvider::LeAudioSubgroupBisConfiguration sub_bis_cfg;
+    sub_bis_cfg.numBis = 1;
+    sub_bis_cfg.bisConfiguration = bis_cfg;
+    IBluetoothAudioProvider::LeAudioBroadcastSubgroupConfiguration sub_cfg;
+    sub_cfg.bisConfigurations = {sub_bis_cfg};
+    setting.subgroupsConfigurations = {sub_cfg};
+
+    broadcast_settings.push_back(setting);
+  }
+
+  LOG(INFO) << __func__
+            << ": Done loading broadcast settings from provider info";
+}
+
+/* Get a new LeAudioAseConfigurationSetting by matching a setting with a
+ * capabilities. The new setting will have a filtered list of
+ * AseDirectionConfiguration that matched the capabilities */
+std::optional<LeAudioBroadcastConfigurationSetting>
+LeAudioOffloadAudioProvider::
+    getCapabilitiesMatchedBroadcastConfigurationSettings(
+        LeAudioBroadcastConfigurationSetting& setting,
+        const IBluetoothAudioProvider::LeAudioDeviceCapabilities&
+            capabilities) {
+  std::vector<IBluetoothAudioProvider::LeAudioBroadcastSubgroupConfiguration>
+      filter_subgroup;
+  for (auto& sub_cfg : setting.subgroupsConfigurations) {
+    std::vector<IBluetoothAudioProvider::LeAudioSubgroupBisConfiguration>
+        filtered_bis_cfg;
+    for (auto& bis_cfg : sub_cfg.bisConfigurations)
+      if (isMatchedBISConfiguration(bis_cfg.bisConfiguration, capabilities)) {
+        filtered_bis_cfg.push_back(bis_cfg);
+      }
+    if (!filtered_bis_cfg.empty()) {
+      IBluetoothAudioProvider::LeAudioBroadcastSubgroupConfiguration
+          subgroup_cfg;
+      subgroup_cfg.bisConfigurations = filtered_bis_cfg;
+      filter_subgroup.push_back(subgroup_cfg);
+    }
+  }
+  if (filter_subgroup.empty()) return std::nullopt;
+
+  // Create a new LeAudioAseConfigurationSetting and return
+  LeAudioBroadcastConfigurationSetting filtered_setting(setting);
+  filtered_setting.subgroupsConfigurations = filter_subgroup;
+
+  return filtered_setting;
+}
+
+ndk::ScopedAStatus
+LeAudioOffloadAudioProvider::getLeAudioBroadcastConfiguration(
+    const std::optional<std::vector<
+        std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>>&
+        in_remoteSinkAudioCapabilities,
+    const IBluetoothAudioProvider::LeAudioBroadcastConfigurationRequirement&
+        in_requirement,
+    LeAudioBroadcastConfigurationSetting* _aidl_return) {
+  getBroadcastSettings();
+  _aidl_return = nullptr;
+
+  // Match and filter capability
+  std::vector<LeAudioBroadcastConfigurationSetting> filtered_settings;
+  if (!in_remoteSinkAudioCapabilities.has_value()) {
+    LOG(WARNING) << __func__ << ": Empty capability";
+    return ndk::ScopedAStatus::ok();
+  }
+  for (auto& setting : broadcast_settings) {
+    for (auto& capability : in_remoteSinkAudioCapabilities.value()) {
+      if (!capability.has_value()) continue;
+      auto filtered_setting =
+          getCapabilitiesMatchedBroadcastConfigurationSettings(
+              setting, capability.value());
+      if (filtered_setting.has_value())
+        filtered_settings.push_back(filtered_setting.value());
+    }
+  }
+
+  if (filtered_settings.empty()) {
+    LOG(WARNING) << __func__ << ": Cannot match any remote capability";
+    return ndk::ScopedAStatus::ok();
+  }
+
+  // Match and return the first matched requirement
+  if (in_requirement.subgroupConfigurationRequirements.empty()) {
+    LOG(INFO) << __func__ << ": Empty requirement";
+    *_aidl_return = filtered_settings[0];
+    return ndk::ScopedAStatus::ok();
+  }
+
+  for (auto& setting : filtered_settings) {
+    // Further filter out bis configuration
+    LeAudioBroadcastConfigurationSetting filtered_setting(setting);
+    filtered_setting.subgroupsConfigurations.clear();
+    for (auto& sub_cfg : setting.subgroupsConfigurations) {
+      bool isMatched = false;
+      for (auto& sub_req : in_requirement.subgroupConfigurationRequirements) {
+        // Matching number of BIS
+        if (sub_req.bisNumPerSubgroup != sub_cfg.bisConfigurations.size())
+          continue;
+        // Currently will ignore quality and context hint.
+        isMatched = true;
+        break;
+      }
+      if (isMatched)
+        filtered_setting.subgroupsConfigurations.push_back(sub_cfg);
+    }
+    // Return the first match
+    if (!filtered_setting.subgroupsConfigurations.empty()) {
+      LOG(INFO) << __func__ << ": Matched requirement";
+      *_aidl_return = filtered_setting;
+      return ndk::ScopedAStatus::ok();
+    }
+  }
+
+  LOG(WARNING) << __func__ << ": Cannot match any requirement";
+  return ndk::ScopedAStatus::ok();
+};
 
 }  // namespace audio
 }  // namespace bluetooth
diff --git a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
index 614c794..2785e7f 100644
--- a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
+++ b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
@@ -16,7 +16,12 @@
 
 #pragma once
 
+#include <map>
+
 #include "BluetoothAudioProvider.h"
+#include "aidl/android/hardware/bluetooth/audio/LeAudioAseConfiguration.h"
+#include "aidl/android/hardware/bluetooth/audio/MetadataLtv.h"
+#include "aidl/android/hardware/bluetooth/audio/SessionType.h"
 
 namespace aidl {
 namespace android {
@@ -24,6 +29,19 @@
 namespace bluetooth {
 namespace audio {
 
+using LeAudioAseConfigurationSetting =
+    IBluetoothAudioProvider::LeAudioAseConfigurationSetting;
+using AseDirectionRequirement = IBluetoothAudioProvider::
+    LeAudioConfigurationRequirement::AseDirectionRequirement;
+using AseDirectionConfiguration = IBluetoothAudioProvider::
+    LeAudioAseConfigurationSetting::AseDirectionConfiguration;
+using AseQosDirectionRequirement = IBluetoothAudioProvider::
+    LeAudioAseQosConfigurationRequirement::AseQosDirectionRequirement;
+using LeAudioAseQosConfiguration =
+    IBluetoothAudioProvider::LeAudioAseQosConfiguration;
+using LeAudioBroadcastConfigurationSetting =
+    IBluetoothAudioProvider::LeAudioBroadcastConfigurationSetting;
+
 class LeAudioOffloadAudioProvider : public BluetoothAudioProvider {
  public:
   LeAudioOffloadAudioProvider();
@@ -33,11 +51,112 @@
   ndk::ScopedAStatus startSession(
       const std::shared_ptr<IBluetoothAudioPort>& host_if,
       const AudioConfiguration& audio_config,
-      const std::vector<LatencyMode>& latency_modes,
-      DataMQDesc* _aidl_return);
+      const std::vector<LatencyMode>& latency_modes, DataMQDesc* _aidl_return);
+  ndk::ScopedAStatus setCodecPriority(const CodecId& in_codecId,
+                                      int32_t in_priority) override;
+  ndk::ScopedAStatus getLeAudioAseConfiguration(
+      const std::optional<std::vector<
+          std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>>&
+          in_remoteSinkAudioCapabilities,
+      const std::optional<std::vector<
+          std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>>&
+          in_remoteSourceAudioCapabilities,
+      const std::vector<
+          IBluetoothAudioProvider::LeAudioConfigurationRequirement>&
+          in_requirements,
+      std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>*
+          _aidl_return) override;
+  ndk::ScopedAStatus getLeAudioAseQosConfiguration(
+      const IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement&
+          in_qosRequirement,
+      IBluetoothAudioProvider::LeAudioAseQosConfigurationPair* _aidl_return)
+      override;
+  ndk::ScopedAStatus onSourceAseMetadataChanged(
+      IBluetoothAudioProvider::AseState in_state, int32_t in_cigId,
+      int32_t in_cisId,
+      const std::optional<std::vector<std::optional<MetadataLtv>>>& in_metadata)
+      override;
+  ndk::ScopedAStatus onSinkAseMetadataChanged(
+      IBluetoothAudioProvider::AseState in_state, int32_t in_cigId,
+      int32_t in_cisId,
+      const std::optional<std::vector<std::optional<MetadataLtv>>>& in_metadata)
+      override;
+  ndk::ScopedAStatus getLeAudioBroadcastConfiguration(
+      const std::optional<std::vector<
+          std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>>&
+          in_remoteSinkAudioCapabilities,
+      const IBluetoothAudioProvider::LeAudioBroadcastConfigurationRequirement&
+          in_requirement,
+      LeAudioBroadcastConfigurationSetting* _aidl_return) override;
 
  private:
   ndk::ScopedAStatus onSessionReady(DataMQDesc* _aidl_return) override;
+  std::map<CodecId, uint32_t> codec_priority_map_;
+  std::vector<LeAudioBroadcastConfigurationSetting> broadcast_settings;
+
+  // Private matching function definitions
+  bool isMatchedValidCodec(CodecId cfg_codec, CodecId req_codec);
+  bool isCapabilitiesMatchedContext(
+      AudioContext setting_context,
+      const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities);
+  bool isMatchedSamplingFreq(
+      CodecSpecificConfigurationLtv::SamplingFrequency& cfg_freq,
+      CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies&
+          capability_freq);
+  bool isMatchedFrameDuration(
+      CodecSpecificConfigurationLtv::FrameDuration& cfg_fduration,
+      CodecSpecificCapabilitiesLtv::SupportedFrameDurations&
+          capability_fduration);
+  bool isMatchedAudioChannel(
+      CodecSpecificConfigurationLtv::AudioChannelAllocation& cfg_channel,
+      CodecSpecificCapabilitiesLtv::SupportedAudioChannelCounts&
+          capability_channel);
+  bool isMatchedCodecFramesPerSDU(
+      CodecSpecificConfigurationLtv::CodecFrameBlocksPerSDU& cfg_frame_sdu,
+      CodecSpecificCapabilitiesLtv::SupportedMaxCodecFramesPerSDU&
+          capability_frame_sdu);
+  bool isMatchedOctetsPerCodecFrame(
+      CodecSpecificConfigurationLtv::OctetsPerCodecFrame& cfg_octets,
+      CodecSpecificCapabilitiesLtv::SupportedOctetsPerCodecFrame&
+          capability_octets);
+  bool isCapabilitiesMatchedCodecConfiguration(
+      std::vector<CodecSpecificConfigurationLtv>& codec_cfg,
+      std::vector<CodecSpecificCapabilitiesLtv> codec_capabilities);
+  bool isMatchedAseConfiguration(LeAudioAseConfiguration setting_cfg,
+                                 LeAudioAseConfiguration requirement_cfg);
+  bool isMatchedBISConfiguration(
+      LeAudioBisConfiguration bis_cfg,
+      const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities);
+  void filterCapabilitiesAseDirectionConfiguration(
+      std::vector<std::optional<AseDirectionConfiguration>>&
+          direction_configurations,
+      const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities,
+      std::vector<std::optional<AseDirectionConfiguration>>&
+          valid_direction_configurations);
+  void filterRequirementAseDirectionConfiguration(
+      std::vector<std::optional<AseDirectionConfiguration>>&
+          direction_configurations,
+      const std::optional<std::vector<std::optional<AseDirectionRequirement>>>&
+          requirements,
+      std::vector<std::optional<AseDirectionConfiguration>>&
+          valid_direction_configurations);
+  std::optional<LeAudioAseConfigurationSetting>
+  getCapabilitiesMatchedAseConfigurationSettings(
+      IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting,
+      const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities,
+      uint8_t direction);
+  std::optional<LeAudioAseConfigurationSetting>
+  getRequirementMatchedAseConfigurationSettings(
+      IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting,
+      const IBluetoothAudioProvider::LeAudioConfigurationRequirement&
+          requirement);
+  bool isMatchedQosRequirement(LeAudioAseQosConfiguration setting_qos,
+                               AseQosDirectionRequirement requirement_qos);
+  std::optional<LeAudioBroadcastConfigurationSetting>
+  getCapabilitiesMatchedBroadcastConfigurationSettings(
+      LeAudioBroadcastConfigurationSetting& setting,
+      const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities);
+  void getBroadcastSettings();
 };
 
 class LeAudioOffloadOutputAudioProvider : public LeAudioOffloadAudioProvider {
diff --git a/bluetooth/audio/aidl/default/bluetooth_audio.xml b/bluetooth/audio/aidl/default/bluetooth_audio.xml
index c0bc55e..3561dd1 100644
--- a/bluetooth/audio/aidl/default/bluetooth_audio.xml
+++ b/bluetooth/audio/aidl/default/bluetooth_audio.xml
@@ -1,7 +1,7 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.bluetooth.audio</name>
-        <version>3</version>
+        <version>4</version>
         <fqname>IBluetoothAudioProviderFactory/default</fqname>
     </hal>
 </manifest>
diff --git a/bluetooth/audio/aidl/vts/Android.bp b/bluetooth/audio/aidl/vts/Android.bp
index fa85fa8..884062a 100644
--- a/bluetooth/audio/aidl/vts/Android.bp
+++ b/bluetooth/audio/aidl/vts/Android.bp
@@ -10,17 +10,17 @@
 cc_test {
     name: "VtsHalBluetoothAudioTargetTest",
     defaults: [
+        "latest_android_hardware_audio_common_ndk_static",
+        "latest_android_hardware_bluetooth_audio_ndk_static",
+        "latest_android_media_audio_common_types_ndk_static",
         "VtsHalTargetTestDefaults",
         "use_libaidlvintf_gtest_helper_static",
     ],
     tidy_timeout_srcs: ["VtsHalBluetoothAudioTargetTest.cpp"],
     srcs: ["VtsHalBluetoothAudioTargetTest.cpp"],
     static_libs: [
-        "android.hardware.audio.common-V2-ndk",
-        "android.hardware.bluetooth.audio-V3-ndk",
         "android.hardware.common-V2-ndk",
         "android.hardware.common.fmq-V1-ndk",
-        "android.media.audio.common.types-V2-ndk",
     ],
     shared_libs: [
         "libbase",
diff --git a/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp b/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
index 858fa38..7b98634 100644
--- a/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
+++ b/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
@@ -33,6 +33,11 @@
 
 using aidl::android::hardware::audio::common::SinkMetadata;
 using aidl::android::hardware::audio::common::SourceMetadata;
+using aidl::android::hardware::bluetooth::audio::A2dpConfiguration;
+using aidl::android::hardware::bluetooth::audio::A2dpConfigurationHint;
+using aidl::android::hardware::bluetooth::audio::A2dpRemoteCapabilities;
+using aidl::android::hardware::bluetooth::audio::A2dpStatus;
+using aidl::android::hardware::bluetooth::audio::A2dpStreamConfiguration;
 using aidl::android::hardware::bluetooth::audio::AacCapabilities;
 using aidl::android::hardware::bluetooth::audio::AacConfiguration;
 using aidl::android::hardware::bluetooth::audio::AptxAdaptiveLeCapabilities;
@@ -41,12 +46,19 @@
 using aidl::android::hardware::bluetooth::audio::AptxConfiguration;
 using aidl::android::hardware::bluetooth::audio::AudioCapabilities;
 using aidl::android::hardware::bluetooth::audio::AudioConfiguration;
+using aidl::android::hardware::bluetooth::audio::AudioContext;
 using aidl::android::hardware::bluetooth::audio::BnBluetoothAudioPort;
 using aidl::android::hardware::bluetooth::audio::BroadcastCapability;
 using aidl::android::hardware::bluetooth::audio::ChannelMode;
 using aidl::android::hardware::bluetooth::audio::CodecCapabilities;
 using aidl::android::hardware::bluetooth::audio::CodecConfiguration;
+using aidl::android::hardware::bluetooth::audio::CodecId;
+using aidl::android::hardware::bluetooth::audio::CodecInfo;
+using aidl::android::hardware::bluetooth::audio::CodecParameters;
+using aidl::android::hardware::bluetooth::audio::CodecSpecificCapabilitiesLtv;
+using aidl::android::hardware::bluetooth::audio::CodecSpecificConfigurationLtv;
 using aidl::android::hardware::bluetooth::audio::CodecType;
+using aidl::android::hardware::bluetooth::audio::HfpConfiguration;
 using aidl::android::hardware::bluetooth::audio::IBluetoothAudioPort;
 using aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider;
 using aidl::android::hardware::bluetooth::audio::IBluetoothAudioProviderFactory;
@@ -55,11 +67,13 @@
 using aidl::android::hardware::bluetooth::audio::Lc3Configuration;
 using aidl::android::hardware::bluetooth::audio::LdacCapabilities;
 using aidl::android::hardware::bluetooth::audio::LdacConfiguration;
+using aidl::android::hardware::bluetooth::audio::LeAudioAseConfiguration;
 using aidl::android::hardware::bluetooth::audio::LeAudioBroadcastConfiguration;
 using aidl::android::hardware::bluetooth::audio::
     LeAudioCodecCapabilitiesSetting;
 using aidl::android::hardware::bluetooth::audio::LeAudioCodecConfiguration;
 using aidl::android::hardware::bluetooth::audio::LeAudioConfiguration;
+using aidl::android::hardware::bluetooth::audio::MetadataLtv;
 using aidl::android::hardware::bluetooth::audio::OpusCapabilities;
 using aidl::android::hardware::bluetooth::audio::OpusConfiguration;
 using aidl::android::hardware::bluetooth::audio::PcmConfiguration;
@@ -83,6 +97,21 @@
 using DataMQ = AidlMessageQueue<MqDataType, MqDataMode>;
 using DataMQDesc = MQDescriptor<MqDataType, MqDataMode>;
 
+using LeAudioAseConfigurationSetting =
+    IBluetoothAudioProvider::LeAudioAseConfigurationSetting;
+using AseDirectionRequirement = IBluetoothAudioProvider::
+    LeAudioConfigurationRequirement::AseDirectionRequirement;
+using AseDirectionConfiguration = IBluetoothAudioProvider::
+    LeAudioAseConfigurationSetting::AseDirectionConfiguration;
+using AseQosDirectionRequirement = IBluetoothAudioProvider::
+    LeAudioAseQosConfigurationRequirement::AseQosDirectionRequirement;
+using LeAudioAseQosConfiguration =
+    IBluetoothAudioProvider::LeAudioAseQosConfiguration;
+using LeAudioDeviceCapabilities =
+    IBluetoothAudioProvider::LeAudioDeviceCapabilities;
+using LeAudioConfigurationRequirement =
+    IBluetoothAudioProvider::LeAudioConfigurationRequirement;
+
 // Constants
 
 static constexpr int32_t a2dp_sample_rates[] = {0, 44100, 48000, 88200, 96000};
@@ -90,6 +119,23 @@
 static constexpr ChannelMode a2dp_channel_modes[] = {
     ChannelMode::UNKNOWN, ChannelMode::MONO, ChannelMode::STEREO};
 static std::vector<LatencyMode> latency_modes = {LatencyMode::FREE};
+
+enum class BluetoothAudioHalVersion : int32_t {
+  VERSION_UNAVAILABLE = 0,
+  VERSION_2_0,
+  VERSION_2_1,
+  VERSION_AIDL_V1,
+  VERSION_AIDL_V2,
+  VERSION_AIDL_V3,
+  VERSION_AIDL_V4,
+};
+
+// Some valid configs for HFP PCM configuration (software sessions)
+static constexpr int32_t hfp_sample_rates_[] = {8000, 16000, 32000};
+static constexpr int8_t hfp_bits_per_samples_[] = {16};
+static constexpr ChannelMode hfp_channel_modes_[] = {ChannelMode::MONO};
+static constexpr int32_t hfp_data_interval_us_[] = {7500};
+
 // Helpers
 
 template <typename T>
@@ -181,6 +227,12 @@
 
   virtual void TearDown() override { provider_factory_ = nullptr; }
 
+  void GetProviderInfoHelper(const SessionType& session_type) {
+    temp_provider_info_ = std::nullopt;
+    auto aidl_reval =
+        provider_factory_->getProviderInfo(session_type, &temp_provider_info_);
+  }
+
   void GetProviderCapabilitiesHelper(const SessionType& session_type) {
     temp_provider_capabilities_.clear();
     auto aidl_retval = provider_factory_->getProviderCapabilities(
@@ -195,7 +247,8 @@
       case SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH:
       case SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH:
       case SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH:
-      case SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH: {
+      case SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH:
+      case SessionType::HFP_SOFTWARE_ENCODING_DATAPATH: {
         // All software paths are mandatory and must have exact 1
         // "PcmParameters"
         ASSERT_EQ(temp_provider_capabilities_.size(), 1);
@@ -256,7 +309,8 @@
                     AudioCapabilities::leAudioCapabilities);
         }
       } break;
-      case SessionType::A2DP_SOFTWARE_DECODING_DATAPATH: {
+      case SessionType::A2DP_SOFTWARE_DECODING_DATAPATH:
+      case SessionType::HFP_SOFTWARE_DECODING_DATAPATH: {
         if (!temp_provider_capabilities_.empty()) {
           ASSERT_EQ(temp_provider_capabilities_.size(), 1);
           ASSERT_EQ(temp_provider_capabilities_[0].getTag(),
@@ -296,7 +350,10 @@
                   LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
           session_type ==
               SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH ||
-          session_type == SessionType::A2DP_SOFTWARE_DECODING_DATAPATH);
+          session_type == SessionType::A2DP_SOFTWARE_DECODING_DATAPATH ||
+          session_type == SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH ||
+          session_type == SessionType::HFP_SOFTWARE_DECODING_DATAPATH ||
+          session_type == SessionType::HFP_SOFTWARE_ENCODING_DATAPATH);
       ASSERT_EQ(audio_provider_, nullptr);
     }
   }
@@ -555,6 +612,8 @@
   std::shared_ptr<IBluetoothAudioProvider> audio_provider_;
   std::shared_ptr<IBluetoothAudioPort> audio_port_;
   std::vector<AudioCapabilities> temp_provider_capabilities_;
+  std::optional<IBluetoothAudioProviderFactory::ProviderInfo>
+      temp_provider_info_;
 
   // temp storage saves the specified codec capability by
   // GetOffloadCodecCapabilityHelper()
@@ -574,6 +633,37 @@
       SessionType::A2DP_SOFTWARE_DECODING_DATAPATH,
       SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH,
   };
+
+  static constexpr SessionType kAndroidVSessionType[] = {
+      SessionType::HFP_SOFTWARE_ENCODING_DATAPATH,
+      SessionType::HFP_SOFTWARE_DECODING_DATAPATH,
+  };
+
+  BluetoothAudioHalVersion GetProviderFactoryInterfaceVersion() {
+    int32_t aidl_version = 0;
+    if (provider_factory_ == nullptr) {
+      return BluetoothAudioHalVersion::VERSION_UNAVAILABLE;
+    }
+
+    auto aidl_retval = provider_factory_->getInterfaceVersion(&aidl_version);
+    if (!aidl_retval.isOk()) {
+      return BluetoothAudioHalVersion::VERSION_UNAVAILABLE;
+    }
+    switch (aidl_version) {
+      case 1:
+        return BluetoothAudioHalVersion::VERSION_AIDL_V1;
+      case 2:
+        return BluetoothAudioHalVersion::VERSION_AIDL_V2;
+      case 3:
+        return BluetoothAudioHalVersion::VERSION_AIDL_V3;
+      case 4:
+        return BluetoothAudioHalVersion::VERSION_AIDL_V4;
+      default:
+        return BluetoothAudioHalVersion::VERSION_UNAVAILABLE;
+    }
+
+    return BluetoothAudioHalVersion::VERSION_UNAVAILABLE;
+  }
 };
 
 /**
@@ -595,6 +685,802 @@
     EXPECT_TRUE(temp_provider_capabilities_.empty() ||
                 audio_provider_ != nullptr);
   }
+  if (GetProviderFactoryInterfaceVersion() >=
+      BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+    for (auto session_type : kAndroidVSessionType) {
+      GetProviderCapabilitiesHelper(session_type);
+      OpenProviderHelper(session_type);
+      EXPECT_TRUE(temp_provider_capabilities_.empty() ||
+                  audio_provider_ != nullptr);
+    }
+  }
+}
+
+/**
+ * Test that getProviderInfo, when implemented,
+ * returns empty information for session types for
+ * software data paths.
+ */
+TEST_P(BluetoothAudioProviderFactoryAidl, getProviderInfo_invalidSessionTypes) {
+  static constexpr SessionType kInvalidSessionTypes[]{
+      SessionType::UNKNOWN,
+      SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH,
+      SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH,
+      SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH,
+      SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH,
+      SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH,
+      SessionType::A2DP_SOFTWARE_DECODING_DATAPATH,
+  };
+
+  for (auto session_type : kInvalidSessionTypes) {
+    std::optional<IBluetoothAudioProviderFactory::ProviderInfo> provider_info =
+        std::nullopt;
+    auto aidl_retval =
+        provider_factory_->getProviderInfo(session_type, &provider_info);
+    if (!aidl_retval.isOk()) {
+      continue;
+    }
+
+    // If getProviderInfo is supported, the provider info
+    // must be empty for software session types.
+    ASSERT_FALSE(provider_info.has_value());
+  }
+}
+
+/**
+ * Test that getProviderInfo, when implemented,
+ * returns valid information for session types for
+ * a2dp hardware data paths.
+ */
+TEST_P(BluetoothAudioProviderFactoryAidl, getProviderInfo_a2dpSessionTypes) {
+  static constexpr SessionType kA2dpSessionTypes[]{
+      SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
+      SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH,
+  };
+
+  for (auto session_type : kA2dpSessionTypes) {
+    std::optional<IBluetoothAudioProviderFactory::ProviderInfo> provider_info =
+        std::nullopt;
+    auto aidl_retval =
+        provider_factory_->getProviderInfo(session_type, &provider_info);
+    if (!aidl_retval.isOk() || !provider_info.has_value()) {
+      continue;
+    }
+
+    for (auto const& codec_info : provider_info->codecInfos) {
+      // The codec id must not be core.
+      ASSERT_NE(codec_info.id.getTag(), CodecId::core);
+      // The codec info must contain the information
+      // for a2dp transport.
+      ASSERT_EQ(codec_info.transport.getTag(), CodecInfo::Transport::a2dp);
+    }
+  }
+}
+
+/**
+ * Test that getProviderInfo, when implemented,
+ * returns valid information for session types for
+ * le audio hardware data paths.
+ */
+TEST_P(BluetoothAudioProviderFactoryAidl, getProviderInfo_leAudioSessionTypes) {
+  static constexpr SessionType kLeAudioSessionTypes[]{
+      SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
+      SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH,
+      SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
+  };
+
+  for (auto session_type : kLeAudioSessionTypes) {
+    std::optional<IBluetoothAudioProviderFactory::ProviderInfo> provider_info =
+        std::nullopt;
+    auto aidl_retval =
+        provider_factory_->getProviderInfo(session_type, &provider_info);
+    if (!aidl_retval.isOk() || !provider_info.has_value()) {
+      continue;
+    }
+
+    for (auto const& codec_info : provider_info->codecInfos) {
+      // The codec id must not be a2dp.
+      ASSERT_NE(codec_info.id.getTag(), CodecId::a2dp);
+      // The codec info must contain the information
+      // for le audio transport.
+      ASSERT_EQ(codec_info.transport.getTag(), CodecInfo::Transport::leAudio);
+    }
+  }
+}
+
+class BluetoothAudioProviderAidl : public BluetoothAudioProviderFactoryAidl {
+ protected:
+  std::optional<IBluetoothAudioProviderFactory::ProviderInfo>
+      a2dp_encoding_provider_info_{};
+  std::optional<IBluetoothAudioProviderFactory::ProviderInfo>
+      a2dp_decoding_provider_info_{};
+  std::shared_ptr<IBluetoothAudioProvider> a2dp_encoding_provider_{nullptr};
+  std::shared_ptr<IBluetoothAudioProvider> a2dp_decoding_provider_{nullptr};
+
+ public:
+  void SetUp() override {
+    BluetoothAudioProviderFactoryAidl::SetUp();
+    audio_port_ = ndk::SharedRefBase::make<BluetoothAudioPort>();
+
+    (void)provider_factory_->getProviderInfo(
+        SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
+        &a2dp_encoding_provider_info_);
+
+    (void)provider_factory_->getProviderInfo(
+        SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH,
+        &a2dp_decoding_provider_info_);
+
+    (void)provider_factory_->openProvider(
+        SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
+        &a2dp_encoding_provider_);
+
+    (void)provider_factory_->openProvider(
+        SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH,
+        &a2dp_decoding_provider_);
+  }
+};
+
+/**
+ * Calling parseA2dpConfiguration on a session of a different type than
+ * A2DP_HARDWARE_OFFLOAD_(ENCODING|DECODING)_DATAPATH must fail.
+ */
+TEST_P(BluetoothAudioProviderAidl, parseA2dpConfiguration_invalidSessionType) {
+  static constexpr SessionType kInvalidSessionTypes[] = {
+      SessionType::UNKNOWN,
+      SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH,
+      SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH,
+      SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH,
+      SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH,
+      SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
+      SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH,
+      SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH,
+      SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
+      SessionType::A2DP_SOFTWARE_DECODING_DATAPATH,
+  };
+
+  for (auto session_type : kInvalidSessionTypes) {
+    // Open a BluetoothAudioProvider instance of the selected session type.
+    // Skip validation if the provider cannot be opened.
+    std::shared_ptr<IBluetoothAudioProvider> provider{nullptr};
+    (void)provider_factory_->openProvider(session_type, &provider);
+    if (provider == nullptr) {
+      continue;
+    }
+
+    // parseA2dpConfiguration must fail without returning an A2dpStatus.
+    CodecId codec_id(CodecId::A2dp::SBC);
+    CodecParameters codec_parameters;
+    A2dpStatus a2dp_status = A2dpStatus::OK;
+    auto aidl_retval = provider->parseA2dpConfiguration(
+        codec_id, std::vector<uint8_t>{}, &codec_parameters, &a2dp_status);
+    EXPECT_FALSE(aidl_retval.isOk());
+  }
+}
+
+/**
+ * Calling parseA2dpConfiguration with an unknown codec must fail
+ * with the A2dpStatus code INVALID_CODEC_TYPE or NOT_SUPPORTED_CODEC_TYPE.
+ */
+TEST_P(BluetoothAudioProviderAidl,
+       parseA2dpConfiguration_unsupportedCodecType) {
+  CodecId unsupported_core_id(CodecId::Core::CVSD);
+  CodecId unsupported_vendor_id(
+      CodecId::Vendor(0xFCB1, 0x42));  // Google Codec #42
+
+  for (auto& provider : {a2dp_encoding_provider_, a2dp_decoding_provider_}) {
+    if (provider == nullptr) {
+      continue;
+    }
+
+    CodecParameters codec_parameters;
+    A2dpStatus a2dp_status = A2dpStatus::OK;
+    ::ndk::ScopedAStatus aidl_retval;
+
+    // Test with two invalid codec identifiers: vendor or core.
+    aidl_retval = provider->parseA2dpConfiguration(
+        unsupported_core_id, std::vector<uint8_t>{}, &codec_parameters,
+        &a2dp_status);
+    EXPECT_TRUE(!aidl_retval.isOk() ||
+                a2dp_status == A2dpStatus::NOT_SUPPORTED_CODEC_TYPE);
+
+    aidl_retval = provider->parseA2dpConfiguration(
+        unsupported_vendor_id, std::vector<uint8_t>{}, &codec_parameters,
+        &a2dp_status);
+    EXPECT_TRUE(!aidl_retval.isOk() ||
+                a2dp_status == A2dpStatus::NOT_SUPPORTED_CODEC_TYPE);
+  }
+}
+
+/**
+ * Calling parseA2dpConfiguration with a known codec and invalid configuration
+ * must fail with an A2dpStatus code different from INVALID_CODEC_TYPE or
+ * NOT_SUPPORTED_CODEC_TYPE.
+ */
+TEST_P(BluetoothAudioProviderAidl,
+       parseA2dpConfiguration_invalidConfiguration) {
+  for (auto& [provider, provider_info] :
+       {std::pair(a2dp_encoding_provider_, a2dp_encoding_provider_info_),
+        std::pair(a2dp_decoding_provider_, a2dp_decoding_provider_info_)}) {
+    if (provider == nullptr || !provider_info.has_value() ||
+        provider_info->codecInfos.empty()) {
+      continue;
+    }
+
+    CodecParameters codec_parameters;
+    A2dpStatus a2dp_status = A2dpStatus::OK;
+    ::ndk::ScopedAStatus aidl_retval;
+
+    // Test with the first available codec in the provider info for testing.
+    // The test runs with an empty parameters array, anything more specific
+    // would need understanding the codec.
+    aidl_retval = provider->parseA2dpConfiguration(
+        provider_info->codecInfos[0].id, std::vector<uint8_t>{},
+        &codec_parameters, &a2dp_status);
+    ASSERT_TRUE(aidl_retval.isOk());
+    EXPECT_TRUE(a2dp_status != A2dpStatus::OK &&
+                a2dp_status != A2dpStatus::NOT_SUPPORTED_CODEC_TYPE &&
+                a2dp_status != A2dpStatus::INVALID_CODEC_TYPE);
+  }
+}
+
+/**
+ * Calling parseA2dpConfiguration with a known codec and valid parameters
+ * must return with A2dpStatus OK.
+ */
+TEST_P(BluetoothAudioProviderAidl, parseA2dpConfiguration_valid) {
+  for (auto& [provider, provider_info] :
+       {std::pair(a2dp_encoding_provider_, a2dp_encoding_provider_info_),
+        std::pair(a2dp_decoding_provider_, a2dp_decoding_provider_info_)}) {
+    if (provider == nullptr || !provider_info.has_value() ||
+        provider_info->codecInfos.empty()) {
+      continue;
+    }
+
+    CodecParameters codec_parameters;
+    A2dpStatus a2dp_status = A2dpStatus::OK;
+    ::ndk::ScopedAStatus aidl_retval;
+
+    // Test with the first available codec in the provider info for testing.
+    // To get a valid configuration (the capabilities array in the provider
+    // info is not a selection), getA2dpConfiguration is used with the
+    // selected codec parameters as input.
+    auto const& codec_info = provider_info->codecInfos[0];
+    auto transport = codec_info.transport.get<CodecInfo::Transport::a2dp>();
+    A2dpRemoteCapabilities remote_capabilities(/*seid*/ 0, codec_info.id,
+                                               transport.capabilities);
+    std::optional<A2dpConfiguration> configuration;
+    aidl_retval = provider->getA2dpConfiguration(
+        std::vector<A2dpRemoteCapabilities>{remote_capabilities},
+        A2dpConfigurationHint(), &configuration);
+    ASSERT_TRUE(aidl_retval.isOk());
+    ASSERT_TRUE(configuration.has_value());
+
+    aidl_retval = provider->parseA2dpConfiguration(
+        configuration->id, configuration->configuration, &codec_parameters,
+        &a2dp_status);
+    ASSERT_TRUE(aidl_retval.isOk());
+    EXPECT_TRUE(a2dp_status == A2dpStatus::OK);
+    EXPECT_EQ(codec_parameters, configuration->parameters);
+  }
+}
+
+/**
+ * Calling getA2dpConfiguration on a session of a different type than
+ * A2DP_HARDWARE_OFFLOAD_(ENCODING|DECODING)_DATAPATH must fail.
+ */
+TEST_P(BluetoothAudioProviderAidl, getA2dpConfiguration_invalidSessionType) {
+  static constexpr SessionType kInvalidSessionTypes[] = {
+      SessionType::UNKNOWN,
+      SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH,
+      SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH,
+      SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH,
+      SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH,
+      SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
+      SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH,
+      SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH,
+      SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
+      SessionType::A2DP_SOFTWARE_DECODING_DATAPATH,
+  };
+
+  for (auto session_type : kInvalidSessionTypes) {
+    // Open a BluetoothAudioProvider instance of the selected session type.
+    // Skip validation if the provider cannot be opened.
+    std::shared_ptr<IBluetoothAudioProvider> provider{nullptr};
+    auto aidl_retval = provider_factory_->openProvider(session_type, &provider);
+    if (provider == nullptr) {
+      continue;
+    }
+
+    // getA2dpConfiguration must fail without returning a configuration.
+    std::optional<A2dpConfiguration> configuration;
+    aidl_retval =
+        provider->getA2dpConfiguration(std::vector<A2dpRemoteCapabilities>{},
+                                       A2dpConfigurationHint(), &configuration);
+    EXPECT_FALSE(aidl_retval.isOk());
+  }
+}
+
+/**
+ * Calling getA2dpConfiguration with empty or unknown remote capabilities
+ * must return an empty configuration.
+ */
+TEST_P(BluetoothAudioProviderAidl,
+       getA2dpConfiguration_unknownRemoteCapabilities) {
+  for (auto& [provider, provider_info] :
+       {std::pair(a2dp_encoding_provider_, a2dp_encoding_provider_info_),
+        std::pair(a2dp_decoding_provider_, a2dp_decoding_provider_info_)}) {
+    if (provider == nullptr || !provider_info.has_value() ||
+        provider_info->codecInfos.empty()) {
+      continue;
+    }
+
+    std::optional<A2dpConfiguration> configuration;
+    ::ndk::ScopedAStatus aidl_retval;
+
+    // Test with empty remote capabilities.
+    aidl_retval =
+        provider->getA2dpConfiguration(std::vector<A2dpRemoteCapabilities>{},
+                                       A2dpConfigurationHint(), &configuration);
+    ASSERT_TRUE(aidl_retval.isOk());
+    EXPECT_FALSE(configuration.has_value());
+
+    // Test with unknown remote capabilities.
+    A2dpRemoteCapabilities unknown_core_remote_capabilities(
+        /*seid*/ 0, CodecId::Core::CVSD, std::vector<uint8_t>{1, 2, 3});
+    A2dpRemoteCapabilities unknown_vendor_remote_capabilities(
+        /*seid*/ 1,
+        /* Google Codec #42 */ CodecId::Vendor(0xFCB1, 0x42),
+        std::vector<uint8_t>{1, 2, 3});
+    aidl_retval = provider->getA2dpConfiguration(
+        std::vector<A2dpRemoteCapabilities>{
+            unknown_core_remote_capabilities,
+            unknown_vendor_remote_capabilities,
+        },
+        A2dpConfigurationHint(), &configuration);
+    ASSERT_TRUE(aidl_retval.isOk());
+    EXPECT_FALSE(configuration.has_value());
+  }
+}
+
+/**
+ * Calling getA2dpConfiguration with invalid remote capabilities
+ * must return an empty configuration.
+ */
+TEST_P(BluetoothAudioProviderAidl,
+       getA2dpConfiguration_invalidRemoteCapabilities) {
+  for (auto& [provider, provider_info] :
+       {std::pair(a2dp_encoding_provider_, a2dp_encoding_provider_info_),
+        std::pair(a2dp_decoding_provider_, a2dp_decoding_provider_info_)}) {
+    if (provider == nullptr || !provider_info.has_value() ||
+        provider_info->codecInfos.empty()) {
+      continue;
+    }
+
+    std::optional<A2dpConfiguration> configuration;
+    ::ndk::ScopedAStatus aidl_retval;
+
+    // Use the first available codec in the provider info for testing.
+    // The capabilities are modified to make them invalid.
+    auto const& codec_info = provider_info->codecInfos[0];
+    auto transport = codec_info.transport.get<CodecInfo::Transport::a2dp>();
+    std::vector<uint8_t> invalid_capabilities = transport.capabilities;
+    invalid_capabilities.push_back(0x42);  // adding bytes should be invalid.
+    aidl_retval = provider->getA2dpConfiguration(
+        std::vector<A2dpRemoteCapabilities>{
+            A2dpRemoteCapabilities(/*seid*/ 0, codec_info.id,
+                                   std::vector<uint8_t>()),
+            A2dpRemoteCapabilities(/*seid*/ 1, codec_info.id,
+                                   invalid_capabilities),
+        },
+        A2dpConfigurationHint(), &configuration);
+    ASSERT_TRUE(aidl_retval.isOk());
+    EXPECT_FALSE(configuration.has_value());
+  }
+}
+
+/**
+ * Calling getA2dpConfiguration with valid remote capabilities
+ * must return a valid configuration. The selected parameters must
+ * be contained in the original capabilities. The returned configuration
+ * must match the returned parameters. The returned SEID must match the
+ * input SEID.
+ */
+TEST_P(BluetoothAudioProviderAidl,
+       getA2dpConfiguration_validRemoteCapabilities) {
+  for (auto& [provider, provider_info] :
+       {std::pair(a2dp_encoding_provider_, a2dp_encoding_provider_info_),
+        std::pair(a2dp_decoding_provider_, a2dp_decoding_provider_info_)}) {
+    if (provider == nullptr || !provider_info.has_value() ||
+        provider_info->codecInfos.empty()) {
+      continue;
+    }
+
+    // Test with all available codecs in the provider info.
+    for (auto const& codec_info : provider_info->codecInfos) {
+      auto a2dp_info = codec_info.transport.get<CodecInfo::Transport::a2dp>();
+      std::optional<A2dpConfiguration> configuration{};
+      ::ndk::ScopedAStatus aidl_retval;
+
+      aidl_retval = provider->getA2dpConfiguration(
+          std::vector<A2dpRemoteCapabilities>{
+              A2dpRemoteCapabilities(/*seid*/ 42, codec_info.id,
+                                     a2dp_info.capabilities),
+          },
+          A2dpConfigurationHint(), &configuration);
+
+      ASSERT_TRUE(aidl_retval.isOk());
+      ASSERT_TRUE(configuration.has_value());
+
+      // Returned configuration must have the same codec id
+      // as the remote capability.
+      EXPECT_EQ(configuration->id, codec_info.id);
+
+      // Returned configuration must have the same SEID
+      // as the remote capability.
+      EXPECT_EQ(configuration->remoteSeid, 42);
+
+      // Returned codec parameters must be in the range of input
+      // parameters.
+      EXPECT_NE(
+          std::find(a2dp_info.channelMode.begin(), a2dp_info.channelMode.end(),
+                    configuration->parameters.channelMode),
+          a2dp_info.channelMode.end());
+      EXPECT_NE(std::find(a2dp_info.samplingFrequencyHz.begin(),
+                          a2dp_info.samplingFrequencyHz.end(),
+                          configuration->parameters.samplingFrequencyHz),
+                a2dp_info.samplingFrequencyHz.end());
+      EXPECT_NE(std::find(a2dp_info.bitdepth.begin(), a2dp_info.bitdepth.end(),
+                          configuration->parameters.bitdepth),
+                a2dp_info.bitdepth.end());
+      EXPECT_EQ(a2dp_info.lossless, configuration->parameters.lossless);
+      EXPECT_TRUE(configuration->parameters.minBitrate <=
+                  configuration->parameters.maxBitrate);
+
+      // Returned configuration must be parsable by parseA2dpParameters
+      // and match the codec parameters.
+      CodecParameters codec_parameters;
+      A2dpStatus a2dp_status = A2dpStatus::OK;
+      aidl_retval = provider->parseA2dpConfiguration(
+          configuration->id, configuration->configuration, &codec_parameters,
+          &a2dp_status);
+      ASSERT_TRUE(aidl_retval.isOk());
+      EXPECT_TRUE(a2dp_status == A2dpStatus::OK);
+      EXPECT_EQ(codec_parameters, configuration->parameters);
+    }
+  }
+}
+
+/**
+ * Calling getA2dpConfiguration with valid remote capabilities
+ * with various hinted codec ids.
+ */
+TEST_P(BluetoothAudioProviderAidl, getA2dpConfiguration_hintCodecId) {
+  for (auto& [provider, provider_info] :
+       {std::pair(a2dp_encoding_provider_, a2dp_encoding_provider_info_),
+        std::pair(a2dp_decoding_provider_, a2dp_decoding_provider_info_)}) {
+    if (provider == nullptr || !provider_info.has_value() ||
+        provider_info->codecInfos.empty()) {
+      continue;
+    }
+
+    // Build the remote capabilities with all supported codecs.
+    std::vector<A2dpRemoteCapabilities> remote_capabilities;
+    for (size_t n = 0; n < provider_info->codecInfos.size(); n++) {
+      auto const& codec_info = provider_info->codecInfos[n];
+      auto a2dp_info = codec_info.transport.get<CodecInfo::Transport::a2dp>();
+      remote_capabilities.push_back(A2dpRemoteCapabilities(
+          /*seid*/ n, codec_info.id, a2dp_info.capabilities));
+    }
+
+    // Test with all supported codec identifiers,
+    for (auto const& codec_info : provider_info->codecInfos) {
+      std::optional<A2dpConfiguration> configuration{};
+      ::ndk::ScopedAStatus aidl_retval;
+
+      A2dpConfigurationHint hint;
+      hint.codecId = codec_info.id;
+
+      aidl_retval = provider->getA2dpConfiguration(remote_capabilities, hint,
+                                                   &configuration);
+
+      ASSERT_TRUE(aidl_retval.isOk());
+      ASSERT_TRUE(configuration.has_value());
+      EXPECT_EQ(configuration->id, codec_info.id);
+    }
+
+    // Test with unknown codec identifiers: either core or vendor.
+    for (auto& codec_id :
+         {CodecId(CodecId::Core::CVSD),
+          CodecId(CodecId::Vendor(0xFCB1, 0x42)) /*Google Codec #42*/}) {
+      std::optional<A2dpConfiguration> configuration{};
+      ::ndk::ScopedAStatus aidl_retval;
+
+      A2dpConfigurationHint hint;
+      hint.codecId = codec_id;
+
+      aidl_retval = provider->getA2dpConfiguration(remote_capabilities, hint,
+                                                   &configuration);
+
+      ASSERT_TRUE(aidl_retval.isOk());
+      ASSERT_TRUE(configuration.has_value());
+      EXPECT_NE(configuration->id, codec_id);
+    }
+  }
+}
+
+/**
+ * Calling getA2dpConfiguration with valid remote capabilities
+ * with various hinted channel modes.
+ */
+TEST_P(BluetoothAudioProviderAidl, getA2dpConfiguration_hintChannelMode) {
+  for (auto& [provider, provider_info] :
+       {std::pair(a2dp_encoding_provider_, a2dp_encoding_provider_info_),
+        std::pair(a2dp_decoding_provider_, a2dp_decoding_provider_info_)}) {
+    if (provider == nullptr || !provider_info.has_value() ||
+        provider_info->codecInfos.empty()) {
+      continue;
+    }
+
+    // Test with all available codecs in the provider info.
+    for (auto const& codec_info : provider_info->codecInfos) {
+      auto a2dp_info = codec_info.transport.get<CodecInfo::Transport::a2dp>();
+      std::optional<A2dpConfiguration> configuration{};
+      ::ndk::ScopedAStatus aidl_retval;
+
+      for (auto& channel_mode :
+           {ChannelMode::STEREO, ChannelMode::MONO, ChannelMode::DUALMONO}) {
+        // Add the hint for the channel mode.
+        A2dpConfigurationHint hint;
+        auto& codec_parameters = hint.codecParameters.emplace();
+        codec_parameters.channelMode = channel_mode;
+
+        aidl_retval = provider->getA2dpConfiguration(
+            std::vector<A2dpRemoteCapabilities>{
+                A2dpRemoteCapabilities(/*seid*/ 42, codec_info.id,
+                                       a2dp_info.capabilities),
+            },
+            hint, &configuration);
+
+        ASSERT_TRUE(aidl_retval.isOk());
+        ASSERT_TRUE(configuration.has_value());
+
+        // The hint must be ignored if the channel mode is not supported
+        // by the codec, and applied otherwise.
+        ASSERT_EQ(configuration->parameters.channelMode == channel_mode,
+                  std::find(a2dp_info.channelMode.begin(),
+                            a2dp_info.channelMode.end(),
+                            channel_mode) != a2dp_info.channelMode.end());
+      }
+    }
+  }
+}
+
+/**
+ * Calling getA2dpConfiguration with valid remote capabilities
+ * with various hinted sampling frequencies.
+ */
+TEST_P(BluetoothAudioProviderAidl,
+       getA2dpConfiguration_hintSamplingFrequencyHz) {
+  for (auto& [provider, provider_info] :
+       {std::pair(a2dp_encoding_provider_, a2dp_encoding_provider_info_),
+        std::pair(a2dp_decoding_provider_, a2dp_decoding_provider_info_)}) {
+    if (provider == nullptr || !provider_info.has_value() ||
+        provider_info->codecInfos.empty()) {
+      continue;
+    }
+
+    // Test with all available codecs in the provider info.
+    for (auto const& codec_info : provider_info->codecInfos) {
+      auto a2dp_info = codec_info.transport.get<CodecInfo::Transport::a2dp>();
+      std::optional<A2dpConfiguration> configuration{};
+      ::ndk::ScopedAStatus aidl_retval;
+
+      for (auto& sampling_frequency_hz : {
+               0,
+               1,
+               8000,
+               16000,
+               24000,
+               32000,
+               44100,
+               48000,
+               88200,
+               96000,
+               176400,
+               192000,
+           }) {
+        // Add the hint for the sampling frequency.
+        A2dpConfigurationHint hint;
+        auto& codec_parameters = hint.codecParameters.emplace();
+        codec_parameters.samplingFrequencyHz = sampling_frequency_hz;
+
+        aidl_retval = provider->getA2dpConfiguration(
+            std::vector<A2dpRemoteCapabilities>{
+                A2dpRemoteCapabilities(/*seid*/ 42, codec_info.id,
+                                       a2dp_info.capabilities),
+            },
+            hint, &configuration);
+
+        ASSERT_TRUE(aidl_retval.isOk());
+        ASSERT_TRUE(configuration.has_value());
+
+        // The hint must be ignored if the sampling frequency is not supported
+        // by the codec, and applied otherwise.
+        ASSERT_EQ(configuration->parameters.samplingFrequencyHz ==
+                      sampling_frequency_hz,
+                  std::find(a2dp_info.samplingFrequencyHz.begin(),
+                            a2dp_info.samplingFrequencyHz.end(),
+                            sampling_frequency_hz) !=
+                      a2dp_info.samplingFrequencyHz.end());
+      }
+    }
+  }
+}
+
+/**
+ * Calling getA2dpConfiguration with valid remote capabilities
+ * with various hinted sampling bit-depths.
+ */
+TEST_P(BluetoothAudioProviderAidl, getA2dpConfiguration_hintBitdepth) {
+  for (auto& [provider, provider_info] :
+       {std::pair(a2dp_encoding_provider_, a2dp_encoding_provider_info_),
+        std::pair(a2dp_decoding_provider_, a2dp_decoding_provider_info_)}) {
+    if (provider == nullptr || !provider_info.has_value() ||
+        provider_info->codecInfos.empty()) {
+      continue;
+    }
+
+    // Test with all available codecs in the provider info.
+    for (auto const& codec_info : provider_info->codecInfos) {
+      auto a2dp_info = codec_info.transport.get<CodecInfo::Transport::a2dp>();
+      std::optional<A2dpConfiguration> configuration{};
+      ::ndk::ScopedAStatus aidl_retval;
+
+      for (auto& bitdepth : {0, 1, 16, 24, 32}) {
+        // Add the hint for the bit depth.
+        A2dpConfigurationHint hint;
+        auto& codec_parameters = hint.codecParameters.emplace();
+        codec_parameters.bitdepth = bitdepth;
+
+        aidl_retval = provider->getA2dpConfiguration(
+            std::vector<A2dpRemoteCapabilities>{
+                A2dpRemoteCapabilities(/*seid*/ 42, codec_info.id,
+                                       a2dp_info.capabilities),
+            },
+            hint, &configuration);
+
+        ASSERT_TRUE(aidl_retval.isOk());
+        ASSERT_TRUE(configuration.has_value());
+
+        // The hint must be ignored if the bitdepth is not supported
+        // by the codec, and applied otherwise.
+        ASSERT_EQ(
+            configuration->parameters.bitdepth == bitdepth,
+            std::find(a2dp_info.bitdepth.begin(), a2dp_info.bitdepth.end(),
+                      bitdepth) != a2dp_info.bitdepth.end());
+      }
+    }
+  }
+}
+
+/**
+ * Calling startSession with an unknown codec id must fail.
+ */
+TEST_P(BluetoothAudioProviderAidl, startSession_unknownCodecId) {
+  for (auto& [provider, provider_info] :
+       {std::pair(a2dp_encoding_provider_, a2dp_encoding_provider_info_),
+        std::pair(a2dp_decoding_provider_, a2dp_decoding_provider_info_)}) {
+    if (provider == nullptr || !provider_info.has_value() ||
+        provider_info->codecInfos.empty()) {
+      continue;
+    }
+
+    for (auto& codec_id :
+         {CodecId(CodecId::Core::CVSD),
+          CodecId(CodecId::Vendor(0xFCB1, 0x42) /*Google Codec #42*/)}) {
+      A2dpStreamConfiguration a2dp_config;
+      DataMQDesc data_mq_desc;
+
+      a2dp_config.codecId = codec_id;
+      a2dp_config.configuration = std::vector<uint8_t>{1, 2, 3};
+
+      auto aidl_retval =
+          provider->startSession(audio_port_, AudioConfiguration(a2dp_config),
+                                 std::vector<LatencyMode>{}, &data_mq_desc);
+
+      EXPECT_FALSE(aidl_retval.isOk());
+    }
+  }
+}
+
+/**
+ * Calling startSession with a known codec and a valid configuration
+ * must succeed.
+ */
+TEST_P(BluetoothAudioProviderAidl, startSession_valid) {
+  for (auto& [provider, provider_info] :
+       {std::pair(a2dp_encoding_provider_, a2dp_encoding_provider_info_),
+        std::pair(a2dp_decoding_provider_, a2dp_decoding_provider_info_)}) {
+    if (provider == nullptr || !provider_info.has_value() ||
+        provider_info->codecInfos.empty()) {
+      continue;
+    }
+
+    // Use the first available codec in the provider info for testing.
+    // To get a valid configuration (the capabilities array in the provider
+    // info is not a selection), getA2dpConfiguration is used with the
+    // selected codec parameters as input.
+    auto const& codec_info = provider_info->codecInfos[0];
+    auto a2dp_info = codec_info.transport.get<CodecInfo::Transport::a2dp>();
+    ::ndk::ScopedAStatus aidl_retval;
+    A2dpRemoteCapabilities remote_capabilities(/*seid*/ 0, codec_info.id,
+                                               a2dp_info.capabilities);
+    std::optional<A2dpConfiguration> configuration;
+    aidl_retval = provider->getA2dpConfiguration(
+        std::vector<A2dpRemoteCapabilities>{remote_capabilities},
+        A2dpConfigurationHint(), &configuration);
+    ASSERT_TRUE(aidl_retval.isOk());
+    ASSERT_TRUE(configuration.has_value());
+
+    // Build the stream configuration.
+    A2dpStreamConfiguration a2dp_config;
+    DataMQDesc data_mq_desc;
+
+    a2dp_config.codecId = codec_info.id;
+    a2dp_config.configuration = configuration->configuration;
+
+    aidl_retval =
+        provider->startSession(audio_port_, AudioConfiguration(a2dp_config),
+                               std::vector<LatencyMode>{}, &data_mq_desc);
+
+    EXPECT_TRUE(aidl_retval.isOk());
+  }
+}
+
+/**
+ * Calling startSession with a known codec but an invalid configuration
+ * must fail.
+ */
+TEST_P(BluetoothAudioProviderAidl, startSession_invalidConfiguration) {
+  for (auto& [provider, provider_info] :
+       {std::pair(a2dp_encoding_provider_, a2dp_encoding_provider_info_),
+        std::pair(a2dp_decoding_provider_, a2dp_decoding_provider_info_)}) {
+    if (provider == nullptr || !provider_info.has_value() ||
+        provider_info->codecInfos.empty()) {
+      continue;
+    }
+
+    // Use the first available codec in the provider info for testing.
+    // To get a valid configuration (the capabilities array in the provider
+    // info is not a selection), getA2dpConfiguration is used with the
+    // selected codec parameters as input.
+    ::ndk::ScopedAStatus aidl_retval;
+    auto const& codec_info = provider_info->codecInfos[0];
+    auto a2dp_info = codec_info.transport.get<CodecInfo::Transport::a2dp>();
+    A2dpRemoteCapabilities remote_capabilities(/*seid*/ 0, codec_info.id,
+                                               a2dp_info.capabilities);
+    std::optional<A2dpConfiguration> configuration;
+    aidl_retval = provider->getA2dpConfiguration(
+        std::vector<A2dpRemoteCapabilities>{remote_capabilities},
+        A2dpConfigurationHint(), &configuration);
+    ASSERT_TRUE(aidl_retval.isOk());
+    ASSERT_TRUE(configuration.has_value());
+
+    // Build the stream configuration but edit the configuration bytes
+    // to make it invalid.
+    A2dpStreamConfiguration a2dp_config;
+    DataMQDesc data_mq_desc;
+
+    a2dp_config.codecId = codec_info.id;
+    a2dp_config.configuration = configuration->configuration;
+    a2dp_config.configuration.push_back(42);
+
+    aidl_retval =
+        provider->startSession(audio_port_, AudioConfiguration(a2dp_config),
+                               std::vector<LatencyMode>{}, &data_mq_desc);
+
+    EXPECT_FALSE(aidl_retval.isOk());
+  }
 }
 
 /**
@@ -625,8 +1511,8 @@
 
 /**
  * Test whether each provider of type
- * SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH can be started and stopped with
- * different PCM config
+ * SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH can be started and stopped
+ * with different PCM config
  */
 TEST_P(BluetoothAudioProviderA2dpEncodingSoftwareAidl,
        StartAndEndA2dpEncodingSoftwareSessionWithPossiblePcmConfig) {
@@ -656,6 +1542,145 @@
 }
 
 /**
+ * openProvider HFP_SOFTWARE_ENCODING_DATAPATH
+ */
+class BluetoothAudioProviderHfpSoftwareEncodingAidl
+    : public BluetoothAudioProviderFactoryAidl {
+ public:
+  virtual void SetUp() override {
+    BluetoothAudioProviderFactoryAidl::SetUp();
+    if (GetProviderFactoryInterfaceVersion() <
+        BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+      GTEST_SKIP();
+    }
+    GetProviderCapabilitiesHelper(SessionType::HFP_SOFTWARE_ENCODING_DATAPATH);
+    OpenProviderHelper(SessionType::HFP_SOFTWARE_ENCODING_DATAPATH);
+    ASSERT_NE(audio_provider_, nullptr);
+  }
+
+  virtual void TearDown() override {
+    audio_port_ = nullptr;
+    audio_provider_ = nullptr;
+    BluetoothAudioProviderFactoryAidl::TearDown();
+  }
+
+  bool OpenSession(int32_t sample_rate, int8_t bits_per_sample,
+                   ChannelMode channel_mode, int32_t data_interval_us) {
+    PcmConfiguration pcm_config{
+        .sampleRateHz = sample_rate,
+        .channelMode = channel_mode,
+        .bitsPerSample = bits_per_sample,
+        .dataIntervalUs = data_interval_us,
+    };
+    // Checking against provider capability from getProviderCapabilities
+    // For HFP software, it's
+    // BluetoothAudioCodecs::GetSoftwarePcmCapabilities();
+    DataMQDesc mq_desc;
+    auto aidl_retval = audio_provider_->startSession(
+        audio_port_, AudioConfiguration(pcm_config), latency_modes, &mq_desc);
+    DataMQ data_mq(mq_desc);
+
+    if (!aidl_retval.isOk()) return false;
+    if (!data_mq.isValid()) return false;
+    return true;
+  }
+};
+
+/**
+ * Test whether we can open a provider of type
+ */
+TEST_P(BluetoothAudioProviderHfpSoftwareEncodingAidl,
+       OpenHfpSoftwareEncodingProvider) {}
+
+/**
+ * Test whether each provider of type
+ * SessionType::HFP_SOFTWARE_ENCODING_DATAPATH can be started and stopped with
+ * different PCM config
+ */
+TEST_P(BluetoothAudioProviderHfpSoftwareEncodingAidl,
+       StartAndEndHfpEncodingSoftwareSessionWithPossiblePcmConfig) {
+  for (auto sample_rate : hfp_sample_rates_) {
+    for (auto bits_per_sample : hfp_bits_per_samples_) {
+      for (auto channel_mode : hfp_channel_modes_) {
+        for (auto data_interval_us : hfp_data_interval_us_) {
+          EXPECT_TRUE(OpenSession(sample_rate, bits_per_sample, channel_mode,
+                                  data_interval_us));
+          EXPECT_TRUE(audio_provider_->endSession().isOk());
+        }
+      }
+    }
+  }
+}
+
+/**
+ * openProvider HFP_SOFTWARE_DECODING_DATAPATH
+ */
+class BluetoothAudioProviderHfpSoftwareDecodingAidl
+    : public BluetoothAudioProviderFactoryAidl {
+ public:
+  virtual void SetUp() override {
+    BluetoothAudioProviderFactoryAidl::SetUp();
+    if (GetProviderFactoryInterfaceVersion() <
+        BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+      GTEST_SKIP();
+    }
+    GetProviderCapabilitiesHelper(SessionType::HFP_SOFTWARE_DECODING_DATAPATH);
+    OpenProviderHelper(SessionType::HFP_SOFTWARE_DECODING_DATAPATH);
+    ASSERT_NE(audio_provider_, nullptr);
+  }
+
+  virtual void TearDown() override {
+    audio_port_ = nullptr;
+    audio_provider_ = nullptr;
+    BluetoothAudioProviderFactoryAidl::TearDown();
+  }
+
+  bool OpenSession(int32_t sample_rate, int8_t bits_per_sample,
+                   ChannelMode channel_mode, int32_t data_interval_us) {
+    PcmConfiguration pcm_config{
+        .sampleRateHz = sample_rate,
+        .channelMode = channel_mode,
+        .bitsPerSample = bits_per_sample,
+        .dataIntervalUs = data_interval_us,
+    };
+    DataMQDesc mq_desc;
+    auto aidl_retval = audio_provider_->startSession(
+        audio_port_, AudioConfiguration(pcm_config), latency_modes, &mq_desc);
+    DataMQ data_mq(mq_desc);
+
+    if (!aidl_retval.isOk()) return false;
+    if (!data_mq.isValid()) return false;
+    return true;
+  }
+};
+
+/**
+ * Test whether we can open a provider of type
+ */
+TEST_P(BluetoothAudioProviderHfpSoftwareDecodingAidl,
+       OpenHfpSoftwareDecodingProvider) {}
+
+/**
+ * Test whether each provider of type
+ * SessionType::HFP_SOFTWARE_DECODING_DATAPATH can be started and stopped with
+ * different PCM config
+ */
+TEST_P(BluetoothAudioProviderHfpSoftwareDecodingAidl,
+       StartAndEndHfpDecodingSoftwareSessionWithPossiblePcmConfig) {
+  for (auto sample_rate : hfp_sample_rates_) {
+    for (auto bits_per_sample : hfp_bits_per_samples_) {
+      for (auto channel_mode : hfp_channel_modes_) {
+        for (auto data_interval_us : hfp_data_interval_us_) {
+          EXPECT_TRUE(OpenSession(sample_rate, bits_per_sample, channel_mode,
+                                  data_interval_us));
+          EXPECT_TRUE(audio_provider_->endSession().isOk());
+        }
+      }
+    }
+  }
+}
+
+/**
  * openProvider A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH
  */
 class BluetoothAudioProviderA2dpEncodingHardwareAidl
@@ -687,13 +1712,13 @@
 
 /**
  * Test whether each provider of type
- * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with
- * SBC hardware encoding config
+ * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped
+ * with SBC hardware encoding config
  */
 TEST_P(BluetoothAudioProviderA2dpEncodingHardwareAidl,
        StartAndEndA2dpSbcEncodingHardwareSession) {
   if (!IsOffloadSupported()) {
-    return;
+    GTEST_SKIP();
   }
 
   CodecConfiguration codec_config = {
@@ -717,13 +1742,13 @@
 
 /**
  * Test whether each provider of type
- * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with
- * AAC hardware encoding config
+ * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped
+ * with AAC hardware encoding config
  */
 TEST_P(BluetoothAudioProviderA2dpEncodingHardwareAidl,
        StartAndEndA2dpAacEncodingHardwareSession) {
   if (!IsOffloadSupported()) {
-    return;
+    GTEST_SKIP();
   }
 
   CodecConfiguration codec_config = {
@@ -747,13 +1772,13 @@
 
 /**
  * Test whether each provider of type
- * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with
- * LDAC hardware encoding config
+ * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped
+ * with LDAC hardware encoding config
  */
 TEST_P(BluetoothAudioProviderA2dpEncodingHardwareAidl,
        StartAndEndA2dpLdacEncodingHardwareSession) {
   if (!IsOffloadSupported()) {
-    return;
+    GTEST_SKIP();
   }
 
   CodecConfiguration codec_config = {
@@ -777,13 +1802,13 @@
 
 /**
  * Test whether each provider of type
- * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with
- * Opus hardware encoding config
+ * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped
+ * with Opus hardware encoding config
  */
 TEST_P(BluetoothAudioProviderA2dpEncodingHardwareAidl,
        StartAndEndA2dpOpusEncodingHardwareSession) {
   if (!IsOffloadSupported()) {
-    return;
+    GTEST_SKIP();
   }
 
   CodecConfiguration codec_config = {
@@ -807,13 +1832,13 @@
 
 /**
  * Test whether each provider of type
- * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with
- * AptX hardware encoding config
+ * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped
+ * with AptX hardware encoding config
  */
 TEST_P(BluetoothAudioProviderA2dpEncodingHardwareAidl,
        StartAndEndA2dpAptxEncodingHardwareSession) {
   if (!IsOffloadSupported()) {
-    return;
+    GTEST_SKIP();
   }
 
   for (auto codec_type : {CodecType::APTX, CodecType::APTX_HD}) {
@@ -843,13 +1868,13 @@
 
 /**
  * Test whether each provider of type
- * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with
- * an invalid codec config
+ * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped
+ * with an invalid codec config
  */
 TEST_P(BluetoothAudioProviderA2dpEncodingHardwareAidl,
        StartAndEndA2dpEncodingHardwareSessionInvalidCodecConfig) {
   if (!IsOffloadSupported()) {
-    return;
+    GTEST_SKIP();
   }
   ASSERT_NE(audio_provider_, nullptr);
 
@@ -908,6 +1933,66 @@
 }
 
 /**
+ * openProvider HFP_HARDWARE_OFFLOAD_DATAPATH
+ */
+class BluetoothAudioProviderHfpHardwareAidl
+    : public BluetoothAudioProviderFactoryAidl {
+ public:
+  virtual void SetUp() override {
+    BluetoothAudioProviderFactoryAidl::SetUp();
+    if (GetProviderFactoryInterfaceVersion() <
+        BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+      GTEST_SKIP();
+    }
+    OpenProviderHelper(SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH);
+    // Can open or empty capability
+    ASSERT_TRUE(temp_provider_capabilities_.empty() ||
+                audio_provider_ != nullptr);
+  }
+
+  virtual void TearDown() override {
+    audio_port_ = nullptr;
+    audio_provider_ = nullptr;
+    BluetoothAudioProviderFactoryAidl::TearDown();
+  }
+
+  bool OpenSession(CodecId codec_id, int connection_handle, bool nrec,
+                   bool controller_codec) {
+    // Check if can open session with a Hfp configuration
+    HfpConfiguration hfp_configuration{
+        .codecId = codec_id,
+        .connectionHandle = connection_handle,
+        .nrec = nrec,
+        .controllerCodec = controller_codec,
+    };
+    DataMQDesc mq_desc;
+    auto aidl_retval = audio_provider_->startSession(
+        audio_port_, AudioConfiguration(hfp_configuration), latency_modes,
+        &mq_desc);
+
+    // Only check if aidl is ok to start session.
+    return aidl_retval.isOk();
+  }
+};
+
+/**
+ * Test whether we can open a provider of type
+ */
+TEST_P(BluetoothAudioProviderHfpHardwareAidl, OpenHfpHardwareProvider) {}
+
+/**
+ * Test whether each provider of type
+ * SessionType::HFP_SOFTWARE_DECODING_DATAPATH can be started and stopped with
+ * different HFP config
+ */
+TEST_P(BluetoothAudioProviderHfpHardwareAidl,
+       StartAndEndHfpHardwareSessionWithPossiblePcmConfig) {
+  // Try to open with a sample configuration
+  EXPECT_TRUE(OpenSession(CodecId::Core::CVSD, 6, false, true));
+  EXPECT_TRUE(audio_provider_->endSession().isOk());
+}
+
+/**
  * openProvider HEARING_AID_SOFTWARE_ENCODING_DATAPATH
  */
 class BluetoothAudioProviderHearingAidSoftwareAidl
@@ -1128,6 +2213,8 @@
     BluetoothAudioProviderFactoryAidl::SetUp();
     GetProviderCapabilitiesHelper(
         SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH);
+    GetProviderInfoHelper(
+        SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH);
     OpenProviderHelper(
         SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH);
     ASSERT_TRUE(temp_provider_capabilities_.empty() ||
@@ -1154,6 +2241,99 @@
     return false;
   }
 
+  bool IsOffloadOutputProviderInfoSupported() {
+    if (!temp_provider_info_.has_value()) return false;
+    if (temp_provider_info_.value().codecInfos.empty()) return false;
+    // Check if all codec info is of LeAudio type
+    for (auto& codec_info : temp_provider_info_.value().codecInfos) {
+      if (codec_info.transport.getTag() != CodecInfo::Transport::leAudio)
+        return false;
+    }
+    return true;
+  }
+
+  std::vector<Lc3Configuration> GetUnicastLc3SupportedListFromProviderInfo() {
+    std::vector<Lc3Configuration> le_audio_codec_configs;
+    for (auto& codec_info : temp_provider_info_.value().codecInfos) {
+      // Only gets LC3 codec information
+      if (codec_info.id != CodecId::Core::LC3) continue;
+      // Combine those parameters into one list of Lc3Configuration
+      auto& transport =
+          codec_info.transport.get<CodecInfo::Transport::Tag::leAudio>();
+      for (int32_t samplingFrequencyHz : transport.samplingFrequencyHz) {
+        for (int32_t frameDurationUs : transport.frameDurationUs) {
+          for (int32_t octetsPerFrame : transport.bitdepth) {
+            Lc3Configuration lc3_config = {
+                .samplingFrequencyHz = samplingFrequencyHz,
+                .frameDurationUs = frameDurationUs,
+                .octetsPerFrame = octetsPerFrame,
+            };
+            le_audio_codec_configs.push_back(lc3_config);
+          }
+        }
+      }
+    }
+
+    return le_audio_codec_configs;
+  }
+
+  AudioContext GetAudioContext(int32_t bitmask) {
+    AudioContext media_audio_context;
+    media_audio_context.bitmask = bitmask;
+    return media_audio_context;
+  }
+
+  LeAudioDeviceCapabilities GetDefaultRemoteCapability() {
+    // Create a capability
+    LeAudioDeviceCapabilities capability;
+
+    capability.codecId = CodecId::Core::LC3;
+
+    auto pref_context_metadata = MetadataLtv::PreferredAudioContexts();
+    pref_context_metadata.values = GetAudioContext(AudioContext::MEDIA);
+    capability.metadata = {pref_context_metadata};
+
+    auto sampling_rate =
+        CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies();
+    sampling_rate.bitmask =
+        CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ8000;
+    auto frame_duration =
+        CodecSpecificCapabilitiesLtv::SupportedFrameDurations();
+    frame_duration.bitmask =
+        CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US7500;
+    auto octets = CodecSpecificCapabilitiesLtv::SupportedOctetsPerCodecFrame();
+    octets.min = 0;
+    octets.max = 60;
+    auto frames = CodecSpecificCapabilitiesLtv::SupportedMaxCodecFramesPerSDU();
+    frames.value = 2;
+    capability.codecSpecificCapabilities = {sampling_rate, frame_duration,
+                                            octets, frames};
+    return capability;
+  }
+
+  LeAudioConfigurationRequirement GetDefaultRequirement(
+      bool is_source_requriement) {
+    // Create a requirements
+    LeAudioConfigurationRequirement requirement;
+    requirement.audioContext = GetAudioContext(AudioContext::MEDIA);
+
+    auto direction_ase_requriement = AseDirectionRequirement();
+    direction_ase_requriement.aseConfiguration.codecId = CodecId::Core::LC3;
+    direction_ase_requriement.aseConfiguration.targetLatency =
+        LeAudioAseConfiguration::TargetLatency::BALANCED_LATENCY_RELIABILITY;
+
+    // Mismatch sampling frequency
+    direction_ase_requriement.aseConfiguration.codecConfiguration = {
+        CodecSpecificConfigurationLtv::SamplingFrequency::HZ11025,
+        CodecSpecificConfigurationLtv::FrameDuration::US7500,
+    };
+    if (is_source_requriement)
+      requirement.sourceAseRequirement = {direction_ase_requriement};
+    else
+      requirement.sinkAseRequirement = {direction_ase_requriement};
+    return requirement;
+  }
+
   std::vector<Lc3Configuration> GetUnicastLc3SupportedList(bool decoding,
                                                            bool supported) {
     std::vector<Lc3Configuration> le_audio_codec_configs;
@@ -1271,6 +2451,14 @@
   }
 
   LeAudioCodecCapabilitiesSetting temp_le_audio_capabilities_;
+  std::vector<int32_t> all_context_bitmasks = {
+      AudioContext::UNSPECIFIED,   AudioContext::CONVERSATIONAL,
+      AudioContext::MEDIA,         AudioContext::GAME,
+      AudioContext::INSTRUCTIONAL, AudioContext::VOICE_ASSISTANTS,
+      AudioContext::LIVE_AUDIO,    AudioContext::SOUND_EFFECTS,
+      AudioContext::NOTIFICATIONS, AudioContext::RINGTONE_ALERTS,
+      AudioContext::ALERTS,        AudioContext::EMERGENCY_ALARM,
+  };
 };
 
 /**
@@ -1284,12 +2472,157 @@
 /**
  * Test whether each provider of type
  * SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH can be started and
+ * stopped with Unicast hardware encoding config taken from provider info
+ */
+TEST_P(
+    BluetoothAudioProviderLeAudioOutputHardwareAidl,
+    StartAndEndLeAudioOutputSessionWithPossibleUnicastConfigFromProviderInfo) {
+  if (GetProviderFactoryInterfaceVersion() <
+      BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+    GTEST_SKIP();
+  }
+  if (!IsOffloadOutputProviderInfoSupported()) {
+    GTEST_SKIP();
+  }
+
+  auto lc3_codec_configs = GetUnicastLc3SupportedListFromProviderInfo();
+  LeAudioConfiguration le_audio_config = {
+      .codecType = CodecType::LC3,
+      .peerDelayUs = 0,
+  };
+
+  for (auto& lc3_config : lc3_codec_configs) {
+    le_audio_config.leAudioCodecConfig
+        .set<LeAudioCodecConfiguration::lc3Config>(lc3_config);
+    DataMQDesc mq_desc;
+    auto aidl_retval = audio_provider_->startSession(
+        audio_port_, AudioConfiguration(le_audio_config), latency_modes,
+        &mq_desc);
+
+    ASSERT_TRUE(aidl_retval.isOk());
+    EXPECT_TRUE(audio_provider_->endSession().isOk());
+  }
+}
+
+TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
+       GetEmptyAseConfigurationEmptyCapability) {
+  if (GetProviderFactoryInterfaceVersion() <
+      BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+    GTEST_SKIP();
+  }
+  std::vector<std::optional<LeAudioDeviceCapabilities>> empty_capability;
+  std::vector<LeAudioConfigurationRequirement> empty_requirement;
+  std::vector<LeAudioAseConfigurationSetting> configurations;
+
+  // Check empty capability for source direction
+  auto aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+      std::nullopt, empty_capability, empty_requirement, &configurations);
+
+  ASSERT_TRUE(aidl_retval.isOk());
+  ASSERT_TRUE(configurations.empty());
+
+  // Check empty capability for sink direction
+  aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+      empty_capability, std::nullopt, empty_requirement, &configurations);
+
+  ASSERT_TRUE(aidl_retval.isOk());
+  ASSERT_TRUE(configurations.empty());
+}
+
+TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
+       GetEmptyAseConfigurationMismatchedRequirement) {
+  if (GetProviderFactoryInterfaceVersion() <
+      BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+    GTEST_SKIP();
+  }
+  std::vector<std::optional<LeAudioDeviceCapabilities>> capabilities = {
+      GetDefaultRemoteCapability()};
+
+  // Check empty capability for source direction
+  std::vector<LeAudioAseConfigurationSetting> configurations;
+  std::vector<LeAudioConfigurationRequirement> source_requirements = {
+      GetDefaultRequirement(true)};
+  auto aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+      std::nullopt, capabilities, source_requirements, &configurations);
+
+  ASSERT_TRUE(aidl_retval.isOk());
+  ASSERT_TRUE(configurations.empty());
+
+  // Check empty capability for sink direction
+  std::vector<LeAudioConfigurationRequirement> sink_requirements = {
+      GetDefaultRequirement(false)};
+  aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+      capabilities, std::nullopt, source_requirements, &configurations);
+
+  ASSERT_TRUE(aidl_retval.isOk());
+  ASSERT_TRUE(configurations.empty());
+}
+
+TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl, GetQoSConfiguration) {
+  if (GetProviderFactoryInterfaceVersion() <
+      BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+    GTEST_SKIP();
+  }
+  IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement requirement;
+  std::vector<IBluetoothAudioProvider::LeAudioAseQosConfiguration>
+      QoSConfigurations;
+  for (auto bitmask : all_context_bitmasks) {
+    requirement.audioContext = GetAudioContext(bitmask);
+    IBluetoothAudioProvider::LeAudioAseQosConfigurationPair result;
+    auto aidl_retval =
+        audio_provider_->getLeAudioAseQosConfiguration(requirement, &result);
+    ASSERT_TRUE(aidl_retval.isOk());
+    if (result.sinkQosConfiguration.has_value())
+      QoSConfigurations.push_back(result.sinkQosConfiguration.value());
+    if (result.sourceQosConfiguration.has_value())
+      QoSConfigurations.push_back(result.sourceQosConfiguration.value());
+  }
+  // QoS Configurations should not be empty, as we searched for all contexts
+  ASSERT_FALSE(QoSConfigurations.empty());
+}
+
+TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
+       GetDataPathConfiguration) {
+  IBluetoothAudioProvider::StreamConfig sink_requirement;
+  IBluetoothAudioProvider::StreamConfig source_requirement;
+  std::vector<IBluetoothAudioProvider::LeAudioDataPathConfiguration>
+      DataPathConfigurations;
+  bool is_supported = false;
+
+  for (auto bitmask : all_context_bitmasks) {
+    sink_requirement.audioContext = GetAudioContext(bitmask);
+    source_requirement.audioContext = GetAudioContext(bitmask);
+    IBluetoothAudioProvider::LeAudioDataPathConfigurationPair result;
+    auto aidl_retval = audio_provider_->getLeAudioAseDatapathConfiguration(
+        sink_requirement, source_requirement, &result);
+    if (!aidl_retval.isOk()) {
+      // If not OK, then it could be not supported, as it is an optional feature
+      ASSERT_EQ(aidl_retval.getExceptionCode(), EX_UNSUPPORTED_OPERATION);
+    } else {
+      is_supported = true;
+      if (result.inputConfig.has_value())
+        DataPathConfigurations.push_back(result.inputConfig.value());
+      if (result.inputConfig.has_value())
+        DataPathConfigurations.push_back(result.inputConfig.value());
+    }
+  }
+
+  if (is_supported) {
+    // Datapath Configurations should not be empty, as we searched for all
+    // contexts
+    ASSERT_FALSE(DataPathConfigurations.empty());
+  }
+}
+
+/**
+ * Test whether each provider of type
+ * SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH can be started and
  * stopped with Unicast hardware encoding config
  */
 TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
        StartAndEndLeAudioOutputSessionWithPossibleUnicastConfig) {
   if (!IsOffloadOutputSupported()) {
-    return;
+    GTEST_SKIP();
   }
 
   auto lc3_codec_configs =
@@ -1322,7 +2655,7 @@
 TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
        DISABLED_StartAndEndLeAudioOutputSessionWithInvalidAudioConfiguration) {
   if (!IsOffloadOutputSupported()) {
-    return;
+    GTEST_SKIP();
   }
 
   auto lc3_codec_configs =
@@ -1360,7 +2693,7 @@
 TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
        StartAndEndLeAudioOutputSessionWithAptxAdaptiveLeUnicastConfig) {
   if (!IsOffloadOutputSupported()) {
-    return;
+    GTEST_SKIP();
   }
   for (auto codec_type :
        {CodecType::APTX_ADAPTIVE_LE, CodecType::APTX_ADAPTIVE_LEX}) {
@@ -1397,7 +2730,7 @@
     BluetoothAudioProviderLeAudioOutputHardwareAidl,
     BluetoothAudioProviderLeAudioOutputHardwareAidl_StartAndEndLeAudioOutputSessionWithInvalidAptxAdaptiveLeAudioConfiguration) {
   if (!IsOffloadOutputSupported()) {
-    return;
+    GTEST_SKIP();
   }
 
   for (auto codec_type :
@@ -1437,6 +2770,8 @@
     BluetoothAudioProviderFactoryAidl::SetUp();
     GetProviderCapabilitiesHelper(
         SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH);
+    GetProviderInfoHelper(
+        SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH);
     OpenProviderHelper(
         SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH);
     ASSERT_TRUE(temp_provider_capabilities_.empty() ||
@@ -1466,7 +2801,7 @@
 
 /**
  * Test whether each provider of type
- * SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH can be started and
+ * SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH can be started and
  * stopped
  */
 TEST_P(BluetoothAudioProviderLeAudioInputHardwareAidl,
@@ -1474,13 +2809,44 @@
 
 /**
  * Test whether each provider of type
- * SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH can be started and
+ * SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH can be started and
+ * stopped with Unicast hardware encoding config taken from provider info
+ */
+TEST_P(
+    BluetoothAudioProviderLeAudioInputHardwareAidl,
+    StartAndEndLeAudioInputSessionWithPossibleUnicastConfigFromProviderInfo) {
+  if (!IsOffloadOutputProviderInfoSupported()) {
+    GTEST_SKIP();
+  }
+
+  auto lc3_codec_configs = GetUnicastLc3SupportedListFromProviderInfo();
+  LeAudioConfiguration le_audio_config = {
+      .codecType = CodecType::LC3,
+      .peerDelayUs = 0,
+  };
+
+  for (auto& lc3_config : lc3_codec_configs) {
+    le_audio_config.leAudioCodecConfig
+        .set<LeAudioCodecConfiguration::lc3Config>(lc3_config);
+    DataMQDesc mq_desc;
+    auto aidl_retval = audio_provider_->startSession(
+        audio_port_, AudioConfiguration(le_audio_config), latency_modes,
+        &mq_desc);
+
+    ASSERT_TRUE(aidl_retval.isOk());
+    EXPECT_TRUE(audio_provider_->endSession().isOk());
+  }
+}
+
+/**
+ * Test whether each provider of type
+ * SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH can be started and
  * stopped with Unicast hardware encoding config
  */
 TEST_P(BluetoothAudioProviderLeAudioInputHardwareAidl,
        StartAndEndLeAudioInputSessionWithPossibleUnicastConfig) {
   if (!IsOffloadInputSupported()) {
-    return;
+    GTEST_SKIP();
   }
 
   auto lc3_codec_configs =
@@ -1505,7 +2871,7 @@
 
 /**
  * Test whether each provider of type
- * SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH can be started and
+ * SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH can be started and
  * stopped with Unicast hardware encoding config
  *
  * Disabled since offload codec checking is not ready
@@ -1513,7 +2879,7 @@
 TEST_P(BluetoothAudioProviderLeAudioInputHardwareAidl,
        DISABLED_StartAndEndLeAudioInputSessionWithInvalidAudioConfiguration) {
   if (!IsOffloadInputSupported()) {
-    return;
+    GTEST_SKIP();
   }
 
   auto lc3_codec_configs =
@@ -1571,16 +2937,16 @@
 
 /**
  * Test whether each provider of type
- * SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH can be started and
- * stopped
+ * SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH can be started
+ * and stopped
  */
 TEST_P(BluetoothAudioProviderLeAudioBroadcastSoftwareAidl,
        OpenLeAudioOutputSoftwareProvider) {}
 
 /**
  * Test whether each provider of type
- * SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH can be started and
- * stopped with different PCM config
+ * SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH can be started
+ * and stopped with different PCM config
  */
 TEST_P(BluetoothAudioProviderLeAudioBroadcastSoftwareAidl,
        StartAndEndLeAudioOutputSessionWithPossiblePcmConfig) {
@@ -1623,6 +2989,8 @@
     BluetoothAudioProviderFactoryAidl::SetUp();
     GetProviderCapabilitiesHelper(
         SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH);
+    GetProviderInfoHelper(
+        SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH);
     OpenProviderHelper(
         SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH);
     ASSERT_TRUE(temp_provider_capabilities_.empty() ||
@@ -1649,6 +3017,42 @@
     return false;
   }
 
+  bool IsBroadcastOffloadProviderInfoSupported() {
+    if (!temp_provider_info_.has_value()) return false;
+    if (temp_provider_info_.value().codecInfos.empty()) return false;
+    // Check if all codec info is of LeAudio type
+    for (auto& codec_info : temp_provider_info_.value().codecInfos) {
+      if (codec_info.transport.getTag() != CodecInfo::Transport::leAudio)
+        return false;
+    }
+    return true;
+  }
+
+  std::vector<Lc3Configuration> GetBroadcastLc3SupportedListFromProviderInfo() {
+    std::vector<Lc3Configuration> le_audio_codec_configs;
+    for (auto& codec_info : temp_provider_info_.value().codecInfos) {
+      // Only gets LC3 codec information
+      if (codec_info.id != CodecId::Core::LC3) continue;
+      // Combine those parameters into one list of Lc3Configuration
+      auto& transport =
+          codec_info.transport.get<CodecInfo::Transport::Tag::leAudio>();
+      for (int32_t samplingFrequencyHz : transport.samplingFrequencyHz) {
+        for (int32_t frameDurationUs : transport.frameDurationUs) {
+          for (int32_t octetsPerFrame : transport.bitdepth) {
+            Lc3Configuration lc3_config = {
+                .samplingFrequencyHz = samplingFrequencyHz,
+                .frameDurationUs = frameDurationUs,
+                .octetsPerFrame = octetsPerFrame,
+            };
+            le_audio_codec_configs.push_back(lc3_config);
+          }
+        }
+      }
+    }
+
+    return le_audio_codec_configs;
+  }
+
   std::vector<Lc3Configuration> GetBroadcastLc3SupportedList(bool supported) {
     std::vector<Lc3Configuration> le_audio_codec_configs;
     if (!supported) {
@@ -1710,6 +3114,68 @@
 /**
  * Test whether each provider of type
  * SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH can be
+ * started and stopped with broadcast hardware encoding config taken from
+ * provider info
+ */
+TEST_P(
+    BluetoothAudioProviderLeAudioBroadcastHardwareAidl,
+    StartAndEndLeAudioBroadcastSessionWithPossibleUnicastConfigFromProviderInfo) {
+  if (GetProviderFactoryInterfaceVersion() <
+      BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+    GTEST_SKIP();
+  }
+  if (!IsBroadcastOffloadProviderInfoSupported()) {
+    return;
+  }
+
+  auto lc3_codec_configs = GetBroadcastLc3SupportedListFromProviderInfo();
+  LeAudioBroadcastConfiguration le_audio_broadcast_config = {
+      .codecType = CodecType::LC3,
+      .streamMap = {},
+  };
+
+  for (auto& lc3_config : lc3_codec_configs) {
+    le_audio_broadcast_config.streamMap.resize(1);
+    le_audio_broadcast_config.streamMap[0]
+        .leAudioCodecConfig.set<LeAudioCodecConfiguration::lc3Config>(
+            lc3_config);
+    le_audio_broadcast_config.streamMap[0].streamHandle = 0x0;
+    le_audio_broadcast_config.streamMap[0].pcmStreamId = 0x0;
+    le_audio_broadcast_config.streamMap[0].audioChannelAllocation = 0x1 << 0;
+
+    DataMQDesc mq_desc;
+    auto aidl_retval = audio_provider_->startSession(
+        audio_port_, AudioConfiguration(le_audio_broadcast_config),
+        latency_modes, &mq_desc);
+
+    ASSERT_TRUE(aidl_retval.isOk());
+    EXPECT_TRUE(audio_provider_->endSession().isOk());
+  }
+}
+
+TEST_P(BluetoothAudioProviderLeAudioBroadcastHardwareAidl,
+       GetEmptyBroadcastConfigurationEmptyCapability) {
+  if (GetProviderFactoryInterfaceVersion() <
+      BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+    GTEST_SKIP();
+  }
+  std::vector<std::optional<LeAudioDeviceCapabilities>> empty_capability;
+  IBluetoothAudioProvider::LeAudioBroadcastConfigurationRequirement
+      empty_requirement;
+
+  IBluetoothAudioProvider::LeAudioBroadcastConfigurationSetting* configuration =
+      new IBluetoothAudioProvider::LeAudioBroadcastConfigurationSetting();
+
+  // Check empty capability for source direction
+  auto aidl_retval = audio_provider_->getLeAudioBroadcastConfiguration(
+      empty_capability, empty_requirement, configuration);
+
+  ASSERT_TRUE(aidl_retval.isOk());
+}
+
+/**
+ * Test whether each provider of type
+ * SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH can be
  * started and stopped with broadcast hardware encoding config
  */
 TEST_P(BluetoothAudioProviderLeAudioBroadcastHardwareAidl,
@@ -1807,8 +3273,8 @@
 
 /**
  * Test whether each provider of type
- * SessionType::A2DP_SOFTWARE_DECODING_DATAPATH can be started and stopped with
- * different PCM config
+ * SessionType::A2DP_SOFTWARE_DECODING_DATAPATH can be started and stopped
+ * with different PCM config
  */
 TEST_P(BluetoothAudioProviderA2dpDecodingSoftwareAidl,
        StartAndEndA2dpDecodingSoftwareSessionWithPossiblePcmConfig) {
@@ -1869,13 +3335,13 @@
 
 /**
  * Test whether each provider of type
- * SessionType::A2DP_HARDWARE_DECODING_DATAPATH can be started and stopped with
- * SBC hardware encoding config
+ * SessionType::A2DP_HARDWARE_DECODING_DATAPATH can be started and stopped
+ * with SBC hardware encoding config
  */
 TEST_P(BluetoothAudioProviderA2dpDecodingHardwareAidl,
        StartAndEndA2dpSbcDecodingHardwareSession) {
   if (!IsOffloadSupported()) {
-    return;
+    GTEST_SKIP();
   }
 
   CodecConfiguration codec_config = {
@@ -1899,13 +3365,13 @@
 
 /**
  * Test whether each provider of type
- * SessionType::A2DP_HARDWARE_DECODING_DATAPATH can be started and stopped with
- * AAC hardware encoding config
+ * SessionType::A2DP_HARDWARE_DECODING_DATAPATH can be started and stopped
+ * with AAC hardware encoding config
  */
 TEST_P(BluetoothAudioProviderA2dpDecodingHardwareAidl,
        StartAndEndA2dpAacDecodingHardwareSession) {
   if (!IsOffloadSupported()) {
-    return;
+    GTEST_SKIP();
   }
 
   CodecConfiguration codec_config = {
@@ -1929,13 +3395,13 @@
 
 /**
  * Test whether each provider of type
- * SessionType::A2DP_HARDWARE_DECODING_DATAPATH can be started and stopped with
- * LDAC hardware encoding config
+ * SessionType::A2DP_HARDWARE_DECODING_DATAPATH can be started and stopped
+ * with LDAC hardware encoding config
  */
 TEST_P(BluetoothAudioProviderA2dpDecodingHardwareAidl,
        StartAndEndA2dpLdacDecodingHardwareSession) {
   if (!IsOffloadSupported()) {
-    return;
+    GTEST_SKIP();
   }
 
   CodecConfiguration codec_config = {
@@ -1959,13 +3425,13 @@
 
 /**
  * Test whether each provider of type
- * SessionType::A2DP_HARDWARE_DECODING_DATAPATH can be started and stopped with
- * Opus hardware encoding config
+ * SessionType::A2DP_HARDWARE_DECODING_DATAPATH can be started and stopped
+ * with Opus hardware encoding config
  */
 TEST_P(BluetoothAudioProviderA2dpDecodingHardwareAidl,
        StartAndEndA2dpOpusDecodingHardwareSession) {
   if (!IsOffloadSupported()) {
-    return;
+    GTEST_SKIP();
   }
 
   CodecConfiguration codec_config = {
@@ -1989,13 +3455,13 @@
 
 /**
  * Test whether each provider of type
- * SessionType::A2DP_HARDWARE_DECODING_DATAPATH can be started and stopped with
- * AptX hardware encoding config
+ * SessionType::A2DP_HARDWARE_DECODING_DATAPATH can be started and stopped
+ * with AptX hardware encoding config
  */
 TEST_P(BluetoothAudioProviderA2dpDecodingHardwareAidl,
        StartAndEndA2dpAptxDecodingHardwareSession) {
   if (!IsOffloadSupported()) {
-    return;
+    GTEST_SKIP();
   }
 
   for (auto codec_type : {CodecType::APTX, CodecType::APTX_HD}) {
@@ -2025,13 +3491,13 @@
 
 /**
  * Test whether each provider of type
- * SessionType::A2DP_HARDWARE_DECODING_DATAPATH can be started and stopped with
- * an invalid codec config
+ * SessionType::A2DP_HARDWARE_DECODING_DATAPATH can be started and stopped
+ * with an invalid codec config
  */
 TEST_P(BluetoothAudioProviderA2dpDecodingHardwareAidl,
        StartAndEndA2dpDecodingHardwareSessionInvalidCodecConfig) {
   if (!IsOffloadSupported()) {
-    return;
+    GTEST_SKIP();
   }
   ASSERT_NE(audio_provider_, nullptr);
 
@@ -2096,6 +3562,12 @@
                              IBluetoothAudioProviderFactory::descriptor)),
                          android::PrintInstanceNameToString);
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BluetoothAudioProviderAidl);
+INSTANTIATE_TEST_SUITE_P(PerInstance, BluetoothAudioProviderAidl,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(
+                             IBluetoothAudioProviderFactory::descriptor)),
+                         android::PrintInstanceNameToString);
+
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
     BluetoothAudioProviderA2dpEncodingSoftwareAidl);
 INSTANTIATE_TEST_SUITE_P(PerInstance,
@@ -2184,6 +3656,29 @@
                              IBluetoothAudioProviderFactory::descriptor)),
                          android::PrintInstanceNameToString);
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+    BluetoothAudioProviderHfpHardwareAidl);
+INSTANTIATE_TEST_SUITE_P(PerInstance, BluetoothAudioProviderHfpHardwareAidl,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(
+                             IBluetoothAudioProviderFactory::descriptor)),
+                         android::PrintInstanceNameToString);
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+    BluetoothAudioProviderHfpSoftwareDecodingAidl);
+INSTANTIATE_TEST_SUITE_P(PerInstance,
+                         BluetoothAudioProviderHfpSoftwareDecodingAidl,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(
+                             IBluetoothAudioProviderFactory::descriptor)),
+                         android::PrintInstanceNameToString);
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+    BluetoothAudioProviderHfpSoftwareEncodingAidl);
+INSTANTIATE_TEST_SUITE_P(PerInstance,
+                         BluetoothAudioProviderHfpSoftwareEncodingAidl,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(
+                             IBluetoothAudioProviderFactory::descriptor)),
+                         android::PrintInstanceNameToString);
+
 int main(int argc, char** argv) {
   ::testing::InitGoogleTest(&argc, argv);
   ABinderProcess_setThreadPoolMaxThreadCount(1);
diff --git a/bluetooth/audio/flags/Android.bp b/bluetooth/audio/flags/Android.bp
new file mode 100644
index 0000000..0d18a4d
--- /dev/null
+++ b/bluetooth/audio/flags/Android.bp
@@ -0,0 +1,12 @@
+aconfig_declarations {
+    name: "btaudiohal_flags",
+    package: "com.android.btaudio.hal.flags",
+    srcs: ["btaudiohal.aconfig"],
+}
+
+cc_aconfig_library {
+    name: "btaudiohal_flags_c_lib",
+    aconfig_declarations: "btaudiohal_flags",
+    vendor: true,
+    host_supported: true,
+}
diff --git a/bluetooth/audio/flags/btaudiohal.aconfig b/bluetooth/audio/flags/btaudiohal.aconfig
new file mode 100644
index 0000000..763777e
--- /dev/null
+++ b/bluetooth/audio/flags/btaudiohal.aconfig
@@ -0,0 +1,8 @@
+package: "com.android.btaudio.hal.flags"
+
+flag {
+    name: "dsa_lea"
+    namespace: "pixel_bluetooth"
+    description: "Flag for DSA Over LEA"
+    bug: "270987427"
+}
diff --git a/bluetooth/audio/utils/Android.bp b/bluetooth/audio/utils/Android.bp
index 8cafb47..c0817f5 100644
--- a/bluetooth/audio/utils/Android.bp
+++ b/bluetooth/audio/utils/Android.bp
@@ -42,12 +42,16 @@
         "aidl_session/BluetoothAudioSession.cpp",
         "aidl_session/HidlToAidlMiddleware.cpp",
         "aidl_session/BluetoothLeAudioCodecsProvider.cpp",
+        "aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.cpp",
     ],
     export_include_dirs: ["aidl_session/"],
     header_libs: [
         "libhardware_headers",
         "libxsdc-utils",
     ],
+    defaults: [
+        "latest_android_hardware_bluetooth_audio_ndk_shared",
+    ],
     shared_libs: [
         "android.hardware.bluetooth.audio@2.0",
         "android.hardware.bluetooth.audio@2.1",
@@ -56,12 +60,25 @@
         "libbinder_ndk",
         "libfmq",
         "liblog",
-        "android.hardware.bluetooth.audio-V3-ndk",
         "libhidlbase",
         "libxml2",
+        "libflatbuffers-cpp",
+        "server_configurable_flags",
+    ],
+    static_libs: [
+        "btaudiohal_flags_c_lib",
     ],
     generated_sources: ["le_audio_codec_capabilities"],
-    generated_headers: ["le_audio_codec_capabilities"],
+    generated_headers: [
+        "le_audio_codec_capabilities",
+        "AIDLLeAudioSetConfigSchemas_h",
+    ],
+    required: [
+        "aidl_audio_set_configurations_bfbs",
+        "aidl_audio_set_configurations_json",
+        "aidl_audio_set_scenarios_bfbs",
+        "aidl_audio_set_scenarios_json",
+    ],
 }
 
 cc_test {
@@ -76,7 +93,7 @@
     shared_libs: [
         "libbase",
         "libbinder_ndk",
-        "android.hardware.bluetooth.audio-V3-ndk",
+        "android.hardware.bluetooth.audio-V4-ndk",
         "libxml2",
     ],
     test_suites: [
@@ -94,4 +111,83 @@
     srcs: ["le_audio_codec_capabilities/le_audio_codec_capabilities.xsd"],
     package_name: "aidl.android.hardware.bluetooth.audio.setting",
     api_dir: "le_audio_codec_capabilities/schema",
+    root_elements: ["leAudioOffloadSetting"],
+}
+
+genrule {
+    name: "AIDLLeAudioSetConfigSchemas_h",
+    tools: [
+        "flatc",
+    ],
+    cmd: "$(location flatc) -I hardware/interfaces/bluetooth/audio/utils/ -o $(genDir) --cpp $(in) ",
+    srcs: [
+        "le_audio_configuration_set/audio_set_configurations.fbs",
+        "le_audio_configuration_set/audio_set_scenarios.fbs",
+    ],
+    out: [
+        "audio_set_configurations_generated.h",
+        "audio_set_scenarios_generated.h",
+    ],
+}
+
+// Binary generation
+genrule {
+    name: "AIDLLeAudioSetScenariosSchema_bfbs",
+    tools: [
+        "flatc",
+    ],
+    cmd: "$(location flatc) -I hardware/interfaces/bluetooth/audio/utils/ -b --schema -o $(genDir) $(in) ",
+    srcs: [
+        "le_audio_configuration_set/audio_set_scenarios.fbs",
+    ],
+    out: [
+        "audio_set_scenarios.bfbs",
+    ],
+}
+
+genrule {
+    name: "AIDLLeAudioSetConfigsSchema_bfbs",
+    tools: [
+        "flatc",
+    ],
+    cmd: "$(location flatc) -I hardware/interfaces/bluetooth/audio/utils/ -b --schema -o $(genDir) $(in) ",
+    srcs: [
+        "le_audio_configuration_set/audio_set_configurations.fbs",
+    ],
+    out: [
+        "audio_set_configurations.bfbs",
+    ],
+}
+
+// Add to prebuilt etc
+prebuilt_etc {
+    name: "aidl_audio_set_scenarios_bfbs",
+    src: ":AIDLLeAudioSetScenariosSchema_bfbs",
+    filename: "aidl_audio_set_scenarios.bfbs",
+    sub_dir: "aidl/le_audio",
+    vendor: true,
+}
+
+prebuilt_etc {
+    name: "aidl_audio_set_scenarios_json",
+    src: "le_audio_configuration_set/audio_set_scenarios.json",
+    filename: "aidl_audio_set_scenarios.json",
+    sub_dir: "aidl/le_audio",
+    vendor: true,
+}
+
+prebuilt_etc {
+    name: "aidl_audio_set_configurations_bfbs",
+    src: ":AIDLLeAudioSetConfigsSchema_bfbs",
+    filename: "aidl_audio_set_configurations.bfbs",
+    sub_dir: "aidl/le_audio",
+    vendor: true,
+}
+
+prebuilt_etc {
+    name: "aidl_audio_set_configurations_json",
+    src: "le_audio_configuration_set/audio_set_configurations.json",
+    filename: "aidl_audio_set_configurations.json",
+    sub_dir: "aidl/le_audio",
+    vendor: true,
 }
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
index 3ed9e07..d37825a 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
@@ -20,8 +20,6 @@
 
 #include <aidl/android/hardware/bluetooth/audio/AacCapabilities.h>
 #include <aidl/android/hardware/bluetooth/audio/AacObjectType.h>
-#include <aidl/android/hardware/bluetooth/audio/AptxAdaptiveLeCapabilities.h>
-#include <aidl/android/hardware/bluetooth/audio/AptxAdaptiveLeConfiguration.h>
 #include <aidl/android/hardware/bluetooth/audio/AptxCapabilities.h>
 #include <aidl/android/hardware/bluetooth/audio/ChannelMode.h>
 #include <aidl/android/hardware/bluetooth/audio/LdacCapabilities.h>
@@ -34,6 +32,7 @@
 #include <aidl/android/hardware/bluetooth/audio/SbcChannelMode.h>
 #include <android-base/logging.h>
 
+#include "BluetoothLeAudioAseConfigurationSettingProvider.h"
 #include "BluetoothLeAudioCodecsProvider.h"
 
 namespace aidl {
@@ -43,7 +42,7 @@
 namespace audio {
 
 static const PcmCapabilities kDefaultSoftwarePcmCapabilities = {
-    .sampleRateHz = {16000, 24000, 32000, 44100, 48000, 88200, 96000},
+    .sampleRateHz = {8000, 16000, 24000, 32000, 44100, 48000, 88200, 96000},
     .channelMode = {ChannelMode::MONO, ChannelMode::STEREO},
     .bitsPerSample = {16, 24, 32},
     .dataIntervalUs = {},
@@ -99,55 +98,8 @@
     {.codecType = CodecType::OPUS, .capabilities = {}}};
 
 std::vector<LeAudioCodecCapabilitiesSetting> kDefaultOffloadLeAudioCapabilities;
-
-static const UnicastCapability kInvalidUnicastCapability = {
-    .codecType = CodecType::UNKNOWN};
-
-static const AptxAdaptiveLeCapabilities
-    kDefaultOffloadAptxAdaptiveLeCapability_48k = {
-        .samplingFrequencyHz = {48000},
-        .frameDurationUs = {10000},
-        .octetsPerFrame = {816}};
-
-static const AptxAdaptiveLeCapabilities
-    kDefaultOffloadAptxAdaptiveLeCapability_96k = {
-        .samplingFrequencyHz = {96000},
-        .frameDurationUs = {10000},
-        .octetsPerFrame = {816}};
-
-static const AptxAdaptiveLeCapabilities
-    kDefaultOffloadAptxAdaptiveLeXCapability_48k = {
-        .samplingFrequencyHz = {48000},
-        .frameDurationUs = {10000},
-        .octetsPerFrame = {816}};
-
-static const AptxAdaptiveLeCapabilities
-    kDefaultOffloadAptxAdaptiveLeXCapability_96k = {
-        .samplingFrequencyHz = {96000},
-        .frameDurationUs = {10000},
-        .octetsPerFrame = {816}};
-
-static const BroadcastCapability kInvalidBroadcastCapability = {
-    .codecType = CodecType::UNKNOWN};
-
-static AudioLocation stereoAudio = static_cast<AudioLocation>(
-    static_cast<uint8_t>(AudioLocation::FRONT_LEFT) |
-    static_cast<uint8_t>(AudioLocation::FRONT_RIGHT));
-
-static const std::vector<AptxAdaptiveLeCapabilities>
-    supportedAptxAdaptiveLeCapabilityList = {
-        kDefaultOffloadAptxAdaptiveLeCapability_48k,
-        kDefaultOffloadAptxAdaptiveLeCapability_96k,
-        kDefaultOffloadAptxAdaptiveLeXCapability_48k,
-        kDefaultOffloadAptxAdaptiveLeXCapability_96k};
-
-// Stores the supported setting of audio location, connected device, and the
-// channel count for each device
-std::vector<std::tuple<AudioLocation, uint8_t, uint8_t>>
-    supportedDeviceSetting = {
-        // Stereo, one connected device for both L and R
-        std::make_tuple(stereoAudio, 1, 2),
-};
+std::unordered_map<SessionType, std::vector<CodecInfo>>
+    kDefaultOffloadLeAudioCodecInfoMap;
 
 template <class T>
 bool BluetoothAudioCodecs::ContainedInVector(
@@ -458,36 +410,41 @@
     kDefaultOffloadLeAudioCapabilities =
         BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities(
             le_audio_offload_setting);
-
-    for (auto [audioLocation, deviceCnt, channelCount] :
-         supportedDeviceSetting) {
-      for (auto capability : supportedAptxAdaptiveLeCapabilityList) {
-        for (auto codec_type :
-             {CodecType::APTX_ADAPTIVE_LE, CodecType::APTX_ADAPTIVE_LEX}) {
-          if (session_type ==
-              SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
-            UnicastCapability aptx_adaptive_le_cap = {
-                .codecType = codec_type,
-                .supportedChannel = audioLocation,
-                .deviceCount = deviceCnt,
-                .channelCountPerDevice = channelCount,
-                .leAudioCodecCapabilities =
-                    UnicastCapability::LeAudioCodecCapabilities(capability),
-            };
-
-            // Adds the capability for encode only
-            kDefaultOffloadLeAudioCapabilities.push_back(
-                {.unicastEncodeCapability = aptx_adaptive_le_cap,
-                 .unicastDecodeCapability = kInvalidUnicastCapability,
-                 .broadcastCapability = kInvalidBroadcastCapability});
-          }
-        }
-      }
-    }
   }
   return kDefaultOffloadLeAudioCapabilities;
 }
 
+std::vector<CodecInfo> BluetoothAudioCodecs::GetLeAudioOffloadCodecInfo(
+    const SessionType& session_type) {
+  if (session_type !=
+          SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
+      session_type !=
+          SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH &&
+      session_type !=
+          SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
+    return std::vector<CodecInfo>();
+  }
+
+  if (kDefaultOffloadLeAudioCodecInfoMap.empty()) {
+    auto le_audio_offload_setting =
+        BluetoothLeAudioCodecsProvider::ParseFromLeAudioOffloadSettingFile();
+    kDefaultOffloadLeAudioCodecInfoMap =
+        BluetoothLeAudioCodecsProvider::GetLeAudioCodecInfo(
+            le_audio_offload_setting);
+  }
+  auto codec_info_map_iter =
+      kDefaultOffloadLeAudioCodecInfoMap.find(session_type);
+  if (codec_info_map_iter == kDefaultOffloadLeAudioCodecInfoMap.end())
+    return std::vector<CodecInfo>();
+  return codec_info_map_iter->second;
+}
+
+std::vector<LeAudioAseConfigurationSetting>
+BluetoothAudioCodecs::GetLeAudioAseConfigurationSettings() {
+  return AudioSetConfigurationProviderJson::
+      GetLeAudioAseConfigurationSettings();
+}
+
 }  // namespace audio
 }  // namespace bluetooth
 }  // namespace hardware
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.h b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.h
index e3d657b..057b9a7 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.h
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.h
@@ -18,6 +18,8 @@
 
 #include <aidl/android/hardware/bluetooth/audio/CodecCapabilities.h>
 #include <aidl/android/hardware/bluetooth/audio/CodecConfiguration.h>
+#include <aidl/android/hardware/bluetooth/audio/CodecInfo.h>
+#include <aidl/android/hardware/bluetooth/audio/IBluetoothAudioProvider.h>
 #include <aidl/android/hardware/bluetooth/audio/LeAudioCodecCapabilitiesSetting.h>
 #include <aidl/android/hardware/bluetooth/audio/LeAudioConfiguration.h>
 #include <aidl/android/hardware/bluetooth/audio/OpusConfiguration.h>
@@ -33,6 +35,9 @@
 namespace bluetooth {
 namespace audio {
 
+using LeAudioAseConfigurationSetting =
+    IBluetoothAudioProvider::LeAudioAseConfigurationSetting;
+
 class BluetoothAudioCodecs {
  public:
   static std::vector<PcmCapabilities> GetSoftwarePcmCapabilities();
@@ -46,6 +51,11 @@
 
   static std::vector<LeAudioCodecCapabilitiesSetting>
   GetLeAudioOffloadCodecCapabilities(const SessionType& session_type);
+  static std::vector<CodecInfo> GetLeAudioOffloadCodecInfo(
+      const SessionType& session_type);
+
+  static std::vector<LeAudioAseConfigurationSetting>
+  GetLeAudioAseConfigurationSettings();
 
  private:
   template <typename T>
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
index 0bcafa3..67ba93c 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
@@ -20,6 +20,7 @@
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
 #include <android/binder_manager.h>
+#include <com_android_btaudio_hal_flags.h>
 #include <hardware/audio.h>
 
 #include "BluetoothAudioSession.h"
@@ -36,6 +37,14 @@
 static constexpr int kWritePollMs = 1;  // polled non-blocking interval
 static constexpr int kReadPollMs = 1;   // polled non-blocking interval
 
+static std::string toString(const std::vector<LatencyMode>& latencies) {
+  std::stringstream latencyModesStr;
+  for (LatencyMode mode : latencies) {
+    latencyModesStr << " " << toString(mode);
+  }
+  return latencyModesStr.str();
+}
+
 BluetoothAudioSession::BluetoothAudioSession(const SessionType& session_type)
     : session_type_(session_type), stack_iface_(nullptr), data_mq_(nullptr) {}
 
@@ -65,6 +74,7 @@
     stack_iface_ = stack_iface;
     latency_modes_ = latency_modes;
     LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+              << " - All LatencyModes=" << toString(latency_modes)
               << ", AudioConfiguration=" << audio_config.toString();
     ReportSessionStatus();
   }
@@ -95,6 +105,8 @@
       case SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH:
       case SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH:
         return AudioConfiguration(CodecConfiguration{});
+      case SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH:
+        return AudioConfiguration(HfpConfiguration{});
       case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH:
       case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH:
         return AudioConfiguration(LeAudioConfiguration{});
@@ -154,6 +166,7 @@
        session_type_ ==
            SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
        session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH ||
+       session_type_ == SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH ||
        (data_mq_ != nullptr && data_mq_->isValid()));
   return stack_iface_ != nullptr && is_mq_valid && audio_config_ != nullptr;
 }
@@ -275,6 +288,8 @@
   bool is_software_session =
       (session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH ||
        session_type_ == SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH ||
+       session_type_ == SessionType::HFP_SOFTWARE_ENCODING_DATAPATH ||
+       session_type_ == SessionType::HFP_SOFTWARE_DECODING_DATAPATH ||
        session_type_ == SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH ||
        session_type_ == SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH ||
        session_type_ ==
@@ -283,6 +298,8 @@
   bool is_offload_a2dp_session =
       (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
        session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH);
+  bool is_offload_hfp_session =
+      session_type_ == SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH;
   bool is_offload_le_audio_unicast_session =
       (session_type_ ==
            SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
@@ -297,7 +314,11 @@
        audio_config_tag == AudioConfiguration::pcmConfig);
   bool is_a2dp_offload_audio_config =
       (is_offload_a2dp_session &&
-       audio_config_tag == AudioConfiguration::a2dpConfig);
+       (audio_config_tag == AudioConfiguration::a2dp ||
+        audio_config_tag == AudioConfiguration::a2dpConfig));
+  bool is_hfp_offload_audio_config =
+      (is_offload_hfp_session &&
+       audio_config_tag == AudioConfiguration::hfpConfig);
   bool is_le_audio_offload_unicast_audio_config =
       (is_offload_le_audio_unicast_session &&
        audio_config_tag == AudioConfiguration::leAudioConfig);
@@ -305,6 +326,7 @@
       (is_offload_le_audio_broadcast_session &&
        audio_config_tag == AudioConfiguration::leAudioBroadcastConfig);
   if (!is_software_audio_config && !is_a2dp_offload_audio_config &&
+      !is_hfp_offload_audio_config &&
       !is_le_audio_offload_unicast_audio_config &&
       !is_le_audio_offload_broadcast_audio_config) {
     return false;
@@ -439,6 +461,9 @@
 }
 
 void BluetoothAudioSession::ReportLowLatencyModeAllowedChanged(bool allowed) {
+  if (session_type_ != SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
+    return;
+  }
   std::lock_guard<std::recursive_mutex> guard(mutex_);
   low_latency_allowed_ = allowed;
   // TODO(b/294498919): Remove this after there is API to update latency mode
@@ -475,14 +500,12 @@
                << " has NO session";
     return false;
   }
-  bool retval = false;
-
   if (!stack_iface_->getPresentationPosition(&presentation_position).isOk()) {
     LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
                  << toString(session_type_) << " failed";
     return false;
   }
-  return retval;
+  return true;
 }
 
 void BluetoothAudioSession::UpdateSourceMetadata(
@@ -588,6 +611,38 @@
                << " has NO session";
     return std::vector<LatencyMode>();
   }
+
+  if (com::android::btaudio::hal::flags::dsa_lea()) {
+    std::vector<LatencyMode> supported_latency_modes;
+    if (session_type_ ==
+        SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
+      for (LatencyMode mode : latency_modes_) {
+        if (mode == LatencyMode::LOW_LATENCY) {
+          // LOW_LATENCY is not supported for LE_HARDWARE_OFFLOAD_ENC sessions
+          continue;
+        }
+        supported_latency_modes.push_back(mode);
+      }
+    } else {
+      for (LatencyMode mode : latency_modes_) {
+        if (!low_latency_allowed_ && mode == LatencyMode::LOW_LATENCY) {
+          // ignore LOW_LATENCY mode if Bluetooth stack doesn't allow
+          continue;
+        }
+        if (mode == LatencyMode::DYNAMIC_SPATIAL_AUDIO_SOFTWARE ||
+            mode == LatencyMode::DYNAMIC_SPATIAL_AUDIO_HARDWARE) {
+          // DSA_SW and DSA_HW only supported for LE_HARDWARE_OFFLOAD_ENC
+          // sessions
+          continue;
+        }
+        supported_latency_modes.push_back(mode);
+      }
+    }
+    LOG(DEBUG) << __func__ << " - Supported LatencyMode="
+               << toString(supported_latency_modes);
+    return supported_latency_modes;
+  }
+
   if (low_latency_allowed_) return latency_modes_;
   std::vector<LatencyMode> modes;
   for (LatencyMode mode : latency_modes_) {
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h b/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h
index 7ae0353..5263222 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h
@@ -84,6 +84,8 @@
       case SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH:
       case SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH:
         return AudioConfiguration(CodecConfiguration{});
+      case SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH:
+        return AudioConfiguration(HfpConfiguration{});
       case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH:
       case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH:
         return AudioConfiguration(LeAudioConfiguration{});
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.cpp b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.cpp
new file mode 100644
index 0000000..5429a8f
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.cpp
@@ -0,0 +1,760 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 STREAM_TO_UINT8(u8, p) \
+  {                            \
+    (u8) = (uint8_t)(*(p));    \
+    (p) += 1;                  \
+  }
+#define STREAM_TO_UINT16(u16, p)                                  \
+  {                                                               \
+    (u16) = ((uint16_t)(*(p)) + (((uint16_t)(*((p) + 1))) << 8)); \
+    (p) += 2;                                                     \
+  }
+#define STREAM_TO_UINT32(u32, p)                                      \
+  {                                                                   \
+    (u32) = (((uint32_t)(*(p))) + ((((uint32_t)(*((p) + 1)))) << 8) + \
+             ((((uint32_t)(*((p) + 2)))) << 16) +                     \
+             ((((uint32_t)(*((p) + 3)))) << 24));                     \
+    (p) += 4;                                                         \
+  }
+
+#define LOG_TAG "BTAudioAseConfigAidl"
+
+#include "BluetoothLeAudioAseConfigurationSettingProvider.h"
+
+#include <aidl/android/hardware/bluetooth/audio/AudioConfiguration.h>
+#include <aidl/android/hardware/bluetooth/audio/AudioContext.h>
+#include <aidl/android/hardware/bluetooth/audio/BluetoothAudioStatus.h>
+#include <aidl/android/hardware/bluetooth/audio/CodecId.h>
+#include <aidl/android/hardware/bluetooth/audio/CodecSpecificCapabilitiesLtv.h>
+#include <aidl/android/hardware/bluetooth/audio/CodecSpecificConfigurationLtv.h>
+#include <aidl/android/hardware/bluetooth/audio/ConfigurationFlags.h>
+#include <aidl/android/hardware/bluetooth/audio/LeAudioAseConfiguration.h>
+#include <aidl/android/hardware/bluetooth/audio/Phy.h>
+#include <android-base/logging.h>
+
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+/* Internal structure definition */
+std::map<std::string,
+         std::tuple<std::vector<std::optional<AseDirectionConfiguration>>,
+                    std::vector<std::optional<AseDirectionConfiguration>>,
+                    ConfigurationFlags>>
+    configurations_;
+
+std::vector<LeAudioAseConfigurationSetting> ase_configuration_settings_;
+
+constexpr uint8_t kIsoDataPathHci = 0x00;
+constexpr uint8_t kIsoDataPathPlatformDefault = 0x01;
+constexpr uint8_t kIsoDataPathDisabled = 0xFF;
+
+constexpr uint8_t kLeAudioDirectionSink = 0x01;
+constexpr uint8_t kLeAudioDirectionSource = 0x02;
+constexpr uint8_t kLeAudioDirectionBoth =
+    kLeAudioDirectionSink | kLeAudioDirectionSource;
+
+/* Sampling Frequencies */
+constexpr uint8_t kLeAudioSamplingFreq8000Hz = 0x01;
+constexpr uint8_t kLeAudioSamplingFreq11025Hz = 0x02;
+constexpr uint8_t kLeAudioSamplingFreq16000Hz = 0x03;
+constexpr uint8_t kLeAudioSamplingFreq22050Hz = 0x04;
+constexpr uint8_t kLeAudioSamplingFreq24000Hz = 0x05;
+constexpr uint8_t kLeAudioSamplingFreq32000Hz = 0x06;
+constexpr uint8_t kLeAudioSamplingFreq44100Hz = 0x07;
+constexpr uint8_t kLeAudioSamplingFreq48000Hz = 0x08;
+constexpr uint8_t kLeAudioSamplingFreq88200Hz = 0x09;
+constexpr uint8_t kLeAudioSamplingFreq96000Hz = 0x0A;
+constexpr uint8_t kLeAudioSamplingFreq176400Hz = 0x0B;
+constexpr uint8_t kLeAudioSamplingFreq192000Hz = 0x0C;
+constexpr uint8_t kLeAudioSamplingFreq384000Hz = 0x0D;
+
+/* Frame Durations */
+constexpr uint8_t kLeAudioCodecFrameDur7500us = 0x00;
+constexpr uint8_t kLeAudioCodecFrameDur10000us = 0x01;
+
+/* Audio Allocations */
+constexpr uint32_t kLeAudioLocationNotAllowed = 0x00000000;
+constexpr uint32_t kLeAudioLocationFrontLeft = 0x00000001;
+constexpr uint32_t kLeAudioLocationFrontRight = 0x00000002;
+constexpr uint32_t kLeAudioLocationFrontCenter = 0x00000004;
+constexpr uint32_t kLeAudioLocationLowFreqEffects1 = 0x00000008;
+constexpr uint32_t kLeAudioLocationBackLeft = 0x00000010;
+constexpr uint32_t kLeAudioLocationBackRight = 0x00000020;
+constexpr uint32_t kLeAudioLocationFrontLeftOfCenter = 0x00000040;
+constexpr uint32_t kLeAudioLocationFrontRightOfCenter = 0x00000080;
+constexpr uint32_t kLeAudioLocationBackCenter = 0x00000100;
+constexpr uint32_t kLeAudioLocationLowFreqEffects2 = 0x00000200;
+constexpr uint32_t kLeAudioLocationSideLeft = 0x00000400;
+constexpr uint32_t kLeAudioLocationSideRight = 0x00000800;
+constexpr uint32_t kLeAudioLocationTopFrontLeft = 0x00001000;
+constexpr uint32_t kLeAudioLocationTopFrontRight = 0x00002000;
+constexpr uint32_t kLeAudioLocationTopFrontCenter = 0x00004000;
+constexpr uint32_t kLeAudioLocationTopCenter = 0x00008000;
+constexpr uint32_t kLeAudioLocationTopBackLeft = 0x00010000;
+constexpr uint32_t kLeAudioLocationTopBackRight = 0x00020000;
+constexpr uint32_t kLeAudioLocationTopSideLeft = 0x00040000;
+constexpr uint32_t kLeAudioLocationTopSideRight = 0x00080000;
+constexpr uint32_t kLeAudioLocationTopBackCenter = 0x00100000;
+constexpr uint32_t kLeAudioLocationBottomFrontCenter = 0x00200000;
+constexpr uint32_t kLeAudioLocationBottomFrontLeft = 0x00400000;
+constexpr uint32_t kLeAudioLocationBottomFrontRight = 0x00800000;
+constexpr uint32_t kLeAudioLocationFrontLeftWide = 0x01000000;
+constexpr uint32_t kLeAudioLocationFrontRightWide = 0x02000000;
+constexpr uint32_t kLeAudioLocationLeftSurround = 0x04000000;
+constexpr uint32_t kLeAudioLocationRightSurround = 0x08000000;
+
+constexpr uint32_t kLeAudioLocationAnyLeft =
+    kLeAudioLocationFrontLeft | kLeAudioLocationBackLeft |
+    kLeAudioLocationFrontLeftOfCenter | kLeAudioLocationSideLeft |
+    kLeAudioLocationTopFrontLeft | kLeAudioLocationTopBackLeft |
+    kLeAudioLocationTopSideLeft | kLeAudioLocationBottomFrontLeft |
+    kLeAudioLocationFrontLeftWide | kLeAudioLocationLeftSurround;
+
+constexpr uint32_t kLeAudioLocationAnyRight =
+    kLeAudioLocationFrontRight | kLeAudioLocationBackRight |
+    kLeAudioLocationFrontRightOfCenter | kLeAudioLocationSideRight |
+    kLeAudioLocationTopFrontRight | kLeAudioLocationTopBackRight |
+    kLeAudioLocationTopSideRight | kLeAudioLocationBottomFrontRight |
+    kLeAudioLocationFrontRightWide | kLeAudioLocationRightSurround;
+
+constexpr uint32_t kLeAudioLocationStereo =
+    kLeAudioLocationFrontLeft | kLeAudioLocationFrontRight;
+
+/* Octets Per Frame */
+constexpr uint16_t kLeAudioCodecFrameLen30 = 30;
+constexpr uint16_t kLeAudioCodecFrameLen40 = 40;
+constexpr uint16_t kLeAudioCodecFrameLen60 = 60;
+constexpr uint16_t kLeAudioCodecFrameLen80 = 80;
+constexpr uint16_t kLeAudioCodecFrameLen100 = 100;
+constexpr uint16_t kLeAudioCodecFrameLen120 = 120;
+
+/* Helper map for matching various sampling frequency notations */
+const std::map<uint8_t, CodecSpecificConfigurationLtv::SamplingFrequency>
+    sampling_freq_map = {
+        {kLeAudioSamplingFreq8000Hz,
+         CodecSpecificConfigurationLtv::SamplingFrequency::HZ8000},
+        {kLeAudioSamplingFreq16000Hz,
+         CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000},
+        {kLeAudioSamplingFreq24000Hz,
+         CodecSpecificConfigurationLtv::SamplingFrequency::HZ24000},
+        {kLeAudioSamplingFreq32000Hz,
+         CodecSpecificConfigurationLtv::SamplingFrequency::HZ32000},
+        {kLeAudioSamplingFreq44100Hz,
+         CodecSpecificConfigurationLtv::SamplingFrequency::HZ44100},
+        {kLeAudioSamplingFreq48000Hz,
+         CodecSpecificConfigurationLtv::SamplingFrequency::HZ48000}};
+
+/* Helper map for matching various frame durations notations */
+const std::map<uint8_t, CodecSpecificConfigurationLtv::FrameDuration>
+    frame_duration_map = {
+        {kLeAudioCodecFrameDur7500us,
+         CodecSpecificConfigurationLtv::FrameDuration::US7500},
+        {kLeAudioCodecFrameDur10000us,
+         CodecSpecificConfigurationLtv::FrameDuration::US10000}};
+
+/* Helper map for matching various audio channel allocation notations */
+std::map<uint32_t, uint32_t> audio_channel_allocation_map = {
+    {kLeAudioLocationNotAllowed,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::NOT_ALLOWED},
+    {kLeAudioLocationFrontLeft,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT},
+    {kLeAudioLocationFrontRight,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT},
+    {kLeAudioLocationFrontCenter,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_CENTER},
+    {kLeAudioLocationLowFreqEffects1,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::
+         LOW_FREQUENCY_EFFECTS_1},
+    {kLeAudioLocationBackLeft,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::BACK_LEFT},
+    {kLeAudioLocationBackRight,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::BACK_RIGHT},
+    {kLeAudioLocationFrontLeftOfCenter,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::
+         FRONT_LEFT_OF_CENTER},
+    {kLeAudioLocationFrontRightOfCenter,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::
+         FRONT_RIGHT_OF_CENTER},
+    {kLeAudioLocationBackCenter,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::BACK_CENTER},
+    {kLeAudioLocationLowFreqEffects2,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::
+         LOW_FREQUENCY_EFFECTS_2},
+    {kLeAudioLocationSideLeft,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::SIDE_LEFT},
+    {kLeAudioLocationSideRight,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::SIDE_RIGHT},
+    {kLeAudioLocationTopFrontLeft,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_FRONT_LEFT},
+    {kLeAudioLocationTopFrontRight,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_FRONT_RIGHT},
+    {kLeAudioLocationTopFrontCenter,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_FRONT_CENTER},
+    {kLeAudioLocationTopCenter,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_CENTER},
+    {kLeAudioLocationTopBackLeft,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_BACK_LEFT},
+    {kLeAudioLocationTopBackRight,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_BACK_RIGHT},
+    {kLeAudioLocationTopSideLeft,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_SIDE_LEFT},
+    {kLeAudioLocationTopSideRight,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_SIDE_RIGHT},
+    {kLeAudioLocationTopBackCenter,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_BACK_CENTER},
+    {kLeAudioLocationBottomFrontCenter,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::
+         BOTTOM_FRONT_CENTER},
+    {kLeAudioLocationBottomFrontLeft,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::BOTTOM_FRONT_LEFT},
+    {kLeAudioLocationBottomFrontRight,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::BOTTOM_FRONT_RIGHT},
+    {kLeAudioLocationFrontLeftWide,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT_WIDE},
+    {kLeAudioLocationFrontRightWide,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT_WIDE},
+    {kLeAudioLocationLeftSurround,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::LEFT_SURROUND},
+    {kLeAudioLocationRightSurround,
+     CodecSpecificConfigurationLtv::AudioChannelAllocation::RIGHT_SURROUND},
+};
+
+static const std::vector<
+    std::pair<const char* /*schema*/, const char* /*content*/>>
+    kLeAudioSetConfigs = {{"/vendor/etc/aidl/le_audio/"
+                           "aidl_audio_set_configurations.bfbs",
+                           "/vendor/etc/aidl/le_audio/"
+                           "aidl_audio_set_configurations.json"}};
+static const std::vector<
+    std::pair<const char* /*schema*/, const char* /*content*/>>
+    kLeAudioSetScenarios = {{"/vendor/etc/aidl/le_audio/"
+                             "aidl_audio_set_scenarios.bfbs",
+                             "/vendor/etc/aidl/le_audio/"
+                             "aidl_audio_set_scenarios.json"}};
+
+/* Implementation */
+
+std::vector<LeAudioAseConfigurationSetting>
+AudioSetConfigurationProviderJson::GetLeAudioAseConfigurationSettings() {
+  AudioSetConfigurationProviderJson::LoadAudioSetConfigurationProviderJson();
+  return ase_configuration_settings_;
+}
+
+void AudioSetConfigurationProviderJson::
+    LoadAudioSetConfigurationProviderJson() {
+  if (configurations_.empty() || ase_configuration_settings_.empty()) {
+    ase_configuration_settings_.clear();
+    configurations_.clear();
+    auto loaded = LoadContent(kLeAudioSetConfigs, kLeAudioSetScenarios,
+                              CodecLocation::HOST);
+    if (!loaded)
+      LOG(ERROR) << ": Unable to load le audio set configuration files.";
+  } else
+    LOG(INFO) << ": Reusing loaded le audio set configuration";
+}
+
+const le_audio::CodecSpecificConfiguration*
+AudioSetConfigurationProviderJson::LookupCodecSpecificParam(
+    const flatbuffers::Vector<flatbuffers::Offset<
+        le_audio::CodecSpecificConfiguration>>* flat_codec_specific_params,
+    le_audio::CodecSpecificLtvGenericTypes type) {
+  auto it = std::find_if(
+      flat_codec_specific_params->cbegin(), flat_codec_specific_params->cend(),
+      [&type](const auto& csc) { return (csc->type() == type); });
+  return (it != flat_codec_specific_params->cend()) ? *it : nullptr;
+}
+
+void AudioSetConfigurationProviderJson::populateAudioChannelAllocation(
+    CodecSpecificConfigurationLtv::AudioChannelAllocation&
+        audio_channel_allocation,
+    uint32_t audio_location) {
+  audio_channel_allocation.bitmask = 0;
+  for (auto [allocation, bitmask] : audio_channel_allocation_map) {
+    if (audio_location & allocation)
+      audio_channel_allocation.bitmask |= bitmask;
+  }
+}
+
+void AudioSetConfigurationProviderJson::populateConfigurationData(
+    LeAudioAseConfiguration& ase,
+    const flatbuffers::Vector<
+        flatbuffers::Offset<le_audio::CodecSpecificConfiguration>>*
+        flat_codec_specific_params) {
+  uint8_t sampling_frequency = 0;
+  uint8_t frame_duration = 0;
+  uint32_t audio_channel_allocation = 0;
+  uint16_t octets_per_codec_frame = 0;
+  uint8_t codec_frames_blocks_per_sdu = 0;
+
+  auto param = LookupCodecSpecificParam(
+      flat_codec_specific_params,
+      le_audio::CodecSpecificLtvGenericTypes_SUPPORTED_SAMPLING_FREQUENCY);
+  if (param) {
+    auto ptr = param->compound_value()->value()->data();
+    STREAM_TO_UINT8(sampling_frequency, ptr);
+  }
+
+  param = LookupCodecSpecificParam(
+      flat_codec_specific_params,
+      le_audio::CodecSpecificLtvGenericTypes_SUPPORTED_FRAME_DURATION);
+  if (param) {
+    auto ptr = param->compound_value()->value()->data();
+    STREAM_TO_UINT8(frame_duration, ptr);
+  }
+
+  param = LookupCodecSpecificParam(
+      flat_codec_specific_params,
+      le_audio::
+          CodecSpecificLtvGenericTypes_SUPPORTED_AUDIO_CHANNEL_ALLOCATION);
+  if (param) {
+    auto ptr = param->compound_value()->value()->data();
+    STREAM_TO_UINT32(audio_channel_allocation, ptr);
+  }
+
+  param = LookupCodecSpecificParam(
+      flat_codec_specific_params,
+      le_audio::CodecSpecificLtvGenericTypes_SUPPORTED_OCTETS_PER_CODEC_FRAME);
+  if (param) {
+    auto ptr = param->compound_value()->value()->data();
+    STREAM_TO_UINT16(octets_per_codec_frame, ptr);
+  }
+
+  param = LookupCodecSpecificParam(
+      flat_codec_specific_params,
+      le_audio::
+          CodecSpecificLtvGenericTypes_SUPPORTED_CODEC_FRAME_BLOCKS_PER_SDU);
+  if (param) {
+    auto ptr = param->compound_value()->value()->data();
+    STREAM_TO_UINT8(codec_frames_blocks_per_sdu, ptr);
+  }
+
+  // Make the correct value
+  ase.codecConfiguration = std::vector<CodecSpecificConfigurationLtv>();
+
+  auto sampling_freq_it = sampling_freq_map.find(sampling_frequency);
+  if (sampling_freq_it != sampling_freq_map.end())
+    ase.codecConfiguration.push_back(sampling_freq_it->second);
+  auto frame_duration_it = frame_duration_map.find(frame_duration);
+  if (frame_duration_it != frame_duration_map.end())
+    ase.codecConfiguration.push_back(frame_duration_it->second);
+
+  CodecSpecificConfigurationLtv::AudioChannelAllocation channel_allocation;
+  populateAudioChannelAllocation(channel_allocation, audio_channel_allocation);
+  ase.codecConfiguration.push_back(channel_allocation);
+
+  auto octet_structure = CodecSpecificConfigurationLtv::OctetsPerCodecFrame();
+  octet_structure.value = octets_per_codec_frame;
+  ase.codecConfiguration.push_back(octet_structure);
+
+  auto frame_sdu_structure =
+      CodecSpecificConfigurationLtv::CodecFrameBlocksPerSDU();
+  frame_sdu_structure.value = codec_frames_blocks_per_sdu;
+  ase.codecConfiguration.push_back(frame_sdu_structure);
+  // TODO: Channel count
+}
+
+void AudioSetConfigurationProviderJson::populateAseConfiguration(
+    LeAudioAseConfiguration& ase,
+    const le_audio::AudioSetSubConfiguration* flat_subconfig,
+    const le_audio::QosConfiguration* qos_cfg) {
+  // Target latency
+  switch (qos_cfg->target_latency()) {
+    case le_audio::AudioSetConfigurationTargetLatency::
+        AudioSetConfigurationTargetLatency_BALANCED_RELIABILITY:
+      ase.targetLatency =
+          LeAudioAseConfiguration::TargetLatency::BALANCED_LATENCY_RELIABILITY;
+      break;
+    case le_audio::AudioSetConfigurationTargetLatency::
+        AudioSetConfigurationTargetLatency_HIGH_RELIABILITY:
+      ase.targetLatency =
+          LeAudioAseConfiguration::TargetLatency::HIGHER_RELIABILITY;
+      break;
+    case le_audio::AudioSetConfigurationTargetLatency::
+        AudioSetConfigurationTargetLatency_LOW:
+      ase.targetLatency = LeAudioAseConfiguration::TargetLatency::LOWER;
+      break;
+    default:
+      ase.targetLatency = LeAudioAseConfiguration::TargetLatency::UNDEFINED;
+      break;
+  };
+
+  ase.targetPhy = Phy::TWO_M;
+  // Making CodecId
+  if (flat_subconfig->codec_id()->coding_format() ==
+      (uint8_t)CodecId::Core::LC3) {
+    ase.codecId = CodecId::Core::LC3;
+  } else {
+    auto vendorC = CodecId::Vendor();
+    vendorC.codecId = flat_subconfig->codec_id()->vendor_codec_id();
+    vendorC.id = flat_subconfig->codec_id()->vendor_company_id();
+    ase.codecId = vendorC;
+  }
+  // Codec configuration data
+  populateConfigurationData(ase, flat_subconfig->codec_configuration());
+}
+
+void AudioSetConfigurationProviderJson::populateAseQosConfiguration(
+    LeAudioAseQosConfiguration& qos,
+    const le_audio::QosConfiguration* qos_cfg) {
+  qos.maxTransportLatencyMs = qos_cfg->max_transport_latency();
+  qos.retransmissionNum = qos_cfg->retransmission_number();
+}
+
+// Parse into AseDirectionConfiguration
+AseDirectionConfiguration
+AudioSetConfigurationProviderJson::SetConfigurationFromFlatSubconfig(
+    const le_audio::AudioSetSubConfiguration* flat_subconfig,
+    const le_audio::QosConfiguration* qos_cfg, CodecLocation location) {
+  AseDirectionConfiguration direction_conf;
+
+  LeAudioAseConfiguration ase;
+  LeAudioAseQosConfiguration qos;
+  LeAudioDataPathConfiguration path;
+
+  // Translate into LeAudioAseConfiguration
+  populateAseConfiguration(ase, flat_subconfig, qos_cfg);
+
+  // Translate into LeAudioAseQosConfiguration
+  populateAseQosConfiguration(qos, qos_cfg);
+
+  // Translate location to data path id
+  switch (location) {
+    case CodecLocation::ADSP:
+      path.isoDataPathConfiguration.isTransparent = true;
+      path.dataPathId = kIsoDataPathPlatformDefault;
+      break;
+    case CodecLocation::HOST:
+      path.isoDataPathConfiguration.isTransparent = true;
+      path.dataPathId = kIsoDataPathHci;
+      break;
+    case CodecLocation::CONTROLLER:
+      path.isoDataPathConfiguration.isTransparent = false;
+      path.dataPathId = kIsoDataPathPlatformDefault;
+      break;
+  }
+
+  direction_conf.aseConfiguration = ase;
+  direction_conf.qosConfiguration = qos;
+  direction_conf.dataPathConfiguration = path;
+
+  return direction_conf;
+}
+
+// Parse into AseDirectionConfiguration and the ConfigurationFlags
+// and put them in the given list.
+void AudioSetConfigurationProviderJson::processSubconfig(
+    const le_audio::AudioSetSubConfiguration* subconfig,
+    const le_audio::QosConfiguration* qos_cfg,
+    std::vector<std::optional<AseDirectionConfiguration>>&
+        directionAseConfiguration,
+    CodecLocation location) {
+  directionAseConfiguration.push_back(
+      SetConfigurationFromFlatSubconfig(subconfig, qos_cfg, location));
+}
+
+void AudioSetConfigurationProviderJson::PopulateAseConfigurationFromFlat(
+    const le_audio::AudioSetConfiguration* flat_cfg,
+    std::vector<const le_audio::CodecConfiguration*>* codec_cfgs,
+    std::vector<const le_audio::QosConfiguration*>* qos_cfgs,
+    CodecLocation location,
+    std::vector<std::optional<AseDirectionConfiguration>>&
+        sourceAseConfiguration,
+    std::vector<std::optional<AseDirectionConfiguration>>& sinkAseConfiguration,
+    ConfigurationFlags& /*configurationFlags*/) {
+  if (flat_cfg == nullptr) {
+    LOG(ERROR) << "flat_cfg cannot be null";
+    return;
+  }
+  std::string codec_config_key = flat_cfg->codec_config_name()->str();
+  auto* qos_config_key_array = flat_cfg->qos_config_name();
+
+  constexpr std::string_view default_qos = "QoS_Config_Balanced_Reliability";
+
+  std::string qos_sink_key(default_qos);
+  std::string qos_source_key(default_qos);
+
+  /* We expect maximum two QoS settings. First for Sink and second for Source
+   */
+  if (qos_config_key_array->size() > 0) {
+    qos_sink_key = qos_config_key_array->Get(0)->str();
+    if (qos_config_key_array->size() > 1) {
+      qos_source_key = qos_config_key_array->Get(1)->str();
+    } else {
+      qos_source_key = qos_sink_key;
+    }
+  }
+
+  LOG(INFO) << "Audio set config " << flat_cfg->name()->c_str()
+            << ": codec config " << codec_config_key.c_str() << ", qos_sink "
+            << qos_sink_key.c_str() << ", qos_source "
+            << qos_source_key.c_str();
+
+  // Find the first qos config that match the name
+  const le_audio::QosConfiguration* qos_sink_cfg = nullptr;
+  for (auto i = qos_cfgs->begin(); i != qos_cfgs->end(); ++i) {
+    if ((*i)->name()->str() == qos_sink_key) {
+      qos_sink_cfg = *i;
+      break;
+    }
+  }
+
+  const le_audio::QosConfiguration* qos_source_cfg = nullptr;
+  for (auto i = qos_cfgs->begin(); i != qos_cfgs->end(); ++i) {
+    if ((*i)->name()->str() == qos_source_key) {
+      qos_source_cfg = *i;
+      break;
+    }
+  }
+
+  // First codec_cfg with the same name
+  const le_audio::CodecConfiguration* codec_cfg = nullptr;
+  for (auto i = codec_cfgs->begin(); i != codec_cfgs->end(); ++i) {
+    if ((*i)->name()->str() == codec_config_key) {
+      codec_cfg = *i;
+      break;
+    }
+  }
+
+  // Process each subconfig and put it into the correct list
+  if (codec_cfg != nullptr && codec_cfg->subconfigurations()) {
+    /* Load subconfigurations */
+    for (auto subconfig : *codec_cfg->subconfigurations()) {
+      if (subconfig->direction() == kLeAudioDirectionSink) {
+        processSubconfig(subconfig, qos_sink_cfg, sinkAseConfiguration,
+                         location);
+      } else {
+        processSubconfig(subconfig, qos_source_cfg, sourceAseConfiguration,
+                         location);
+      }
+    }
+  } else {
+    if (codec_cfg == nullptr) {
+      LOG(ERROR) << "No codec config matching key " << codec_config_key.c_str()
+                 << " found";
+    } else {
+      LOG(ERROR) << "Configuration '" << flat_cfg->name()->c_str()
+                 << "' has no valid subconfigurations.";
+    }
+  }
+
+  // TODO: Populate information for ConfigurationFlags
+}
+
+bool AudioSetConfigurationProviderJson::LoadConfigurationsFromFiles(
+    const char* schema_file, const char* content_file, CodecLocation location) {
+  flatbuffers::Parser configurations_parser_;
+  std::string configurations_schema_binary_content;
+  bool ok = flatbuffers::LoadFile(schema_file, true,
+                                  &configurations_schema_binary_content);
+  LOG(INFO) << __func__ << ": Loading file " << schema_file;
+  if (!ok) return ok;
+
+  /* Load the binary schema */
+  ok = configurations_parser_.Deserialize(
+      (uint8_t*)configurations_schema_binary_content.c_str(),
+      configurations_schema_binary_content.length());
+  if (!ok) return ok;
+
+  /* Load the content from JSON */
+  std::string configurations_json_content;
+  LOG(INFO) << __func__ << ": Loading file " << content_file;
+  ok = flatbuffers::LoadFile(content_file, false, &configurations_json_content);
+  if (!ok) return ok;
+
+  /* Parse */
+  LOG(INFO) << __func__ << ": Parse JSON content";
+  ok = configurations_parser_.Parse(configurations_json_content.c_str());
+  if (!ok) return ok;
+
+  /* Import from flatbuffers */
+  LOG(INFO) << __func__ << ": Build flat buffer structure";
+  auto configurations_root = le_audio::GetAudioSetConfigurations(
+      configurations_parser_.builder_.GetBufferPointer());
+  if (!configurations_root) return false;
+
+  auto flat_qos_configs = configurations_root->qos_configurations();
+  if ((flat_qos_configs == nullptr) || (flat_qos_configs->size() == 0))
+    return false;
+
+  LOG(DEBUG) << ": Updating " << flat_qos_configs->size()
+             << " qos config entries.";
+  std::vector<const le_audio::QosConfiguration*> qos_cfgs;
+  for (auto const& flat_qos_cfg : *flat_qos_configs) {
+    qos_cfgs.push_back(flat_qos_cfg);
+  }
+
+  auto flat_codec_configs = configurations_root->codec_configurations();
+  if ((flat_codec_configs == nullptr) || (flat_codec_configs->size() == 0))
+    return false;
+
+  LOG(DEBUG) << ": Updating " << flat_codec_configs->size()
+             << " codec config entries.";
+  std::vector<const le_audio::CodecConfiguration*> codec_cfgs;
+  for (auto const& flat_codec_cfg : *flat_codec_configs) {
+    codec_cfgs.push_back(flat_codec_cfg);
+  }
+
+  auto flat_configs = configurations_root->configurations();
+  if ((flat_configs == nullptr) || (flat_configs->size() == 0)) return false;
+
+  LOG(DEBUG) << ": Updating " << flat_configs->size() << " config entries.";
+  for (auto const& flat_cfg : *flat_configs) {
+    // Create 3 vector to use
+    std::vector<std::optional<AseDirectionConfiguration>>
+        sourceAseConfiguration;
+    std::vector<std::optional<AseDirectionConfiguration>> sinkAseConfiguration;
+    ConfigurationFlags configurationFlags;
+    PopulateAseConfigurationFromFlat(flat_cfg, &codec_cfgs, &qos_cfgs, location,
+                                     sourceAseConfiguration,
+                                     sinkAseConfiguration, configurationFlags);
+    if (sourceAseConfiguration.empty() && sinkAseConfiguration.empty())
+      continue;
+    configurations_[flat_cfg->name()->str()] = std::make_tuple(
+        sourceAseConfiguration, sinkAseConfiguration, configurationFlags);
+  }
+
+  return true;
+}
+
+bool AudioSetConfigurationProviderJson::LoadScenariosFromFiles(
+    const char* schema_file, const char* content_file) {
+  flatbuffers::Parser scenarios_parser_;
+  std::string scenarios_schema_binary_content;
+  bool ok = flatbuffers::LoadFile(schema_file, true,
+                                  &scenarios_schema_binary_content);
+  LOG(INFO) << __func__ << ": Loading file " << schema_file;
+  if (!ok) return ok;
+
+  /* Load the binary schema */
+  ok = scenarios_parser_.Deserialize(
+      (uint8_t*)scenarios_schema_binary_content.c_str(),
+      scenarios_schema_binary_content.length());
+  if (!ok) return ok;
+
+  /* Load the content from JSON */
+  LOG(INFO) << __func__ << ": Loading file " << content_file;
+  std::string scenarios_json_content;
+  ok = flatbuffers::LoadFile(content_file, false, &scenarios_json_content);
+  if (!ok) return ok;
+
+  /* Parse */
+  LOG(INFO) << __func__ << ": Parse json content";
+  ok = scenarios_parser_.Parse(scenarios_json_content.c_str());
+  if (!ok) return ok;
+
+  /* Import from flatbuffers */
+  LOG(INFO) << __func__ << ": Build flat buffer structure";
+  auto scenarios_root = le_audio::GetAudioSetScenarios(
+      scenarios_parser_.builder_.GetBufferPointer());
+  if (!scenarios_root) return false;
+
+  auto flat_scenarios = scenarios_root->scenarios();
+  if ((flat_scenarios == nullptr) || (flat_scenarios->size() == 0))
+    return false;
+
+  LOG(INFO) << __func__ << ": Turn flat buffer into structure";
+  AudioContext media_context = AudioContext();
+  media_context.bitmask =
+      (AudioContext::ALERTS | AudioContext::INSTRUCTIONAL |
+       AudioContext::NOTIFICATIONS | AudioContext::EMERGENCY_ALARM |
+       AudioContext::UNSPECIFIED | AudioContext::MEDIA);
+
+  AudioContext conversational_context = AudioContext();
+  conversational_context.bitmask =
+      (AudioContext::RINGTONE_ALERTS | AudioContext::CONVERSATIONAL);
+
+  AudioContext live_context = AudioContext();
+  live_context.bitmask = AudioContext::LIVE_AUDIO;
+
+  AudioContext game_context = AudioContext();
+  game_context.bitmask = AudioContext::GAME;
+
+  AudioContext voice_assistants_context = AudioContext();
+  voice_assistants_context.bitmask = AudioContext::VOICE_ASSISTANTS;
+
+  LOG(DEBUG) << "Updating " << flat_scenarios->size() << " scenarios.";
+  for (auto const& scenario : *flat_scenarios) {
+    LOG(DEBUG) << "Scenario " << scenario->name()->c_str()
+               << " configs: " << scenario->configurations()->size();
+
+    if (!scenario->configurations()) continue;
+    std::string scenario_name = scenario->name()->c_str();
+    AudioContext context;
+    if (scenario_name == "Media")
+      context = AudioContext(media_context);
+    else if (scenario_name == "Conversational")
+      context = AudioContext(conversational_context);
+    else if (scenario_name == "Live")
+      context = AudioContext(live_context);
+    else if (scenario_name == "Game")
+      context = AudioContext(game_context);
+    else if (scenario_name == "VoiceAssistants")
+      context = AudioContext(voice_assistants_context);
+
+    for (auto it = scenario->configurations()->begin();
+         it != scenario->configurations()->end(); ++it) {
+      auto config_name = it->str();
+      auto configuration = configurations_.find(config_name);
+      if (configuration == configurations_.end()) continue;
+      LOG(DEBUG) << "Getting configuration with name: " << config_name;
+      auto [source, sink, flags] = configuration->second;
+      // Each configuration will create a LeAudioAseConfigurationSetting
+      // with the same {context, packing}
+      // and different data
+      LeAudioAseConfigurationSetting setting;
+      setting.audioContext = context;
+      // TODO: Packing
+      setting.sourceAseConfiguration = source;
+      setting.sinkAseConfiguration = sink;
+      setting.flags = flags;
+      // Add to list of setting
+      LOG(DEBUG) << "Pushing configuration to list: " << config_name;
+      ase_configuration_settings_.push_back(setting);
+    }
+  }
+
+  return true;
+}
+
+bool AudioSetConfigurationProviderJson::LoadContent(
+    std::vector<std::pair<const char* /*schema*/, const char* /*content*/>>
+        config_files,
+    std::vector<std::pair<const char* /*schema*/, const char* /*content*/>>
+        scenario_files,
+    CodecLocation location) {
+  for (auto [schema, content] : config_files) {
+    if (!LoadConfigurationsFromFiles(schema, content, location)) return false;
+  }
+
+  for (auto [schema, content] : scenario_files) {
+    if (!LoadScenariosFromFiles(schema, content)) return false;
+  }
+  return true;
+}
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.h b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.h
new file mode 100644
index 0000000..ce91fca
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.h
@@ -0,0 +1,125 @@
+
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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/bluetooth/audio/IBluetoothAudioProvider.h>
+
+#include <map>
+#include <mutex>
+#include <optional>
+#include <string>
+#include <string_view>
+#include <tuple>
+
+#include "audio_set_configurations_generated.h"
+#include "audio_set_scenarios_generated.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+using LeAudioAseConfigurationSetting =
+    IBluetoothAudioProvider::LeAudioAseConfigurationSetting;
+using AseDirectionConfiguration = IBluetoothAudioProvider::
+    LeAudioAseConfigurationSetting::AseDirectionConfiguration;
+using LeAudioAseQosConfiguration =
+    IBluetoothAudioProvider::LeAudioAseQosConfiguration;
+using LeAudioDataPathConfiguration =
+    IBluetoothAudioProvider::LeAudioDataPathConfiguration;
+
+enum class CodecLocation {
+  HOST,
+  ADSP,
+  CONTROLLER,
+};
+
+class AudioSetConfigurationProviderJson {
+ public:
+  static std::vector<LeAudioAseConfigurationSetting>
+  GetLeAudioAseConfigurationSettings();
+
+ private:
+  static void LoadAudioSetConfigurationProviderJson();
+
+  static const le_audio::CodecSpecificConfiguration* LookupCodecSpecificParam(
+      const flatbuffers::Vector<flatbuffers::Offset<
+          le_audio::CodecSpecificConfiguration>>* flat_codec_specific_params,
+      le_audio::CodecSpecificLtvGenericTypes type);
+
+  static void populateAudioChannelAllocation(
+      CodecSpecificConfigurationLtv::AudioChannelAllocation&
+          audio_channel_allocation,
+      uint32_t audio_location);
+
+  static void populateConfigurationData(
+      LeAudioAseConfiguration& ase,
+      const flatbuffers::Vector<
+          flatbuffers::Offset<le_audio::CodecSpecificConfiguration>>*
+          flat_codec_specific_params);
+
+  static void populateAseConfiguration(
+      LeAudioAseConfiguration& ase,
+      const le_audio::AudioSetSubConfiguration* flat_subconfig,
+      const le_audio::QosConfiguration* qos_cfg);
+
+  static void populateAseQosConfiguration(
+      LeAudioAseQosConfiguration& qos,
+      const le_audio::QosConfiguration* qos_cfg);
+
+  static AseDirectionConfiguration SetConfigurationFromFlatSubconfig(
+      const le_audio::AudioSetSubConfiguration* flat_subconfig,
+      const le_audio::QosConfiguration* qos_cfg, CodecLocation location);
+
+  static void processSubconfig(
+      const le_audio::AudioSetSubConfiguration* subconfig,
+      const le_audio::QosConfiguration* qos_cfg,
+      std::vector<std::optional<AseDirectionConfiguration>>&
+          directionAseConfiguration,
+      CodecLocation location);
+
+  static void PopulateAseConfigurationFromFlat(
+      const le_audio::AudioSetConfiguration* flat_cfg,
+      std::vector<const le_audio::CodecConfiguration*>* codec_cfgs,
+      std::vector<const le_audio::QosConfiguration*>* qos_cfgs,
+      CodecLocation location,
+      std::vector<std::optional<AseDirectionConfiguration>>&
+          sourceAseConfiguration,
+      std::vector<std::optional<AseDirectionConfiguration>>&
+          sinkAseConfiguration,
+      ConfigurationFlags& configurationFlags);
+
+  static bool LoadConfigurationsFromFiles(const char* schema_file,
+                                          const char* content_file,
+                                          CodecLocation location);
+
+  static bool LoadScenariosFromFiles(const char* schema_file,
+                                     const char* content_file);
+
+  static bool LoadContent(
+      std::vector<std::pair<const char* /*schema*/, const char* /*content*/>>
+          config_files,
+      std::vector<std::pair<const char* /*schema*/, const char* /*content*/>>
+          scenario_files,
+      CodecLocation location);
+};
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp
index 0a804bb..473777c 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp
@@ -14,6 +14,11 @@
  * limitations under the License.
  */
 
+#include <set>
+
+#include "aidl/android/hardware/bluetooth/audio/ChannelMode.h"
+#include "aidl/android/hardware/bluetooth/audio/CodecId.h"
+#include "aidl_android_hardware_bluetooth_audio_setting_enums.h"
 #define LOG_TAG "BTAudioCodecsProviderAidl"
 
 #include "BluetoothLeAudioCodecsProvider.h"
@@ -38,9 +43,6 @@
 
 std::optional<setting::LeAudioOffloadSetting>
 BluetoothLeAudioCodecsProvider::ParseFromLeAudioOffloadSettingFile() {
-  if (!leAudioCodecCapabilities.empty() || isInvalidFileContent) {
-    return std::nullopt;
-  }
   auto le_audio_offload_setting =
       setting::readLeAudioOffloadSetting(kLeAudioCodecCapabilitiesFile);
   if (!le_audio_offload_setting.has_value()) {
@@ -50,6 +52,131 @@
   return le_audio_offload_setting;
 }
 
+std::unordered_map<SessionType, std::vector<CodecInfo>>
+BluetoothLeAudioCodecsProvider::GetLeAudioCodecInfo(
+    const std::optional<setting::LeAudioOffloadSetting>&
+        le_audio_offload_setting) {
+  // Load from previous storage if present
+  if (!session_codecs_map_.empty()) return session_codecs_map_;
+
+  isInvalidFileContent = true;
+  if (!le_audio_offload_setting.has_value()) return {};
+
+  // Load scenario, configuration, codec configuration and strategy
+  LoadConfigurationToMap(le_audio_offload_setting);
+  if (supported_scenarios_.empty() || configuration_map_.empty() ||
+      codec_configuration_map_.empty() || strategy_configuration_map_.empty())
+    return {};
+
+  // Map each configuration into a CodecInfo
+  std::unordered_map<std::string, CodecInfo> config_codec_info_map_;
+
+  for (auto& p : configuration_map_) {
+    // Initialize new CodecInfo for the config
+    auto config_name = p.first;
+
+    // Getting informations from codecConfig and strategyConfig
+    const auto codec_config_name = p.second.getCodecConfiguration();
+    const auto strategy_config_name = p.second.getStrategyConfiguration();
+    const auto codec_configuration_map_iter =
+        codec_configuration_map_.find(codec_config_name);
+    if (codec_configuration_map_iter == codec_configuration_map_.end())
+      continue;
+    const auto strategy_configuration_map_iter =
+        strategy_configuration_map_.find(strategy_config_name);
+    if (strategy_configuration_map_iter == strategy_configuration_map_.end())
+      continue;
+
+    if (config_codec_info_map_.count(config_name) == 0)
+      config_codec_info_map_[config_name] = CodecInfo();
+
+    const auto& codec_config = codec_configuration_map_iter->second;
+    const auto codec = codec_config.getCodec();
+    const auto& strategy_config = strategy_configuration_map_iter->second;
+    const auto strategy_config_channel_count =
+        strategy_config.getChannelCount();
+
+    // Initiate information
+    auto& codec_info = config_codec_info_map_[config_name];
+    switch (codec) {
+      case setting::CodecType::LC3:
+        codec_info.name = "LC3";
+        codec_info.id = CodecId::Core::LC3;
+        break;
+      default:
+        codec_info.name = "UNDEFINE";
+        codec_info.id = CodecId::Vendor();
+        break;
+    }
+    codec_info.transport =
+        CodecInfo::Transport::make<CodecInfo::Transport::Tag::leAudio>();
+
+    // Mapping codec configuration information
+    auto& transport =
+        codec_info.transport.get<CodecInfo::Transport::Tag::leAudio>();
+    transport.samplingFrequencyHz.push_back(
+        codec_config.getSamplingFrequency());
+    // Mapping octetsPerCodecFrame to bitdepth for easier comparison.
+    transport.bitdepth.push_back(codec_config.getOctetsPerCodecFrame());
+    transport.frameDurationUs.push_back(codec_config.getFrameDurationUs());
+    switch (strategy_config.getAudioLocation()) {
+      case setting::AudioLocation::MONO:
+        if (strategy_config_channel_count == 1)
+          transport.channelMode.push_back(ChannelMode::MONO);
+        else
+          transport.channelMode.push_back(ChannelMode::DUALMONO);
+        break;
+      case setting::AudioLocation::STEREO:
+        transport.channelMode.push_back(ChannelMode::STEREO);
+        break;
+      default:
+        transport.channelMode.push_back(ChannelMode::UNKNOWN);
+        break;
+    }
+  }
+
+  // Goes through every scenario, deduplicate configuration, skip the invalid
+  // config references (e.g. the "invalid" entries in the xml file).
+  std::set<std::string> encoding_config, decoding_config, broadcast_config;
+  for (auto& s : supported_scenarios_) {
+    if (s.hasEncode() && config_codec_info_map_.count(s.getEncode())) {
+      encoding_config.insert(s.getEncode());
+    }
+    if (s.hasDecode() && config_codec_info_map_.count(s.getDecode())) {
+      decoding_config.insert(s.getDecode());
+    }
+    if (s.hasBroadcast() && config_codec_info_map_.count(s.getBroadcast())) {
+      broadcast_config.insert(s.getBroadcast());
+    }
+  }
+
+  // Split by session types and add results
+  const auto encoding_path =
+      SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH;
+  const auto decoding_path =
+      SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH;
+  const auto broadcast_path =
+      SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH;
+  session_codecs_map_ =
+      std::unordered_map<SessionType, std::vector<CodecInfo>>();
+  session_codecs_map_[encoding_path] = std::vector<CodecInfo>();
+  session_codecs_map_[decoding_path] = std::vector<CodecInfo>();
+  session_codecs_map_[broadcast_path] = std::vector<CodecInfo>();
+  session_codecs_map_[encoding_path].reserve(encoding_config.size());
+  session_codecs_map_[decoding_path].reserve(decoding_config.size());
+  session_codecs_map_[broadcast_path].reserve(broadcast_config.size());
+  for (auto& c : encoding_config)
+    session_codecs_map_[encoding_path].push_back(config_codec_info_map_[c]);
+  for (auto& c : decoding_config)
+    session_codecs_map_[decoding_path].push_back(config_codec_info_map_[c]);
+  for (auto& c : broadcast_config)
+    session_codecs_map_[broadcast_path].push_back(config_codec_info_map_[c]);
+
+  isInvalidFileContent = session_codecs_map_.empty();
+
+  return session_codecs_map_;
+}
+
 std::vector<LeAudioCodecCapabilitiesSetting>
 BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities(
     const std::optional<setting::LeAudioOffloadSetting>&
@@ -58,6 +185,8 @@
     return leAudioCodecCapabilities;
   }
 
+  isInvalidFileContent = true;
+
   if (!le_audio_offload_setting.has_value()) {
     LOG(ERROR)
         << __func__
@@ -65,40 +194,13 @@
     return {};
   }
 
-  ClearLeAudioCodecCapabilities();
-  isInvalidFileContent = true;
-
-  std::vector<setting::Scenario> supported_scenarios =
-      GetScenarios(le_audio_offload_setting);
-  if (supported_scenarios.empty()) {
-    LOG(ERROR) << __func__ << ": No scenarios in "
-               << kLeAudioCodecCapabilitiesFile;
+  LoadConfigurationToMap(le_audio_offload_setting);
+  if (supported_scenarios_.empty() || configuration_map_.empty() ||
+      codec_configuration_map_.empty() || strategy_configuration_map_.empty())
     return {};
-  }
-
-  UpdateConfigurationsToMap(le_audio_offload_setting);
-  if (configuration_map_.empty()) {
-    LOG(ERROR) << __func__ << ": No configurations in "
-               << kLeAudioCodecCapabilitiesFile;
-    return {};
-  }
-
-  UpdateCodecConfigurationsToMap(le_audio_offload_setting);
-  if (codec_configuration_map_.empty()) {
-    LOG(ERROR) << __func__ << ": No codec configurations in "
-               << kLeAudioCodecCapabilitiesFile;
-    return {};
-  }
-
-  UpdateStrategyConfigurationsToMap(le_audio_offload_setting);
-  if (strategy_configuration_map_.empty()) {
-    LOG(ERROR) << __func__ << ": No strategy configurations in "
-               << kLeAudioCodecCapabilitiesFile;
-    return {};
-  }
 
   leAudioCodecCapabilities =
-      ComposeLeAudioCodecCapabilities(supported_scenarios);
+      ComposeLeAudioCodecCapabilities(supported_scenarios_);
   isInvalidFileContent = leAudioCodecCapabilities.empty();
 
   return leAudioCodecCapabilities;
@@ -109,6 +211,8 @@
   configuration_map_.clear();
   codec_configuration_map_.clear();
   strategy_configuration_map_.clear();
+  session_codecs_map_.clear();
+  supported_scenarios_.clear();
 }
 
 std::vector<setting::Scenario> BluetoothLeAudioCodecsProvider::GetScenarios(
@@ -191,6 +295,40 @@
   }
 }
 
+void BluetoothLeAudioCodecsProvider::LoadConfigurationToMap(
+    const std::optional<setting::LeAudioOffloadSetting>&
+        le_audio_offload_setting) {
+  ClearLeAudioCodecCapabilities();
+
+  supported_scenarios_ = GetScenarios(le_audio_offload_setting);
+  if (supported_scenarios_.empty()) {
+    LOG(ERROR) << __func__ << ": No scenarios in "
+               << kLeAudioCodecCapabilitiesFile;
+    return;
+  }
+
+  UpdateConfigurationsToMap(le_audio_offload_setting);
+  if (configuration_map_.empty()) {
+    LOG(ERROR) << __func__ << ": No configurations in "
+               << kLeAudioCodecCapabilitiesFile;
+    return;
+  }
+
+  UpdateCodecConfigurationsToMap(le_audio_offload_setting);
+  if (codec_configuration_map_.empty()) {
+    LOG(ERROR) << __func__ << ": No codec configurations in "
+               << kLeAudioCodecCapabilitiesFile;
+    return;
+  }
+
+  UpdateStrategyConfigurationsToMap(le_audio_offload_setting);
+  if (strategy_configuration_map_.empty()) {
+    LOG(ERROR) << __func__ << ": No strategy configurations in "
+               << kLeAudioCodecCapabilitiesFile;
+    return;
+  }
+}
+
 std::vector<LeAudioCodecCapabilitiesSetting>
 BluetoothLeAudioCodecsProvider::ComposeLeAudioCodecCapabilities(
     const std::vector<setting::Scenario>& supported_scenarios) {
@@ -256,6 +394,15 @@
         strategy_configuration_iter->second.getConnectedDevice(),
         strategy_configuration_iter->second.getChannelCount(),
         ComposeLc3Capability(codec_configuration_iter->second));
+  } else if (codec_type == CodecType::APTX_ADAPTIVE_LE ||
+             codec_type == CodecType::APTX_ADAPTIVE_LEX) {
+    return ComposeUnicastCapability(
+        codec_type,
+        GetAudioLocation(
+            strategy_configuration_iter->second.getAudioLocation()),
+        strategy_configuration_iter->second.getConnectedDevice(),
+        strategy_configuration_iter->second.getChannelCount(),
+        ComposeAptxAdaptiveLeCapability(codec_configuration_iter->second));
   }
   return {.codecType = CodecType::UNKNOWN};
 }
@@ -330,6 +477,14 @@
           .octetsPerFrame = {codec_configuration.getOctetsPerCodecFrame()}};
 }
 
+AptxAdaptiveLeCapabilities
+BluetoothLeAudioCodecsProvider::ComposeAptxAdaptiveLeCapability(
+    const setting::CodecConfiguration& codec_configuration) {
+  return {.samplingFrequencyHz = {codec_configuration.getSamplingFrequency()},
+          .frameDurationUs = {codec_configuration.getFrameDurationUs()},
+          .octetsPerFrame = {codec_configuration.getOctetsPerCodecFrame()}};
+}
+
 AudioLocation BluetoothLeAudioCodecsProvider::GetAudioLocation(
     const setting::AudioLocation& audio_location) {
   switch (audio_location) {
@@ -347,6 +502,10 @@
   switch (codec_type) {
     case setting::CodecType::LC3:
       return CodecType::LC3;
+    case setting::CodecType::APTX_ADAPTIVE_LE:
+      return CodecType::APTX_ADAPTIVE_LE;
+    case setting::CodecType::APTX_ADAPTIVE_LEX:
+      return CodecType::APTX_ADAPTIVE_LEX;
     default:
       return CodecType::UNKNOWN;
   }
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h
index 06e4595..5bf67e2 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h
@@ -22,6 +22,8 @@
 #include <unordered_map>
 #include <vector>
 
+#include "aidl/android/hardware/bluetooth/audio/CodecInfo.h"
+#include "aidl/android/hardware/bluetooth/audio/SessionType.h"
 #include "aidl_android_hardware_bluetooth_audio_setting.h"
 
 namespace aidl {
@@ -39,14 +41,20 @@
       const std::optional<setting::LeAudioOffloadSetting>&
           le_audio_offload_setting);
   static void ClearLeAudioCodecCapabilities();
+  static std::unordered_map<SessionType, std::vector<CodecInfo>>
+  GetLeAudioCodecInfo(const std::optional<setting::LeAudioOffloadSetting>&
+                          le_audio_offload_setting);
 
  private:
+  static inline std::vector<setting::Scenario> supported_scenarios_;
   static inline std::unordered_map<std::string, setting::Configuration>
       configuration_map_;
   static inline std::unordered_map<std::string, setting::CodecConfiguration>
       codec_configuration_map_;
   static inline std::unordered_map<std::string, setting::StrategyConfiguration>
       strategy_configuration_map_;
+  static inline std::unordered_map<SessionType, std::vector<CodecInfo>>
+      session_codecs_map_;
 
   static std::vector<setting::Scenario> GetScenarios(
       const std::optional<setting::LeAudioOffloadSetting>&
@@ -60,6 +68,9 @@
   static void UpdateStrategyConfigurationsToMap(
       const std::optional<setting::LeAudioOffloadSetting>&
           le_audio_offload_setting);
+  static void LoadConfigurationToMap(
+      const std::optional<setting::LeAudioOffloadSetting>&
+          le_audio_offload_setting);
 
   static std::vector<LeAudioCodecCapabilitiesSetting>
   ComposeLeAudioCodecCapabilities(
@@ -84,6 +95,9 @@
   static inline Lc3Capabilities ComposeLc3Capability(
       const setting::CodecConfiguration& codec_configuration);
 
+  static inline AptxAdaptiveLeCapabilities ComposeAptxAdaptiveLeCapability(
+      const setting::CodecConfiguration& codec_configuration);
+
   static inline AudioLocation GetAudioLocation(
       const setting::AudioLocation& audio_location);
   static inline CodecType GetCodecType(const setting::CodecType& codec_type);
diff --git a/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware.cpp b/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware.cpp
index 3d92ee7..fd12a6e 100644
--- a/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware.cpp
+++ b/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware.cpp
@@ -467,6 +467,8 @@
       hidl_audio_config.codecConfig(to_hidl_codec_config_2_0(
           audio_config.get<AudioConfiguration::a2dpConfig>()));
       break;
+    case AudioConfiguration::a2dp:
+      break;
     case AudioConfiguration::leAudioConfig:
       hidl_audio_config.leAudioCodecConfig(to_hidl_leaudio_config_2_1(
           audio_config.get<AudioConfiguration::leAudioConfig>()));
@@ -475,6 +477,8 @@
       hidl_audio_config.leAudioCodecConfig(to_hidl_leaudio_broadcast_config_2_1(
           audio_config.get<AudioConfiguration::leAudioBroadcastConfig>()));
       break;
+    default:
+      LOG(FATAL) << __func__ << ": unexpected AudioConfiguration";
   }
   return hidl_audio_config;
 }
diff --git a/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xml b/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xml
index c8d1af0..eaace78 100644
--- a/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xml
+++ b/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xml
@@ -31,6 +31,10 @@
     <scenario encode="OneChanMono_16_2" decode="invalid"/>
     <scenario encode="TwoChanStereo_16_2" decode="invalid"/>
     <scenario encode="OneChanStereo_16_2" decode="invalid"/>
+    <scenario encode="APEX_ADAPTIVE_LE_TwoChanStereo_48" decode="invalid"/>
+    <scenario encode="APEX_ADAPTIVE_LE_TwoChanStereo_96" decode="invalid"/>
+    <scenario encode="APEX_ADAPTIVE_LEX_TwoChanStereo_48" decode="invalid"/>
+    <scenario encode="APEX_ADAPTIVE_LEX_TwoChanStereo_96" decode="invalid"/>
     <!-- encode and decode -->
     <scenario encode="OneChanStereo_16_1" decode="OneChanStereo_16_1"/>
     <scenario encode="OneChanStereo_16_1" decode="OneChanMono_16_1"/>
@@ -51,10 +55,18 @@
     <configuration name="TwoChanStereo_16_2" codecConfiguration="LC3_16k_2" strategyConfiguration="STEREO_TWO_CISES_PER_DEVICE"/>
     <configuration name="OneChanStereo_16_2" codecConfiguration="LC3_16k_2" strategyConfiguration="STEREO_ONE_CIS_PER_DEVICE"/>
     <configuration name="BcastStereo_16_2" codecConfiguration="LC3_16k_2" strategyConfiguration="BROADCAST_STEREO"/>
+    <configuration name="APEX_ADAPTIVE_LE_TwoChanStereo_48" codecConfiguration="APTX_ADAPTIVE_LE_48k" strategyConfiguration="STEREO_TWO_CISES_PER_DEVICE"/>
+    <configuration name="APEX_ADAPTIVE_LE_TwoChanStereo_96" codecConfiguration="APTX_ADAPTIVE_LE_96k" strategyConfiguration="STEREO_TWO_CISES_PER_DEVICE"/>
+    <configuration name="APEX_ADAPTIVE_LEX_TwoChanStereo_48" codecConfiguration="APTX_ADAPTIVE_LEX_48k" strategyConfiguration="STEREO_TWO_CISES_PER_DEVICE"/>
+    <configuration name="APEX_ADAPTIVE_LEX_TwoChanStereo_96" codecConfiguration="APTX_ADAPTIVE_LEX_96k" strategyConfiguration="STEREO_TWO_CISES_PER_DEVICE"/>
   </configurationList>
   <codecConfigurationList>
     <codecConfiguration name="LC3_16k_1" codec="LC3" samplingFrequency="16000" frameDurationUs="7500" octetsPerCodecFrame="30"/>
     <codecConfiguration name="LC3_16k_2" codec="LC3" samplingFrequency="16000" frameDurationUs="10000" octetsPerCodecFrame="40"/>
+    <codecConfiguration name="APTX_ADAPTIVE_LE_48k" codec="APTX_ADAPTIVE_LE" samplingFrequency="48000" frameDurationUs="10000" octetsPerCodecFrame="816"/>
+    <codecConfiguration name="APTX_ADAPTIVE_LE_96k" codec="APTX_ADAPTIVE_LE" samplingFrequency="96000" frameDurationUs="10000" octetsPerCodecFrame="816"/>
+    <codecConfiguration name="APTX_ADAPTIVE_LEX_48k" codec="APTX_ADAPTIVE_LEX" samplingFrequency="48000" frameDurationUs="10000" octetsPerCodecFrame="816"/>
+    <codecConfiguration name="APTX_ADAPTIVE_LEX_96k" codec="APTX_ADAPTIVE_LEX" samplingFrequency="96000" frameDurationUs="10000" octetsPerCodecFrame="816"/>
   </codecConfigurationList>
   <strategyConfigurationList>
     <strategyConfiguration name="STEREO_ONE_CIS_PER_DEVICE" audioLocation="STEREO" connectedDevice="2" channelCount="1"/>
diff --git a/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xsd b/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xsd
index 8c2d6a1..03c8ade 100644
--- a/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xsd
+++ b/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xsd
@@ -70,6 +70,8 @@
   <xs:simpleType name="codecType">
     <xs:restriction base="xs:string">
       <xs:enumeration value="LC3"/>
+      <xs:enumeration value="APTX_ADAPTIVE_LE"/>
+      <xs:enumeration value="APTX_ADAPTIVE_LEX"/>
     </xs:restriction>
   </xs:simpleType>
 </xs:schema>
diff --git a/bluetooth/audio/utils/le_audio_codec_capabilities/schema/current.txt b/bluetooth/audio/utils/le_audio_codec_capabilities/schema/current.txt
index 886350e..a882174 100644
--- a/bluetooth/audio/utils/le_audio_codec_capabilities/schema/current.txt
+++ b/bluetooth/audio/utils/le_audio_codec_capabilities/schema/current.txt
@@ -32,6 +32,8 @@
 
   public enum CodecType {
     method public String getRawName();
+    enum_constant public static final aidl.android.hardware.bluetooth.audio.setting.CodecType APTX_ADAPTIVE_LE;
+    enum_constant public static final aidl.android.hardware.bluetooth.audio.setting.CodecType APTX_ADAPTIVE_LEX;
     enum_constant public static final aidl.android.hardware.bluetooth.audio.setting.CodecType LC3;
   }
 
@@ -96,15 +98,7 @@
 
   public class XmlParser {
     ctor public XmlParser();
-    method public static aidl.android.hardware.bluetooth.audio.setting.CodecConfiguration readCodecConfiguration(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public static aidl.android.hardware.bluetooth.audio.setting.CodecConfigurationList readCodecConfigurationList(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public static aidl.android.hardware.bluetooth.audio.setting.Configuration readConfiguration(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public static aidl.android.hardware.bluetooth.audio.setting.ConfigurationList readConfigurationList(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public static aidl.android.hardware.bluetooth.audio.setting.LeAudioOffloadSetting readLeAudioOffloadSetting(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public static aidl.android.hardware.bluetooth.audio.setting.Scenario readScenario(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public static aidl.android.hardware.bluetooth.audio.setting.ScenarioList readScenarioList(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public static aidl.android.hardware.bluetooth.audio.setting.StrategyConfiguration readStrategyConfiguration(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public static aidl.android.hardware.bluetooth.audio.setting.StrategyConfigurationList readStrategyConfigurationList(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
   }
diff --git a/bluetooth/audio/utils/le_audio_configuration_set/audio_set_configurations.fbs b/bluetooth/audio/utils/le_audio_configuration_set/audio_set_configurations.fbs
new file mode 100644
index 0000000..bde467d
--- /dev/null
+++ b/bluetooth/audio/utils/le_audio_configuration_set/audio_set_configurations.fbs
@@ -0,0 +1,91 @@
+/*
+ *  Copyright (c) 2022 The Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+namespace aidl.android.hardware.bluetooth.audio.le_audio;
+enum CodecSpecificLtvGenericTypes : byte {
+    SUPPORTED_SAMPLING_FREQUENCY = 0x01,
+    SUPPORTED_FRAME_DURATION = 0x02,
+    SUPPORTED_AUDIO_CHANNEL_ALLOCATION = 0x03,
+    SUPPORTED_OCTETS_PER_CODEC_FRAME = 0x04,
+    SUPPORTED_CODEC_FRAME_BLOCKS_PER_SDU = 0x05,
+}
+/// Note: Holds either a single value (when `value_width == 0`) or multiple
+///       values if `value.length()` is no-remainder divisible by the non-zero
+///       `value_width`.
+/// Note: Consider extending it with `flags` field, to hold additional info like
+///       IsBitfield, IsRange, etc. if we need these type-specific validations.
+table CompoundValue {
+    value: [ubyte] (required);
+    value_width: ubyte = 0;
+}
+table CodecSpecificConfiguration {
+    name: string;
+    type: ubyte (key);
+    compound_value: CompoundValue;
+}
+struct CodecId {
+    coding_format: ubyte;
+    vendor_company_id : ushort;
+    vendor_codec_id : ushort;
+}
+enum AudioSetConfigurationStrategy : byte {
+    MONO_ONE_CIS_PER_DEVICE = 0x00,
+    STEREO_TWO_CISES_PER_DEVICE = 0x01,
+    STEREO_ONE_CIS_PER_DEVICE = 0x02,
+}
+enum AudioSetConfigurationDirection : byte {
+    SINK = 0x01,
+    SOURCE = 0x02,
+}
+enum AudioSetConfigurationTargetLatency : byte {
+    LOW = 0x01,
+    BALANCED_RELIABILITY = 0x02,
+    HIGH_RELIABILITY = 0x03,
+}
+table AudioSetSubConfiguration {
+    device_cnt: ubyte;
+    ase_cnt: ubyte;
+    direction: AudioSetConfigurationDirection = SINK;
+    configuration_strategy: AudioSetConfigurationStrategy;
+    codec_id : CodecId (required);
+    codec_configuration: [CodecSpecificConfiguration] (required);
+}
+table CodecConfiguration {
+    name: string (key, required);
+    subconfigurations: [AudioSetSubConfiguration] (required);
+}
+table QosConfiguration {
+    name: string (key, required);
+    target_latency: AudioSetConfigurationTargetLatency = BALANCED_RELIABILITY;
+    retransmission_number: ubyte;
+    max_transport_latency : ushort;
+}
+/// Each set configration can contain multiple logical subconfigurations, which
+/// all must be configurable with the current set of audio devices. For example,
+/// one can define multiple output stream configurations with different
+/// qualities, or assign different configurations to each stream direction.
+table AudioSetConfiguration {
+    name: string (key, required);
+    codec_config_name: string (required);
+    qos_config_name: [string] (required);
+}
+table AudioSetConfigurations {
+    _comments_: [string];
+    configurations: [AudioSetConfiguration] (required);
+    codec_configurations: [CodecConfiguration] (required);
+    qos_configurations: [QosConfiguration] (required);
+}
+root_type AudioSetConfigurations;
diff --git a/bluetooth/audio/utils/le_audio_configuration_set/audio_set_configurations.json b/bluetooth/audio/utils/le_audio_configuration_set/audio_set_configurations.json
new file mode 100644
index 0000000..404a48a
--- /dev/null
+++ b/bluetooth/audio/utils/le_audio_configuration_set/audio_set_configurations.json
@@ -0,0 +1,11382 @@
+{
+  "_comments_": [
+    " == Audio Set Configurations == ",
+    " Contains: ",
+    "   1. configurations : ",
+    "        Maps configuration name with codec and qos config to be used",
+    "   2. codec_configurations : ",
+    "        Array of codec specific configurations",
+    "   3. qos_configurations : ",
+    "        Array of QoS specific configurations",
+    "        QoS configuration values are as per BAP spec 1.0",
+    " Example values which can be used as 'codec_configuration.type'",
+    "   Codec Configuration parameter types:",
+    "     SUPPORTED_SAMPLING_FREQUENCY = 1",
+    "     SUPPORTED_FRAME_DURATION = 2",
+    "     SUPPORTED_AUDIO_CHANNEL_ALLOCATION = 3",
+    "     SUPPORTED_OCTETS_PER_CODEC_FRAME = 4",
+    "     SUPPORTED_CODEC_FRAME_BLOCKS_PER_SDU = 5",
+    " Example values which can be used as 'codec_configuration.compound_value'",
+    "   Codec Coding formats:",
+    "     LC3 = 6",
+    "   ASE Configuration strategies:",
+    "     MONO_ONE_CIS_PER_DEVICE = 0",
+    "     STEREO_TWO_CISES_PER_DEVICE = 1",
+    "     STEREO_ONE_CIS_PER_DEVICE = 2",
+    "   Sampling Frequencies: ",
+    "     8000Hz = 1",
+    "     11025Hz = 2",
+    "     16000Hz = 3",
+    "     22050Hz = 4",
+    "     24000Hz = 5",
+    "     32000Hz = 6",
+    "     44100Hz = 7",
+    "     48000Hz = 8",
+    "     88200Hz = 9",
+    "     96000Hz = 10",
+    "     176400Hz = 11",
+    "     192000Hz = 12",
+    "     384000Hz = 13",
+    "   Frame Durations:",
+    "     7500us = 0",
+    "     10000us = 1"
+  ],
+  "configurations": [
+    {
+      "name": "DualDev_OneChanStereoSnk_16_1_Low_Latency",
+      "codec_config_name": "DualDev_OneChanStereoSnk_16_1",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_16_1_Balanced_Reliability",
+      "codec_config_name": "DualDev_OneChanStereoSnk_16_1",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_16_1_1",
+      "codec_config_name": "DualDev_OneChanStereoSnk_16_1",
+      "qos_config_name": [
+        "QoS_Config_16_1_1"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_16_1_2",
+      "codec_config_name": "DualDev_OneChanStereoSnk_16_1",
+      "qos_config_name": [
+        "QoS_Config_16_1_2"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_16_2_Low_Latency",
+      "codec_config_name": "DualDev_OneChanStereoSnk_16_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_16_2_Balanced_Reliability",
+      "codec_config_name": "DualDev_OneChanStereoSnk_16_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_16_2_1",
+      "codec_config_name": "DualDev_OneChanStereoSnk_16_2",
+      "qos_config_name": [
+        "QoS_Config_16_2_1"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_16_2_2",
+      "codec_config_name": "DualDev_OneChanStereoSnk_16_2",
+      "qos_config_name": [
+        "QoS_Config_16_2_2"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_16_1_Low_Latency",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_16_1",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_16_1_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_16_1",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_16_1_1",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_16_1",
+      "qos_config_name": [
+        "QoS_Config_16_1_1"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_16_1_2",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_16_1",
+      "qos_config_name": [
+        "QoS_Config_16_1_2"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_16_2_Low_Latency",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_16_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_16_2_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_16_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_16_2_1",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_16_2",
+      "qos_config_name": [
+        "QoS_Config_16_2_1"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_16_2_2",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_16_2",
+      "qos_config_name": [
+        "QoS_Config_16_2_2"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_16_1_Low_Latency",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_16_1",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_16_1_Balanced_Reliability",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_16_1",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_16_1_1",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_16_1",
+      "qos_config_name": [
+        "QoS_Config_16_1_1"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_16_1_2",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_16_1",
+      "qos_config_name": [
+        "QoS_Config_16_1_2"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_16_2_Low_Latency",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_16_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_16_2_Balanced_Reliability",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_16_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_16_2_1",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_16_2",
+      "qos_config_name": [
+        "QoS_Config_16_2_1"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_16_2_2",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_16_2",
+      "qos_config_name": [
+        "QoS_Config_16_2_2"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_32_1_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_32_1",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_32_1_1",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_32_1",
+      "qos_config_name": [
+        "QoS_Config_32_1_1"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_32_2_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_32_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_32_2_1",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_32_2",
+      "qos_config_name": [
+        "QoS_Config_32_2_1"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_16_1_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_16_1",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_16_1_1",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_16_1",
+      "qos_config_name": [
+        "QoS_Config_16_1_1"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_16_1_2",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_16_1",
+      "qos_config_name": [
+        "QoS_Config_16_1_2"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanMonoSnk_16_2_Balanced_Reliability",
+      "codec_config_name": "DualDev_OneChanMonoSnk_16_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_16_2_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_16_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_16_2_1",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_16_2",
+      "qos_config_name": [
+        "QoS_Config_16_2_1"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_16_2_2",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_16_2",
+      "qos_config_name": [
+        "QoS_Config_16_2_2"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_1_Low_Latency",
+      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_1",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_1_1",
+      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_1",
+      "qos_config_name": [
+        "QoS_Config_16_1_1"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_1_2",
+      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_1",
+      "qos_config_name": [
+        "QoS_Config_16_1_2"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2_Low_Latency",
+      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2_2",
+      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2",
+      "qos_config_name": [
+        "QoS_Config_16_2_2"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2_1",
+      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2",
+      "qos_config_name": [
+        "QoS_Config_16_2_1"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1_Low_Latency",
+      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1_2",
+      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1",
+      "qos_config_name": [
+        "QoS_Config_16_1_2"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1_1",
+      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1",
+      "qos_config_name": [
+        "QoS_Config_16_1_1"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency",
+      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_2_1",
+      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_2",
+      "qos_config_name": [
+        "QoS_Config_16_2_1"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_2_2",
+      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_2",
+      "qos_config_name": [
+        "QoS_Config_16_2_2"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_1_Low_Latency",
+      "codec_config_name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_1",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_1_1",
+      "codec_config_name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_1",
+      "qos_config_name": [
+        "QoS_Config_16_1_1"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2_Low_Latency",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2_1",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2",
+      "qos_config_name": [
+        "QoS_Config_32_2_1"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2_Low_Latency",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2_2",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2",
+      "qos_config_name": [
+        "QoS_Config_16_2_2"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2_1",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2",
+      "qos_config_name": [
+        "QoS_Config_16_2_1"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1_Low_Latency",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1_2",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1",
+      "qos_config_name": [
+        "QoS_Config_16_1_2"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1_1",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1",
+      "qos_config_name": [
+        "QoS_Config_16_1_1"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_1_2",
+      "codec_config_name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_1",
+      "qos_config_name": [
+        "QoS_Config_16_1_2"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_2_Low_Latency",
+      "codec_config_name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_2_1",
+      "codec_config_name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_2",
+      "qos_config_name": [
+        "QoS_Config_16_2_1"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_2_2",
+      "codec_config_name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_2",
+      "qos_config_name": [
+        "QoS_Config_16_2_2"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1_Low_Latency",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1_1",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1",
+      "qos_config_name": [
+        "QoS_Config_16_1_1"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1_2",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1",
+      "qos_config_name": [
+        "QoS_Config_16_1_2"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2_1",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2",
+      "qos_config_name": [
+        "QoS_Config_16_2_1"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2_2",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2",
+      "qos_config_name": [
+        "QoS_Config_16_2_2"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1_Low_Latency",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1_1",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1",
+      "qos_config_name": [
+        "QoS_Config_16_1_1"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1_2",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1",
+      "qos_config_name": [
+        "QoS_Config_16_1_2"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2_1",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2",
+      "qos_config_name": [
+        "QoS_Config_16_2_1"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2_2",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2",
+      "qos_config_name": [
+        "QoS_Config_16_2_2"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_Low_Latency",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_1",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1",
+      "qos_config_name": [
+        "QoS_Config_16_1_1"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanMonoSrc_16_2_Balanced_Reliability",
+      "codec_config_name": "DualDev_OneChanMonoSrc_16_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSrc_16_2_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanStereoSrc_16_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSrc_48_4_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanMonoSrc_48_4",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSrc_48_3_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanMonoSrc_48_3",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSrc_48_2_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanMonoSrc_48_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSrc_48_1_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanMonoSrc_48_1",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSrc_32_2_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanMonoSrc_32_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSrc_32_1_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanMonoSrc_32_1",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSrc_24_2_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanMonoSrc_24_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSrc_24_1_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanMonoSrc_24_1",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSrc_16_2_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanMonoSrc_16_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSrc_16_1_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanMonoSrc_16_1",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_2",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1",
+      "qos_config_name": [
+        "QoS_Config_16_1_2"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2_Low_Latency",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2_1",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2",
+      "qos_config_name": [
+        "QoS_Config_16_2_1"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2_2",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2",
+      "qos_config_name": [
+        "QoS_Config_16_2_2"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_24_1_Low_Latency",
+      "codec_config_name": "DualDev_OneChanStereoSnk_24_1",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_24_1_Low_Latency",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_24_1",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_24_1_Low_Latency",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_24_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_24_2_Low_Latency",
+      "codec_config_name": "DualDev_OneChanStereoSnk_24_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_24_2_Balanced_Reliability",
+      "codec_config_name": "DualDev_OneChanStereoSnk_24_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_24_2_2",
+      "codec_config_name": "DualDev_OneChanStereoSnk_24_2",
+      "qos_config_name": [
+        "QoS_Config_24_2_2"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_24_2_Low_Latency",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_24_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_24_2_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_24_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_24_2_2",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_24_2",
+      "qos_config_name": [
+        "QoS_Config_24_2_2"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_24_2_Low_Latency",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_24_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_24_2_Balanced_Reliability",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_24_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_24_2_2",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_24_2",
+      "qos_config_name": [
+        "QoS_Config_24_2_2"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_24_2_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_24_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_24_2_2",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_24_2",
+      "qos_config_name": [
+        "QoS_Config_24_2_2"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2_Low_Latency",
+      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2_1",
+      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2",
+      "qos_config_name": [
+        "QoS_Config_32_2_1"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency",
+      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_32_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_32_2_1",
+      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_32_2",
+      "qos_config_name": [
+        "QoS_Config_32_2_1"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_32_2_Low_Latency",
+      "codec_config_name": "DualDev_OneChanStereoSnk_32_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_32_1_Low_Latency",
+      "codec_config_name": "DualDev_OneChanStereoSnk_32_1",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_32_1_Low_Latency",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_32_1",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_32_2_Low_Latency",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_32_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_32_1_Low_Latency",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_32_1",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_32_2_Low_Latency",
+      "codec_config_name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_32_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_32_2_1",
+      "codec_config_name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_32_2",
+      "qos_config_name": [
+        "QoS_Config_32_2_1"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2_1",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2",
+      "qos_config_name": [
+        "QoS_Config_32_2_1"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_32_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_32_2_1",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_32_2",
+      "qos_config_name": [
+        "QoS_Config_32_2_1"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2_Low_Latency",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2_1",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2",
+      "qos_config_name": [
+        "QoS_Config_32_2_1"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_32_2_Low_Latency",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_32_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_48_4_High_Reliability",
+      "codec_config_name": "DualDev_OneChanStereoSnk_48_4",
+      "qos_config_name": [
+        "QoS_Config_High_Reliability"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_48_4_1",
+      "codec_config_name": "DualDev_OneChanStereoSnk_48_4",
+      "qos_config_name": [
+        "QoS_Config_48_4_1"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_48_4_2",
+      "codec_config_name": "DualDev_OneChanStereoSnk_48_4",
+      "qos_config_name": [
+        "QoS_Config_48_4_2"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_48_3_Low_Latency",
+      "codec_config_name": "DualDev_OneChanStereoSnk_48_3",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_48_3_High_Reliability",
+      "codec_config_name": "DualDev_OneChanStereoSnk_48_3",
+      "qos_config_name": [
+        "QoS_Config_High_Reliability"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_48_3_2",
+      "codec_config_name": "DualDev_OneChanStereoSnk_48_3",
+      "qos_config_name": [
+        "QoS_Config_48_3_2"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_48_2_Low_Latency",
+      "codec_config_name": "DualDev_OneChanStereoSnk_48_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_48_2_High_Reliability",
+      "codec_config_name": "DualDev_OneChanStereoSnk_48_2",
+      "qos_config_name": [
+        "QoS_Config_High_Reliability"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_48_2_2",
+      "codec_config_name": "DualDev_OneChanStereoSnk_48_2",
+      "qos_config_name": [
+        "QoS_Config_48_2_2"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_48_1_Low_Latency",
+      "codec_config_name": "DualDev_OneChanStereoSnk_48_1",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_48_1_High_Reliability",
+      "codec_config_name": "DualDev_OneChanStereoSnk_48_1",
+      "qos_config_name": [
+        "QoS_Config_High_Reliability"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_48_1_2",
+      "codec_config_name": "DualDev_OneChanStereoSnk_48_1",
+      "qos_config_name": [
+        "QoS_Config_48_1_2"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_48_4_High_Reliability",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_48_4",
+      "qos_config_name": [
+        "QoS_Config_High_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_48_4_1",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_48_4",
+      "qos_config_name": [
+        "QoS_Config_48_4_1"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_48_4_2",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_48_4",
+      "qos_config_name": [
+        "QoS_Config_48_4_2"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_48_3_Low_Latency",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_48_3",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_48_3_High_Reliability",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_48_3",
+      "qos_config_name": [
+        "QoS_Config_High_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_48_3_2",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_48_3",
+      "qos_config_name": [
+        "QoS_Config_48_3_2"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_48_2_Low_Latency",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_48_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_48_2_High_Reliability",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_48_2",
+      "qos_config_name": [
+        "QoS_Config_High_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_48_2_2",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_48_2",
+      "qos_config_name": [
+        "QoS_Config_48_2_2"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_48_1_Low_Latency",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_48_1",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_48_1_High_Reliability",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_48_1",
+      "qos_config_name": [
+        "QoS_Config_High_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_48_1_2",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_48_1",
+      "qos_config_name": [
+        "QoS_Config_48_1_2"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_48_4_High_Reliability",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_4",
+      "qos_config_name": [
+        "QoS_Config_High_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_48_4_1",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_4",
+      "qos_config_name": [
+        "QoS_Config_48_4_1"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_48_4_2",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_4",
+      "qos_config_name": [
+        "QoS_Config_48_4_2"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_48_3_Low_Latency",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_3",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_48_3_High_Reliability",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_3",
+      "qos_config_name": [
+        "QoS_Config_High_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_48_3_2",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_3",
+      "qos_config_name": [
+        "QoS_Config_48_3_2"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_48_2_Low_Latency",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_48_2_High_Reliability",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_2",
+      "qos_config_name": [
+        "QoS_Config_High_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_48_2_2",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_2",
+      "qos_config_name": [
+        "QoS_Config_48_2_2"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_48_1_Low_Latency",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_1",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_48_1_High_Reliability",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_1",
+      "qos_config_name": [
+        "QoS_Config_High_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_48_1_2",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_1",
+      "qos_config_name": [
+        "QoS_Config_48_1_2"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_48_4_High_Reliability",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_48_4",
+      "qos_config_name": [
+        "QoS_Config_High_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_48_4_1",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_48_4",
+      "qos_config_name": [
+        "QoS_Config_48_4_1"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_48_4_2",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_48_4",
+      "qos_config_name": [
+        "QoS_Config_48_4_2"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_48_3_High_Reliability",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_48_3",
+      "qos_config_name": [
+        "QoS_Config_High_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_48_3_2",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_48_3",
+      "qos_config_name": [
+        "QoS_Config_48_3_2"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_48_2_High_Reliability",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_48_2",
+      "qos_config_name": [
+        "QoS_Config_High_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_48_2_2",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_48_2",
+      "qos_config_name": [
+        "QoS_Config_48_2_2"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_48_1_High_Reliability",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_48_1",
+      "qos_config_name": [
+        "QoS_Config_High_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_48_1_2",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_48_1",
+      "qos_config_name": [
+        "QoS_Config_48_1_2"
+      ]
+    },
+    {
+      "name": "VND_SingleDev_TwoChanStereoSnk_OneChanStereoSrc_32khz_60octs_Low_Latency_1",
+      "codec_config_name": "VND_SingleDev_TwoChanStereoSnk_OneChanStereoSrc_32khz_60octs_1",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "VND_SingleDev_TwoChanStereoSnk_OneChanStereoSrc_32khz_60oct_R3_L22_1",
+      "codec_config_name": "VND_SingleDev_TwoChanStereoSnk_OneChanStereoSrc_32khz_60octs_1",
+      "qos_config_name": [
+        "VND_QoS_Config_R3_L22"
+      ]
+    },
+    {
+      "name": "VND_DualDev_OneChanStereoSnk_48khz_100octs_High_Reliability_1",
+      "codec_config_name": "VND_DualDev_OneChanStereoSnk_48khz_100octs_1",
+      "qos_config_name": [
+        "QoS_Config_High_Reliability"
+      ]
+    },
+    {
+      "name": "VND_DualDev_OneChanStereoSnk_48khz_100octs_R15_L70_1",
+      "codec_config_name": "VND_DualDev_OneChanStereoSnk_48khz_100octs_1",
+      "qos_config_name": [
+        "VND_QoS_Config_R15_L70"
+      ]
+    },
+    {
+      "name": "VND_SingleDev_OneChanStereoSnk_48khz_100octs_High_Reliability_1",
+      "codec_config_name": "VND_SingleDev_OneChanStereoSnk_48khz_100octs_1",
+      "qos_config_name": [
+        "QoS_Config_High_Reliability"
+      ]
+    },
+    {
+      "name": "VND_SingleDev_OneChanStereoSnk_48khz_100octs_R15_L70_1",
+      "codec_config_name": "VND_SingleDev_OneChanStereoSnk_48khz_100octs_1",
+      "qos_config_name": [
+        "VND_QoS_Config_R15_L70"
+      ]
+    },
+    {
+      "name": "VND_SingleDev_TwoChanStereoSnk_48khz_100octs_High_Reliability_1",
+      "codec_config_name": "VND_SingleDev_TwoChanStereoSnk_48khz_100octs_1",
+      "qos_config_name": [
+        "QoS_Config_High_Reliability"
+      ]
+    },
+    {
+      "name": "VND_SingleDev_TwoChanStereoSnk_48khz_100octs_R15_L70_1",
+      "codec_config_name": "VND_SingleDev_TwoChanStereoSnk_48khz_100octs_1",
+      "qos_config_name": [
+        "VND_QoS_Config_R15_L70"
+      ]
+    },
+    {
+      "name": "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_High_Reliability_1",
+      "codec_config_name": "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_1",
+      "qos_config_name": [
+        "QoS_Config_High_Reliability"
+      ]
+    },
+    {
+      "name": "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_R5_L12_1",
+      "codec_config_name": "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_1",
+      "qos_config_name": [
+        "VND_QoS_Config_R5_L12"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_48_4_OneChanStereoSrc_32_2_Balanced_Reliability",
+      "codec_config_name": "DualDev_OneChanStereoSnk_48_4_OneChanStereoSrc_32_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_48_4_OneChanStereoSrc_24_2_Balanced_Reliability",
+      "codec_config_name": "DualDev_OneChanStereoSnk_48_4_OneChanStereoSrc_24_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_48_4_OneChanStereoSrc_16_2_Balanced_Reliability",
+      "codec_config_name": "DualDev_OneChanStereoSnk_48_4_OneChanStereoSrc_16_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_48_4_OneChanMonoSrc_32_2_Balanced_Reliability",
+      "codec_config_name": "DualDev_OneChanStereoSnk_48_4_OneChanMonoSrc_32_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_48_4_OneChanMonoSrc_24_2_Balanced_Reliability",
+      "codec_config_name": "DualDev_OneChanStereoSnk_48_4_OneChanMonoSrc_24_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_48_4_OneChanMonoSrc_16_2_Balanced_Reliability",
+      "codec_config_name": "DualDev_OneChanStereoSnk_48_4_OneChanMonoSrc_16_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanDoubleStereoSnk_48_4_OneChanMonoSrc_32_2_Balanced_Reliability",
+      "codec_config_name": "DualDev_OneChanDoubleStereoSnk_48_4_OneChanMonoSrc_32_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanDoubleStereoSnk_48_4_OneChanMonoSrc_24_2_Balanced_Reliability",
+      "codec_config_name": "DualDev_OneChanDoubleStereoSnk_48_4_OneChanMonoSrc_24_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanDoubleStereoSnk_48_4_OneChanMonoSrc_16_2_Balanced_Reliability",
+      "codec_config_name": "DualDev_OneChanDoubleStereoSnk_48_4_OneChanMonoSrc_16_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_48_4_TwoChanStereoSrc_32_2_Balanced_Reliability",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_4_TwoChanStereoSrc_32_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_48_4_TwoChanStereoSrc_24_2_Balanced_Reliability",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_4_TwoChanStereoSrc_24_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_48_4_TwoChanStereoSrc_16_2_Balanced_Reliability",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_4_TwoChanStereoSrc_16_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_48_4_OneChanMonoSrc_32_2_Balanced_Reliability",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_4_OneChanMonoSrc_32_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_48_4_1_OneChanMonoSrc_24_2_Balanced_Reliability",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_4_OneChanMonoSrc_24_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_48_4_1_OneChanMonoSrc_16_2_Balanced_Reliability",
+      "codec_config_name": "SingleDev_TwoChanStereoSnk_48_4_OneChanMonoSrc_16_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_48_4_1_OneChanMonoSrc_32_2_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_48_4_OneChanMonoSrc_32_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_48_4_1_OneChanMonoSrc_24_2_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_48_4_OneChanMonoSrc_24_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_48_4_1_OneChanMonoSrc_16_2_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanStereoSnk_48_4_OneChanMonoSrc_16_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_48_4_1_OneChanMonoSrc_32_2_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_48_4_OneChanMonoSrc_32_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_48_4_1_OneChanMonoSrc_24_2_1_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_48_4_OneChanMonoSrc_24_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_48_4_1_OneChanMonoSrc_16_2_Balanced_Reliability",
+      "codec_config_name": "SingleDev_OneChanMonoSnk_48_4_OneChanMonoSrc_16_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_1_Low_Latency",
+      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_1",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_1_Balanced_Reliability",
+      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_1",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_2_Low_Latency",
+      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_2",
+      "qos_config_name": [
+        "QoS_Config_Low_Latency"
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_2_Balanced_Reliability",
+      "codec_config_name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_2",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "VND_SingleDev_TwoChanStereoSrc_48khz_100octs_Balanced_Reliability_1",
+      "codec_config_name": "VND_SingleDev_TwoChanStereoSrc_48khz_100octs_1",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "VND_SingleDev_TwoChanStereoSrc_48khz_100octs_R11_L40_1",
+      "codec_config_name": "VND_SingleDev_TwoChanStereoSrc_48khz_100octs_1",
+      "qos_config_name": [
+        "VND_QoS_Config_R11_L40"
+      ]
+    },
+    {
+      "name": "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_R5_L12_TwoChanStereoSrc_16khz_30octs_R3_L12_1",
+      "codec_config_name": "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_TwoChanStereoSrc_16khz_30octs_1",
+      "qos_config_name": [
+        "VND_QoS_Config_R5_L12",
+        "VND_QoS_Config_R3_L12"
+      ]
+    },
+    {
+      "name": "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_TwoChanStereoSrc_16khz_30octs_Balanced_Reliability_1",
+      "codec_config_name": "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_TwoChanStereoSrc_16khz_30octs_1",
+      "qos_config_name": [
+        "QoS_Config_Balanced_Reliability"
+      ]
+    }
+  ],
+  "codec_configurations": [
+    {
+      "name": "DualDev_OneChanStereoSnk_16_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 2,
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  40,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_16_1",
+      "subconfigurations": [
+        {
+          "device_cnt": 2,
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  30,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_16_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  40,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_16_1",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  30,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_16_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  3,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  40,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_16_1",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  3,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  30,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSrc_16_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 2,
+          "direction": "SOURCE",
+          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  40,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSrc_24_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  5
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  60,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_32_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 2,
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_32_1",
+      "subconfigurations": [
+        {
+          "device_cnt": 2,
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  60,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_32_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_32_1",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  60,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "DualDev_OneChanMonoSnk_16_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 2,
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  40,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_16_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  40,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_16_1",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  30,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 2,
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  40,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  40,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 2,
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  40,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 2,
+          "ase_cnt": 2,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  40,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1",
+      "subconfigurations": [
+        {
+          "device_cnt": 2,
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  30,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 2,
+          "ase_cnt": 2,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  30,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_1",
+      "subconfigurations": [
+        {
+          "device_cnt": 2,
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  30,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  30,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 2,
+          "ase_cnt": 4,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  40,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  40,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_1",
+      "subconfigurations": [
+        {
+          "device_cnt": 2,
+          "ase_cnt": 4,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  30,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  30,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  3,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  3,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  3,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  40,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  3,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  40,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  3,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  30,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  3,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  30,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  3,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  40,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  40,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  3,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  30,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  30,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  40,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  40,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  30,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  30,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  40,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  40,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  30,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  30,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "DualDev_OneChanMonoSrc_16_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 2,
+          "ase_cnt": 2,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  40,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSrc_48_4",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  120,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSrc_48_3",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  90,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSrc_48_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  100,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSrc_48_1",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  75,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSrc_32_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSrc_32_1",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  60,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSrc_24_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  5
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  60,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSrc_24_1",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  5
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  45,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSrc_16_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  40,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSrc_16_1",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  30,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_48_4",
+      "subconfigurations": [
+        {
+          "device_cnt": 2,
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  120,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_48_3",
+      "subconfigurations": [
+        {
+          "device_cnt": 2,
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  90,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_48_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 2,
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  100,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_48_1",
+      "subconfigurations": [
+        {
+          "device_cnt": 2,
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  75,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_48_4",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  120,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_48_3",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  90,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_48_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  100,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_48_1",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  75,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_48_4",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  3,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  120,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_48_3",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  3,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  90,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_48_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  3,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  100,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_48_1",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  3,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  75,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_48_4",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  120,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_48_3",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  90,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_48_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  100,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_48_1",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  75,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "VND_SingleDev_TwoChanStereoSnk_48khz_100octs_1",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  3,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  100,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "VND_DualDev_OneChanStereoSnk_48khz_100octs_1",
+      "subconfigurations": [
+        {
+          "device_cnt": 2,
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  100,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "VND_SingleDev_OneChanStereoSnk_48khz_100octs_1",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  100,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_1",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  3,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  75,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_48_4_OneChanStereoSrc_32_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 2,
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  120,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 2,
+          "ase_cnt": 2,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_48_4_OneChanStereoSrc_24_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 2,
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  120,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 2,
+          "ase_cnt": 2,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  5
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_48_4_OneChanStereoSrc_16_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 2,
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  120,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 2,
+          "ase_cnt": 2,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_48_4_OneChanMonoSrc_32_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 2,
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  120,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_48_4_OneChanMonoSrc_24_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 2,
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  120,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  5
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_48_4_OneChanMonoSrc_16_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 2,
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  120,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "DualDev_OneChanDoubleStereoSnk_48_4_OneChanMonoSrc_32_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 2,
+          "ase_cnt": 4,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  120,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "DualDev_OneChanDoubleStereoSnk_48_4_OneChanMonoSrc_24_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 2,
+          "ase_cnt": 4,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  120,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  5
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "DualDev_OneChanDoubleStereoSnk_48_4_OneChanMonoSrc_16_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 2,
+          "ase_cnt": 4,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  120,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_48_4_TwoChanStereoSrc_32_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  3,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  120,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  3,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_48_4_TwoChanStereoSrc_24_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  3,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  120,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  5
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  3,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_48_4_TwoChanStereoSrc_16_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  3,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  120,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  3,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_48_4_OneChanMonoSrc_32_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  3,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  120,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_48_4_OneChanMonoSrc_24_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  3,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  120,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  5
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_48_4_OneChanMonoSrc_16_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  3,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  120,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_48_4_OneChanMonoSrc_32_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  120,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_48_4_OneChanMonoSrc_24_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  120,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  5
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_48_4_OneChanMonoSrc_16_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  120,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_48_4_OneChanMonoSrc_32_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  120,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_48_4_OneChanMonoSrc_24_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  120,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  5
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_48_4_OneChanMonoSrc_16_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  120,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_1",
+      "subconfigurations": [
+        {
+          "device_cnt": 2,
+          "ase_cnt": 2,
+          "direction": "SOURCE",
+          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  3,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  75,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 2,
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  3,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  75,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 2,
+          "ase_cnt": 2,
+          "direction": "SOURCE",
+          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  3,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  100,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 2,
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  3,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  100,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "VND_SingleDev_TwoChanStereoSrc_48khz_100octs_1",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  3,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  100,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "VND_SingleDev_TwoChanStereoSnk_OneChanStereoSrc_32khz_60octs_1",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  3,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  60,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  60,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_TwoChanStereoSrc_16khz_30octs_1",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  8
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  3,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  75,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  3
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  3,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  30,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_24_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 2,
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  5
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  60,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_24_1",
+      "subconfigurations": [
+        {
+          "device_cnt": 2,
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  5
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  45,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_24_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  5
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  60,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_24_1",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  5
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  45,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_24_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  5
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  3,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  60,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_24_1",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  5
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  3,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  45,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_24_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "configuration_strategy": "MONO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  5
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  60,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 2,
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 2,
+          "ase_cnt": 2,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "DualDev_OneChanStereoSnk_OneChanMonoSrc_32_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 2,
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_32_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 2,
+          "ase_cnt": 4,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  3,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_OneChanMonoSrc_32_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SOURCE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_32_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  3,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_TwoChanStereoSnk_32_1",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 1,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_ONE_CIS_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  3,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  60,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_32_2",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  80,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "SingleDev_OneChanStereoSnk_32_1",
+      "subconfigurations": [
+        {
+          "device_cnt": 1,
+          "ase_cnt": 2,
+          "direction": "SINK",
+          "configuration_strategy": "STEREO_TWO_CISES_PER_DEVICE",
+          "codec_id": {
+            "coding_format": 6,
+            "vendor_company_id": 0,
+            "vendor_codec_id": 0
+          },
+          "codec_configuration": [
+            {
+              "name": "sampling_frequency",
+              "type": 1,
+              "compound_value": {
+                "value": [
+                  6
+                ]
+              }
+            },
+            {
+              "name": "frame_duration",
+              "type": 2,
+              "compound_value": {
+                "value": [
+                  0
+                ]
+              }
+            },
+            {
+              "name": "audio_channel_allocation",
+              "type": 3,
+              "compound_value": {
+                "value": [
+                  1,
+                  0,
+                  0,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "octets_per_codec_frame",
+              "type": 4,
+              "compound_value": {
+                "value": [
+                  60,
+                  0
+                ]
+              }
+            },
+            {
+              "name": "codec_frame_blocks_per_sdu",
+              "type": 5,
+              "compound_value": {
+                "value": [
+                  1
+                ]
+              }
+            }
+          ]
+        }
+      ]
+    }
+  ],
+  "qos_configurations": [
+    {
+      "name": "QoS_Config_16_1_1",
+      "retransmission_number": 2,
+      "max_transport_latency": 8
+    },
+    {
+      "name": "QoS_Config_16_1_2",
+      "retransmission_number": 13,
+      "max_transport_latency": 75
+    },
+    {
+      "name": "QoS_Config_16_2_1",
+      "retransmission_number": 2,
+      "max_transport_latency": 10
+    },
+    {
+      "name": "QoS_Config_16_2_2",
+      "retransmission_number": 13,
+      "max_transport_latency": 95
+    },
+    {
+      "name": "QoS_Config_24_1_1",
+      "retransmission_number": 2,
+      "max_transport_latency": 8
+    },
+    {
+      "name": "QoS_Config_24_1_2",
+      "retransmission_number": 13,
+      "max_transport_latency": 75
+    },
+    {
+      "name": "QoS_Config_24_2_1",
+      "retransmission_number": 2,
+      "max_transport_latency": 10
+    },
+    {
+      "name": "QoS_Config_24_2_2",
+      "retransmission_number": 13,
+      "max_transport_latency": 95
+    },
+    {
+      "name": "QoS_Config_32_1_1",
+      "retransmission_number": 2,
+      "max_transport_latency": 8
+    },
+    {
+      "name": "QoS_Config_32_1_2",
+      "retransmission_number": 13,
+      "max_transport_latency": 75
+    },
+    {
+      "name": "QoS_Config_32_2_1",
+      "retransmission_number": 2,
+      "max_transport_latency": 10
+    },
+    {
+      "name": "QoS_Config_32_2_2",
+      "retransmission_number": 13,
+      "max_transport_latency": 95
+    },
+    {
+      "name": "QoS_Config_48_1_2",
+      "retransmission_number": 13,
+      "max_transport_latency": 75
+    },
+    {
+      "name": "QoS_Config_48_2_2",
+      "retransmission_number": 13,
+      "max_transport_latency": 95
+    },
+    {
+      "name": "QoS_Config_48_3_2",
+      "retransmission_number": 13,
+      "max_transport_latency": 75
+    },
+    {
+      "name": "QoS_Config_48_4_1",
+      "retransmission_number": 5,
+      "max_transport_latency": 20
+    },
+    {
+      "name": "QoS_Config_48_4_2",
+      "retransmission_number": 13,
+      "max_transport_latency": 100
+    },
+    {
+      "name": "VND_QoS_Config_R3_L22",
+      "retransmission_number": 3,
+      "max_transport_latency": 22
+    },
+    {
+      "name": "VND_QoS_Config_R15_L70",
+      "retransmission_number": 15,
+      "max_transport_latency": 70
+    },
+    {
+      "name": "VND_QoS_Config_R5_L12",
+      "retransmission_number": 5,
+      "max_transport_latency": 12
+    },
+    {
+      "name": "VND_QoS_Config_R11_L40",
+      "retransmission_number": 11,
+      "max_transport_latency": 40
+    },
+    {
+      "name": "VND_QoS_Config_R3_L12",
+      "retransmission_number": 3,
+      "max_transport_latency": 12
+    },
+    {
+      "name": "QoS_Config_Low_Latency",
+      "target_latency": "LOW",
+      "retransmission_number": 0,
+      "max_transport_latency": 0
+    },
+    {
+      "name": "QoS_Config_Balanced_Reliability",
+      "target_latency": "BALANCED_RELIABILITY",
+      "retransmission_number": 0,
+      "max_transport_latency": 0
+    },
+    {
+      "name": "QoS_Config_High_Reliability",
+      "target_latency": "HIGH_RELIABILITY",
+      "retransmission_number": 0,
+      "max_transport_latency": 0
+    }
+
+  ]
+}
diff --git a/bluetooth/audio/utils/le_audio_configuration_set/audio_set_scenarios.fbs b/bluetooth/audio/utils/le_audio_configuration_set/audio_set_scenarios.fbs
new file mode 100644
index 0000000..e898bdc
--- /dev/null
+++ b/bluetooth/audio/utils/le_audio_configuration_set/audio_set_scenarios.fbs
@@ -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.
+ *
+ */
+namespace aidl.android.hardware.bluetooth.audio.le_audio;
+/// Scenario represents the use case such as "Media", "Conversation", etc.
+/// Each scenario can list any number of codec configurations by their names in
+/// the order of preference. That means if the first entry does not meet all
+/// the current requirements (such as peer device capabilities etc.) next
+/// configurations are being checked.
+///
+/// The referenced codec configurations are defined by the
+/// audio_set_configurations.fbs schema and loaded from a different source file.
+/// Multiple scenarios can reference same codec configurations.
+table AudioSetScenario {
+    _comments_: [string];
+    name: string (key, required);
+    configurations: [string] (required);
+}
+table AudioSetScenarios {
+    _comments_: [string];
+    scenarios: [AudioSetScenario] (required);
+}
+root_type AudioSetScenarios;
diff --git a/bluetooth/audio/utils/le_audio_configuration_set/audio_set_scenarios.json b/bluetooth/audio/utils/le_audio_configuration_set/audio_set_scenarios.json
new file mode 100644
index 0000000..a28c6cd
--- /dev/null
+++ b/bluetooth/audio/utils/le_audio_configuration_set/audio_set_scenarios.json
@@ -0,0 +1,304 @@
+{
+  "_comments_": [
+    "== Audio Set Scenarios ==",
+    "  Each defined scenario references externally defined audio set",
+    "  configurations, listed in the order of priority."
+  ],
+  "scenarios": [
+    {
+      "name": "Conversational",
+      "configurations": [
+        "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2_Low_Latency",
+        "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2_1",
+        "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2_Low_Latency",
+        "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2_1",
+        "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2_2",
+        "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1_Low_Latency",
+        "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1_1",
+        "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1_2",
+        "DualDev_OneChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency",
+        "DualDev_OneChanStereoSnk_OneChanMonoSrc_32_2_1",
+        "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency",
+        "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_2_1",
+        "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_1_Low_Latency",
+        "DualDev_OneChanStereoSnk_OneChanMonoSrc_16_1_1",
+        "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_32_2_Low_Latency",
+        "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_32_2_1",
+        "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_2_Low_Latency",
+        "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_2_1",
+        "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_1_Low_Latency",
+        "DualDev_OneChanDoubleStereoSnk_OneChanMonoSrc_16_1_1",
+        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2_Low_Latency",
+        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2_1",
+        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2_Low_Latency",
+        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2_1",
+        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2_2",
+        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1_Low_Latency",
+        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1_1",
+        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1_2",
+        "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency",
+        "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2_1",
+        "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency",
+        "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2_1",
+        "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1_Low_Latency",
+        "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1_1",
+        "SingleDev_OneChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency",
+        "SingleDev_OneChanStereoSnk_OneChanMonoSrc_32_2_1",
+        "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency",
+        "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2_1",
+        "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1_Low_Latency",
+        "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1_1",
+        "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2_Low_Latency",
+        "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2_1",
+        "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2_Low_Latency",
+        "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2_1",
+        "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_Low_Latency",
+        "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_1",
+        "DualDev_OneChanMonoSrc_16_2_Balanced_Reliability",
+        "SingleDev_OneChanStereoSrc_16_2_Balanced_Reliability",
+        "SingleDev_OneChanMonoSrc_48_4_Balanced_Reliability",
+        "SingleDev_OneChanMonoSrc_48_2_Balanced_Reliability",
+        "SingleDev_OneChanMonoSrc_48_3_Balanced_Reliability",
+        "SingleDev_OneChanMonoSrc_48_1_Balanced_Reliability",
+        "SingleDev_OneChanMonoSrc_32_2_Balanced_Reliability",
+        "SingleDev_OneChanMonoSrc_32_1_Balanced_Reliability",
+        "SingleDev_OneChanMonoSrc_24_2_Balanced_Reliability",
+        "SingleDev_OneChanMonoSrc_24_1_Balanced_Reliability",
+        "SingleDev_OneChanMonoSrc_16_2_Balanced_Reliability",
+        "SingleDev_OneChanMonoSrc_16_1_Balanced_Reliability",
+        "VND_SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32khz_Server_Prefered_1",
+        "VND_SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32khz_60oct_R3_L22_1",
+        "DualDev_OneChanMonoSnk_16_2_Balanced_Reliability",
+        "SingleDev_OneChanStereoSnk_16_2_Balanced_Reliability",
+        "SingleDev_TwoChanStereoSnk_16_2_Balanced_Reliability",
+        "SingleDev_OneChanMonoSnk_16_2_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "Media",
+      "configurations": [
+        "DualDev_OneChanStereoSnk_48_4_High_Reliability",
+        "DualDev_OneChanStereoSnk_48_4_2",
+        "DualDev_OneChanStereoSnk_48_2_High_Reliability",
+        "DualDev_OneChanStereoSnk_48_2_2",
+        "DualDev_OneChanStereoSnk_48_3_High_Reliability",
+        "DualDev_OneChanStereoSnk_48_3_2",
+        "DualDev_OneChanStereoSnk_48_1_High_Reliability",
+        "DualDev_OneChanStereoSnk_48_1_2",
+        "DualDev_OneChanStereoSnk_24_2_Balanced_Reliability",
+        "DualDev_OneChanStereoSnk_24_2_2",
+        "DualDev_OneChanStereoSnk_16_2_Balanced_Reliability",
+        "DualDev_OneChanStereoSnk_16_2_2",
+        "DualDev_OneChanStereoSnk_16_1_Balanced_Reliability",
+        "DualDev_OneChanStereoSnk_16_1_2",
+        "SingleDev_OneChanStereoSnk_48_4_High_Reliability",
+        "SingleDev_OneChanStereoSnk_48_4_2",
+        "SingleDev_OneChanStereoSnk_48_2_High_Reliability",
+        "SingleDev_OneChanStereoSnk_48_2_2",
+        "SingleDev_OneChanStereoSnk_48_3_High_Reliability",
+        "SingleDev_OneChanStereoSnk_48_3_2",
+        "SingleDev_OneChanStereoSnk_48_1_High_Reliability",
+        "SingleDev_OneChanStereoSnk_48_1_2",
+        "SingleDev_OneChanStereoSnk_24_2_Balanced_Reliability",
+        "SingleDev_OneChanStereoSnk_24_2_2",
+        "SingleDev_OneChanStereoSnk_16_2_Balanced_Reliability",
+        "SingleDev_OneChanStereoSnk_16_2_2",
+        "SingleDev_OneChanStereoSnk_16_1_Balanced_Reliability",
+        "SingleDev_OneChanStereoSnk_16_1_2",
+        "SingleDev_TwoChanStereoSnk_48_4_High_Reliability",
+        "SingleDev_TwoChanStereoSnk_48_4_2",
+        "SingleDev_TwoChanStereoSnk_48_4_High_Reliability",
+        "SingleDev_TwoChanStereoSnk_48_4_2",
+        "SingleDev_TwoChanStereoSnk_48_2_High_Reliability",
+        "SingleDev_TwoChanStereoSnk_48_2_2",
+        "SingleDev_TwoChanStereoSnk_48_3_High_Reliability",
+        "SingleDev_TwoChanStereoSnk_48_3_2",
+        "SingleDev_TwoChanStereoSnk_48_1_High_Reliability",
+        "SingleDev_TwoChanStereoSnk_48_1_2",
+        "SingleDev_TwoChanStereoSnk_24_2_Balanced_Reliability",
+        "SingleDev_TwoChanStereoSnk_24_2_2",
+        "SingleDev_TwoChanStereoSnk_16_2_Balanced_Reliability",
+        "SingleDev_TwoChanStereoSnk_16_2_2",
+        "SingleDev_TwoChanStereoSnk_16_1_Balanced_Reliability",
+        "SingleDev_TwoChanStereoSnk_16_1_2",
+        "SingleDev_OneChanMonoSnk_48_4_High_Reliability",
+        "SingleDev_OneChanMonoSnk_48_4_2",
+        "SingleDev_OneChanMonoSnk_48_2_High_Reliability",
+        "SingleDev_OneChanMonoSnk_48_2_2",
+        "SingleDev_OneChanMonoSnk_48_3_High_Reliability",
+        "SingleDev_OneChanMonoSnk_48_3_2",
+        "SingleDev_OneChanMonoSnk_48_1_High_Reliability",
+        "SingleDev_OneChanMonoSnk_48_1_2",
+        "SingleDev_OneChanMonoSnk_32_2_Balanced_Reliability",
+        "SingleDev_OneChanMonoSnk_32_2_2",
+        "SingleDev_OneChanMonoSnk_32_1_Balanced_Reliability",
+        "SingleDev_OneChanMonoSnk_32_1_2",
+        "SingleDev_OneChanMonoSnk_24_2_Balanced_Reliability",
+        "SingleDev_OneChanMonoSnk_24_2_2",
+        "SingleDev_OneChanMonoSnk_16_2_Balanced_Reliability",
+        "SingleDev_OneChanMonoSnk_16_2_2",
+        "SingleDev_OneChanMonoSnk_16_1_Balanced_Reliability",
+        "SingleDev_OneChanMonoSnk_16_1_2",
+        "VND_DualDev_OneChanStereoSnk_48khz_100octs_High_Reliability_1",
+        "VND_DualDev_OneChanStereoSnk_48khz_100octs_R15_L70_1",
+        "VND_SingleDev_TwoChanStereoSnk_48khz_100octs_High_Reliability_1",
+        "VND_SingleDev_TwoChanStereoSnk_48khz_100octs_R15_L70_1",
+        "VND_SingleDev_OneChanStereoSnk_48khz_100octs_High_Reliability_1",
+        "VND_SingleDev_OneChanStereoSnk_48khz_100octs_R15_L70_1",
+        "DualDev_OneChanMonoSrc_16_2_Balanced_Reliability",
+        "SingleDev_OneChanStereoSrc_16_2_Balanced_Reliability",
+        "SingleDev_OneChanMonoSrc_16_2_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "Game",
+      "configurations": [
+        "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2_Low_Latency",
+        "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2_Low_Latency",
+        "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1_Low_Latency",
+        "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_2_Low_Latency",
+        "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_1_Low_Latency",
+        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2_Low_Latency",
+        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2_Low_Latency",
+        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1_Low_Latency",
+        "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency",
+        "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency",
+        "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1_Low_Latency",
+        "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_TwoChanStereoSrc_16khz_30octs_Balanced_Reliability_1",
+        "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_R5_L12_TwoChanStereoSrc_16khz_30octs_R3_L12_1",
+        "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_High_Reliability_1",
+        "VND_SingleDev_TwoChanStereoSnk_48khz_75octs_R5_L12_1",
+        "SingleDev_OneChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency",
+        "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency",
+        "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1_Low_Latency",
+        "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2_Low_Latency",
+        "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2_Low_Latency",
+        "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_Low_Latency",
+        "DualDev_OneChanStereoSnk_48_2_Low_Latency",
+        "DualDev_OneChanStereoSnk_48_3_Low_Latency",
+        "DualDev_OneChanStereoSnk_48_1_Low_Latency",
+        "DualDev_OneChanStereoSnk_32_2_Low_Latency",
+        "DualDev_OneChanStereoSnk_32_1_Low_Latency",
+        "DualDev_OneChanStereoSnk_24_2_Low_Latency",
+        "DualDev_OneChanStereoSnk_24_1_Low_Latency",
+        "DualDev_OneChanStereoSnk_16_2_Low_Latency",
+        "DualDev_OneChanStereoSnk_16_1_Low_Latency",
+        "SingleDev_TwoChanStereoSnk_48_2_Low_Latency",
+        "SingleDev_TwoChanStereoSnk_48_3_Low_Latency",
+        "SingleDev_TwoChanStereoSnk_48_1_Low_Latency",
+        "SingleDev_TwoChanStereoSnk_32_2_Low_Latency",
+        "SingleDev_TwoChanStereoSnk_32_1_Low_Latency",
+        "SingleDev_TwoChanStereoSnk_24_2_Low_Latency",
+        "SingleDev_TwoChanStereoSnk_24_1_Low_Latency",
+        "SingleDev_TwoChanStereoSnk_16_2_Low_Latency",
+        "SingleDev_TwoChanStereoSnk_16_1_Low_Latency",
+        "SingleDev_OneChanStereoSnk_48_2_Low_Latency",
+        "SingleDev_OneChanStereoSnk_48_3_Low_Latency",
+        "SingleDev_OneChanStereoSnk_48_1_Low_Latency",
+        "SingleDev_OneChanStereoSnk_32_2_Low_Latency",
+        "SingleDev_OneChanStereoSnk_32_1_Low_Latency",
+        "SingleDev_OneChanStereoSnk_24_2_Low_Latency",
+        "SingleDev_OneChanStereoSnk_24_1_Low_Latency",
+        "SingleDev_OneChanStereoSnk_16_2_Low_Latency",
+        "SingleDev_OneChanStereoSnk_16_1_Low_Latency"
+      ]
+    },
+    {
+      "name": "VoiceAssistants",
+      "configurations": [
+        "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2_Low_Latency",
+        "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2_1",
+        "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2_Low_Latency",
+        "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2_1",
+        "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1_Low_Latency",
+        "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1_1",
+        "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_2_Balanced_Reliability",
+        "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_1_Balanced_Reliability",
+        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2_Low_Latency",
+        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2_1",
+        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2_Low_Latency",
+        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2_1",
+        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1_Low_Latency",
+        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1_1",
+        "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency",
+        "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2_1",
+        "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency",
+        "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2_1",
+        "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1_Low_Latency",
+        "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1_1",
+        "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2_Low_Latency",
+        "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2_1",
+        "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2_Low_Latency",
+        "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2_1",
+        "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_Low_Latency",
+        "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_1",
+        "DualDev_OneChanStereoSnk_48_4_OneChanStereoSrc_16_2_Balanced_Reliability",
+        "DualDev_OneChanStereoSnk_48_4_OneChanStereoSrc_24_2_Balanced_Reliability",
+        "DualDev_OneChanStereoSnk_48_4_OneChanStereoSrc_32_2_Balanced_Reliability",
+        "DualDev_OneChanStereoSnk_48_4_OneChanMonoSrc_16_2_Balanced_Reliability",
+        "DualDev_OneChanStereoSnk_48_4_OneChanMonoSrc_24_2_Balanced_Reliability",
+        "DualDev_OneChanStereoSnk_48_4_OneChanMonoSrc_32_2_Balanced_Reliability",
+        "DualDev_OneChanDoubleStereoSnk_48_4_OneChanMonoSrc_16_2_Balanced_Reliability",
+        "DualDev_OneChanDoubleStereoSnk_48_4_OneChanMonoSrc_24_2_Balanced_Reliability",
+        "DualDev_OneChanDoubleStereoSnk_48_4_OneChanMonoSrc_32_2_Balanced_Reliability",
+        "SingleDev_TwoChanStereoSnk_48_4_TwoChanStereoSrc_16_2_Balanced_Reliability",
+        "SingleDev_TwoChanStereoSnk_48_4_TwoChanStereoSrc_24_2_Balanced_Reliability",
+        "SingleDev_TwoChanStereoSnk_48_4_TwoChanStereoSrc_32_2_Balanced_Reliability",
+        "SingleDev_TwoChanStereoSnk_48_4_OneChanMonoSrc_16_2_Balanced_Reliability",
+        "SingleDev_TwoChanStereoSnk_48_4_OneChanMonoSrc_24_2_Balanced_Reliability",
+        "SingleDev_TwoChanStereoSnk_48_4_OneChanMonoSrc_32_2_Balanced_Reliability",
+        "SingleDev_OneChanStereoSnk_48_4_OneChanMonoSrc_16_2_Balanced_Reliability",
+        "SingleDev_OneChanStereoSnk_48_4_OneChanMonoSrc_24_2_Balanced_Reliability",
+        "SingleDev_OneChanStereoSnk_48_4_OneChanMonoSrc_32_2_Balanced_Reliability",
+        "SingleDev_OneChanMonoSnk_48_4_OneChanMonoSrc_16_2_Balanced_Reliability",
+        "SingleDev_OneChanMonoSnk_48_4_OneChanMonoSrc_24_2_Balanced_Reliability",
+        "SingleDev_OneChanMonoSnk_48_4_OneChanMonoSrc_32_2_Balanced_Reliability"
+      ]
+    },
+    {
+      "name": "Live",
+      "configurations": [
+        "VND_SingleDev_TwoChanStereoSrc_48khz_100octs_Balanced_Reliability_1",
+        "VND_SingleDev_TwoChanStereoSrc_48khz_100octs_R11_L40_1",
+        "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2_Low_Latency",
+        "DualDev_OneChanStereoSnk_OneChanStereoSrc_32_2_1",
+        "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2_Low_Latency",
+        "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_2_1",
+        "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1_Low_Latency",
+        "DualDev_OneChanStereoSnk_OneChanStereoSrc_16_1_1",
+        "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_2_Balanced_Reliability",
+        "DualDev_OneChanStereoSnk_OneChanStereoSrc_48_1_Balanced_Reliability",
+        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2_Low_Latency",
+        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_32_2_1",
+        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2_Low_Latency",
+        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_2_1",
+        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1_Low_Latency",
+        "SingleDev_TwoChanStereoSnk_TwoChanStereoSrc_16_1_1",
+        "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency",
+        "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_32_2_1",
+        "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency",
+        "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_2_1",
+        "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1_Low_Latency",
+        "SingleDev_TwoChanStereoSnk_OneChanMonoSrc_16_1_1",
+        "SingleDev_OneChanStereoSnk_OneChanMonoSrc_32_2_Low_Latency",
+        "SingleDev_OneChanStereoSnk_OneChanMonoSrc_32_2_1",
+        "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2_Low_Latency",
+        "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_2_1",
+        "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1_Low_Latency",
+        "SingleDev_OneChanStereoSnk_OneChanMonoSrc_16_1_1",
+        "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2_Low_Latency",
+        "SingleDev_OneChanMonoSnk_OneChanMonoSrc_32_2_1",
+        "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2_Low_Latency",
+        "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_2_1",
+        "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_Low_Latency",
+        "SingleDev_OneChanMonoSnk_OneChanMonoSrc_16_1_1",
+        "SingleDev_OneChanMonoSrc_48_2_Balanced_Reliability",
+        "SingleDev_OneChanMonoSrc_48_1_Balanced_Reliability",
+        "SingleDev_OneChanMonoSrc_32_2_Balanced_Reliability",
+        "SingleDev_OneChanMonoSrc_32_1_Balanced_Reliability",
+        "SingleDev_OneChanMonoSrc_16_2_Balanced_Reliability",
+        "SingleDev_OneChanMonoSrc_16_1_Balanced_Reliability"
+      ]
+    }
+  ]
+}
diff --git a/bluetooth/finder/aidl/Android.bp b/bluetooth/finder/aidl/Android.bp
new file mode 100644
index 0000000..24f5ca5
--- /dev/null
+++ b/bluetooth/finder/aidl/Android.bp
@@ -0,0 +1,38 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES 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.bluetooth.finder",
+    vendor_available: true,
+    srcs: ["android/hardware/bluetooth/finder/*.aidl"],
+    stability: "vintf",
+
+    backend: {
+        ndk: {
+            enabled: true,
+        },
+        java: {
+            enabled: true,
+            sdk_version: "module_current",
+            min_sdk_version: "30",
+            apex_available: [
+                "com.android.tethering",
+            ],
+        },
+    },
+}
diff --git a/bluetooth/finder/aidl/aidl_api/android.hardware.bluetooth.finder/current/android/hardware/bluetooth/finder/Eid.aidl b/bluetooth/finder/aidl/aidl_api/android.hardware.bluetooth.finder/current/android/hardware/bluetooth/finder/Eid.aidl
new file mode 100644
index 0000000..42461c5
--- /dev/null
+++ b/bluetooth/finder/aidl/aidl_api/android.hardware.bluetooth.finder/current/android/hardware/bluetooth/finder/Eid.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.finder;
+@VintfStability
+parcelable Eid {
+  byte[20] bytes;
+}
diff --git a/bluetooth/finder/aidl/aidl_api/android.hardware.bluetooth.finder/current/android/hardware/bluetooth/finder/IBluetoothFinder.aidl b/bluetooth/finder/aidl/aidl_api/android.hardware.bluetooth.finder/current/android/hardware/bluetooth/finder/IBluetoothFinder.aidl
new file mode 100644
index 0000000..4bc9041
--- /dev/null
+++ b/bluetooth/finder/aidl/aidl_api/android.hardware.bluetooth.finder/current/android/hardware/bluetooth/finder/IBluetoothFinder.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.finder;
+@VintfStability
+interface IBluetoothFinder {
+  void sendEids(in android.hardware.bluetooth.finder.Eid[] eids);
+  void setPoweredOffFinderMode(in boolean enable);
+  boolean getPoweredOffFinderMode();
+}
diff --git a/bluetooth/finder/aidl/android/hardware/bluetooth/finder/Eid.aidl b/bluetooth/finder/aidl/android/hardware/bluetooth/finder/Eid.aidl
new file mode 100644
index 0000000..0de306f
--- /dev/null
+++ b/bluetooth/finder/aidl/android/hardware/bluetooth/finder/Eid.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.finder;
+
+/**
+ * Find My Device network ephemeral identifier
+ */
+@VintfStability
+parcelable Eid {
+    byte[20] bytes;
+}
diff --git a/bluetooth/finder/aidl/android/hardware/bluetooth/finder/IBluetoothFinder.aidl b/bluetooth/finder/aidl/android/hardware/bluetooth/finder/IBluetoothFinder.aidl
new file mode 100644
index 0000000..a374c2a
--- /dev/null
+++ b/bluetooth/finder/aidl/android/hardware/bluetooth/finder/IBluetoothFinder.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.finder;
+
+import android.hardware.bluetooth.finder.Eid;
+
+@VintfStability
+interface IBluetoothFinder {
+    /**
+     * API to set Find My Device network EIDs to the Bluetooth Controller
+     *
+     * @param eids array of 20 bytes EID to the Bluetooth
+     * controller
+     */
+    void sendEids(in Eid[] eids);
+
+    /**
+     * API to enable the powered-off finder feature, which allows the Bluetooth controller to send
+     * beacons after the device is powered off.
+     *
+     * @param enable true to enable; false to disable
+     */
+    void setPoweredOffFinderMode(in boolean enable);
+
+    /**
+     * API for retrieving feature enablement status
+     *
+     * @return the value last set by setPoweredOffFinderMode, false if setPoweredOffFinderMode was
+     *         never been invoked since boot.
+     */
+    boolean getPoweredOffFinderMode();
+}
diff --git a/bluetooth/finder/aidl/default/Android.bp b/bluetooth/finder/aidl/default/Android.bp
new file mode 100644
index 0000000..b364ae1
--- /dev/null
+++ b/bluetooth/finder/aidl/default/Android.bp
@@ -0,0 +1,42 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_binary {
+    name: "android.hardware.bluetooth.finder-service.default",
+    relative_install_path: "hw",
+    init_rc: ["bluetooth-finder-service-default.rc"],
+    vintf_fragments: [":manifest_android.hardware.bluetooth.finder-service.default.xml"],
+    vendor: true,
+    srcs: [
+        "BluetoothFinder.cpp",
+        "service.cpp",
+    ],
+    shared_libs: [
+        "android.hardware.bluetooth.finder-V1-ndk",
+        "libbase",
+        "libbinder_ndk",
+        "libhidlbase",
+        "libutils",
+        "liblog",
+    ],
+}
+
+filegroup {
+    name: "manifest_android.hardware.bluetooth.finder-service.default.xml",
+    srcs: ["bluetooth-finder-service-default.xml"],
+}
diff --git a/bluetooth/finder/aidl/default/BluetoothFinder.cpp b/bluetooth/finder/aidl/default/BluetoothFinder.cpp
new file mode 100644
index 0000000..236a1f8
--- /dev/null
+++ b/bluetooth/finder/aidl/default/BluetoothFinder.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BluetoothFinder.h"
+
+namespace aidl::android::hardware::bluetooth::finder::impl {
+
+::ndk::ScopedAStatus BluetoothFinder::sendEids(const ::std::vector<Eid>& keys) {
+  keys_.insert(keys_.end(), keys.begin(), keys.end());
+  return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus BluetoothFinder::setPoweredOffFinderMode(bool enable) {
+  pof_enabled_ = enable;
+  return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus BluetoothFinder::getPoweredOffFinderMode(
+    bool* _aidl_return) {
+  *_aidl_return = pof_enabled_;
+  return ::ndk::ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::bluetooth::finder::impl
diff --git a/bluetooth/finder/aidl/default/BluetoothFinder.h b/bluetooth/finder/aidl/default/BluetoothFinder.h
new file mode 100644
index 0000000..16110f6
--- /dev/null
+++ b/bluetooth/finder/aidl/default/BluetoothFinder.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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/bluetooth/finder/BnBluetoothFinder.h>
+
+#include <vector>
+
+namespace aidl::android::hardware::bluetooth::finder::impl {
+
+using ::aidl::android::hardware::bluetooth::finder::BnBluetoothFinder;
+using ::aidl::android::hardware::bluetooth::finder::Eid;
+
+class BluetoothFinder : public BnBluetoothFinder {
+ public:
+  BluetoothFinder() = default;
+
+  ::ndk::ScopedAStatus sendEids(const ::std::vector<Eid>& keys) override;
+  ::ndk::ScopedAStatus setPoweredOffFinderMode(bool enable) override;
+  ::ndk::ScopedAStatus getPoweredOffFinderMode(bool* _aidl_return) override;
+
+ private:
+  bool pof_enabled_;
+  std::vector<Eid> keys_;
+};
+
+}  // namespace aidl::android::hardware::bluetooth::finder::impl
diff --git a/bluetooth/finder/aidl/default/bluetooth-finder-service-default.rc b/bluetooth/finder/aidl/default/bluetooth-finder-service-default.rc
new file mode 100644
index 0000000..64bbf09
--- /dev/null
+++ b/bluetooth/finder/aidl/default/bluetooth-finder-service-default.rc
@@ -0,0 +1,6 @@
+service vendor.bluetooth.finder-default /vendor/bin/hw/android.hardware.bluetooth.finder-service.default
+    class hal
+    capabilities BLOCK_SUSPEND NET_ADMIN SYS_NICE
+    user bluetooth
+    group bluetooth
+    task_profiles ServicePerformance
diff --git a/bluetooth/finder/aidl/default/bluetooth-finder-service-default.xml b/bluetooth/finder/aidl/default/bluetooth-finder-service-default.xml
new file mode 100644
index 0000000..be7c00d
--- /dev/null
+++ b/bluetooth/finder/aidl/default/bluetooth-finder-service-default.xml
@@ -0,0 +1,7 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.bluetooth.finder</name>
+        <version>1</version>
+        <fqname>IBluetoothFinder/default</fqname>
+    </hal>
+</manifest>
diff --git a/bluetooth/finder/aidl/default/service.cpp b/bluetooth/finder/aidl/default/service.cpp
new file mode 100644
index 0000000..a117df8
--- /dev/null
+++ b/bluetooth/finder/aidl/default/service.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "aidl.android.hardware.bluetooth.finder.default"
+
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <utils/Log.h>
+
+#include "BluetoothFinder.h"
+
+using ::aidl::android::hardware::bluetooth::finder::impl::BluetoothFinder;
+
+int main(int /* argc */, char** /* argv */) {
+  ALOGI("Bluetooth Finder HAL registering");
+  if (!ABinderProcess_setThreadPoolMaxThreadCount(0)) {
+    ALOGE("failed to set thread pool max thread count");
+    return 1;
+  }
+
+  std::shared_ptr<BluetoothFinder> service =
+      ndk::SharedRefBase::make<BluetoothFinder>();
+  std::string instance =
+      std::string() + BluetoothFinder::descriptor + "/default";
+  auto result =
+      AServiceManager_addService(service->asBinder().get(), instance.c_str());
+  if (result == STATUS_OK) {
+    ABinderProcess_joinThreadPool();
+  } else {
+    ALOGE("Could not register as a service!");
+  }
+  return 0;
+}
diff --git a/bluetooth/finder/aidl/vts/Android.bp b/bluetooth/finder/aidl/vts/Android.bp
new file mode 100644
index 0000000..6b0285e
--- /dev/null
+++ b/bluetooth/finder/aidl/vts/Android.bp
@@ -0,0 +1,41 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES 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: "VtsHalBluetoothFinderTargetTest",
+    defaults: [
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: ["VtsHalBluetoothFinderTargetTest.cpp"],
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "libbinder_ndk",
+        "liblog",
+        "libutils",
+    ],
+    static_libs: [
+        "android.hardware.bluetooth.finder-V1-ndk",
+        "libbluetooth-types",
+    ],
+    test_config: "VtsHalBluetoothFinderTargetTest.xml",
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
diff --git a/bluetooth/finder/aidl/vts/VtsHalBluetoothFinderTargetTest.cpp b/bluetooth/finder/aidl/vts/VtsHalBluetoothFinderTargetTest.cpp
new file mode 100644
index 0000000..be07a7d
--- /dev/null
+++ b/bluetooth/finder/aidl/vts/VtsHalBluetoothFinderTargetTest.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/bluetooth/finder/IBluetoothFinder.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <binder/IServiceManager.h>
+#include <utils/Log.h>
+
+#include <array>
+#include <vector>
+
+using ::aidl::android::hardware::bluetooth::finder::Eid;
+using ::aidl::android::hardware::bluetooth::finder::IBluetoothFinder;
+using ::ndk::ScopedAStatus;
+
+class BluetoothFinderTest : public ::testing::TestWithParam<std::string> {
+ public:
+  virtual void SetUp() override {
+    ALOGI("SetUp Finder Test");
+    bluetooth_finder = IBluetoothFinder::fromBinder(
+        ndk::SpAIBinder(AServiceManager_waitForService(GetParam().c_str())));
+    ASSERT_NE(bluetooth_finder, nullptr);
+  }
+
+  virtual void TearDown() override {
+    ALOGI("TearDown Finder Test");
+    bluetooth_finder = nullptr;
+    ASSERT_EQ(bluetooth_finder, nullptr);
+  }
+
+  ScopedAStatus sendEids(uint8_t num);
+  ScopedAStatus setPoweredOffFinderMode(bool enable);
+  ScopedAStatus getPoweredOffFinderMode(bool* status);
+
+ private:
+  std::shared_ptr<IBluetoothFinder> bluetooth_finder;
+};
+
+ScopedAStatus BluetoothFinderTest::sendEids(uint8_t numKeys) {
+  std::vector<Eid> keys(numKeys);
+  for (uint_t i = 0; i < numKeys; i++) {
+    std::array<uint8_t, 20> key;
+    key.fill(i + 1);
+    keys[i].bytes = key;
+  }
+  return bluetooth_finder->sendEids(keys);
+}
+
+ScopedAStatus BluetoothFinderTest::setPoweredOffFinderMode(bool enable) {
+  return bluetooth_finder->setPoweredOffFinderMode(enable);
+}
+
+ScopedAStatus BluetoothFinderTest::getPoweredOffFinderMode(bool* status) {
+  return bluetooth_finder->getPoweredOffFinderMode(status);
+}
+
+TEST_P(BluetoothFinderTest, SendEidsSingle) {
+  ScopedAStatus status = sendEids(1);
+  ASSERT_TRUE(status.isOk());
+}
+
+TEST_P(BluetoothFinderTest, Send255Eids) {
+  ScopedAStatus status = sendEids(255);
+  ASSERT_TRUE(status.isOk());
+}
+
+TEST_P(BluetoothFinderTest, setAndGetPoweredOffFinderModeEnable) {
+  ScopedAStatus status = setPoweredOffFinderMode(true);
+  ASSERT_TRUE(status.isOk());
+  bool pof_status;
+  status = getPoweredOffFinderMode(&pof_status);
+  ASSERT_TRUE(status.isOk());
+  ASSERT_TRUE(pof_status);
+}
+
+TEST_P(BluetoothFinderTest, setAndGetPoweredOffFinderModeDisable) {
+  ScopedAStatus status = setPoweredOffFinderMode(false);
+  ASSERT_TRUE(status.isOk());
+  bool pof_status;
+  status = getPoweredOffFinderMode(&pof_status);
+  ASSERT_TRUE(status.isOk());
+  ASSERT_TRUE(!pof_status);
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BluetoothFinderTest);
+INSTANTIATE_TEST_SUITE_P(PerInstance, BluetoothFinderTest,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(
+                             IBluetoothFinder::descriptor)),
+                         android::PrintInstanceNameToString);
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  ABinderProcess_startThreadPool();
+  int status = RUN_ALL_TESTS();
+  ALOGI("Test result = %d", status);
+  return status;
+}
diff --git a/bluetooth/finder/aidl/vts/VtsHalBluetoothFinderTargetTest.xml b/bluetooth/finder/aidl/vts/VtsHalBluetoothFinderTargetTest.xml
new file mode 100644
index 0000000..46053dd
--- /dev/null
+++ b/bluetooth/finder/aidl/vts/VtsHalBluetoothFinderTargetTest.xml
@@ -0,0 +1,33 @@
+<!--
+  Copyright (C) 2023 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT 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 VtsHalBluetoothFinderTargetTest.">
+    <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="VtsHalBluetoothFinderTargetTest->/data/local/tmp/VtsHalBluetoothFinderTargetTest" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="VtsHalBluetoothFinderTargetTest" />
+    </test>
+</configuration>
diff --git a/bluetooth/hci/h4_protocol.cc b/bluetooth/hci/h4_protocol.cc
index 51a624f..5f6d86e 100644
--- a/bluetooth/hci/h4_protocol.cc
+++ b/bluetooth/hci/h4_protocol.cc
@@ -105,15 +105,12 @@
       buffer_offset += 1;
     } else {
       bool packet_ready = hci_packetizer_.OnDataReady(
-          hci_packet_type_, input_buffer, buffer_offset);
+          hci_packet_type_, input_buffer, &buffer_offset);
       if (packet_ready) {
-        // Call packet callback and move offset.
-        buffer_offset += OnPacketReady(hci_packetizer_.GetPacket());
+        // Call packet callback.
+        OnPacketReady(hci_packetizer_.GetPacket());
         // Get ready for the next type byte.
         hci_packet_type_ = PacketType::UNKNOWN;
-      } else {
-        // The data was consumed, but there wasn't a packet.
-        buffer_offset = input_buffer.size();
       }
     }
   }
diff --git a/bluetooth/hci/hci_packetizer.cc b/bluetooth/hci/hci_packetizer.cc
index 5b6c443..4135920 100644
--- a/bluetooth/hci/hci_packetizer.cc
+++ b/bluetooth/hci/hci_packetizer.cc
@@ -51,9 +51,10 @@
 
 bool HciPacketizer::OnDataReady(PacketType packet_type,
                                 const std::vector<uint8_t>& buffer,
-                                size_t offset) {
+                                size_t* offset) {
   bool packet_completed = false;
-  size_t bytes_available = buffer.size() - offset;
+  size_t bytes_available = buffer.size() - *offset;
+
   switch (state_) {
     case HCI_HEADER: {
       size_t header_size =
@@ -62,18 +63,20 @@
         bytes_remaining_ = header_size;
         packet_.clear();
       }
+
       size_t bytes_to_copy = std::min(bytes_remaining_, bytes_available);
-      packet_.insert(packet_.end(), buffer.begin() + offset,
-                     buffer.begin() + offset + bytes_to_copy);
+      packet_.insert(packet_.end(), buffer.begin() + *offset,
+                     buffer.begin() + *offset + bytes_to_copy);
       bytes_remaining_ -= bytes_to_copy;
       bytes_available -= bytes_to_copy;
+      *offset += bytes_to_copy;
+
       if (bytes_remaining_ == 0) {
         bytes_remaining_ = HciGetPacketLengthForType(packet_type, packet_);
         if (bytes_remaining_ > 0) {
           state_ = HCI_PAYLOAD;
           if (bytes_available > 0) {
-            packet_completed =
-                OnDataReady(packet_type, buffer, offset + bytes_to_copy);
+            packet_completed = OnDataReady(packet_type, buffer, offset);
           }
         } else {
           packet_completed = true;
@@ -84,9 +87,10 @@
 
     case HCI_PAYLOAD: {
       size_t bytes_to_copy = std::min(bytes_remaining_, bytes_available);
-      packet_.insert(packet_.end(), buffer.begin() + offset,
-                     buffer.begin() + offset + bytes_to_copy);
+      packet_.insert(packet_.end(), buffer.begin() + *offset,
+                     buffer.begin() + *offset + bytes_to_copy);
       bytes_remaining_ -= bytes_to_copy;
+      *offset += bytes_to_copy;
       if (bytes_remaining_ == 0) {
         state_ = HCI_HEADER;
         packet_completed = true;
@@ -94,6 +98,7 @@
       break;
     }
   }
+
   return packet_completed;
 }
 
diff --git a/bluetooth/hci/hci_packetizer.h b/bluetooth/hci/hci_packetizer.h
index ba3e841..0d9319f 100644
--- a/bluetooth/hci/hci_packetizer.h
+++ b/bluetooth/hci/hci_packetizer.h
@@ -28,7 +28,7 @@
  public:
   HciPacketizer() = default;
   bool OnDataReady(PacketType packet_type, const std::vector<uint8_t>& data,
-                   size_t offset);
+                   size_t* offset);
   const std::vector<uint8_t>& GetPacket() const;
 
  protected:
diff --git a/bluetooth/hci/test/h4_protocol_unittest.cc b/bluetooth/hci/test/h4_protocol_unittest.cc
index d3fab61..f0c49b5 100644
--- a/bluetooth/hci/test/h4_protocol_unittest.cc
+++ b/bluetooth/hci/test/h4_protocol_unittest.cc
@@ -31,7 +31,6 @@
 #include <vector>
 
 #include "async_fd_watcher.h"
-#include "log/log.h"
 
 using android::hardware::bluetooth::async::AsyncFdWatcher;
 using namespace android::hardware::bluetooth::hci;
@@ -49,6 +48,7 @@
 static char event_data[100] = "The edges of a surface are lines.";
 static char iso_data[100] =
     "A plane angle is the inclination to one another of two lines in a ...";
+static char short_payload[10] = "12345";
 
 // 5 seconds.  Just don't hang.
 static constexpr size_t kTimeoutMs = 5000;
@@ -225,6 +225,49 @@
     CallDataReady();
   }
 
+  void WriteAndExpectManyAclDataPacketsDifferentOffsetsShort() {
+    std::promise<void> last_packet_promise;
+    size_t kNumPackets = 30;
+    // h4 type[1] + handle[2] + size[2]
+    char preamble[5] = {static_cast<uint8_t>(PacketType::ACL_DATA), 19, 92, 0,
+                        0};
+    int length = strlen(short_payload);
+    preamble[3] = length & 0xFF;
+    preamble[4] = 0;
+
+    EXPECT_CALL(acl_cb_, Call(PacketMatches(preamble + 1, kAclHeaderSize,
+                                            short_payload)))
+        .Times(kNumPackets);
+    ExpectInboundEvent(event_data, &last_packet_promise);
+
+    char all_packets[kNumPackets * 10];
+    size_t total_bytes = 0;
+
+    for (size_t packet = 0; packet < kNumPackets; packet++) {
+      for (size_t i = 0; i < sizeof(preamble); i++) {
+        all_packets[total_bytes++] = preamble[i];
+      }
+      for (size_t i = 0; i < length; i++) {
+        all_packets[total_bytes++] = short_payload[i];
+      }
+    }
+
+    size_t written_bytes = 0;
+    size_t partial_size = 1;
+    while (written_bytes < total_bytes) {
+      size_t to_write = std::min(partial_size, total_bytes - written_bytes);
+      TEMP_FAILURE_RETRY(
+          write(chip_uart_fd_, all_packets + written_bytes, to_write));
+      written_bytes += to_write;
+      CallDataReady();
+      partial_size++;
+      partial_size = partial_size % 5 + 1;
+    }
+    WriteInboundEvent(event_data);
+    CallDataReady();
+    WaitForTimeout(&last_packet_promise);
+  }
+
   testing::MockFunction<void(const std::vector<uint8_t>&)> cmd_cb_;
   testing::MockFunction<void(const std::vector<uint8_t>&)> event_cb_;
   testing::MockFunction<void(const std::vector<uint8_t>&)> acl_cb_;
@@ -276,6 +319,10 @@
   WriteAndExpectManyInboundAclDataPackets(sco_data);
 }
 
+TEST_F(H4ProtocolTest, TestMultipleWritesPacketsShortWrites) {
+  WriteAndExpectManyAclDataPacketsDifferentOffsetsShort();
+}
+
 TEST_F(H4ProtocolTest, TestDisconnect) {
   EXPECT_CALL(disconnect_cb_, Call());
   close(chip_uart_fd_);
@@ -332,10 +379,8 @@
 
   void TearDown() override { fd_watcher_.StopWatchingFileDescriptors(); }
 
-  void CallDataReady() override {
-    // The Async test can't call data ready.
-    FAIL();
-  }
+  // Calling CallDataReady() has no effect in the AsyncTest
+  void CallDataReady() override {}
 
   void SendAndReadUartOutbound(PacketType type, char* data) {
     ALOGD("%s sending", __func__);
@@ -434,6 +479,10 @@
   WriteAndExpectManyInboundAclDataPackets(sco_data);
 }
 
+TEST_F(H4ProtocolAsyncTest, TestMultipleWritesPacketsShortWrites) {
+  WriteAndExpectManyAclDataPacketsDifferentOffsetsShort();
+}
+
 TEST_F(H4ProtocolAsyncTest, TestDisconnect) {
   std::promise<void> promise;
   EXPECT_CALL(disconnect_cb_, Call()).WillOnce(Notify(&promise));
diff --git a/bluetooth/lmp_event/aidl/Android.bp b/bluetooth/lmp_event/aidl/Android.bp
new file mode 100644
index 0000000..6c2f278
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/Android.bp
@@ -0,0 +1,33 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+    name: "android.hardware.bluetooth.lmp_event",
+    vendor_available: true,
+    host_supported: true,
+    srcs: ["android/hardware/bluetooth/lmp_event/*.aidl"],
+    stability: "vintf",
+    backend: {
+        java: {
+            enabled: true,
+            platform_apis: true,
+        },
+        cpp: {
+            enabled: true,
+        },
+        ndk: {
+            enabled: true,
+            min_sdk_version: "33",
+        },
+        rust: {
+            enabled: true,
+            min_sdk_version: "33",
+        },
+    },
+}
diff --git a/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/AddressType.aidl b/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/AddressType.aidl
new file mode 100644
index 0000000..0f239e8
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/AddressType.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.lmp_event;
+@Backing(type="byte") @VintfStability
+enum AddressType {
+  PUBLIC = 0x00,
+  RANDOM = 0x01,
+}
diff --git a/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/Direction.aidl b/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/Direction.aidl
new file mode 100644
index 0000000..6f807cc
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/Direction.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.lmp_event;
+@Backing(type="byte") @VintfStability
+enum Direction {
+  TX = 0x00,
+  RX = 0x01,
+}
diff --git a/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/IBluetoothLmpEvent.aidl b/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/IBluetoothLmpEvent.aidl
new file mode 100644
index 0000000..3431010
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/IBluetoothLmpEvent.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.lmp_event;
+@VintfStability
+interface IBluetoothLmpEvent {
+  void registerForLmpEvents(in android.hardware.bluetooth.lmp_event.IBluetoothLmpEventCallback callback, in android.hardware.bluetooth.lmp_event.AddressType addressType, in byte[6] address, in android.hardware.bluetooth.lmp_event.LmpEventId[] lmpEventIds);
+  void unregisterLmpEvents(in android.hardware.bluetooth.lmp_event.AddressType addressType, in byte[6] address);
+}
diff --git a/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/IBluetoothLmpEventCallback.aidl b/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/IBluetoothLmpEventCallback.aidl
new file mode 100644
index 0000000..fc6758c
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/IBluetoothLmpEventCallback.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.lmp_event;
+@VintfStability
+interface IBluetoothLmpEventCallback {
+  void onEventGenerated(in android.hardware.bluetooth.lmp_event.Timestamp timestamp, in android.hardware.bluetooth.lmp_event.AddressType addressType, in byte[6] address, in android.hardware.bluetooth.lmp_event.Direction direction, in android.hardware.bluetooth.lmp_event.LmpEventId lmpEventId, in char connEventCounter);
+  void onRegistered(in boolean status);
+}
diff --git a/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/LmpEventId.aidl b/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/LmpEventId.aidl
new file mode 100644
index 0000000..4ee95d1
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/LmpEventId.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.lmp_event;
+@Backing(type="byte") @VintfStability
+enum LmpEventId {
+  CONNECT_IND = 0x00,
+  LL_PHY_UPDATE_IND = 0x01,
+}
diff --git a/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/Timestamp.aidl b/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/Timestamp.aidl
new file mode 100644
index 0000000..5ef32ba
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/aidl_api/android.hardware.bluetooth.lmp_event/current/android/hardware/bluetooth/lmp_event/Timestamp.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.lmp_event;
+@VintfStability
+parcelable Timestamp {
+  long systemTimeUs;
+  long bluetoothTimeUs;
+}
diff --git a/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/AddressType.aidl b/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/AddressType.aidl
new file mode 100644
index 0000000..6bfc7c7
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/AddressType.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.lmp_event;
+
+/**
+ * Type of Address
+ */
+@VintfStability
+@Backing(type="byte")
+enum AddressType {
+    PUBLIC = 0x00,
+    RANDOM = 0x01,
+}
diff --git a/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/Direction.aidl b/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/Direction.aidl
new file mode 100644
index 0000000..884c2bb
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/Direction.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.lmp_event;
+
+/**
+ * Direction of the LMP event
+ */
+@VintfStability
+@Backing(type="byte")
+enum Direction {
+    TX = 0x00,
+    RX = 0x01,
+}
diff --git a/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/IBluetoothLmpEvent.aidl b/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/IBluetoothLmpEvent.aidl
new file mode 100644
index 0000000..3828af6
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/IBluetoothLmpEvent.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.lmp_event;
+
+import android.hardware.bluetooth.lmp_event.IBluetoothLmpEventCallback;
+import android.hardware.bluetooth.lmp_event.AddressType;
+import android.hardware.bluetooth.lmp_event.LmpEventId;
+
+@VintfStability
+interface IBluetoothLmpEvent {
+    /**
+     * API to monitor specific LMP event timestamp for given Bluetooth device.
+     *
+     * @param callback An instance of the |IBluetoothLmpEventCallback| AIDL interface object.
+     * @param addressType  Type of bluetooth address.
+     * @param address Bluetooth address to monitor.
+     * @param lmpEventIds LMP events to monitor.
+     */
+    void registerForLmpEvents(in IBluetoothLmpEventCallback callback,
+                              in AddressType addressType,
+                              in byte[6] address,
+                              in LmpEventId[] lmpEventIds);
+
+    /**
+     * API to stop monitoring a given Bluetooth device.
+     *
+     * @param addressType  Type of Bluetooth address.
+     * @param address Bluetooth device to stop monitoring.
+     */
+    void unregisterLmpEvents(in AddressType addressType, in byte[6] address);
+}
diff --git a/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/IBluetoothLmpEventCallback.aidl b/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/IBluetoothLmpEventCallback.aidl
new file mode 100644
index 0000000..3295ef0
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/IBluetoothLmpEventCallback.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.lmp_event;
+
+import android.hardware.bluetooth.lmp_event.Direction;
+import android.hardware.bluetooth.lmp_event.AddressType;
+import android.hardware.bluetooth.lmp_event.LmpEventId;
+import android.hardware.bluetooth.lmp_event.Timestamp;
+
+@VintfStability
+interface IBluetoothLmpEventCallback {
+    /**
+     * Callback when monitored LMP event invoked.
+     *
+     * @param timestamp Timestamp when the LMP event invoked
+     * @param addressType  Type of Bluetooth address.
+     * @param address Remote bluetooth address that invoke LMP event
+     * @param direction Direction of the invoked LMP event
+     * @param lmpEventId LMP event id that bluetooth chip invoked
+     * @param connEventCounter counter incremented by one for each new connection event
+     */
+    void onEventGenerated(in Timestamp timestamp,
+                          in AddressType addressType,
+                          in byte[6] address,
+                          in Direction direction,
+                          in LmpEventId lmpEventId,
+                          in char connEventCounter);
+
+    /**
+     * Callback when registration done.
+     */
+    void onRegistered(in boolean status);
+}
diff --git a/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/LmpEventId.aidl b/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/LmpEventId.aidl
new file mode 100644
index 0000000..3584b0c
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/LmpEventId.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.lmp_event;
+
+/**
+ * LMP event id to be monitored
+ * CONNECT_IND indicator for initiating connection
+ * LL_PHY_UPDATE_IND indicator for PHY update
+ */
+@VintfStability
+@Backing(type="byte")
+enum LmpEventId {
+    CONNECT_IND = 0x00,
+    LL_PHY_UPDATE_IND = 0x01,
+}
diff --git a/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/Timestamp.aidl b/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/Timestamp.aidl
new file mode 100644
index 0000000..e3c991d
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/android/hardware/bluetooth/lmp_event/Timestamp.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.lmp_event;
+
+/**
+ * Generic structure to return the timestamp
+ */
+@VintfStability
+parcelable Timestamp {
+    /**
+     * Timestamp in microsecond since system boot.
+     *  if systemTimeUs is set to 0, its value is to be ignored
+     */
+    long systemTimeUs;
+    /**
+     * Timestamp in microsecond since Bluetooth controller power up.
+     */
+    long bluetoothTimeUs;
+}
diff --git a/bluetooth/lmp_event/aidl/default/Android.bp b/bluetooth/lmp_event/aidl/default/Android.bp
new file mode 100644
index 0000000..f8ca5e6
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/default/Android.bp
@@ -0,0 +1,28 @@
+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"],
+}
+
+rust_binary {
+    name: "android.hardware.bluetooth.lmp_event-service.default",
+    relative_install_path: "hw",
+    init_rc: ["lmp_event-default.rc"],
+    vintf_fragments: [":manifest_android.hardware.bluetooth.lmp_event-service.default.xml"],
+    vendor: true,
+    rustlibs: [
+        "liblogger",
+        "liblog_rust",
+        "libbinder_rs",
+        "android.hardware.bluetooth.lmp_event-V1-rust",
+    ],
+    srcs: [ "src/main.rs" ],
+}
+
+filegroup {
+    name: "manifest_android.hardware.bluetooth.lmp_event-service.default.xml",
+    srcs: [ "lmp_event-default.xml" ],
+}
diff --git a/bluetooth/lmp_event/aidl/default/lmp_event-default.rc b/bluetooth/lmp_event/aidl/default/lmp_event-default.rc
new file mode 100644
index 0000000..845e04d
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/default/lmp_event-default.rc
@@ -0,0 +1,6 @@
+service vendor.bluetooth.lmp_event-default /vendor/bin/hw/android.hardware.bluetooth.lmp_event-service.default
+    class hal
+    capabilities BLOCK_SUSPEND NET_ADMIN SYS_NICE
+    user bluetooth
+    group bluetooth
+    task_profiles HighPerformance
diff --git a/bluetooth/lmp_event/aidl/default/lmp_event-default.xml b/bluetooth/lmp_event/aidl/default/lmp_event-default.xml
new file mode 100644
index 0000000..24d93f8
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/default/lmp_event-default.xml
@@ -0,0 +1,10 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.bluetooth.lmp_event</name>
+        <version>1</version>
+        <interface>
+            <name>IBluetoothLmpEvent</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/bluetooth/lmp_event/aidl/default/src/lmp_event.rs b/bluetooth/lmp_event/aidl/default/src/lmp_event.rs
new file mode 100644
index 0000000..f016c3f
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/default/src/lmp_event.rs
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+//! Implements LMP Event AIDL Interface.
+
+use android_hardware_bluetooth_lmp_event::aidl::android::hardware::bluetooth::lmp_event::{
+    Direction::Direction, AddressType::AddressType, IBluetoothLmpEvent::IBluetoothLmpEvent,
+    IBluetoothLmpEventCallback::IBluetoothLmpEventCallback, LmpEventId::LmpEventId,
+    Timestamp::Timestamp,
+};
+
+use binder::{Interface, Result, Strong};
+
+use log::info;
+use std::thread;
+use std::time;
+
+
+pub struct LmpEvent;
+
+impl LmpEvent {
+    pub fn new() -> Self {
+        Self
+    }
+}
+
+impl Interface for LmpEvent {}
+
+impl IBluetoothLmpEvent for LmpEvent {
+    fn registerForLmpEvents(&self,
+                            callback: &Strong<dyn IBluetoothLmpEventCallback>,
+                            address_type: AddressType,
+                            address: &[u8; 6],
+                            lmp_event_ids: &[LmpEventId]
+    ) -> Result<()> {
+        info!("registerForLmpEvents");
+
+        let cb = callback.clone();
+        let addr_type = address_type;
+        let addr = address.clone();
+        let lmp_event = lmp_event_ids.to_vec();
+
+        let thread_handle = thread::spawn(move || {
+            let ts = Timestamp {
+                bluetoothTimeUs: 1000000,
+                systemTimeUs: 2000000,
+            };
+
+            info!("sleep for 1000 ms");
+            thread::sleep(time::Duration::from_millis(1000));
+
+            info!("callback event");
+            cb.onEventGenerated(&ts, addr_type, &addr, Direction::RX, lmp_event[0], 1)
+                .expect("onEventGenerated failed");
+        });
+
+        info!("callback register");
+        callback.onRegistered(true)?;
+
+        thread_handle.join().expect("join failed");
+        Ok(())
+    }
+    fn unregisterLmpEvents(&self, _address_type: AddressType, _address: &[u8; 6]) -> Result<()> {
+        info!("unregisterLmpEvents");
+
+        Ok(())
+    }
+}
diff --git a/bluetooth/lmp_event/aidl/default/src/main.rs b/bluetooth/lmp_event/aidl/default/src/main.rs
new file mode 100644
index 0000000..cbdd4d1
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/default/src/main.rs
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+//! Implements LMP Event Example Service.
+
+
+use android_hardware_bluetooth_lmp_event::aidl::android::hardware::bluetooth::lmp_event::IBluetoothLmpEvent::{
+    IBluetoothLmpEvent, BnBluetoothLmpEvent
+};
+
+use binder::BinderFeatures;
+use log::{info, Level};
+
+mod lmp_event;
+
+const LOG_TAG: &str = "lmp_event_service_example";
+
+fn main() {
+    info!("{LOG_TAG}: starting service");
+    let logger_success = logger::init(
+        logger::Config::default().with_tag_on_device(LOG_TAG).with_min_level(Level::Trace)
+    );
+    if !logger_success {
+        panic!("{LOG_TAG}: Failed to start logger");
+    }
+
+    binder::ProcessState::set_thread_pool_max_thread_count(0);
+
+    let lmp_event_service = lmp_event::LmpEvent::new();
+    let lmp_event_service_binder = BnBluetoothLmpEvent::new_binder(lmp_event_service, BinderFeatures::default());
+
+    binder::add_service(
+        &format!("{}/default", lmp_event::LmpEvent::get_descriptor()),
+        lmp_event_service_binder.as_binder(),
+    ).expect("Failed to register service");
+
+    binder::ProcessState::join_thread_pool()
+}
diff --git a/bluetooth/lmp_event/aidl/vts/Android.bp b/bluetooth/lmp_event/aidl/vts/Android.bp
new file mode 100644
index 0000000..b89351e
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/vts/Android.bp
@@ -0,0 +1,20 @@
+cc_test {
+    name: "VtsHalLmpEventTargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: ["VtsHalLmpEventTargetTest.cpp"],
+    shared_libs: [
+        "libbinder",
+        "libbinder_ndk"
+    ],
+    static_libs: [
+        "android.hardware.bluetooth.lmp_event-V1-ndk",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ]
+}
+
diff --git a/bluetooth/lmp_event/aidl/vts/VtsHalLmpEventTargetTest.cpp b/bluetooth/lmp_event/aidl/vts/VtsHalLmpEventTargetTest.cpp
new file mode 100644
index 0000000..c49f60b
--- /dev/null
+++ b/bluetooth/lmp_event/aidl/vts/VtsHalLmpEventTargetTest.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the std::shared_ptrecific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "lmp_event_hal_test"
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+
+#include <aidl/android/hardware/bluetooth/lmp_event/BnBluetoothLmpEvent.h>
+#include <aidl/android/hardware/bluetooth/lmp_event/BnBluetoothLmpEventCallback.h>
+#include <aidl/android/hardware/bluetooth/lmp_event/Direction.h>
+#include <aidl/android/hardware/bluetooth/lmp_event/AddressType.h>
+#include <aidl/android/hardware/bluetooth/lmp_event/LmpEventId.h>
+#include <aidl/android/hardware/bluetooth/lmp_event/Timestamp.h>
+
+#include <android/binder_auto_utils.h>
+#include <android/binder_manager.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <log/log.h>
+
+#include <chrono>
+#include <condition_variable>
+#include <cinttypes>
+#include <thread>
+
+using ::aidl::android::hardware::bluetooth::lmp_event::BnBluetoothLmpEventCallback;
+using ::aidl::android::hardware::bluetooth::lmp_event::IBluetoothLmpEvent;
+using ::aidl::android::hardware::bluetooth::lmp_event::IBluetoothLmpEventCallback;
+using ::aidl::android::hardware::bluetooth::lmp_event::Direction;
+using ::aidl::android::hardware::bluetooth::lmp_event::AddressType;
+using ::aidl::android::hardware::bluetooth::lmp_event::LmpEventId;
+using ::aidl::android::hardware::bluetooth::lmp_event::Timestamp;
+
+using ::android::ProcessState;
+using ::ndk::SpAIBinder;
+
+namespace {
+    static constexpr std::chrono::milliseconds kEventTimeoutMs(10000);
+}
+
+class BluetoothLmpEventTest : public testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        ALOGI("%s", __func__);
+
+        ibt_lmp_event_ = IBluetoothLmpEvent::fromBinder(SpAIBinder(AServiceManager_waitForService(GetParam().c_str())));
+        ASSERT_NE(ibt_lmp_event_, nullptr);
+
+        ibt_lmp_event_cb_ = ndk::SharedRefBase::make<BluetoothLmpEventCallback>(*this);
+        ASSERT_NE(ibt_lmp_event_cb_, nullptr);
+    }
+
+    virtual void TearDown() override {
+        ALOGI("%s", __func__);
+        ibt_lmp_event_->unregisterLmpEvents(address_type, address);
+
+        ibt_lmp_event_cb_ = nullptr;
+    }
+
+    class BluetoothLmpEventCallback : public BnBluetoothLmpEventCallback {
+        public:
+            BluetoothLmpEventTest& parent_;
+            BluetoothLmpEventCallback(BluetoothLmpEventTest& parent)
+                : parent_(parent) {}
+            ~BluetoothLmpEventCallback() = default;
+
+            ::ndk::ScopedAStatus onEventGenerated(const Timestamp& timestamp, AddressType address_type,
+                    const std::array<uint8_t, 6>& address, Direction direction,
+                    LmpEventId lmp_event_id, char16_t conn_event_counter) override {
+                for (auto t: address) {
+                    ALOGD("%s: 0x%02x", __func__, t);
+                }
+                if (direction == Direction::TX) {
+                    ALOGD("%s: Transmitting", __func__);
+                } else if (direction == Direction::RX) {
+                    ALOGD("%s: Receiving", __func__);
+                }
+                if (address_type == AddressType::PUBLIC) {
+                    ALOGD("%s: Public address", __func__);
+                } else if (address_type == AddressType::RANDOM) {
+                    ALOGD("%s: Random address", __func__);
+                }
+                if (lmp_event_id == LmpEventId::CONNECT_IND) {
+                    ALOGD("%s: initiating connection", __func__);
+                } else if (lmp_event_id == LmpEventId::LL_PHY_UPDATE_IND) {
+                    ALOGD("%s: PHY update indication", __func__);
+                }
+
+                ALOGD("%s: time: %" PRId64 "counter value: %x", __func__, timestamp.bluetoothTimeUs, conn_event_counter);
+
+                parent_.event_recv = true;
+                parent_.notify();
+
+                return ::ndk::ScopedAStatus::ok();
+            }
+            ::ndk::ScopedAStatus onRegistered(bool status) override {
+                ALOGD("%s: status: %d", __func__, status);
+                parent_.status_recv = status;
+                parent_.notify();
+                return ::ndk::ScopedAStatus::ok();
+            }
+    };
+
+    inline void notify() {
+        std::unique_lock<std::mutex> lock(lmp_event_mtx);
+        lmp_event_cv.notify_one();
+    }
+
+    inline void wait(bool is_register_event) {
+        std::unique_lock<std::mutex> lock(lmp_event_mtx);
+
+
+        if (is_register_event) {
+            lmp_event_cv.wait(lock, [&]() { return status_recv == true; });
+        } else {
+            lmp_event_cv.wait_for(lock, kEventTimeoutMs,
+                    [&](){ return event_recv == true; });
+        }
+
+    }
+
+    std::shared_ptr<IBluetoothLmpEvent> ibt_lmp_event_;
+    std::shared_ptr<IBluetoothLmpEventCallback> ibt_lmp_event_cb_;
+
+    AddressType address_type;
+    std::array<uint8_t, 6> address;
+
+    std::atomic<bool> event_recv;
+    bool status_recv;
+
+    std::mutex lmp_event_mtx;
+    std::condition_variable lmp_event_cv;
+};
+
+TEST_P(BluetoothLmpEventTest, RegisterAndReceive) {
+    address = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+    address_type = AddressType::RANDOM;
+    std::vector<LmpEventId> lmp_event_ids{LmpEventId::CONNECT_IND, LmpEventId::LL_PHY_UPDATE_IND};
+
+    ibt_lmp_event_->registerForLmpEvents(ibt_lmp_event_cb_, address_type, address, lmp_event_ids);
+    wait(true);
+    EXPECT_EQ(true, status_recv);
+
+    /* Wait for event generated here */
+    wait(false);
+    EXPECT_EQ(true, event_recv);
+
+    ibt_lmp_event_->unregisterLmpEvents(address_type, address);
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BluetoothLmpEventTest);
+INSTANTIATE_TEST_SUITE_P(BluetoothLmpEvent, BluetoothLmpEventTest,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(IBluetoothLmpEvent::descriptor)),
+                         android::PrintInstanceNameToString);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ProcessState::self()->setThreadPoolMaxThreadCount(1);
+    ProcessState::self()->startThreadPool();
+    return RUN_ALL_TESTS();
+}
+
diff --git a/bluetooth/ranging/OWNERS b/bluetooth/ranging/OWNERS
new file mode 100644
index 0000000..3d95624
--- /dev/null
+++ b/bluetooth/ranging/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 27441
+
+include platform/packages/modules/Bluetooth:/OWNERS
+
+chienyuanhuang@google.com
diff --git a/bluetooth/ranging/aidl/Android.bp b/bluetooth/ranging/aidl/Android.bp
new file mode 100644
index 0000000..9e53ef6
--- /dev/null
+++ b/bluetooth/ranging/aidl/Android.bp
@@ -0,0 +1,39 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES 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.bluetooth.ranging",
+    vendor_available: true,
+    host_supported: true,
+    srcs: ["android/hardware/bluetooth/ranging/*.aidl"],
+    stability: "vintf",
+    backend: {
+        ndk: {
+            apex_available: [
+                "//apex_available:platform",
+                "com.android.btservices",
+            ],
+            min_sdk_version: "33",
+        },
+    },
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/AddressType.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/AddressType.aidl
new file mode 100644
index 0000000..fc417f0
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/AddressType.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.ranging;
+@Backing(type="int") @VintfStability
+enum AddressType {
+  PUBLIC = 0x00,
+  RANDOM = 0x01,
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/BluetoothChannelSoundingParameters.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/BluetoothChannelSoundingParameters.aidl
new file mode 100644
index 0000000..e8fefbe
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/BluetoothChannelSoundingParameters.aidl
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.ranging;
+@VintfStability
+parcelable BluetoothChannelSoundingParameters {
+  android.hardware.bluetooth.ranging.SessionType sessionType;
+  int aclHandle;
+  int l2capCid;
+  int realTimeProcedureDataAttHandle;
+  android.hardware.bluetooth.ranging.Role role;
+  boolean localSupportsSoundingPhaseBasedRanging;
+  boolean remoteSupportsSoundingPhaseBaseRanging;
+  android.hardware.bluetooth.ranging.Config config;
+  android.hardware.bluetooth.ranging.DeviceAddress address;
+  @nullable android.hardware.bluetooth.ranging.VendorSpecificData[] vendorSpecificData;
+  android.hardware.bluetooth.ranging.LocationType locationType;
+  android.hardware.bluetooth.ranging.SightType sightType;
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ChannelSoudingRawData.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ChannelSoudingRawData.aidl
new file mode 100644
index 0000000..8fc77ae
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ChannelSoudingRawData.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.ranging;
+@VintfStability
+parcelable ChannelSoudingRawData {
+  int procedureCounter;
+  int[] frequencyCompensation;
+  boolean aborted;
+  android.hardware.bluetooth.ranging.ChannelSoundingSingleSideData initiatorData;
+  android.hardware.bluetooth.ranging.ChannelSoundingSingleSideData reflectorData;
+  byte[] stepChannels;
+  @nullable int[] toaTodInitiator;
+  @nullable int[] todToaReflector;
+  android.hardware.bluetooth.ranging.ModeType[] stepMode;
+  byte numAntennaPaths;
+  long timestampMs;
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ChannelSoundingSingleSideData.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ChannelSoundingSingleSideData.aidl
new file mode 100644
index 0000000..172ac5e
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ChannelSoundingSingleSideData.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.ranging;
+@VintfStability
+parcelable ChannelSoundingSingleSideData {
+  @nullable android.hardware.bluetooth.ranging.StepTonePct[] stepTonePcts;
+  @nullable byte[] packetQuality;
+  @nullable byte[] packetRssiDbm;
+  @nullable android.hardware.bluetooth.ranging.Nadm[] packetNadm;
+  @nullable int[] measuredFreqOffset;
+  @nullable android.hardware.bluetooth.ranging.ComplexNumber[] packetPct1;
+  @nullable android.hardware.bluetooth.ranging.ComplexNumber[] packetPct2;
+  byte referencePowerDbm;
+  @nullable byte[] vendorSpecificCsSingleSidedata;
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ComplexNumber.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ComplexNumber.aidl
new file mode 100644
index 0000000..4d5ac21
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ComplexNumber.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.ranging;
+@VintfStability
+parcelable ComplexNumber {
+  double real;
+  double imaginary;
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/Config.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/Config.aidl
new file mode 100644
index 0000000..c9ac991
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/Config.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.ranging;
+@VintfStability
+parcelable Config {
+  android.hardware.bluetooth.ranging.ModeType modeType;
+  android.hardware.bluetooth.ranging.SubModeType subModeType;
+  android.hardware.bluetooth.ranging.RttType rttType;
+  byte[10] channelMap;
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/CsSecurityLevel.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/CsSecurityLevel.aidl
new file mode 100644
index 0000000..6a31547
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/CsSecurityLevel.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.ranging;
+@Backing(type="int") @VintfStability
+enum CsSecurityLevel {
+  NOT_SUPPORTED = 0x00,
+  ONE = 0x01,
+  TWO = 0x02,
+  THREE = 0x03,
+  FOUR = 0x04,
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/DeviceAddress.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/DeviceAddress.aidl
new file mode 100644
index 0000000..69cad5d
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/DeviceAddress.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.ranging;
+@VintfStability
+parcelable DeviceAddress {
+  android.hardware.bluetooth.ranging.AddressType addressType;
+  byte[6] address;
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/IBluetoothChannelSounding.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/IBluetoothChannelSounding.aidl
new file mode 100644
index 0000000..004a482
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/IBluetoothChannelSounding.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.ranging;
+@VintfStability
+interface IBluetoothChannelSounding {
+  @nullable android.hardware.bluetooth.ranging.VendorSpecificData[] getVendorSpecificData();
+  @nullable android.hardware.bluetooth.ranging.SessionType[] getSupportedSessionTypes();
+  android.hardware.bluetooth.ranging.CsSecurityLevel getMaxSupportedCsSecurityLevel();
+  @nullable android.hardware.bluetooth.ranging.IBluetoothChannelSoundingSession openSession(in android.hardware.bluetooth.ranging.BluetoothChannelSoundingParameters params, in android.hardware.bluetooth.ranging.IBluetoothChannelSoundingSessionCallback callback);
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/IBluetoothChannelSoundingSession.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/IBluetoothChannelSoundingSession.aidl
new file mode 100644
index 0000000..9f691b4
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/IBluetoothChannelSoundingSession.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.ranging;
+@VintfStability
+interface IBluetoothChannelSoundingSession {
+  @nullable android.hardware.bluetooth.ranging.VendorSpecificData[] getVendorSpecificReplies();
+  android.hardware.bluetooth.ranging.ResultType[] getSupportedResultTypes();
+  boolean isAbortedProcedureRequired();
+  void writeRawData(in android.hardware.bluetooth.ranging.ChannelSoudingRawData rawData);
+  void close(android.hardware.bluetooth.ranging.Reason reason);
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/IBluetoothChannelSoundingSessionCallback.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/IBluetoothChannelSoundingSessionCallback.aidl
new file mode 100644
index 0000000..d6622de
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/IBluetoothChannelSoundingSessionCallback.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.ranging;
+@VintfStability
+interface IBluetoothChannelSoundingSessionCallback {
+  void onOpened(android.hardware.bluetooth.ranging.Reason reason);
+  void onOpenFailed(android.hardware.bluetooth.ranging.Reason reason);
+  void onResult(in android.hardware.bluetooth.ranging.RangingResult result);
+  void onClose(android.hardware.bluetooth.ranging.Reason reason);
+  void onCloseFailed(android.hardware.bluetooth.ranging.Reason reason);
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/LocationType.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/LocationType.aidl
new file mode 100644
index 0000000..d95af26
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/LocationType.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.ranging;
+@Backing(type="byte") @VintfStability
+enum LocationType {
+  UNKNOWN = 0x00,
+  INDOOR = 0x01,
+  OUTDOOR = 0x02,
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ModeType.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ModeType.aidl
new file mode 100644
index 0000000..1e8ae91
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ModeType.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.ranging;
+@Backing(type="byte") @VintfStability
+enum ModeType {
+  ZERO = 0x00,
+  ONE = 0x01,
+  TWO = 0x02,
+  THREE = 0x03,
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/Nadm.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/Nadm.aidl
new file mode 100644
index 0000000..a0aa47b
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/Nadm.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.ranging;
+@Backing(type="byte") @VintfStability
+enum Nadm {
+  ATTACK_IS_EXTREMELY_UNLIKELY = 0x00,
+  ATTACK_IS_VERY_UNLIKELY = 0x01,
+  ATTACK_IS_UNLIKELY = 0x02,
+  ATTACK_IS_POSSIBLE = 0x03,
+  ATTACK_IS_LIKELY = 0x04,
+  ATTACK_IS_VERY_LIKELY = 0x05,
+  ATTACK_IS_EXTREMELY_LIKELY = 0x06,
+  UNKNOWN = 0xFFu8,
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/RangingResult.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/RangingResult.aidl
new file mode 100644
index 0000000..d092b80
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/RangingResult.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.ranging;
+@VintfStability
+parcelable RangingResult {
+  double resultMeters;
+  double errorMeters;
+  double azimuthDegrees;
+  double errorAzimuthDegrees;
+  double altitudeDegrees;
+  double errorAltitudeDegrees;
+  double delaySpreadMeters;
+  byte confidenceLevel;
+  android.hardware.bluetooth.ranging.Nadm detectedAttackLevel;
+  double velocityMetersPerSecond;
+  @nullable byte[] vendorSpecificCsRangingResultsData;
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/Reason.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/Reason.aidl
new file mode 100644
index 0000000..ddd44fe
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/Reason.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.ranging;
+@Backing(type="int") @VintfStability
+enum Reason {
+  LOCAL_STACK_REQUEST,
+  HAL_INITIATED,
+  HARDWARE_INITIATED,
+  ERROR_INVALID_PARAMETER,
+  ERROR_UNKNOWN,
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ResultType.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ResultType.aidl
new file mode 100644
index 0000000..b3e098c
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ResultType.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.ranging;
+@Backing(type="int") @VintfStability
+enum ResultType {
+  RESULT_METERS = 0x00,
+  ERROR_METERS = 0x01,
+  AZIMUTH_DEGREES = 0x02,
+  ERROR_AZIMUTH_DEGREES = 0x03,
+  ALTITUDE_DEGREES = 0x04,
+  ERROR_ALTITUDE_DEGREES = 0x05,
+  DELAY_SPREAD_METERS = 0x06,
+  CONFIDENCE_LEVEL = 0x07,
+  SECURITY_LEVEL = 0x08,
+  VELOCITY = 0x09,
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/Role.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/Role.aidl
new file mode 100644
index 0000000..61ee1aa
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/Role.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.ranging;
+@Backing(type="int") @VintfStability
+enum Role {
+  INITIATOR = 0,
+  REFLECTOR = 1,
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/RttType.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/RttType.aidl
new file mode 100644
index 0000000..e662c07
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/RttType.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.ranging;
+@Backing(type="int") @VintfStability
+enum RttType {
+  AA_COARSE = 0x00,
+  WITH_32_BIT_SOUNDING_SEQUENCE = 0x01,
+  WITH_96_BIT_SOUNDING_SEQUENCE = 0x02,
+  WITH_32_BIT_RANDOM_SEQUENCE = 0x03,
+  WITH_64_BIT_RANDOM_SEQUENCE = 0x04,
+  WITH_96_BIT_RANDOM_SEQUENCE = 0x05,
+  WITH_128_BIT_RANDOM_SEQUENCE = 0x06,
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/SessionType.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/SessionType.aidl
new file mode 100644
index 0000000..d43022f
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/SessionType.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.ranging;
+@Backing(type="int") @VintfStability
+enum SessionType {
+  SOFTWARE_STACK_DATA_PARSING = 0,
+  HARDWARE_OFFLOAD_DATA_PARSING = 1,
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/SightType.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/SightType.aidl
new file mode 100644
index 0000000..6e96ba4
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/SightType.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.ranging;
+@Backing(type="byte") @VintfStability
+enum SightType {
+  UNKNOWN = 0x00,
+  LINE_OF_SIGHT = 0x01,
+  NON_LINE_OF_SIGHT = 0x02,
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/StepTonePct.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/StepTonePct.aidl
new file mode 100644
index 0000000..4125748
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/StepTonePct.aidl
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.ranging;
+@VintfStability
+parcelable StepTonePct {
+  List<android.hardware.bluetooth.ranging.ComplexNumber> tonePcts;
+  byte[] toneQualityIndicator;
+  byte toneExtensionAntennaIndex;
+  const int TONE_QUALITY_GOOD = 0;
+  const int TONE_QUALITY_MEDIUM = 1;
+  const int TONE_QUALITY_LOW = 2;
+  const int TONE_QUALITY_UNAVAILABLE = 3;
+  const int EXTENSION_SLOT_NONE = 0;
+  const int EXTENSION_SLOT_TONE_NOT_EXPECTED_TO_BE_PRESENT = 1;
+  const int EXTENSION_SLOT_TONE_EXPECTED_TO_BE_PRESENT = 2;
+  const int EXTENSION_SLOT_SHIFT_AMOUNT = 4;
+  const byte TONE_EXTENSION_ANTENNA_1 = 0x0;
+  const byte TONE_EXTENSION_ANTENNA_2 = 0x1;
+  const byte TONE_EXTENSION_ANTENNA_3 = 0x2;
+  const byte TONE_EXTENSION_ANTENNA_4 = 0x3;
+  const byte TONE_EXTENSION_UNUSED = 0xFFu8;
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/SubModeType.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/SubModeType.aidl
new file mode 100644
index 0000000..b72a97d
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/SubModeType.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.ranging;
+@Backing(type="byte") @VintfStability
+enum SubModeType {
+  ONE = 0x01,
+  TWO = 0x02,
+  THREE = 0x03,
+  UNUSED = 0xffu8,
+}
diff --git a/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/VendorSpecificData.aidl b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/VendorSpecificData.aidl
new file mode 100644
index 0000000..13bf696
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/VendorSpecificData.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.ranging;
+@VintfStability
+parcelable VendorSpecificData {
+  byte[16] characteristicUuid;
+  byte[] opaqueValue;
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/AddressType.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/AddressType.aidl
new file mode 100644
index 0000000..499d42f
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/AddressType.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+/**
+ * Same as the BLE address type, except anonymous isn't supported for ranging.
+ */
+@VintfStability
+@Backing(type="int")
+enum AddressType {
+    PUBLIC = 0x00,
+    /* Still may be fixed on the device and is not randomized on boot */
+    RANDOM = 0x01,
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/BluetoothChannelSoundingParameters.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/BluetoothChannelSoundingParameters.aidl
new file mode 100644
index 0000000..0cda847
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/BluetoothChannelSoundingParameters.aidl
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+import android.hardware.bluetooth.ranging.Config;
+import android.hardware.bluetooth.ranging.DeviceAddress;
+import android.hardware.bluetooth.ranging.LocationType;
+import android.hardware.bluetooth.ranging.Role;
+import android.hardware.bluetooth.ranging.SessionType;
+import android.hardware.bluetooth.ranging.SightType;
+import android.hardware.bluetooth.ranging.VendorSpecificData;
+
+/**
+ * Parameters for IBluetoothChannelSoundingSession.openSession().
+ */
+@VintfStability
+parcelable BluetoothChannelSoundingParameters {
+    SessionType sessionType;
+    /**
+     * Acl handle of the connection.
+     */
+    int aclHandle;
+    /**
+     * L2CAP Cid, needed in case of EATT which may use dynamic channel for GATT.
+     */
+    int l2capCid;
+    /**
+     * ATT handle of the Real-time Procedure Data.
+     */
+    int realTimeProcedureDataAttHandle;
+    /**
+     * Role of the local device.
+     */
+    Role role;
+    /**
+     * If sounding phase-based ranging is supported by the local device.
+     */
+    boolean localSupportsSoundingPhaseBasedRanging;
+    /**
+     * If sounding phase-based ranging is supported by the remote device.
+     */
+    boolean remoteSupportsSoundingPhaseBaseRanging;
+    /**
+     * CS conifg used for procedure enable.
+     */
+    Config config;
+    /**
+     * Device address of the remote device.
+     */
+    DeviceAddress address;
+    /**
+     * Vendor-specific data get from remote GATT Server
+     */
+    @nullable VendorSpecificData[] vendorSpecificData;
+    /**
+     * Specifies the preferred location type of the use case (indoor, outdoor, unknown), this is
+     * used by the HAL to choose the corresponding ranging algorithm if it supports multiple
+     * algorithms
+     */
+    LocationType locationType;
+    /**
+     * Specifies the preferred sight type of the use case (line-of-sight, non-line-of-sight,
+     * unknown), this is used by the HAL to choose the corresponding ranging algorithm if it
+     * supports multiple algorithms
+     */
+    SightType sightType;
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ChannelSoudingRawData.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ChannelSoudingRawData.aidl
new file mode 100644
index 0000000..78ce4f4
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ChannelSoudingRawData.aidl
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+import android.hardware.bluetooth.ranging.ChannelSoundingSingleSideData;
+import android.hardware.bluetooth.ranging.ModeType;
+
+/**
+ * Raw ranging data of Channel Sounding.
+ * See Channel Sounding CR_PR 3.1.10 and Channel Sounding HCI Updates CR_PR 3.1.23 for details.
+ *
+ * Specification: https://www.bluetooth.com/specifications/specs/channel-sounding-cr-pr/
+ */
+@VintfStability
+parcelable ChannelSoudingRawData {
+    /**
+     * Procedure counter of the CS procedure.
+     */
+    int procedureCounter;
+    /**
+     * Frequency Compensation indicates fractional frequency
+     * offset (FFO) value of initiator, in 0.01ppm
+     */
+    int[] frequencyCompensation;
+    /**
+     * Indicate if the procedure aborted.
+     */
+    boolean aborted;
+    /**
+     * Common data for both initator and reflector sided.
+     */
+    ChannelSoundingSingleSideData initiatorData;
+    ChannelSoundingSingleSideData reflectorData;
+    /**
+     * The channel indices of every step in a CS procedure (in time order).
+     */
+    byte[] stepChannels;
+    /**
+     * Toa_tod_initator from mode-1 or mode-3 steps in a CS procedure (in time order).
+     * Time of flight = 0.5 * (toa_tod_initiator - tod_toa_reflector).
+     */
+    @nullable int[] toaTodInitiator;
+    /**
+     * Tod_toa_reflector from mode-1 or mode-3 steps in a CS procedure (in time order).
+     * Time of flight = 0.5 * (toa_tod_initiator - tod_toa_reflector).
+     */
+    @nullable int[] todToaReflector;
+    /**
+     * CS mode (0, 1, 2, 3) of each CS step.
+     */
+    ModeType[] stepMode;
+    /**
+     * Number of antenna paths (1 to 4) reported in the CS procedure.
+     */
+    byte numAntennaPaths;
+    /**
+     * Timestamp when the procedure is created. Using epoch time in ms (e.g., 1697673127175).
+     */
+    long timestampMs;
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ChannelSoundingSingleSideData.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ChannelSoundingSingleSideData.aidl
new file mode 100644
index 0000000..9c4b472
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ChannelSoundingSingleSideData.aidl
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+import android.hardware.bluetooth.ranging.ComplexNumber;
+import android.hardware.bluetooth.ranging.Nadm;
+import android.hardware.bluetooth.ranging.StepTonePct;
+
+/**
+ * Raw ranging data of Channel Sounding from either Initator or Reflector.
+ * See Channel Sounding CR_PR 3.1.10 and Channel Sounding HCI Updates CR_PR 3.1.23 for details.
+ *
+ * Specification: https://www.bluetooth.com/specifications/specs/channel-sounding-cr-pr/
+ */
+@VintfStability
+parcelable ChannelSoundingSingleSideData {
+    /**
+     * PCT (complex value) measured from mode-2 or mode-3 steps in a CS procedure (in time order).
+     */
+    @nullable StepTonePct[] stepTonePcts;
+    /**
+     * Packet Quality from mode-1 or mode-3 steps in a CS procedures (in time order).
+     */
+    @nullable byte[] packetQuality;
+    /**
+     * Packet RSSI (-127 to 20) of mode-0, mode-1, or mode-3 step data, in dBm.
+     */
+    @nullable byte[] packetRssiDbm;
+    /**
+     * Packet NADM of mode-1 or mode-3 step data for attack detection.
+     */
+    @nullable Nadm[] packetNadm;
+    /**
+     * Measured Frequency Offset from mode 0, relative to the remote device, in 0.01ppm
+     */
+    @nullable int[] measuredFreqOffset;
+    /**
+     * Packet_PCT1 or packet_PCT2 of mode-1 or mode-3, if sounding sequence is used and sounding
+     * phase-based ranging is supported.
+     */
+    @nullable ComplexNumber[] packetPct1;
+    @nullable ComplexNumber[] packetPct2;
+    /**
+     * Reference power level (-127 to 20) of the signal in the procedure, in dBm.
+     */
+    byte referencePowerDbm;
+    /**
+     * Parameter for vendors to place vendor-specific raw ranging data.
+     */
+    @nullable byte[] vendorSpecificCsSingleSidedata;
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ComplexNumber.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ComplexNumber.aidl
new file mode 100644
index 0000000..5253d9f
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ComplexNumber.aidl
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+@VintfStability
+parcelable ComplexNumber {
+    double real;
+    double imaginary;
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/Config.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/Config.aidl
new file mode 100644
index 0000000..85ae4c1
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/Config.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+import android.hardware.bluetooth.ranging.ModeType;
+import android.hardware.bluetooth.ranging.RttType;
+import android.hardware.bluetooth.ranging.SubModeType;
+
+@VintfStability
+parcelable Config {
+    /**
+     * Main_Mode_Type of the CS conifg
+     */
+    ModeType modeType;
+    /**
+     * Sub_Mode_Type of the CS conifg
+     */
+    SubModeType subModeType;
+    /**
+     * RTT_Type of the CS conifg
+     */
+    RttType rttType;
+    /**
+     * Channel_Map of the CS conifg, this parameter contains 80 1-bit fields. The nth such field
+     * (in the range 0 to 78) contains the value for the CS channel index n.
+     *
+     * Channel n is enabled for CS procedure = 1
+     * Channel n is disabled for CS procedure = 0
+     */
+    byte[10] channelMap;
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/CsSecurityLevel.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/CsSecurityLevel.aidl
new file mode 100644
index 0000000..3fd4424
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/CsSecurityLevel.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+@VintfStability
+@Backing(type="int")
+enum CsSecurityLevel {
+    /**
+     * Ranging algorithm is not implemented.
+     */
+    NOT_SUPPORTED = 0x00,
+    /**
+     * Either CS tone or CS RTT.
+     */
+    ONE = 0x01,
+    /**
+     * 150 ns CS RTT accuracy and CS tones.
+     */
+    TWO = 0x02,
+    /**
+     * 10 ns CS RTT accuracy and CS tones.
+     */
+    THREE = 0x03,
+    /**
+     * Level 3 with the addition of CS RTT sounding sequence or random sequence
+     * payloads, and support of the Normalized Attack Detector Metric requirements.
+     */
+    FOUR = 0x04,
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/DeviceAddress.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/DeviceAddress.aidl
new file mode 100644
index 0000000..c847c30
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/DeviceAddress.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+import android.hardware.bluetooth.ranging.AddressType;
+
+/**
+ * Bluetooth address with address type
+ */
+@VintfStability
+parcelable DeviceAddress {
+    AddressType addressType;
+    byte[6] address;
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/IBluetoothChannelSounding.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/IBluetoothChannelSounding.aidl
new file mode 100644
index 0000000..45ec79f
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/IBluetoothChannelSounding.aidl
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+import android.hardware.bluetooth.ranging.BluetoothChannelSoundingParameters;
+import android.hardware.bluetooth.ranging.CsSecurityLevel;
+import android.hardware.bluetooth.ranging.IBluetoothChannelSoundingSession;
+import android.hardware.bluetooth.ranging.IBluetoothChannelSoundingSessionCallback;
+import android.hardware.bluetooth.ranging.Nadm;
+import android.hardware.bluetooth.ranging.SessionType;
+import android.hardware.bluetooth.ranging.VendorSpecificData;
+
+/**
+ * The interface for the Bluetooth stack to get vendor specifc data and open session
+ * for channel sounding.
+ */
+@VintfStability
+interface IBluetoothChannelSounding {
+    /**
+     * API to get vendor-specific data, the Bluetooth stack will provision the GATT server with
+     * these vendor-specific UUIDs and data.
+     *
+     * @return an array of vendor specifc data
+     */
+    @nullable VendorSpecificData[] getVendorSpecificData();
+
+    /**
+     * API to get supported session types of the HAL
+     *
+     * @return an array of supported session types
+     */
+    @nullable SessionType[] getSupportedSessionTypes();
+
+    /**
+     * API to get max supported security level (0 to 4) of CS for ranging algorithms.
+     *
+     *  See: https://bluetooth.com/specifications/specs/channel-sounding-cr-pr/
+     *
+     * @return CsSecurityLevel that indicates max supported security level of CS for ranging
+     *         algorithms.
+     */
+    CsSecurityLevel getMaxSupportedCsSecurityLevel();
+
+    /**
+     * API to open session for channel sounding and register the corresponeding callback
+     *
+     * @return an instance of IBluetoothChannelSoundingSession
+     */
+    @nullable IBluetoothChannelSoundingSession openSession(
+            in BluetoothChannelSoundingParameters params,
+            in IBluetoothChannelSoundingSessionCallback callback);
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/IBluetoothChannelSoundingSession.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/IBluetoothChannelSoundingSession.aidl
new file mode 100644
index 0000000..97b147e
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/IBluetoothChannelSoundingSession.aidl
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+import android.hardware.bluetooth.ranging.ChannelSoudingRawData;
+import android.hardware.bluetooth.ranging.Reason;
+import android.hardware.bluetooth.ranging.ResultType;
+import android.hardware.bluetooth.ranging.VendorSpecificData;
+
+/**
+ * Session of Channel Sounding get from IBluetoothChannelSounding.openSession().
+ * Used by the Bluetooth stack to get preferred config from HAL and provide raw ranging data to
+ * the HAL.
+ */
+@VintfStability
+interface IBluetoothChannelSoundingSession {
+    /**
+     * API to get vendor-specifc replies
+     *
+     * @return an array of vendor-specifc data
+     */
+    @nullable VendorSpecificData[] getVendorSpecificReplies();
+
+    /**
+     * API to obtain supported result types. The Bluetooth stack should use this function to check
+     * for supported result types and ignore unsupported types in the RangingResult.
+     *
+     * @return an array of vendor-specifc data
+     */
+    ResultType[] getSupportedResultTypes();
+
+    /**
+     * Indicate whether the HAL would like to receive raw data of abort procedures.
+     * If this function returns true, the Bluetooth stack should pass the data to the HAL using
+     * the writeRawData() function, even if the CS procedure is aborted.
+     *
+     * @return true if the HAL would like to receive raw data of abort procedures.
+     */
+    boolean isAbortedProcedureRequired();
+
+    /**
+     * API to provide raw ranging data to the HAL. The HAL converts this data into meaningful
+     * ranging results using a proprietary algorithm and then calls back to the Bluetooth stack via
+     * IBluetoothChannelSoundingSessionCallback.onResult().
+     */
+    void writeRawData(in ChannelSoudingRawData rawData);
+
+    /**
+     * Close the current session. Object is no longer useful after this method.
+     */
+    void close(Reason reason);
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/IBluetoothChannelSoundingSessionCallback.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/IBluetoothChannelSoundingSessionCallback.aidl
new file mode 100644
index 0000000..6901305
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/IBluetoothChannelSoundingSessionCallback.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+import android.hardware.bluetooth.ranging.RangingResult;
+import android.hardware.bluetooth.ranging.Reason;
+
+/**
+ * The callback from the HAL to the stack.
+ * Register by IBluetoothChannelSoundingSession.openSession().
+ */
+@VintfStability
+interface IBluetoothChannelSoundingSessionCallback {
+    /**
+     * Invoked when IBluetoothChannelSounding.openSession() is successful.
+     */
+    void onOpened(Reason reason);
+    /**
+     * Invoked when IBluetoothChannelSounding.openSession() fails.
+     */
+    void onOpenFailed(Reason reason);
+    /**
+     * Invoked when HAL get raning result.
+     */
+    void onResult(in RangingResult result);
+    /**
+     * Invoked when IBluetoothChannelSoundingSession.close() is successful.
+     */
+    void onClose(Reason reason);
+    /**
+     * Invoked when IBluetoothChannelSoundingSession.close() fails.
+     */
+    void onCloseFailed(Reason reason);
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/LocationType.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/LocationType.aidl
new file mode 100644
index 0000000..bccf291
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/LocationType.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+@VintfStability
+@Backing(type="byte")
+enum LocationType {
+    UNKNOWN = 0x00,
+    INDOOR = 0x01,
+    OUTDOOR = 0x02,
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ModeType.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ModeType.aidl
new file mode 100644
index 0000000..3a727aa
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ModeType.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+@VintfStability
+@Backing(type="byte")
+enum ModeType {
+    ZERO = 0x00,
+    ONE = 0x01,
+    TWO = 0x02,
+    THREE = 0x03,
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/Nadm.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/Nadm.aidl
new file mode 100644
index 0000000..74cf731
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/Nadm.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+/**
+ * Normalized Attack Detector Metric.
+ * See Channel Sounding CR_PR, 3.13.24 for details.
+ *
+ * Specification: https://www.bluetooth.com/specifications/specs/channel-sounding-cr-pr/
+ */
+@VintfStability
+@Backing(type="byte")
+enum Nadm {
+    ATTACK_IS_EXTREMELY_UNLIKELY = 0x00,
+    ATTACK_IS_VERY_UNLIKELY = 0x01,
+    ATTACK_IS_UNLIKELY = 0x02,
+    ATTACK_IS_POSSIBLE = 0x03,
+    ATTACK_IS_LIKELY = 0x04,
+    ATTACK_IS_VERY_LIKELY = 0x05,
+    ATTACK_IS_EXTREMELY_LIKELY = 0x06,
+    /* If a device is unable to determine a NADM value, then it shall report a NADM value of Unknown
+     */
+    UNKNOWN = 0xFFu8,
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/RangingResult.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/RangingResult.aidl
new file mode 100644
index 0000000..65907dd
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/RangingResult.aidl
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+import android.hardware.bluetooth.ranging.Nadm;
+
+/**
+ * Generic structure to return the ranging result
+ */
+@VintfStability
+parcelable RangingResult {
+    /**
+     * Estimated distance in meters.
+     */
+    double resultMeters;
+    /**
+     * Potential distance estimate error (plus or minus) in meters, always positive.
+     */
+    double errorMeters;
+    /**
+     * Azimuth Angle measurement in degrees.
+     *
+     * Azimuth of remote device in horizontal coordinate system, this measured from azimuth north
+     * and increasing eastward. When the remote device in azimuth north, this angle is 0, when the
+     * remote device in azimuth south, this angle is 180.
+     *
+     * See: <a href="https://en.wikipedia.org/wiki/Horizontal_coordinate_system">Horizontal
+     *  coordinate system</a>for the details
+     *
+     * On an Android device, azimuth north is defined as the angle perpendicular away from the
+     * back of the device when holding it in portrait mode upright.
+     *
+     * The Azimuth north is defined as the direction in which the top edge of the device is
+     * facing when it is placed flat.
+     *
+     */
+    double azimuthDegrees;
+    /**
+     * Estimated error (plus or minus) of azimuth angle measurement in degrees, always positive.
+     */
+    double errorAzimuthDegrees;
+    /**
+     * Altitude Angle measurement in degrees.
+     *
+     * Altitude of remote device in horizontal coordinate system, this is the angle between the
+     * remote device and the top edge of local device. When local device is placed flat, the angle
+     * of the zenith is 90, the angle of the nadir is -90.
+     *
+     * See: https://en.wikipedia.org/wiki/Horizontal_coordinate_system
+     */
+    double altitudeDegrees;
+    /**
+     * Estimated error (plus or minus) of altitude angle measurement in degrees, always positive.
+     */
+    double errorAltitudeDegrees;
+    /**
+     * Estimated delay spread in meters of the measured channel. This is a measure of multipath
+     * richness of the channel.
+     */
+    double delaySpreadMeters;
+    /**
+     * A normalized value from 0 (low confidence) to 100 (high confidence) representing the
+     * confidence of estimated distance.
+     */
+    byte confidenceLevel;
+    /**
+     * A value representing the chance of being attacked for the measurement.
+     */
+    Nadm detectedAttackLevel;
+    /**
+     * Estimated velocity, in the direction of line between two devices, of the moving object in
+     * meters/sec.
+     */
+    double velocityMetersPerSecond;
+    /**
+     * Parameter for vendors to place vendor-specific ranging results data.
+     */
+    @nullable byte[] vendorSpecificCsRangingResultsData;
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/Reason.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/Reason.aidl
new file mode 100644
index 0000000..4f587de
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/Reason.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+@VintfStability
+@Backing(type="int")
+enum Reason {
+    LOCAL_STACK_REQUEST,
+    HAL_INITIATED,
+    HARDWARE_INITIATED,
+    ERROR_INVALID_PARAMETER,
+    ERROR_UNKNOWN,
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ResultType.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ResultType.aidl
new file mode 100644
index 0000000..561b7dd
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ResultType.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+@VintfStability
+@Backing(type="int")
+enum ResultType {
+    RESULT_METERS = 0x00,
+    ERROR_METERS = 0x01,
+    AZIMUTH_DEGREES = 0x02,
+    ERROR_AZIMUTH_DEGREES = 0x03,
+    ALTITUDE_DEGREES = 0x04,
+    ERROR_ALTITUDE_DEGREES = 0x05,
+    DELAY_SPREAD_METERS = 0x06,
+    CONFIDENCE_LEVEL = 0x07,
+    SECURITY_LEVEL = 0x08,
+    VELOCITY = 0x09,
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/Role.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/Role.aidl
new file mode 100644
index 0000000..b531935
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/Role.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+@VintfStability
+@Backing(type="int")
+enum Role {
+    INITIATOR = 0,
+    REFLECTOR = 1,
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/RttType.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/RttType.aidl
new file mode 100644
index 0000000..6e163c9
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/RttType.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+@VintfStability
+@Backing(type="int")
+enum RttType {
+    AA_COARSE = 0x00,
+    WITH_32_BIT_SOUNDING_SEQUENCE = 0x01,
+    WITH_96_BIT_SOUNDING_SEQUENCE = 0x02,
+    WITH_32_BIT_RANDOM_SEQUENCE = 0x03,
+    WITH_64_BIT_RANDOM_SEQUENCE = 0x04,
+    WITH_96_BIT_RANDOM_SEQUENCE = 0x05,
+    WITH_128_BIT_RANDOM_SEQUENCE = 0x06,
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/SessionType.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/SessionType.aidl
new file mode 100644
index 0000000..4f0d529
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/SessionType.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+@VintfStability
+@Backing(type="int")
+enum SessionType {
+    /**
+     * Stack parses raw data and passes it to the HAL
+     */
+    SOFTWARE_STACK_DATA_PARSING = 0,
+    /**
+     * Offloader parses raw data
+     */
+    HARDWARE_OFFLOAD_DATA_PARSING = 1
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/SightType.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/SightType.aidl
new file mode 100644
index 0000000..14106e0
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/SightType.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+@VintfStability
+@Backing(type="byte")
+enum SightType {
+    UNKNOWN = 0x00,
+    LINE_OF_SIGHT = 0x01,
+    NON_LINE_OF_SIGHT = 0x02,
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/StepTonePct.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/StepTonePct.aidl
new file mode 100644
index 0000000..4650861
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/StepTonePct.aidl
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+import android.hardware.bluetooth.ranging.ComplexNumber;
+
+/**
+ * Tone PCT data with quality indicator from a mode-2 or mode-3 step.
+ */
+@VintfStability
+parcelable StepTonePct {
+    /**
+     * PCT measured from mode-2 or mode-3 steps
+     * (in ascending order of antenna position with tone extension data at the end).
+     */
+    List<ComplexNumber> tonePcts;
+    const int TONE_QUALITY_GOOD = 0;
+    const int TONE_QUALITY_MEDIUM = 1;
+    const int TONE_QUALITY_LOW = 2;
+    const int TONE_QUALITY_UNAVAILABLE = 3;
+    const int EXTENSION_SLOT_NONE = 0;
+    const int EXTENSION_SLOT_TONE_NOT_EXPECTED_TO_BE_PRESENT = 1;
+    const int EXTENSION_SLOT_TONE_EXPECTED_TO_BE_PRESENT = 2;
+    /**
+     * Shift amount for extension slot (bits 4 to 7).
+     */
+    const int EXTENSION_SLOT_SHIFT_AMOUNT = 4;
+    /**
+     * Tone_Quality_Indicator defined in the LE CS Subevent Result event
+     *
+     * Bits 0 to 3:
+     * 0x0 = Tone quality is good
+     * 0x1 = Tone quality is medium
+     * 0x2 = Tone quality is low
+     * 0x3 = Tone quality is unavailable
+     *
+     * Bits 4 to 7:
+     * 0x0 = Not tone extension slot
+     * 0x1 = Tone extension slot; tone not expected to be present
+     * 0x2 = Tone extension slot; tone expected to be present
+     *
+     * See: https://bluetooth.com/specifications/specs/channel-sounding-cr-pr/
+     */
+    byte[] toneQualityIndicator;
+
+    const byte TONE_EXTENSION_ANTENNA_1 = 0x0;
+    const byte TONE_EXTENSION_ANTENNA_2 = 0x1;
+    const byte TONE_EXTENSION_ANTENNA_3 = 0x2;
+    const byte TONE_EXTENSION_ANTENNA_4 = 0x3;
+    const byte TONE_EXTENSION_UNUSED = 0xFFu8;
+    /**
+     * Tone Extension Antenna Index indicates the Antenna position used in tone extension slot
+     *
+     * 0x00 = A1
+     * 0x01 = A2
+     * 0x02 = A3
+     * 0x03 = A4
+     * 0xFF = Tone extension not used
+     */
+    byte toneExtensionAntennaIndex;
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/SubModeType.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/SubModeType.aidl
new file mode 100644
index 0000000..b775002
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/SubModeType.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+@VintfStability
+@Backing(type="byte")
+enum SubModeType {
+    ONE = 0x01,
+    TWO = 0x02,
+    THREE = 0x03,
+    UNUSED = 0xffu8,
+}
diff --git a/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/VendorSpecificData.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/VendorSpecificData.aidl
new file mode 100644
index 0000000..a8c9a2a
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/VendorSpecificData.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.ranging;
+
+/**
+ * Vendor specific data for GATT.
+ */
+@VintfStability
+parcelable VendorSpecificData {
+    byte[16] characteristicUuid;
+    byte[] opaqueValue;
+}
diff --git a/bluetooth/ranging/aidl/default/Android.bp b/bluetooth/ranging/aidl/default/Android.bp
new file mode 100644
index 0000000..5072a43
--- /dev/null
+++ b/bluetooth/ranging/aidl/default/Android.bp
@@ -0,0 +1,29 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_binary {
+    name: "android.hardware.bluetooth.ranging-service.default",
+    relative_install_path: "hw",
+    init_rc: ["bluetooth-ranging-service-default.rc"],
+    vintf_fragments: [":manifest_android.hardware.bluetooth.ranging-service.default.xml"],
+    vendor: true,
+    srcs: [
+        "BluetoothChannelSounding.cpp",
+        "BluetoothChannelSoundingSession.cpp",
+        "service.cpp",
+    ],
+    shared_libs: [
+        "android.hardware.bluetooth.ranging-V1-ndk",
+        "libbase",
+        "libbinder_ndk",
+        "libhidlbase",
+        "libutils",
+        "liblog",
+    ],
+}
+
+filegroup {
+    name: "manifest_android.hardware.bluetooth.ranging-service.default.xml",
+    srcs: ["bluetooth-ranging-service-default.xml"],
+}
diff --git a/bluetooth/ranging/aidl/default/BluetoothChannelSounding.cpp b/bluetooth/ranging/aidl/default/BluetoothChannelSounding.cpp
new file mode 100644
index 0000000..3807d4f
--- /dev/null
+++ b/bluetooth/ranging/aidl/default/BluetoothChannelSounding.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BluetoothChannelSounding.h"
+
+#include "BluetoothChannelSoundingSession.h"
+
+namespace aidl::android::hardware::bluetooth::ranging::impl {
+
+BluetoothChannelSounding::BluetoothChannelSounding() {}
+BluetoothChannelSounding::~BluetoothChannelSounding() {}
+
+ndk::ScopedAStatus BluetoothChannelSounding::getVendorSpecificData(
+    std::optional<
+        std::vector<std::optional<VendorSpecificData>>>* /*_aidl_return*/) {
+  return ::ndk::ScopedAStatus::ok();
+}
+ndk::ScopedAStatus BluetoothChannelSounding::getSupportedSessionTypes(
+    std::optional<std::vector<SessionType>>* _aidl_return) {
+  std::vector<SessionType> supported_session_types = {};
+  *_aidl_return = supported_session_types;
+  return ::ndk::ScopedAStatus::ok();
+}
+ndk::ScopedAStatus BluetoothChannelSounding::getMaxSupportedCsSecurityLevel(
+    CsSecurityLevel* _aidl_return) {
+  CsSecurityLevel security_level = CsSecurityLevel::NOT_SUPPORTED;
+  *_aidl_return = security_level;
+  return ::ndk::ScopedAStatus::ok();
+}
+ndk::ScopedAStatus BluetoothChannelSounding::openSession(
+    const BluetoothChannelSoundingParameters& /*in_params*/,
+    const std::shared_ptr<IBluetoothChannelSoundingSessionCallback>&
+        in_callback,
+    std::shared_ptr<IBluetoothChannelSoundingSession>* _aidl_return) {
+  if (in_callback == nullptr) {
+    return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+        EX_ILLEGAL_ARGUMENT, "Invalid nullptr callback");
+  }
+  std::shared_ptr<BluetoothChannelSoundingSession> session = nullptr;
+  session = ndk::SharedRefBase::make<BluetoothChannelSoundingSession>(
+      in_callback, Reason::LOCAL_STACK_REQUEST);
+  *_aidl_return = session;
+  return ::ndk::ScopedAStatus::ok();
+}
+}  // namespace aidl::android::hardware::bluetooth::ranging::impl
diff --git a/bluetooth/ranging/aidl/default/BluetoothChannelSounding.h b/bluetooth/ranging/aidl/default/BluetoothChannelSounding.h
new file mode 100644
index 0000000..d6b5c03
--- /dev/null
+++ b/bluetooth/ranging/aidl/default/BluetoothChannelSounding.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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/bluetooth/ranging/BnBluetoothChannelSounding.h>
+
+#include <vector>
+
+namespace aidl::android::hardware::bluetooth::ranging::impl {
+
+using ::aidl::android::hardware::bluetooth::ranging::
+    BluetoothChannelSoundingParameters;
+using ::aidl::android::hardware::bluetooth::ranging::BnBluetoothChannelSounding;
+using ::aidl::android::hardware::bluetooth::ranging::CsSecurityLevel;
+using ::aidl::android::hardware::bluetooth::ranging::
+    IBluetoothChannelSoundingSession;
+using ::aidl::android::hardware::bluetooth::ranging::
+    IBluetoothChannelSoundingSessionCallback;
+using ::aidl::android::hardware::bluetooth::ranging::SessionType;
+using ::aidl::android::hardware::bluetooth::ranging::VendorSpecificData;
+
+class BluetoothChannelSounding : public BnBluetoothChannelSounding {
+ public:
+  BluetoothChannelSounding();
+  ~BluetoothChannelSounding();  // Add the destructor declaration
+  ndk::ScopedAStatus getVendorSpecificData(
+      std::optional<std::vector<std::optional<VendorSpecificData>>>*
+          _aidl_return) override;
+  ndk::ScopedAStatus getSupportedSessionTypes(
+      std::optional<std::vector<SessionType>>* _aidl_return) override;
+  ndk::ScopedAStatus getMaxSupportedCsSecurityLevel(
+      CsSecurityLevel* _aidl_return) override;
+  ndk::ScopedAStatus openSession(
+      const BluetoothChannelSoundingParameters& in_params,
+      const std::shared_ptr<IBluetoothChannelSoundingSessionCallback>&
+          in_callback,
+      std::shared_ptr<IBluetoothChannelSoundingSession>* _aidl_return) override;
+};
+
+}  // namespace aidl::android::hardware::bluetooth::ranging::impl
diff --git a/bluetooth/ranging/aidl/default/BluetoothChannelSoundingSession.cpp b/bluetooth/ranging/aidl/default/BluetoothChannelSoundingSession.cpp
new file mode 100644
index 0000000..6c58a07
--- /dev/null
+++ b/bluetooth/ranging/aidl/default/BluetoothChannelSoundingSession.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BluetoothChannelSoundingSession.h"
+
+namespace aidl::android::hardware::bluetooth::ranging::impl {
+
+BluetoothChannelSoundingSession::BluetoothChannelSoundingSession(
+    std::shared_ptr<IBluetoothChannelSoundingSessionCallback> callback,
+    Reason reason) {
+  callback_ = callback;
+  callback_->onOpened(reason);
+}
+
+ndk::ScopedAStatus BluetoothChannelSoundingSession::getVendorSpecificReplies(
+    std::optional<
+        std::vector<std::optional<VendorSpecificData>>>* /*_aidl_return*/) {
+  return ::ndk::ScopedAStatus::ok();
+}
+ndk::ScopedAStatus BluetoothChannelSoundingSession::getSupportedResultTypes(
+    std::vector<ResultType>* _aidl_return) {
+  std::vector<ResultType> supported_result_types = {ResultType::RESULT_METERS};
+  *_aidl_return = supported_result_types;
+  return ::ndk::ScopedAStatus::ok();
+}
+ndk::ScopedAStatus BluetoothChannelSoundingSession::isAbortedProcedureRequired(
+    bool* _aidl_return) {
+  *_aidl_return = false;
+  return ::ndk::ScopedAStatus::ok();
+}
+ndk::ScopedAStatus BluetoothChannelSoundingSession::writeRawData(
+    const ChannelSoudingRawData& /*in_rawData*/) {
+  RangingResult ranging_result;
+  ranging_result.resultMeters = 0.0;
+  callback_->onResult(ranging_result);
+  return ::ndk::ScopedAStatus::ok();
+}
+ndk::ScopedAStatus BluetoothChannelSoundingSession::close(Reason in_reason) {
+  callback_->onClose(in_reason);
+  return ::ndk::ScopedAStatus::ok();
+}
+}  // namespace aidl::android::hardware::bluetooth::ranging::impl
diff --git a/bluetooth/ranging/aidl/default/BluetoothChannelSoundingSession.h b/bluetooth/ranging/aidl/default/BluetoothChannelSoundingSession.h
new file mode 100644
index 0000000..6703f7f
--- /dev/null
+++ b/bluetooth/ranging/aidl/default/BluetoothChannelSoundingSession.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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/bluetooth/ranging/BnBluetoothChannelSoundingSession.h>
+#include <aidl/android/hardware/bluetooth/ranging/IBluetoothChannelSoundingSessionCallback.h>
+
+#include <vector>
+
+namespace aidl::android::hardware::bluetooth::ranging::impl {
+
+using ::aidl::android::hardware::bluetooth::ranging::ChannelSoudingRawData;
+using ::aidl::android::hardware::bluetooth::ranging::Reason;
+using ::aidl::android::hardware::bluetooth::ranging::ResultType;
+using ::aidl::android::hardware::bluetooth::ranging::VendorSpecificData;
+
+class BluetoothChannelSoundingSession
+    : public BnBluetoothChannelSoundingSession {
+ public:
+  BluetoothChannelSoundingSession(
+      std::shared_ptr<IBluetoothChannelSoundingSessionCallback> callback,
+      Reason reason);
+
+  ndk::ScopedAStatus getVendorSpecificReplies(
+      std::optional<std::vector<std::optional<VendorSpecificData>>>*
+          _aidl_return) override;
+  ndk::ScopedAStatus getSupportedResultTypes(
+      std::vector<ResultType>* _aidl_return) override;
+  ndk::ScopedAStatus isAbortedProcedureRequired(bool* _aidl_return) override;
+  ndk::ScopedAStatus writeRawData(
+      const ChannelSoudingRawData& in_rawData) override;
+  ndk::ScopedAStatus close(Reason in_reason) override;
+
+ private:
+  std::shared_ptr<IBluetoothChannelSoundingSessionCallback> callback_;
+};
+
+}  // namespace aidl::android::hardware::bluetooth::ranging::impl
diff --git a/bluetooth/ranging/aidl/default/bluetooth-ranging-service-default.rc b/bluetooth/ranging/aidl/default/bluetooth-ranging-service-default.rc
new file mode 100644
index 0000000..fabb409
--- /dev/null
+++ b/bluetooth/ranging/aidl/default/bluetooth-ranging-service-default.rc
@@ -0,0 +1,6 @@
+service vendor.bluetooth.ranging-default /vendor/bin/hw/android.hardware.bluetooth.ranging-service.default
+    class hal
+    capabilities BLOCK_SUSPEND NET_ADMIN SYS_NICE
+    user bluetooth
+    group bluetooth
+    task_profiles HighPerformance
diff --git a/bluetooth/ranging/aidl/default/bluetooth-ranging-service-default.xml b/bluetooth/ranging/aidl/default/bluetooth-ranging-service-default.xml
new file mode 100644
index 0000000..fe3613d
--- /dev/null
+++ b/bluetooth/ranging/aidl/default/bluetooth-ranging-service-default.xml
@@ -0,0 +1,7 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.bluetooth.ranging</name>
+        <version>1</version>
+        <fqname>IBluetoothChannelSounding/default</fqname>
+    </hal>
+</manifest>
diff --git a/bluetooth/ranging/aidl/default/service.cpp b/bluetooth/ranging/aidl/default/service.cpp
new file mode 100644
index 0000000..83e539e
--- /dev/null
+++ b/bluetooth/ranging/aidl/default/service.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "aidl.android.hardware.bluetooth.ranging.service.default"
+
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <utils/Log.h>
+
+#include "BluetoothChannelSounding.h"
+#include "BluetoothChannelSoundingSession.h"
+
+using ::aidl::android::hardware::bluetooth::ranging::impl::
+    BluetoothChannelSounding;
+
+int main(int /* argc */, char** /* argv */) {
+  ALOGI("Bluetooth Ranging HAL registering");
+  if (!ABinderProcess_setThreadPoolMaxThreadCount(0)) {
+    ALOGE("Failed to set thread pool max thread count");
+    return 1;
+  }
+
+  std::shared_ptr<BluetoothChannelSounding> service =
+      ndk::SharedRefBase::make<BluetoothChannelSounding>();
+  std::string instance =
+      std::string() + BluetoothChannelSounding::descriptor + "/default";
+  auto result =
+      AServiceManager_addService(service->asBinder().get(), instance.c_str());
+  if (result == STATUS_OK) {
+    ABinderProcess_joinThreadPool();
+  } else {
+    ALOGE("Could not register as a service!");
+  }
+  return 0;
+}
diff --git a/bluetooth/ranging/aidl/vts/Android.bp b/bluetooth/ranging/aidl/vts/Android.bp
new file mode 100644
index 0000000..ead9992
--- /dev/null
+++ b/bluetooth/ranging/aidl/vts/Android.bp
@@ -0,0 +1,27 @@
+package {
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_test {
+    name: "VtsHalBluetoothRangingTargetTest",
+    defaults: [
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: ["VtsHalBluetoothRangingTargetTest.cpp"],
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "libcutils",
+        "liblog",
+        "libutils",
+    ],
+    static_libs: [
+        "android.hardware.bluetooth.ranging-V1-ndk",
+        "libbluetooth-types",
+    ],
+    test_config: "VtsHalBluetoothRangingTargetTest.xml",
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
diff --git a/bluetooth/ranging/aidl/vts/VtsHalBluetoothRangingTargetTest.cpp b/bluetooth/ranging/aidl/vts/VtsHalBluetoothRangingTargetTest.cpp
new file mode 100644
index 0000000..702df95
--- /dev/null
+++ b/bluetooth/ranging/aidl/vts/VtsHalBluetoothRangingTargetTest.cpp
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/bluetooth/ranging/BnBluetoothChannelSoundingSessionCallback.h>
+#include <aidl/android/hardware/bluetooth/ranging/IBluetoothChannelSounding.h>
+#include <aidl/android/hardware/bluetooth/ranging/IBluetoothChannelSoundingSessionCallback.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <binder/IServiceManager.h>
+#include <utils/Log.h>
+
+using aidl::android::hardware::bluetooth::ranging::
+    BluetoothChannelSoundingParameters;
+using aidl::android::hardware::bluetooth::ranging::
+    BnBluetoothChannelSoundingSessionCallback;
+using aidl::android::hardware::bluetooth::ranging::ChannelSoudingRawData;
+using aidl::android::hardware::bluetooth::ranging::CsSecurityLevel;
+using aidl::android::hardware::bluetooth::ranging::IBluetoothChannelSounding;
+using aidl::android::hardware::bluetooth::ranging::
+    IBluetoothChannelSoundingSession;
+using aidl::android::hardware::bluetooth::ranging::
+    IBluetoothChannelSoundingSessionCallback;
+using aidl::android::hardware::bluetooth::ranging::RangingResult;
+using aidl::android::hardware::bluetooth::ranging::Reason;
+using aidl::android::hardware::bluetooth::ranging::ResultType;
+using aidl::android::hardware::bluetooth::ranging::SessionType;
+using aidl::android::hardware::bluetooth::ranging::VendorSpecificData;
+using ndk::ScopedAStatus;
+
+class BluetoothChannelSoundingSessionCallback
+    : public BnBluetoothChannelSoundingSessionCallback {
+ public:
+  ScopedAStatus onOpened(Reason reason) override;
+  ScopedAStatus onOpenFailed(Reason reason) override;
+  ScopedAStatus onResult(const RangingResult& in_result) override;
+  ScopedAStatus onClose(Reason reason) override;
+  ScopedAStatus onCloseFailed(Reason reason) override;
+};
+
+ScopedAStatus BluetoothChannelSoundingSessionCallback::onOpened(
+    Reason /*reason*/) {
+  return ::ndk::ScopedAStatus::ok();
+}
+ScopedAStatus BluetoothChannelSoundingSessionCallback::onOpenFailed(
+    Reason /*reason*/) {
+  return ::ndk::ScopedAStatus::ok();
+}
+ScopedAStatus BluetoothChannelSoundingSessionCallback::onResult(
+    const RangingResult& /*in_result*/) {
+  return ::ndk::ScopedAStatus::ok();
+}
+ScopedAStatus BluetoothChannelSoundingSessionCallback::onClose(
+    Reason /*reason*/) {
+  return ::ndk::ScopedAStatus::ok();
+}
+ScopedAStatus BluetoothChannelSoundingSessionCallback::onCloseFailed(
+    Reason /*reason*/) {
+  return ::ndk::ScopedAStatus::ok();
+}
+
+class BluetoothRangingTest : public ::testing::TestWithParam<std::string> {
+ public:
+  virtual void SetUp() override {
+    ALOGI("SetUp Ranging Test");
+    bluetooth_channel_sounding_ = IBluetoothChannelSounding::fromBinder(
+        ndk::SpAIBinder(AServiceManager_waitForService(GetParam().c_str())));
+    ASSERT_NE(bluetooth_channel_sounding_, nullptr);
+  }
+
+  virtual void TearDown() override {
+    ALOGI("TearDown Ranging Test");
+    bluetooth_channel_sounding_ = nullptr;
+    ASSERT_EQ(bluetooth_channel_sounding_, nullptr);
+  }
+
+  ScopedAStatus getVendorSpecificData(
+      std::optional<std::vector<std::optional<VendorSpecificData>>>*
+          _aidl_return);
+  ScopedAStatus getSupportedSessionTypes(
+      std::optional<std::vector<SessionType>>* _aidl_return);
+  ScopedAStatus getMaxSupportedCsSecurityLevel(CsSecurityLevel* _aidl_return);
+  ScopedAStatus openSession(
+      const BluetoothChannelSoundingParameters& in_params,
+      const std::shared_ptr<IBluetoothChannelSoundingSessionCallback>&
+          in_callback,
+      std::shared_ptr<IBluetoothChannelSoundingSession>* _aidl_return);
+
+  ScopedAStatus initBluetoothChannelSoundingSession(
+      std::shared_ptr<IBluetoothChannelSoundingSession>* session) {
+    BluetoothChannelSoundingParameters params;
+    std::shared_ptr<BluetoothChannelSoundingSessionCallback> callback = nullptr;
+    callback =
+        ndk::SharedRefBase::make<BluetoothChannelSoundingSessionCallback>();
+    ScopedAStatus status = openSession(params, callback, session);
+    return status;
+  }
+
+ private:
+  std::shared_ptr<IBluetoothChannelSounding> bluetooth_channel_sounding_;
+};
+
+ScopedAStatus BluetoothRangingTest::getVendorSpecificData(
+    std::optional<std::vector<std::optional<VendorSpecificData>>>*
+        _aidl_return) {
+  return bluetooth_channel_sounding_->getVendorSpecificData(_aidl_return);
+}
+ScopedAStatus BluetoothRangingTest::getSupportedSessionTypes(
+    std::optional<std::vector<SessionType>>* _aidl_return) {
+  return bluetooth_channel_sounding_->getSupportedSessionTypes(_aidl_return);
+}
+
+ScopedAStatus BluetoothRangingTest::getMaxSupportedCsSecurityLevel(
+    CsSecurityLevel* _aidl_return) {
+  return bluetooth_channel_sounding_->getMaxSupportedCsSecurityLevel(
+      _aidl_return);
+}
+ScopedAStatus BluetoothRangingTest::openSession(
+    const BluetoothChannelSoundingParameters& in_params,
+    const std::shared_ptr<IBluetoothChannelSoundingSessionCallback>&
+        in_callback,
+    std::shared_ptr<IBluetoothChannelSoundingSession>* _aidl_return) {
+  return bluetooth_channel_sounding_->openSession(in_params, in_callback,
+                                                  _aidl_return);
+}
+
+TEST_P(BluetoothRangingTest, SetupAndTearDown) {}
+
+TEST_P(BluetoothRangingTest, GetVendorSpecificData) {
+  std::optional<std::vector<std::optional<VendorSpecificData>>>
+      vendor_specific_data;
+  ScopedAStatus status = getVendorSpecificData(&vendor_specific_data);
+  ASSERT_TRUE(status.isOk());
+}
+
+TEST_P(BluetoothRangingTest, GetSupportedSessionTypes) {
+  std::optional<std::vector<SessionType>> supported_session_types;
+  ScopedAStatus status = getSupportedSessionTypes(&supported_session_types);
+  ASSERT_TRUE(status.isOk());
+}
+
+TEST_P(BluetoothRangingTest, GetMaxSupportedCsSecurityLevel) {
+  CsSecurityLevel security_level;
+  ScopedAStatus status = getMaxSupportedCsSecurityLevel(&security_level);
+  ASSERT_TRUE(status.isOk());
+}
+
+TEST_P(BluetoothRangingTest, OpenSession) {
+  BluetoothChannelSoundingParameters params;
+  std::shared_ptr<BluetoothChannelSoundingSessionCallback> callback = nullptr;
+  callback =
+      ndk::SharedRefBase::make<BluetoothChannelSoundingSessionCallback>();
+  std::shared_ptr<IBluetoothChannelSoundingSession> session;
+  ScopedAStatus status = openSession(params, callback, &session);
+  ASSERT_TRUE(status.isOk());
+}
+
+TEST_P(BluetoothRangingTest, GetVendorSpecificReplies) {
+  std::shared_ptr<IBluetoothChannelSoundingSession> session;
+  auto status = initBluetoothChannelSoundingSession(&session);
+  ASSERT_TRUE(status.isOk());
+  if (session != nullptr) {
+    std::optional<std::vector<std::optional<VendorSpecificData>>>
+        vendor_specific_data;
+    status = session->getVendorSpecificReplies(&vendor_specific_data);
+    ASSERT_TRUE(status.isOk());
+  }
+}
+
+TEST_P(BluetoothRangingTest, GetSupportedResultTypes) {
+  std::shared_ptr<IBluetoothChannelSoundingSession> session;
+  auto status = initBluetoothChannelSoundingSession(&session);
+  ASSERT_TRUE(status.isOk());
+  if (session != nullptr) {
+    std::vector<ResultType> supported_result_types;
+    status = session->getSupportedResultTypes(&supported_result_types);
+    ASSERT_TRUE(status.isOk());
+  }
+}
+
+TEST_P(BluetoothRangingTest, IsAbortedProcedureRequired) {
+  std::shared_ptr<IBluetoothChannelSoundingSession> session;
+  auto status = initBluetoothChannelSoundingSession(&session);
+  ASSERT_TRUE(status.isOk());
+  if (session != nullptr) {
+    bool is_abort_procedure_required = true;
+    status = session->isAbortedProcedureRequired(&is_abort_procedure_required);
+    ASSERT_TRUE(status.isOk());
+  }
+}
+
+TEST_P(BluetoothRangingTest, WriteRawData) {
+  std::shared_ptr<IBluetoothChannelSoundingSession> session;
+  auto status = initBluetoothChannelSoundingSession(&session);
+  ASSERT_TRUE(status.isOk());
+  if (session != nullptr) {
+    ChannelSoudingRawData raw_data;
+    status = session->writeRawData(raw_data);
+    ASSERT_TRUE(status.isOk());
+  }
+}
+
+TEST_P(BluetoothRangingTest, CloseSession) {
+  std::shared_ptr<IBluetoothChannelSoundingSession> session;
+  auto status = initBluetoothChannelSoundingSession(&session);
+  ASSERT_TRUE(status.isOk());
+  if (session != nullptr) {
+    status = session->close(Reason::LOCAL_STACK_REQUEST);
+    ASSERT_TRUE(status.isOk());
+  }
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BluetoothRangingTest);
+INSTANTIATE_TEST_SUITE_P(PerInstance, BluetoothRangingTest,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(
+                             IBluetoothChannelSounding::descriptor)),
+                         android::PrintInstanceNameToString);
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  ABinderProcess_startThreadPool();
+  int status = RUN_ALL_TESTS();
+  ALOGI("Test result = %d", status);
+  return status;
+}
\ No newline at end of file
diff --git a/bluetooth/ranging/aidl/vts/VtsHalBluetoothRangingTargetTest.xml b/bluetooth/ranging/aidl/vts/VtsHalBluetoothRangingTargetTest.xml
new file mode 100644
index 0000000..624b77e
--- /dev/null
+++ b/bluetooth/ranging/aidl/vts/VtsHalBluetoothRangingTargetTest.xml
@@ -0,0 +1,33 @@
+<!--
+  Copyright (C) 2023 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT 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 VtsHalBluetoothRangingTargetTest.">
+    <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="VtsHalBluetoothRangingTargetTest->/data/local/tmp/VtsHalBluetoothRangingTargetTest" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="VtsHalBluetoothRangingTargetTest" />
+    </test>
+</configuration>
diff --git a/boot/1.0/vts/functional/OWNERS b/boot/1.0/vts/functional/OWNERS
deleted file mode 100644
index 36e79be..0000000
--- a/boot/1.0/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 30545
-dvander@google.com
diff --git a/boot/1.1/default/Android.bp b/boot/1.1/default/Android.bp
index 0b0a5b7..e7a8d6e 100644
--- a/boot/1.1/default/Android.bp
+++ b/boot/1.1/default/Android.bp
@@ -20,6 +20,7 @@
     srcs: ["BootControl.cpp"],
 
     shared_libs: [
+        "libbase",
         "liblog",
         "libhidlbase",
         "libhardware",
diff --git a/boot/1.1/default/boot_control/Android.bp b/boot/1.1/default/boot_control/Android.bp
index 6aa30c2..d0dcb59 100644
--- a/boot/1.1/default/boot_control/Android.bp
+++ b/boot/1.1/default/boot_control/Android.bp
@@ -35,14 +35,13 @@
     ],
 
     shared_libs: [
-        "android.hardware.boot@1.1",
-        "libbase",
         "liblog",
     ],
     static_libs: [
         "libbootloader_message",
         "libfstab",
     ],
+
 }
 
 cc_library_static {
@@ -52,7 +51,13 @@
     recovery_available: true,
     vendor_available: true,
 
-    srcs: ["libboot_control.cpp"],
+    srcs: [
+        "libboot_control.cpp",
+    ],
+    static_libs: [
+        "android.hardware.boot@1.1",
+        "libbase",
+    ],
 }
 
 cc_library_shared {
@@ -67,6 +72,8 @@
         "libboot_control",
     ],
     shared_libs: [
+        "android.hardware.boot@1.1",
+        "libbase",
         "libhardware",
     ],
 }
diff --git a/boot/1.1/vts/functional/OWNERS b/boot/1.1/vts/functional/OWNERS
deleted file mode 100644
index 36e79be..0000000
--- a/boot/1.1/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 30545
-dvander@google.com
diff --git a/boot/1.2/default/Android.bp b/boot/1.2/default/Android.bp
index 4e1c35e..f1e9c34 100644
--- a/boot/1.2/default/Android.bp
+++ b/boot/1.2/default/Android.bp
@@ -20,6 +20,7 @@
     srcs: ["BootControl.cpp"],
 
     shared_libs: [
+        "libbase",
         "liblog",
         "libhidlbase",
         "libhardware",
diff --git a/boot/OWNERS b/boot/OWNERS
new file mode 100644
index 0000000..fca3dff
--- /dev/null
+++ b/boot/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 1014951
+
+dvander@google.com
+zhangkelvin@google.com
diff --git a/boot/aidl/default/Android.bp b/boot/aidl/default/Android.bp
index dcb40db..c1d3c57 100644
--- a/boot/aidl/default/Android.bp
+++ b/boot/aidl/default/Android.bp
@@ -27,7 +27,39 @@
     name: "android.hardware.boot-service_common",
     relative_install_path: "hw",
     defaults: ["libboot_control_defaults"],
+    srcs: [
+        "main.cpp",
+        "BootControl.cpp",
+    ],
+}
+
+cc_binary {
+    name: "android.hardware.boot-service.default",
+    defaults: ["android.hardware.boot-service_common"],
+    vendor: true,
+
+    stl: "c++_static",
+    shared_libs: [
+        "libbinder_ndk",
+        "liblog",
+    ],
+    static_libs: [
+        "android.hardware.boot@1.1",
+        "android.hardware.boot-V1-ndk",
+        "libbase",
+        "libboot_control",
+    ],
+
+    installable: false, // installed in APEX
+}
+
+cc_binary {
+    name: "android.hardware.boot-service.default_recovery",
+    defaults: ["android.hardware.boot-service_common"],
+    init_rc: ["android.hardware.boot-service.default_recovery.rc"],
     vintf_fragments: ["android.hardware.boot-service.default.xml"],
+    recovery: true,
+
     shared_libs: [
         "libbase",
         "libbinder_ndk",
@@ -37,19 +69,35 @@
     static_libs: [
         "libboot_control",
     ],
-    srcs: ["main.cpp", "BootControl.cpp"],
 }
 
-cc_binary {
-    name: "android.hardware.boot-service.default",
-    defaults: ["android.hardware.boot-service_common"],
-    init_rc: ["android.hardware.boot-service.default.rc"],
+prebuilt_etc {
+    name: "android.hardware.boot-service.default.rc",
+    src: "android.hardware.boot-service.default.rc",
+    installable: false,
+}
+
+prebuilt_etc {
+    name: "android.hardware.boot-service.default.xml",
+    src: "android.hardware.boot-service.default.xml",
+    sub_dir: "vintf",
+    installable: false,
+}
+
+apex {
+    name: "com.android.hardware.boot",
     vendor: true,
-}
+    manifest: "apex_manifest.json",
+    file_contexts: "apex_file_contexts",
+    key: "com.android.hardware.key",
+    certificate: ":com.android.hardware.certificate",
+    updatable: false,
 
-cc_binary {
-    name: "android.hardware.boot-service.default_recovery",
-    defaults: ["android.hardware.boot-service_common"],
-    init_rc: ["android.hardware.boot-service.default_recovery.rc"],
-    recovery: true,
+    binaries: [
+        "android.hardware.boot-service.default",
+    ],
+    prebuilts: [
+        "android.hardware.boot-service.default.rc",
+        "android.hardware.boot-service.default.xml",
+    ],
 }
diff --git a/boot/aidl/default/android.hardware.boot-service.default.rc b/boot/aidl/default/android.hardware.boot-service.default.rc
index 589f803..5090e2c 100644
--- a/boot/aidl/default/android.hardware.boot-service.default.rc
+++ b/boot/aidl/default/android.hardware.boot-service.default.rc
@@ -1,4 +1,4 @@
-service vendor.boot-default /vendor/bin/hw/android.hardware.boot-service.default
+service vendor.boot-default /apex/com.android.hardware.boot/bin/hw/android.hardware.boot-service.default
     class early_hal
     user root
     group root
diff --git a/boot/aidl/default/apex_file_contexts b/boot/aidl/default/apex_file_contexts
new file mode 100644
index 0000000..bf03585
--- /dev/null
+++ b/boot/aidl/default/apex_file_contexts
@@ -0,0 +1,3 @@
+(/.*)?                                                          u:object_r:vendor_file:s0
+/etc(/.*)?                                                      u:object_r:vendor_configs_file:s0
+/bin/hw/android\.hardware\.boot-service\.default                u:object_r:hal_bootctl_default_exec:s0
diff --git a/boot/aidl/default/apex_manifest.json b/boot/aidl/default/apex_manifest.json
new file mode 100644
index 0000000..92661c9
--- /dev/null
+++ b/boot/aidl/default/apex_manifest.json
@@ -0,0 +1,5 @@
+{
+    "name": "com.android.hardware.boot",
+    "version": 1,
+    "vendorBootstrap": true
+}
\ No newline at end of file
diff --git a/boot/aidl/vts/functional/OWNERS b/boot/aidl/vts/functional/OWNERS
deleted file mode 100644
index bc813d8..0000000
--- a/boot/aidl/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 30545
-zhangkelvin@google.com
diff --git a/broadcastradio/1.0/default/OWNERS b/broadcastradio/1.0/default/OWNERS
deleted file mode 100644
index 302fdd7..0000000
--- a/broadcastradio/1.0/default/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-xuweilin@google.com
-oscarazu@google.com
-ericjeong@google.com
-keunyoung@google.com
diff --git a/broadcastradio/1.0/vts/functional/OWNERS b/broadcastradio/1.0/vts/functional/OWNERS
deleted file mode 100644
index aa19d6a..0000000
--- a/broadcastradio/1.0/vts/functional/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-# Bug component: 533946
-xuweilin@google.com
-oscarazu@google.com
-ericjeong@google.com
-keunyoung@google.com
diff --git a/broadcastradio/1.0/vts/functional/VtsHalBroadcastradioV1_0TargetTest.cpp b/broadcastradio/1.0/vts/functional/VtsHalBroadcastradioV1_0TargetTest.cpp
index cac3dd0..dec1f17 100644
--- a/broadcastradio/1.0/vts/functional/VtsHalBroadcastradioV1_0TargetTest.cpp
+++ b/broadcastradio/1.0/vts/functional/VtsHalBroadcastradioV1_0TargetTest.cpp
@@ -52,10 +52,9 @@
 using ::android::hardware::broadcastradio::V1_0::Result;
 using ::android::hardware::broadcastradio::V1_0::vts::RadioClassFromString;
 
-#define RETURN_IF_SKIPPED \
-    if (skipped) { \
-        std::cout << "[  SKIPPED ] This device class is not supported. " << std::endl; \
-        return; \
+#define RETURN_IF_SKIPPED                                                   \
+    if (skipped) {                                                          \
+        GTEST_SKIP() << "This device class is not supported."; \
     }
 
 // The main test class for Broadcast Radio HIDL HAL.
@@ -734,4 +733,4 @@
         testing::Combine(testing::ValuesIn(android::hardware::getAllHalInstanceNames(
                                  IBroadcastRadioFactory::descriptor)),
                          ::testing::Values("AM_FM", "SAT", "DT")),
-        android::hardware::PrintInstanceTupleNameToString<>);
\ No newline at end of file
+        android::hardware::PrintInstanceTupleNameToString<>);
diff --git a/broadcastradio/1.1/default/OWNERS b/broadcastradio/1.1/default/OWNERS
deleted file mode 100644
index 259b91e..0000000
--- a/broadcastradio/1.1/default/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-# Automotive team
-xuweilin@google.com
-oscarazu@google.com
-ericjeong@google.com
-keunyoung@google.com
diff --git a/broadcastradio/1.1/vts/OWNERS b/broadcastradio/1.1/vts/OWNERS
deleted file mode 100644
index aa19d6a..0000000
--- a/broadcastradio/1.1/vts/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-# Bug component: 533946
-xuweilin@google.com
-oscarazu@google.com
-ericjeong@google.com
-keunyoung@google.com
diff --git a/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp b/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp
index caf6cbd..b54e9d8 100644
--- a/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp
+++ b/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp
@@ -73,10 +73,6 @@
     ProgramType::AM,  ProgramType::FM,   ProgramType::AM_HD, ProgramType::FM_HD,
     ProgramType::DAB, ProgramType::DRMO, ProgramType::SXM};
 
-static void printSkipped(std::string msg) {
-    std::cout << "[  SKIPPED ] " << msg << std::endl;
-}
-
 struct TunerCallbackMock : public ITunerCallback {
     TunerCallbackMock() { EXPECT_CALL(*this, hardwareFailure()).Times(0); }
 
@@ -106,7 +102,6 @@
     bool getProgramList(std::function<void(const hidl_vec<ProgramInfo>& list)> cb);
 
     Class radioClass;
-    bool skipped = false;
 
     sp<IBroadcastRadio> mRadioModule;
     sp<ITuner> mTuner;
@@ -137,9 +132,7 @@
     ASSERT_TRUE(onConnect.waitForCall(kConnectModuleTimeout));
 
     if (connectResult == Result::INVALID_ARGUMENTS) {
-        printSkipped("This device class is not supported.");
-        skipped = true;
-        return;
+        GTEST_SKIP() << "This device class is not supported.";
     }
     ASSERT_EQ(connectResult, Result::OK);
     ASSERT_NE(nullptr, mRadioModule.get());
@@ -285,8 +278,6 @@
  * might fail.
  */
 TEST_P(BroadcastRadioHalTest, OpenTunerTwice) {
-    if (skipped) return;
-
     ASSERT_TRUE(openTuner());
 
     auto secondTuner = mTuner;
@@ -306,7 +297,6 @@
  *  - getProgramInformation_1_1 returns the same selector as returned in tuneComplete_1_1 call.
  */
 TEST_P(BroadcastRadioHalTest, TuneFromProgramList) {
-    if (skipped) return;
     ASSERT_TRUE(openTuner());
 
     ProgramInfo firstProgram;
@@ -320,8 +310,7 @@
     } while (nextBand());
     if (HasFailure()) return;
     if (!foundAny) {
-        printSkipped("Program list is empty.");
-        return;
+        GTEST_SKIP() << "Program list is empty.";
     }
 
     ProgramInfo infoCb;
@@ -356,7 +345,6 @@
  *    identifier for program types other than VENDORn.
  */
 TEST_P(BroadcastRadioHalTest, TuneFailsForPrimaryVendor) {
-    if (skipped) return;
     ASSERT_TRUE(openTuner());
 
     for (auto ptype : kStandardProgramTypes) {
@@ -377,7 +365,6 @@
  *  - tuneByProgramSelector fails with INVALID_ARGUMENT when unknown program type is passed.
  */
 TEST_P(BroadcastRadioHalTest, TuneFailsForUnknownProgram) {
-    if (skipped) return;
     ASSERT_TRUE(openTuner());
 
     // Program type is 1-based, so 0 will be always invalid.
@@ -393,7 +380,6 @@
  *  - cancelAnnouncement succeeds either when there is an announcement or there is none.
  */
 TEST_P(BroadcastRadioHalTest, CancelAnnouncement) {
-    if (skipped) return;
     ASSERT_TRUE(openTuner());
 
     auto hidlResult = mTuner->cancelAnnouncement();
@@ -407,8 +393,6 @@
  * - getImage call handles argument 0 gracefully.
  */
 TEST_P(BroadcastRadioHalTest, GetNoImage) {
-    if (skipped) return;
-
     size_t len = 0;
     auto hidlResult =
         mRadioModule->getImage(0, [&](hidl_vec<uint8_t> rawImage) { len = rawImage.size(); });
@@ -425,7 +409,6 @@
  * - images are available for getImage call.
  */
 TEST_P(BroadcastRadioHalTest, OobImagesOnly) {
-    if (skipped) return;
     ASSERT_TRUE(openTuner());
 
     std::vector<int> imageIds;
@@ -446,8 +429,7 @@
     } while (nextBand());
 
     if (imageIds.size() == 0) {
-        printSkipped("No images found");
-        return;
+        GTEST_SKIP() << "No images found";
     }
 
     for (auto id : imageIds) {
@@ -469,7 +451,6 @@
  * - setAnalogForced results either with INVALID_STATE, or isAnalogForced replying the same.
  */
 TEST_P(BroadcastRadioHalTest, AnalogForcedSwitch) {
-    if (skipped) return;
     ASSERT_TRUE(openTuner());
 
     bool forced;
@@ -584,7 +565,6 @@
  * - values of ProgramIdentifier match their definitions at IdentifierType.
  */
 TEST_P(BroadcastRadioHalTest, VerifyIdentifiersFormat) {
-    if (skipped) return;
     ASSERT_TRUE(openTuner());
 
     do {
diff --git a/broadcastradio/2.0/default/OWNERS b/broadcastradio/2.0/default/OWNERS
deleted file mode 100644
index 259b91e..0000000
--- a/broadcastradio/2.0/default/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-# Automotive team
-xuweilin@google.com
-oscarazu@google.com
-ericjeong@google.com
-keunyoung@google.com
diff --git a/broadcastradio/2.0/vts/OWNERS b/broadcastradio/2.0/vts/OWNERS
deleted file mode 100644
index 09690ef..0000000
--- a/broadcastradio/2.0/vts/OWNERS
+++ /dev/null
@@ -1,8 +0,0 @@
-# Automotive team
-xuweilin@google.com
-oscarazu@google.com
-ericjeong@google.com
-keunyoung@google.com
-
-# VTS team
-dshi@google.com
diff --git a/broadcastradio/2.0/vts/functional/OWNERS b/broadcastradio/2.0/vts/functional/OWNERS
deleted file mode 100644
index aa19d6a..0000000
--- a/broadcastradio/2.0/vts/functional/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-# Bug component: 533946
-xuweilin@google.com
-oscarazu@google.com
-ericjeong@google.com
-keunyoung@google.com
diff --git a/broadcastradio/OWNERS b/broadcastradio/OWNERS
new file mode 100644
index 0000000..7c6aaca
--- /dev/null
+++ b/broadcastradio/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 533946
+
+ericjeong@google.com
+oscarazu@google.com
+xuweilin@google.com
diff --git a/broadcastradio/TEST_MAPPING b/broadcastradio/TEST_MAPPING
new file mode 100644
index 0000000..8295331
--- /dev/null
+++ b/broadcastradio/TEST_MAPPING
@@ -0,0 +1,18 @@
+{
+  "postsubmit": [
+    {
+      "name": "broadcastradio_utils_aidl_test"
+    },
+    {
+      "name": "DefaultBroadcastRadioHalTestCase"
+    },
+    {
+      "name": "android.hardware.broadcastradio@common-utils-tests"
+    }
+  ],
+  "auto-presubmit": [
+    {
+      "name": "VtsHalBroadcastradioAidlTargetTest"
+    }
+  ]
+}
diff --git a/broadcastradio/aidl/Android.bp b/broadcastradio/aidl/Android.bp
index 3f89029..e8bc5eb 100644
--- a/broadcastradio/aidl/Android.bp
+++ b/broadcastradio/aidl/Android.bp
@@ -43,6 +43,6 @@
             imports: [],
         },
     ],
-    frozen: true,
+    frozen: false,
 
 }
diff --git a/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/AmFmRegionConfig.aidl b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/AmFmRegionConfig.aidl
index fe8489c..b96def3 100644
--- a/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/AmFmRegionConfig.aidl
+++ b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/AmFmRegionConfig.aidl
@@ -37,8 +37,8 @@
   android.hardware.broadcastradio.AmFmBandRange[] ranges;
   int fmDeemphasis;
   int fmRds;
-  const int DEEMPHASIS_D50 = (1 << 0);
-  const int DEEMPHASIS_D75 = (1 << 1);
-  const int RDS = (1 << 0);
-  const int RBDS = (1 << 1);
+  const int DEEMPHASIS_D50 = (1 << 0) /* 1 */;
+  const int DEEMPHASIS_D75 = (1 << 1) /* 2 */;
+  const int RDS = (1 << 0) /* 1 */;
+  const int RBDS = (1 << 1) /* 2 */;
 }
diff --git a/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/ConfigFlag.aidl b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/ConfigFlag.aidl
index 98af437..d6d33bc 100644
--- a/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/ConfigFlag.aidl
+++ b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/ConfigFlag.aidl
@@ -35,6 +35,9 @@
 @Backing(type="int") @JavaDerive(equals=true, toString=true) @VintfStability
 enum ConfigFlag {
   FORCE_MONO = 1,
+  /**
+   * @deprecated Use {link #FORCE_ANALOG_FM} instead
+   */
   FORCE_ANALOG,
   FORCE_DIGITAL,
   RDS_AF,
@@ -43,4 +46,6 @@
   DAB_FM_LINKING,
   DAB_DAB_SOFT_LINKING,
   DAB_FM_SOFT_LINKING,
+  FORCE_ANALOG_FM,
+  FORCE_ANALOG_AM,
 }
diff --git a/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/HdSubChannel.aidl b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/HdSubChannel.aidl
new file mode 100644
index 0000000..dd06134
--- /dev/null
+++ b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/HdSubChannel.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.broadcastradio;
+@Backing(type="int") @JavaDerive(equals=true, toString=true) @VintfStability
+enum HdSubChannel {
+  HD1 = 0,
+  HD2 = 1,
+  HD3 = 2,
+  HD4 = 3,
+  HD5 = 4,
+  HD6 = 5,
+  HD7 = 6,
+  HD8 = 7,
+}
diff --git a/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/IdentifierType.aidl b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/IdentifierType.aidl
index 4df272c..ed41af0 100644
--- a/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/IdentifierType.aidl
+++ b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/IdentifierType.aidl
@@ -47,6 +47,13 @@
   DAB_FREQUENCY_KHZ,
   DRMO_SERVICE_ID,
   DRMO_FREQUENCY_KHZ,
-  SXM_SERVICE_ID = (DRMO_FREQUENCY_KHZ + 2),
+  /**
+   * @deprecated SiriusXM Satellite Radio is not supported.
+   */
+  SXM_SERVICE_ID = (DRMO_FREQUENCY_KHZ + 2) /* 12 */,
+  /**
+   * @deprecated SiriusXM Satellite Radio is not supported.
+   */
   SXM_CHANNEL,
+  HD_STATION_LOCATION,
 }
diff --git a/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Metadata.aidl b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Metadata.aidl
index e02b6b1..b4a1efa 100644
--- a/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Metadata.aidl
+++ b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Metadata.aidl
@@ -50,4 +50,12 @@
   String dabServiceNameShort;
   String dabComponentName;
   String dabComponentNameShort;
+  String genre;
+  String commentShortDescription;
+  String commentActualText;
+  String commercial;
+  String[] ufids;
+  String hdStationNameShort;
+  String hdStationNameLong;
+  int hdSubChannelsAvailable;
 }
diff --git a/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/ProgramInfo.aidl b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/ProgramInfo.aidl
index b14023a..997cdd7 100644
--- a/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/ProgramInfo.aidl
+++ b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/ProgramInfo.aidl
@@ -42,10 +42,13 @@
   int signalQuality;
   android.hardware.broadcastradio.Metadata[] metadata;
   android.hardware.broadcastradio.VendorKeyValue[] vendorInfo;
-  const int FLAG_LIVE = (1 << 0);
-  const int FLAG_MUTED = (1 << 1);
-  const int FLAG_TRAFFIC_PROGRAM = (1 << 2);
-  const int FLAG_TRAFFIC_ANNOUNCEMENT = (1 << 3);
-  const int FLAG_TUNABLE = (1 << 4);
-  const int FLAG_STEREO = (1 << 5);
+  const int FLAG_LIVE = (1 << 0) /* 1 */;
+  const int FLAG_MUTED = (1 << 1) /* 2 */;
+  const int FLAG_TRAFFIC_PROGRAM = (1 << 2) /* 4 */;
+  const int FLAG_TRAFFIC_ANNOUNCEMENT = (1 << 3) /* 8 */;
+  const int FLAG_TUNABLE = (1 << 4) /* 16 */;
+  const int FLAG_STEREO = (1 << 5) /* 32 */;
+  const int FLAG_SIGNAL_ACQUISITION = (1 << 6) /* 64 */;
+  const int FLAG_HD_SIS_ACQUISITION = (1 << 7) /* 128 */;
+  const int FLAG_HD_AUDIO_ACQUISITION = (1 << 8) /* 256 */;
 }
diff --git a/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Result.aidl b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Result.aidl
index 8af74c7..b0fc018 100644
--- a/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Result.aidl
+++ b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Result.aidl
@@ -34,7 +34,7 @@
 package android.hardware.broadcastradio;
 @Backing(type="int") @JavaDerive(equals=true, toString=true) @VintfStability
 enum Result {
-  OK,
+  OK = 0,
   INTERNAL_ERROR,
   INVALID_ARGUMENTS,
   INVALID_STATE,
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/ConfigFlag.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/ConfigFlag.aidl
index 11da39c..ddf60e0 100644
--- a/broadcastradio/aidl/android/hardware/broadcastradio/ConfigFlag.aidl
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/ConfigFlag.aidl
@@ -36,10 +36,12 @@
      * Forces the analog playback for the supporting radio technology.
      *
      * User may disable digital playback for FM HD Radio or hybrid FM/DAB with
-     * this option. This is purely user choice, ie. does not reflect digital-
+     * this option. This is purely user choice, i.e. does not reflect digital-
      * analog handover state managed from the HAL implementation side.
      *
-     * Some radio technologies may not support this, ie. DAB.
+     * Some radio technologies may not support this, i.e. DAB.
+     *
+     * @deprecated Use {link #FORCE_ANALOG_FM} instead
      */
     FORCE_ANALOG,
 
@@ -89,4 +91,26 @@
      * Enables DAB-FM soft-linking (related content).
      */
     DAB_FM_SOFT_LINKING,
+
+    /**
+     * Forces the FM analog playback for the supporting radio technology.
+     *
+     * User may disable FM digital playback for FM HD Radio or hybrid FM/DAB
+     * with this option. This is purely user choice, i.e. does not reflect
+     * digital-analog handover state managed from the HAL implementation side.
+     *
+     * Some radio technologies may not support this, i.e. DAB.
+     */
+    FORCE_ANALOG_FM,
+
+    /**
+     * Forces the AM analog playback for the supporting radio technology.
+     *
+     * User may disable AM digital playback for AM HD Radio or hybrid AM/DAB
+     * with this option. This is purely user choice, i.e. does not reflect
+     * digital-analog handover state managed from the HAL implementation side.
+     *
+     * Some radio technologies may not support this, i.e. DAB.
+     */
+    FORCE_ANALOG_AM,
 }
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/HdSubChannel.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/HdSubChannel.aidl
new file mode 100644
index 0000000..46a3e0c
--- /dev/null
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/HdSubChannel.aidl
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.broadcastradio;
+
+/**
+ * Index of HD radio subchannel.
+ */
+@VintfStability
+@Backing(type="int")
+@JavaDerive(equals=true, toString=true)
+enum HdSubChannel {
+    /**
+     * Index of HD radio subchannel 1.
+     *
+     * <p>There are at most 8 HD radio subchannels of 1-based om HD radio standard. It is
+     * converted to 0-based index. 0 is the index of main program service (MPS). 1 to 7
+     * are indexes of additional supplemental program services (SPS).
+     */
+    HD1 = 0,
+    /**
+     * {@see HD1}
+     */
+    HD2 = 1,
+    /**
+     * {@see HD1}
+     */
+    HD3 = 2,
+    /**
+     * {@see HD1}
+     */
+    HD4 = 3,
+    /**
+     * {@see HD1}
+     */
+    HD5 = 4,
+    /**
+     * {@see HD1}
+     */
+    HD6 = 5,
+    /**
+     * {@see HD1}
+     */
+    HD7 = 6,
+    /**
+     * {@see HD1}
+     */
+    HD8 = 7,
+}
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/IdentifierType.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/IdentifierType.aidl
index 646c502..4a95a41 100644
--- a/broadcastradio/aidl/android/hardware/broadcastradio/IdentifierType.aidl
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/IdentifierType.aidl
@@ -154,11 +154,42 @@
 
     /**
      * 32bit primary identifier for SiriusXM Satellite Radio.
+     *
+     * @deprecated SiriusXM Satellite Radio is not supported.
      */
     SXM_SERVICE_ID = DRMO_FREQUENCY_KHZ + 2,
 
     /**
      * 0-999 range
+     *
+     * @deprecated SiriusXM Satellite Radio is not supported.
      */
     SXM_CHANNEL,
+
+    /**
+     * 64bit additional identifier for HD Radio representing station location.
+     *
+     * Consists of (from the LSB):
+     * - 4 bit: Bits 0:3 of altitude
+     * - 13 bit: Fractional bits of longitude
+     * - 8 bit: Integer bits of longitude
+     * - 1 bit: 0 for east and 1 for west for longitude
+     * - 1 bit: 0, representing latitude
+     * - 5 bit: pad of zeros separating longitude and latitude
+     * - 4 bit: Bits 4:7 of altitude
+     * - 13 bit: Fractional bits of latitude
+     * - 8 bit: Integer bits of latitude
+     * - 1 bit: 0 for north and 1 for south for latitude
+     * - 1 bit: 1, representing latitude
+     * - 5 bit: pad of zeros
+     *
+     * This format is defined in NRSC-5-C document: SY_IDD_1020s.
+     *
+     * Due to Station ID abuse, some HD_STATION_ID_EXT identifiers may be not
+     * globally unique. To provide a best-effort solution, the station’s
+     * broadcast antenna containing the latitude and longitude may be carried
+     * as additional identifier and may be used by the tuner hardware to
+     * double-check tuning.
+     */
+    HD_STATION_LOCATION,
 }
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/Metadata.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/Metadata.aidl
index 7769b8c..f1800dc 100644
--- a/broadcastradio/aidl/android/hardware/broadcastradio/Metadata.aidl
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/Metadata.aidl
@@ -86,7 +86,7 @@
     /**
      * DAB ensemble name abbreviated (string).
      *
-     * <p>Note: The string must be up to 8 characters long.
+     * <p>Note: The string should be <= 8 characters.
      *
      * <p>Note: If the short variant is present, the long ({@link Metadata#dabEnsembleName})
      * one must be present as well.
@@ -101,7 +101,7 @@
     /**
      * DAB service name abbreviated (string)
      *
-     * <p>Note: The string must be up to 8 characters long.
+     * <p>Note: The string should be <= 8 characters.
      */
     String dabServiceNameShort;
 
@@ -113,7 +113,73 @@
     /**
      * DAB component name abbreviated (string)
      *
-     * <p>Note: The string must be up to 8 characters long.
+     * <p>Note: The string should be <= 8 characters.
      */
     String dabComponentNameShort;
+
+    /**
+     * Genre of the current audio piece (string)
+     *
+     * <p>(see NRSC-G200-A and id3v2.3.0 for more info)
+     */
+    String genre;
+
+    /**
+     * Short context description of comment (string)
+     *
+     * <p>Comment could relate to the current audio program content, or it might
+     * be unrelated information that the station chooses to send. It is
+     * composed of short content description and actual text (see NRSC-G200-A
+     * and id3v2.3.0 for more info).
+     */
+    String commentShortDescription;
+
+    /**
+     * Actual text of comment (string)
+     *
+     * @see #commentShortDescription
+     */
+    String commentActualText;
+
+    /**
+     * Commercial (string)
+     *
+     * <p>Commercial is application specific and generally used to facilitate the
+     * sale of products and services (see NRSC-G200-A and id3v2.3.0 for more info).
+     */
+    String commercial;
+
+    /**
+     * HD Unique File Identifiers (Array of strings)
+     *
+     * <p>Unique File Identifier (UFID) can be used to transmit an alphanumeric
+     * identifier of the current content, or of an advertised product or service
+     * (see NRSC-G200-A and id3v2.3.0 for more info).
+     */
+    String[] ufids;
+
+    /**
+     * HD short station name or HD universal short station name
+     *
+     * <p>It can be <= 12 characters (see SY_IDD_1020s for more info).
+     */
+    String hdStationNameShort;
+
+    /**
+     * HD long station name, HD station slogan or HD station message
+     *
+     * <p>(see SY_IDD_1020s for more info)
+     */
+    String hdStationNameLong;
+
+    /**
+     * Bit mask of all HD Radio subchannels available (uint8_t)
+     *
+     * <p>Bit {@link HdSubChannel#HD1} from LSB represents the availability
+     * of HD-1 subchannel (main program service, MPS). Bits
+     * {@link HdSubChannel#HD2} to {@link HdSubChannel#HD8} from LSB represent
+     * HD-2 to HD-8 subchannel (supplemental program services, SPS)
+     * respectively.
+     */
+    int hdSubChannelsAvailable;
 }
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/ProgramInfo.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/ProgramInfo.aidl
index 7632c81..d4ccd01 100644
--- a/broadcastradio/aidl/android/hardware/broadcastradio/ProgramInfo.aidl
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/ProgramInfo.aidl
@@ -71,6 +71,23 @@
     const int FLAG_STEREO = 1 << 5;
 
     /**
+     * A signal has been acquired if this bit is set.
+     */
+
+    const int FLAG_SIGNAL_ACQUISITION = 1 << 6;
+    /**
+     * An HD Station Information Service (SIS) information is available if this
+     * bit is set.
+     */
+
+    const int FLAG_HD_SIS_ACQUISITION = 1 << 7;
+
+    /**
+     * An HD digital audio is available if this bit is set.
+     */
+    const int FLAG_HD_AUDIO_ACQUISITION = 1 << 8;
+
+    /**
      * An identifier used to point at the program (primarily to tune to it).
      *
      * This field is required - its type field must not be set to
@@ -153,7 +170,8 @@
      *
      * It can be a combination of {@link #FLAG_LIVE}, {@link #FLAG_MUTED},
      * {@link #FLAG_TRAFFIC_PROGRAM}, {@link #FLAG_TRAFFIC_ANNOUNCEMENT},
-     * {@link #FLAG_TUNABLE}, and {@link #FLAG_STEREO}.
+     * {@link #FLAG_TUNABLE}, {@link #FLAG_STEREO}, {@link #FLAG_SIGNAL_ACQUISITION},
+     * {@link #FLAG_HD_SIS_ACQUISITION}, and {@link #FLAG_HD_AUDIO_ACQUISITION}.
      */
     int infoFlags;
 
diff --git a/broadcastradio/aidl/default/Android.bp b/broadcastradio/aidl/default/Android.bp
index 720aa8a..d7bb751 100644
--- a/broadcastradio/aidl/default/Android.bp
+++ b/broadcastradio/aidl/default/Android.bp
@@ -23,32 +23,75 @@
     default_applicable_licenses: ["hardware_interfaces_license"],
 }
 
+cc_defaults {
+    name: "BroadcastRadioHalDefaults",
+    static_libs: [
+        "android.hardware.broadcastradio-V2-ndk",
+        "android.hardware.broadcastradio@common-utils-aidl-lib-V2",
+        "android.hardware.broadcastradio@common-utils-lib",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "liblog",
+        "libcutils",
+    ],
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+}
+
 cc_binary {
     name: "android.hardware.broadcastradio-service.default",
     relative_install_path: "hw",
     init_rc: ["broadcastradio-default.rc"],
     vintf_fragments: ["broadcastradio-default.xml"],
     vendor: true,
-    cflags: [
-        "-Wall",
-        "-Wextra",
-        "-Werror",
+    defaults: [
+        "BroadcastRadioHalDefaults",
+    ],
+    srcs: [
+        "main.cpp",
+    ],
+    static_libs: [
+        "DefaultBroadcastRadioHal",
+    ],
+}
+
+cc_library {
+    name: "DefaultBroadcastRadioHal",
+    vendor_available: true,
+    export_include_dirs: ["."],
+    defaults: [
+        "BroadcastRadioHalDefaults",
     ],
     srcs: [
         "BroadcastRadio.cpp",
-        "main.cpp",
         "VirtualProgram.cpp",
         "VirtualRadio.cpp",
     ],
+}
+
+cc_fuzz {
+    name: "android.hardware.broadcastradio-service.default_fuzzer",
+    // TODO(b/307611931): avoid fuzzing on vendor until hermiticity issue is fixed
+    // vendor: true,
+    defaults: [
+        "BroadcastRadioHalDefaults",
+        "service_fuzzer_defaults",
+    ],
     static_libs: [
-        "android.hardware.broadcastradio@common-utils-aidl-lib",
-        "android.hardware.broadcastradio@common-utils-lib",
+        "DefaultBroadcastRadioHal",
+        "android.hardware.broadcastradio-V2-ndk",
     ],
-    shared_libs: [
-        "android.hardware.broadcastradio-V1-ndk",
-        "libbase",
-        "libbinder_ndk",
-        "liblog",
-        "libcutils",
+    srcs: [
+        "fuzzer.cpp",
     ],
+    fuzz_config: {
+        cc: [
+            "xuweilin@google.com",
+        ],
+    },
 }
diff --git a/broadcastradio/aidl/default/BroadcastRadio.cpp b/broadcastradio/aidl/default/BroadcastRadio.cpp
index c0c475a..4d6d81d 100644
--- a/broadcastradio/aidl/default/BroadcastRadio.cpp
+++ b/broadcastradio/aidl/default/BroadcastRadio.cpp
@@ -16,6 +16,7 @@
 
 #include "BroadcastRadio.h"
 #include <broadcastradio-utils-aidl/Utils.h>
+#include <broadcastradio-utils-aidl/UtilsV2.h>
 #include "resources.h"
 
 #include <aidl/android/hardware/broadcastradio/IdentifierType.h>
@@ -47,6 +48,8 @@
 inline constexpr std::chrono::seconds kListDelayTimeS = 1s;
 
 // clang-format off
+const AmFmBandRange kFmFullBandRange = {65000, 108000, 10, 0};
+const AmFmBandRange kAmFullBandRange = {150, 30000, 1, 0};
 const AmFmRegionConfig kDefaultAmFmConfig = {
         {
                 {87500, 108000, 100, 100},  // FM
@@ -63,12 +66,7 @@
 
     prop.maker = "Android";
     prop.product = virtualRadio.getName();
-    prop.supportedIdentifierTypes = vector<IdentifierType>({
-            IdentifierType::AMFM_FREQUENCY_KHZ,
-            IdentifierType::RDS_PI,
-            IdentifierType::HD_STATION_ID_EXT,
-            IdentifierType::DAB_SID_EXT,
-    });
+    prop.supportedIdentifierTypes = virtualRadio.getSupportedIdentifierTypes();
     prop.vendorInfo = vector<VendorKeyValue>({
             {"com.android.sample", "sample"},
     });
@@ -76,14 +74,71 @@
     return prop;
 }
 
+bool isDigitalProgramAllowed(const ProgramSelector& sel, bool forceAnalogFm, bool forceAnalogAm) {
+    if (sel.primaryId.type != IdentifierType::HD_STATION_ID_EXT) {
+        return true;
+    }
+    int32_t freq = static_cast<int32_t>(utils::getAmFmFrequency(sel));
+    bool isFm = freq >= kFmFullBandRange.lowerBound && freq <= kFmFullBandRange.upperBound;
+    return isFm ? !forceAnalogFm : !forceAnalogAm;
+}
+
+/**
+ * Checks whether a program selector is in the current band.
+ *
+ * <p>For an AM/FM program, this method checks whether it is in the current AM/FM band. For a
+ * program selector is also an HD program, it is also checked whether HD radio is enabled in the
+ * current AM/FM band. For a non-AM/FM program, the method will returns {@code true} directly.
+ * @param sel Program selector to be checked
+ * @param currentAmFmBandRange the current AM/FM band
+ * @param forceAnalogFm whether FM band is forced to be analog
+ * @param forceAnalogAm  whether AM band is forced to be analog
+ * @return whether the program selector is in the current band if it is an AM/FM (including HD)
+ * selector, {@code true} otherwise
+ */
+bool isProgramInBand(const ProgramSelector& sel,
+                     const std::optional<AmFmBandRange>& currentAmFmBandRange, bool forceAnalogFm,
+                     bool forceAnalogAm) {
+    if (!utils::hasAmFmFrequency(sel)) {
+        return true;
+    }
+    if (!currentAmFmBandRange.has_value()) {
+        return false;
+    }
+    int32_t freq = static_cast<int32_t>(utils::getAmFmFrequency(sel));
+    if (freq < currentAmFmBandRange->lowerBound || freq > currentAmFmBandRange->upperBound) {
+        return false;
+    }
+    return isDigitalProgramAllowed(sel, forceAnalogFm, forceAnalogAm);
+}
+
 // Makes ProgramInfo that does not point to any particular program
 ProgramInfo makeSampleProgramInfo(const ProgramSelector& selector) {
     ProgramInfo info = {};
     info.selector = selector;
-    info.logicallyTunedTo =
-            utils::makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ,
-                                  utils::getId(selector, IdentifierType::AMFM_FREQUENCY_KHZ));
-    info.physicallyTunedTo = info.logicallyTunedTo;
+    switch (info.selector.primaryId.type) {
+        case IdentifierType::AMFM_FREQUENCY_KHZ:
+            info.logicallyTunedTo = utils::makeIdentifier(
+                    IdentifierType::AMFM_FREQUENCY_KHZ,
+                    utils::getId(selector, IdentifierType::AMFM_FREQUENCY_KHZ));
+            info.physicallyTunedTo = info.logicallyTunedTo;
+            break;
+        case IdentifierType::HD_STATION_ID_EXT:
+            info.logicallyTunedTo = utils::makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ,
+                                                          utils::getAmFmFrequency(info.selector));
+            info.physicallyTunedTo = info.logicallyTunedTo;
+            break;
+        case IdentifierType::DAB_SID_EXT:
+            info.logicallyTunedTo = info.selector.primaryId;
+            info.physicallyTunedTo = utils::makeIdentifier(
+                    IdentifierType::DAB_FREQUENCY_KHZ,
+                    utils::getId(selector, IdentifierType::DAB_FREQUENCY_KHZ));
+            break;
+        default:
+            info.logicallyTunedTo = info.selector.primaryId;
+            info.physicallyTunedTo = info.logicallyTunedTo;
+            break;
+    }
     return info;
 }
 
@@ -111,19 +166,21 @@
         } else {
             mCurrentProgram = sel;
         }
+        adjustAmFmRangeLocked();
     }
 }
 
 BroadcastRadio::~BroadcastRadio() {
-    mThread.reset();
+    mTuningThread.reset();
+    mProgramListThread.reset();
 }
 
 ScopedAStatus BroadcastRadio::getAmFmRegionConfig(bool full, AmFmRegionConfig* returnConfigs) {
     if (full) {
         *returnConfigs = {};
         returnConfigs->ranges = vector<AmFmBandRange>({
-                {65000, 108000, 10, 0},  // FM
-                {150, 30000, 1, 0},      // AM
+                kFmFullBandRange,
+                kAmFullBandRange,
         });
         returnConfigs->fmDeemphasis =
                 AmFmRegionConfig::DEEMPHASIS_D50 | AmFmRegionConfig::DEEMPHASIS_D75;
@@ -169,14 +226,27 @@
 
     VirtualProgram virtualProgram = {};
     ProgramInfo programInfo;
-    if (mVirtualRadio.getProgram(sel, &virtualProgram)) {
+    bool isProgramAllowed =
+            isDigitalProgramAllowed(sel, isConfigFlagSetLocked(ConfigFlag::FORCE_ANALOG_FM),
+                                    isConfigFlagSetLocked(ConfigFlag::FORCE_ANALOG_AM));
+    if (isProgramAllowed && mVirtualRadio.getProgram(sel, &virtualProgram)) {
         mCurrentProgram = virtualProgram.selector;
         programInfo = virtualProgram;
     } else {
-        mCurrentProgram = sel;
+        if (!isProgramAllowed) {
+            mCurrentProgram = utils::makeSelectorAmfm(utils::getAmFmFrequency(sel));
+        } else {
+            mCurrentProgram = sel;
+        }
         programInfo = makeSampleProgramInfo(sel);
     }
-    mIsTuneCompleted = true;
+    programInfo.infoFlags |= ProgramInfo::FLAG_SIGNAL_ACQUISITION;
+    if (programInfo.selector.primaryId.type != IdentifierType::HD_STATION_ID_EXT) {
+        mIsTuneCompleted = true;
+    }
+    if (adjustAmFmRangeLocked()) {
+        startProgramListUpdatesLocked({});
+    }
 
     return programInfo;
 }
@@ -204,6 +274,32 @@
     return ScopedAStatus::ok();
 }
 
+void BroadcastRadio::handleProgramInfoUpdateRadioCallback(
+        ProgramInfo programInfo, const std::shared_ptr<ITunerCallback>& callback) {
+    callback->onCurrentProgramInfoChanged(programInfo);
+    if (programInfo.selector.primaryId.type != IdentifierType::HD_STATION_ID_EXT) {
+        return;
+    }
+    ProgramSelector sel = programInfo.selector;
+    auto cancelTask = [sel, callback]() { callback->onTuneFailed(Result::CANCELED, sel); };
+    programInfo.infoFlags |= ProgramInfo::FLAG_HD_SIS_ACQUISITION;
+    auto sisAcquiredTask = [this, callback, programInfo, cancelTask]() {
+        callback->onCurrentProgramInfoChanged(programInfo);
+        auto audioAcquiredTask = [this, callback, programInfo]() {
+            ProgramInfo hdProgramInfoWithAudio = programInfo;
+            hdProgramInfoWithAudio.infoFlags |= ProgramInfo::FLAG_HD_AUDIO_ACQUISITION;
+            callback->onCurrentProgramInfoChanged(hdProgramInfoWithAudio);
+            lock_guard<mutex> lk(mMutex);
+            mIsTuneCompleted = true;
+        };
+        lock_guard<mutex> lk(mMutex);
+        mTuningThread->schedule(audioAcquiredTask, cancelTask, kTuneDelayTimeMs);
+    };
+
+    lock_guard<mutex> lk(mMutex);
+    mTuningThread->schedule(sisAcquiredTask, cancelTask, kTuneDelayTimeMs);
+}
+
 ScopedAStatus BroadcastRadio::tune(const ProgramSelector& program) {
     LOG(DEBUG) << __func__ << ": tune to " << program.toString() << "...";
 
@@ -220,7 +316,7 @@
                 resultToInt(Result::NOT_SUPPORTED), "selector is not supported");
     }
 
-    if (!utils::isValid(program)) {
+    if (!utils::isValidV2(program)) {
         LOG(ERROR) << __func__ << ": selector is not valid: " << program.toString();
         return ScopedAStatus::fromServiceSpecificErrorWithMessage(
                 resultToInt(Result::INVALID_ARGUMENTS), "selector is not valid");
@@ -236,14 +332,130 @@
             lock_guard<mutex> lk(mMutex);
             programInfo = tuneInternalLocked(program);
         }
-        callback->onCurrentProgramInfoChanged(programInfo);
+        handleProgramInfoUpdateRadioCallback(programInfo, callback);
     };
     auto cancelTask = [program, callback]() { callback->onTuneFailed(Result::CANCELED, program); };
-    mThread->schedule(task, cancelTask, kTuneDelayTimeMs);
+    mTuningThread->schedule(task, cancelTask, kTuneDelayTimeMs);
 
     return ScopedAStatus::ok();
 }
 
+bool BroadcastRadio::findNextLocked(const ProgramSelector& current, bool directionUp,
+                                    bool skipSubChannel, VirtualProgram* nextProgram) const {
+    if (mProgramList.empty()) {
+        return false;
+    }
+    // The list is not sorted here since it has already stored in VirtualRadio.
+    bool hasAmFmFrequency = utils::hasAmFmFrequency(current);
+    bool hasDabSId = utils::hasId(current, IdentifierType::DAB_SID_EXT);
+    uint32_t currentChannel =
+            hasAmFmFrequency ? utils::getAmFmFrequency(current) : utils::getDabSId(current);
+    auto found =
+            std::lower_bound(mProgramList.begin(), mProgramList.end(), VirtualProgram({current}));
+    if (directionUp) {
+        if (found < mProgramList.end() - 1) {
+            // When seeking up, tuner will jump to the first selector which is main program service
+            // greater than and of the same band as the current program selector in the program
+            // list (if not exist, jump to the first selector in the same band) for skipping
+            // sub-channels case or AM/FM without HD radio enabled case. Otherwise, the tuner will
+            // jump to the first selector which is greater than and of the same band as the current
+            // program selector.
+            if (utils::tunesTo(current, found->selector)) found++;
+            if (skipSubChannel) {
+                if (hasAmFmFrequency || hasDabSId) {
+                    auto firstFound = found;
+                    while ((hasAmFmFrequency &&
+                            utils::getAmFmFrequency(found->selector) == currentChannel) ||
+                           (hasDabSId && utils::getDabSId(found->selector) == currentChannel)) {
+                        if (found < mProgramList.end() - 1) {
+                            found++;
+                        } else {
+                            found = mProgramList.begin();
+                        }
+                        if (found == firstFound) {
+                            // Only one main channel exists in the program list, the tuner cannot
+                            // skip sub-channel to the next program selector.
+                            return false;
+                        }
+                    }
+                }
+            }
+        } else {
+            // If the selector of current program is no less than all selectors of the same band or
+            // not found in the program list, seeking up should wrap the tuner to the first program
+            // selector of the same band in the program list.
+            found = mProgramList.begin();
+        }
+    } else {
+        if (found > mProgramList.begin() && found != mProgramList.end()) {
+            // When seeking down, tuner will jump to the first selector which is main program
+            // service less than and of the same band as the current program selector in the
+            // program list (if not exist, jump to the last main program service selector of the
+            // same band) for skipping sub-channels case or AM/FM without HD radio enabled case.
+            // Otherwise, the tuner will jump to the first selector less than and of the same band
+            // as the current program selector.
+            found--;
+            if ((hasAmFmFrequency && utils::hasAmFmFrequency(found->selector)) ||
+                (hasDabSId && utils::hasId(found->selector, IdentifierType::DAB_SID_EXT))) {
+                uint32_t nextChannel = hasAmFmFrequency ? utils::getAmFmFrequency(found->selector)
+                                                        : utils::getDabSId(found->selector);
+                if (nextChannel != currentChannel) {
+                    jumpToFirstSubChannelLocked(found);
+                } else if (skipSubChannel) {
+                    jumpToFirstSubChannelLocked(found);
+                    auto firstFound = found;
+                    if (found > mProgramList.begin()) {
+                        found--;
+                    } else {
+                        found = mProgramList.end() - 1;
+                    }
+                    jumpToFirstSubChannelLocked(found);
+                    if (found == firstFound) {
+                        // Only one main channel exists in the program list, the tuner cannot skip
+                        // sub-channel to the next program selector.
+                        return false;
+                    }
+                }
+            }
+        } else {
+            // If the selector of current program is no greater than all selectors of the same band
+            // or not found in the program list, seeking down should wrap the tuner to the last
+            // selector of the same band in the program list. If the last program selector in the
+            // program list is sub-channel and skipping sub-channels is needed, the tuner will jump
+            // to the last main program service of the same band in the program list.
+            found = mProgramList.end() - 1;
+            jumpToFirstSubChannelLocked(found);
+        }
+    }
+    *nextProgram = *found;
+    return true;
+}
+
+void BroadcastRadio::jumpToFirstSubChannelLocked(vector<VirtualProgram>::const_iterator& it) const {
+    if (it == mProgramList.begin()) {
+        return;
+    }
+    bool hasAmFmFrequency = utils::hasAmFmFrequency(it->selector);
+    bool hasDabSId = utils::hasId(it->selector, IdentifierType::DAB_SID_EXT);
+    if (hasAmFmFrequency || hasDabSId) {
+        uint32_t currentChannel = hasAmFmFrequency ? utils::getAmFmFrequency(it->selector)
+                                                   : utils::getDabSId(it->selector);
+        it--;
+        while (it != mProgramList.begin()) {
+            if (hasAmFmFrequency && utils::hasAmFmFrequency(it->selector) &&
+                utils::getAmFmFrequency(it->selector) == currentChannel) {
+                it--;
+            } else if (hasDabSId && utils::hasId(it->selector, IdentifierType::DAB_SID_EXT) &&
+                       utils::getDabSId(it->selector) == currentChannel) {
+                it--;
+            } else {
+                break;
+            }
+        }
+        it++;
+    }
+}
+
 ScopedAStatus BroadcastRadio::seek(bool directionUp, bool skipSubChannel) {
     LOG(DEBUG) << __func__ << ": seek " << (directionUp ? "up" : "down") << " with skipSubChannel? "
                << (skipSubChannel ? "yes" : "no") << "...";
@@ -257,50 +469,40 @@
 
     cancelLocked();
 
+    auto filterCb = [this](const VirtualProgram& program) {
+        return isProgramInBand(program.selector, mCurrentAmFmBandRange,
+                               isConfigFlagSetLocked(ConfigFlag::FORCE_ANALOG_FM),
+                               isConfigFlagSetLocked(ConfigFlag::FORCE_ANALOG_AM));
+    };
     const auto& list = mVirtualRadio.getProgramList();
+    mProgramList.clear();
+    std::copy_if(list.begin(), list.end(), std::back_inserter(mProgramList), filterCb);
     std::shared_ptr<ITunerCallback> callback = mCallback;
     auto cancelTask = [callback]() { callback->onTuneFailed(Result::CANCELED, {}); };
-    if (list.empty()) {
-        mIsTuneCompleted = false;
+
+    VirtualProgram nextProgram = {};
+    bool foundNext = findNextLocked(mCurrentProgram, directionUp, skipSubChannel, &nextProgram);
+    mIsTuneCompleted = false;
+    if (!foundNext) {
         auto task = [callback]() {
             LOG(DEBUG) << "seek: program list is empty, seek couldn't stop";
 
             callback->onTuneFailed(Result::TIMEOUT, {});
         };
-        mThread->schedule(task, cancelTask, kSeekDelayTimeMs);
+        mTuningThread->schedule(task, cancelTask, kSeekDelayTimeMs);
 
         return ScopedAStatus::ok();
     }
 
-    // The list is not sorted here since it has already stored in VirtualRadio.
-    // If the list is not sorted in advance, it should be sorted here.
-    const auto& current = mCurrentProgram;
-    auto found = std::lower_bound(list.begin(), list.end(), VirtualProgram({current}));
-    if (directionUp) {
-        if (found < list.end() - 1) {
-            if (tunesTo(current, found->selector)) found++;
-        } else {
-            found = list.begin();
-        }
-    } else {
-        if (found > list.begin() && found != list.end()) {
-            found--;
-        } else {
-            found = list.end() - 1;
-        }
-    }
-    const ProgramSelector tuneTo = found->selector;
-
-    mIsTuneCompleted = false;
-    auto task = [this, tuneTo, callback]() {
+    auto task = [this, nextProgram, callback]() {
         ProgramInfo programInfo = {};
         {
             lock_guard<mutex> lk(mMutex);
-            programInfo = tuneInternalLocked(tuneTo);
+            programInfo = tuneInternalLocked(nextProgram.selector);
         }
-        callback->onCurrentProgramInfoChanged(programInfo);
+        handleProgramInfoUpdateRadioCallback(programInfo, callback);
     };
-    mThread->schedule(task, cancelTask, kSeekDelayTimeMs);
+    mTuningThread->schedule(task, cancelTask, kSeekDelayTimeMs);
 
     return ScopedAStatus::ok();
 }
@@ -317,31 +519,33 @@
 
     cancelLocked();
 
-    if (!utils::hasId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY_KHZ)) {
+    int64_t stepTo;
+    if (utils::hasId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY_KHZ)) {
+        stepTo = utils::getId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY_KHZ);
+    } else if (mCurrentProgram.primaryId.type == IdentifierType::HD_STATION_ID_EXT) {
+        stepTo = utils::getHdFrequency(mCurrentProgram);
+    } else {
         LOG(WARNING) << __func__ << ": can't step in anything else than AM/FM";
         return ScopedAStatus::fromServiceSpecificErrorWithMessage(
                 resultToInt(Result::NOT_SUPPORTED), "cannot step in anything else than AM/FM");
     }
 
-    int64_t stepTo = utils::getId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY_KHZ);
-    std::optional<AmFmBandRange> range = getAmFmRangeLocked();
-    if (!range) {
-        LOG(ERROR) << __func__ << ": can't find current band or tune operation is in process";
-        ScopedAStatus::fromServiceSpecificErrorWithMessage(
-                resultToInt(Result::INTERNAL_ERROR),
-                "can't find current band or tune operation is in process");
+    if (!mCurrentAmFmBandRange.has_value()) {
+        LOG(ERROR) << __func__ << ": can't find current band";
+        return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                resultToInt(Result::INTERNAL_ERROR), "can't find current band");
     }
 
     if (directionUp) {
-        stepTo += range->spacing;
+        stepTo += mCurrentAmFmBandRange->spacing;
     } else {
-        stepTo -= range->spacing;
+        stepTo -= mCurrentAmFmBandRange->spacing;
     }
-    if (stepTo > range->upperBound) {
-        stepTo = range->lowerBound;
+    if (stepTo > mCurrentAmFmBandRange->upperBound) {
+        stepTo = mCurrentAmFmBandRange->lowerBound;
     }
-    if (stepTo < range->lowerBound) {
-        stepTo = range->upperBound;
+    if (stepTo < mCurrentAmFmBandRange->lowerBound) {
+        stepTo = mCurrentAmFmBandRange->upperBound;
     }
 
     mIsTuneCompleted = false;
@@ -352,18 +556,18 @@
             lock_guard<mutex> lk(mMutex);
             programInfo = tuneInternalLocked(utils::makeSelectorAmfm(stepTo));
         }
-        callback->onCurrentProgramInfoChanged(programInfo);
+        handleProgramInfoUpdateRadioCallback(programInfo, callback);
     };
     auto cancelTask = [callback]() { callback->onTuneFailed(Result::CANCELED, {}); };
-    mThread->schedule(task, cancelTask, kStepDelayTimeMs);
+    mTuningThread->schedule(task, cancelTask, kStepDelayTimeMs);
 
     return ScopedAStatus::ok();
 }
 
 void BroadcastRadio::cancelLocked() {
-    LOG(DEBUG) << __func__ << ": cancelling current operations...";
+    LOG(DEBUG) << __func__ << ": cancelling current tuning operations...";
 
-    mThread->cancelAll();
+    mTuningThread->cancelAll();
     if (mCurrentProgram.primaryId.type != IdentifierType::INVALID) {
         mIsTuneCompleted = true;
     }
@@ -378,15 +582,15 @@
     return ScopedAStatus::ok();
 }
 
-ScopedAStatus BroadcastRadio::startProgramListUpdates(const ProgramFilter& filter) {
-    LOG(DEBUG) << __func__ << ": requested program list updates, filter = " << filter.toString()
-               << "...";
-
-    auto filterCb = [&filter](const VirtualProgram& program) {
-        return utils::satisfies(filter, program.selector);
+void BroadcastRadio::startProgramListUpdatesLocked(const ProgramFilter& filter) {
+    auto filterCb = [&filter, this](const VirtualProgram& program) {
+        return utils::satisfies(filter, program.selector) &&
+               isProgramInBand(program.selector, mCurrentAmFmBandRange,
+                               isConfigFlagSetLocked(ConfigFlag::FORCE_ANALOG_FM),
+                               isConfigFlagSetLocked(ConfigFlag::FORCE_ANALOG_AM));
     };
 
-    lock_guard<mutex> lk(mMutex);
+    cancelProgramListUpdateLocked();
 
     const auto& list = mVirtualRadio.getProgramList();
     vector<VirtualProgram> filteredList;
@@ -410,31 +614,65 @@
 
         callback->onProgramListUpdated(chunk);
     };
-    mThread->schedule(task, kListDelayTimeS);
+    mProgramListThread->schedule(task, kListDelayTimeS);
+}
+
+ScopedAStatus BroadcastRadio::startProgramListUpdates(const ProgramFilter& filter) {
+    LOG(DEBUG) << __func__ << ": requested program list updates, filter = " << filter.toString()
+               << "...";
+
+    lock_guard<mutex> lk(mMutex);
+
+    startProgramListUpdatesLocked(filter);
 
     return ScopedAStatus::ok();
 }
 
+void BroadcastRadio::cancelProgramListUpdateLocked() {
+    LOG(DEBUG) << __func__ << ": cancelling current program list update operations...";
+    mProgramListThread->cancelAll();
+}
+
 ScopedAStatus BroadcastRadio::stopProgramListUpdates() {
     LOG(DEBUG) << __func__ << ": requested program list updates to stop...";
-    // TODO(b/243681584) Implement stop program list updates method
+    lock_guard<mutex> lk(mMutex);
+    cancelProgramListUpdateLocked();
     return ScopedAStatus::ok();
 }
 
-ScopedAStatus BroadcastRadio::isConfigFlagSet(ConfigFlag flag, [[maybe_unused]] bool* returnIsSet) {
+bool BroadcastRadio::isConfigFlagSetLocked(ConfigFlag flag) const {
+    int flagBit = static_cast<int>(flag);
+    return ((mConfigFlagValues >> flagBit) & 1) == 1;
+}
+
+ScopedAStatus BroadcastRadio::isConfigFlagSet(ConfigFlag flag, bool* returnIsSet) {
     LOG(DEBUG) << __func__ << ": flag = " << toString(flag);
 
-    LOG(INFO) << __func__ << ": getting ConfigFlag is not supported";
-    return ScopedAStatus::fromServiceSpecificErrorWithMessage(
-            resultToInt(Result::NOT_SUPPORTED), "getting ConfigFlag is not supported");
+    if (flag == ConfigFlag::FORCE_ANALOG) {
+        flag = ConfigFlag::FORCE_ANALOG_FM;
+    }
+    lock_guard<mutex> lk(mMutex);
+    *returnIsSet = isConfigFlagSetLocked(flag);
+    return ScopedAStatus::ok();
 }
 
 ScopedAStatus BroadcastRadio::setConfigFlag(ConfigFlag flag, bool value) {
     LOG(DEBUG) << __func__ << ": flag = " << toString(flag) << ", value = " << value;
 
-    LOG(INFO) << __func__ << ": setting ConfigFlag is not supported";
-    return ScopedAStatus::fromServiceSpecificErrorWithMessage(
-            resultToInt(Result::NOT_SUPPORTED), "setting ConfigFlag is not supported");
+    if (flag == ConfigFlag::FORCE_ANALOG) {
+        flag = ConfigFlag::FORCE_ANALOG_FM;
+    }
+    int flagBitMask = 1 << (static_cast<int>(flag));
+    lock_guard<mutex> lk(mMutex);
+    if (value) {
+        mConfigFlagValues |= flagBitMask;
+    } else {
+        mConfigFlagValues &= ~flagBitMask;
+    }
+    if (flag == ConfigFlag::FORCE_ANALOG_AM || flag == ConfigFlag::FORCE_ANALOG_FM) {
+        startProgramListUpdatesLocked({});
+    }
+    return ScopedAStatus::ok();
 }
 
 ScopedAStatus BroadcastRadio::setParameters(
@@ -452,24 +690,25 @@
     return ScopedAStatus::ok();
 }
 
-std::optional<AmFmBandRange> BroadcastRadio::getAmFmRangeLocked() const {
-    if (!mIsTuneCompleted) {
-        LOG(WARNING) << __func__ << ": tune operation is in process";
-        return {};
-    }
-    if (!utils::hasId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY_KHZ)) {
+bool BroadcastRadio::adjustAmFmRangeLocked() {
+    bool hasBandBefore = mCurrentAmFmBandRange.has_value();
+    if (!utils::hasAmFmFrequency(mCurrentProgram)) {
         LOG(WARNING) << __func__ << ": current program does not has AMFM_FREQUENCY_KHZ identifier";
-        return {};
+        mCurrentAmFmBandRange.reset();
+        return hasBandBefore;
     }
 
-    int64_t freq = utils::getId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY_KHZ);
+    int32_t freq = static_cast<int32_t>(utils::getAmFmFrequency(mCurrentProgram));
     for (const auto& range : mAmFmConfig.ranges) {
         if (range.lowerBound <= freq && range.upperBound >= freq) {
-            return range;
+            bool isBandChanged = hasBandBefore ? *mCurrentAmFmBandRange != range : true;
+            mCurrentAmFmBandRange = range;
+            return isBandChanged;
         }
     }
 
-    return {};
+    mCurrentAmFmBandRange.reset();
+    return !hasBandBefore;
 }
 
 ScopedAStatus BroadcastRadio::registerAnnouncementListener(
diff --git a/broadcastradio/aidl/default/BroadcastRadio.h b/broadcastradio/aidl/default/BroadcastRadio.h
index 1c85ddc..60ea907 100644
--- a/broadcastradio/aidl/default/BroadcastRadio.h
+++ b/broadcastradio/aidl/default/BroadcastRadio.h
@@ -39,21 +39,25 @@
   public:
     explicit BroadcastRadio(const VirtualRadio& virtualRadio);
     ~BroadcastRadio();
-    ndk::ScopedAStatus getAmFmRegionConfig(bool full, AmFmRegionConfig* returnConfigs) override;
+    ndk::ScopedAStatus getAmFmRegionConfig(bool full, AmFmRegionConfig* returnConfigs)
+            EXCLUDES(mMutex) override;
     ndk::ScopedAStatus getDabRegionConfig(std::vector<DabTableEntry>* returnConfigs) override;
     ndk::ScopedAStatus getImage(int32_t id, std::vector<uint8_t>* returnImage) override;
-    ndk::ScopedAStatus getProperties(Properties* returnProperties) override;
+    ndk::ScopedAStatus getProperties(Properties* returnProperties) EXCLUDES(mMutex) override;
 
-    ndk::ScopedAStatus setTunerCallback(const std::shared_ptr<ITunerCallback>& callback) override;
-    ndk::ScopedAStatus unsetTunerCallback() override;
-    ndk::ScopedAStatus tune(const ProgramSelector& program) override;
-    ndk::ScopedAStatus seek(bool directionUp, bool skipSubChannel) override;
-    ndk::ScopedAStatus step(bool directionUp) override;
-    ndk::ScopedAStatus cancel() override;
-    ndk::ScopedAStatus startProgramListUpdates(const ProgramFilter& filter) override;
-    ndk::ScopedAStatus stopProgramListUpdates() override;
-    ndk::ScopedAStatus isConfigFlagSet(ConfigFlag flag, bool* returnIsSet) override;
-    ndk::ScopedAStatus setConfigFlag(ConfigFlag flag, bool in_value) override;
+    ndk::ScopedAStatus setTunerCallback(const std::shared_ptr<ITunerCallback>& callback)
+            EXCLUDES(mMutex) override;
+    ndk::ScopedAStatus unsetTunerCallback() EXCLUDES(mMutex) override;
+    ndk::ScopedAStatus tune(const ProgramSelector& program) EXCLUDES(mMutex) override;
+    ndk::ScopedAStatus seek(bool directionUp, bool skipSubChannel) EXCLUDES(mMutex) override;
+    ndk::ScopedAStatus step(bool directionUp) EXCLUDES(mMutex) override;
+    ndk::ScopedAStatus cancel() EXCLUDES(mMutex) override;
+    ndk::ScopedAStatus startProgramListUpdates(const ProgramFilter& filter)
+            EXCLUDES(mMutex) override;
+    ndk::ScopedAStatus stopProgramListUpdates() EXCLUDES(mMutex) override;
+    ndk::ScopedAStatus isConfigFlagSet(ConfigFlag flag, bool* returnIsSet)
+            EXCLUDES(mMutex) override;
+    ndk::ScopedAStatus setConfigFlag(ConfigFlag flag, bool in_value) EXCLUDES(mMutex) override;
     ndk::ScopedAStatus setParameters(const std::vector<VendorKeyValue>& parameters,
                                      std::vector<VendorKeyValue>* returnParameters) override;
     ndk::ScopedAStatus getParameters(const std::vector<std::string>& keys,
@@ -62,22 +66,39 @@
             const std::shared_ptr<IAnnouncementListener>& listener,
             const std::vector<AnnouncementType>& enabled,
             std::shared_ptr<ICloseHandle>* returnCloseHandle) override;
-    binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
+    binder_status_t dump(int fd, const char** args, uint32_t numArgs) EXCLUDES(mMutex) override;
 
   private:
     const VirtualRadio& mVirtualRadio;
     std::mutex mMutex;
     AmFmRegionConfig mAmFmConfig GUARDED_BY(mMutex);
-    std::unique_ptr<::android::WorkerThread> mThread GUARDED_BY(mMutex) =
+    std::unique_ptr<::android::WorkerThread> mTuningThread GUARDED_BY(mMutex) =
+            std::unique_ptr<::android::WorkerThread>(new ::android::WorkerThread());
+    std::unique_ptr<::android::WorkerThread> mProgramListThread GUARDED_BY(mMutex) =
             std::unique_ptr<::android::WorkerThread>(new ::android::WorkerThread());
     bool mIsTuneCompleted GUARDED_BY(mMutex) = true;
     Properties mProperties GUARDED_BY(mMutex);
     ProgramSelector mCurrentProgram GUARDED_BY(mMutex) = {};
+    std::vector<VirtualProgram> mProgramList GUARDED_BY(mMutex) = {};
+    std::optional<AmFmBandRange> mCurrentAmFmBandRange GUARDED_BY(mMutex);
     std::shared_ptr<ITunerCallback> mCallback GUARDED_BY(mMutex);
 
-    std::optional<AmFmBandRange> getAmFmRangeLocked() const;
-    void cancelLocked();
-    ProgramInfo tuneInternalLocked(const ProgramSelector& sel);
+    // Bitmap for all ConfigFlag values
+    int mConfigFlagValues GUARDED_BY(mMutex) = 0;
+
+    bool adjustAmFmRangeLocked() REQUIRES(mMutex);
+    void cancelLocked() REQUIRES(mMutex);
+    ProgramInfo tuneInternalLocked(const ProgramSelector& sel) REQUIRES(mMutex);
+    void startProgramListUpdatesLocked(const ProgramFilter& filter) REQUIRES(mMutex);
+    void cancelProgramListUpdateLocked() REQUIRES(mMutex);
+    void handleProgramInfoUpdateRadioCallback(ProgramInfo programInfo,
+                                              const std::shared_ptr<ITunerCallback>& callback)
+            EXCLUDES(mMutex);
+    bool findNextLocked(const ProgramSelector& current, bool directionUp, bool skipSubChannel,
+                        VirtualProgram* nextProgram) const REQUIRES(mMutex);
+    void jumpToFirstSubChannelLocked(std::vector<VirtualProgram>::const_iterator& it) const
+            REQUIRES(mMutex);
+    bool isConfigFlagSetLocked(ConfigFlag flag) const REQUIRES(mMutex);
 
     binder_status_t cmdHelp(int fd) const;
     binder_status_t cmdTune(int fd, const char** args, uint32_t numArgs);
@@ -87,7 +108,7 @@
     binder_status_t cmdStartProgramListUpdates(int fd, const char** args, uint32_t numArgs);
     binder_status_t cmdStopProgramListUpdates(int fd, uint32_t numArgs);
 
-    binder_status_t dumpsys(int fd);
+    binder_status_t dumpsys(int fd) EXCLUDES(mMutex);
 };
 
 }  // namespace aidl::android::hardware::broadcastradio
diff --git a/broadcastradio/aidl/default/VirtualProgram.cpp b/broadcastradio/aidl/default/VirtualProgram.cpp
index 4fe6567..fab4a49 100644
--- a/broadcastradio/aidl/default/VirtualProgram.cpp
+++ b/broadcastradio/aidl/default/VirtualProgram.cpp
@@ -49,7 +49,12 @@
             break;
         case IdentifierType::HD_STATION_ID_EXT:
             info.logicallyTunedTo = selectId(IdentifierType::HD_STATION_ID_EXT);
-            info.physicallyTunedTo = selectId(IdentifierType::AMFM_FREQUENCY_KHZ);
+            if (utils::hasId(info.selector, IdentifierType::AMFM_FREQUENCY_KHZ)) {
+                info.physicallyTunedTo = selectId(IdentifierType::AMFM_FREQUENCY_KHZ);
+            } else {
+                info.physicallyTunedTo = utils::makeIdentifier(
+                        IdentifierType::AMFM_FREQUENCY_KHZ, utils::getHdFrequency(info.selector));
+            }
             break;
         case IdentifierType::DAB_SID_EXT:
             info.logicallyTunedTo = selectId(IdentifierType::DAB_SID_EXT);
@@ -88,13 +93,7 @@
 }
 
 bool operator<(const VirtualProgram& lhs, const VirtualProgram& rhs) {
-    auto& l = lhs.selector;
-    auto& r = rhs.selector;
-
-    // Two programs with the same primaryId are considered the same.
-    if (l.primaryId.type != r.primaryId.type) return l.primaryId.type < r.primaryId.type;
-
-    return l.primaryId.value < r.primaryId.value;
+    return utils::ProgramSelectorComparator()(lhs.selector, rhs.selector);
 }
 
 }  // namespace aidl::android::hardware::broadcastradio
diff --git a/broadcastradio/aidl/default/VirtualRadio.cpp b/broadcastradio/aidl/default/VirtualRadio.cpp
index 86c5a96..d6e58cd 100644
--- a/broadcastradio/aidl/default/VirtualRadio.cpp
+++ b/broadcastradio/aidl/default/VirtualRadio.cpp
@@ -16,12 +16,15 @@
 
 #include "VirtualRadio.h"
 #include <broadcastradio-utils-aidl/Utils.h>
+#include <unordered_set>
 
 namespace aidl::android::hardware::broadcastradio {
 
 using ::aidl::android::hardware::broadcastradio::utils::makeSelectorAmfm;
 using ::aidl::android::hardware::broadcastradio::utils::makeSelectorDab;
+using ::aidl::android::hardware::broadcastradio::utils::makeSelectorHd;
 using ::std::string;
+using ::std::unordered_set;
 using ::std::vector;
 
 VirtualRadio::VirtualRadio(const string& name, const vector<VirtualProgram>& initialList)
@@ -38,15 +41,43 @@
 }
 
 bool VirtualRadio::getProgram(const ProgramSelector& selector, VirtualProgram* programOut) const {
-    for (const auto& program : mPrograms) {
-        if (utils::tunesTo(selector, program.selector)) {
-            *programOut = program;
-            return true;
+    for (auto it = mPrograms.begin(); it != mPrograms.end(); it++) {
+        if (!utils::tunesTo(selector, it->selector)) {
+            continue;
         }
+        auto firstMatchIt = it;
+        if (utils::hasAmFmFrequency(it->selector)) {
+            uint32_t channelFreq = utils::getAmFmFrequency(it->selector);
+            it++;
+            while (it != mPrograms.end() && utils::hasAmFmFrequency(it->selector) &&
+                   utils::getAmFmFrequency(it->selector) == channelFreq) {
+                if (it->selector == selector) {
+                    *programOut = *it;
+                    return true;
+                }
+                it++;
+            }
+        }
+        *programOut = *firstMatchIt;
+        return true;
     }
     return false;
 }
 
+vector<IdentifierType> VirtualRadio::getSupportedIdentifierTypes() const {
+    unordered_set<IdentifierType> supportedIdentifierTypeSet;
+    for (const auto& program : mPrograms) {
+        IdentifierType type = program.selector.primaryId.type;
+        if (supportedIdentifierTypeSet.count(type)) {
+            continue;
+        }
+        supportedIdentifierTypeSet.insert(type);
+    }
+    vector<IdentifierType> supportedIdentifierTypes(supportedIdentifierTypeSet.begin(),
+                                                    supportedIdentifierTypeSet.end());
+    return supportedIdentifierTypes;
+}
+
 // get singleton of AMFM Virtual Radio
 const VirtualRadio& VirtualRadio::getAmFmRadio() {
     // clang-format off
@@ -56,15 +87,27 @@
             {makeSelectorAmfm(/* frequency= */ 94900u), "Wild 94.9", "Drake ft. Rihanna",
                 "Too Good"},
             {makeSelectorAmfm(/* frequency= */ 96500u), "KOIT", "Celine Dion", "All By Myself"},
-            {makeSelectorAmfm(/* frequency= */ 97300u), "Alice@97.3", "Drops of Jupiter", "Train"},
-            {makeSelectorAmfm(/* frequency= */ 99700u), "99.7 Now!", "The Chainsmokers", "Closer"},
             {makeSelectorAmfm(/* frequency= */ 101300u), "101-3 KISS-FM", "Justin Timberlake",
                 "Rock Your Body"},
             {makeSelectorAmfm(/* frequency= */ 103700u), "iHeart80s @ 103.7", "Michael Jackson",
                 "Billie Jean"},
             {makeSelectorAmfm(/* frequency= */ 106100u), "106 KMEL", "Drake", "Marvins Room"},
-            {makeSelectorAmfm(/* frequency= */ 700u), "700 AM", "Artist700", "Title700"},
-            {makeSelectorAmfm(/* frequency= */ 1700u), "1700 AM", "Artist1700", "Title1700"},
+            {makeSelectorAmfm(/* frequency= */ 560u), "Talk Radio 560 KSFO", "Artist560", "Title560"},
+            {makeSelectorAmfm(/* frequency= */ 680u), "KNBR 680", "Artist680", "Title680"},
+            {makeSelectorAmfm(/* frequency= */ 97300u), "Alice@97.3", "Drops of Jupiter", "Train"},
+            {makeSelectorAmfm(/* frequency= */ 99700u), "99.7 Now!", "The Chainsmokers", "Closer"},
+            {makeSelectorHd(/* stationId= */ 0xA0000001u, /* subChannel= */ 0u, /* frequency= */ 97700u),
+                "K-LOVE", "ArtistHd0", "TitleHd0"},
+            {makeSelectorHd(/* stationId= */ 0xA0000001u, /* subChannel= */ 1u, /* frequency= */ 97700u),
+                "Air1", "ArtistHd1", "TitleHd1"},
+            {makeSelectorHd(/* stationId= */ 0xA0000001u, /* subChannel= */ 2u, /* frequency= */ 97700u),
+                "K-LOVE Classics", "ArtistHd2", "TitleHd2"},
+            {makeSelectorHd(/* stationId= */ 0xA0000001u, /* subChannel= */ 0u, /* frequency= */ 98500u),
+                "98.5-1 South Bay's Classic Rock", "ArtistHd0", "TitleHd0"},
+            {makeSelectorHd(/* stationId= */ 0xA0000001u, /* subChannel= */ 1u, /* frequency= */ 98500u),
+                "Highway 1 - Different", "ArtistHd1", "TitleHd1"},
+            {makeSelectorHd(/* stationId= */ 0xB0000001u, /* subChannel= */ 0u, /* frequency= */ 1170u),
+                "KLOK", "ArtistHd1", "TitleHd1"},
         });
     // clang-format on
     return amFmRadioMock;
@@ -76,14 +119,24 @@
     static VirtualRadio dabRadioMock(
         "DAB radio mock",
         {
-            {makeSelectorDab(/* sidExt= */ 0xA000000001u, /* ensemble= */ 0x0001u,
+            {makeSelectorDab(/* sidExt= */ 0x0E10000C221u, /* ensemble= */ 0xCE15u,
                 /* freq= */ 225648u), "BBC Radio 1", "Khalid", "Talk"},
-            {makeSelectorDab(/* sidExt= */ 0xB000000001u, /* ensemble= */ 0x1001u,
+            {makeSelectorDab(/* sidExt= */ 0x0E10000C222u, /* ensemble= */ 0xCE15u,
+                    /* freq= */ 225648u), "BBC Radio 2", "Khalid", "Talk"},
+            {makeSelectorDab(/* sidExt= */ 0xE10000C224u, /* ensemble= */ 0xCE15u,
+                    /* freq= */ 225648u), "BBC Radio 4", "ArtistBBC1", "TitleCountry1"},
+            {makeSelectorDab(/* sidExt= */ 0x1E10000C224u, /* ensemble= */ 0xCE15u,
+                    /* freq= */ 225648u), "BBC Radio 4 LW", "ArtistBBC2", "TitleCountry2"},
+            {makeSelectorDab(/* sidExt= */ 0x0E10000C21Au, /* ensemble= */ 0xC181u,
                 /* freq= */ 222064u), "Classic FM", "Jean Sibelius", "Andante Festivo"},
-            {makeSelectorDab(/* sidExt= */ 0xB000000002u, /* ensemble= */ 0x1002u,
-                /* freq= */ 227360u), "Absolute Radio", "Coldplay", "Clocks"},
-            {makeSelectorDab(/* sidExt= */ 0xB000000002u, /* ensemble= */ 0x1002u,
+            {makeSelectorDab(/* sidExt= */ 0x0E10000C1C0u, /* ensemble= */ 0xC181u,
+                /* freq= */ 223936u), "Absolute Radio", "Coldplay", "Clocks"},
+            {makeSelectorDab(/* sidExt= */ 0x0E10000C1C0u, /* ensemble= */ 0xC181u,
                 /* freq= */ 222064u), "Absolute Radio", "Coldplay", "Clocks"},
+            {makeSelectorDab(/* sidExt= */ 0x0E10000CCE7u, /* ensemble= */ 0xC19Du,
+                    /* freq= */ 218640u), "Absolute Radio Country", "ArtistCountry1", "TitleCountry1"},
+            {makeSelectorDab(/* sidExt= */ 0x0E10000CCE7u, /* ensemble= */ 0xC1A0u,
+                    /* freq= */ 218640u), "Absolute Radio Country", "ArtistCountry2", "TitleCountry2"},
         });
     // clang-format on
     return dabRadioMock;
diff --git a/broadcastradio/aidl/default/VirtualRadio.h b/broadcastradio/aidl/default/VirtualRadio.h
index ae039c4..0d70aef 100644
--- a/broadcastradio/aidl/default/VirtualRadio.h
+++ b/broadcastradio/aidl/default/VirtualRadio.h
@@ -36,6 +36,7 @@
     std::string getName() const;
     const std::vector<VirtualProgram>& getProgramList() const;
     bool getProgram(const ProgramSelector& selector, VirtualProgram* program) const;
+    std::vector<IdentifierType> getSupportedIdentifierTypes() const;
 
     static const VirtualRadio& getAmFmRadio();
     static const VirtualRadio& getDabRadio();
diff --git a/broadcastradio/aidl/default/broadcastradio-default.xml b/broadcastradio/aidl/default/broadcastradio-default.xml
index 1555822..a57b724 100644
--- a/broadcastradio/aidl/default/broadcastradio-default.xml
+++ b/broadcastradio/aidl/default/broadcastradio-default.xml
@@ -1,6 +1,7 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.broadcastradio</name>
+        <version>2</version>
         <fqname>IBroadcastRadio/amfm</fqname>
         <fqname>IBroadcastRadio/dab</fqname>
     </hal>
diff --git a/broadcastradio/aidl/default/fuzzer.cpp b/broadcastradio/aidl/default/fuzzer.cpp
new file mode 100644
index 0000000..d535432
--- /dev/null
+++ b/broadcastradio/aidl/default/fuzzer.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fuzzbinder/libbinder_ndk_driver.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include "BroadcastRadio.h"
+#include "VirtualRadio.h"
+
+using ::aidl::android::hardware::broadcastradio::BroadcastRadio;
+using ::aidl::android::hardware::broadcastradio::VirtualRadio;
+using ::android::fuzzService;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    const VirtualRadio& amFmRadioMock = VirtualRadio::getAmFmRadio();
+    std::shared_ptr<BroadcastRadio> amFmRadio =
+            ::ndk::SharedRefBase::make<BroadcastRadio>(amFmRadioMock);
+    const VirtualRadio& dabRadioMock = VirtualRadio::getDabRadio();
+    std::shared_ptr<BroadcastRadio> dabRadio =
+            ::ndk::SharedRefBase::make<BroadcastRadio>(dabRadioMock);
+
+    std::vector<ndk::SpAIBinder> binder_services = {amFmRadio->asBinder(), dabRadio->asBinder()};
+
+    fuzzService(binder_services, FuzzedDataProvider(data, size));
+
+    return 0;
+}
diff --git a/broadcastradio/aidl/default/test/Android.bp b/broadcastradio/aidl/default/test/Android.bp
new file mode 100644
index 0000000..9e1b89d
--- /dev/null
+++ b/broadcastradio/aidl/default/test/Android.bp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_test {
+    name: "DefaultBroadcastRadioHalTestCase",
+    vendor: true,
+    srcs: ["*.cpp"],
+    static_libs: [
+        "DefaultBroadcastRadioHal",
+        "libgtest",
+        "libgmock",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "liblog",
+        "libutils",
+    ],
+    header_libs: [
+        "IVehicleHardware",
+    ],
+    defaults: [
+        "BroadcastRadioHalDefaults",
+    ],
+    test_suites: ["device-tests"],
+}
diff --git a/broadcastradio/aidl/default/test/DefaultBroadcastRadioHalTest.cpp b/broadcastradio/aidl/default/test/DefaultBroadcastRadioHalTest.cpp
new file mode 100644
index 0000000..f0cc9a2
--- /dev/null
+++ b/broadcastradio/aidl/default/test/DefaultBroadcastRadioHalTest.cpp
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "MockBroadcastRadioCallback.h"
+
+#include <BroadcastRadio.h>
+#include <VirtualRadio.h>
+#include <broadcastradio-utils-aidl/Utils.h>
+
+#include <android-base/logging.h>
+#include <gtest/gtest.h>
+
+namespace aidl::android::hardware::broadcastradio {
+
+namespace {
+using ::std::vector;
+
+constexpr uint32_t kAmFreq1 = 560u;
+constexpr uint32_t kAmFreq2 = 680u;
+constexpr uint32_t kAmHdFreq = 1170u;
+constexpr uint64_t kAmHdSid = 0xB0000001u;
+constexpr uint32_t kFmFreq1 = 94900u;
+constexpr uint64_t kFmHdSid1 = 0xA0000001u;
+constexpr uint64_t kFmHdSid2 = 0xA0000002u;
+constexpr uint32_t kFmHdFreq1 = 98500u;
+constexpr uint32_t kFmHdSubChannel0 = 0u;
+constexpr uint32_t kFmHdSubChannel1 = 1u;
+constexpr uint32_t kFmFreq2 = 99100u;
+constexpr uint32_t kFmHdFreq2 = 101100u;
+
+const ProgramSelector kAmSel1 = utils::makeSelectorAmfm(kAmFreq1);
+const ProgramSelector kAmSel2 = utils::makeSelectorAmfm(kAmFreq2);
+const ProgramSelector kAmHdSel = utils::makeSelectorHd(kAmHdSid, kFmHdSubChannel0, kAmHdFreq);
+const ProgramSelector kFmSel1 = utils::makeSelectorAmfm(kFmFreq1);
+const ProgramSelector kFmSel2 = utils::makeSelectorAmfm(kFmFreq2);
+const ProgramSelector kFmHdFreq1Sel1 =
+        utils::makeSelectorHd(kFmHdSid1, kFmHdSubChannel0, kFmHdFreq1);
+const ProgramSelector kFmHdFreq1Sel2 =
+        utils::makeSelectorHd(kFmHdSid1, kFmHdSubChannel1, kFmHdFreq1);
+const ProgramSelector kFmHdFreq2Sel1 =
+        utils::makeSelectorHd(kFmHdSid2, kFmHdSubChannel0, kFmHdFreq2);
+const ProgramSelector kFmHdFreq2Sel2 =
+        utils::makeSelectorHd(kFmHdSid2, kFmHdSubChannel1, kFmHdFreq2);
+
+const VirtualRadio& getAmFmMockTestRadio() {
+    static VirtualRadio amFmRadioMockTestRadio(
+            "AM/FM radio mock for test",
+            {
+                    {kAmSel1, "ProgramAm1", "ArtistAm1", "TitleAm1"},
+                    {kAmSel2, "ProgramAm2", "ArtistAm2", "TitleAm2"},
+                    {kFmSel1, "ProgramFm1", "ArtistFm1", "TitleFm1"},
+                    {kFmSel2, "ProgramFm2", "ArtistFm2", "TitleFm2"},
+                    {kAmHdSel, "ProgramAmHd1", "ArtistAmHd1", "TitleAmHd1"},
+                    {kFmHdFreq1Sel1, "ProgramFmHd1", "ArtistFmHd1", "TitleFmHd1"},
+                    {kFmHdFreq1Sel2, "ProgramFmHd2", "ArtistFmHd2", "TitleFmHd2"},
+                    {kFmHdFreq2Sel1, "ProgramFmHd3", "ArtistFmHd3", "TitleFmHd3"},
+                    {kFmHdFreq2Sel2, "ProgramFmHd4", "ArtistFmHd4", "TitleFmHd4"},
+            });
+    return amFmRadioMockTestRadio;
+}
+
+}  // namespace
+
+class DefaultBroadcastRadioHalTest : public testing::Test {
+  public:
+    void SetUp() override {
+        ::android::base::SetDefaultTag("BcRadioAidlDef.test");
+        const VirtualRadio& amFmRadioMockTest = getAmFmMockTestRadio();
+        mBroadcastRadioHal = ::ndk::SharedRefBase::make<BroadcastRadio>(amFmRadioMockTest);
+        mTunerCallback = ndk::SharedRefBase::make<MockBroadcastRadioCallback>();
+    }
+
+    void TearDown() override {
+        mBroadcastRadioHal->unsetTunerCallback();
+        EXPECT_FALSE(mTunerCallback->isTunerFailed());
+    }
+
+    std::shared_ptr<BroadcastRadio> mBroadcastRadioHal;
+    std::shared_ptr<MockBroadcastRadioCallback> mTunerCallback;
+};
+
+TEST_F(DefaultBroadcastRadioHalTest, GetAmFmRegionConfig) {
+    AmFmRegionConfig config;
+
+    auto halResult = mBroadcastRadioHal->getAmFmRegionConfig(/* full= */ false, &config);
+
+    ASSERT_TRUE(halResult.isOk());
+    EXPECT_EQ(config.fmDeemphasis, AmFmRegionConfig::DEEMPHASIS_D50);
+    EXPECT_EQ(config.fmRds, AmFmRegionConfig::RDS);
+}
+
+TEST_F(DefaultBroadcastRadioHalTest, GetAmFmRegionConfigWithFullBand) {
+    AmFmRegionConfig config;
+
+    auto halResult = mBroadcastRadioHal->getAmFmRegionConfig(/* full= */ true, &config);
+
+    ASSERT_TRUE(halResult.isOk());
+    EXPECT_EQ(config.fmDeemphasis,
+              AmFmRegionConfig::DEEMPHASIS_D50 | AmFmRegionConfig::DEEMPHASIS_D75);
+    EXPECT_EQ(config.fmRds, AmFmRegionConfig::RDS | AmFmRegionConfig::RBDS);
+}
+
+TEST_F(DefaultBroadcastRadioHalTest, GetDabRegionConfig) {
+    vector<DabTableEntry> config;
+
+    auto halResult = mBroadcastRadioHal->getDabRegionConfig(&config);
+
+    ASSERT_TRUE(halResult.isOk());
+    ASSERT_FALSE(config.empty());
+}
+
+TEST_F(DefaultBroadcastRadioHalTest, GetImage) {
+    vector<uint8_t> img;
+
+    auto halResult = mBroadcastRadioHal->getImage(BroadcastRadio::INVALID_IMAGE, &img);
+
+    ASSERT_TRUE(halResult.isOk());
+    ASSERT_TRUE(img.empty());
+}
+
+TEST_F(DefaultBroadcastRadioHalTest, GetProperties) {
+    vector<VirtualProgram> mockPrograms = getAmFmMockTestRadio().getProgramList();
+    Properties prop;
+
+    auto halResult = mBroadcastRadioHal->getProperties(&prop);
+
+    ASSERT_TRUE(halResult.isOk());
+    ASSERT_FALSE(prop.supportedIdentifierTypes.empty());
+    std::unordered_set<IdentifierType> supportedTypeSet;
+    for (const auto& supportedType : prop.supportedIdentifierTypes) {
+        supportedTypeSet.insert(supportedType);
+    }
+    for (const auto& program : mockPrograms) {
+        EXPECT_NE(supportedTypeSet.find(program.selector.primaryId.type), supportedTypeSet.end());
+    }
+}
+
+TEST_F(DefaultBroadcastRadioHalTest, SetTunerCallback) {
+    auto halResult = mBroadcastRadioHal->setTunerCallback(mTunerCallback);
+
+    ASSERT_TRUE(halResult.isOk());
+}
+
+TEST_F(DefaultBroadcastRadioHalTest, SetTunerCallbackWithNull) {
+    auto halResult = mBroadcastRadioHal->setTunerCallback(nullptr);
+
+    ASSERT_EQ(halResult.getServiceSpecificError(), utils::resultToInt(Result::INVALID_ARGUMENTS));
+}
+
+TEST_F(DefaultBroadcastRadioHalTest, UnsetTunerCallbackWithNull) {
+    ASSERT_TRUE(mBroadcastRadioHal->setTunerCallback(mTunerCallback).isOk());
+
+    auto halResult = mBroadcastRadioHal->unsetTunerCallback();
+
+    ASSERT_TRUE(halResult.isOk());
+}
+
+}  // namespace aidl::android::hardware::broadcastradio
diff --git a/broadcastradio/aidl/default/test/MockBroadcastRadioCallback.cpp b/broadcastradio/aidl/default/test/MockBroadcastRadioCallback.cpp
new file mode 100644
index 0000000..48f65fc
--- /dev/null
+++ b/broadcastradio/aidl/default/test/MockBroadcastRadioCallback.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "MockBroadcastRadioCallback.h"
+
+#include <android-base/logging.h>
+
+namespace aidl::android::hardware::broadcastradio {
+
+namespace {
+using std::vector;
+}
+
+MockBroadcastRadioCallback::MockBroadcastRadioCallback() {
+    mAntennaConnectionState = true;
+}
+
+ScopedAStatus MockBroadcastRadioCallback::onTuneFailed(Result result,
+                                                       const ProgramSelector& selector) {
+    LOG(DEBUG) << "onTuneFailed with result with " << selector.toString().c_str();
+    if (result != Result::CANCELED) {
+        std::lock_guard<std::mutex> lk(mLock);
+        tunerFailed = true;
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+ScopedAStatus MockBroadcastRadioCallback::onCurrentProgramInfoChanged(const ProgramInfo& info) {
+    LOG(DEBUG) << "onCurrentProgramInfoChanged with " << info.toString().c_str();
+    {
+        std::lock_guard<std::mutex> lk(mLock);
+        mCurrentProgramInfo = info;
+    }
+
+    mOnCurrentProgramInfoChangedFlag.notify();
+    return ndk::ScopedAStatus::ok();
+}
+
+ScopedAStatus MockBroadcastRadioCallback::onProgramListUpdated(
+        [[maybe_unused]] const ProgramListChunk& chunk) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ScopedAStatus MockBroadcastRadioCallback::onParametersUpdated(
+        [[maybe_unused]] const vector<VendorKeyValue>& parameters) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ScopedAStatus MockBroadcastRadioCallback::onAntennaStateChange(bool connected) {
+    if (!connected) {
+        std::lock_guard<std::mutex> lk(mLock);
+        mAntennaConnectionState = false;
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+ScopedAStatus MockBroadcastRadioCallback::onConfigFlagUpdated([[maybe_unused]] ConfigFlag in_flag,
+                                                              [[maybe_unused]] bool in_value) {
+    return ndk::ScopedAStatus::ok();
+}
+
+bool MockBroadcastRadioCallback::waitOnCurrentProgramInfoChangedCallback() {
+    return mOnCurrentProgramInfoChangedFlag.wait();
+}
+
+void MockBroadcastRadioCallback::reset() {
+    mOnCurrentProgramInfoChangedFlag.reset();
+}
+
+bool MockBroadcastRadioCallback::isTunerFailed() {
+    std::lock_guard<std::mutex> lk(mLock);
+    return tunerFailed;
+}
+
+ProgramInfo MockBroadcastRadioCallback::getCurrentProgramInfo() {
+    std::lock_guard<std::mutex> lk(mLock);
+    return mCurrentProgramInfo;
+}
+
+}  // namespace aidl::android::hardware::broadcastradio
diff --git a/broadcastradio/aidl/default/test/MockBroadcastRadioCallback.h b/broadcastradio/aidl/default/test/MockBroadcastRadioCallback.h
new file mode 100644
index 0000000..2ae03e3
--- /dev/null
+++ b/broadcastradio/aidl/default/test/MockBroadcastRadioCallback.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/broadcastradio/BnTunerCallback.h>
+#include <aidl/android/hardware/broadcastradio/ConfigFlag.h>
+#include <aidl/android/hardware/broadcastradio/IBroadcastRadio.h>
+#include <aidl/android/hardware/broadcastradio/ProgramInfo.h>
+#include <aidl/android/hardware/broadcastradio/ProgramListChunk.h>
+#include <aidl/android/hardware/broadcastradio/ProgramSelector.h>
+#include <aidl/android/hardware/broadcastradio/Result.h>
+#include <aidl/android/hardware/broadcastradio/VendorKeyValue.h>
+
+#include <android-base/thread_annotations.h>
+
+#include <broadcastradio-utils-aidl/Utils.h>
+
+#include <condition_variable>
+
+namespace aidl::android::hardware::broadcastradio {
+
+namespace {
+using ::ndk::ScopedAStatus;
+
+}  // namespace
+
+class MockBroadcastRadioCallback final : public BnTunerCallback {
+  public:
+    explicit MockBroadcastRadioCallback();
+    ScopedAStatus onTuneFailed(Result result, const ProgramSelector& selector) override;
+    ScopedAStatus onCurrentProgramInfoChanged(const ProgramInfo& info) override;
+    ScopedAStatus onProgramListUpdated(const ProgramListChunk& chunk) override;
+    ScopedAStatus onParametersUpdated(const std::vector<VendorKeyValue>& parameters) override;
+    ScopedAStatus onAntennaStateChange(bool connected) override;
+    ScopedAStatus onConfigFlagUpdated(ConfigFlag in_flag, bool in_value) override;
+
+    bool waitOnCurrentProgramInfoChangedCallback();
+    bool isTunerFailed();
+    void reset();
+
+    ProgramInfo getCurrentProgramInfo();
+
+  private:
+    class CallbackFlag final {
+      public:
+        CallbackFlag(int timeoutMs) { mTimeoutMs = timeoutMs; }
+        /**
+         * Notify that the callback is called.
+         */
+        void notify() {
+            std::unique_lock<std::mutex> lock(mMutex);
+            mCalled = true;
+            lock.unlock();
+            mCv.notify_all();
+        };
+
+        /**
+         * Wait for the timeout passed into the constructor.
+         */
+        bool wait() {
+            std::unique_lock<std::mutex> lock(mMutex);
+            return mCv.wait_for(lock, std::chrono::milliseconds(mTimeoutMs),
+                                [this] { return mCalled; });
+        };
+
+        /**
+         * Reset the callback to not called.
+         */
+        void reset() {
+            std::unique_lock<std::mutex> lock(mMutex);
+            mCalled = false;
+        }
+
+      private:
+        std::mutex mMutex;
+        bool mCalled GUARDED_BY(mMutex) = false;
+        std::condition_variable mCv;
+        int mTimeoutMs;
+    };
+
+    std::mutex mLock;
+    bool mAntennaConnectionState GUARDED_BY(mLock);
+    bool tunerFailed GUARDED_BY(mLock) = false;
+    ProgramInfo mCurrentProgramInfo GUARDED_BY(mLock);
+    utils::ProgramInfoSet mProgramList GUARDED_BY(mLock);
+    CallbackFlag mOnCurrentProgramInfoChangedFlag = CallbackFlag(IBroadcastRadio::TUNER_TIMEOUT_MS);
+};
+
+}  // namespace aidl::android::hardware::broadcastradio
diff --git a/broadcastradio/aidl/vts/Android.bp b/broadcastradio/aidl/vts/Android.bp
index b60387e..87e48a9 100644
--- a/broadcastradio/aidl/vts/Android.bp
+++ b/broadcastradio/aidl/vts/Android.bp
@@ -35,8 +35,8 @@
         "libxml2",
     ],
     static_libs: [
-        "android.hardware.broadcastradio-V1-ndk",
-        "android.hardware.broadcastradio@common-utils-aidl-lib",
+        "android.hardware.broadcastradio-V2-ndk",
+        "android.hardware.broadcastradio@common-utils-aidl-lib-V2",
         "android.hardware.broadcastradio@vts-utils-lib",
         "libgmock",
     ],
diff --git a/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp b/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp
index 790d60b..9633ebb 100644
--- a/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp
+++ b/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp
@@ -32,8 +32,10 @@
 #include <aidl/Gtest.h>
 #include <aidl/Vintf.h>
 #include <broadcastradio-utils-aidl/Utils.h>
+#include <broadcastradio-utils-aidl/UtilsV2.h>
 #include <cutils/bitops.h>
 #include <gmock/gmock.h>
+#include <gtest/gtest.h>
 
 #include <chrono>
 #include <condition_variable>
@@ -50,7 +52,6 @@
 using ::aidl::android::hardware::broadcastradio::utils::resultToInt;
 using ::ndk::ScopedAStatus;
 using ::ndk::SharedRefBase;
-using ::std::string;
 using ::std::vector;
 using ::testing::_;
 using ::testing::AnyNumber;
@@ -73,20 +74,23 @@
         ConfigFlag::DAB_FM_SOFT_LINKING,
 };
 
-void printSkipped(const string& msg) {
-    const auto testInfo = testing::UnitTest::GetInstance()->current_test_info();
-    LOG(INFO) << "[  SKIPPED ] " << testInfo->test_case_name() << "." << testInfo->name()
-              << " with message: " << msg;
-}
+constexpr int32_t kAidlVersion1 = 1;
+constexpr int32_t kAidlVersion2 = 2;
 
-bool isValidAmFmFreq(int64_t freq) {
+bool isValidAmFmFreq(int64_t freq, int aidlVersion) {
     ProgramIdentifier id = bcutils::makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, freq);
-    return bcutils::isValid(id);
+    if (aidlVersion == kAidlVersion1) {
+        return bcutils::isValid(id);
+    } else if (aidlVersion == kAidlVersion2) {
+        return bcutils::isValidV2(id);
+    }
+    LOG(ERROR) << "Unknown AIDL version " << aidlVersion;
+    return false;
 }
 
-void validateRange(const AmFmBandRange& range) {
-    EXPECT_TRUE(isValidAmFmFreq(range.lowerBound));
-    EXPECT_TRUE(isValidAmFmFreq(range.upperBound));
+void validateRange(const AmFmBandRange& range, int aidlVersion) {
+    EXPECT_TRUE(isValidAmFmFreq(range.lowerBound, aidlVersion));
+    EXPECT_TRUE(isValidAmFmFreq(range.upperBound, aidlVersion));
     EXPECT_LT(range.lowerBound, range.upperBound);
     EXPECT_GT(range.spacing, 0u);
     EXPECT_EQ((range.upperBound - range.lowerBound) % range.spacing, 0u);
@@ -142,7 +146,7 @@
 
 class TunerCallbackImpl final : public BnTunerCallback {
   public:
-    TunerCallbackImpl();
+    explicit TunerCallbackImpl(int32_t aidlVersion);
     ScopedAStatus onTuneFailed(Result result, const ProgramSelector& selector) override;
     ScopedAStatus onCurrentProgramInfoChanged(const ProgramInfo& info) override;
     ScopedAStatus onProgramListUpdated(const ProgramListChunk& chunk) override;
@@ -160,6 +164,7 @@
 
   private:
     std::mutex mLock;
+    int32_t mCallbackAidlVersion;
     bool mAntennaConnectionState GUARDED_BY(mLock);
     ProgramInfo mCurrentProgramInfo GUARDED_BY(mLock);
     bcutils::ProgramInfoSet mProgramList GUARDED_BY(mLock);
@@ -171,7 +176,7 @@
     MOCK_METHOD1(onListUpdated, ScopedAStatus(const vector<Announcement>&));
 };
 
-class BroadcastRadioHalTest : public testing::TestWithParam<string> {
+class BroadcastRadioHalTest : public testing::TestWithParam<std::string> {
   protected:
     void SetUp() override;
     void TearDown() override;
@@ -183,14 +188,17 @@
     std::shared_ptr<IBroadcastRadio> mModule;
     Properties mProperties;
     std::shared_ptr<TunerCallbackImpl> mCallback;
+    int32_t mAidlVersion;
 };
 
-MATCHER_P(InfoHasId, id, string(negation ? "does not contain" : "contains") + " " + id.toString()) {
+MATCHER_P(InfoHasId, id,
+          std::string(negation ? "does not contain" : "contains") + " " + id.toString()) {
     vector<int> ids = bcutils::getAllIds(arg.selector, id.type);
     return ids.end() != find(ids.begin(), ids.end(), id.value);
 }
 
-TunerCallbackImpl::TunerCallbackImpl() {
+TunerCallbackImpl::TunerCallbackImpl(int32_t aidlVersion) {
+    mCallbackAidlVersion = aidlVersion;
     mAntennaConnectionState = true;
 }
 
@@ -230,13 +238,28 @@
                 physically > IdentifierType::SXM_CHANNEL);
 
     if (logically == IdentifierType::AMFM_FREQUENCY_KHZ) {
-        std::optional<string> ps = bcutils::getMetadataString(info, Metadata::rdsPs);
+        std::optional<std::string> ps;
+        if (mCallbackAidlVersion == kAidlVersion1) {
+            ps = bcutils::getMetadataString(info, Metadata::rdsPs);
+        } else {
+            ps = bcutils::getMetadataStringV2(info, Metadata::rdsPs);
+        }
         if (ps.has_value()) {
             EXPECT_NE(::android::base::Trim(*ps), "")
                     << "Don't use empty RDS_PS as an indicator of missing RSD PS data.";
         }
     }
 
+    for (const auto& metadataItem : info.metadata) {
+        bool validMetadata = false;
+        if (mCallbackAidlVersion == kAidlVersion1) {
+            validMetadata = bcutils::isValidMetadata(metadataItem);
+        } else {
+            validMetadata = bcutils::isValidMetadataV2(metadataItem);
+        }
+        EXPECT_TRUE(validMetadata) << "Invalid metadata " << metadataItem.toString().c_str();
+    }
+
     {
         std::lock_guard<std::mutex> lk(mLock);
         mCurrentProgramInfo = info;
@@ -323,9 +346,13 @@
     EXPECT_FALSE(mProperties.product.empty());
     EXPECT_GT(mProperties.supportedIdentifierTypes.size(), 0u);
 
-    mCallback = SharedRefBase::make<TunerCallbackImpl>();
+    // get AIDL HAL version
+    ASSERT_TRUE(mModule->getInterfaceVersion(&mAidlVersion).isOk());
+    EXPECT_GE(mAidlVersion, kAidlVersion1);
+    EXPECT_LE(mAidlVersion, kAidlVersion2);
 
     // set callback
+    mCallback = SharedRefBase::make<TunerCallbackImpl>(mAidlVersion);
     EXPECT_TRUE(mModule->setTunerCallback(mCallback).isOk());
 }
 
@@ -363,7 +390,7 @@
     auto startResult = mModule->startProgramListUpdates(filter);
 
     if (startResult.getServiceSpecificError() == resultToInt(Result::NOT_SUPPORTED)) {
-        printSkipped("Program list not supported");
+        LOG(WARNING) << "Program list not supported";
         return std::nullopt;
     }
     EXPECT_TRUE(startResult.isOk());
@@ -408,8 +435,7 @@
     bool supported = getAmFmRegionConfig(/* full= */ false, &config);
 
     if (!supported) {
-        printSkipped("AM/FM not supported");
-        return;
+        GTEST_SKIP() << "AM/FM not supported";
     }
 
     EXPECT_LE(popcountll(static_cast<unsigned long long>(config.fmDeemphasis)), 1);
@@ -437,13 +463,12 @@
     bool supported = getAmFmRegionConfig(/* full= */ false, &config);
 
     if (!supported) {
-        printSkipped("AM/FM not supported");
-        return;
+        GTEST_SKIP() << "AM/FM not supported";
     }
 
     EXPECT_GT(config.ranges.size(), 0u);
     for (const auto& range : config.ranges) {
-        validateRange(range);
+        validateRange(range, mAidlVersion);
         EXPECT_EQ(range.seekSpacing % range.spacing, 0u);
         EXPECT_GE(range.seekSpacing, range.spacing);
     }
@@ -466,7 +491,7 @@
     if (supported && supportsFM(config)) {
         EXPECT_GE(popcountll(static_cast<unsigned long long>(config.fmDeemphasis)), 1);
     } else {
-        printSkipped("FM not supported");
+        GTEST_SKIP() << "FM not supported";
     }
 }
 
@@ -487,14 +512,13 @@
     bool supported = getAmFmRegionConfig(/* full= */ true, &config);
 
     if (!supported) {
-        printSkipped("AM/FM not supported");
-        return;
+        GTEST_SKIP() << "AM/FM not supported";
     }
 
     EXPECT_GT(config.ranges.size(), 0u);
 
     for (const auto& range : config.ranges) {
-        validateRange(range);
+        validateRange(range, mAidlVersion);
         EXPECT_EQ(range.seekSpacing, 0u);
     }
 }
@@ -514,19 +538,24 @@
     auto halResult = mModule->getDabRegionConfig(&config);
 
     if (halResult.getServiceSpecificError() == resultToInt(Result::NOT_SUPPORTED)) {
-        printSkipped("DAB not supported");
-        return;
+        GTEST_SKIP() << "DAB not supported";
     }
     ASSERT_TRUE(halResult.isOk());
 
     std::regex re("^[A-Z0-9][A-Z0-9 ]{0,5}[A-Z0-9]$");
 
     for (const auto& entry : config) {
-        EXPECT_TRUE(std::regex_match(string(entry.label), re));
+        EXPECT_TRUE(std::regex_match(std::string(entry.label), re));
 
         ProgramIdentifier id =
                 bcutils::makeIdentifier(IdentifierType::DAB_FREQUENCY_KHZ, entry.frequencyKhz);
-        EXPECT_TRUE(bcutils::isValid(id));
+        if (mAidlVersion == kAidlVersion1) {
+            EXPECT_TRUE(bcutils::isValid(id));
+        } else if (mAidlVersion == kAidlVersion2) {
+            EXPECT_TRUE(bcutils::isValidV2(id));
+        } else {
+            LOG(ERROR) << "Unknown callback AIDL version " << mAidlVersion;
+        }
     }
 }
 
@@ -643,7 +672,7 @@
  *  - if it is supported, the method succeeds;
  *  - after a successful tune call, onCurrentProgramInfoChanged callback is
  *    invoked carrying a proper selector;
- *  - program changes exactly to what was requested.
+ *  - program changes to a program info with the program selector requested.
  */
 TEST_P(BroadcastRadioHalTest, FmTune) {
     LOG(DEBUG) << "FmTune Test";
@@ -674,6 +703,57 @@
 }
 
 /**
+ * Test tuning with HD selector.
+ *
+ * Verifies that:
+ *  - if AM/FM HD selector is not supported, the method returns NOT_SUPPORTED;
+ *  - if it is supported, the method succeeds;
+ *  - after a successful tune call, onCurrentProgramInfoChanged callback is
+ *    invoked carrying a proper selector;
+ *  - program changes to a program info with the program selector requested.
+ */
+TEST_P(BroadcastRadioHalTest, HdTune) {
+    LOG(DEBUG) << "HdTune Test";
+    auto programList = getProgramList();
+    if (!programList) {
+        GTEST_SKIP() << "Empty station list, tune cannot be performed";
+    }
+    ProgramSelector hdSel = {};
+    ProgramIdentifier physicallyTunedToExpected = {};
+    bool hdStationPresent = false;
+    for (auto&& programInfo : *programList) {
+        if (programInfo.selector.primaryId.type != IdentifierType::HD_STATION_ID_EXT) {
+            continue;
+        }
+        hdSel = programInfo.selector;
+        hdStationPresent = true;
+        physicallyTunedToExpected = bcutils::makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ,
+                                                            bcutils::getAmFmFrequency(hdSel));
+        break;
+    }
+    if (!hdStationPresent) {
+        GTEST_SKIP() << "No HD stations in the list, tune cannot be performed";
+    }
+
+    // try tuning
+    auto result = mModule->tune(hdSel);
+
+    // expect a failure if it's not supported
+    if (!bcutils::isSupported(mProperties, hdSel)) {
+        EXPECT_EQ(result.getServiceSpecificError(), resultToInt(Result::NOT_SUPPORTED));
+        return;
+    }
+    // expect a callback if it succeeds
+    EXPECT_TRUE(result.isOk());
+    EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
+    ProgramInfo infoCb = mCallback->getCurrentProgramInfo();
+    LOG(DEBUG) << "Current program info: " << infoCb.toString();
+    // it should tune exactly to what was requested
+    EXPECT_EQ(infoCb.selector.primaryId, hdSel.primaryId);
+    EXPECT_EQ(infoCb.physicallyTunedTo, physicallyTunedToExpected);
+}
+
+/**
  * Test tuning with DAB selector.
  *
  * Verifies that:
@@ -681,7 +761,7 @@
  *  - if it is supported, the method succeeds;
  *  - after a successful tune call, onCurrentProgramInfoChanged callback is
  *    invoked carrying a proper selector;
- *  - program changes exactly to what was requested.
+ *  - program changes to a program info with the program selector requested.
  */
 TEST_P(BroadcastRadioHalTest, DabTune) {
     LOG(DEBUG) << "DabTune Test";
@@ -690,8 +770,7 @@
     auto halResult = mModule->getDabRegionConfig(&config);
 
     if (halResult.getServiceSpecificError() == resultToInt(Result::NOT_SUPPORTED)) {
-        printSkipped("DAB not supported");
-        return;
+        GTEST_SKIP() << "DAB not supported";
     }
     ASSERT_TRUE(halResult.isOk());
     ASSERT_NE(config.size(), 0U);
@@ -699,8 +778,7 @@
     auto programList = getProgramList();
 
     if (!programList) {
-        printSkipped("Empty DAB station list, tune cannot be performed");
-        return;
+        GTEST_SKIP() << "Empty DAB station list, tune cannot be performed";
     }
 
     ProgramSelector sel = {};
@@ -730,8 +808,7 @@
     }
 
     if (!dabStationPresent) {
-        printSkipped("No DAB stations in the list, tune cannot be performed");
-        return;
+        GTEST_SKIP() << "No DAB stations in the list, tune cannot be performed";
     }
 
     // try tuning
@@ -763,7 +840,7 @@
  * Verifies that:
  *  - the method succeeds;
  *  - the program info is changed within kTuneTimeoutMs;
- *  - works both directions and with or without skipping sub-channel.
+ *  - works both directions and with or without ing sub-channel.
  */
 TEST_P(BroadcastRadioHalTest, Seek) {
     LOG(DEBUG) << "Seek Test";
@@ -773,8 +850,7 @@
     auto result = mModule->seek(/* in_directionUp= */ true, /* in_skipSubChannel= */ true);
 
     if (result.getServiceSpecificError() == resultToInt(Result::NOT_SUPPORTED)) {
-        printSkipped("Seek not supported");
-        return;
+        GTEST_SKIP() << "Seek not supported";
     }
 
     EXPECT_TRUE(result.isOk());
@@ -824,8 +900,7 @@
     auto result = mModule->step(/* in_directionUp= */ true);
 
     if (result.getServiceSpecificError() == resultToInt(Result::NOT_SUPPORTED)) {
-        printSkipped("Step not supported");
-        return;
+        GTEST_SKIP() << "Step not supported";
     }
     EXPECT_TRUE(result.isOk());
     EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
@@ -876,8 +951,7 @@
         auto result = mModule->seek(/* in_directionUp= */ true, /* in_skipSubChannel= */ true);
 
         if (result.getServiceSpecificError() == notSupportedError) {
-            printSkipped("Cancel is skipped because of seek not supported");
-            return;
+            GTEST_SKIP() << "Cancel is skipped because of seek not supported";
         }
         EXPECT_TRUE(result.isOk());
 
@@ -1071,8 +1145,7 @@
 
     std::optional<bcutils::ProgramInfoSet> completeList = getProgramList();
     if (!completeList) {
-        printSkipped("No program list available");
-        return;
+        GTEST_SKIP() << "No program list available";
     }
 
     ProgramFilter amfmFilter = {};
@@ -1097,8 +1170,7 @@
     }
 
     if (expectedResultSize == 0) {
-        printSkipped("No Am/FM programs available");
-        return;
+        GTEST_SKIP() << "No Am/FM programs available";
     }
     std::optional<bcutils::ProgramInfoSet> amfmList = getProgramList(amfmFilter);
     ASSERT_EQ(amfmList->size(), expectedResultSize) << "amfm filter result size is wrong";
@@ -1119,8 +1191,7 @@
 
     std::optional<bcutils::ProgramInfoSet> completeList = getProgramList();
     if (!completeList) {
-        printSkipped("No program list available");
-        return;
+        GTEST_SKIP() << "No program list available";
     }
 
     ProgramFilter dabFilter = {};
@@ -1144,8 +1215,7 @@
     }
 
     if (expectedResultSize == 0) {
-        printSkipped("No DAB programs available");
-        return;
+        GTEST_SKIP() << "No DAB programs available";
     }
     std::optional<bcutils::ProgramInfoSet> dabList = getProgramList(dabFilter);
     ASSERT_EQ(dabList->size(), expectedResultSize) << "dab filter result size is wrong";
@@ -1164,8 +1234,7 @@
 
     std::optional<bcutils::ProgramInfoSet> list = getProgramList();
     if (!list) {
-        printSkipped("No program list");
-        return;
+        GTEST_SKIP() << "No program list";
     }
 
     for (const auto& program : *list) {
@@ -1175,10 +1244,21 @@
             continue;
         }
 
-        std::optional<string> name = bcutils::getMetadataString(program, Metadata::programName);
-        if (!name) {
-            name = bcutils::getMetadataString(program, Metadata::rdsPs);
+        std::optional<std::string> name;
+        if (mAidlVersion == kAidlVersion1) {
+            name = bcutils::getMetadataString(program, Metadata::programName);
+            if (!name) {
+                name = bcutils::getMetadataString(program, Metadata::rdsPs);
+            }
+        } else if (mAidlVersion == kAidlVersion2) {
+            name = bcutils::getMetadataStringV2(program, Metadata::programName);
+            if (!name) {
+                name = bcutils::getMetadataStringV2(program, Metadata::rdsPs);
+            }
+        } else {
+            LOG(ERROR) << "Unknown HAL AIDL version " << mAidlVersion;
         }
+
         ASSERT_TRUE(name.has_value());
 
         ProgramIdentifier expectedId = bcutils::makeHdRadioStationName(*name);
@@ -1205,8 +1285,7 @@
 
     if (halResult.getServiceSpecificError() == resultToInt(Result::NOT_SUPPORTED)) {
         ASSERT_EQ(closeHandle.get(), nullptr);
-        printSkipped("Announcements not supported");
-        return;
+        GTEST_SKIP() << "Announcements not supported";
     }
 
     ASSERT_TRUE(halResult.isOk());
diff --git a/broadcastradio/common/OWNERS b/broadcastradio/common/OWNERS
deleted file mode 100644
index 259b91e..0000000
--- a/broadcastradio/common/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-# Automotive team
-xuweilin@google.com
-oscarazu@google.com
-ericjeong@google.com
-keunyoung@google.com
diff --git a/broadcastradio/common/tests/Android.bp b/broadcastradio/common/tests/Android.bp
index 0a6a3a2..1ea4e85 100644
--- a/broadcastradio/common/tests/Android.bp
+++ b/broadcastradio/common/tests/Android.bp
@@ -86,4 +86,7 @@
     ],
     static_libs: ["android.hardware.broadcastradio@common-utils-lib"],
     test_suites: ["general-tests"],
+    shared_libs: [
+        "libbase",
+    ],
 }
diff --git a/broadcastradio/common/utils/WorkerThread.cpp b/broadcastradio/common/utils/WorkerThread.cpp
index 43fd04a..5c8e59c 100644
--- a/broadcastradio/common/utils/WorkerThread.cpp
+++ b/broadcastradio/common/utils/WorkerThread.cpp
@@ -69,8 +69,11 @@
 }
 
 void WorkerThread::threadLoop() {
-    while (!mIsTerminating) {
+    while (true) {
         unique_lock<mutex> lk(mMut);
+        if (mIsTerminating) {
+            return;
+        }
         if (mTasks.empty()) {
             mCond.wait(lk);
             continue;
diff --git a/broadcastradio/common/utils/include/broadcastradio-utils/WorkerThread.h b/broadcastradio/common/utils/include/broadcastradio-utils/WorkerThread.h
index 457b57e..e381f5a 100644
--- a/broadcastradio/common/utils/include/broadcastradio-utils/WorkerThread.h
+++ b/broadcastradio/common/utils/include/broadcastradio-utils/WorkerThread.h
@@ -20,6 +20,8 @@
 #include <queue>
 #include <thread>
 
+#include <android-base/thread_annotations.h>
+
 namespace android {
 
 class WorkerThread {
@@ -40,11 +42,11 @@
     };
     friend bool operator<(const Task& lhs, const Task& rhs);
 
-    std::atomic<bool> mIsTerminating;
     std::mutex mMut;
-    std::condition_variable mCond;
+    bool mIsTerminating GUARDED_BY(mMut);
+    std::condition_variable mCond GUARDED_BY(mMut);
     std::thread mThread;
-    std::priority_queue<Task> mTasks;
+    std::priority_queue<Task> mTasks GUARDED_BY(mMut);
 
     void threadLoop();
 };
diff --git a/broadcastradio/common/utilsaidl/Android.bp b/broadcastradio/common/utilsaidl/Android.bp
index fa6de19..4814778 100644
--- a/broadcastradio/common/utilsaidl/Android.bp
+++ b/broadcastradio/common/utilsaidl/Android.bp
@@ -25,6 +25,44 @@
 
 cc_library_static {
     name: "android.hardware.broadcastradio@common-utils-aidl-lib",
+    defaults: [
+        "BroadcastRadioUtilsDefaults",
+    ],
+    shared_libs: [
+        "android.hardware.broadcastradio-V1-ndk",
+    ],
+}
+
+cc_library_static {
+    name: "android.hardware.broadcastradio@common-utils-aidl-lib-V2",
+    defaults: [
+        "BroadcastRadioUtilsDefaults",
+    ],
+    srcs: [
+        "src/UtilsV2.cpp",
+    ],
+    shared_libs: [
+        "android.hardware.broadcastradio-V2-ndk",
+    ],
+}
+
+cc_test {
+    name: "broadcastradio_utils_aidl_test",
+    defaults: [
+        "BroadcastRadioUtilsDefaults",
+    ],
+    srcs: [
+        "test/*.cpp",
+    ],
+    static_libs: [
+        "android.hardware.broadcastradio@common-utils-aidl-lib-V2",
+        "android.hardware.broadcastradio-V2-ndk",
+    ],
+    test_suites: ["general-tests"],
+}
+
+cc_defaults {
+    name: "BroadcastRadioUtilsDefaults",
     vendor_available: true,
     relative_install_path: "hw",
     cflags: [
@@ -37,11 +75,10 @@
         "-std=c++1z",
     ],
     srcs: [
-        "Utils.cpp",
+        "src/Utils.cpp",
     ],
     export_include_dirs: ["include"],
     shared_libs: [
-        "android.hardware.broadcastradio-V1-ndk",
         "libbase",
     ],
     static_libs: [
diff --git a/broadcastradio/common/utilsaidl/Utils.cpp b/broadcastradio/common/utilsaidl/Utils.cpp
deleted file mode 100644
index de4f529..0000000
--- a/broadcastradio/common/utilsaidl/Utils.cpp
+++ /dev/null
@@ -1,558 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "BcRadioAidlDef.utils"
-
-#include "broadcastradio-utils-aidl/Utils.h"
-
-#include <android-base/logging.h>
-#include <android-base/parseint.h>
-#include <android-base/strings.h>
-
-#include <math/HashCombine.h>
-
-namespace aidl::android::hardware::broadcastradio {
-
-namespace utils {
-
-namespace {
-
-using ::android::base::EqualsIgnoreCase;
-using ::std::string;
-using ::std::vector;
-
-const int64_t kValueForNotFoundIdentifier = 0;
-
-bool bothHaveId(const ProgramSelector& a, const ProgramSelector& b, const IdentifierType& type) {
-    return hasId(a, type) && hasId(b, type);
-}
-
-bool haveEqualIds(const ProgramSelector& a, const ProgramSelector& b, const IdentifierType& type) {
-    if (!bothHaveId(a, b, type)) {
-        return false;
-    }
-    /* We should check all Ids of a given type (ie. other AF),
-     * but it doesn't matter for default implementation.
-     */
-    return getId(a, type) == getId(b, type);
-}
-
-int getHdSubchannel(const ProgramSelector& sel) {
-    int64_t hdSidExt = getId(sel, IdentifierType::HD_STATION_ID_EXT, /* defaultValue */ 0);
-    hdSidExt >>= 32;        // Station ID number
-    return hdSidExt & 0xF;  // HD Radio subchannel
-}
-
-bool maybeGetId(const ProgramSelector& sel, const IdentifierType& type, int64_t* val) {
-    // iterate through primaryId and secondaryIds
-    for (auto it = begin(sel); it != end(sel); it++) {
-        if (it->type == type) {
-            if (val != nullptr) {
-                *val = it->value;
-            }
-            return true;
-        }
-    }
-
-    return false;
-}
-
-}  // namespace
-
-IdentifierIterator::IdentifierIterator(const ProgramSelector& sel) : IdentifierIterator(sel, 0) {}
-
-IdentifierIterator::IdentifierIterator(const ProgramSelector& sel, size_t pos)
-    : mSel(sel), mPos(pos) {}
-
-const IdentifierIterator IdentifierIterator::operator++(int) {
-    IdentifierIterator i = *this;
-    mPos++;
-    return i;
-}
-
-IdentifierIterator& IdentifierIterator::operator++() {
-    ++mPos;
-    return *this;
-}
-
-IdentifierIterator::refType IdentifierIterator::operator*() const {
-    if (mPos == 0) {
-        return getSelector().primaryId;
-    }
-
-    // mPos is 1-based for secondary identifiers
-    DCHECK(mPos <= getSelector().secondaryIds.size());
-    return getSelector().secondaryIds[mPos - 1];
-}
-
-bool IdentifierIterator::operator==(const IdentifierIterator& rhs) const {
-    // Check, if both iterators points at the same selector.
-    if (reinterpret_cast<intptr_t>(&getSelector()) !=
-        reinterpret_cast<intptr_t>(&rhs.getSelector())) {
-        return false;
-    }
-
-    return mPos == rhs.mPos;
-}
-
-int32_t resultToInt(Result result) {
-    return static_cast<int32_t>(result);
-}
-
-FrequencyBand getBand(int64_t freq) {
-    // keep in sync with
-    // frameworks/base/services/core/java/com/android/server/broadcastradio/aidl/Utils.java
-    if (freq < 30) return FrequencyBand::UNKNOWN;
-    if (freq < 500) return FrequencyBand::AM_LW;
-    if (freq < 1705) return FrequencyBand::AM_MW;
-    if (freq < 30000) return FrequencyBand::AM_SW;
-    if (freq < 60000) return FrequencyBand::UNKNOWN;
-    if (freq < 110000) return FrequencyBand::FM;
-    return FrequencyBand::UNKNOWN;
-}
-
-bool tunesTo(const ProgramSelector& a, const ProgramSelector& b) {
-    IdentifierType type = b.primaryId.type;
-
-    switch (type) {
-        case IdentifierType::HD_STATION_ID_EXT:
-        case IdentifierType::RDS_PI:
-        case IdentifierType::AMFM_FREQUENCY_KHZ:
-            if (haveEqualIds(a, b, IdentifierType::HD_STATION_ID_EXT)) return true;
-            if (haveEqualIds(a, b, IdentifierType::RDS_PI)) return true;
-            return getHdSubchannel(b) == 0 &&
-                   haveEqualIds(a, b, IdentifierType::AMFM_FREQUENCY_KHZ);
-        case IdentifierType::DAB_SID_EXT:
-            if (!haveEqualIds(a, b, IdentifierType::DAB_SID_EXT)) {
-                return false;
-            }
-            if (hasId(a, IdentifierType::DAB_ENSEMBLE) &&
-                !haveEqualIds(a, b, IdentifierType::DAB_ENSEMBLE)) {
-                return false;
-            }
-            if (hasId(a, IdentifierType::DAB_FREQUENCY_KHZ) &&
-                !haveEqualIds(a, b, IdentifierType::DAB_FREQUENCY_KHZ)) {
-                return false;
-            }
-            return true;
-        case IdentifierType::DRMO_SERVICE_ID:
-            return haveEqualIds(a, b, IdentifierType::DRMO_SERVICE_ID);
-        case IdentifierType::SXM_SERVICE_ID:
-            return haveEqualIds(a, b, IdentifierType::SXM_SERVICE_ID);
-        default:  // includes all vendor types
-            LOG(WARNING) << "unsupported program type: " << toString(type);
-            return false;
-    }
-}
-
-bool hasId(const ProgramSelector& sel, const IdentifierType& type) {
-    return maybeGetId(sel, type, /* val */ nullptr);
-}
-
-int64_t getId(const ProgramSelector& sel, const IdentifierType& type) {
-    int64_t val;
-
-    if (maybeGetId(sel, type, &val)) {
-        return val;
-    }
-
-    LOG(WARNING) << "identifier not found: " << toString(type);
-    return kValueForNotFoundIdentifier;
-}
-
-int64_t getId(const ProgramSelector& sel, const IdentifierType& type, int64_t defaultValue) {
-    if (!hasId(sel, type)) {
-        return defaultValue;
-    }
-    return getId(sel, type);
-}
-
-vector<int> getAllIds(const ProgramSelector& sel, const IdentifierType& type) {
-    vector<int> ret;
-
-    // iterate through primaryId and secondaryIds
-    for (auto it = begin(sel); it != end(sel); it++) {
-        if (it->type == type) {
-            ret.push_back(it->value);
-        }
-    }
-
-    return ret;
-}
-
-bool isSupported(const Properties& prop, const ProgramSelector& sel) {
-    for (auto it = prop.supportedIdentifierTypes.begin(); it != prop.supportedIdentifierTypes.end();
-         it++) {
-        if (hasId(sel, *it)) {
-            return true;
-        }
-    }
-    return false;
-}
-
-bool isValid(const ProgramIdentifier& id) {
-    uint64_t val = static_cast<uint64_t>(id.value);
-    bool valid = true;
-
-    auto expect = [&valid](bool condition, const string& message) {
-        if (!condition) {
-            valid = false;
-            LOG(ERROR) << "identifier not valid, expected " << message;
-        }
-    };
-
-    switch (id.type) {
-        case IdentifierType::INVALID:
-            expect(false, "IdentifierType::INVALID");
-            break;
-        case IdentifierType::DAB_FREQUENCY_KHZ:
-            expect(val > 100000u, "f > 100MHz");
-            [[fallthrough]];
-        case IdentifierType::AMFM_FREQUENCY_KHZ:
-        case IdentifierType::DRMO_FREQUENCY_KHZ:
-            expect(val > 100u, "f > 100kHz");
-            expect(val < 10000000u, "f < 10GHz");
-            break;
-        case IdentifierType::RDS_PI:
-            expect(val != 0u, "RDS PI != 0");
-            expect(val <= 0xFFFFu, "16bit id");
-            break;
-        case IdentifierType::HD_STATION_ID_EXT: {
-            uint64_t stationId = val & 0xFFFFFFFF;  // 32bit
-            val >>= 32;
-            uint64_t subchannel = val & 0xF;  // 4bit
-            val >>= 4;
-            uint64_t freq = val & 0x3FFFF;  // 18bit
-            expect(stationId != 0u, "HD station id != 0");
-            expect(subchannel < 8u, "HD subch < 8");
-            expect(freq > 100u, "f > 100kHz");
-            expect(freq < 10000000u, "f < 10GHz");
-            break;
-        }
-        case IdentifierType::HD_STATION_NAME: {
-            while (val > 0) {
-                char ch = static_cast<char>(val & 0xFF);
-                val >>= 8;
-                expect((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z'),
-                       "HD_STATION_NAME does not match [A-Z0-9]+");
-            }
-            break;
-        }
-        case IdentifierType::DAB_SID_EXT: {
-            uint64_t sid = val & 0xFFFFFFFF;  // 32bit
-            val >>= 32;
-            uint64_t ecc = val & 0xFF;  // 8bit
-            expect(sid != 0u, "DAB SId != 0");
-            expect(ecc >= 0xA0u && ecc <= 0xF6u, "Invalid ECC, see ETSI TS 101 756 V2.1.1");
-            break;
-        }
-        case IdentifierType::DAB_ENSEMBLE:
-            expect(val != 0u, "DAB ensemble != 0");
-            expect(val <= 0xFFFFu, "16bit id");
-            break;
-        case IdentifierType::DAB_SCID:
-            expect(val > 0xFu, "12bit SCId (not 4bit SCIdS)");
-            expect(val <= 0xFFFu, "12bit id");
-            break;
-        case IdentifierType::DRMO_SERVICE_ID:
-            expect(val != 0u, "DRM SId != 0");
-            expect(val <= 0xFFFFFFu, "24bit id");
-            break;
-        case IdentifierType::SXM_SERVICE_ID:
-            expect(val != 0u, "SXM SId != 0");
-            expect(val <= 0xFFFFFFFFu, "32bit id");
-            break;
-        case IdentifierType::SXM_CHANNEL:
-            expect(val < 1000u, "SXM channel < 1000");
-            break;
-        case IdentifierType::VENDOR_START:
-        case IdentifierType::VENDOR_END:
-            // skip
-            break;
-    }
-
-    return valid;
-}
-
-bool isValid(const ProgramSelector& sel) {
-    if (sel.primaryId.type != IdentifierType::AMFM_FREQUENCY_KHZ &&
-        sel.primaryId.type != IdentifierType::RDS_PI &&
-        sel.primaryId.type != IdentifierType::HD_STATION_ID_EXT &&
-        sel.primaryId.type != IdentifierType::DAB_SID_EXT &&
-        sel.primaryId.type != IdentifierType::DRMO_SERVICE_ID &&
-        sel.primaryId.type != IdentifierType::SXM_SERVICE_ID &&
-        (sel.primaryId.type < IdentifierType::VENDOR_START ||
-         sel.primaryId.type > IdentifierType::VENDOR_END)) {
-        return false;
-    }
-    return isValid(sel.primaryId);
-}
-
-ProgramIdentifier makeIdentifier(IdentifierType type, int64_t value) {
-    return {type, value};
-}
-
-ProgramSelector makeSelectorAmfm(uint32_t frequency) {
-    ProgramSelector sel = {};
-    sel.primaryId = makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, frequency);
-    return sel;
-}
-
-ProgramSelector makeSelectorDab(uint64_t sidExt) {
-    ProgramSelector sel = {};
-    sel.primaryId = makeIdentifier(IdentifierType::DAB_SID_EXT, sidExt);
-    return sel;
-}
-
-ProgramSelector makeSelectorDab(uint64_t sidExt, uint32_t ensemble, uint64_t freq) {
-    ProgramSelector sel = {};
-    sel.primaryId = makeIdentifier(IdentifierType::DAB_SID_EXT, sidExt);
-    vector<ProgramIdentifier> secondaryIds = {
-            makeIdentifier(IdentifierType::DAB_ENSEMBLE, ensemble),
-            makeIdentifier(IdentifierType::DAB_FREQUENCY_KHZ, freq)};
-    sel.secondaryIds = std::move(secondaryIds);
-    return sel;
-}
-
-bool satisfies(const ProgramFilter& filter, const ProgramSelector& sel) {
-    if (filter.identifierTypes.size() > 0) {
-        auto typeEquals = [](const ProgramIdentifier& id, IdentifierType type) {
-            return id.type == type;
-        };
-        auto it = std::find_first_of(begin(sel), end(sel), filter.identifierTypes.begin(),
-                                     filter.identifierTypes.end(), typeEquals);
-        if (it == end(sel)) {
-            return false;
-        }
-    }
-
-    if (filter.identifiers.size() > 0) {
-        auto it = std::find_first_of(begin(sel), end(sel), filter.identifiers.begin(),
-                                     filter.identifiers.end());
-        if (it == end(sel)) {
-            return false;
-        }
-    }
-
-    return true;
-}
-
-size_t ProgramInfoHasher::operator()(const ProgramInfo& info) const {
-    const ProgramIdentifier& id = info.selector.primaryId;
-
-    // This is not the best hash implementation, but good enough for default HAL
-    // implementation and tests.
-    size_t h = 0;
-    ::android::hashCombineSingle(h, id.type);
-    ::android::hashCombineSingle(h, id.value);
-    return h;
-}
-
-bool ProgramInfoKeyEqual::operator()(const ProgramInfo& info1, const ProgramInfo& info2) const {
-    const ProgramIdentifier& id1 = info1.selector.primaryId;
-    const ProgramIdentifier& id2 = info2.selector.primaryId;
-    return id1.type == id2.type && id1.value == id2.value;
-}
-
-void updateProgramList(const ProgramListChunk& chunk, ProgramInfoSet* list) {
-    if (chunk.purge) {
-        list->clear();
-    }
-
-    list->insert(chunk.modified.begin(), chunk.modified.end());
-
-    if (!chunk.removed.has_value()) {
-        return;
-    }
-
-    for (auto& id : chunk.removed.value()) {
-        if (id.has_value()) {
-            ProgramInfo info = {};
-            info.selector.primaryId = id.value();
-            list->erase(info);
-        }
-    }
-}
-
-std::optional<std::string> getMetadataString(const ProgramInfo& info, const Metadata::Tag& tag) {
-    auto isRdsPs = [tag](const Metadata& item) { return item.getTag() == tag; };
-
-    auto it = std::find_if(info.metadata.begin(), info.metadata.end(), isRdsPs);
-    if (it == info.metadata.end()) {
-        return std::nullopt;
-    }
-
-    std::string metadataString;
-    switch (it->getTag()) {
-        case Metadata::rdsPs:
-            metadataString = it->get<Metadata::rdsPs>();
-            break;
-        case Metadata::rdsPty:
-            metadataString = std::to_string(it->get<Metadata::rdsPty>());
-            break;
-        case Metadata::rbdsPty:
-            metadataString = std::to_string(it->get<Metadata::rbdsPty>());
-            break;
-        case Metadata::rdsRt:
-            metadataString = it->get<Metadata::rdsRt>();
-            break;
-        case Metadata::songTitle:
-            metadataString = it->get<Metadata::songTitle>();
-            break;
-        case Metadata::songArtist:
-            metadataString = it->get<Metadata::songArtist>();
-            break;
-        case Metadata::songAlbum:
-            metadataString = it->get<Metadata::songAlbum>();
-            break;
-        case Metadata::stationIcon:
-            metadataString = std::to_string(it->get<Metadata::stationIcon>());
-            break;
-        case Metadata::albumArt:
-            metadataString = std::to_string(it->get<Metadata::albumArt>());
-            break;
-        case Metadata::programName:
-            metadataString = it->get<Metadata::programName>();
-            break;
-        case Metadata::dabEnsembleName:
-            metadataString = it->get<Metadata::dabEnsembleName>();
-            break;
-        case Metadata::dabEnsembleNameShort:
-            metadataString = it->get<Metadata::dabEnsembleNameShort>();
-            break;
-        case Metadata::dabServiceName:
-            metadataString = it->get<Metadata::dabServiceName>();
-            break;
-        case Metadata::dabServiceNameShort:
-            metadataString = it->get<Metadata::dabServiceNameShort>();
-            break;
-        case Metadata::dabComponentName:
-            metadataString = it->get<Metadata::dabComponentName>();
-            break;
-        case Metadata::dabComponentNameShort:
-            metadataString = it->get<Metadata::dabComponentNameShort>();
-            break;
-        default:
-            LOG(ERROR) << "Metadata " << it->toString() << " is not converted.";
-            return std::nullopt;
-    }
-    return metadataString;
-}
-
-ProgramIdentifier makeHdRadioStationName(const string& name) {
-    constexpr size_t maxlen = 8;
-
-    string shortName;
-    shortName.reserve(maxlen);
-
-    const auto& loc = std::locale::classic();
-    for (const char& ch : name) {
-        if (!std::isalnum(ch, loc)) {
-            continue;
-        }
-        shortName.push_back(std::toupper(ch, loc));
-        if (shortName.length() >= maxlen) {
-            break;
-        }
-    }
-
-    // Short name is converted to HD_STATION_NAME by encoding each char into its ASCII value in
-    // in little-endian order. For example, "Abc" is converted to 0x434241.
-    int64_t val = 0;
-    for (auto rit = shortName.rbegin(); rit != shortName.rend(); ++rit) {
-        val <<= 8;
-        val |= static_cast<char>(*rit);
-    }
-
-    return makeIdentifier(IdentifierType::HD_STATION_NAME, val);
-}
-
-IdentifierType getType(int typeAsInt) {
-    return static_cast<IdentifierType>(typeAsInt);
-}
-
-bool parseArgInt(const string& s, int* out) {
-    return ::android::base::ParseInt(s, out);
-}
-
-bool parseArgLong(const std::string& s, long* out) {
-    return ::android::base::ParseInt(s, out);
-}
-
-bool parseArgBool(const string& s, bool* out) {
-    if (EqualsIgnoreCase(s, "true")) {
-        *out = true;
-    } else if (EqualsIgnoreCase(s, "false")) {
-        *out = false;
-    } else {
-        return false;
-    }
-    return true;
-}
-
-bool parseArgDirection(const string& s, bool* out) {
-    if (EqualsIgnoreCase(s, "up")) {
-        *out = true;
-    } else if (EqualsIgnoreCase(s, "down")) {
-        *out = false;
-    } else {
-        return false;
-    }
-    return true;
-}
-
-bool parseArgIdentifierTypeArray(const string& s, vector<IdentifierType>* out) {
-    for (const string& val : ::android::base::Split(s, ",")) {
-        int outInt;
-        if (!parseArgInt(val, &outInt)) {
-            return false;
-        }
-        out->push_back(getType(outInt));
-    }
-    return true;
-}
-
-bool parseProgramIdentifierList(const std::string& s, vector<ProgramIdentifier>* out) {
-    for (const string& idStr : ::android::base::Split(s, ",")) {
-        const vector<string> idStrPair = ::android::base::Split(idStr, ":");
-        if (idStrPair.size() != 2) {
-            return false;
-        }
-        int idType;
-        if (!parseArgInt(idStrPair[0], &idType)) {
-            return false;
-        }
-        long idVal;
-        if (!parseArgLong(idStrPair[1], &idVal)) {
-            return false;
-        }
-        ProgramIdentifier id = {getType(idType), idVal};
-        out->push_back(id);
-    }
-    return true;
-}
-
-}  // namespace utils
-
-utils::IdentifierIterator begin(const ProgramSelector& sel) {
-    return utils::IdentifierIterator(sel);
-}
-
-utils::IdentifierIterator end(const ProgramSelector& sel) {
-    return utils::IdentifierIterator(sel) + 1 /* primary id */ + sel.secondaryIds.size();
-}
-
-}  // namespace aidl::android::hardware::broadcastradio
diff --git a/broadcastradio/common/utilsaidl/include/broadcastradio-utils-aidl/Utils.h b/broadcastradio/common/utilsaidl/include/broadcastradio-utils-aidl/Utils.h
index ee85a17..25c96d0 100644
--- a/broadcastradio/common/utilsaidl/include/broadcastradio-utils-aidl/Utils.h
+++ b/broadcastradio/common/utilsaidl/include/broadcastradio-utils-aidl/Utils.h
@@ -17,7 +17,6 @@
 #pragma once
 
 #include <aidl/android/hardware/broadcastradio/IdentifierType.h>
-#include <aidl/android/hardware/broadcastradio/Metadata.h>
 #include <aidl/android/hardware/broadcastradio/ProgramFilter.h>
 #include <aidl/android/hardware/broadcastradio/ProgramIdentifier.h>
 #include <aidl/android/hardware/broadcastradio/ProgramInfo.h>
@@ -140,9 +139,20 @@
 ProgramSelector makeSelectorAmfm(uint32_t frequency);
 ProgramSelector makeSelectorDab(uint64_t sidExt);
 ProgramSelector makeSelectorDab(uint64_t sidExt, uint32_t ensemble, uint64_t freq);
+ProgramSelector makeSelectorHd(uint64_t stationId, uint64_t subChannel, uint64_t frequency);
 
 bool satisfies(const ProgramFilter& filter, const ProgramSelector& sel);
 
+bool isValidMetadata(const Metadata& metadata);
+
+struct ProgramSelectorComparator {
+    bool operator()(const ProgramSelector& lhs, const ProgramSelector& rhs) const;
+};
+
+struct ProgramInfoComparator {
+    bool operator()(const ProgramInfo& lhs, const ProgramInfo& rhs) const;
+};
+
 struct ProgramInfoHasher {
     size_t operator()(const ProgramInfo& info) const;
 };
@@ -159,6 +169,20 @@
 
 ProgramIdentifier makeHdRadioStationName(const std::string& name);
 
+uint32_t getHdFrequency(const ProgramSelector& sel);
+
+int getHdSubchannel(const ProgramSelector& sel);
+
+uint32_t getDabSId(const ProgramSelector& sel);
+
+int getDabEccCode(const ProgramSelector& sel);
+
+int getDabSCIdS(const ProgramSelector& sel);
+
+bool hasAmFmFrequency(const ProgramSelector& sel);
+
+uint32_t getAmFmFrequency(const ProgramSelector& sel);
+
 template <typename aidl_type>
 inline std::string vectorToString(const std::vector<aidl_type>& in_values) {
     return std::accumulate(std::begin(in_values), std::end(in_values), std::string{},
diff --git a/broadcastradio/common/utilsaidl/include/broadcastradio-utils-aidl/UtilsV2.h b/broadcastradio/common/utilsaidl/include/broadcastradio-utils-aidl/UtilsV2.h
new file mode 100644
index 0000000..734758d
--- /dev/null
+++ b/broadcastradio/common/utilsaidl/include/broadcastradio-utils-aidl/UtilsV2.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/broadcastradio/IdentifierType.h>
+#include <aidl/android/hardware/broadcastradio/Metadata.h>
+#include <aidl/android/hardware/broadcastradio/ProgramIdentifier.h>
+#include <aidl/android/hardware/broadcastradio/ProgramInfo.h>
+#include <aidl/android/hardware/broadcastradio/ProgramSelector.h>
+
+namespace aidl::android::hardware::broadcastradio {
+
+namespace utils {
+
+bool isValidV2(const ProgramIdentifier& id);
+bool isValidV2(const ProgramSelector& sel);
+bool isValidMetadataV2(const Metadata& metadata);
+std::optional<std::string> getMetadataStringV2(const ProgramInfo& info, const Metadata::Tag& tag);
+
+}  // namespace utils
+
+}  // namespace aidl::android::hardware::broadcastradio
diff --git a/broadcastradio/common/utilsaidl/src/Utils.cpp b/broadcastradio/common/utilsaidl/src/Utils.cpp
new file mode 100644
index 0000000..ddc5b8d
--- /dev/null
+++ b/broadcastradio/common/utilsaidl/src/Utils.cpp
@@ -0,0 +1,692 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "BcRadioAidlDef.utils"
+
+#include "broadcastradio-utils-aidl/Utils.h"
+
+#include <android-base/logging.h>
+#include <android-base/parseint.h>
+#include <android-base/strings.h>
+
+#include <math/HashCombine.h>
+
+namespace aidl::android::hardware::broadcastradio {
+
+namespace utils {
+
+namespace {
+
+using ::android::base::EqualsIgnoreCase;
+using ::std::vector;
+
+const int64_t kValueForNotFoundIdentifier = 0;
+
+bool bothHaveId(const ProgramSelector& a, const ProgramSelector& b, const IdentifierType& type) {
+    return hasId(a, type) && hasId(b, type);
+}
+
+bool haveEqualIds(const ProgramSelector& a, const ProgramSelector& b, const IdentifierType& type) {
+    if (!bothHaveId(a, b, type)) {
+        return false;
+    }
+    /* We should check all Ids of a given type (ie. other AF),
+     * but it doesn't matter for default implementation.
+     */
+    return getId(a, type) == getId(b, type);
+}
+
+bool maybeGetId(const ProgramSelector& sel, const IdentifierType& type, int64_t* val) {
+    // iterate through primaryId and secondaryIds
+    for (auto it = begin(sel); it != end(sel); it++) {
+        if (it->type == type) {
+            if (val != nullptr) {
+                *val = it->value;
+            }
+            return true;
+        }
+    }
+
+    return false;
+}
+
+}  // namespace
+
+IdentifierIterator::IdentifierIterator(const ProgramSelector& sel) : IdentifierIterator(sel, 0) {}
+
+IdentifierIterator::IdentifierIterator(const ProgramSelector& sel, size_t pos)
+    : mSel(sel), mPos(pos) {}
+
+const IdentifierIterator IdentifierIterator::operator++(int) {
+    IdentifierIterator i = *this;
+    mPos++;
+    return i;
+}
+
+IdentifierIterator& IdentifierIterator::operator++() {
+    ++mPos;
+    return *this;
+}
+
+IdentifierIterator::refType IdentifierIterator::operator*() const {
+    if (mPos == 0) {
+        return getSelector().primaryId;
+    }
+
+    // mPos is 1-based for secondary identifiers
+    DCHECK(mPos <= getSelector().secondaryIds.size());
+    return getSelector().secondaryIds[mPos - 1];
+}
+
+bool IdentifierIterator::operator==(const IdentifierIterator& rhs) const {
+    // Check, if both iterators points at the same selector.
+    if (reinterpret_cast<intptr_t>(&getSelector()) !=
+        reinterpret_cast<intptr_t>(&rhs.getSelector())) {
+        return false;
+    }
+
+    return mPos == rhs.mPos;
+}
+
+int32_t resultToInt(Result result) {
+    return static_cast<int32_t>(result);
+}
+
+FrequencyBand getBand(int64_t freq) {
+    // keep in sync with
+    // frameworks/base/services/core/java/com/android/server/broadcastradio/aidl/Utils.java
+    if (freq < 30) return FrequencyBand::UNKNOWN;
+    if (freq < 500) return FrequencyBand::AM_LW;
+    if (freq < 1705) return FrequencyBand::AM_MW;
+    if (freq < 30000) return FrequencyBand::AM_SW;
+    if (freq < 60000) return FrequencyBand::UNKNOWN;
+    if (freq < 110000) return FrequencyBand::FM;
+    return FrequencyBand::UNKNOWN;
+}
+
+bool tunesTo(const ProgramSelector& a, const ProgramSelector& b) {
+    IdentifierType type = b.primaryId.type;
+
+    switch (type) {
+        case IdentifierType::HD_STATION_ID_EXT:
+        case IdentifierType::RDS_PI:
+        case IdentifierType::AMFM_FREQUENCY_KHZ:
+            if (haveEqualIds(a, b, IdentifierType::HD_STATION_ID_EXT)) return true;
+            if (haveEqualIds(a, b, IdentifierType::RDS_PI)) return true;
+            if (getHdSubchannel(b) != 0) {  // supplemental program services
+                return false;
+            }
+            return haveEqualIds(a, b, IdentifierType::AMFM_FREQUENCY_KHZ) ||
+                   (b.primaryId.type == IdentifierType::HD_STATION_ID_EXT &&
+                    static_cast<uint32_t>(getId(a, IdentifierType::AMFM_FREQUENCY_KHZ)) ==
+                            getAmFmFrequency(b));
+        case IdentifierType::DAB_SID_EXT:
+            if (!haveEqualIds(a, b, IdentifierType::DAB_SID_EXT)) {
+                return false;
+            }
+            if (hasId(a, IdentifierType::DAB_ENSEMBLE) &&
+                !haveEqualIds(a, b, IdentifierType::DAB_ENSEMBLE)) {
+                return false;
+            }
+            if (hasId(a, IdentifierType::DAB_FREQUENCY_KHZ) &&
+                !haveEqualIds(a, b, IdentifierType::DAB_FREQUENCY_KHZ)) {
+                return false;
+            }
+            return true;
+        case IdentifierType::DRMO_SERVICE_ID:
+            return haveEqualIds(a, b, IdentifierType::DRMO_SERVICE_ID);
+        case IdentifierType::SXM_SERVICE_ID:
+            return haveEqualIds(a, b, IdentifierType::SXM_SERVICE_ID);
+        default:  // includes all vendor types
+            LOG(WARNING) << "unsupported program type: " << toString(type);
+            return false;
+    }
+}
+
+bool hasId(const ProgramSelector& sel, const IdentifierType& type) {
+    return maybeGetId(sel, type, /* val */ nullptr);
+}
+
+int64_t getId(const ProgramSelector& sel, const IdentifierType& type) {
+    int64_t val;
+
+    if (maybeGetId(sel, type, &val)) {
+        return val;
+    }
+
+    LOG(WARNING) << "identifier not found: " << toString(type);
+    return kValueForNotFoundIdentifier;
+}
+
+int64_t getId(const ProgramSelector& sel, const IdentifierType& type, int64_t defaultValue) {
+    if (!hasId(sel, type)) {
+        return defaultValue;
+    }
+    return getId(sel, type);
+}
+
+vector<int> getAllIds(const ProgramSelector& sel, const IdentifierType& type) {
+    vector<int> ret;
+
+    // iterate through primaryId and secondaryIds
+    for (auto it = begin(sel); it != end(sel); it++) {
+        if (it->type == type) {
+            ret.push_back(it->value);
+        }
+    }
+
+    return ret;
+}
+
+bool isSupported(const Properties& prop, const ProgramSelector& sel) {
+    for (auto it = prop.supportedIdentifierTypes.begin(); it != prop.supportedIdentifierTypes.end();
+         it++) {
+        if (hasId(sel, *it)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool isValid(const ProgramIdentifier& id) {
+    uint64_t val = static_cast<uint64_t>(id.value);
+    bool valid = true;
+
+    auto expect = [&valid](bool condition, const std::string& message) {
+        if (!condition) {
+            valid = false;
+            LOG(ERROR) << "identifier not valid, expected " << message;
+        }
+    };
+
+    switch (id.type) {
+        case IdentifierType::INVALID:
+            expect(false, "IdentifierType::INVALID");
+            break;
+        case IdentifierType::DAB_FREQUENCY_KHZ:
+            expect(val > 100000u, "f > 100MHz");
+            [[fallthrough]];
+        case IdentifierType::AMFM_FREQUENCY_KHZ:
+        case IdentifierType::DRMO_FREQUENCY_KHZ:
+            expect(val > 100u, "f > 100kHz");
+            expect(val < 10000000u, "f < 10GHz");
+            break;
+        case IdentifierType::RDS_PI:
+            expect(val != 0u, "RDS PI != 0");
+            expect(val <= 0xFFFFu, "16bit id");
+            break;
+        case IdentifierType::HD_STATION_ID_EXT: {
+            uint64_t stationId = val & 0xFFFFFFFF;  // 32bit
+            val >>= 32;
+            uint64_t subchannel = val & 0xF;  // 4bit
+            val >>= 4;
+            uint64_t freq = val & 0x3FFFF;  // 18bit
+            expect(stationId != 0u, "HD station id != 0");
+            expect(subchannel < 8u, "HD subch < 8");
+            expect(freq > 100u, "f > 100kHz");
+            expect(freq < 10000000u, "f < 10GHz");
+            break;
+        }
+        case IdentifierType::HD_STATION_NAME: {
+            while (val > 0) {
+                char ch = static_cast<char>(val & 0xFF);
+                val >>= 8;
+                expect((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z'),
+                       "HD_STATION_NAME does not match [A-Z0-9]+");
+            }
+            break;
+        }
+        case IdentifierType::DAB_SID_EXT: {
+            uint64_t sid = val & 0xFFFFFFFF;  // 32bit
+            val >>= 32;
+            uint64_t ecc = val & 0xFF;  // 8bit
+            expect(sid != 0u, "DAB SId != 0");
+            expect(ecc >= 0xA0u && ecc <= 0xF6u, "Invalid ECC, see ETSI TS 101 756 V2.1.1");
+            break;
+        }
+        case IdentifierType::DAB_ENSEMBLE:
+            expect(val != 0u, "DAB ensemble != 0");
+            expect(val <= 0xFFFFu, "16bit id");
+            break;
+        case IdentifierType::DAB_SCID:
+            expect(val > 0xFu, "12bit SCId (not 4bit SCIdS)");
+            expect(val <= 0xFFFu, "12bit id");
+            break;
+        case IdentifierType::DRMO_SERVICE_ID:
+            expect(val != 0u, "DRM SId != 0");
+            expect(val <= 0xFFFFFFu, "24bit id");
+            break;
+        case IdentifierType::SXM_SERVICE_ID:
+            expect(val != 0u, "SXM SId != 0");
+            expect(val <= 0xFFFFFFFFu, "32bit id");
+            break;
+        case IdentifierType::SXM_CHANNEL:
+            expect(val < 1000u, "SXM channel < 1000");
+            break;
+        default:
+            expect(id.type >= IdentifierType::VENDOR_START && id.type <= IdentifierType::VENDOR_END,
+                   "Undefined identifier type");
+            break;
+    }
+
+    return valid;
+}
+
+bool isValid(const ProgramSelector& sel) {
+    if (sel.primaryId.type != IdentifierType::AMFM_FREQUENCY_KHZ &&
+        sel.primaryId.type != IdentifierType::RDS_PI &&
+        sel.primaryId.type != IdentifierType::HD_STATION_ID_EXT &&
+        sel.primaryId.type != IdentifierType::DAB_SID_EXT &&
+        sel.primaryId.type != IdentifierType::DRMO_SERVICE_ID &&
+        sel.primaryId.type != IdentifierType::SXM_SERVICE_ID &&
+        (sel.primaryId.type < IdentifierType::VENDOR_START ||
+         sel.primaryId.type > IdentifierType::VENDOR_END)) {
+        return false;
+    }
+    return isValid(sel.primaryId);
+}
+
+ProgramIdentifier makeIdentifier(IdentifierType type, int64_t value) {
+    return {type, value};
+}
+
+ProgramSelector makeSelectorAmfm(uint32_t frequency) {
+    ProgramSelector sel = {};
+    sel.primaryId = makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, frequency);
+    return sel;
+}
+
+ProgramSelector makeSelectorDab(uint64_t sidExt) {
+    ProgramSelector sel = {};
+    sel.primaryId = makeIdentifier(IdentifierType::DAB_SID_EXT, sidExt);
+    return sel;
+}
+
+ProgramSelector makeSelectorHd(uint64_t stationId, uint64_t subChannel, uint64_t frequency) {
+    ProgramSelector sel = {};
+    uint64_t sidExt = stationId | (subChannel << 32) | (frequency << 36);
+    sel.primaryId = makeIdentifier(IdentifierType::HD_STATION_ID_EXT, sidExt);
+    return sel;
+}
+
+ProgramSelector makeSelectorDab(uint64_t sidExt, uint32_t ensemble, uint64_t freq) {
+    ProgramSelector sel = {};
+    sel.primaryId = makeIdentifier(IdentifierType::DAB_SID_EXT, sidExt);
+    vector<ProgramIdentifier> secondaryIds = {
+            makeIdentifier(IdentifierType::DAB_ENSEMBLE, ensemble),
+            makeIdentifier(IdentifierType::DAB_FREQUENCY_KHZ, freq)};
+    sel.secondaryIds = std::move(secondaryIds);
+    return sel;
+}
+
+bool satisfies(const ProgramFilter& filter, const ProgramSelector& sel) {
+    if (filter.identifierTypes.size() > 0) {
+        auto typeEquals = [](const ProgramIdentifier& id, IdentifierType type) {
+            return id.type == type;
+        };
+        auto it = std::find_first_of(begin(sel), end(sel), filter.identifierTypes.begin(),
+                                     filter.identifierTypes.end(), typeEquals);
+        if (it == end(sel)) {
+            return false;
+        }
+    }
+
+    if (filter.identifiers.size() > 0) {
+        auto it = std::find_first_of(begin(sel), end(sel), filter.identifiers.begin(),
+                                     filter.identifiers.end());
+        if (it == end(sel)) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+bool ProgramSelectorComparator::operator()(const ProgramSelector& lhs,
+                                           const ProgramSelector& rhs) const {
+    if ((utils::hasId(lhs, IdentifierType::AMFM_FREQUENCY_KHZ) ||
+         lhs.primaryId.type == IdentifierType::HD_STATION_ID_EXT) &&
+        (utils::hasId(rhs, IdentifierType::AMFM_FREQUENCY_KHZ) ||
+         rhs.primaryId.type == IdentifierType::HD_STATION_ID_EXT)) {
+        uint32_t freq1 = utils::getAmFmFrequency(lhs);
+        int subChannel1 = lhs.primaryId.type == IdentifierType::HD_STATION_ID_EXT
+                                  ? utils::getHdSubchannel(lhs)
+                                  : 0;
+        uint32_t freq2 = utils::getAmFmFrequency(rhs);
+        int subChannel2 = rhs.primaryId.type == IdentifierType::HD_STATION_ID_EXT
+                                  ? utils::getHdSubchannel(rhs)
+                                  : 0;
+        return freq1 < freq2 || (freq1 == freq2 && (lhs.primaryId.type < rhs.primaryId.type ||
+                                                    subChannel1 < subChannel2));
+    }
+    if (lhs.primaryId.type == IdentifierType::DAB_SID_EXT &&
+        rhs.primaryId.type == IdentifierType::DAB_SID_EXT) {
+        uint64_t dabFreq1 = utils::getId(lhs, IdentifierType::DAB_FREQUENCY_KHZ);
+        uint64_t dabFreq2 = utils::getId(rhs, IdentifierType::DAB_FREQUENCY_KHZ);
+        if (dabFreq1 != dabFreq2) {
+            return dabFreq1 < dabFreq2;
+        }
+        uint32_t ecc1 = utils::getDabEccCode(lhs);
+        uint32_t ecc2 = utils::getDabEccCode(rhs);
+        if (ecc1 != ecc2) {
+            return ecc1 < ecc2;
+        }
+        uint64_t dabEnsemble1 = utils::getId(lhs, IdentifierType::DAB_ENSEMBLE);
+        uint64_t dabEnsemble2 = utils::getId(rhs, IdentifierType::DAB_ENSEMBLE);
+        if (dabEnsemble1 != dabEnsemble2) {
+            return dabEnsemble1 < dabEnsemble2;
+        }
+        uint32_t sId1 = utils::getDabSId(lhs);
+        uint32_t sId2 = utils::getDabSId(rhs);
+        return sId1 < sId2 || (sId1 == sId2 && utils::getDabSCIdS(lhs) < utils::getDabSCIdS(rhs));
+    }
+
+    if (lhs.primaryId.type != rhs.primaryId.type) {
+        return lhs.primaryId.type < rhs.primaryId.type;
+    }
+    return lhs.primaryId.value < rhs.primaryId.value;
+}
+
+bool ProgramInfoComparator::operator()(const ProgramInfo& lhs, const ProgramInfo& rhs) const {
+    return ProgramSelectorComparator()(lhs.selector, rhs.selector);
+}
+
+size_t ProgramInfoHasher::operator()(const ProgramInfo& info) const {
+    const ProgramIdentifier& id = info.selector.primaryId;
+
+    // This is not the best hash implementation, but good enough for default HAL
+    // implementation and tests.
+    size_t h = 0;
+    ::android::hashCombineSingle(h, id.type);
+    ::android::hashCombineSingle(h, id.value);
+    return h;
+}
+
+bool ProgramInfoKeyEqual::operator()(const ProgramInfo& info1, const ProgramInfo& info2) const {
+    const ProgramIdentifier& id1 = info1.selector.primaryId;
+    const ProgramIdentifier& id2 = info2.selector.primaryId;
+    return id1.type == id2.type && id1.value == id2.value;
+}
+
+void updateProgramList(const ProgramListChunk& chunk, ProgramInfoSet* list) {
+    if (chunk.purge) {
+        list->clear();
+    }
+
+    list->insert(chunk.modified.begin(), chunk.modified.end());
+
+    if (!chunk.removed.has_value()) {
+        return;
+    }
+
+    for (auto& id : chunk.removed.value()) {
+        if (id.has_value()) {
+            ProgramInfo info = {};
+            info.selector.primaryId = id.value();
+            list->erase(info);
+        }
+    }
+}
+
+std::optional<std::string> getMetadataString(const ProgramInfo& info, const Metadata::Tag& tag) {
+    auto hasMetadataType = [tag](const Metadata& item) { return item.getTag() == tag; };
+
+    auto it = std::find_if(info.metadata.begin(), info.metadata.end(), hasMetadataType);
+    if (it == info.metadata.end()) {
+        return std::nullopt;
+    }
+
+    std::string metadataString;
+    switch (it->getTag()) {
+        case Metadata::rdsPs:
+            metadataString = it->get<Metadata::rdsPs>();
+            break;
+        case Metadata::rdsPty:
+            metadataString = std::to_string(it->get<Metadata::rdsPty>());
+            break;
+        case Metadata::rbdsPty:
+            metadataString = std::to_string(it->get<Metadata::rbdsPty>());
+            break;
+        case Metadata::rdsRt:
+            metadataString = it->get<Metadata::rdsRt>();
+            break;
+        case Metadata::songTitle:
+            metadataString = it->get<Metadata::songTitle>();
+            break;
+        case Metadata::songArtist:
+            metadataString = it->get<Metadata::songArtist>();
+            break;
+        case Metadata::songAlbum:
+            metadataString = it->get<Metadata::songAlbum>();
+            break;
+        case Metadata::stationIcon:
+            metadataString = std::to_string(it->get<Metadata::stationIcon>());
+            break;
+        case Metadata::albumArt:
+            metadataString = std::to_string(it->get<Metadata::albumArt>());
+            break;
+        case Metadata::programName:
+            metadataString = it->get<Metadata::programName>();
+            break;
+        case Metadata::dabEnsembleName:
+            metadataString = it->get<Metadata::dabEnsembleName>();
+            break;
+        case Metadata::dabEnsembleNameShort:
+            metadataString = it->get<Metadata::dabEnsembleNameShort>();
+            break;
+        case Metadata::dabServiceName:
+            metadataString = it->get<Metadata::dabServiceName>();
+            break;
+        case Metadata::dabServiceNameShort:
+            metadataString = it->get<Metadata::dabServiceNameShort>();
+            break;
+        case Metadata::dabComponentName:
+            metadataString = it->get<Metadata::dabComponentName>();
+            break;
+        case Metadata::dabComponentNameShort:
+            metadataString = it->get<Metadata::dabComponentNameShort>();
+            break;
+        default:
+            LOG(ERROR) << "Metadata " << it->toString() << " is not converted.";
+            return std::nullopt;
+    }
+    return metadataString;
+}
+
+ProgramIdentifier makeHdRadioStationName(const std::string& name) {
+    constexpr size_t maxlen = 8;
+
+    std::string shortName;
+    shortName.reserve(maxlen);
+
+    const auto& loc = std::locale::classic();
+    for (const char& ch : name) {
+        if (!std::isalnum(ch, loc)) {
+            continue;
+        }
+        shortName.push_back(std::toupper(ch, loc));
+        if (shortName.length() >= maxlen) {
+            break;
+        }
+    }
+
+    // Short name is converted to HD_STATION_NAME by encoding each char into its ASCII value in
+    // in little-endian order. For example, "Abc" is converted to 0x434241.
+    int64_t val = 0;
+    for (auto rit = shortName.rbegin(); rit != shortName.rend(); ++rit) {
+        val <<= 8;
+        val |= static_cast<char>(*rit);
+    }
+
+    return makeIdentifier(IdentifierType::HD_STATION_NAME, val);
+}
+
+IdentifierType getType(int typeAsInt) {
+    return static_cast<IdentifierType>(typeAsInt);
+}
+
+uint32_t getDabSId(const ProgramSelector& sel) {
+    int64_t dabSidExt = getId(sel, IdentifierType::DAB_SID_EXT, /* defaultValue */ 0);
+    return static_cast<uint32_t>(dabSidExt & 0xFFFFFFFF);
+}
+
+int getDabEccCode(const ProgramSelector& sel) {
+    int64_t dabSidExt = getId(sel, IdentifierType::DAB_SID_EXT, /* defaultValue */ 0);
+    return static_cast<uint32_t>((dabSidExt >> 32) & 0xFF);
+}
+
+int getDabSCIdS(const ProgramSelector& sel) {
+    int64_t dabSidExt = getId(sel, IdentifierType::DAB_SID_EXT, /* defaultValue */ 0);
+    return static_cast<uint32_t>((dabSidExt >> 40) & 0xF);
+}
+
+int getHdSubchannel(const ProgramSelector& sel) {
+    int64_t hdSidExt = getId(sel, IdentifierType::HD_STATION_ID_EXT, kValueForNotFoundIdentifier);
+    hdSidExt >>= 32;        // Station ID number
+    return hdSidExt & 0xF;  // HD Radio subchannel
+}
+
+uint32_t getHdFrequency(const ProgramSelector& sel) {
+    int64_t hdSidExt = getId(sel, IdentifierType::HD_STATION_ID_EXT, kValueForNotFoundIdentifier);
+    if (hdSidExt == kValueForNotFoundIdentifier) {
+        return kValueForNotFoundIdentifier;
+    }
+    return static_cast<uint32_t>((hdSidExt >> 36) & 0x3FFFF);  // HD Radio subchannel
+}
+
+bool hasAmFmFrequency(const ProgramSelector& sel) {
+    return hasId(sel, IdentifierType::AMFM_FREQUENCY_KHZ) ||
+           sel.primaryId.type == IdentifierType::HD_STATION_ID_EXT;
+}
+
+uint32_t getAmFmFrequency(const ProgramSelector& sel) {
+    if (hasId(sel, IdentifierType::AMFM_FREQUENCY_KHZ)) {
+        return static_cast<uint32_t>(getId(sel, IdentifierType::AMFM_FREQUENCY_KHZ));
+    }
+    return getHdFrequency(sel);
+}
+
+bool isValidMetadata(const Metadata& metadata) {
+    bool valid = true;
+
+    auto expect = [&valid](bool condition, const std::string& message) {
+        if (!condition) {
+            valid = false;
+            LOG(ERROR) << "metadata not valid, expected " << message;
+        }
+    };
+
+    switch (metadata.getTag()) {
+        case Metadata::rdsPty:
+            expect(metadata.get<Metadata::rdsPty>() >= 0, "RDS PTY >= 0");
+            expect(metadata.get<Metadata::rdsPty>() <= std::numeric_limits<uint8_t>::max(),
+                   "8bit RDS PTY");
+            break;
+        case Metadata::rbdsPty:
+            expect(metadata.get<Metadata::rbdsPty>() >= 0, "RBDS PTY >= 0");
+            expect(metadata.get<Metadata::rbdsPty>() <= std::numeric_limits<uint8_t>::max(),
+                   "8bit RBDS PTY");
+            break;
+        case Metadata::dabEnsembleNameShort:
+            expect(metadata.get<Metadata::dabEnsembleNameShort>().size() <= 8,
+                   "Dab ensemble name abbreviated length <= 8");
+            break;
+        case Metadata::dabServiceNameShort:
+            expect(metadata.get<Metadata::dabServiceNameShort>().size() <= 8,
+                   "Dab component name abbreviated length <= 8");
+            break;
+        case Metadata::dabComponentNameShort:
+            expect(metadata.get<Metadata::dabComponentNameShort>().size() <= 8,
+                   "Dab component name abbreviated length <= 8");
+            break;
+        default:
+            break;
+    }
+    return valid;
+}
+
+bool parseArgInt(const std::string& s, int* out) {
+    return ::android::base::ParseInt(s, out);
+}
+
+bool parseArgLong(const std::string& s, long* out) {
+    return ::android::base::ParseInt(s, out);
+}
+
+bool parseArgBool(const std::string& s, bool* out) {
+    if (EqualsIgnoreCase(s, "true")) {
+        *out = true;
+    } else if (EqualsIgnoreCase(s, "false")) {
+        *out = false;
+    } else {
+        return false;
+    }
+    return true;
+}
+
+bool parseArgDirection(const std::string& s, bool* out) {
+    if (EqualsIgnoreCase(s, "up")) {
+        *out = true;
+    } else if (EqualsIgnoreCase(s, "down")) {
+        *out = false;
+    } else {
+        return false;
+    }
+    return true;
+}
+
+bool parseArgIdentifierTypeArray(const std::string& s, vector<IdentifierType>* out) {
+    for (const std::string& val : ::android::base::Split(s, ",")) {
+        int outInt;
+        if (!parseArgInt(val, &outInt)) {
+            return false;
+        }
+        out->push_back(getType(outInt));
+    }
+    return true;
+}
+
+bool parseProgramIdentifierList(const std::string& s, vector<ProgramIdentifier>* out) {
+    for (const std::string& idStr : ::android::base::Split(s, ",")) {
+        const vector<std::string> idStrPair = ::android::base::Split(idStr, ":");
+        if (idStrPair.size() != 2) {
+            return false;
+        }
+        int idType;
+        if (!parseArgInt(idStrPair[0], &idType)) {
+            return false;
+        }
+        long idVal;
+        if (!parseArgLong(idStrPair[1], &idVal)) {
+            return false;
+        }
+        ProgramIdentifier id = {getType(idType), idVal};
+        out->push_back(id);
+    }
+    return true;
+}
+
+}  // namespace utils
+
+utils::IdentifierIterator begin(const ProgramSelector& sel) {
+    return utils::IdentifierIterator(sel);
+}
+
+utils::IdentifierIterator end(const ProgramSelector& sel) {
+    return utils::IdentifierIterator(sel) + 1 /* primary id */ + sel.secondaryIds.size();
+}
+
+}  // namespace aidl::android::hardware::broadcastradio
diff --git a/broadcastradio/common/utilsaidl/src/UtilsV2.cpp b/broadcastradio/common/utilsaidl/src/UtilsV2.cpp
new file mode 100644
index 0000000..6c75759
--- /dev/null
+++ b/broadcastradio/common/utilsaidl/src/UtilsV2.cpp
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "BcRadioAidlDef.utilsV2"
+
+#include "broadcastradio-utils-aidl/UtilsV2.h"
+#include "broadcastradio-utils-aidl/Utils.h"
+
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+
+namespace aidl::android::hardware::broadcastradio {
+
+namespace utils {
+
+bool isValidV2(const ProgramIdentifier& id) {
+    uint64_t val = static_cast<uint64_t>(id.value);
+    bool valid = true;
+
+    auto expect = [&valid](bool condition, const std::string& message) {
+        if (!condition) {
+            valid = false;
+            LOG(ERROR) << "identifier not valid, expected " << message;
+        }
+    };
+
+    switch (id.type) {
+        case IdentifierType::INVALID:
+            expect(false, "IdentifierType::INVALID");
+            break;
+        case IdentifierType::DAB_FREQUENCY_KHZ:
+            expect(val > 100000u, "f > 100MHz");
+            [[fallthrough]];
+        case IdentifierType::AMFM_FREQUENCY_KHZ:
+        case IdentifierType::DRMO_FREQUENCY_KHZ:
+            expect(val > 100u, "f > 100kHz");
+            expect(val < 10000000u, "f < 10GHz");
+            break;
+        case IdentifierType::RDS_PI:
+            expect(val != 0u, "RDS PI != 0");
+            expect(val <= 0xFFFFu, "16bit id");
+            break;
+        case IdentifierType::HD_STATION_ID_EXT: {
+            uint64_t stationId = val & 0xFFFFFFFF;  // 32bit
+            val >>= 32;
+            uint64_t subchannel = val & 0xF;  // 4bit
+            val >>= 4;
+            uint64_t freq = val & 0x3FFFF;  // 18bit
+            expect(stationId != 0u, "HD station id != 0");
+            expect(subchannel < 8u, "HD subch < 8");
+            expect(freq > 100u, "f > 100kHz");
+            expect(freq < 10000000u, "f < 10GHz");
+            break;
+        }
+        case IdentifierType::HD_STATION_NAME: {
+            while (val > 0) {
+                char ch = static_cast<char>(val & 0xFF);
+                val >>= 8;
+                expect((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z'),
+                       "HD_STATION_NAME does not match [A-Z0-9]+");
+            }
+            break;
+        }
+        case IdentifierType::DAB_SID_EXT: {
+            uint64_t sid = val & 0xFFFFFFFF;  // 32bit
+            val >>= 32;
+            uint64_t ecc = val & 0xFF;  // 8bit
+            expect(sid != 0u, "DAB SId != 0");
+            expect(ecc >= 0xA0u && ecc <= 0xF6u, "Invalid ECC, see ETSI TS 101 756 V2.1.1");
+            break;
+        }
+        case IdentifierType::DAB_ENSEMBLE:
+            expect(val != 0u, "DAB ensemble != 0");
+            expect(val <= 0xFFFFu, "16bit id");
+            break;
+        case IdentifierType::DAB_SCID:
+            expect(val > 0xFu, "12bit SCId (not 4bit SCIdS)");
+            expect(val <= 0xFFFu, "12bit id");
+            break;
+        case IdentifierType::DRMO_SERVICE_ID:
+            expect(val != 0u, "DRM SId != 0");
+            expect(val <= 0xFFFFFFu, "24bit id");
+            break;
+        case IdentifierType::SXM_SERVICE_ID:
+            expect(val != 0u, "SXM SId != 0");
+            expect(val <= 0xFFFFFFFFu, "32bit id");
+            break;
+        case IdentifierType::SXM_CHANNEL:
+            expect(val < 1000u, "SXM channel < 1000");
+            break;
+        case IdentifierType::HD_STATION_LOCATION: {
+            uint64_t latitudeBit = val & 0x1;
+            expect(latitudeBit == 1u, "Latitude comes first");
+            val >>= 27;
+            uint64_t latitudePad = val & 0x1Fu;
+            expect(latitudePad == 0u, "Latitude padding");
+            val >>= 5;
+            uint64_t longitudeBit = val & 0x1;
+            expect(longitudeBit == 1u, "Longitude comes next");
+            val >>= 27;
+            uint64_t longitudePad = val & 0x1Fu;
+            expect(longitudePad == 0u, "Latitude padding");
+            break;
+        }
+        default:
+            expect(id.type >= IdentifierType::VENDOR_START && id.type <= IdentifierType::VENDOR_END,
+                   "Undefined identifier type");
+            break;
+    }
+
+    return valid;
+}
+
+bool isValidV2(const ProgramSelector& sel) {
+    if (sel.primaryId.type != IdentifierType::AMFM_FREQUENCY_KHZ &&
+        sel.primaryId.type != IdentifierType::RDS_PI &&
+        sel.primaryId.type != IdentifierType::HD_STATION_ID_EXT &&
+        sel.primaryId.type != IdentifierType::DAB_SID_EXT &&
+        sel.primaryId.type != IdentifierType::DRMO_SERVICE_ID &&
+        sel.primaryId.type != IdentifierType::SXM_SERVICE_ID &&
+        (sel.primaryId.type < IdentifierType::VENDOR_START ||
+         sel.primaryId.type > IdentifierType::VENDOR_END)) {
+        return false;
+    }
+    return isValidV2(sel.primaryId);
+}
+
+bool isValidMetadataV2(const Metadata& metadata) {
+    if (!isValidMetadata(metadata)) {
+        return false;
+    }
+
+    if (metadata.getTag() == Metadata::hdStationNameShort) {
+        if (metadata.get<Metadata::hdStationNameShort>().size() > 12) {
+            LOG(ERROR) << "metadata not valid, expected HD short name length <= 12";
+            return false;
+        }
+    } else if (metadata.getTag() == Metadata::hdSubChannelsAvailable) {
+        if (metadata.get<Metadata::hdSubChannelsAvailable>() < 0) {
+            LOG(ERROR) << "metadata not valid, expected HD subchannels available >= 0";
+            return false;
+        } else if (metadata.get<Metadata::hdSubChannelsAvailable>() >
+                   std::numeric_limits<uint8_t>::max()) {
+            LOG(ERROR) << "metadata not valid, expected 8bit HD subchannels available";
+            return false;
+        }
+    }
+    return true;
+}
+
+std::optional<std::string> getMetadataStringV2(const ProgramInfo& info, const Metadata::Tag& tag) {
+    auto hasMetadataType = [tag](const Metadata& item) { return item.getTag() == tag; };
+
+    auto it = std::find_if(info.metadata.begin(), info.metadata.end(), hasMetadataType);
+    if (it == info.metadata.end()) {
+        return std::nullopt;
+    }
+
+    std::string metadataString;
+    switch (it->getTag()) {
+        case Metadata::rdsPs:
+            metadataString = it->get<Metadata::rdsPs>();
+            break;
+        case Metadata::rdsPty:
+            metadataString = std::to_string(it->get<Metadata::rdsPty>());
+            break;
+        case Metadata::rbdsPty:
+            metadataString = std::to_string(it->get<Metadata::rbdsPty>());
+            break;
+        case Metadata::rdsRt:
+            metadataString = it->get<Metadata::rdsRt>();
+            break;
+        case Metadata::songTitle:
+            metadataString = it->get<Metadata::songTitle>();
+            break;
+        case Metadata::songArtist:
+            metadataString = it->get<Metadata::songArtist>();
+            break;
+        case Metadata::songAlbum:
+            metadataString = it->get<Metadata::songAlbum>();
+            break;
+        case Metadata::stationIcon:
+            metadataString = std::to_string(it->get<Metadata::stationIcon>());
+            break;
+        case Metadata::albumArt:
+            metadataString = std::to_string(it->get<Metadata::albumArt>());
+            break;
+        case Metadata::programName:
+            metadataString = it->get<Metadata::programName>();
+            break;
+        case Metadata::dabEnsembleName:
+            metadataString = it->get<Metadata::dabEnsembleName>();
+            break;
+        case Metadata::dabEnsembleNameShort:
+            metadataString = it->get<Metadata::dabEnsembleNameShort>();
+            break;
+        case Metadata::dabServiceName:
+            metadataString = it->get<Metadata::dabServiceName>();
+            break;
+        case Metadata::dabServiceNameShort:
+            metadataString = it->get<Metadata::dabServiceNameShort>();
+            break;
+        case Metadata::dabComponentName:
+            metadataString = it->get<Metadata::dabComponentName>();
+            break;
+        case Metadata::dabComponentNameShort:
+            metadataString = it->get<Metadata::dabComponentNameShort>();
+            break;
+        case Metadata::genre:
+            metadataString = it->get<Metadata::genre>();
+            break;
+        case Metadata::commentShortDescription:
+            metadataString = it->get<Metadata::commentShortDescription>();
+            break;
+        case Metadata::commentActualText:
+            metadataString = it->get<Metadata::commentActualText>();
+            break;
+        case Metadata::commercial:
+            metadataString = it->get<Metadata::commercial>();
+            break;
+        case Metadata::ufids: {
+            auto& ufids = it->get<Metadata::ufids>();
+            metadataString = "[";
+            for (const auto& ufid : ufids) {
+                metadataString += std::string(ufid) + ",";
+            }
+            if (ufids.empty()) {
+                metadataString += "]";
+            } else {
+                metadataString[metadataString.size() - 1] = ']';
+            }
+        } break;
+        case Metadata::hdStationNameShort:
+            metadataString = it->get<Metadata::hdStationNameShort>();
+            break;
+        case Metadata::hdStationNameLong:
+            metadataString = it->get<Metadata::hdStationNameLong>();
+            break;
+        case Metadata::hdSubChannelsAvailable:
+            metadataString = std::to_string(it->get<Metadata::hdSubChannelsAvailable>());
+            break;
+        default:
+            LOG(ERROR) << "Metadata " << it->toString() << " is not converted.";
+            return std::nullopt;
+    }
+    return metadataString;
+}
+
+}  // namespace utils
+
+}  // namespace aidl::android::hardware::broadcastradio
diff --git a/broadcastradio/common/utilsaidl/test/BroadcastRadioUtilsTest.cpp b/broadcastradio/common/utilsaidl/test/BroadcastRadioUtilsTest.cpp
new file mode 100644
index 0000000..44f4d88
--- /dev/null
+++ b/broadcastradio/common/utilsaidl/test/BroadcastRadioUtilsTest.cpp
@@ -0,0 +1,454 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <broadcastradio-utils-aidl/Utils.h>
+#include <gtest/gtest.h>
+
+namespace aidl::android::hardware::broadcastradio {
+
+namespace {
+constexpr int64_t kFmFrequencyKHz = 97900;
+constexpr uint32_t kDabSid = 0x0000C221u;
+constexpr int kDabEccCode = 0xE1u;
+constexpr int kDabSCIdS = 0x1u;
+constexpr uint64_t kDabSidExt = static_cast<uint64_t>(kDabSid) |
+                                (static_cast<uint64_t>(kDabEccCode) << 32) |
+                                (static_cast<uint64_t>(kDabSCIdS) << 40);
+constexpr uint32_t kDabEnsemble = 0xCE15u;
+constexpr uint64_t kDabFrequencyKhz = 225648u;
+constexpr uint64_t kHdStationId = 0xA0000001u;
+constexpr uint64_t kHdSubChannel = 1u;
+constexpr uint64_t kHdFrequency = 97700u;
+
+const Properties kAmFmTunerProp = {
+        .maker = "makerTest",
+        .product = "productTest",
+        .supportedIdentifierTypes = {IdentifierType::AMFM_FREQUENCY_KHZ, IdentifierType::RDS_PI,
+                                     IdentifierType::HD_STATION_ID_EXT}};
+
+struct GetBandTestCase {
+    std::string name;
+    int64_t frequency;
+    utils::FrequencyBand bandResult;
+};
+
+std::vector<GetBandTestCase> getBandTestCases() {
+    return std::vector<GetBandTestCase>(
+            {GetBandTestCase{.name = "unknown_low_band",
+                             .frequency = 0,
+                             .bandResult = utils::FrequencyBand::UNKNOWN},
+             GetBandTestCase{.name = "am_lw_band",
+                             .frequency = 30,
+                             .bandResult = utils::FrequencyBand::AM_LW},
+             GetBandTestCase{.name = "am_mw_band",
+                             .frequency = 700,
+                             .bandResult = utils::FrequencyBand::AM_MW},
+             GetBandTestCase{.name = "am_sw_band",
+                             .frequency = 2000,
+                             .bandResult = utils::FrequencyBand::AM_SW},
+             GetBandTestCase{
+                     .name = "fm_band", .frequency = 97900, .bandResult = utils::FrequencyBand::FM},
+             GetBandTestCase{.name = "unknown_high_band",
+                             .frequency = 110000,
+                             .bandResult = utils::FrequencyBand::UNKNOWN}});
+}
+
+struct IsValidMetadataTestCase {
+    std::string name;
+    Metadata metadata;
+    bool valid;
+};
+
+std::vector<IsValidMetadataTestCase> getIsValidMetadataTestCases() {
+    return std::vector<IsValidMetadataTestCase>({
+            IsValidMetadataTestCase{.name = "valid_rds_pty",
+                                    .metadata = Metadata::make<Metadata::rdsPty>(1),
+                                    .valid = true},
+            IsValidMetadataTestCase{.name = "negative_rds_pty",
+                                    .metadata = Metadata::make<Metadata::rdsPty>(-1),
+                                    .valid = false},
+            IsValidMetadataTestCase{.name = "large_rds_pty",
+                                    .metadata = Metadata::make<Metadata::rdsPty>(256),
+                                    .valid = false},
+            IsValidMetadataTestCase{.name = "valid_rbds_pty",
+                                    .metadata = Metadata::make<Metadata::rbdsPty>(1),
+                                    .valid = true},
+            IsValidMetadataTestCase{.name = "negative_rbds_pty",
+                                    .metadata = Metadata::make<Metadata::rbdsPty>(-1),
+                                    .valid = false},
+            IsValidMetadataTestCase{.name = "large_rbds_pty",
+                                    .metadata = Metadata::make<Metadata::rbdsPty>(256),
+                                    .valid = false},
+            IsValidMetadataTestCase{
+                    .name = "valid_dab_ensemble_name_short",
+                    .metadata = Metadata::make<Metadata::dabEnsembleNameShort>("name"),
+                    .valid = true},
+            IsValidMetadataTestCase{
+                    .name = "too_long_dab_ensemble_name_short",
+                    .metadata = Metadata::make<Metadata::dabEnsembleNameShort>("name_long"),
+                    .valid = false},
+            IsValidMetadataTestCase{
+                    .name = "valid_dab_service_name_short",
+                    .metadata = Metadata::make<Metadata::dabServiceNameShort>("name"),
+                    .valid = true},
+            IsValidMetadataTestCase{
+                    .name = "too_long_dab_service_name_short",
+                    .metadata = Metadata::make<Metadata::dabServiceNameShort>("name_long"),
+                    .valid = false},
+            IsValidMetadataTestCase{
+                    .name = "valid_dab_component_name_short",
+                    .metadata = Metadata::make<Metadata::dabComponentNameShort>("name"),
+                    .valid = true},
+            IsValidMetadataTestCase{
+                    .name = "too_long_dab_component_name_short",
+                    .metadata = Metadata::make<Metadata::dabComponentNameShort>("name_long"),
+                    .valid = false},
+    });
+}
+}  // namespace
+
+class GetBandTest : public testing::TestWithParam<GetBandTestCase> {};
+
+INSTANTIATE_TEST_SUITE_P(GetBandTests, GetBandTest, testing::ValuesIn(getBandTestCases()),
+                         [](const testing::TestParamInfo<GetBandTest::ParamType>& info) {
+                             return info.param.name;
+                         });
+
+TEST_P(GetBandTest, GetBand) {
+    GetBandTestCase testcase = GetParam();
+
+    ASSERT_EQ(utils::getBand(testcase.frequency), testcase.bandResult);
+}
+
+class IsValidMetadataTest : public testing::TestWithParam<IsValidMetadataTestCase> {};
+
+INSTANTIATE_TEST_SUITE_P(IsValidMetadataTests, IsValidMetadataTest,
+                         testing::ValuesIn(getIsValidMetadataTestCases()),
+                         [](const testing::TestParamInfo<IsValidMetadataTest::ParamType>& info) {
+                             return info.param.name;
+                         });
+
+TEST_P(IsValidMetadataTest, IsValidMetadata) {
+    IsValidMetadataTestCase testParam = GetParam();
+
+    ASSERT_EQ(utils::isValidMetadata(testParam.metadata), testParam.valid);
+}
+
+TEST(BroadcastRadioUtilsTest, IsSupportedWithSupportedSelector) {
+    ProgramSelector sel = utils::makeSelectorAmfm(kFmFrequencyKHz);
+
+    ASSERT_TRUE(utils::isSupported(kAmFmTunerProp, sel));
+}
+
+TEST(BroadcastRadioUtilsTest, IsSupportedWithUnsupportedSelector) {
+    ProgramSelector sel = utils::makeSelectorDab(kDabSidExt, kDabEnsemble, kDabFrequencyKhz);
+
+    ASSERT_FALSE(utils::isSupported(kAmFmTunerProp, sel));
+}
+
+TEST(BroadcastRadioUtilsTest, GetBandWithFmFrequency) {
+    ProgramSelector sel = utils::makeSelectorAmfm(kFmFrequencyKHz);
+
+    ASSERT_TRUE(utils::hasId(sel, IdentifierType::AMFM_FREQUENCY_KHZ));
+}
+
+TEST(BroadcastRadioUtilsTest, HasIdWithPrimaryIdType) {
+    ProgramSelector sel = utils::makeSelectorAmfm(kFmFrequencyKHz);
+
+    ASSERT_TRUE(utils::hasId(sel, IdentifierType::AMFM_FREQUENCY_KHZ));
+}
+
+TEST(BroadcastRadioUtilsTest, HasIdWithSecondaryIdType) {
+    ProgramSelector sel = utils::makeSelectorDab(kDabSidExt, kDabEnsemble, kDabFrequencyKhz);
+
+    ASSERT_TRUE(utils::hasId(sel, IdentifierType::DAB_FREQUENCY_KHZ));
+}
+
+TEST(BroadcastRadioUtilsTest, HasIdWithIdNotInSelector) {
+    ProgramSelector sel = utils::makeSelectorDab(kDabSidExt, kDabEnsemble, kDabFrequencyKhz);
+
+    ASSERT_FALSE(utils::hasId(sel, IdentifierType::AMFM_FREQUENCY_KHZ));
+}
+
+TEST(BroadcastRadioUtilsTest, GetIdWithPrimaryIdType) {
+    ProgramSelector sel = utils::makeSelectorDab(kDabSidExt, kDabEnsemble, kDabFrequencyKhz);
+
+    ASSERT_EQ(utils::getId(sel, IdentifierType::DAB_SID_EXT), static_cast<int64_t>(kDabSidExt));
+}
+
+TEST(BroadcastRadioUtilsTest, GetIdWithSecondaryIdType) {
+    ProgramSelector sel = utils::makeSelectorDab(kDabSidExt, kDabEnsemble, kDabFrequencyKhz);
+
+    ASSERT_EQ(utils::getId(sel, IdentifierType::DAB_ENSEMBLE), static_cast<int64_t>(kDabEnsemble));
+}
+
+TEST(BroadcastRadioUtilsTest, GetIdWithIdNotFound) {
+    ProgramSelector sel = utils::makeSelectorDab(kDabSidExt, kDabEnsemble, kDabFrequencyKhz);
+
+    ASSERT_EQ(utils::getId(sel, IdentifierType::AMFM_FREQUENCY_KHZ), 0);
+}
+
+TEST(BroadcastRadioUtilsTest, GetIdWithIdFoundAndDefaultValue) {
+    int64_t defaultValue = 0x0E10000C222u;
+    ProgramSelector sel = utils::makeSelectorDab(kDabSidExt, kDabEnsemble, kDabFrequencyKhz);
+
+    ASSERT_EQ(utils::getId(sel, IdentifierType::DAB_SID_EXT, defaultValue),
+              static_cast<int64_t>(kDabSidExt));
+}
+
+TEST(BroadcastRadioUtilsTest, GetIdWithIdNotFoundAndDefaultValue) {
+    ProgramSelector sel = utils::makeSelectorDab(kDabSidExt, kDabEnsemble, kDabFrequencyKhz);
+
+    ASSERT_EQ(utils::getId(sel, IdentifierType::AMFM_FREQUENCY_KHZ, kFmFrequencyKHz),
+              static_cast<int64_t>(kFmFrequencyKHz));
+}
+
+TEST(BroadcastRadioUtilsTest, GetAllIdsWithAvailableIds) {
+    int64_t secondaryFrequencyKHz = kFmFrequencyKHz + 200;
+    ProgramSelector sel = utils::makeSelectorAmfm(kFmFrequencyKHz);
+    sel.secondaryIds.push_back(
+            utils::makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, secondaryFrequencyKHz));
+
+    std::vector<int> allIds = utils::getAllIds(sel, IdentifierType::AMFM_FREQUENCY_KHZ);
+
+    ASSERT_EQ(allIds.size(), 2u);
+    EXPECT_NE(std::find(allIds.begin(), allIds.end(), kFmFrequencyKHz), allIds.end());
+    EXPECT_NE(std::find(allIds.begin(), allIds.end(), secondaryFrequencyKHz), allIds.end());
+}
+
+TEST(BroadcastRadioUtilsTest, GetAllIdsWithIdNotFound) {
+    ProgramSelector sel = utils::makeSelectorDab(kDabSidExt, kDabEnsemble, kDabFrequencyKhz);
+
+    ASSERT_TRUE(utils::getAllIds(sel, IdentifierType::AMFM_FREQUENCY_KHZ).empty());
+}
+
+TEST(BroadcastRadioUtilsTest, MakeIdentifier) {
+    ProgramIdentifier id =
+            utils::makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, kFmFrequencyKHz);
+
+    EXPECT_EQ(id.type, IdentifierType::AMFM_FREQUENCY_KHZ);
+    EXPECT_EQ(id.value, kFmFrequencyKHz);
+}
+
+TEST(BroadcastRadioUtilsTest, MakeSelectorAmfm) {
+    ProgramSelector sel = utils::makeSelectorAmfm(kFmFrequencyKHz);
+
+    EXPECT_EQ(sel.primaryId.type, IdentifierType::AMFM_FREQUENCY_KHZ);
+    EXPECT_EQ(sel.primaryId.value, kFmFrequencyKHz);
+    EXPECT_TRUE(sel.secondaryIds.empty());
+}
+
+TEST(BroadcastRadioUtilsTest, MakeSelectorHd) {
+    ProgramSelector sel = utils::makeSelectorHd(kHdStationId, kHdSubChannel, kHdFrequency);
+
+    EXPECT_EQ(sel.primaryId.type, IdentifierType::HD_STATION_ID_EXT);
+    EXPECT_TRUE(sel.secondaryIds.empty());
+    EXPECT_EQ(utils::getHdSubchannel(sel), static_cast<int>(kHdSubChannel));
+    EXPECT_EQ(utils::getHdFrequency(sel), static_cast<uint32_t>(kHdFrequency));
+}
+
+TEST(BroadcastRadioUtilsTest, MakeHdRadioStationName) {
+    std::string stationName = "aB1-FM";
+    int64_t expectedIdValue = 0x4D46314241;
+
+    ProgramIdentifier stationNameId = utils::makeHdRadioStationName(stationName);
+
+    EXPECT_EQ(stationNameId.type, IdentifierType::HD_STATION_NAME);
+    EXPECT_EQ(stationNameId.value, expectedIdValue);
+}
+
+TEST(BroadcastRadioUtilsTest, GetHdFrequencyWithoutHdId) {
+    ProgramSelector sel = utils::makeSelectorDab(kDabSidExt, kDabEnsemble, kDabFrequencyKhz);
+
+    ASSERT_EQ(utils::getHdFrequency(sel), 0u);
+}
+
+TEST(BroadcastRadioUtilsTest, HasAmFmFrequencyWithAmFmSelector) {
+    ProgramSelector sel = utils::makeSelectorAmfm(kFmFrequencyKHz);
+
+    ASSERT_TRUE(utils::hasAmFmFrequency(sel));
+}
+
+TEST(BroadcastRadioUtilsTest, HasAmFmFrequencyWithHdSelector) {
+    ProgramSelector sel = utils::makeSelectorHd(kHdStationId, kHdSubChannel, kHdFrequency);
+
+    ASSERT_TRUE(utils::hasAmFmFrequency(sel));
+}
+
+TEST(BroadcastRadioUtilsTest, HasAmFmFrequencyWithNonAmFmHdSelector) {
+    ProgramSelector sel = utils::makeSelectorDab(kDabSidExt, kDabEnsemble, kDabFrequencyKhz);
+
+    ASSERT_FALSE(utils::hasAmFmFrequency(sel));
+}
+
+TEST(BroadcastRadioUtilsTest, GetAmFmFrequencyWithAmFmSelector) {
+    ProgramSelector sel = utils::makeSelectorAmfm(kFmFrequencyKHz);
+
+    ASSERT_EQ(utils::getAmFmFrequency(sel), static_cast<uint32_t>(kFmFrequencyKHz));
+}
+
+TEST(BroadcastRadioUtilsTest, GetAmFmFrequencyWithHdSelector) {
+    ProgramSelector sel = utils::makeSelectorHd(kHdStationId, kHdSubChannel, kHdFrequency);
+
+    ASSERT_EQ(utils::getAmFmFrequency(sel), static_cast<uint32_t>(kHdFrequency));
+}
+
+TEST(BroadcastRadioUtilsTest, GetAmFmFrequencyWithNonAmFmHdSelector) {
+    ProgramSelector sel = utils::makeSelectorDab(kDabSidExt, kDabEnsemble, kDabFrequencyKhz);
+
+    ASSERT_EQ(utils::getAmFmFrequency(sel), 0u);
+}
+
+TEST(BroadcastRadioUtilsTest, MakeSelectorDabWithOnlySidExt) {
+    ProgramSelector sel = utils::makeSelectorDab(kDabSidExt);
+
+    EXPECT_EQ(sel.primaryId.type, IdentifierType::DAB_SID_EXT);
+    EXPECT_EQ(sel.primaryId.value, static_cast<int64_t>(kDabSidExt));
+    EXPECT_TRUE(sel.secondaryIds.empty());
+}
+
+TEST(BroadcastRadioUtilsTest, MakeSelectorDab) {
+    ProgramIdentifier ensembleIdExpected =
+            utils::makeIdentifier(IdentifierType::DAB_ENSEMBLE, kDabEnsemble);
+    ProgramIdentifier frequencyIdExpected =
+            utils::makeIdentifier(IdentifierType::DAB_FREQUENCY_KHZ, kDabFrequencyKhz);
+
+    ProgramSelector sel = utils::makeSelectorDab(kDabSidExt, kDabEnsemble, kDabFrequencyKhz);
+
+    EXPECT_EQ(sel.primaryId.type, IdentifierType::DAB_SID_EXT);
+    EXPECT_EQ(sel.primaryId.value, static_cast<int64_t>(kDabSidExt));
+    EXPECT_EQ(sel.secondaryIds.size(), 2u);
+    EXPECT_NE(std::find(sel.secondaryIds.begin(), sel.secondaryIds.end(), ensembleIdExpected),
+              sel.secondaryIds.end());
+    EXPECT_NE(std::find(sel.secondaryIds.begin(), sel.secondaryIds.end(), frequencyIdExpected),
+              sel.secondaryIds.end());
+}
+
+TEST(BroadcastRadioUtilsTest, GetDabSId) {
+    ProgramSelector sel = utils::makeSelectorDab(kDabSidExt, kDabEnsemble, kDabFrequencyKhz);
+
+    ASSERT_EQ(utils::getDabSId(sel), kDabSid);
+}
+
+TEST(BroadcastRadioUtilsTest, GetDabEccCode) {
+    ProgramSelector sel = utils::makeSelectorDab(kDabSidExt, kDabEnsemble, kDabFrequencyKhz);
+
+    ASSERT_EQ(utils::getDabEccCode(sel), kDabEccCode);
+}
+
+TEST(BroadcastRadioUtilsTest, GetDabSCIdS) {
+    ProgramSelector sel = utils::makeSelectorDab(kDabSidExt, kDabEnsemble, kDabFrequencyKhz);
+
+    ASSERT_EQ(utils::getDabSCIdS(sel), kDabSCIdS);
+}
+
+TEST(BroadcastRadioUtilsTest, TunesToWithTheSameHdSelector) {
+    ProgramSelector sel = utils::makeSelectorHd(kHdStationId, kHdSubChannel, kHdFrequency);
+    ProgramSelector selTarget = utils::makeSelectorHd(kHdStationId, kHdSubChannel, kHdFrequency);
+
+    ASSERT_TRUE(utils::tunesTo(sel, selTarget));
+}
+
+TEST(BroadcastRadioUtilsTest, TunesToAmFmSelectorWithDifferentSubChannels) {
+    ProgramSelector sel = utils::makeSelectorHd(kHdStationId, kHdSubChannel, kHdFrequency);
+    ProgramSelector selTarget = utils::makeSelectorAmfm(kHdFrequency);
+
+    ASSERT_FALSE(utils::tunesTo(sel, selTarget));
+}
+
+TEST(BroadcastRadioUtilsTest, TunesToMainHdChannelWithDifferentSubChannels) {
+    ProgramSelector sel = utils::makeSelectorAmfm(kHdFrequency);
+    ProgramSelector selTarget =
+            utils::makeSelectorHd(kHdStationId, /* subChannel= */ 0, kHdFrequency);
+
+    ASSERT_TRUE(utils::tunesTo(sel, selTarget));
+}
+
+TEST(BroadcastRadioUtilsTest, TunesToWithTheSameAmFmSelector) {
+    ProgramSelector sel = utils::makeSelectorAmfm(kFmFrequencyKHz);
+    ProgramSelector selTarget = utils::makeSelectorAmfm(kFmFrequencyKHz);
+
+    ASSERT_TRUE(utils::tunesTo(sel, selTarget));
+}
+
+TEST(BroadcastRadioUtilsTest, TunesToWithDifferentFrequencies) {
+    ProgramSelector sel = utils::makeSelectorAmfm(kFmFrequencyKHz);
+    ProgramSelector selTarget = utils::makeSelectorAmfm(kFmFrequencyKHz + 200);
+
+    ASSERT_FALSE(utils::tunesTo(sel, selTarget));
+}
+
+TEST(BroadcastRadioUtilsTest, TunesToWithTheSameDabSelector) {
+    ProgramSelector sel = utils::makeSelectorDab(kDabSidExt, kDabEnsemble, kDabFrequencyKhz);
+    ProgramSelector selTarget = utils::makeSelectorDab(kDabSidExt, kDabEnsemble, kDabFrequencyKhz);
+
+    ASSERT_TRUE(utils::tunesTo(sel, selTarget));
+}
+
+TEST(BroadcastRadioUtilsTest, TunesToWithDabSelectorOfDifferentPrimaryIds) {
+    ProgramSelector sel = utils::makeSelectorDab(kDabSidExt + 1, kDabEnsemble, kDabFrequencyKhz);
+    ProgramSelector selTarget = utils::makeSelectorDab(kDabSidExt, kDabEnsemble, kDabFrequencyKhz);
+
+    ASSERT_FALSE(utils::tunesTo(sel, selTarget));
+}
+
+TEST(BroadcastRadioUtilsTest, TunesToWithDabSelectorOfDifferentSecondayIds) {
+    ProgramSelector sel = utils::makeSelectorDab(kDabSidExt, kDabEnsemble + 100, kDabFrequencyKhz);
+    ProgramSelector selTarget = utils::makeSelectorDab(kDabSidExt, kDabEnsemble, kDabFrequencyKhz);
+
+    ASSERT_FALSE(utils::tunesTo(sel, selTarget));
+}
+
+TEST(BroadcastRadioUtilsTest, TunesToWithDabSelectorWithoutSecondaryIds) {
+    ProgramSelector sel = utils::makeSelectorDab(kDabSidExt);
+    ProgramSelector selTarget = utils::makeSelectorDab(kDabSidExt, kDabEnsemble, kDabFrequencyKhz);
+
+    ASSERT_TRUE(utils::tunesTo(sel, selTarget));
+}
+
+TEST(BroadcastRadioUtilsTest, SatisfiesWithSatisfiedIdTypesFilter) {
+    ProgramFilter filter = ProgramFilter{.identifierTypes = {IdentifierType::DAB_FREQUENCY_KHZ}};
+    ProgramSelector sel = utils::makeSelectorDab(kDabSidExt, kDabEnsemble, kDabFrequencyKhz);
+
+    ASSERT_TRUE(utils::satisfies(filter, sel));
+}
+
+TEST(BroadcastRadioUtilsTest, SatisfiesWithUnsatisfiedIdTypesFilter) {
+    ProgramFilter filter = ProgramFilter{.identifierTypes = {IdentifierType::DAB_FREQUENCY_KHZ}};
+    ProgramSelector sel = utils::makeSelectorAmfm(kFmFrequencyKHz);
+
+    ASSERT_FALSE(utils::satisfies(filter, sel));
+}
+
+TEST(BroadcastRadioUtilsTest, SatisfiesWithSatisfiedIdsFilter) {
+    ProgramFilter filter =
+            ProgramFilter{.identifiers = {utils::makeIdentifier(IdentifierType::DAB_FREQUENCY_KHZ,
+                                                                kDabFrequencyKhz)}};
+    ProgramSelector sel = utils::makeSelectorDab(kDabSidExt, kDabEnsemble, kDabFrequencyKhz);
+
+    ASSERT_TRUE(utils::satisfies(filter, sel));
+}
+
+TEST(BroadcastRadioUtilsTest, SatisfiesWithUnsatisfiedIdsFilter) {
+    ProgramFilter filter =
+            ProgramFilter{.identifiers = {utils::makeIdentifier(IdentifierType::DAB_FREQUENCY_KHZ,
+                                                                kDabFrequencyKhz)}};
+    ProgramSelector sel = utils::makeSelectorDab(kDabSidExt, kDabEnsemble, kDabFrequencyKhz + 100);
+
+    ASSERT_FALSE(utils::satisfies(filter, sel));
+}
+
+}  // namespace aidl::android::hardware::broadcastradio
diff --git a/broadcastradio/common/utilsaidl/test/BroadcastRadioUtilsV2Test.cpp b/broadcastradio/common/utilsaidl/test/BroadcastRadioUtilsV2Test.cpp
new file mode 100644
index 0000000..cf9f9e9
--- /dev/null
+++ b/broadcastradio/common/utilsaidl/test/BroadcastRadioUtilsV2Test.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <broadcastradio-utils-aidl/UtilsV2.h>
+#include <gtest/gtest.h>
+
+namespace aidl::android::hardware::broadcastradio {
+
+namespace {
+struct IsValidMetadataV2TestCase {
+    std::string name;
+    Metadata metadata;
+    bool valid;
+};
+
+std::vector<IsValidMetadataV2TestCase> getIsValidMetadataV2TestCases() {
+    return std::vector<IsValidMetadataV2TestCase>({
+            IsValidMetadataV2TestCase{.name = "valid_rds_pty",
+                                      .metadata = Metadata::make<Metadata::rdsPty>(1),
+                                      .valid = true},
+            IsValidMetadataV2TestCase{.name = "negative_rds_pty",
+                                      .metadata = Metadata::make<Metadata::rdsPty>(-1),
+                                      .valid = false},
+            IsValidMetadataV2TestCase{
+                    .name = "valid_hd_station_name_short",
+                    .metadata = Metadata::make<Metadata::hdStationNameShort>("name_short"),
+                    .valid = true},
+            IsValidMetadataV2TestCase{
+                    .name = "too_long_hd_station_name_short",
+                    .metadata = Metadata::make<Metadata::hdStationNameShort>("name_too_long"),
+                    .valid = false},
+            IsValidMetadataV2TestCase{
+                    .name = "valid_hd_subchannel_available",
+                    .metadata = Metadata::make<Metadata::hdSubChannelsAvailable>(1),
+                    .valid = true},
+            IsValidMetadataV2TestCase{
+                    .name = "negative_subchannel_available",
+                    .metadata = Metadata::make<Metadata::hdSubChannelsAvailable>(-1),
+                    .valid = false},
+            IsValidMetadataV2TestCase{
+                    .name = "large_subchannel_available",
+                    .metadata = Metadata::make<Metadata::hdSubChannelsAvailable>(256),
+                    .valid = false},
+    });
+}
+}  // namespace
+
+class IsValidMetadataV2Test : public testing::TestWithParam<IsValidMetadataV2TestCase> {};
+
+INSTANTIATE_TEST_SUITE_P(IsValidMetadataV2Tests, IsValidMetadataV2Test,
+                         testing::ValuesIn(getIsValidMetadataV2TestCases()),
+                         [](const testing::TestParamInfo<IsValidMetadataV2Test::ParamType>& info) {
+                             return info.param.name;
+                         });
+
+TEST_P(IsValidMetadataV2Test, IsValidMetadataV2) {
+    IsValidMetadataV2TestCase testParam = GetParam();
+
+    ASSERT_EQ(utils::isValidMetadataV2(testParam.metadata), testParam.valid);
+}
+
+}  // namespace aidl::android::hardware::broadcastradio
diff --git a/camera/common/default/Android.bp b/camera/common/default/Android.bp
index e8c8f9d..b5d3095 100644
--- a/camera/common/default/Android.bp
+++ b/camera/common/default/Android.bp
@@ -30,13 +30,12 @@
         "libgralloctypes",
         "libhardware",
         "libcamera_metadata",
-        "android.hardware.graphics.mapper@2.0",
-        "android.hardware.graphics.mapper@3.0",
-        "android.hardware.graphics.mapper@4.0",
         "libexif",
+        "libui",
     ],
     include_dirs: ["system/media/private/camera/include"],
     export_include_dirs: ["include"],
+    export_shared_lib_headers: ["libui"],
 }
 
 // NOTE: Deprecated module kept for compatibility reasons.
diff --git a/camera/common/default/CameraMetadata.cpp b/camera/common/default/CameraMetadata.cpp
index ed56261..3252e3c 100644
--- a/camera/common/default/CameraMetadata.cpp
+++ b/camera/common/default/CameraMetadata.cpp
@@ -258,7 +258,7 @@
         return res;
     }
     // string.size() doesn't count the null termination character.
-    return updateImpl(tag, (const void*)string.string(), string.size() + 1);
+    return updateImpl(tag, (const void*)string.c_str(), string.size() + 1);
 }
 
 status_t CameraMetadata::update(const camera_metadata_ro_entry& entry) {
@@ -455,7 +455,7 @@
     for (size_t i = 0; i < totalSectionCount; ++i) {
         const char* str = (i < ANDROID_SECTION_COUNT)
                                   ? camera_metadata_section_names[i]
-                                  : (*vendorSections)[i - ANDROID_SECTION_COUNT].string();
+                                  : (*vendorSections)[i - ANDROID_SECTION_COUNT].c_str();
 
         ALOGV("%s: Trying to match against section '%s'", __FUNCTION__, str);
 
diff --git a/camera/common/default/CameraParameters.cpp b/camera/common/default/CameraParameters.cpp
index 37e28a2..3689c90 100644
--- a/camera/common/default/CameraParameters.cpp
+++ b/camera/common/default/CameraParameters.cpp
@@ -204,7 +204,7 @@
 }
 
 void CameraParameters::unflatten(const String8& params) {
-    const char* a = params.string();
+    const char* a = params.c_str();
     const char* b;
 
     mMap.clear();
@@ -263,7 +263,7 @@
 const char* CameraParameters::get(const char* key) const {
     String8 v = mMap.valueFor(String8(key));
     if (v.length() == 0) return 0;
-    return v.string();
+    return v.c_str();
 }
 
 int CameraParameters::getInt(const char* key) const {
@@ -429,7 +429,7 @@
         String8 k, v;
         k = mMap.keyAt(i);
         v = mMap.valueAt(i);
-        ALOGD("%s: %s\n", k.string(), v.string());
+        ALOGD("%s: %s\n", k.c_str(), v.c_str());
     }
 }
 
@@ -443,10 +443,10 @@
         String8 k, v;
         k = mMap.keyAt(i);
         v = mMap.valueAt(i);
-        snprintf(buffer, 255, "\t%s: %s\n", k.string(), v.string());
+        snprintf(buffer, 255, "\t%s: %s\n", k.c_str(), v.c_str());
         result.append(buffer);
     }
-    write(fd, result.string(), result.size());
+    write(fd, result.c_str(), result.size());
     return NO_ERROR;
 }
 
diff --git a/camera/common/default/HandleImporter.cpp b/camera/common/default/HandleImporter.cpp
index 1145baa..9c579e5 100644
--- a/camera/common/default/HandleImporter.cpp
+++ b/camera/common/default/HandleImporter.cpp
@@ -17,9 +17,10 @@
 #define LOG_TAG "HandleImporter"
 #include "HandleImporter.h"
 
+#include <aidl/android/hardware/graphics/common/Smpte2086.h>
 #include <gralloctypes/Gralloc4.h>
 #include <log/log.h>
-#include "aidl/android/hardware/graphics/common/Smpte2086.h"
+#include <ui/GraphicBufferMapper.h>
 
 namespace android {
 namespace hardware {
@@ -31,12 +32,6 @@
 using aidl::android::hardware::graphics::common::PlaneLayoutComponent;
 using aidl::android::hardware::graphics::common::PlaneLayoutComponentType;
 using aidl::android::hardware::graphics::common::Smpte2086;
-using MetadataType = android::hardware::graphics::mapper::V4_0::IMapper::MetadataType;
-using MapperErrorV2 = android::hardware::graphics::mapper::V2_0::Error;
-using MapperErrorV3 = android::hardware::graphics::mapper::V3_0::Error;
-using MapperErrorV4 = android::hardware::graphics::mapper::V4_0::Error;
-using IMapperV3 = android::hardware::graphics::mapper::V3_0::IMapper;
-using IMapperV4 = android::hardware::graphics::mapper::V4_0::IMapper;
 
 HandleImporter::HandleImporter() : mInitialized(false) {}
 
@@ -45,51 +40,20 @@
         return;
     }
 
-    mMapperV4 = IMapperV4::getService();
-    if (mMapperV4 != nullptr) {
-        mInitialized = true;
-        return;
-    }
-
-    mMapperV3 = IMapperV3::getService();
-    if (mMapperV3 != nullptr) {
-        mInitialized = true;
-        return;
-    }
-
-    mMapperV2 = IMapper::getService();
-    if (mMapperV2 == nullptr) {
-        ALOGE("%s: cannnot acccess graphics mapper HAL!", __FUNCTION__);
-        return;
-    }
-
+    GraphicBufferMapper::preloadHal();
     mInitialized = true;
     return;
 }
 
 void HandleImporter::cleanup() {
-    mMapperV4.clear();
-    mMapperV3.clear();
-    mMapperV2.clear();
     mInitialized = false;
 }
 
-template <class M, class E>
-bool HandleImporter::importBufferInternal(const sp<M> mapper, buffer_handle_t& handle) {
-    E error;
+bool HandleImporter::importBufferInternal(buffer_handle_t& handle) {
     buffer_handle_t importedHandle;
-    auto ret = mapper->importBuffer(
-            hidl_handle(handle), [&](const auto& tmpError, const auto& tmpBufferHandle) {
-                error = tmpError;
-                importedHandle = static_cast<buffer_handle_t>(tmpBufferHandle);
-            });
-
-    if (!ret.isOk()) {
-        ALOGE("%s: mapper importBuffer failed: %s", __FUNCTION__, ret.description().c_str());
-        return false;
-    }
-
-    if (error != E::NONE) {
+    auto status = GraphicBufferMapper::get().importBufferNoValidate(handle, &importedHandle);
+    if (status != OK) {
+        ALOGE("%s: mapper importBuffer failed: %d", __FUNCTION__, status);
         return false;
     }
 
@@ -97,172 +61,34 @@
     return true;
 }
 
-template <class M, class E>
-YCbCrLayout HandleImporter::lockYCbCrInternal(const sp<M> mapper, buffer_handle_t& buf,
-                                              uint64_t cpuUsage,
-                                              const IMapper::Rect& accessRegion) {
-    hidl_handle acquireFenceHandle;
-    auto buffer = const_cast<native_handle_t*>(buf);
-    YCbCrLayout layout = {};
+android_ycbcr HandleImporter::lockYCbCr(buffer_handle_t& buf, uint64_t cpuUsage,
+                                        const android::Rect& accessRegion) {
+    Mutex::Autolock lock(mLock);
 
-    typename M::Rect accessRegionCopy = {accessRegion.left, accessRegion.top, accessRegion.width,
-                                         accessRegion.height};
-    mapper->lockYCbCr(buffer, cpuUsage, accessRegionCopy, acquireFenceHandle,
-                      [&](const auto& tmpError, const auto& tmpLayout) {
-                          if (tmpError == E::NONE) {
-                              // Member by member copy from different versions of YCbCrLayout.
-                              layout.y = tmpLayout.y;
-                              layout.cb = tmpLayout.cb;
-                              layout.cr = tmpLayout.cr;
-                              layout.yStride = tmpLayout.yStride;
-                              layout.cStride = tmpLayout.cStride;
-                              layout.chromaStep = tmpLayout.chromaStep;
-                          } else {
-                              ALOGE("%s: failed to lockYCbCr error %d!", __FUNCTION__, tmpError);
-                          }
-                      });
+    if (!mInitialized) {
+        initializeLocked();
+    }
+    android_ycbcr layout;
+
+    status_t status = GraphicBufferMapper::get().lockYCbCr(buf, cpuUsage, accessRegion, &layout);
+
+    if (status != OK) {
+        ALOGE("%s: failed to lockYCbCr error %d!", __FUNCTION__, status);
+    }
+
     return layout;
 }
 
-bool isMetadataPesent(const sp<IMapperV4> mapper, const buffer_handle_t& buf,
-                      MetadataType metadataType) {
-    auto buffer = const_cast<native_handle_t*>(buf);
-    bool ret = false;
-    hidl_vec<uint8_t> vec;
-    mapper->get(buffer, metadataType, [&](const auto& tmpError, const auto& tmpMetadata) {
-        if (tmpError == MapperErrorV4::NONE) {
-            vec = tmpMetadata;
-        } else {
-            ALOGE("%s: failed to get metadata %d!", __FUNCTION__, tmpError);
-        }
-    });
-
-    if (vec.size() > 0) {
-        if (metadataType == gralloc4::MetadataType_Smpte2086) {
-            std::optional<Smpte2086> realSmpte2086;
-            gralloc4::decodeSmpte2086(vec, &realSmpte2086);
-            ret = realSmpte2086.has_value();
-        } else if (metadataType == gralloc4::MetadataType_Smpte2094_10) {
-            std::optional<std::vector<uint8_t>> realSmpte2094_10;
-            gralloc4::decodeSmpte2094_10(vec, &realSmpte2094_10);
-            ret = realSmpte2094_10.has_value();
-        } else if (metadataType == gralloc4::MetadataType_Smpte2094_40) {
-            std::optional<std::vector<uint8_t>> realSmpte2094_40;
-            gralloc4::decodeSmpte2094_40(vec, &realSmpte2094_40);
-            ret = realSmpte2094_40.has_value();
-        } else {
-            ALOGE("%s: Unknown metadata type!", __FUNCTION__);
-        }
-    }
-
-    return ret;
-}
-
-std::vector<PlaneLayout> getPlaneLayouts(const sp<IMapperV4> mapper, buffer_handle_t& buf) {
-    auto buffer = const_cast<native_handle_t*>(buf);
+std::vector<PlaneLayout> getPlaneLayouts(buffer_handle_t& buf) {
     std::vector<PlaneLayout> planeLayouts;
-    hidl_vec<uint8_t> encodedPlaneLayouts;
-    mapper->get(buffer, gralloc4::MetadataType_PlaneLayouts,
-                [&](const auto& tmpError, const auto& tmpEncodedPlaneLayouts) {
-                    if (tmpError == MapperErrorV4::NONE) {
-                        encodedPlaneLayouts = tmpEncodedPlaneLayouts;
-                    } else {
-                        ALOGE("%s: failed to get plane layouts %d!", __FUNCTION__, tmpError);
-                    }
-                });
-
-    gralloc4::decodePlaneLayouts(encodedPlaneLayouts, &planeLayouts);
+    status_t status = GraphicBufferMapper::get().getPlaneLayouts(buf, &planeLayouts);
+    if (status != OK) {
+        ALOGE("%s: failed to get PlaneLayouts! Status %d", __FUNCTION__, status);
+    }
 
     return planeLayouts;
 }
 
-template <>
-YCbCrLayout HandleImporter::lockYCbCrInternal<IMapperV4, MapperErrorV4>(
-        const sp<IMapperV4> mapper, buffer_handle_t& buf, uint64_t cpuUsage,
-        const IMapper::Rect& accessRegion) {
-    hidl_handle acquireFenceHandle;
-    auto buffer = const_cast<native_handle_t*>(buf);
-    YCbCrLayout layout = {};
-    void* mapped = nullptr;
-
-    typename IMapperV4::Rect accessRegionV4 = {accessRegion.left, accessRegion.top,
-                                               accessRegion.width, accessRegion.height};
-    mapper->lock(buffer, cpuUsage, accessRegionV4, acquireFenceHandle,
-                 [&](const auto& tmpError, const auto& tmpPtr) {
-                     if (tmpError == MapperErrorV4::NONE) {
-                         mapped = tmpPtr;
-                     } else {
-                         ALOGE("%s: failed to lock error %d!", __FUNCTION__, tmpError);
-                     }
-                 });
-
-    if (mapped == nullptr) {
-        return layout;
-    }
-
-    std::vector<PlaneLayout> planeLayouts = getPlaneLayouts(mapper, buf);
-    for (const auto& planeLayout : planeLayouts) {
-        for (const auto& planeLayoutComponent : planeLayout.components) {
-            const auto& type = planeLayoutComponent.type;
-
-            if (!gralloc4::isStandardPlaneLayoutComponentType(type)) {
-                continue;
-            }
-
-            uint8_t* data = reinterpret_cast<uint8_t*>(mapped);
-            data += planeLayout.offsetInBytes;
-            data += planeLayoutComponent.offsetInBits / 8;
-
-            switch (static_cast<PlaneLayoutComponentType>(type.value)) {
-                case PlaneLayoutComponentType::Y:
-                    layout.y = data;
-                    layout.yStride = planeLayout.strideInBytes;
-                    break;
-                case PlaneLayoutComponentType::CB:
-                    layout.cb = data;
-                    layout.cStride = planeLayout.strideInBytes;
-                    layout.chromaStep = planeLayout.sampleIncrementInBits / 8;
-                    break;
-                case PlaneLayoutComponentType::CR:
-                    layout.cr = data;
-                    layout.cStride = planeLayout.strideInBytes;
-                    layout.chromaStep = planeLayout.sampleIncrementInBits / 8;
-                    break;
-                default:
-                    break;
-            }
-        }
-    }
-
-    return layout;
-}
-
-template <class M, class E>
-int HandleImporter::unlockInternal(const sp<M> mapper, buffer_handle_t& buf) {
-    int releaseFence = -1;
-    auto buffer = const_cast<native_handle_t*>(buf);
-
-    mapper->unlock(buffer, [&](const auto& tmpError, const auto& tmpReleaseFence) {
-        if (tmpError == E::NONE) {
-            auto fenceHandle = tmpReleaseFence.getNativeHandle();
-            if (fenceHandle) {
-                if (fenceHandle->numInts != 0 || fenceHandle->numFds != 1) {
-                    ALOGE("%s: bad release fence numInts %d numFds %d", __FUNCTION__,
-                          fenceHandle->numInts, fenceHandle->numFds);
-                    return;
-                }
-                releaseFence = dup(fenceHandle->data[0]);
-                if (releaseFence < 0) {
-                    ALOGE("%s: bad release fence FD %d", __FUNCTION__, releaseFence);
-                }
-            }
-        } else {
-            ALOGE("%s: failed to unlock error %d!", __FUNCTION__, tmpError);
-        }
-    });
-    return releaseFence;
-}
-
 // In IComposer, any buffer_handle_t is owned by the caller and we need to
 // make a clone for hwcomposer2.  We also need to translate empty handle
 // to nullptr.  This function does that, in-place.
@@ -277,20 +103,7 @@
         initializeLocked();
     }
 
-    if (mMapperV4 != nullptr) {
-        return importBufferInternal<IMapperV4, MapperErrorV4>(mMapperV4, handle);
-    }
-
-    if (mMapperV3 != nullptr) {
-        return importBufferInternal<IMapperV3, MapperErrorV3>(mMapperV3, handle);
-    }
-
-    if (mMapperV2 != nullptr) {
-        return importBufferInternal<IMapper, MapperErrorV2>(mMapperV2, handle);
-    }
-
-    ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__);
-    return false;
+    return importBufferInternal(handle);
 }
 
 void HandleImporter::freeBuffer(buffer_handle_t handle) {
@@ -303,21 +116,9 @@
         initializeLocked();
     }
 
-    if (mMapperV4 != nullptr) {
-        auto ret = mMapperV4->freeBuffer(const_cast<native_handle_t*>(handle));
-        if (!ret.isOk()) {
-            ALOGE("%s: mapper freeBuffer failed: %s", __FUNCTION__, ret.description().c_str());
-        }
-    } else if (mMapperV3 != nullptr) {
-        auto ret = mMapperV3->freeBuffer(const_cast<native_handle_t*>(handle));
-        if (!ret.isOk()) {
-            ALOGE("%s: mapper freeBuffer failed: %s", __FUNCTION__, ret.description().c_str());
-        }
-    } else {
-        auto ret = mMapperV2->freeBuffer(const_cast<native_handle_t*>(handle));
-        if (!ret.isOk()) {
-            ALOGE("%s: mapper freeBuffer failed: %s", __FUNCTION__, ret.description().c_str());
-        }
+    status_t status = GraphicBufferMapper::get().freeBuffer(handle);
+    if (status != OK) {
+        ALOGE("%s: mapper freeBuffer failed. Status %d", __FUNCTION__, status);
     }
 }
 
@@ -345,12 +146,12 @@
 }
 
 void* HandleImporter::lock(buffer_handle_t& buf, uint64_t cpuUsage, size_t size) {
-    IMapper::Rect accessRegion{0, 0, static_cast<int>(size), 1};
+    android::Rect accessRegion{0, 0, static_cast<int>(size), 1};
     return lock(buf, cpuUsage, accessRegion);
 }
 
 void* HandleImporter::lock(buffer_handle_t& buf, uint64_t cpuUsage,
-                           const IMapper::Rect& accessRegion) {
+                           const android::Rect& accessRegion) {
     Mutex::Autolock lock(mLock);
 
     if (!mInitialized) {
@@ -358,81 +159,18 @@
     }
 
     void* ret = nullptr;
-
-    if (mMapperV4 == nullptr && mMapperV3 == nullptr && mMapperV2 == nullptr) {
-        ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__);
-        return ret;
-    }
-
-    hidl_handle acquireFenceHandle;
-    auto buffer = const_cast<native_handle_t*>(buf);
-    if (mMapperV4 != nullptr) {
-        IMapperV4::Rect accessRegionV4{accessRegion.left, accessRegion.top, accessRegion.width,
-                                       accessRegion.height};
-
-        mMapperV4->lock(buffer, cpuUsage, accessRegionV4, acquireFenceHandle,
-                        [&](const auto& tmpError, const auto& tmpPtr) {
-                            if (tmpError == MapperErrorV4::NONE) {
-                                ret = tmpPtr;
-                            } else {
-                                ALOGE("%s: failed to lock error %d!", __FUNCTION__, tmpError);
-                            }
-                        });
-    } else if (mMapperV3 != nullptr) {
-        IMapperV3::Rect accessRegionV3{accessRegion.left, accessRegion.top, accessRegion.width,
-                                       accessRegion.height};
-
-        mMapperV3->lock(buffer, cpuUsage, accessRegionV3, acquireFenceHandle,
-                        [&](const auto& tmpError, const auto& tmpPtr, const auto& /*bytesPerPixel*/,
-                            const auto& /*bytesPerStride*/) {
-                            if (tmpError == MapperErrorV3::NONE) {
-                                ret = tmpPtr;
-                            } else {
-                                ALOGE("%s: failed to lock error %d!", __FUNCTION__, tmpError);
-                            }
-                        });
-    } else {
-        mMapperV2->lock(buffer, cpuUsage, accessRegion, acquireFenceHandle,
-                        [&](const auto& tmpError, const auto& tmpPtr) {
-                            if (tmpError == MapperErrorV2::NONE) {
-                                ret = tmpPtr;
-                            } else {
-                                ALOGE("%s: failed to lock error %d!", __FUNCTION__, tmpError);
-                            }
-                        });
+    status_t status = GraphicBufferMapper::get().lock(buf, cpuUsage, accessRegion, &ret);
+    if (status != OK) {
+        ALOGE("%s: failed to lock error %d!", __FUNCTION__, status);
     }
 
     ALOGV("%s: ptr %p accessRegion.top: %d accessRegion.left: %d accessRegion.width: %d "
           "accessRegion.height: %d",
-          __FUNCTION__, ret, accessRegion.top, accessRegion.left, accessRegion.width,
-          accessRegion.height);
+          __FUNCTION__, ret, accessRegion.top, accessRegion.left, accessRegion.width(),
+          accessRegion.height());
     return ret;
 }
 
-YCbCrLayout HandleImporter::lockYCbCr(buffer_handle_t& buf, uint64_t cpuUsage,
-                                      const IMapper::Rect& accessRegion) {
-    Mutex::Autolock lock(mLock);
-
-    if (!mInitialized) {
-        initializeLocked();
-    }
-
-    if (mMapperV4 != nullptr) {
-        return lockYCbCrInternal<IMapperV4, MapperErrorV4>(mMapperV4, buf, cpuUsage, accessRegion);
-    }
-
-    if (mMapperV3 != nullptr) {
-        return lockYCbCrInternal<IMapperV3, MapperErrorV3>(mMapperV3, buf, cpuUsage, accessRegion);
-    }
-
-    if (mMapperV2 != nullptr) {
-        return lockYCbCrInternal<IMapper, MapperErrorV2>(mMapperV2, buf, cpuUsage, accessRegion);
-    }
-
-    ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__);
-    return {};
-}
-
 status_t HandleImporter::getMonoPlanarStrideBytes(buffer_handle_t& buf, uint32_t* stride /*out*/) {
     if (stride == nullptr) {
         return BAD_VALUE;
@@ -444,35 +182,26 @@
         initializeLocked();
     }
 
-    if (mMapperV4 != nullptr) {
-        std::vector<PlaneLayout> planeLayouts = getPlaneLayouts(mMapperV4, buf);
-        if (planeLayouts.size() != 1) {
-            ALOGE("%s: Unexpected number of planes %zu!", __FUNCTION__, planeLayouts.size());
-            return BAD_VALUE;
-        }
-
-        *stride = planeLayouts[0].strideInBytes;
-    } else {
-        ALOGE("%s: mMapperV4 is null! Query not supported!", __FUNCTION__);
-        return NO_INIT;
+    std::vector<PlaneLayout> planeLayouts = getPlaneLayouts(buf);
+    if (planeLayouts.size() != 1) {
+        ALOGE("%s: Unexpected number of planes %zu!", __FUNCTION__, planeLayouts.size());
+        return BAD_VALUE;
     }
 
+    *stride = planeLayouts[0].strideInBytes;
+
     return OK;
 }
 
 int HandleImporter::unlock(buffer_handle_t& buf) {
-    if (mMapperV4 != nullptr) {
-        return unlockInternal<IMapperV4, MapperErrorV4>(mMapperV4, buf);
-    }
-    if (mMapperV3 != nullptr) {
-        return unlockInternal<IMapperV3, MapperErrorV3>(mMapperV3, buf);
-    }
-    if (mMapperV2 != nullptr) {
-        return unlockInternal<IMapper, MapperErrorV2>(mMapperV2, buf);
+    int releaseFence = -1;
+
+    status_t status = GraphicBufferMapper::get().unlockAsync(buf, &releaseFence);
+    if (status != OK) {
+        ALOGE("%s: failed to unlock error %d!", __FUNCTION__, status);
     }
 
-    ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__);
-    return -1;
+    return releaseFence;
 }
 
 bool HandleImporter::isSmpte2086Present(const buffer_handle_t& buf) {
@@ -481,14 +210,14 @@
     if (!mInitialized) {
         initializeLocked();
     }
-
-    if (mMapperV4 != nullptr) {
-        return isMetadataPesent(mMapperV4, buf, gralloc4::MetadataType_Smpte2086);
-    } else {
-        ALOGE("%s: mMapperV4 is null! Query not supported!", __FUNCTION__);
+    std::optional<ui::Smpte2086> metadata;
+    status_t status = GraphicBufferMapper::get().getSmpte2086(buf, &metadata);
+    if (status != OK) {
+        ALOGE("%s: Mapper failed to get Smpte2094_40 metadata! Status: %d", __FUNCTION__, status);
+        return false;
     }
 
-    return false;
+    return metadata.has_value();
 }
 
 bool HandleImporter::isSmpte2094_10Present(const buffer_handle_t& buf) {
@@ -498,13 +227,14 @@
         initializeLocked();
     }
 
-    if (mMapperV4 != nullptr) {
-        return isMetadataPesent(mMapperV4, buf, gralloc4::MetadataType_Smpte2094_10);
-    } else {
-        ALOGE("%s: mMapperV4 is null! Query not supported!", __FUNCTION__);
+    std::optional<std::vector<uint8_t>> metadata;
+    status_t status = GraphicBufferMapper::get().getSmpte2094_10(buf, &metadata);
+    if (status != OK) {
+        ALOGE("%s: Mapper failed to get Smpte2094_40 metadata! Status: %d", __FUNCTION__, status);
+        return false;
     }
 
-    return false;
+    return metadata.has_value();
 }
 
 bool HandleImporter::isSmpte2094_40Present(const buffer_handle_t& buf) {
@@ -514,13 +244,14 @@
         initializeLocked();
     }
 
-    if (mMapperV4 != nullptr) {
-        return isMetadataPesent(mMapperV4, buf, gralloc4::MetadataType_Smpte2094_40);
-    } else {
-        ALOGE("%s: mMapperV4 is null! Query not supported!", __FUNCTION__);
+    std::optional<std::vector<uint8_t>> metadata;
+    status_t status = GraphicBufferMapper::get().getSmpte2094_40(buf, &metadata);
+    if (status != OK) {
+        ALOGE("%s: Mapper failed to get Smpte2094_40 metadata! Status: %d", __FUNCTION__, status);
+        return false;
     }
 
-    return false;
+    return metadata.has_value();
 }
 
 }  // namespace helper
diff --git a/camera/common/default/VendorTagDescriptor.cpp b/camera/common/default/VendorTagDescriptor.cpp
index 1282bd0..fba9caa 100644
--- a/camera/common/default/VendorTagDescriptor.cpp
+++ b/camera/common/default/VendorTagDescriptor.cpp
@@ -97,7 +97,7 @@
     if (index < 0) {
         return VENDOR_SECTION_NAME_ERR;
     }
-    return mSections[mTagToSectionMap.valueAt(index)].string();
+    return mSections[mTagToSectionMap.valueAt(index)].c_str();
 }
 
 ssize_t VendorTagDescriptor::getSectionIndex(uint32_t tag) const {
@@ -109,7 +109,7 @@
     if (index < 0) {
         return VENDOR_TAG_NAME_ERR;
     }
-    return mTagToNameMap.valueAt(index).string();
+    return mTagToNameMap.valueAt(index).c_str();
 }
 
 int VendorTagDescriptor::getTagType(uint32_t tag) const {
@@ -128,13 +128,13 @@
                                         /*out*/ uint32_t* tag) const {
     ssize_t index = mReverseMapping.indexOfKey(section);
     if (index < 0) {
-        ALOGE("%s: Section '%s' does not exist.", __FUNCTION__, section.string());
+        ALOGE("%s: Section '%s' does not exist.", __FUNCTION__, section.c_str());
         return BAD_VALUE;
     }
 
     ssize_t nameIndex = mReverseMapping[index]->indexOfKey(name);
     if (nameIndex < 0) {
-        ALOGE("%s: Tag name '%s' does not exist.", __FUNCTION__, name.string());
+        ALOGE("%s: Tag name '%s' does not exist.", __FUNCTION__, name.c_str());
         return BAD_VALUE;
     }
 
@@ -167,7 +167,7 @@
         const char* typeName =
                 (type >= 0 && type < NUM_TYPES) ? camera_metadata_type_names[type] : "UNKNOWN";
         dprintf(fd, "%*s0x%x (%s) with type %d (%s) defined in section %s\n", indentation + 2, "",
-                tag, name.string(), type, typeName, sectionName.string());
+                tag, name.c_str(), type, typeName, sectionName.c_str());
     }
 }
 
diff --git a/camera/common/default/include/HandleImporter.h b/camera/common/default/include/HandleImporter.h
index 5408ba9..df01202 100644
--- a/camera/common/default/include/HandleImporter.h
+++ b/camera/common/default/include/HandleImporter.h
@@ -17,15 +17,11 @@
 #ifndef CAMERA_COMMON_1_0_HANDLEIMPORTED_H
 #define CAMERA_COMMON_1_0_HANDLEIMPORTED_H
 
-#include <android/hardware/graphics/mapper/2.0/IMapper.h>
-#include <android/hardware/graphics/mapper/3.0/IMapper.h>
-#include <android/hardware/graphics/mapper/4.0/IMapper.h>
 #include <cutils/native_handle.h>
+#include <system/graphics.h>
+#include <ui/Rect.h>
 #include <utils/Mutex.h>
 
-using android::hardware::graphics::mapper::V2_0::IMapper;
-using android::hardware::graphics::mapper::V2_0::YCbCrLayout;
-
 namespace android {
 namespace hardware {
 namespace camera {
@@ -49,11 +45,11 @@
     void* lock(buffer_handle_t& buf, uint64_t cpuUsage, size_t size);
 
     // Locks 2-D buffer. Assumes caller has waited for acquire fences.
-    void* lock(buffer_handle_t& buf, uint64_t cpuUsage, const IMapper::Rect& accessRegion);
+    void* lock(buffer_handle_t& buf, uint64_t cpuUsage, const android::Rect& accessRegion);
 
     // Assumes caller has waited for acquire fences.
-    YCbCrLayout lockYCbCr(buffer_handle_t& buf, uint64_t cpuUsage,
-                          const IMapper::Rect& accessRegion);
+    android_ycbcr lockYCbCr(buffer_handle_t& buf, uint64_t cpuUsage,
+                            const android::Rect& accessRegion);
 
     // Query the stride of the first plane in bytes.
     status_t getMonoPlanarStrideBytes(buffer_handle_t& buf, uint32_t* stride /*out*/);
@@ -69,19 +65,11 @@
     void initializeLocked();
     void cleanup();
 
-    template <class M, class E>
-    bool importBufferInternal(const sp<M> mapper, buffer_handle_t& handle);
-    template <class M, class E>
-    YCbCrLayout lockYCbCrInternal(const sp<M> mapper, buffer_handle_t& buf, uint64_t cpuUsage,
-                                  const IMapper::Rect& accessRegion);
-    template <class M, class E>
-    int unlockInternal(const sp<M> mapper, buffer_handle_t& buf);
+    bool importBufferInternal(buffer_handle_t& handle);
+    int unlockInternal(buffer_handle_t& buf);
 
     Mutex mLock;
     bool mInitialized;
-    sp<IMapper> mMapperV2;
-    sp<graphics::mapper::V3_0::IMapper> mMapperV3;
-    sp<graphics::mapper::V4_0::IMapper> mMapperV4;
 };
 
 }  // namespace helper
diff --git a/camera/device/1.0/default/Android.bp b/camera/device/1.0/default/Android.bp
index 9ff6480..6992ff0 100644
--- a/camera/device/1.0/default/Android.bp
+++ b/camera/device/1.0/default/Android.bp
@@ -32,6 +32,7 @@
         "libgralloctypes",
         "libhardware",
         "libcamera_metadata",
+        "libui",
     ],
     static_libs: [
         "android.hardware.camera.common@1.0-helper",
diff --git a/camera/device/3.2/default/Android.bp b/camera/device/3.2/default/Android.bp
index a196291..adf834a 100644
--- a/camera/device/3.2/default/Android.bp
+++ b/camera/device/3.2/default/Android.bp
@@ -30,6 +30,7 @@
         "libhardware",
         "libcamera_metadata",
         "libfmq",
+        "libui",
     ],
     static_libs: [
         "android.hardware.camera.common@1.0-helper",
diff --git a/camera/device/3.4/default/Android.bp b/camera/device/3.4/default/Android.bp
index 9f0c777..100106e 100644
--- a/camera/device/3.4/default/Android.bp
+++ b/camera/device/3.4/default/Android.bp
@@ -106,6 +106,7 @@
         "libjpeg",
         "libexif",
         "libtinyxml2",
+        "libui",
     ],
     static_libs: [
         "android.hardware.camera.common@1.0-helper",
diff --git a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
index ca7186b..01b3d41 100644
--- a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
+++ b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
@@ -1574,14 +1574,23 @@
             } break;
             case PixelFormat::YCBCR_420_888:
             case PixelFormat::YV12: {
-                IMapper::Rect outRect {0, 0,
-                        static_cast<int32_t>(halBuf.width),
-                        static_cast<int32_t>(halBuf.height)};
-                YCbCrLayout outLayout = sHandleImporter.lockYCbCr(
-                        *(halBuf.bufPtr), halBuf.usage, outRect);
-                ALOGV("%s: outLayout y %p cb %p cr %p y_str %d c_str %d c_step %d",
-                        __FUNCTION__, outLayout.y, outLayout.cb, outLayout.cr,
-                        outLayout.yStride, outLayout.cStride, outLayout.chromaStep);
+                android::Rect outRect{0, 0, static_cast<int32_t>(halBuf.width),
+                                      static_cast<int32_t>(halBuf.height)};
+                android_ycbcr result =
+                        sHandleImporter.lockYCbCr(*(halBuf.bufPtr), halBuf.usage, outRect);
+                ALOGV("%s: outLayout y %p cb %p cr %p y_str %zu c_str %zu c_step %zu", __FUNCTION__,
+                      result.y, result.cb, result.cr, result.ystride, result.cstride,
+                      result.chroma_step);
+                if (result.ystride > UINT32_MAX || result.cstride > UINT32_MAX ||
+                    result.chroma_step > UINT32_MAX) {
+                    return onDeviceError("%s: lockYCbCr failed. Unexpected values!", __FUNCTION__);
+                }
+                YCbCrLayout outLayout = {.y = result.y,
+                                         .cb = result.cb,
+                                         .cr = result.cr,
+                                         .yStride = static_cast<uint32_t>(result.ystride),
+                                         .cStride = static_cast<uint32_t>(result.cstride),
+                                         .chromaStep = static_cast<uint32_t>(result.chroma_step)};
 
                 // Convert to output buffer size/format
                 uint32_t outputFourcc = getFourCcFromLayout(outLayout);
diff --git a/camera/device/3.5/default/Android.bp b/camera/device/3.5/default/Android.bp
index 9d27b32..bc15629 100644
--- a/camera/device/3.5/default/Android.bp
+++ b/camera/device/3.5/default/Android.bp
@@ -46,6 +46,7 @@
     ],
     shared_libs: [
         "libhidlbase",
+        "libui",
         "libutils",
         "libcutils",
         "camera.device@3.2-impl",
@@ -81,6 +82,7 @@
     ],
     shared_libs: [
         "libhidlbase",
+        "libui",
         "libutils",
         "libcutils",
         "camera.device@3.2-impl",
diff --git a/camera/device/3.6/default/Android.bp b/camera/device/3.6/default/Android.bp
index 89ee145..b4a486f 100644
--- a/camera/device/3.6/default/Android.bp
+++ b/camera/device/3.6/default/Android.bp
@@ -41,6 +41,7 @@
     ],
     shared_libs: [
         "libhidlbase",
+        "libui",
         "libutils",
         "libcutils",
         "camera.device@3.2-impl",
diff --git a/camera/device/3.6/default/ExternalCameraOfflineSession.cpp b/camera/device/3.6/default/ExternalCameraOfflineSession.cpp
index e606fda..1f1dfee 100644
--- a/camera/device/3.6/default/ExternalCameraOfflineSession.cpp
+++ b/camera/device/3.6/default/ExternalCameraOfflineSession.cpp
@@ -222,14 +222,23 @@
             } break;
             case PixelFormat::YCBCR_420_888:
             case PixelFormat::YV12: {
-                IMapper::Rect outRect {0, 0,
-                        static_cast<int32_t>(halBuf.width),
-                        static_cast<int32_t>(halBuf.height)};
-                YCbCrLayout outLayout = sHandleImporter.lockYCbCr(
-                        *(halBuf.bufPtr), halBuf.usage, outRect);
-                ALOGV("%s: outLayout y %p cb %p cr %p y_str %d c_str %d c_step %d",
-                        __FUNCTION__, outLayout.y, outLayout.cb, outLayout.cr,
-                        outLayout.yStride, outLayout.cStride, outLayout.chromaStep);
+                android::Rect outRect{0, 0, static_cast<int32_t>(halBuf.width),
+                                      static_cast<int32_t>(halBuf.height)};
+                android_ycbcr result =
+                        sHandleImporter.lockYCbCr(*(halBuf.bufPtr), halBuf.usage, outRect);
+                ALOGV("%s: outLayout y %p cb %p cr %p y_str %zu c_str %zu c_step %zu", __FUNCTION__,
+                      result.y, result.cb, result.cr, result.ystride, result.cstride,
+                      result.chroma_step);
+                if (result.ystride > UINT32_MAX || result.cstride > UINT32_MAX ||
+                    result.chroma_step > UINT32_MAX) {
+                    return onDeviceError("%s: lockYCbCr failed. Unexpected values!", __FUNCTION__);
+                }
+                YCbCrLayout outLayout = {.y = result.y,
+                                         .cb = result.cb,
+                                         .cr = result.cr,
+                                         .yStride = static_cast<uint32_t>(result.ystride),
+                                         .cStride = static_cast<uint32_t>(result.cstride),
+                                         .chromaStep = static_cast<uint32_t>(result.chroma_step)};
 
                 // Convert to output buffer size/format
                 uint32_t outputFourcc = V3_4::implementation::getFourCcFromLayout(outLayout);
diff --git a/camera/device/aidl/Android.bp b/camera/device/aidl/Android.bp
index 43a3934..0104636 100644
--- a/camera/device/aidl/Android.bp
+++ b/camera/device/aidl/Android.bp
@@ -11,14 +11,14 @@
     name: "android.hardware.camera.device",
     vendor_available: true,
     srcs: ["android/hardware/camera/device/*.aidl"],
-    frozen: true,
+    frozen: false,
     stability: "vintf",
     imports: [
         "android.hardware.common-V2",
         "android.hardware.common.fmq-V1",
         "android.hardware.camera.common-V1",
-        "android.hardware.camera.metadata-V2",
-        "android.hardware.graphics.common-V4",
+        "android.hardware.camera.metadata-V3",
+        "android.hardware.graphics.common-V5",
     ],
     backend: {
         cpp: {
@@ -37,7 +37,7 @@
                 "android.hardware.common.fmq-V1",
                 "android.hardware.camera.common-V1",
                 "android.hardware.camera.metadata-V1",
-                "android.hardware.graphics.common-V4",
+                "android.hardware.graphics.common-V5",
             ],
         },
         {
@@ -47,7 +47,7 @@
                 "android.hardware.common.fmq-V1",
                 "android.hardware.camera.common-V1",
                 "android.hardware.camera.metadata-V2",
-                "android.hardware.graphics.common-V4",
+                "android.hardware.graphics.common-V5",
             ],
         },
 
diff --git a/camera/device/aidl/aidl_api/android.hardware.camera.device/current/android/hardware/camera/device/ConfigureStreamsRet.aidl b/camera/device/aidl/aidl_api/android.hardware.camera.device/current/android/hardware/camera/device/ConfigureStreamsRet.aidl
new file mode 100644
index 0000000..670f7d2
--- /dev/null
+++ b/camera/device/aidl/aidl_api/android.hardware.camera.device/current/android/hardware/camera/device/ConfigureStreamsRet.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.camera.device;
+@VintfStability
+parcelable ConfigureStreamsRet {
+  android.hardware.camera.device.HalStream[] halStreams;
+}
diff --git a/camera/device/aidl/aidl_api/android.hardware.camera.device/current/android/hardware/camera/device/HalStream.aidl b/camera/device/aidl/aidl_api/android.hardware.camera.device/current/android/hardware/camera/device/HalStream.aidl
index a5784bc..3ae261d 100644
--- a/camera/device/aidl/aidl_api/android.hardware.camera.device/current/android/hardware/camera/device/HalStream.aidl
+++ b/camera/device/aidl/aidl_api/android.hardware.camera.device/current/android/hardware/camera/device/HalStream.aidl
@@ -42,4 +42,5 @@
   android.hardware.graphics.common.Dataspace overrideDataSpace;
   String physicalCameraId;
   boolean supportOffline;
+  boolean enableHalBufferManager;
 }
diff --git a/camera/device/aidl/aidl_api/android.hardware.camera.device/current/android/hardware/camera/device/ICameraDevice.aidl b/camera/device/aidl/aidl_api/android.hardware.camera.device/current/android/hardware/camera/device/ICameraDevice.aidl
index 51c6067..f73483a 100644
--- a/camera/device/aidl/aidl_api/android.hardware.camera.device/current/android/hardware/camera/device/ICameraDevice.aidl
+++ b/camera/device/aidl/aidl_api/android.hardware.camera.device/current/android/hardware/camera/device/ICameraDevice.aidl
@@ -43,4 +43,7 @@
   void setTorchMode(boolean on);
   void turnOnTorchWithStrengthLevel(int torchStrength);
   int getTorchStrengthLevel();
+  android.hardware.camera.device.CameraMetadata constructDefaultRequestSettings(in android.hardware.camera.device.RequestTemplate type);
+  boolean isStreamCombinationWithSettingsSupported(in android.hardware.camera.device.StreamConfiguration streams);
+  android.hardware.camera.device.CameraMetadata getSessionCharacteristics(in android.hardware.camera.device.StreamConfiguration sessionConfig);
 }
diff --git a/camera/device/aidl/aidl_api/android.hardware.camera.device/current/android/hardware/camera/device/ICameraDeviceSession.aidl b/camera/device/aidl/aidl_api/android.hardware.camera.device/current/android/hardware/camera/device/ICameraDeviceSession.aidl
index 2196d37..b6ae734 100644
--- a/camera/device/aidl/aidl_api/android.hardware.camera.device/current/android/hardware/camera/device/ICameraDeviceSession.aidl
+++ b/camera/device/aidl/aidl_api/android.hardware.camera.device/current/android/hardware/camera/device/ICameraDeviceSession.aidl
@@ -45,4 +45,5 @@
   oneway void signalStreamFlush(in int[] streamIds, in int streamConfigCounter);
   android.hardware.camera.device.ICameraOfflineSession switchToOffline(in int[] streamsToKeep, out android.hardware.camera.device.CameraOfflineSessionInfo offlineSessionInfo);
   void repeatingRequestEnd(in int frameNumber, in int[] streamIds);
+  android.hardware.camera.device.ConfigureStreamsRet configureStreamsV2(in android.hardware.camera.device.StreamConfiguration requestedConfiguration);
 }
diff --git a/camera/device/aidl/android/hardware/camera/device/ConfigureStreamsRet.aidl b/camera/device/aidl/android/hardware/camera/device/ConfigureStreamsRet.aidl
new file mode 100644
index 0000000..702901f
--- /dev/null
+++ b/camera/device/aidl/android/hardware/camera/device/ConfigureStreamsRet.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera.device;
+
+import android.hardware.camera.device.HalStream;
+
+/**
+ * ConfigureStreamsRet.
+ *
+ * Parcelable returned by the 'configureStreamsV2' call.
+ * This contains information which informs the camera framework
+ * about properties of each stream configured and also whether the
+ * the hal buffer manager must be used for the session configured.
+ */
+@VintfStability
+parcelable ConfigureStreamsRet {
+    /**
+     * A vector of HalStream Parcelables, which contain information
+     * about the stream parameters desired by the HAL such as usage flags,
+     * overridden format, maximum buffers etc.
+     */
+    HalStream[] halStreams;
+}
diff --git a/camera/device/aidl/android/hardware/camera/device/HalStream.aidl b/camera/device/aidl/android/hardware/camera/device/HalStream.aidl
index 25a80bc..fac89e6 100644
--- a/camera/device/aidl/android/hardware/camera/device/HalStream.aidl
+++ b/camera/device/aidl/android/hardware/camera/device/HalStream.aidl
@@ -127,4 +127,24 @@
      *
      */
     boolean supportOffline;
+
+    /**
+     * Whether the buffers for this stream are HAL buffer managed.
+     *
+     * If ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION is
+     * ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_SESSION_CONFIGURABLE, this field
+     * must be set by the HAL to inform the camera framework, whether output buffers for this
+     * stream will be HAL buffer managed - i.e. requested through the
+     * ICameraDeviceCallback.requestStreamsBuffers() API. Only the output buffers for the streams
+     * that have this field set to 'true' will be HAL buffer managed. The output buffers for other
+     * streams will be managed by the camera framework.
+     *
+     * If the value of ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION is
+     * ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_AIDL_DEVICE, the camera framework
+     * will ignore this field and assume that all output streams are hal buffer managed.
+     *
+     * If ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION is not set at all, the camera framework
+     * will ignore this field and assume output buffers are managed by the camera framework.
+     */
+    boolean enableHalBufferManager;
 }
diff --git a/camera/device/aidl/android/hardware/camera/device/ICameraDevice.aidl b/camera/device/aidl/android/hardware/camera/device/ICameraDevice.aidl
index f940000..da3d5df 100644
--- a/camera/device/aidl/android/hardware/camera/device/ICameraDevice.aidl
+++ b/camera/device/aidl/android/hardware/camera/device/ICameraDevice.aidl
@@ -21,6 +21,7 @@
 import android.hardware.camera.device.ICameraDeviceCallback;
 import android.hardware.camera.device.ICameraDeviceSession;
 import android.hardware.camera.device.ICameraInjectionSession;
+import android.hardware.camera.device.RequestTemplate;
 import android.hardware.camera.device.StreamConfiguration;
 import android.os.ParcelFileDescriptor;
 
@@ -346,4 +347,127 @@
      *
      */
     int getTorchStrengthLevel();
+
+    /**
+     * constructDefaultRequestSettings:
+     *
+     * This is the same as ICameraDeviceSession.constructDefaultRequestSettings, with
+     * the exception that it can be called before the ICameraDevice.open call.
+     *
+     * @param type The requested template CaptureRequest type to create the default settings for.
+     *
+     * @return capture settings for the requested use case.
+     *
+     */
+    CameraMetadata constructDefaultRequestSettings(in RequestTemplate type);
+
+    /**
+     * isStreamCombinationWithSettingsSupported:
+     *
+     * This is the same as isStreamCombinationSupported with below exceptions:
+     * 1. The input StreamConfiguration parameter may contain session parameters
+     * as well as additional CaptureRequest keys. See the comment
+     * sections below on what additional capture request keys are passed in
+     * StreamConfiguration::sessionParameters for each interface version. When checking if
+     * the particular StreamConfiguration is supported, the camera HAL must take all
+     * the keys in sessionParameters into consideration.
+     *
+     * 2. For version 3 of this interface, the camera compliance test will verify that
+     * isStreamCombinationWithSettingsSupported behaves properly for all combinations of
+     * below features. This function must return true for all supported combinations,
+     * and return false for non-supported feature combinations. The list of features
+     * required may grow in future versions. The additional metadata entries in
+     * StreamConfiguration::sessionParameters are {CONTROL_AE_TARGET_FPS_RANGE,
+     * CONTROL_VIDEO_STABILIZATION_MODE}.
+     *
+     * - Stream Combinations (a subset of LEGACY device mandatory stream combinations):
+     *   {
+     *     //                    4:3                16:9
+     *     // S1440P:         1920 x 1440         2560 x 1440
+     *     // S1080P:         1440 x 1080         1920 x 1080
+     *     // S720P:           960 x 720          1280 x 720
+     *
+     *     // Simple preview, GPU video processing, or no-preview video recording
+     *     {PRIV, MAXIMUM},
+     *     {PRIV, PREVIEW},
+     *     {PRIV, S1440P},
+     *     {PRIV, S1080P},
+     *     {PRIV, S720P},
+     *     // In-application video/image processing
+     *     {YUV, MAXIMUM},
+     *     {YUV, PREVIEW},
+     *     {YUV, S1440P},
+     *     {YUV, S1080P},
+     *     {YUV, S720P},
+     *     // Standard still imaging.
+     *     {PRIV, PREVIEW, JPEG, MAXIMUM},
+     *     {PRIV, S1440P,  JPEG, MAXIMUM},
+     *     {PRIV, S1080P,  JPEG, MAXIMUM},
+     *     {PRIV, S720P,   JPEG, MAXIMUM},
+     *     {PRIV, S1440P,  JPEG, S1440P},
+     *     {PRIV, S1080P,  JPEG, S1080P},
+     *     {PRIV, S720P,   JPEG, S1080P},
+     *     // In-app processing plus still capture.
+     *     {YUV,  PREVIEW, JPEG, MAXIMUM},
+     *     {YUV,  S1440P,  JPEG, MAXIMUM},
+     *     {YUV,  S1080P,  JPEG, MAXIMUM},
+     *     {YUV,  S720P,   JPEG, MAXIMUM},
+     *     // Standard recording.
+     *     {PRIV, PREVIEW, PRIV, PREVIEW},
+     *     {PRIV, S1440P,  PRIV, S1440P},
+     *     {PRIV, S1080P,  PRIV, S1080P},
+     *     {PRIV, S720P,   PRIV, S720P},
+     *     // Preview plus in-app processing.
+     *     {PRIV, PREVIEW, YUV,  PREVIEW},
+     *     {PRIV, S1440P,  YUV,  S1440P},
+     *     {PRIV, S1080P,  YUV,  S1080P},
+     *     {PRIV, S720P,   YUV,  S720P},
+     *   }
+     * - VIDEO_STABILIZATION_MODES: {OFF, PREVIEW}
+     * - AE_TARGET_FPS_RANGE: {{*, 30}, {*, 60}}
+     * - DYNAMIC_RANGE_PROFILE: {STANDARD, HLG10}
+     *
+     * Note: If a combination contains a S1440P, S1080P, or S720P stream,
+     * both 4:3 and 16:9 aspect ratio will be considered. For example, for the
+     * stream combination of {PRIV, S1440P, JPEG, MAXIMUM}, and if MAXIMUM ==
+     * 4032 x 3024, the camera compliance test will verify both
+     * {PRIV, 1920 x 1440, JPEG, 4032 x 3024} and {PRIV, 2560 x 1440, JPEG, 4032 x 2268}.
+     *
+     * @param streams The StreamConfiguration to be tested, with optional CaptureRequest parameters.
+     *
+     * @return true in case the stream combination is supported, false otherwise.
+     *
+     */
+    boolean isStreamCombinationWithSettingsSupported(in StreamConfiguration streams);
+
+    /**
+     * getSessionCharacteristics
+     *
+     * Gets the session characteristics associated with a particular session
+     * configuration by the CameraDevice.
+     *
+     * For Android 15, the characteristics which need to be set are:
+     *   - ANDROID_CONTROL_ZOOM_RATIO_RANGE
+     *   - SCALER_AVAILABLE_MAX_DIGITAL_ZOOM
+     *
+     * A service specific error will be returned on the following conditions
+     *     INTERNAL_ERROR:
+     *         The camera device cannot be opened due to an internal
+     *         error.
+     *     CAMERA_DISCONNECTED:
+     *         An external camera device has been disconnected, and is no longer
+     *         available. This camera device interface is now stale, and a new
+     *         instance must be acquired if the device is reconnected. All
+     *         subsequent calls on this interface must return
+     *         CAMERA_DISCONNECTED.
+     *     ILLEGAL_ARGUMENT:
+     *         If the given session configuration is not supported.
+     *
+     * @param sessionConfig: The session configuration for which the
+     * characteristics are being fetched.
+     *
+     * @return The static metadata for this particular session config, or an
+     * empty metadata structure if a service specific error is returned.
+     */
+    CameraMetadata getSessionCharacteristics(in StreamConfiguration sessionConfig);
 }
diff --git a/camera/device/aidl/android/hardware/camera/device/ICameraDeviceSession.aidl b/camera/device/aidl/android/hardware/camera/device/ICameraDeviceSession.aidl
index 885c71a..ffc1a11 100644
--- a/camera/device/aidl/android/hardware/camera/device/ICameraDeviceSession.aidl
+++ b/camera/device/aidl/android/hardware/camera/device/ICameraDeviceSession.aidl
@@ -20,6 +20,7 @@
 import android.hardware.camera.device.CameraMetadata;
 import android.hardware.camera.device.CameraOfflineSessionInfo;
 import android.hardware.camera.device.CaptureRequest;
+import android.hardware.camera.device.ConfigureStreamsRet;
 import android.hardware.camera.device.HalStream;
 import android.hardware.camera.device.ICameraOfflineSession;
 import android.hardware.camera.device.RequestTemplate;
@@ -88,6 +89,13 @@
      * with processCaptureResult (and its respective releaseFence has been
      * signaled) the framework may free or reuse it at any time.
      *
+     * This method wil only be called by the framework if
+     * ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION is either not advertised or is
+     * ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_AIDL. If the value of
+     * ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION is
+     * ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_SESSION_CONFIGURABLE, configureStreamsV2
+     * will be called instead.
+     *
      * ------------------------------------------------------------------------
      *
      * Preconditions:
@@ -386,8 +394,8 @@
      *          error.
      * @return true in case the stream reconfiguration is required, false otherwise.
      */
-    boolean isReconfigurationRequired(in CameraMetadata oldSessionParams,
-                                      in CameraMetadata newSessionParams);
+    boolean isReconfigurationRequired(
+            in CameraMetadata oldSessionParams, in CameraMetadata newSessionParams);
 
     /**
      * processCaptureRequest:
@@ -576,4 +584,29 @@
      */
     void repeatingRequestEnd(in int frameNumber, in int[] streamIds);
 
+    /**
+     *
+     * configureStreamsV2:
+     *
+     * Performs the same function as 'configureStreams'. This function returns a
+     * 'ConfigureStreamsRet' Parcelable. This tells the framework about the desired stream
+     * parameters such as usage flags, maximum buffers, overridden format etc. It also informs
+     * camera framework whether the HAL will use the HAL buffer manager APIs 'requestStreamBuffers'
+     * and 'returnStreamBuffers' to request and return buffers to the framework.
+     *
+     * This method is only supported if
+     * ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION is
+     * ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_SESSION_CONFIGURABLE. It must not be
+     * called by the camera framework if it isn't supported. That is, the framework will only
+     * ever call one of 'configureStreams' or 'configureStreamsV2' depending on the value of
+     * ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION.
+     *
+     * @param requestedConfiguration The stream configuration requested by the camera framework to
+     *        be configured by the camera HAL.
+     * @return A ConfigureStreamsRet Parcelable containing a vector of HalStreams and a boolean
+     *         specifying whether the HAL buffer manager must be used for this session
+     *         configuration.
+     *
+     */
+    ConfigureStreamsRet configureStreamsV2(in StreamConfiguration requestedConfiguration);
 }
diff --git a/camera/device/aidl/android/hardware/camera/device/StreamConfiguration.aidl b/camera/device/aidl/android/hardware/camera/device/StreamConfiguration.aidl
index 197d9af..0f5bad9 100644
--- a/camera/device/aidl/android/hardware/camera/device/StreamConfiguration.aidl
+++ b/camera/device/aidl/android/hardware/camera/device/StreamConfiguration.aidl
@@ -59,6 +59,14 @@
      * pipeline updates. The field is optional, clients can choose to ignore it and avoid
      * including any initial settings. If parameters are present, then hal must examine
      * their values and configure the internal camera pipeline accordingly.
+     *
+     * A null pointer is equivalent to a valid CameraMetadata object with zero entries.
+     *
+     * For a StreamConfiguration passed to ICameraDevice.isStreamCombinationWithSettingsSupported
+     * or ICameraDevice.getSessionCharacteristics, this variable may also contain keys
+     * that are not session parameters, but are used to specify certain features for a
+     * session. For example, CONTROL_VIDEO_STABILIZATION_MODE may be included even if it's not a
+     * session parameter.
      */
     CameraMetadata sessionParams;
 
diff --git a/camera/device/default/Android.bp b/camera/device/default/Android.bp
index b577597..5fbcb5d 100644
--- a/camera/device/default/Android.bp
+++ b/camera/device/default/Android.bp
@@ -25,7 +25,10 @@
 
 cc_library_shared {
     name: "camera.device-external-impl",
-    defaults: ["hidl_defaults"],
+    defaults: [
+        "android.hardware.graphics.common-ndk_shared",
+        "hidl_defaults",
+    ],
     proprietary: true,
     srcs: [
         "ExternalCameraDevice.cpp",
@@ -37,8 +40,7 @@
     shared_libs: [
         "android.hardware.camera.common-V1-ndk",
         "android.hardware.camera.device-V1-ndk",
-        "android.hardware.graphics.allocator-V1-ndk",
-        "android.hardware.graphics.common-V4-ndk",
+        "android.hardware.graphics.allocator-V2-ndk",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@3.0",
         "android.hardware.graphics.mapper@4.0",
@@ -58,6 +60,7 @@
         "libsync",
         "libtinyxml2",
         "libutils",
+        "libui",
         "libyuv",
     ],
     static_libs: [
diff --git a/camera/device/default/ExternalCameraDevice.cpp b/camera/device/default/ExternalCameraDevice.cpp
index 677fb42..8e84748 100644
--- a/camera/device/default/ExternalCameraDevice.cpp
+++ b/camera/device/default/ExternalCameraDevice.cpp
@@ -399,6 +399,10 @@
     const uint8_t hotPixelMode = ANDROID_HOT_PIXEL_MODE_OFF;
     UPDATE(ANDROID_HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES, &hotPixelMode, 1);
 
+    // android.info
+    const uint8_t bufMgrVer = ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5;
+    UPDATE(ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION, &bufMgrVer, 1);
+
     // android.jpeg
     const int32_t jpegAvailableThumbnailSizes[] = {0,   0,   176, 144, 240, 144, 256,
                                                    144, 240, 160, 256, 154, 240, 180};
@@ -493,6 +497,9 @@
     const int32_t maxLatency = ANDROID_SYNC_MAX_LATENCY_UNKNOWN;
     UPDATE(ANDROID_SYNC_MAX_LATENCY, &maxLatency, 1);
 
+    const uint8_t sensorReadoutTimestamp = ANDROID_SENSOR_READOUT_TIMESTAMP_NOT_SUPPORTED;
+    UPDATE(ANDROID_SENSOR_READOUT_TIMESTAMP, &sensorReadoutTimestamp, 1);
+
     /* Other sensor/RAW related keys:
      * android.sensor.info.colorFilterArrangement -> no need if we don't do RAW
      * android.sensor.info.physicalSize           -> not available
@@ -998,4 +1005,4 @@
 }  // namespace device
 }  // namespace camera
 }  // namespace hardware
-}  // namespace android
\ No newline at end of file
+}  // namespace android
diff --git a/camera/device/default/ExternalCameraDeviceSession.cpp b/camera/device/default/ExternalCameraDeviceSession.cpp
index c962974..a16dd7f 100644
--- a/camera/device/default/ExternalCameraDeviceSession.cpp
+++ b/camera/device/default/ExternalCameraDeviceSession.cpp
@@ -224,10 +224,6 @@
 }
 
 void ExternalCameraDeviceSession::closeOutputThread() {
-    closeOutputThreadImpl();
-}
-
-void ExternalCameraDeviceSession::closeOutputThreadImpl() {
     if (mOutputThread != nullptr) {
         mOutputThread->flush();
         mOutputThread->requestExitAndWait();
@@ -235,6 +231,13 @@
     }
 }
 
+void ExternalCameraDeviceSession::closeBufferRequestThread() {
+    if (mBufferRequestThread != nullptr) {
+        mBufferRequestThread->requestExitAndWait();
+        mBufferRequestThread.reset();
+    }
+}
+
 Status ExternalCameraDeviceSession::initStatus() const {
     Mutex::Autolock _l(mLock);
     Status status = Status::OK;
@@ -248,7 +251,7 @@
 ExternalCameraDeviceSession::~ExternalCameraDeviceSession() {
     if (!isClosed()) {
         ALOGE("ExternalCameraDeviceSession deleted before close!");
-        close(/*callerIsDtor*/ true);
+        closeImpl();
     }
 }
 
@@ -788,7 +791,8 @@
                 if (buffer.acquireFence >= 0) {
                     native_handle_t* handle = native_handle_create(/*numFds*/ 1, /*numInts*/ 0);
                     handle->data[0] = buffer.acquireFence;
-                    outputBuffer.releaseFence = android::makeToAidl(handle);
+                    outputBuffer.releaseFence = android::dupToAidl(handle);
+                    native_handle_delete(handle);
                 }
             } else {
                 offlineBuffers.push_back(buffer);
@@ -1387,12 +1391,14 @@
 
     // All buffers are imported. Now validate output buffer acquire fences
     for (size_t i = 0; i < numOutputBufs; i++) {
-        if (!sHandleImporter.importFence(
-                    ::android::makeFromAidl(request.outputBuffers[i].acquireFence), allFences[i])) {
+        native_handle_t* h = ::android::makeFromAidl(request.outputBuffers[i].acquireFence);
+        if (!sHandleImporter.importFence(h, allFences[i])) {
             ALOGE("%s: output buffer %zu acquire fence is invalid", __FUNCTION__, i);
             cleanupInflightFences(allFences, i);
+            native_handle_delete(h);
             return Status::INTERNAL_ERROR;
         }
+        native_handle_delete(h);
     }
     return Status::OK;
 }
@@ -1411,19 +1417,16 @@
 }
 
 ScopedAStatus ExternalCameraDeviceSession::close() {
-    close(false);
+    closeImpl();
     return fromStatus(Status::OK);
 }
 
-void ExternalCameraDeviceSession::close(bool callerIsDtor) {
+void ExternalCameraDeviceSession::closeImpl() {
     Mutex::Autolock _il(mInterfaceLock);
     bool closed = isClosed();
     if (!closed) {
-        if (callerIsDtor) {
-            closeOutputThreadImpl();
-        } else {
-            closeOutputThread();
-        }
+        closeOutputThread();
+        closeBufferRequestThread();
 
         Mutex::Autolock _l(mLock);
         // free all buffers
@@ -1771,7 +1774,8 @@
         if (req->buffers[i].acquireFence >= 0) {
             native_handle_t* handle = native_handle_create(/*numFds*/ 1, /*numInts*/ 0);
             handle->data[0] = req->buffers[i].acquireFence;
-            result.outputBuffers[i].releaseFence = ::android::makeToAidl(handle);
+            result.outputBuffers[i].releaseFence = android::dupToAidl(handle);
+            native_handle_delete(handle);
         }
     }
 
@@ -1817,7 +1821,8 @@
             if (req->buffers[i].acquireFence >= 0) {
                 native_handle_t* handle = native_handle_create(/*numFds*/ 1, /*numInts*/ 0);
                 handle->data[0] = req->buffers[i].acquireFence;
-                result.outputBuffers[i].releaseFence = ::android::makeToAidl(handle);
+                result.outputBuffers[i].releaseFence = android::dupToAidl(handle);
+                native_handle_delete(handle);
             }
             notifyError(req->frameNumber, req->buffers[i].streamId, ErrorCode::ERROR_BUFFER);
         } else {
@@ -1826,7 +1831,8 @@
             if (req->buffers[i].acquireFence >= 0) {
                 native_handle_t* handle = native_handle_create(/*numFds*/ 1, /*numInts*/ 0);
                 handle->data[0] = req->buffers[i].acquireFence;
-                result.outputBuffers[i].releaseFence = ::android::makeToAidl(handle);
+                result.outputBuffers[i].releaseFence = android::dupToAidl(handle);
+                native_handle_delete(handle);
             }
         }
     }
@@ -2090,9 +2096,10 @@
                     // TODO: create a batch import API so we don't need to lock/unlock mCbsLock
                     // repeatedly?
                     lk.unlock();
-                    Status s =
-                            parent->importBuffer(streamId, hBuf.bufferId, makeFromAidl(hBuf.buffer),
-                                                 /*out*/ &mBufferReqs[i].bufPtr);
+                    native_handle_t* h = makeFromAidl(hBuf.buffer);
+                    Status s = parent->importBuffer(streamId, hBuf.bufferId, h,
+                                                    /*out*/ &mBufferReqs[i].bufPtr);
+                    native_handle_delete(h);
                     lk.lock();
 
                     if (s != Status::OK) {
@@ -2100,12 +2107,14 @@
                         cleanupInflightFences(importedFences, i - 1);
                         return false;
                     }
-                    if (!sHandleImporter.importFence(makeFromAidl(hBuf.acquireFence),
-                                                     mBufferReqs[i].acquireFence)) {
+                    h = makeFromAidl(hBuf.acquireFence);
+                    if (!sHandleImporter.importFence(h, mBufferReqs[i].acquireFence)) {
                         ALOGE("%s: stream %d import fence failed!", __FUNCTION__, streamId);
                         cleanupInflightFences(importedFences, i - 1);
+                        native_handle_delete(h);
                         return false;
                     }
+                    native_handle_delete(h);
                     importedFences[i] = mBufferReqs[i].acquireFence;
                 } break;
                 default:
@@ -2882,13 +2891,23 @@
             } break;
             case PixelFormat::YCBCR_420_888:
             case PixelFormat::YV12: {
-                IMapper::Rect outRect{0, 0, static_cast<int32_t>(halBuf.width),
+                android::Rect outRect{0, 0, static_cast<int32_t>(halBuf.width),
                                       static_cast<int32_t>(halBuf.height)};
-                YCbCrLayout outLayout = sHandleImporter.lockYCbCr(
+                android_ycbcr result = sHandleImporter.lockYCbCr(
                         *(halBuf.bufPtr), static_cast<uint64_t>(halBuf.usage), outRect);
-                ALOGV("%s: outLayout y %p cb %p cr %p y_str %d c_str %d c_step %d", __FUNCTION__,
-                      outLayout.y, outLayout.cb, outLayout.cr, outLayout.yStride, outLayout.cStride,
-                      outLayout.chromaStep);
+                ALOGV("%s: outLayout y %p cb %p cr %p y_str %zu c_str %zu c_step %zu", __FUNCTION__,
+                      result.y, result.cb, result.cr, result.ystride, result.cstride,
+                      result.chroma_step);
+                if (result.ystride > UINT32_MAX || result.cstride > UINT32_MAX ||
+                    result.chroma_step > UINT32_MAX) {
+                    return onDeviceError("%s: lockYCbCr failed. Unexpected values!", __FUNCTION__);
+                }
+                YCbCrLayout outLayout = {.y = result.y,
+                                         .cb = result.cb,
+                                         .cr = result.cr,
+                                         .yStride = static_cast<uint32_t>(result.ystride),
+                                         .cStride = static_cast<uint32_t>(result.cstride),
+                                         .chromaStep = static_cast<uint32_t>(result.chroma_step)};
 
                 // Convert to output buffer size/format
                 uint32_t outputFourcc = getFourCcFromLayout(outLayout);
diff --git a/camera/device/default/ExternalCameraDeviceSession.h b/camera/device/default/ExternalCameraDeviceSession.h
index e7eb799..736bfd1 100644
--- a/camera/device/default/ExternalCameraDeviceSession.h
+++ b/camera/device/default/ExternalCameraDeviceSession.h
@@ -24,6 +24,9 @@
 #include <aidl/android/hardware/camera/device/BufferRequest.h>
 #include <aidl/android/hardware/camera/device/Stream.h>
 #include <android-base/unique_fd.h>
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <android/hardware/graphics/mapper/3.0/IMapper.h>
+#include <android/hardware/graphics/mapper/4.0/IMapper.h>
 #include <fmq/AidlMessageQueue.h>
 #include <utils/Thread.h>
 #include <deque>
@@ -55,6 +58,7 @@
 using ::android::hardware::camera::common::helper::SimpleThread;
 using ::android::hardware::camera::external::common::ExternalCameraConfig;
 using ::android::hardware::camera::external::common::SizeHasher;
+using ::android::hardware::graphics::mapper::V2_0::YCbCrLayout;
 using ::ndk::ScopedAStatus;
 
 class ExternalCameraDeviceSession : public BnCameraDeviceSession, public OutputThreadInterface {
@@ -240,9 +244,9 @@
     // To init/close different version of output thread
     void initOutputThread();
     void closeOutputThread();
-    void closeOutputThreadImpl();
+    void closeBufferRequestThread();
 
-    void close(bool callerIsDtor);
+    void closeImpl();
     Status initStatus() const;
     status_t initDefaultRequests();
 
diff --git a/camera/device/default/ExternalCameraOfflineSession.cpp b/camera/device/default/ExternalCameraOfflineSession.cpp
index 4c7f732..2d4e2e0 100644
--- a/camera/device/default/ExternalCameraOfflineSession.cpp
+++ b/camera/device/default/ExternalCameraOfflineSession.cpp
@@ -110,7 +110,8 @@
             if (req->buffers[i].acquireFence >= 0) {
                 native_handle_t* handle = native_handle_create(/*numFds*/ 1, /*numInts*/ 0);
                 handle->data[0] = req->buffers[i].acquireFence;
-                result.outputBuffers[i].releaseFence = android::makeToAidl(handle);
+                result.outputBuffers[i].releaseFence = android::dupToAidl(handle);
+                native_handle_delete(handle);
             }
             notifyError(req->frameNumber, req->buffers[i].streamId, ErrorCode::ERROR_BUFFER);
         } else {
@@ -119,7 +120,8 @@
             if (req->buffers[i].acquireFence >= 0) {
                 native_handle_t* handle = native_handle_create(/*numFds*/ 1, /*numInts*/ 0);
                 handle->data[0] = req->buffers[i].acquireFence;
-                outputBuffer.releaseFence = android::makeToAidl(handle);
+                outputBuffer.releaseFence = android::dupToAidl(handle);
+                native_handle_delete(handle);
             }
         }
     }
@@ -247,7 +249,8 @@
         if (req->buffers[i].acquireFence >= 0) {
             native_handle_t* handle = native_handle_create(/*numFds*/ 1, /*numInts*/ 0);
             handle->data[0] = req->buffers[i].acquireFence;
-            outputBuffer.releaseFence = makeToAidl(handle);
+            outputBuffer.releaseFence = dupToAidl(handle);
+            native_handle_delete(handle);
         }
     }
 
@@ -486,13 +489,23 @@
             } break;
             case PixelFormat::YCBCR_420_888:
             case PixelFormat::YV12: {
-                IMapper::Rect outRect{0, 0, static_cast<int32_t>(halBuf.width),
+                android::Rect outRect{0, 0, static_cast<int32_t>(halBuf.width),
                                       static_cast<int32_t>(halBuf.height)};
-                YCbCrLayout outLayout = sHandleImporter.lockYCbCr(
+                android_ycbcr result = sHandleImporter.lockYCbCr(
                         *(halBuf.bufPtr), static_cast<uint64_t>(halBuf.usage), outRect);
-                ALOGV("%s: outLayout y %p cb %p cr %p y_str %d c_str %d c_step %d", __FUNCTION__,
-                      outLayout.y, outLayout.cb, outLayout.cr, outLayout.yStride, outLayout.cStride,
-                      outLayout.chromaStep);
+                ALOGV("%s: outLayout y %p cb %p cr %p y_str %zu c_str %zu c_step %zu", __FUNCTION__,
+                      result.y, result.cb, result.cr, result.ystride, result.cstride,
+                      result.chroma_step);
+                if (result.ystride > UINT32_MAX || result.cstride > UINT32_MAX ||
+                    result.chroma_step > UINT32_MAX) {
+                    return onDeviceError("%s: lockYCbCr failed. Unexpected values!", __FUNCTION__);
+                }
+                YCbCrLayout outLayout = {.y = result.y,
+                                         .cb = result.cb,
+                                         .cr = result.cr,
+                                         .yStride = static_cast<uint32_t>(result.ystride),
+                                         .cStride = static_cast<uint32_t>(result.cstride),
+                                         .chromaStep = static_cast<uint32_t>(result.chroma_step)};
 
                 // Convert to output buffer size/format
                 uint32_t outputFourcc = getFourCcFromLayout(outLayout);
@@ -544,4 +557,4 @@
 }  // namespace device
 }  // namespace camera
 }  // namespace hardware
-}  // namespace android
\ No newline at end of file
+}  // namespace android
diff --git a/camera/device/default/ExternalCameraUtils.cpp b/camera/device/default/ExternalCameraUtils.cpp
index cfb95f2..2dc3c77 100644
--- a/camera/device/default/ExternalCameraUtils.cpp
+++ b/camera/device/default/ExternalCameraUtils.cpp
@@ -402,7 +402,10 @@
         buffer_handle_t buf,
         /*out*/ buffer_handle_t** outBufPtr) {
     using ::aidl::android::hardware::camera::common::Status;
-    if (buf == nullptr && bufId == BUFFER_ID_NO_BUFFER) {
+    // AIDL does not have null NativeHandles. It sends empty handles instead.
+    // We check for when the buf is empty instead of when buf is null.
+    bool isBufEmpty = buf == nullptr || (buf->numFds == 0 && buf->numInts == 0);
+    if (isBufEmpty && bufId == BUFFER_ID_NO_BUFFER) {
         ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId);
         return Status::ILLEGAL_ARGUMENT;
     }
@@ -747,18 +750,12 @@
 
 void freeReleaseFences(std::vector<CaptureResult>& results) {
     for (auto& result : results) {
-        native_handle_t* inputReleaseFence =
-                ::android::makeFromAidl(result.inputBuffer.releaseFence);
-        if (inputReleaseFence != nullptr) {
-            native_handle_close(inputReleaseFence);
-            native_handle_delete(inputReleaseFence);
-        }
+        // NativeHandles free fd's on desctruction. Simply delete the objects!
+        result.inputBuffer.releaseFence.fds.clear();  // Implicitly closes fds
+        result.inputBuffer.releaseFence.ints.clear();
         for (auto& buf : result.outputBuffers) {
-            native_handle_t* outReleaseFence = ::android::makeFromAidl(buf.releaseFence);
-            if (outReleaseFence != nullptr) {
-                native_handle_close(outReleaseFence);
-                native_handle_delete(outReleaseFence);
-            }
+            buf.releaseFence.fds.clear();  // Implicitly closes fds
+            buf.releaseFence.ints.clear();
         }
     }
 }
@@ -857,4 +854,4 @@
 }  // namespace device
 }  // namespace camera
 }  // namespace hardware
-}  // namespace android
\ No newline at end of file
+}  // namespace android
diff --git a/camera/device/default/ExternalCameraUtils.h b/camera/device/default/ExternalCameraUtils.h
index b37933c..d434905 100644
--- a/camera/device/default/ExternalCameraUtils.h
+++ b/camera/device/default/ExternalCameraUtils.h
@@ -25,7 +25,11 @@
 #include <aidl/android/hardware/camera/device/NotifyMsg.h>
 #include <aidl/android/hardware/graphics/common/BufferUsage.h>
 #include <aidl/android/hardware/graphics/common/PixelFormat.h>
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <android/hardware/graphics/mapper/3.0/IMapper.h>
+#include <android/hardware/graphics/mapper/4.0/IMapper.h>
 #include <tinyxml2.h>
+#include <map>
 #include <unordered_map>
 #include <unordered_set>
 
@@ -37,6 +41,8 @@
 using ::aidl::android::hardware::graphics::common::PixelFormat;
 using ::android::hardware::camera::common::V1_0::helper::CameraMetadata;
 using ::android::hardware::camera::common::V1_0::helper::HandleImporter;
+using ::android::hardware::graphics::mapper::V2_0::IMapper;
+using ::android::hardware::graphics::mapper::V2_0::YCbCrLayout;
 
 namespace android {
 namespace hardware {
diff --git a/camera/metadata/aidl/Android.bp b/camera/metadata/aidl/Android.bp
index 5872a86..2b2be55 100644
--- a/camera/metadata/aidl/Android.bp
+++ b/camera/metadata/aidl/Android.bp
@@ -11,7 +11,7 @@
     name: "android.hardware.camera.metadata",
     vendor_available: true,
     srcs: ["android/hardware/camera/metadata/*.aidl"],
-    frozen: true,
+    frozen: false,
     stability: "vintf",
     backend: {
         cpp: {
diff --git a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataTag.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataTag.aidl
index 71d4e41..9321ec0 100644
--- a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataTag.aidl
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataTag.aidl
@@ -98,6 +98,8 @@
   ANDROID_CONTROL_AUTOFRAMING,
   ANDROID_CONTROL_AUTOFRAMING_AVAILABLE,
   ANDROID_CONTROL_AUTOFRAMING_STATE,
+  ANDROID_CONTROL_LOW_LIGHT_BOOST_INFO_LUMINANCE_RANGE,
+  ANDROID_CONTROL_LOW_LIGHT_BOOST_STATE,
   ANDROID_DEMOSAIC_MODE = android.hardware.camera.metadata.CameraMetadataSectionStart.ANDROID_DEMOSAIC_START /* 131072 */,
   ANDROID_EDGE_MODE = android.hardware.camera.metadata.CameraMetadataSectionStart.ANDROID_EDGE_START /* 196608 */,
   ANDROID_EDGE_STRENGTH,
@@ -108,6 +110,11 @@
   ANDROID_FLASH_COLOR_TEMPERATURE,
   ANDROID_FLASH_MAX_ENERGY,
   ANDROID_FLASH_STATE,
+  ANDROID_FLASH_STRENGTH_LEVEL,
+  ANDROID_FLASH_SINGLE_STRENGTH_MAX_LEVEL,
+  ANDROID_FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL,
+  ANDROID_FLASH_TORCH_STRENGTH_MAX_LEVEL,
+  ANDROID_FLASH_TORCH_STRENGTH_DEFAULT_LEVEL,
   ANDROID_FLASH_INFO_AVAILABLE = android.hardware.camera.metadata.CameraMetadataSectionStart.ANDROID_FLASH_INFO_START /* 327680 */,
   ANDROID_FLASH_INFO_CHARGE_DURATION,
   ANDROID_FLASH_INFO_STRENGTH_MAXIMUM_LEVEL,
@@ -239,6 +246,7 @@
   ANDROID_SENSOR_OPAQUE_RAW_SIZE_MAXIMUM_RESOLUTION,
   ANDROID_SENSOR_PIXEL_MODE,
   ANDROID_SENSOR_RAW_BINNING_FACTOR_USED,
+  ANDROID_SENSOR_READOUT_TIMESTAMP,
   ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE = android.hardware.camera.metadata.CameraMetadataSectionStart.ANDROID_SENSOR_INFO_START /* 983040 */,
   ANDROID_SENSOR_INFO_SENSITIVITY_RANGE,
   ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT,
@@ -278,6 +286,8 @@
   ANDROID_STATISTICS_OIS_TIMESTAMPS,
   ANDROID_STATISTICS_OIS_X_SHIFTS,
   ANDROID_STATISTICS_OIS_Y_SHIFTS,
+  ANDROID_STATISTICS_LENS_INTRINSIC_TIMESTAMPS,
+  ANDROID_STATISTICS_LENS_INTRINSIC_SAMPLES,
   ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES = android.hardware.camera.metadata.CameraMetadataSectionStart.ANDROID_STATISTICS_INFO_START /* 1179648 */,
   ANDROID_STATISTICS_INFO_HISTOGRAM_BUCKET_COUNT,
   ANDROID_STATISTICS_INFO_MAX_FACE_COUNT,
@@ -324,6 +334,7 @@
   ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS = android.hardware.camera.metadata.CameraMetadataSectionStart.ANDROID_LOGICAL_MULTI_CAMERA_START /* 1703936 */,
   ANDROID_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE,
   ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID,
+  ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_SENSOR_CROP_REGION,
   ANDROID_DISTORTION_CORRECTION_MODE = android.hardware.camera.metadata.CameraMetadataSectionStart.ANDROID_DISTORTION_CORRECTION_START /* 1769472 */,
   ANDROID_DISTORTION_CORRECTION_AVAILABLE_MODES,
   ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS = android.hardware.camera.metadata.CameraMetadataSectionStart.ANDROID_HEIC_START /* 1835008 */,
diff --git a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ControlAeMode.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ControlAeMode.aidl
index 5e1b871..c1423aa 100644
--- a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ControlAeMode.aidl
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ControlAeMode.aidl
@@ -44,4 +44,5 @@
   ANDROID_CONTROL_AE_MODE_ON_ALWAYS_FLASH,
   ANDROID_CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE,
   ANDROID_CONTROL_AE_MODE_ON_EXTERNAL_FLASH,
+  ANDROID_CONTROL_AE_MODE_ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY,
 }
diff --git a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ControlLowLightBoostState.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ControlLowLightBoostState.aidl
new file mode 100644
index 0000000..f8ae013
--- /dev/null
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ControlLowLightBoostState.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *//*
+ * Autogenerated from camera metadata definitions in
+ * /system/media/camera/docs/metadata_definitions.xml
+ * *** DO NOT EDIT BY HAND ***
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.camera.metadata;
+@Backing(type="int") @VintfStability
+enum ControlLowLightBoostState {
+  ANDROID_CONTROL_LOW_LIGHT_BOOST_STATE_INACTIVE,
+  ANDROID_CONTROL_LOW_LIGHT_BOOST_STATE_ACTIVE,
+}
diff --git a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/InfoSupportedBufferManagementVersion.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/InfoSupportedBufferManagementVersion.aidl
index 7303ff5..2c31cff 100644
--- a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/InfoSupportedBufferManagementVersion.aidl
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/InfoSupportedBufferManagementVersion.aidl
@@ -39,4 +39,5 @@
 @Backing(type="int") @VintfStability
 enum InfoSupportedBufferManagementVersion {
   ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_AIDL_DEVICE,
+  ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_SESSION_CONFIGURABLE,
 }
diff --git a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/SensorReadoutTimestamp.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/SensorReadoutTimestamp.aidl
new file mode 100644
index 0000000..35dc1a9
--- /dev/null
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/SensorReadoutTimestamp.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *//*
+ * Autogenerated from camera metadata definitions in
+ * /system/media/camera/docs/metadata_definitions.xml
+ * *** DO NOT EDIT BY HAND ***
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.camera.metadata;
+@Backing(type="int") @VintfStability
+enum SensorReadoutTimestamp {
+  ANDROID_SENSOR_READOUT_TIMESTAMP_NOT_SUPPORTED,
+  ANDROID_SENSOR_READOUT_TIMESTAMP_HARDWARE,
+}
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl
index 3303ff9..f133372 100644
--- a/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl
@@ -490,6 +490,18 @@
      */
     ANDROID_CONTROL_AUTOFRAMING_STATE,
     /**
+     * android.control.lowLightBoostInfoLuminanceRange [static, float[], public]
+     *
+     * <p>The operating luminance range of low light boost measured in lux (lx).</p>
+     */
+    ANDROID_CONTROL_LOW_LIGHT_BOOST_INFO_LUMINANCE_RANGE,
+    /**
+     * android.control.lowLightBoostState [dynamic, enum, public]
+     *
+     * <p>Current state of the low light boost AE mode.</p>
+     */
+    ANDROID_CONTROL_LOW_LIGHT_BOOST_STATE,
+    /**
      * android.demosaic.mode [controls, enum, system]
      *
      * <p>Controls the quality of the demosaicing
@@ -560,6 +572,36 @@
      */
     ANDROID_FLASH_STATE,
     /**
+     * android.flash.strengthLevel [dynamic, int32, public]
+     *
+     * <p>Flash strength level to be used when manual flash control is active.</p>
+     */
+    ANDROID_FLASH_STRENGTH_LEVEL,
+    /**
+     * android.flash.singleStrengthMaxLevel [static, int32, public]
+     *
+     * <p>Maximum flash brightness level for manual flash control in SINGLE mode.</p>
+     */
+    ANDROID_FLASH_SINGLE_STRENGTH_MAX_LEVEL,
+    /**
+     * android.flash.singleStrengthDefaultLevel [static, int32, public]
+     *
+     * <p>Default flash brightness level for manual flash control in SINGLE mode.</p>
+     */
+    ANDROID_FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL,
+    /**
+     * android.flash.torchStrengthMaxLevel [static, int32, public]
+     *
+     * <p>Maximum flash brightness level for manual flash control in TORCH mode</p>
+     */
+    ANDROID_FLASH_TORCH_STRENGTH_MAX_LEVEL,
+    /**
+     * android.flash.torchStrengthDefaultLevel [static, int32, public]
+     *
+     * <p>Default flash brightness level for manual flash control in TORCH mode</p>
+     */
+    ANDROID_FLASH_TORCH_STRENGTH_DEFAULT_LEVEL,
+    /**
      * android.flash.info.available [static, enum, public]
      *
      * <p>Whether this camera device has a
@@ -1300,8 +1342,8 @@
     /**
      * android.sensor.frameDuration [dynamic, int64, public]
      *
-     * <p>Duration from start of frame exposure to
-     * start of next frame exposure.</p>
+     * <p>Duration from start of frame readout to
+     * start of next frame readout.</p>
      */
     ANDROID_SENSOR_FRAME_DURATION,
     /**
@@ -1549,6 +1591,13 @@
      */
     ANDROID_SENSOR_RAW_BINNING_FACTOR_USED,
     /**
+     * android.sensor.readoutTimestamp [static, enum, java_public]
+     *
+     * <p>Whether or not the camera device supports readout timestamp and
+     * {@code onReadoutStarted} callback.</p>
+     */
+    ANDROID_SENSOR_READOUT_TIMESTAMP,
+    /**
      * android.sensor.info.activeArraySize [static, int32[], public]
      *
      * <p>The area of the image sensor which corresponds to active pixels after any geometric
@@ -1838,6 +1887,18 @@
      */
     ANDROID_STATISTICS_OIS_Y_SHIFTS,
     /**
+     * android.statistics.lensIntrinsicTimestamps [dynamic, int64[], ndk_public]
+     *
+     * <p>An array of timestamps of lens intrinsics samples, in nanoseconds.</p>
+     */
+    ANDROID_STATISTICS_LENS_INTRINSIC_TIMESTAMPS,
+    /**
+     * android.statistics.lensIntrinsicSamples [dynamic, float[], ndk_public]
+     *
+     * <p>An array of intra-frame lens intrinsics.</p>
+     */
+    ANDROID_STATISTICS_LENS_INTRINSIC_SAMPLES,
+    /**
      * android.statistics.info.availableFaceDetectModes [static, byte[], public]
      *
      * <p>List of face detection modes for ANDROID_STATISTICS_FACE_DETECT_MODE that are
@@ -2211,6 +2272,13 @@
      */
     ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID,
     /**
+     * android.logicalMultiCamera.activePhysicalSensorCropRegion [dynamic, int32[], public]
+     *
+     * <p>The current region of the active physical sensor that will be read out for this
+     * capture.</p>
+     */
+    ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_SENSOR_CROP_REGION,
+    /**
      * android.distortionCorrection.mode [dynamic, enum, public]
      *
      * <p>Mode of operation for the lens distortion correction block.</p>
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/ControlAeMode.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/ControlAeMode.aidl
index e2f5553..70174be 100644
--- a/camera/metadata/aidl/android/hardware/camera/metadata/ControlAeMode.aidl
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/ControlAeMode.aidl
@@ -35,4 +35,5 @@
     ANDROID_CONTROL_AE_MODE_ON_ALWAYS_FLASH,
     ANDROID_CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE,
     ANDROID_CONTROL_AE_MODE_ON_EXTERNAL_FLASH,
+    ANDROID_CONTROL_AE_MODE_ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY,
 }
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/ControlLowLightBoostState.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/ControlLowLightBoostState.aidl
new file mode 100644
index 0000000..67591c8
--- /dev/null
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/ControlLowLightBoostState.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Autogenerated from camera metadata definitions in
+ * /system/media/camera/docs/metadata_definitions.xml
+ * *** DO NOT EDIT BY HAND ***
+ */
+
+package android.hardware.camera.metadata;
+
+/**
+ * android.control.lowLightBoostState enumeration values
+ * @see ANDROID_CONTROL_LOW_LIGHT_BOOST_STATE
+ */
+@VintfStability
+@Backing(type="int")
+enum ControlLowLightBoostState {
+    ANDROID_CONTROL_LOW_LIGHT_BOOST_STATE_INACTIVE,
+    ANDROID_CONTROL_LOW_LIGHT_BOOST_STATE_ACTIVE,
+}
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/InfoSupportedBufferManagementVersion.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/InfoSupportedBufferManagementVersion.aidl
index 9522377..964d079 100644
--- a/camera/metadata/aidl/android/hardware/camera/metadata/InfoSupportedBufferManagementVersion.aidl
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/InfoSupportedBufferManagementVersion.aidl
@@ -30,4 +30,5 @@
 @Backing(type="int")
 enum InfoSupportedBufferManagementVersion {
     ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_AIDL_DEVICE,
+    ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_SESSION_CONFIGURABLE,
 }
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/SensorReadoutTimestamp.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/SensorReadoutTimestamp.aidl
new file mode 100644
index 0000000..1678515
--- /dev/null
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/SensorReadoutTimestamp.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Autogenerated from camera metadata definitions in
+ * /system/media/camera/docs/metadata_definitions.xml
+ * *** DO NOT EDIT BY HAND ***
+ */
+
+package android.hardware.camera.metadata;
+
+/**
+ * android.sensor.readoutTimestamp enumeration values
+ * @see ANDROID_SENSOR_READOUT_TIMESTAMP
+ */
+@VintfStability
+@Backing(type="int")
+enum SensorReadoutTimestamp {
+    ANDROID_SENSOR_READOUT_TIMESTAMP_NOT_SUPPORTED,
+    ANDROID_SENSOR_READOUT_TIMESTAMP_HARDWARE,
+}
diff --git a/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp b/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp
index 4fc7437..2d919cc 100644
--- a/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp
+++ b/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp
@@ -18,15 +18,16 @@
 //#define LOG_NDEBUG 0
 #include <log/log.h>
 
-#include <regex>
-#include <sys/inotify.h>
+#include <cutils/properties.h>
 #include <errno.h>
 #include <linux/videodev2.h>
-#include <cutils/properties.h>
-#include "ExternalCameraProviderImpl_2_4.h"
+#include <sys/inotify.h>
+#include <regex>
+#include <string>
 #include "ExternalCameraDevice_3_4.h"
 #include "ExternalCameraDevice_3_5.h"
 #include "ExternalCameraDevice_3_6.h"
+#include "ExternalCameraProviderImpl_2_4.h"
 
 namespace android {
 namespace hardware {
@@ -41,10 +42,10 @@
 // "device@<version>/external/<id>"
 const std::regex kDeviceNameRE("device@([0-9]+\\.[0-9]+)/external/(.+)");
 const int kMaxDevicePathLen = 256;
-const char* kDevicePath = "/dev/";
-constexpr char kPrefix[] = "video";
-constexpr int kPrefixLen = sizeof(kPrefix) - 1;
-constexpr int kDevicePrefixLen = sizeof(kDevicePath) + kPrefixLen + 1;
+constexpr const char* kDevicePath = "/dev/";
+constexpr const char* kPrefix = "video";
+constexpr int kPrefixLen = std::char_traits<char>::length(kPrefix);
+constexpr int kDevicePrefixLen = std::char_traits<char>::length(kDevicePath) + kPrefixLen;
 
 bool matchDeviceName(int cameraIdOffset,
                      const hidl_string& deviceName, std::string* deviceVersion,
@@ -94,13 +95,14 @@
 
 Return<Status> ExternalCameraProviderImpl_2_4::setCallback(
         const sp<ICameraProviderCallback>& callback) {
+    if (callback == nullptr) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
     {
         Mutex::Autolock _l(mLock);
         mCallbacks = callback;
     }
-    if (mCallbacks == nullptr) {
-        return Status::OK;
-    }
     // Send a callback for all devices to initialize
     {
         for (const auto& pair : mCameraStatusMap) {
diff --git a/camera/provider/2.4/default/LegacyCameraProviderImpl_2_4.cpp b/camera/provider/2.4/default/LegacyCameraProviderImpl_2_4.cpp
index 7c3b982..07ed689 100644
--- a/camera/provider/2.4/default/LegacyCameraProviderImpl_2_4.cpp
+++ b/camera/provider/2.4/default/LegacyCameraProviderImpl_2_4.cpp
@@ -439,7 +439,7 @@
     }
     mVendorTagSections.resize(numSections);
     for (size_t s = 0; s < numSections; s++) {
-        mVendorTagSections[s].sectionName = (*sectionNames)[s].string();
+        mVendorTagSections[s].sectionName = (*sectionNames)[s].c_str();
         mVendorTagSections[s].tags = tagsBySection[s];
     }
     return true;
@@ -448,11 +448,11 @@
 // Methods from ::android::hardware::camera::provider::V2_4::ICameraProvider follow.
 Return<Status> LegacyCameraProviderImpl_2_4::setCallback(
         const sp<ICameraProviderCallback>& callback) {
+    if (callback == nullptr) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
     Mutex::Autolock _l(mCbLock);
     mCallbacks = callback;
-    if (mCallbacks == nullptr) {
-        return Status::OK;
-    }
     // Add and report all presenting external cameras.
     for (auto const& statusPair : mCameraStatusMap) {
         int id = std::stoi(statusPair.first);
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index 339a142..c8e683c 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -244,7 +244,7 @@
                          std::string* deviceVersion, std::string* cameraId) {
         ::android::String8 pattern;
         pattern.appendFormat(kDeviceNameRE, providerType.c_str());
-        std::regex e(pattern.string());
+        std::regex e(pattern.c_str());
         std::string deviceNameStd(deviceName.c_str());
         std::smatch sm;
         if (std::regex_match(deviceNameStd, sm, e)) {
@@ -8801,8 +8801,7 @@
 void CameraHidlTest::setParameters(
         const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device,
         const CameraParameters &cameraParams) {
-    Return<Status> returnStatus = device->setParameters(
-            cameraParams.flatten().string());
+    Return<Status> returnStatus = device->setParameters(cameraParams.flatten().c_str());
     ASSERT_TRUE(returnStatus.isOk());
     ASSERT_EQ(Status::OK, returnStatus);
 }
diff --git a/camera/provider/2.7/default/ExternalCameraProviderImpl_2_7.cpp b/camera/provider/2.7/default/ExternalCameraProviderImpl_2_7.cpp
index b63e3bb..eba49a5 100644
--- a/camera/provider/2.7/default/ExternalCameraProviderImpl_2_7.cpp
+++ b/camera/provider/2.7/default/ExternalCameraProviderImpl_2_7.cpp
@@ -23,6 +23,7 @@
 #include <linux/videodev2.h>
 #include <sys/inotify.h>
 #include <regex>
+#include <string>
 #include "ExternalCameraDevice_3_4.h"
 #include "ExternalCameraDevice_3_5.h"
 #include "ExternalCameraDevice_3_6.h"
@@ -39,10 +40,10 @@
 // "device@<version>/external/<id>"
 const std::regex kDeviceNameRE("device@([0-9]+\\.[0-9]+)/external/(.+)");
 const int kMaxDevicePathLen = 256;
-const char* kDevicePath = "/dev/";
-constexpr char kPrefix[] = "video";
-constexpr int kPrefixLen = sizeof(kPrefix) - 1;
-constexpr int kDevicePrefixLen = sizeof(kDevicePath) + kPrefixLen + 1;
+constexpr const char* kDevicePath = "/dev/";
+constexpr const char* kPrefix = "video";
+constexpr int kPrefixLen = std::char_traits<char>::length(kPrefix);
+constexpr int kDevicePrefixLen = std::char_traits<char>::length(kDevicePath) + kPrefixLen;
 
 bool matchDeviceName(int cameraIdOffset, const hidl_string& deviceName, std::string* deviceVersion,
                      std::string* cameraDevicePath) {
@@ -90,11 +91,11 @@
 
 Return<Status> ExternalCameraProviderImpl_2_7::setCallback(
         const sp<ICameraProviderCallback>& callback) {
+    if (callback == nullptr) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
     Mutex::Autolock _l(mLock);
     mCallbacks = callback;
-    if (mCallbacks == nullptr) {
-        return Status::OK;
-    }
     // Send a callback for all devices to initialize
     {
         for (const auto& pair : mCameraStatusMap) {
diff --git a/camera/provider/aidl/Android.bp b/camera/provider/aidl/Android.bp
index 35ec976..f6b00a1 100644
--- a/camera/provider/aidl/Android.bp
+++ b/camera/provider/aidl/Android.bp
@@ -14,10 +14,10 @@
         "android/hardware/camera/provider/*.aidl",
     ],
     imports: [
-        "android.hardware.camera.device-V2",
+        "android.hardware.camera.device-V3",
         "android.hardware.camera.common-V1",
     ],
-    frozen: true,
+    frozen: false,
     stability: "vintf",
     backend: {
         java: {
diff --git a/camera/provider/aidl/vts/Android.bp b/camera/provider/aidl/vts/Android.bp
index 8429b21..1c106f6 100644
--- a/camera/provider/aidl/vts/Android.bp
+++ b/camera/provider/aidl/vts/Android.bp
@@ -53,21 +53,33 @@
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@3.0",
         "android.hardware.graphics.mapper@4.0",
+        "camera_platform_flags_c_lib",
     ],
 
     // Statically link to libs not guaranteed to be present on the device.
     static_libs: [
         "android.hardware.camera.common@1.0-helper",
         "android.hardware.camera.common-V1-ndk",
-        "android.hardware.camera.device-V2-ndk",
-        "android.hardware.camera.metadata-V2-ndk",
-        "android.hardware.camera.provider-V2-ndk",
+        "android.hardware.camera.device-V3-ndk",
+        "android.hardware.camera.metadata-V3-ndk",
+        "android.hardware.camera.provider-V3-ndk",
         "android.hidl.allocator@1.0",
         "libgrallocusage",
         "libhidlmemory",
         "libgralloctypes",
         "libaidlcommonsupport",
+        "libgtest",
     ],
+
+    require_root: true,
+    test_options: {
+        test_runner_options: [
+            {
+                name: "native-test-timeout",
+                value: "1800000",
+            },
+        ],
+    },
     test_suites: [
         "general-tests",
         "vts",
diff --git a/camera/provider/aidl/vts/AndroidTest.xml b/camera/provider/aidl/vts/AndroidTest.xml
deleted file mode 100644
index 226121d..0000000
--- a/camera/provider/aidl/vts/AndroidTest.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<configuration description="Runs VtsAidlHalCameraProvider_TargetTest.">
-    <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="VtsAidlHalCameraProvider_TargetTest->/data/local/tmp/VtsAidlHalCameraProvider_TargetTest" />
-    </target_preparer>
-
-    <test class="com.android.tradefed.testtype.GTest" >
-        <option name="native-test-device-path" value="/data/local/tmp" />
-        <option name="module-name" value="VtsAidlHalCameraProvider_TargetTest" />
-        <option name="native-test-timeout" value="1800000"/> <!-- 30 min -->
-    </test>
-</configuration>
\ No newline at end of file
diff --git a/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
index 2845180..9a5f248 100644
--- a/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
+++ b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#include <gtest/gtest.h>
 
 #include <aidl/Vintf.h>
 #include <aidl/android/hardware/camera/common/VendorTagSection.h>
@@ -29,6 +30,7 @@
 #include <hidl/GtestPrinter.h>
 #include <hidl/HidlSupport.h>
 #include <torch_provider_cb.h>
+#include <com_android_internal_camera_flags.h>
 #include <list>
 
 using ::aidl::android::hardware::camera::common::CameraDeviceStatus;
@@ -50,6 +52,7 @@
 const uint32_t kMaxStillHeight = 1536;
 
 const int64_t kEmptyFlushTimeoutMSec = 200;
+namespace flags = com::android::internal::camera::flags;
 
 const static std::vector<int64_t> kMandatoryUseCases = {
         ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT,
@@ -159,6 +162,28 @@
     }
 }
 
+// Validate the integrity of manual flash strength control metadata
+TEST_P(CameraAidlTest, validateManualFlashStrengthControlKeys) {
+    if (flags::camera_manual_flash_strength_control()) {
+        std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+        for (const auto& name : cameraDeviceNames) {
+            ALOGI("validateManualFlashStrengthControlKeys: Testing camera device %s", name.c_str());
+            CameraMetadata meta;
+            std::shared_ptr<ICameraDevice> cameraDevice;
+            openEmptyDeviceSession(name, mProvider, &mSession /*out*/, &meta /*out*/,
+                    &cameraDevice /*out*/);
+            ndk::ScopedAStatus ret = cameraDevice->getCameraCharacteristics(&meta);
+            ASSERT_TRUE(ret.isOk());
+            const camera_metadata_t* staticMeta =
+                    reinterpret_cast<const camera_metadata_t*>(meta.metadata.data());
+            verifyManualFlashStrengthControlCharacteristics(staticMeta);
+        }
+    } else {
+        ALOGI("validateManualFlashStrengthControlKeys: Test skipped.\n");
+        GTEST_SKIP();
+    }
+}
+
 TEST_P(CameraAidlTest, systemCameraTest) {
     std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
     std::map<std::string, std::vector<SystemCameraKind>> hiddenPhysicalIdToLogicalMap;
@@ -242,6 +267,7 @@
         verifyCameraCharacteristics(chars);
         verifyMonochromeCharacteristics(chars);
         verifyRecommendedConfigs(chars);
+        verifyHighSpeedRecordingCharacteristics(name, chars);
         verifyLogicalOrUltraHighResCameraMetadata(name, device, chars, cameraDeviceNames);
 
         ASSERT_TRUE(ret.isOk());
@@ -257,6 +283,64 @@
     }
 }
 
+TEST_P(CameraAidlTest, getSessionCharacteristics) {
+    if (flags::feature_combination_query()) {
+        std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+
+        for (const auto& name : cameraDeviceNames) {
+            std::shared_ptr<ICameraDevice> device;
+            ALOGI("getSessionCharacteristics: Testing camera device %s", name.c_str());
+            ndk::ScopedAStatus ret = mProvider->getCameraDeviceInterface(name, &device);
+            ALOGI("getCameraDeviceInterface returns: %d:%d", ret.getExceptionCode(),
+                  ret.getServiceSpecificError());
+            ASSERT_TRUE(ret.isOk());
+            ASSERT_NE(device, nullptr);
+
+            CameraMetadata meta;
+            openEmptyDeviceSession(name, mProvider, &mSession /*out*/, &meta /*out*/,
+                                   &device /*out*/);
+
+            std::vector<AvailableStream> outputStreams;
+            camera_metadata_t* staticMeta =
+                    reinterpret_cast<camera_metadata_t*>(meta.metadata.data());
+            outputStreams.clear();
+            ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, outputStreams));
+            ASSERT_NE(0u, outputStreams.size());
+
+            AvailableStream sampleStream = outputStreams[0];
+
+            int32_t streamId = 0;
+            Stream stream = {streamId,
+                             StreamType::OUTPUT,
+                             sampleStream.width,
+                             sampleStream.height,
+                             static_cast<PixelFormat>(sampleStream.format),
+                             static_cast<aidl::android::hardware::graphics::common::BufferUsage>(
+                                     GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER),
+                             Dataspace::UNKNOWN,
+                             StreamRotation::ROTATION_0,
+                             std::string(),
+                             /*bufferSize*/ 0,
+                             /*groupId*/ -1,
+                             {SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT},
+                             RequestAvailableDynamicRangeProfilesMap::
+                                     ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD};
+
+            std::vector<Stream> streams = {stream};
+            StreamConfiguration config;
+            createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE, &config);
+
+            CameraMetadata chars;
+            ret = device->getSessionCharacteristics(config, &chars);
+            ASSERT_TRUE(ret.isOk());
+            verifySessionCharacteristics(chars);
+        }
+    } else {
+        ALOGI("getSessionCharacteristics: Test skipped.\n");
+        GTEST_SKIP();
+    }
+}
+
 // Verify that the torch strength level can be set and retrieved successfully.
 TEST_P(CameraAidlTest, turnOnTorchWithStrengthLevel) {
     std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
@@ -474,6 +558,12 @@
         ASSERT_TRUE(ret.isOk());
         ASSERT_NE(device, nullptr);
 
+        int32_t interfaceVersion;
+        ret = device->getInterfaceVersion(&interfaceVersion);
+        ASSERT_TRUE(ret.isOk());
+        bool supportFeatureCombinationQuery =
+                (interfaceVersion >= CAMERA_DEVICE_API_MINOR_VERSION_3);
+
         std::shared_ptr<EmptyDeviceCb> cb = ndk::SharedRefBase::make<EmptyDeviceCb>();
         ret = device->open(cb, &mSession);
         ALOGI("device::open returns status:%d:%d", ret.getExceptionCode(),
@@ -499,14 +589,26 @@
             }
 
             if (ret.isOk()) {
-                const camera_metadata_t* metadata = (camera_metadata_t*)rawMetadata.metadata.data();
-                size_t expectedSize = rawMetadata.metadata.size();
-                int result = validate_camera_metadata_structure(metadata, &expectedSize);
-                ASSERT_TRUE((result == 0) || (result == CAMERA_METADATA_VALIDATION_SHIFTED));
-                verifyRequestTemplate(metadata, reqTemplate);
+                validateDefaultRequestMetadata(reqTemplate, rawMetadata);
             } else {
                 ASSERT_EQ(0u, rawMetadata.metadata.size());
             }
+
+            if (flags::feature_combination_query()) {
+                if (supportFeatureCombinationQuery) {
+                    CameraMetadata rawMetadata2;
+                    ndk::ScopedAStatus ret2 =
+                            device->constructDefaultRequestSettings(reqTemplate, &rawMetadata2);
+
+                    ASSERT_EQ(ret.isOk(), ret2.isOk());
+                    ASSERT_EQ(ret.getStatus(), ret2.getStatus());
+
+                    ASSERT_EQ(rawMetadata.metadata.size(), rawMetadata2.metadata.size());
+                    if (ret2.isOk()) {
+                        validateDefaultRequestMetadata(reqTemplate, rawMetadata2);
+                    }
+                }
+            }
         }
         ret = mSession->close();
         mSession = nullptr;
@@ -562,8 +664,7 @@
             createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE, &config,
                                       jpegBufferSize);
 
-            bool expectStreamCombQuery = (isLogicalMultiCamera(staticMeta) == Status::OK);
-            verifyStreamCombination(device, config, /*expectedStatus*/ true, expectStreamCombQuery);
+            verifyStreamCombination(device, config, /*expectedStatus*/ true);
 
             config.streamConfigCounter = streamConfigCounter++;
             std::vector<HalStream> halConfigs;
@@ -597,7 +698,6 @@
     for (const auto& cameraDeviceIds : concurrentDeviceCombinations) {
         std::vector<CameraIdAndStreamCombination> cameraIdsAndStreamCombinations;
         std::vector<CameraTestInfo> cameraTestInfos;
-        size_t i = 0;
         for (const auto& id : cameraDeviceIds.combination) {
             CameraTestInfo cti;
             auto it = idToNameMap.find(id);
@@ -648,7 +748,6 @@
             cameraIdAndStreamCombination.cameraId = id;
             cameraIdAndStreamCombination.streamConfiguration = cti.config;
             cameraIdsAndStreamCombinations.push_back(cameraIdAndStreamCombination);
-            i++;
             cameraTestInfos.push_back(cti);
         }
         // Now verify that concurrent streams are supported
@@ -661,11 +760,7 @@
         // Test the stream can actually be configured
         for (auto& cti : cameraTestInfos) {
             if (cti.session != nullptr) {
-                camera_metadata_t* staticMeta =
-                        reinterpret_cast<camera_metadata_t*>(cti.staticMeta.metadata.data());
-                bool expectStreamCombQuery = (isLogicalMultiCamera(staticMeta) == Status::OK);
-                verifyStreamCombination(cti.cameraDevice, cti.config, /*expectedStatus*/ true,
-                                        expectStreamCombQuery);
+                verifyStreamCombination(cti.cameraDevice, cti.config, /*expectedStatus*/ true);
             }
 
             if (cti.session != nullptr) {
@@ -726,8 +821,7 @@
         createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE, &config,
                                   jpegBufferSize);
 
-        verifyStreamCombination(cameraDevice, config, /*expectedStatus*/ false,
-                                /*expectStreamCombQuery*/ false);
+        verifyStreamCombination(cameraDevice, config, /*expectedStatus*/ false);
 
         config.streamConfigCounter = streamConfigCounter++;
         std::vector<HalStream> halConfigs;
@@ -946,8 +1040,7 @@
                 createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE, &config,
                                           jpegBufferSize);
 
-                verifyStreamCombination(cameraDevice, config, /*expectedStatus*/ true,
-                                        /*expectStreamCombQuery*/ false);
+                verifyStreamCombination(cameraDevice, config, /*expectedStatus*/ true);
 
                 config.streamConfigCounter = streamConfigCounter++;
                 std::vector<HalStream> halConfigs;
@@ -1165,8 +1258,7 @@
                 createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE, &config,
                                           jpegBufferSize);
                 config.streamConfigCounter = streamConfigCounter++;
-                verifyStreamCombination(cameraDevice, config, /*expectedStatus*/ true,
-                                        /*expectStreamCombQuery*/ false);
+                verifyStreamCombination(cameraDevice, config, /*expectedStatus*/ true);
 
                 std::vector<HalStream> halConfigs;
                 ndk::ScopedAStatus ret = mSession->configureStreams(config, &halConfigs);
@@ -1230,8 +1322,7 @@
         createStreamConfiguration(streams, StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE,
                                   &config);
 
-        verifyStreamCombination(cameraDevice, config, /*expectedStatus*/ true,
-                                /*expectStreamCombQuery*/ false);
+        verifyStreamCombination(cameraDevice, config, /*expectedStatus*/ true);
 
         config.streamConfigCounter = streamConfigCounter++;
         std::vector<HalStream> halConfigs;
@@ -1403,8 +1494,7 @@
 
                 createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE, &config,
                                           jpegBufferSize);
-                verifyStreamCombination(cameraDevice, config, /*expectedStatus*/ true,
-                                        /*expectStreamCombQuery*/ false);
+                verifyStreamCombination(cameraDevice, config, /*expectedStatus*/ true);
 
                 config.streamConfigCounter = streamConfigCounter++;
                 std::vector<HalStream> halConfigs;
@@ -1522,7 +1612,7 @@
 
         std::vector<HalStream> halStreams;
         bool supportsPartialResults = false;
-        bool useHalBufManager = false;
+        std::set<int32_t> halBufManagedStreamIds;
         int32_t partialResultCount = 0;
         Stream previewStream;
         std::shared_ptr<DeviceCb> cb;
@@ -1530,7 +1620,7 @@
         configurePreviewStreams(
                 name, mProvider, &previewThreshold, physicalIds, &mSession, &previewStream,
                 &halStreams /*out*/, &supportsPartialResults /*out*/, &partialResultCount /*out*/,
-                &useHalBufManager /*out*/, &cb /*out*/, 0 /*streamConfigCounter*/, true);
+                &halBufManagedStreamIds /*out*/, &cb /*out*/, 0 /*streamConfigCounter*/, true);
         if (mSession == nullptr) {
             // stream combination not supported by HAL, skip test for device
             continue;
@@ -1567,7 +1657,9 @@
         size_t k = 0;
         for (const auto& halStream : halStreams) {
             buffer_handle_t buffer_handle;
-            if (useHalBufManager) {
+            bool useHalBufManagerForStream =
+                    halBufManagedStreamIds.find(halStream.id) != halBufManagedStreamIds.end();
+            if (useHalBufManagerForStream) {
                 outputBuffers[k] = {halStream.id,     /*bufferId*/ 0, NativeHandle(),
                                     BufferStatus::OK, NativeHandle(), NativeHandle()};
             } else {
@@ -1671,10 +1763,13 @@
         defaultPreviewSettings.unlock(settingsBuffer);
         filteredSettings.unlock(filteredSettingsBuffer);
 
-        if (useHalBufManager) {
-            std::vector<int32_t> streamIds(halStreams.size());
-            for (size_t i = 0; i < streamIds.size(); i++) {
-                streamIds[i] = halStreams[i].id;
+        if (halBufManagedStreamIds.size() != 0) {
+            std::vector<int32_t> streamIds;
+            for (size_t i = 0; i < halStreams.size(); i++) {
+                int32_t streamId = halStreams[i].id;
+                if (halBufManagedStreamIds.find(streamId) != halBufManagedStreamIds.end()) {
+                    streamIds.emplace_back(streamId);
+                }
             }
             verifyBuffersReturned(mSession, streamIds, cb);
         }
@@ -1738,7 +1833,7 @@
 
         std::vector<HalStream> halStreams;
         bool supportsPartialResults = false;
-        bool useHalBufManager = false;
+        std::set<int32_t> halBufManagedStreamIds;
         int32_t partialResultCount = 0;
         Stream previewStream;
         std::shared_ptr<DeviceCb> cb;
@@ -1750,8 +1845,8 @@
                         GRALLOC1_CONSUMER_USAGE_CPU_READ);
             previewStream.dataSpace = Dataspace::UNKNOWN;
             configureStreams(name, mProvider, format, &mSession, &previewStream, &halStreams,
-                             &supportsPartialResults, &partialResultCount, &useHalBufManager, &cb,
-                             0, /*maxResolution*/ true);
+                             &supportsPartialResults, &partialResultCount, &halBufManagedStreamIds,
+                             &cb, 0, /*maxResolution*/ true);
             ASSERT_NE(mSession, nullptr);
 
             ::aidl::android::hardware::common::fmq::MQDescriptor<
@@ -1782,7 +1877,9 @@
             size_t k = 0;
             for (const auto& halStream : halStreams) {
                 buffer_handle_t buffer_handle;
-                if (useHalBufManager) {
+                bool halBufManagerUsed =
+                        halBufManagedStreamIds.find(halStream.id) != halBufManagedStreamIds.end();
+                if (halBufManagerUsed) {
                     outputBuffers[k] = {halStream.id,   0,
                                         NativeHandle(), BufferStatus::OK,
                                         NativeHandle(), NativeHandle()};
@@ -1834,10 +1931,12 @@
                 ASSERT_FALSE(inflightReq->errorCodeValid);
                 ASSERT_NE(inflightReq->resultOutputBuffers.size(), 0u);
             }
-            if (useHalBufManager) {
-                std::vector<int32_t> streamIds(halStreams.size());
-                for (size_t i = 0; i < streamIds.size(); i++) {
-                    streamIds[i] = halStreams[i].id;
+            if (halBufManagedStreamIds.size()) {
+                std::vector<int32_t> streamIds;
+                for (size_t i = 0; i < halStreams.size(); i++) {
+                    if (contains(halBufManagedStreamIds, halStreams[i].id)) {
+                        streamIds.emplace_back(halStreams[i].id);
+                    }
                 }
                 verifyBuffersReturned(mSession, streamIds, cb);
             }
@@ -1899,7 +1998,7 @@
 
         std::vector<HalStream> halStreams;
         bool supportsPartialResults = false;
-        bool useHalBufManager = false;
+        std::set<int32_t> halBufManagedStreamIds;
         int32_t partialResultCount = 0;
         Stream previewStream;
         std::shared_ptr<DeviceCb> cb;
@@ -1910,7 +2009,7 @@
             previewStream.dataSpace = getDataspace(PixelFormat::IMPLEMENTATION_DEFINED);
             configureStreams(name, mProvider, PixelFormat::IMPLEMENTATION_DEFINED, &mSession,
                              &previewStream, &halStreams, &supportsPartialResults,
-                             &partialResultCount, &useHalBufManager, &cb, 0,
+                             &partialResultCount, &halBufManagedStreamIds, &cb, 0,
                              /*maxResolution*/ false, profile);
             ASSERT_NE(mSession, nullptr);
 
@@ -1949,7 +2048,7 @@
                 auto bufferId = requestId + 1; // Buffer id value 0 is not valid
                 for (const auto& halStream : halStreams) {
                     buffer_handle_t buffer_handle;
-                    if (useHalBufManager) {
+                    if (contains(halBufManagedStreamIds, halStream.id)) {
                         outputBuffers[k] = {halStream.id,   0,
                                             NativeHandle(), BufferStatus::OK,
                                             NativeHandle(), NativeHandle()};
@@ -2015,10 +2114,12 @@
                 verify10BitMetadata(mHandleImporter, *inflightReq, profile);
             }
 
-            if (useHalBufManager) {
-                std::vector<int32_t> streamIds(halStreams.size());
-                for (size_t i = 0; i < streamIds.size(); i++) {
-                    streamIds[i] = halStreams[i].id;
+            if (halBufManagedStreamIds.size() != 0) {
+                std::vector<int32_t> streamIds;
+                for (size_t i = 0; i < halStreams.size(); i++) {
+                    if (contains(halBufManagedStreamIds, halStreams[i].id)) {
+                        streamIds.emplace_back(halStreams[i].id);
+                    }
                 }
                 mSession->signalStreamFlush(streamIds, /*streamConfigCounter*/ 0);
                 cb->waitForBuffersReturned();
@@ -2350,11 +2451,11 @@
         std::vector<HalStream> halStreams;
         std::shared_ptr<DeviceCb> cb;
         int32_t jpegBufferSize;
-        bool useHalBufManager;
+        std::set<int32_t> halBufManagedStreamIds;
         configureOfflineStillStream(name, mProvider, &threshold, &mSession /*out*/, &stream /*out*/,
                                     &halStreams /*out*/, &supportsPartialResults /*out*/,
                                     &partialResultCount /*out*/, &cb /*out*/,
-                                    &jpegBufferSize /*out*/, &useHalBufManager /*out*/);
+                                    &jpegBufferSize /*out*/, &halBufManagedStreamIds /*out*/);
 
         auto ret = mSession->constructDefaultRequestSettings(RequestTemplate::STILL_CAPTURE,
                                                              &settings);
@@ -2390,7 +2491,7 @@
             StreamBuffer& outputBuffer = outputBuffers[0];
 
             std::unique_lock<std::mutex> l(mLock);
-            if (useHalBufManager) {
+            if (contains(halBufManagedStreamIds, halStream.id)) {
                 outputBuffer = {halStream.id,  0, NativeHandle(), BufferStatus::OK, NativeHandle(),
                                 NativeHandle()};
             } else {
diff --git a/camera/provider/aidl/vts/camera_aidl_test.cpp b/camera/provider/aidl/vts/camera_aidl_test.cpp
index 9559a1e..7958da9 100644
--- a/camera/provider/aidl/vts/camera_aidl_test.cpp
+++ b/camera/provider/aidl/vts/camera_aidl_test.cpp
@@ -30,6 +30,7 @@
 #include <aidlcommonsupport/NativeHandle.h>
 #include <android/binder_manager.h>
 #include <android/binder_process.h>
+#include <com_android_internal_camera_flags.h>
 #include <device_cb.h>
 #include <empty_device_cb.h>
 #include <grallocusage/GrallocUsageConversion.h>
@@ -39,6 +40,7 @@
 #include <ui/GraphicBufferAllocator.h>
 #include <regex>
 #include <typeinfo>
+#include "utils/Errors.h"
 
 using ::aidl::android::hardware::camera::common::CameraDeviceStatus;
 using ::aidl::android::hardware::camera::common::TorchModeStatus;
@@ -56,6 +58,8 @@
 using ::ndk::SpAIBinder;
 
 namespace {
+namespace flags = com::android::internal::camera::flags;
+
 bool parseProviderName(const std::string& serviceDescriptor, std::string* type /*out*/,
                        uint32_t* id /*out*/) {
     if (!type || !id) {
@@ -101,6 +105,8 @@
     return true;
 }
 
+namespace flags = com::android::internal::camera::flags;
+
 const std::vector<int64_t> kMandatoryUseCases = {
         ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT,
         ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW,
@@ -468,6 +474,38 @@
     } else {
         ADD_FAILURE() << "Get LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID failed!";
     }
+
+    if (flags::concert_mode()) {
+        auto ret = find_camera_metadata_ro_entry(
+                metadata, ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_SENSOR_CROP_REGION, &entry);
+        if ((ret == android::OK) && (entry.count > 0)) {
+            ASSERT_TRUE(entry.count == 4);
+            ASSERT_GE(entry.data.i32[0], 0);  // Top must be non-negative
+            ASSERT_GE(entry.data.i32[1], 0);  // Left must be non-negative
+            ASSERT_GT(entry.data.i32[2], 0);  // Width must be positive
+            ASSERT_GT(entry.data.i32[3], 0);  // Height must be positive
+        }
+    }
+}
+
+void CameraAidlTest::verifyLensIntrinsicsResult(const std::vector<uint8_t>& resultMetadata) {
+    if (flags::concert_mode()) {
+        camera_metadata_t* metadata = (camera_metadata_t*)resultMetadata.data();
+
+        camera_metadata_ro_entry timestampsEntry, intrinsicsEntry;
+        auto tsRet = find_camera_metadata_ro_entry(
+                metadata, ANDROID_STATISTICS_LENS_INTRINSIC_TIMESTAMPS, &timestampsEntry);
+        auto inRet = find_camera_metadata_ro_entry(
+                metadata, ANDROID_STATISTICS_LENS_INTRINSIC_SAMPLES, &intrinsicsEntry);
+        ASSERT_EQ(tsRet, inRet);
+        ASSERT_TRUE((intrinsicsEntry.count % 5) == 0);
+        ASSERT_EQ(timestampsEntry.count, intrinsicsEntry.count / 5);
+        if (timestampsEntry.count > 0) {
+            for (size_t i = 0; i < timestampsEntry.count - 1; i++) {
+                ASSERT_GE(timestampsEntry.data.i64[i + 1], timestampsEntry.data.i64[i]);
+            }
+        }
+    }
 }
 
 Status CameraAidlTest::getPhysicalCameraIds(const camera_metadata_t* staticMeta,
@@ -821,6 +859,90 @@
     ASSERT_TRUE(hasBokehStillCaptureMode || hasBokehContinuousMode || hasVendorMode);
 }
 
+void CameraAidlTest::verifyHighSpeedRecordingCharacteristics(const std::string& cameraName,
+                                                             const CameraMetadata& chars) {
+    const camera_metadata_t* metadata =
+            reinterpret_cast<const camera_metadata_t*>(chars.metadata.data());
+
+    // Check capabilities
+    bool hasHighSpeedRecordingCapability = false;
+    bool hasUltraHighResolutionCapability = false;
+    camera_metadata_ro_entry entry;
+    int rc =
+            find_camera_metadata_ro_entry(metadata, ANDROID_REQUEST_AVAILABLE_CAPABILITIES, &entry);
+    if ((0 == rc) && (entry.count > 0)) {
+        hasHighSpeedRecordingCapability =
+                std::find(entry.data.u8, entry.data.u8 + entry.count,
+                          ANDROID_REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO) !=
+                entry.data.u8 + entry.count;
+
+        hasUltraHighResolutionCapability =
+                std::find(entry.data.u8, entry.data.u8 + entry.count,
+                          ANDROID_REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR) !=
+                entry.data.u8 + entry.count;
+    }
+
+    // Check high speed video configurations
+    camera_metadata_ro_entry highSpeedEntry;
+    rc = find_camera_metadata_ro_entry(
+            metadata, ANDROID_CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS, &highSpeedEntry);
+    bool hasHighSpeedEntry = (0 == rc && highSpeedEntry.count > 0);
+
+    camera_metadata_ro_entry highSpeedMaxResEntry;
+    rc = find_camera_metadata_ro_entry(
+            metadata, ANDROID_CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS_MAXIMUM_RESOLUTION,
+            &highSpeedMaxResEntry);
+    bool hasHighSpeedMaxResEntry = (0 == rc && highSpeedMaxResEntry.count > 0);
+
+    // High speed recording configuration entry must be available based on capabilities
+    bool noHighSpeedRecording =
+            !hasHighSpeedRecordingCapability && !hasHighSpeedEntry && !hasHighSpeedMaxResEntry;
+    if (noHighSpeedRecording) {
+        return;
+    }
+    bool hasHighSpeedRecording = hasHighSpeedRecordingCapability && hasHighSpeedEntry &&
+                                 ((hasHighSpeedMaxResEntry && hasUltraHighResolutionCapability) ||
+                                  !hasHighSpeedMaxResEntry);
+    ASSERT_TRUE(hasHighSpeedRecording);
+
+    std::string version, cameraId;
+    ASSERT_TRUE(matchDeviceName(cameraName, mProviderType, &version, &cameraId));
+    bool needBatchSizeCheck = (version != CAMERA_DEVICE_API_VERSION_1);
+
+    // Check each entry item
+    ASSERT_TRUE(highSpeedEntry.count > 0 && highSpeedEntry.count % 5 == 0);
+    for (auto i = 4; i < highSpeedEntry.count; i += 5) {
+        int32_t fps_min = highSpeedEntry.data.i32[i - 2];
+        int32_t fps_max = highSpeedEntry.data.i32[i - 1];
+        int32_t batch_size_max = highSpeedEntry.data.i32[i];
+        int32_t allowedMaxBatchSize = fps_max / 30;
+
+        ASSERT_GE(fps_max, 120);
+        ASSERT_TRUE(fps_min % 30 == 0 && fps_max % 30 == 0);
+        if (needBatchSizeCheck) {
+            ASSERT_LE(batch_size_max, 32);
+            ASSERT_TRUE(allowedMaxBatchSize % batch_size_max == 0);
+        }
+    }
+
+    if (hasHighSpeedMaxResEntry) {
+        ASSERT_TRUE(highSpeedMaxResEntry.count > 0 && highSpeedMaxResEntry.count % 5 == 0);
+        for (auto i = 4; i < highSpeedMaxResEntry.count; i += 5) {
+            int32_t fps_min = highSpeedMaxResEntry.data.i32[i - 2];
+            int32_t fps_max = highSpeedMaxResEntry.data.i32[i - 1];
+            int32_t batch_size_max = highSpeedMaxResEntry.data.i32[i];
+            int32_t allowedMaxBatchSize = fps_max / 30;
+
+            ASSERT_GE(fps_max, 120);
+            ASSERT_TRUE(fps_min % 30 == 0 && fps_max % 30 == 0);
+            if (needBatchSizeCheck) {
+                ASSERT_LE(batch_size_max, 32);
+                ASSERT_TRUE(allowedMaxBatchSize % batch_size_max == 0);
+            }
+        }
+    }
+}
+
 Status CameraAidlTest::getAvailableOutputStreams(const camera_metadata_t* staticMeta,
                                                  std::vector<AvailableStream>& outputStreams,
                                                  const AvailableStream* threshold,
@@ -1058,6 +1180,58 @@
     }
 }
 
+void CameraAidlTest::verifyManualFlashStrengthControlCharacteristics(
+        const camera_metadata_t* staticMeta) {
+    camera_metadata_ro_entry singleMaxEntry;
+    camera_metadata_ro_entry singleDefEntry;
+    camera_metadata_ro_entry torchMaxEntry;
+    camera_metadata_ro_entry torchDefEntry;
+    bool torch_supported = false;
+    int32_t singleMaxLevel = 0;
+    int32_t singleDefLevel = 0;
+    int32_t torchMaxLevel = 0;
+    int32_t torchDefLevel = 0;
+
+    // determine whether the device supports torch or not
+    torch_supported = isTorchSupported(staticMeta);
+
+    int singleMaxRetCode = find_camera_metadata_ro_entry(staticMeta,
+            ANDROID_FLASH_SINGLE_STRENGTH_MAX_LEVEL, &singleMaxEntry);
+    int singleDefRetCode = find_camera_metadata_ro_entry(staticMeta,
+            ANDROID_FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL, &singleDefEntry);
+    int torchMaxRetCode = find_camera_metadata_ro_entry(staticMeta,
+            ANDROID_FLASH_TORCH_STRENGTH_MAX_LEVEL, &torchMaxEntry);
+    int torchDefRetCode = find_camera_metadata_ro_entry(staticMeta,
+            ANDROID_FLASH_TORCH_STRENGTH_DEFAULT_LEVEL, &torchDefEntry);
+    if (torch_supported) {
+        if(singleMaxRetCode == 0 && singleDefRetCode == 0 && torchMaxRetCode == 0 &&
+                torchDefRetCode == 0) {
+            singleMaxLevel = *singleMaxEntry.data.i32;
+            singleDefLevel = *singleDefEntry.data.i32;
+            torchMaxLevel = *torchMaxEntry.data.i32;
+            torchDefLevel = *torchDefEntry.data.i32;
+            ASSERT_TRUE((singleMaxEntry.count == singleDefEntry.count == torchMaxEntry.count
+                    == torchDefEntry.count == 1));
+        } else {
+            ASSERT_TRUE((singleMaxEntry.count == singleDefEntry.count == torchMaxEntry.count
+                    == torchDefEntry.count == 0));
+        }
+        // if the device supports this feature default levels should be greater than 0
+        if (singleMaxLevel > 1) {
+            ASSERT_GT(torchMaxLevel, 1);
+            ASSERT_GT(torchDefLevel, 0);
+            ASSERT_GT(singleDefLevel, 0);
+            ASSERT_TRUE(torchDefLevel <= torchMaxLevel); // default levels should be <= max levels
+            ASSERT_TRUE(singleDefLevel <= singleMaxLevel);
+        }
+    } else {
+        ASSERT_TRUE(singleMaxRetCode != 0);
+        ASSERT_TRUE(singleDefRetCode != 0);
+        ASSERT_TRUE(torchMaxRetCode != 0);
+        ASSERT_TRUE(torchDefRetCode != 0);
+    }
+}
+
 void CameraAidlTest::verifyRecommendedConfigs(const CameraMetadata& chars) {
     size_t CONFIG_ENTRY_SIZE = 5;
     size_t CONFIG_ENTRY_TYPE_OFFSET = 3;
@@ -1204,13 +1378,17 @@
     bool hasHalBufferManager =
             (0 == retcode && 1 == entry.count &&
              entry.data.i32[0] == ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5);
+    bool sessionHalBufferManager =
+            (0 == retcode && 1 == entry.count &&
+             entry.data.i32[0] ==
+                     ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_SESSION_CONFIGURABLE);
     retcode = find_camera_metadata_ro_entry(
             metadata, ANDROID_SCALER_MULTI_RESOLUTION_STREAM_SUPPORTED, &entry);
     bool multiResolutionStreamSupported =
             (0 == retcode && 1 == entry.count &&
              entry.data.u8[0] == ANDROID_SCALER_MULTI_RESOLUTION_STREAM_SUPPORTED_TRUE);
     if (multiResolutionStreamSupported) {
-        ASSERT_TRUE(hasHalBufferManager);
+        ASSERT_TRUE(hasHalBufferManager || sessionHalBufferManager);
     }
 
     std::string version, cameraId;
@@ -1713,17 +1891,76 @@
 }
 
 void CameraAidlTest::verifyStreamCombination(const std::shared_ptr<ICameraDevice>& device,
-                                             const StreamConfiguration& config, bool expectedStatus,
-                                             bool expectStreamCombQuery) {
+                                             const StreamConfiguration& config,
+                                             bool expectedStatus) {
     if (device != nullptr) {
         bool streamCombinationSupported;
         ScopedAStatus ret =
                 device->isStreamCombinationSupported(config, &streamCombinationSupported);
-        // TODO: Check is unsupported operation is correct.
-        ASSERT_TRUE(ret.isOk() ||
-                    (expectStreamCombQuery && ret.getExceptionCode() == EX_UNSUPPORTED_OPERATION));
-        if (ret.isOk()) {
-            ASSERT_EQ(expectedStatus, streamCombinationSupported);
+        ASSERT_TRUE(ret.isOk());
+        ASSERT_EQ(expectedStatus, streamCombinationSupported);
+
+        if (flags::feature_combination_query()) {
+            int32_t interfaceVersion;
+            ret = device->getInterfaceVersion(&interfaceVersion);
+            ASSERT_TRUE(ret.isOk());
+            bool supportFeatureCombinationQuery =
+                    (interfaceVersion >= CAMERA_DEVICE_API_MINOR_VERSION_3);
+            if (supportFeatureCombinationQuery) {
+                ret = device->isStreamCombinationWithSettingsSupported(config,
+                                                                       &streamCombinationSupported);
+                ASSERT_TRUE(ret.isOk());
+                ASSERT_EQ(expectedStatus, streamCombinationSupported);
+            }
+        }
+    }
+}
+
+void CameraAidlTest::verifySessionCharacteristics(const CameraMetadata& chars) {
+    if (flags::feature_combination_query()) {
+        const camera_metadata_t* metadata =
+                reinterpret_cast<const camera_metadata_t*>(chars.metadata.data());
+
+        size_t expectedSize = chars.metadata.size();
+        int result = validate_camera_metadata_structure(metadata, &expectedSize);
+        ASSERT_TRUE((result == 0) || (result == CAMERA_METADATA_VALIDATION_SHIFTED));
+        size_t entryCount = get_camera_metadata_entry_count(metadata);
+        ASSERT_GT(entryCount, 0u);
+
+        camera_metadata_ro_entry entry;
+        int retcode = 0;
+        float maxDigitalZoom = 1.0;
+
+        retcode = find_camera_metadata_ro_entry(metadata, ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,
+                                                &entry);
+        // ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM should always be present.
+        if ((0 == retcode) && (entry.count == 1)) {
+            maxDigitalZoom = entry.data.f[0];
+        } else {
+            ADD_FAILURE() << "Get camera scalerAvailableMaxDigitalZoom failed!";
+        }
+
+        retcode = find_camera_metadata_ro_entry(metadata, ANDROID_CONTROL_ZOOM_RATIO_RANGE, &entry);
+        bool hasZoomRatioRange = (0 == retcode && entry.count == 2);
+        if (!hasZoomRatioRange) {
+            return;
+        }
+        float minZoomRatio = entry.data.f[0];
+        float maxZoomRatio = entry.data.f[1];
+        constexpr float FLOATING_POINT_THRESHOLD = 0.00001f;
+        if (abs(maxDigitalZoom - maxZoomRatio) > FLOATING_POINT_THRESHOLD) {
+            ADD_FAILURE() << "Difference between maximum digital zoom " << maxDigitalZoom
+                          << " and maximum zoom ratio " << maxZoomRatio
+                          << " is greater than the threshold " << FLOATING_POINT_THRESHOLD << "!";
+        }
+        if (minZoomRatio > maxZoomRatio) {
+            ADD_FAILURE() << "Maximum zoom ratio is less than minimum zoom ratio!";
+        }
+        if (minZoomRatio > 1.0f) {
+            ADD_FAILURE() << "Minimum zoom ratio is more than 1.0!";
+        }
+        if (maxZoomRatio < 1.0f) {
+            ADD_FAILURE() << "Maximum zoom ratio is less than 1.0!";
         }
     }
 }
@@ -2006,7 +2243,6 @@
     int64_t bufferId = 1;
     int32_t frameNumber = 1;
     CameraMetadata settings;
-
     for (const auto& name : cameraDeviceNames) {
         Stream testStream;
         std::vector<HalStream> halStreams;
@@ -2294,6 +2530,41 @@
 
 }
 
+ndk::ScopedAStatus CameraAidlTest::configureStreams(std::shared_ptr<ICameraDeviceSession>& session,
+                                                    const StreamConfiguration& config,
+                                                    BufferManagerType bufferManagerType,
+                                                    std::set<int32_t>* halBufManagedStreamIds,
+                                                    std::vector<HalStream>* halStreams) {
+    auto ret = ndk::ScopedAStatus::ok();
+    ConfigureStreamsRet aidl_return;
+    int32_t interfaceVersion = -1;
+    ret = session->getInterfaceVersion(&interfaceVersion);
+    if (!ret.isOk()) {
+        return ret;
+    }
+
+    if (flags::session_hal_buf_manager() &&
+        (bufferManagerType == BufferManagerType::SESSION && interfaceVersion >= 3)) {
+        ret = session->configureStreamsV2(config, &aidl_return);
+    } else {
+        ret = session->configureStreams(config, halStreams);
+    }
+    if (!ret.isOk()) {
+        return ret;
+    }
+    if (flags::session_hal_buf_manager() && bufferManagerType == BufferManagerType::SESSION) {
+        *halStreams = std::move(aidl_return.halStreams);
+    }
+    for (const auto& halStream : *halStreams) {
+        if ((flags::session_hal_buf_manager() && bufferManagerType == BufferManagerType::SESSION &&
+             halStream.enableHalBufferManager) ||
+            bufferManagerType == BufferManagerType::HAL) {
+            halBufManagedStreamIds->insert(halStream.id);
+        }
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
 void CameraAidlTest::configureSingleStream(
         const std::string& name, const std::shared_ptr<ICameraProvider>& provider,
         const AvailableStream* previewThreshold, uint64_t bufferUsage, RequestTemplate reqTemplate,
@@ -2347,12 +2618,16 @@
     ASSERT_TRUE(ret.isOk());
     ASSERT_NE(*session, nullptr);
 
-    *useHalBufManager = false;
+    BufferManagerType bufferManagerType = BufferManagerType::FRAMEWORK;
     status = find_camera_metadata_ro_entry(
             staticMeta, ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION, &entry);
     if ((0 == status) && (entry.count == 1)) {
-        *useHalBufManager = (entry.data.u8[0] ==
-                             ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5);
+        if (entry.data.u8[0] == ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5) {
+            bufferManagerType = BufferManagerType::HAL;
+        } else if (entry.data.u8[0] ==
+                   ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_SESSION_CONFIGURABLE) {
+            bufferManagerType = BufferManagerType::SESSION;
+        }
     }
 
     outputPreviewStreams.clear();
@@ -2411,13 +2686,16 @@
         ASSERT_EQ(supported, true);
 
         std::vector<HalStream> halConfigs;
-        ret = (*session)->configureStreams(config, &halConfigs);
+        std::set<int32_t> halBufManagedStreamIds;
+        ret = configureStreams(*session, config, bufferManagerType, &halBufManagedStreamIds,
+                               &halConfigs);
         ALOGI("configureStreams returns status: %d:%d", ret.getExceptionCode(),
               ret.getServiceSpecificError());
         ASSERT_TRUE(ret.isOk());
         ASSERT_EQ(1u, halConfigs.size());
         halStreams->clear();
         halStreams->push_back(halConfigs[0]);
+        *useHalBufManager = halBufManagedStreamIds.size() != 0;
         if (*useHalBufManager) {
             std::vector<Stream> ss(1);
             std::vector<HalStream> hs(1);
@@ -2544,6 +2822,7 @@
         overrideRotateAndCrop(&request.settings);
         request.outputBuffers = std::vector<StreamBuffer>(1);
         StreamBuffer& outputBuffer = request.outputBuffers[0];
+
         if (useHalBufManager) {
             outputBuffer = {halStreams[0].id,
                             /*bufferId*/ 0,   NativeHandle(), BufferStatus::OK,
@@ -2662,14 +2941,14 @@
         const AvailableStream* previewThreshold, const std::unordered_set<std::string>& physicalIds,
         std::shared_ptr<ICameraDeviceSession>* session, Stream* previewStream,
         std::vector<HalStream>* halStreams, bool* supportsPartialResults,
-        int32_t* partialResultCount, bool* useHalBufManager, std::shared_ptr<DeviceCb>* cb,
-        int32_t streamConfigCounter, bool allowUnsupport) {
+        int32_t* partialResultCount, std::set<int32_t>* halBufManagedStreamIds,
+        std::shared_ptr<DeviceCb>* cb, int32_t streamConfigCounter, bool allowUnsupport) {
     ASSERT_NE(nullptr, session);
     ASSERT_NE(nullptr, halStreams);
     ASSERT_NE(nullptr, previewStream);
     ASSERT_NE(nullptr, supportsPartialResults);
     ASSERT_NE(nullptr, partialResultCount);
-    ASSERT_NE(nullptr, useHalBufManager);
+    ASSERT_NE(nullptr, halBufManagedStreamIds);
     ASSERT_NE(nullptr, cb);
 
     ASSERT_FALSE(physicalIds.empty());
@@ -2706,12 +2985,16 @@
     ASSERT_TRUE(ret.isOk());
     ASSERT_NE(*session, nullptr);
 
-    *useHalBufManager = false;
+    BufferManagerType bufferManagerType = BufferManagerType::FRAMEWORK;
     status = find_camera_metadata_ro_entry(
             staticMeta, ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION, &entry);
     if ((0 == status) && (entry.count == 1)) {
-        *useHalBufManager = (entry.data.u8[0] ==
-                             ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5);
+        if (entry.data.u8[0] == ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5) {
+            bufferManagerType = BufferManagerType::HAL;
+        } else if (entry.data.u8[0] ==
+                   ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_SESSION_CONFIGURABLE) {
+            bufferManagerType = BufferManagerType::SESSION;
+        }
     }
 
     outputPreviewStreams.clear();
@@ -2766,16 +3049,21 @@
 
     config.streamConfigCounter = streamConfigCounter;
     std::vector<HalStream> halConfigs;
-    ret = (*session)->configureStreams(config, &halConfigs);
+    ret = configureStreams(*session, config, bufferManagerType, halBufManagedStreamIds,
+                           &halConfigs);
+
     ASSERT_TRUE(ret.isOk());
     ASSERT_EQ(physicalIds.size(), halConfigs.size());
     *halStreams = halConfigs;
-    if (*useHalBufManager) {
-        std::vector<Stream> ss(physicalIds.size());
-        std::vector<HalStream> hs(physicalIds.size());
+    if (halBufManagedStreamIds->size() != 0) {
+        // Only include the streams that are HAL buffer managed
+        std::vector<Stream> ss;
+        std::vector<HalStream> hs;
         for (size_t i = 0; i < physicalIds.size(); i++) {
-            ss[i] = streams[i];
-            hs[i] = halConfigs[i];
+            if (contains(*halBufManagedStreamIds, halConfigs[i].id)) {
+                ss.emplace_back(streams[i]);
+                hs.emplace_back(halConfigs[i]);
+            }
         }
         (*cb)->setCurrentStreamConfig(ss, hs);
     }
@@ -2793,22 +3081,20 @@
     cb->waitForBuffersReturned();
 }
 
-void CameraAidlTest::configureStreams(const std::string& name,
-                                      const std::shared_ptr<ICameraProvider>& provider,
-                                      PixelFormat format,
-                                      std::shared_ptr<ICameraDeviceSession>* session,
-                                      Stream* previewStream, std::vector<HalStream>* halStreams,
-                                      bool* supportsPartialResults, int32_t* partialResultCount,
-                                      bool* useHalBufManager, std::shared_ptr<DeviceCb>* outCb,
-                                      uint32_t streamConfigCounter, bool maxResolution,
-                                      RequestAvailableDynamicRangeProfilesMap dynamicRangeProf,
-                                      RequestAvailableColorSpaceProfilesMap colorSpaceProf) {
+void CameraAidlTest::configureStreams(
+        const std::string& name, const std::shared_ptr<ICameraProvider>& provider,
+        PixelFormat format, std::shared_ptr<ICameraDeviceSession>* session, Stream* previewStream,
+        std::vector<HalStream>* halStreams, bool* supportsPartialResults,
+        int32_t* partialResultCount, std::set<int32_t>* halBufManagedStreamIds,
+        std::shared_ptr<DeviceCb>* outCb, uint32_t streamConfigCounter, bool maxResolution,
+        RequestAvailableDynamicRangeProfilesMap dynamicRangeProf,
+        RequestAvailableColorSpaceProfilesMap colorSpaceProf) {
     ASSERT_NE(nullptr, session);
     ASSERT_NE(nullptr, halStreams);
     ASSERT_NE(nullptr, previewStream);
     ASSERT_NE(nullptr, supportsPartialResults);
     ASSERT_NE(nullptr, partialResultCount);
-    ASSERT_NE(nullptr, useHalBufManager);
+    ASSERT_NE(nullptr, halBufManagedStreamIds);
     ASSERT_NE(nullptr, outCb);
 
     ALOGI("configureStreams: Testing camera device %s", name.c_str());
@@ -2845,12 +3131,16 @@
     ASSERT_TRUE(ret.isOk());
     ASSERT_NE(*session, nullptr);
 
-    *useHalBufManager = false;
+    BufferManagerType bufferManagerType = BufferManagerType::FRAMEWORK;
     status = find_camera_metadata_ro_entry(
             staticMeta, ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION, &entry);
     if ((0 == status) && (entry.count == 1)) {
-        *useHalBufManager = (entry.data.u8[0] ==
-                             ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5);
+        if (entry.data.u8[0] == ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5) {
+            bufferManagerType = BufferManagerType::HAL;
+        } else if (entry.data.u8[0] ==
+                   ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_SESSION_CONFIGURABLE) {
+            bufferManagerType = BufferManagerType::SESSION;
+        }
     }
 
     outputStreams.clear();
@@ -2904,10 +3194,11 @@
     ASSERT_TRUE(ret.isOk());
     ASSERT_EQ(supported, true);
 
-    ret = (*session)->configureStreams(config, halStreams);
+    ret = configureStreams(*session, config, bufferManagerType, halBufManagedStreamIds, halStreams);
+
     ASSERT_TRUE(ret.isOk());
 
-    if (*useHalBufManager) {
+    if (halBufManagedStreamIds->size() != 0) {
         std::vector<Stream> ss(1);
         std::vector<HalStream> hs(1);
         ss[0] = streams[0];
@@ -3267,7 +3558,7 @@
         const AvailableStream* threshold, std::shared_ptr<ICameraDeviceSession>* session,
         Stream* stream, std::vector<HalStream>* halStreams, bool* supportsPartialResults,
         int32_t* partialResultCount, std::shared_ptr<DeviceCb>* outCb, int32_t* jpegBufferSize,
-        bool* useHalBufManager) {
+        std::set<int32_t>* halBufManagedStreamIds) {
     ASSERT_NE(nullptr, session);
     ASSERT_NE(nullptr, halStreams);
     ASSERT_NE(nullptr, stream);
@@ -3275,7 +3566,7 @@
     ASSERT_NE(nullptr, partialResultCount);
     ASSERT_NE(nullptr, outCb);
     ASSERT_NE(nullptr, jpegBufferSize);
-    ASSERT_NE(nullptr, useHalBufManager);
+    ASSERT_NE(nullptr, halBufManagedStreamIds);
 
     std::vector<AvailableStream> outputStreams;
     std::shared_ptr<ICameraDevice> cameraDevice;
@@ -3302,12 +3593,16 @@
         *supportsPartialResults = (*partialResultCount > 1);
     }
 
-    *useHalBufManager = false;
+    BufferManagerType bufferManagerType = BufferManagerType::FRAMEWORK;
     status = find_camera_metadata_ro_entry(
             staticMeta, ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION, &entry);
     if ((0 == status) && (entry.count == 1)) {
-        *useHalBufManager = (entry.data.u8[0] ==
-                             ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5);
+        if (entry.data.u8[0] == ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5) {
+            bufferManagerType = BufferManagerType::HAL;
+        } else if (entry.data.u8[0] ==
+                   ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_SESSION_CONFIGURABLE) {
+            bufferManagerType = BufferManagerType::SESSION;
+        }
     }
 
     auto st = getJpegBufferSize(staticMeta, jpegBufferSize);
@@ -3360,10 +3655,11 @@
 
     StreamConfiguration config = {streams, StreamConfigurationMode::NORMAL_MODE, CameraMetadata()};
 
-    (*session)->configureStreams(config, halStreams);
+    ret = configureStreams(*session, config, bufferManagerType, halBufManagedStreamIds, halStreams);
+
     ASSERT_TRUE(ret.isOk());
 
-    if (*useHalBufManager) {
+    if (halBufManagedStreamIds->size() != 0) {
         (*outCb)->setCurrentStreamConfig(streams, *halStreams);
     }
 
@@ -3466,7 +3762,7 @@
 
         std::vector<HalStream> halStreams;
         bool supportsPartialResults = false;
-        bool useHalBufManager = false;
+        std::set<int32_t> halBufManagedStreamIds;
         int32_t partialResultCount = 0;
         Stream previewStream;
         std::shared_ptr<DeviceCb> cb;
@@ -3475,7 +3771,7 @@
                 GRALLOC1_CONSUMER_USAGE_HWCOMPOSER);
         configureStreams(name, mProvider, PixelFormat::IMPLEMENTATION_DEFINED, &mSession,
                          &previewStream, &halStreams, &supportsPartialResults, &partialResultCount,
-                         &useHalBufManager, &cb, 0,
+                         &halBufManagedStreamIds, &cb, 0,
                          /*maxResolution*/ false, dynamicRangeProfile, colorSpace);
         ASSERT_NE(mSession, nullptr);
 
@@ -3514,7 +3810,7 @@
             auto bufferId = requestId + 1;  // Buffer id value 0 is not valid
             for (const auto& halStream : halStreams) {
                 buffer_handle_t buffer_handle;
-                if (useHalBufManager) {
+                if (contains(halBufManagedStreamIds, halStream.id)) {
                     outputBuffers[k] = {halStream.id,   0,
                                         NativeHandle(), BufferStatus::OK,
                                         NativeHandle(), NativeHandle()};
@@ -3581,10 +3877,12 @@
             }
         }
 
-        if (useHalBufManager) {
-            std::vector<int32_t> streamIds(halStreams.size());
+        if (halBufManagedStreamIds.size() != 0) {
+            std::vector<int32_t> streamIds;
             for (size_t i = 0; i < streamIds.size(); i++) {
-                streamIds[i] = halStreams[i].id;
+                if (contains(halBufManagedStreamIds, halStreams[i].id)) {
+                    streamIds.emplace_back(halStreams[i].id);
+                }
             }
             mSession->signalStreamFlush(streamIds, /*streamConfigCounter*/ 0);
             cb->waitForBuffersReturned();
@@ -3795,3 +4093,12 @@
         }
     }
 }
+
+void CameraAidlTest::validateDefaultRequestMetadata(RequestTemplate reqTemplate,
+                                                    const CameraMetadata& rawMetadata) {
+    const camera_metadata_t* metadata = (camera_metadata_t*)rawMetadata.metadata.data();
+    size_t expectedSize = rawMetadata.metadata.size();
+    int result = validate_camera_metadata_structure(metadata, &expectedSize);
+    ASSERT_TRUE((result == 0) || (result == CAMERA_METADATA_VALIDATION_SHIFTED));
+    verifyRequestTemplate(metadata, reqTemplate);
+}
diff --git a/camera/provider/aidl/vts/camera_aidl_test.h b/camera/provider/aidl/vts/camera_aidl_test.h
index fa21a06..7bcf430 100644
--- a/camera/provider/aidl/vts/camera_aidl_test.h
+++ b/camera/provider/aidl/vts/camera_aidl_test.h
@@ -64,6 +64,7 @@
 using ::aidl::android::hardware::camera::device::BufferRequestStatus;
 using ::aidl::android::hardware::camera::device::CameraMetadata;
 using ::aidl::android::hardware::camera::device::CaptureResult;
+using ::aidl::android::hardware::camera::device::ConfigureStreamsRet;
 using ::aidl::android::hardware::camera::device::ErrorCode;
 using ::aidl::android::hardware::camera::device::HalStream;
 using ::aidl::android::hardware::camera::device::ICameraDevice;
@@ -98,6 +99,11 @@
 
 class DeviceCb;  // Forward declare to break circular header dependency
 
+template <typename T>
+bool contains(const std::set<T>& container, T value) {
+    return container.find(value) != container.end();
+}
+
 class CameraAidlTest : public ::testing::TestWithParam<std::string> {
   public:
     enum SystemCameraKind {
@@ -120,6 +126,8 @@
         HIDDEN_SECURE_CAMERA
     };
 
+    enum BufferManagerType { FRAMEWORK = 0, HAL, SESSION };
+
     struct AvailableStream {
         int32_t width;
         int32_t height;
@@ -199,15 +207,22 @@
             std::shared_ptr<ICameraDeviceSession>* session /*out*/, Stream* stream /*out*/,
             std::vector<HalStream>* halStreams, bool* supportsPartialResults /*out*/,
             int32_t* partialResultCount /*out*/, std::shared_ptr<DeviceCb>* outCb /*out*/,
-            int32_t* jpegBufferSize /*out*/, bool* useHalBufManager /*out*/);
+            int32_t* jpegBufferSize /*out*/, std::set<int32_t>* halBufManagedStreamIds /*out*/);
+
+    ndk::ScopedAStatus configureStreams(std::shared_ptr<ICameraDeviceSession>& session,
+                                        const StreamConfiguration& config,
+                                        BufferManagerType bufferManagerType,
+                                        std::set<int32_t>* halBufManagedStreamIds,
+                                        std::vector<HalStream>* halStreams);
 
     void configureStreams(
             const std::string& name, const std::shared_ptr<ICameraProvider>& provider,
             PixelFormat format, std::shared_ptr<ICameraDeviceSession>* session /*out*/,
             Stream* previewStream /*out*/, std::vector<HalStream>* halStreams /*out*/,
             bool* supportsPartialResults /*out*/, int32_t* partialResultCount /*out*/,
-            bool* useHalBufManager /*out*/, std::shared_ptr<DeviceCb>* outCb /*out*/,
-            uint32_t streamConfigCounter, bool maxResolution,
+            std::set<int32_t>* halBufManagedStreamIds /*out*/,
+            std::shared_ptr<DeviceCb>* outCb /*out*/, uint32_t streamConfigCounter,
+            bool maxResolution,
             RequestAvailableDynamicRangeProfilesMap dynamicRangeProf =
                     RequestAvailableDynamicRangeProfilesMap::
                             ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD,
@@ -221,7 +236,7 @@
             const std::unordered_set<std::string>& physicalIds,
             std::shared_ptr<ICameraDeviceSession>* session /*out*/, Stream* previewStream /*out*/,
             std::vector<HalStream>* halStreams /*out*/, bool* supportsPartialResults /*out*/,
-            int32_t* partialResultCount /*out*/, bool* useHalBufManager /*out*/,
+            int32_t* partialResultCount /*out*/, std::set<int32_t>* halBufManagedStreamIds /*out*/,
             std::shared_ptr<DeviceCb>* cb /*out*/, int32_t streamConfigCounter = 0,
             bool allowUnsupport = false);
 
@@ -253,12 +268,18 @@
 
     static void verifyExtendedSceneModeCharacteristics(const camera_metadata_t* metadata);
 
+    void verifyHighSpeedRecordingCharacteristics(const std::string& cameraName,
+                                                 const CameraMetadata& chars);
+
     static void verifyZoomCharacteristics(const camera_metadata_t* metadata);
 
     static void verifyRecommendedConfigs(const CameraMetadata& chars);
 
     static void verifyMonochromeCharacteristics(const CameraMetadata& chars);
 
+    static void verifyManualFlashStrengthControlCharacteristics(
+            const camera_metadata_t* staticMeta);
+
     static void verifyMonochromeCameraResult(
             const ::android::hardware::camera::common::V1_0::helper::CameraMetadata& metadata);
 
@@ -267,12 +288,15 @@
     static void verifySettingsOverrideCharacteristics(const camera_metadata_t* metadata);
 
     static void verifyStreamCombination(const std::shared_ptr<ICameraDevice>& device,
-                                        const StreamConfiguration& config, bool expectedStatus,
-                                        bool expectStreamCombQuery);
+                                        const StreamConfiguration& config, bool expectedStatus);
+
+    static void verifySessionCharacteristics(const CameraMetadata& chars);
 
     static void verifyLogicalCameraResult(const camera_metadata_t* staticMetadata,
                                           const std::vector<uint8_t>& resultMetadata);
 
+    static void verifyLensIntrinsicsResult(const std::vector<uint8_t>& resultMetadata);
+
     static void verifyBuffersReturned(const std::shared_ptr<ICameraDeviceSession>& session,
                                       int32_t streamId, const std::shared_ptr<DeviceCb>& cb,
                                       uint32_t streamConfigCounter = 0);
@@ -576,6 +600,9 @@
     static void waitForReleaseFence(
             std::vector<InFlightRequest::StreamBufferAndTimestamp>& resultOutputBuffers);
 
+    static void validateDefaultRequestMetadata(RequestTemplate reqTemplate,
+                                               const CameraMetadata& rawMetadata);
+
     // Map from frame number to the in-flight request state
     typedef std::unordered_map<uint32_t, std::shared_ptr<InFlightRequest>> InFlightMap;
 
@@ -611,6 +638,9 @@
 namespace {
 // device@<major>.<minor>/<type>/id
 const char* kDeviceNameRE = "device@([0-9]+\\.[0-9]+)/\\s+/(.+)";
+const std::string CAMERA_DEVICE_API_VERSION_1 = "1.1";
+const int32_t CAMERA_DEVICE_API_MINOR_VERSION_3 = 3;
+
 const int32_t kMaxVideoWidth = 4096;
 const int32_t kMaxVideoHeight = 2160;
 
diff --git a/camera/provider/aidl/vts/device_cb.cpp b/camera/provider/aidl/vts/device_cb.cpp
index 7e0969a..2c11d3f 100644
--- a/camera/provider/aidl/vts/device_cb.cpp
+++ b/camera/provider/aidl/vts/device_cb.cpp
@@ -388,15 +388,16 @@
         // Verify logical camera result metadata
         bool isLogicalCamera =
                 Status::OK == CameraAidlTest::isLogicalMultiCamera(staticMetadataBuffer);
+        camera_metadata_t* collectedMetadata =
+                const_cast<camera_metadata_t*>(request->collectedResult.getAndLock());
+        uint8_t* rawMetadata = reinterpret_cast<uint8_t*>(collectedMetadata);
+        std::vector metadata =
+                std::vector(rawMetadata, rawMetadata + get_camera_metadata_size(collectedMetadata));
         if (isLogicalCamera) {
-            camera_metadata_t* collectedMetadata =
-                    const_cast<camera_metadata_t*>(request->collectedResult.getAndLock());
-            uint8_t* rawMetadata = reinterpret_cast<uint8_t*>(collectedMetadata);
-            std::vector metadata = std::vector(
-                    rawMetadata, rawMetadata + get_camera_metadata_size(collectedMetadata));
             CameraAidlTest::verifyLogicalCameraResult(staticMetadataBuffer, metadata);
-            request->collectedResult.unlock(collectedMetadata);
         }
+        CameraAidlTest::verifyLensIntrinsicsResult(metadata);
+        request->collectedResult.unlock(collectedMetadata);
     }
 
     uint32_t numBuffersReturned = results.outputBuffers.size();
diff --git a/camera/provider/default/ExternalCameraProvider.cpp b/camera/provider/default/ExternalCameraProvider.cpp
index 4d2c847..54875ab 100644
--- a/camera/provider/default/ExternalCameraProvider.cpp
+++ b/camera/provider/default/ExternalCameraProvider.cpp
@@ -75,15 +75,15 @@
 
 ndk::ScopedAStatus ExternalCameraProvider::setCallback(
         const std::shared_ptr<ICameraProviderCallback>& in_callback) {
+    if (in_callback == nullptr) {
+        return fromStatus(Status::ILLEGAL_ARGUMENT);
+    }
+
     {
         Mutex::Autolock _l(mLock);
         mCallback = in_callback;
     }
 
-    if (mCallback == nullptr) {
-        return fromStatus(Status::OK);
-    }
-
     for (const auto& pair : mCameraStatusMap) {
         mCallback->cameraDeviceStatusChange(pair.first, pair.second);
     }
diff --git a/cas/1.0/default/CasImpl.cpp b/cas/1.0/default/CasImpl.cpp
index 178020e..98e7593 100644
--- a/cas/1.0/default/CasImpl.cpp
+++ b/cas/1.0/default/CasImpl.cpp
@@ -103,8 +103,7 @@
 
 Return<Status> CasImpl::setSessionPrivateData(
         const HidlCasSessionId &sessionId, const HidlCasData& pvtData) {
-    ALOGV("%s: sessionId=%s", __FUNCTION__,
-            sessionIdToString(sessionId).string());
+    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).c_str());
     std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
     if (holder.get() == nullptr) {
         return toStatus(INVALID_OPERATION);
@@ -113,8 +112,7 @@
 }
 
 Return<Status> CasImpl::closeSession(const HidlCasSessionId &sessionId) {
-    ALOGV("%s: sessionId=%s", __FUNCTION__,
-            sessionIdToString(sessionId).string());
+    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).c_str());
     std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
     if (holder.get() == nullptr) {
         return toStatus(INVALID_OPERATION);
@@ -124,8 +122,7 @@
 
 Return<Status> CasImpl::processEcm(
         const HidlCasSessionId &sessionId, const HidlCasData& ecm) {
-    ALOGV("%s: sessionId=%s", __FUNCTION__,
-            sessionIdToString(sessionId).string());
+    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).c_str());
     std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
     if (holder.get() == nullptr) {
         return toStatus(INVALID_OPERATION);
diff --git a/cas/1.0/default/DescramblerImpl.cpp b/cas/1.0/default/DescramblerImpl.cpp
index f79b32d..6d7c304 100644
--- a/cas/1.0/default/DescramblerImpl.cpp
+++ b/cas/1.0/default/DescramblerImpl.cpp
@@ -62,8 +62,7 @@
 }
 
 Return<Status> DescramblerImpl::setMediaCasSession(const HidlCasSessionId& sessionId) {
-    ALOGV("%s: sessionId=%s", __FUNCTION__,
-            sessionIdToString(sessionId).string());
+    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).c_str());
 
     std::shared_ptr<DescramblerPlugin> holder = std::atomic_load(&mPluginHolder);
     if (holder.get() == nullptr) {
@@ -80,7 +79,7 @@
         return false;
     }
 
-    return holder->requiresSecureDecoderComponent(String8(mime.c_str()));
+    return holder->requiresSecureDecoderComponent(mime.c_str());
 }
 
 static inline bool validateRangeForSize(
diff --git a/cas/1.0/default/FactoryLoader.h b/cas/1.0/default/FactoryLoader.h
index 45e515a..3d49d9e 100644
--- a/cas/1.0/default/FactoryLoader.h
+++ b/cas/1.0/default/FactoryLoader.h
@@ -17,6 +17,7 @@
 #ifndef ANDROID_HARDWARE_CAS_V1_0_FACTORY_LOADER_H_
 #define ANDROID_HARDWARE_CAS_V1_0_FACTORY_LOADER_H_
 
+#include <android-base/strings.h>
 #include <dirent.h>
 #include <dlfcn.h>
 #include "SharedLibrary.h"
@@ -98,17 +99,17 @@
     String8 dirPath("/vendor/lib/mediacas");
 #endif
 
-    DIR* pDir = opendir(dirPath.string());
+    DIR* pDir = opendir(dirPath.c_str());
 
     if (pDir == NULL) {
-        ALOGE("Failed to open plugin directory %s", dirPath.string());
+        ALOGE("Failed to open plugin directory %s", dirPath.c_str());
         return false;
     }
 
     struct dirent* pEntry;
     while ((pEntry = readdir(pDir))) {
         String8 pluginPath = dirPath + "/" + pEntry->d_name;
-        if (pluginPath.getPathExtension() == ".so") {
+        if (base::EndsWith(pluginPath.c_str(), ".so")) {
             if (loadFactoryForSchemeFromPath(
                     pluginPath, CA_system_id, library, factory)) {
                 mCASystemIdToLibraryPathMap.add(CA_system_id, pluginPath);
@@ -138,10 +139,10 @@
     String8 dirPath("/vendor/lib/mediacas");
 #endif
 
-    DIR* pDir = opendir(dirPath.string());
+    DIR* pDir = opendir(dirPath.c_str());
 
     if (pDir == NULL) {
-        ALOGE("Failed to open plugin directory %s", dirPath.string());
+        ALOGE("Failed to open plugin directory %s", dirPath.c_str());
         return false;
     }
 
@@ -150,7 +151,7 @@
     struct dirent* pEntry;
     while ((pEntry = readdir(pDir))) {
         String8 pluginPath = dirPath + "/" + pEntry->d_name;
-        if (pluginPath.getPathExtension() == ".so") {
+        if (base::EndsWith(pluginPath.c_str(), ".so")) {
             queryPluginsFromPath(pluginPath, results);
         }
     }
diff --git a/cas/1.0/default/SharedLibrary.cpp b/cas/1.0/default/SharedLibrary.cpp
index 9c7f385..90c84b8 100644
--- a/cas/1.0/default/SharedLibrary.cpp
+++ b/cas/1.0/default/SharedLibrary.cpp
@@ -29,7 +29,7 @@
 namespace implementation {
 
 SharedLibrary::SharedLibrary(const String8 &path) {
-    mLibHandle = dlopen(path.string(), RTLD_NOW);
+    mLibHandle = dlopen(path.c_str(), RTLD_NOW);
 }
 
 SharedLibrary::~SharedLibrary() {
diff --git a/cas/1.0/default/TypeConvert.cpp b/cas/1.0/default/TypeConvert.cpp
index cd0efdb..cc25cf5 100644
--- a/cas/1.0/default/TypeConvert.cpp
+++ b/cas/1.0/default/TypeConvert.cpp
@@ -82,7 +82,7 @@
     for (size_t i = 0; i < sessionId.size(); i++) {
         result.appendFormat("%02x ", sessionId[i]);
     }
-    if (result.isEmpty()) {
+    if (result.empty()) {
         result.append("(null)");
     }
     return result;
diff --git a/cas/1.0/default/android.hardware.cas@1.0-service-lazy.rc b/cas/1.0/default/android.hardware.cas@1.0-service-lazy.rc
index 622ee8f..1a08ebc 100644
--- a/cas/1.0/default/android.hardware.cas@1.0-service-lazy.rc
+++ b/cas/1.0/default/android.hardware.cas@1.0-service-lazy.rc
@@ -5,5 +5,6 @@
     class hal
     user media
     group mediadrm drmrpc
+    capabilities SYS_NICE
     ioprio rt 4
     task_profiles ProcessCapacityHigh
diff --git a/cas/1.0/default/android.hardware.cas@1.0-service.rc b/cas/1.0/default/android.hardware.cas@1.0-service.rc
index 5df4825..a65160a 100644
--- a/cas/1.0/default/android.hardware.cas@1.0-service.rc
+++ b/cas/1.0/default/android.hardware.cas@1.0-service.rc
@@ -2,5 +2,6 @@
     class hal
     user media
     group mediadrm drmrpc
+    capabilities SYS_NICE
     ioprio rt 4
     task_profiles ProcessCapacityHigh
diff --git a/cas/1.0/vts/functional/OWNERS b/cas/1.0/vts/functional/OWNERS
deleted file mode 100644
index 7d8c2ee..0000000
--- a/cas/1.0/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 1344
-include ../../../1.2/vts/functional/OWNERS
diff --git a/cas/1.1/default/CasImpl.cpp b/cas/1.1/default/CasImpl.cpp
index 4cc6017..105e036 100644
--- a/cas/1.1/default/CasImpl.cpp
+++ b/cas/1.1/default/CasImpl.cpp
@@ -125,7 +125,7 @@
 
 Return<Status> CasImpl::setSessionPrivateData(const HidlCasSessionId& sessionId,
                                               const HidlCasData& pvtData) {
-    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string());
+    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).c_str());
     std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
     if (holder.get() == nullptr) {
         return toStatus(INVALID_OPERATION);
@@ -134,7 +134,7 @@
 }
 
 Return<Status> CasImpl::closeSession(const HidlCasSessionId& sessionId) {
-    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string());
+    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).c_str());
     std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
     if (holder.get() == nullptr) {
         return toStatus(INVALID_OPERATION);
@@ -143,7 +143,7 @@
 }
 
 Return<Status> CasImpl::processEcm(const HidlCasSessionId& sessionId, const HidlCasData& ecm) {
-    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string());
+    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).c_str());
     std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
     if (holder.get() == nullptr) {
         return toStatus(INVALID_OPERATION);
diff --git a/cas/1.1/default/DescramblerImpl.cpp b/cas/1.1/default/DescramblerImpl.cpp
index 309cd3c..237d56b 100644
--- a/cas/1.1/default/DescramblerImpl.cpp
+++ b/cas/1.1/default/DescramblerImpl.cpp
@@ -59,7 +59,7 @@
 }
 
 Return<Status> DescramblerImpl::setMediaCasSession(const HidlCasSessionId& sessionId) {
-    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string());
+    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).c_str());
 
     std::shared_ptr<DescramblerPlugin> holder = std::atomic_load(&mPluginHolder);
     if (holder.get() == nullptr) {
@@ -75,7 +75,7 @@
         return false;
     }
 
-    return holder->requiresSecureDecoderComponent(String8(mime.c_str()));
+    return holder->requiresSecureDecoderComponent(mime.c_str());
 }
 
 static inline bool validateRangeForSize(uint64_t offset, uint64_t length, uint64_t size) {
diff --git a/cas/1.1/default/FactoryLoader.h b/cas/1.1/default/FactoryLoader.h
index 121f90c..a575df6 100644
--- a/cas/1.1/default/FactoryLoader.h
+++ b/cas/1.1/default/FactoryLoader.h
@@ -17,6 +17,7 @@
 #ifndef ANDROID_HARDWARE_CAS_V1_1_FACTORY_LOADER_H_
 #define ANDROID_HARDWARE_CAS_V1_1_FACTORY_LOADER_H_
 
+#include <android-base/strings.h>
 #include <dirent.h>
 #include <dlfcn.h>
 #include <media/cas/CasAPI.h>
@@ -90,17 +91,17 @@
 #else
     String8 dirPath("/vendor/lib/mediacas");
 #endif
-    DIR* pDir = opendir(dirPath.string());
+    DIR* pDir = opendir(dirPath.c_str());
 
     if (pDir == NULL) {
-        ALOGE("Failed to open plugin directory %s", dirPath.string());
+        ALOGE("Failed to open plugin directory %s", dirPath.c_str());
         return false;
     }
 
     struct dirent* pEntry;
     while ((pEntry = readdir(pDir))) {
         String8 pluginPath = dirPath + "/" + pEntry->d_name;
-        if (pluginPath.getPathExtension() == ".so") {
+        if (base::EndsWith(pluginPath.c_str(), ".so")) {
             if (loadFactoryForSchemeFromPath(pluginPath, CA_system_id, library, factory)) {
                 mCASystemIdToLibraryPathMap.add(CA_system_id, pluginPath);
                 closedir(pDir);
@@ -127,10 +128,10 @@
 #else
     String8 dirPath("/vendor/lib/mediacas");
 #endif
-    DIR* pDir = opendir(dirPath.string());
+    DIR* pDir = opendir(dirPath.c_str());
 
     if (pDir == NULL) {
-        ALOGE("Failed to open plugin directory %s", dirPath.string());
+        ALOGE("Failed to open plugin directory %s", dirPath.c_str());
         return false;
     }
 
@@ -139,7 +140,7 @@
     struct dirent* pEntry;
     while ((pEntry = readdir(pDir))) {
         String8 pluginPath = dirPath + "/" + pEntry->d_name;
-        if (pluginPath.getPathExtension() == ".so") {
+        if (base::EndsWith(pluginPath.c_str(), ".so")) {
             queryPluginsFromPath(pluginPath, results);
         }
     }
diff --git a/cas/1.1/default/SharedLibrary.cpp b/cas/1.1/default/SharedLibrary.cpp
index ffe4bb9..ac5dbcf 100644
--- a/cas/1.1/default/SharedLibrary.cpp
+++ b/cas/1.1/default/SharedLibrary.cpp
@@ -29,7 +29,7 @@
 namespace implementation {
 
 SharedLibrary::SharedLibrary(const String8& path) {
-    mLibHandle = dlopen(path.string(), RTLD_NOW);
+    mLibHandle = dlopen(path.c_str(), RTLD_NOW);
 }
 
 SharedLibrary::~SharedLibrary() {
diff --git a/cas/1.1/default/TypeConvert.cpp b/cas/1.1/default/TypeConvert.cpp
index 09ef41a..2ffc79a 100644
--- a/cas/1.1/default/TypeConvert.cpp
+++ b/cas/1.1/default/TypeConvert.cpp
@@ -81,7 +81,7 @@
     for (size_t i = 0; i < sessionId.size(); i++) {
         result.appendFormat("%02x ", sessionId[i]);
     }
-    if (result.isEmpty()) {
+    if (result.empty()) {
         result.append("(null)");
     }
     return result;
diff --git a/cas/1.1/default/android.hardware.cas@1.1-service-lazy.rc b/cas/1.1/default/android.hardware.cas@1.1-service-lazy.rc
index 0721dc3..9fca8fd 100644
--- a/cas/1.1/default/android.hardware.cas@1.1-service-lazy.rc
+++ b/cas/1.1/default/android.hardware.cas@1.1-service-lazy.rc
@@ -6,5 +6,6 @@
     class hal
     user media
     group mediadrm drmrpc
+    capabilities SYS_NICE
     ioprio rt 4
     task_profiles ProcessCapacityHigh
diff --git a/cas/1.1/default/android.hardware.cas@1.1-service.rc b/cas/1.1/default/android.hardware.cas@1.1-service.rc
index 132d943..19fd031 100644
--- a/cas/1.1/default/android.hardware.cas@1.1-service.rc
+++ b/cas/1.1/default/android.hardware.cas@1.1-service.rc
@@ -2,5 +2,6 @@
     class hal
     user media
     group mediadrm drmrpc
+    capabilities SYS_NICE
     ioprio rt 4
     task_profiles ProcessCapacityHigh
diff --git a/cas/1.1/vts/functional/OWNERS b/cas/1.1/vts/functional/OWNERS
deleted file mode 100644
index 7d8c2ee..0000000
--- a/cas/1.1/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 1344
-include ../../../1.2/vts/functional/OWNERS
diff --git a/cas/1.2/default/CasImpl.cpp b/cas/1.2/default/CasImpl.cpp
index 46dd251..b1038bc 100644
--- a/cas/1.2/default/CasImpl.cpp
+++ b/cas/1.2/default/CasImpl.cpp
@@ -174,7 +174,7 @@
 
 Return<Status> CasImpl::setSessionPrivateData(const HidlCasSessionId& sessionId,
                                               const HidlCasData& pvtData) {
-    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string());
+    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).c_str());
     std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
     if (holder.get() == nullptr) {
         return toStatus(INVALID_OPERATION);
@@ -183,7 +183,7 @@
 }
 
 Return<Status> CasImpl::closeSession(const HidlCasSessionId& sessionId) {
-    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string());
+    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).c_str());
     std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
     if (holder.get() == nullptr) {
         return toStatus(INVALID_OPERATION);
@@ -192,7 +192,7 @@
 }
 
 Return<Status> CasImpl::processEcm(const HidlCasSessionId& sessionId, const HidlCasData& ecm) {
-    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string());
+    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).c_str());
     std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
     if (holder.get() == nullptr) {
         return toStatus(INVALID_OPERATION);
diff --git a/cas/1.2/default/DescramblerImpl.cpp b/cas/1.2/default/DescramblerImpl.cpp
index 309cd3c..237d56b 100644
--- a/cas/1.2/default/DescramblerImpl.cpp
+++ b/cas/1.2/default/DescramblerImpl.cpp
@@ -59,7 +59,7 @@
 }
 
 Return<Status> DescramblerImpl::setMediaCasSession(const HidlCasSessionId& sessionId) {
-    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string());
+    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).c_str());
 
     std::shared_ptr<DescramblerPlugin> holder = std::atomic_load(&mPluginHolder);
     if (holder.get() == nullptr) {
@@ -75,7 +75,7 @@
         return false;
     }
 
-    return holder->requiresSecureDecoderComponent(String8(mime.c_str()));
+    return holder->requiresSecureDecoderComponent(mime.c_str());
 }
 
 static inline bool validateRangeForSize(uint64_t offset, uint64_t length, uint64_t size) {
diff --git a/cas/1.2/default/FactoryLoader.h b/cas/1.2/default/FactoryLoader.h
index a374b31..0b05bfc 100644
--- a/cas/1.2/default/FactoryLoader.h
+++ b/cas/1.2/default/FactoryLoader.h
@@ -17,6 +17,7 @@
 #ifndef ANDROID_HARDWARE_CAS_V1_1_FACTORY_LOADER_H_
 #define ANDROID_HARDWARE_CAS_V1_1_FACTORY_LOADER_H_
 
+#include <android-base/strings.h>
 #include <dirent.h>
 #include <dlfcn.h>
 #include <media/cas/CasAPI.h>
@@ -90,17 +91,17 @@
 #else
     String8 dirPath("/vendor/lib/mediacas");
 #endif
-    DIR* pDir = opendir(dirPath.string());
+    DIR* pDir = opendir(dirPath.c_str());
 
     if (pDir == NULL) {
-        ALOGE("Failed to open plugin directory %s", dirPath.string());
+        ALOGE("Failed to open plugin directory %s", dirPath.c_str());
         return false;
     }
 
     struct dirent* pEntry;
     while ((pEntry = readdir(pDir))) {
         String8 pluginPath = dirPath + "/" + pEntry->d_name;
-        if (pluginPath.getPathExtension() == ".so") {
+        if (base::EndsWith(pluginPath.c_str(), ".so")) {
             if (loadFactoryForSchemeFromPath(pluginPath, CA_system_id, library, factory)) {
                 mCASystemIdToLibraryPathMap.add(CA_system_id, pluginPath);
                 closedir(pDir);
@@ -127,10 +128,10 @@
 #else
     String8 dirPath("/vendor/lib/mediacas");
 #endif
-    DIR* pDir = opendir(dirPath.string());
+    DIR* pDir = opendir(dirPath.c_str());
 
     if (pDir == NULL) {
-        ALOGE("Failed to open plugin directory %s", dirPath.string());
+        ALOGE("Failed to open plugin directory %s", dirPath.c_str());
         return false;
     }
 
@@ -139,7 +140,7 @@
     struct dirent* pEntry;
     while ((pEntry = readdir(pDir))) {
         String8 pluginPath = dirPath + "/" + pEntry->d_name;
-        if (pluginPath.getPathExtension() == ".so") {
+        if (base::EndsWith(pluginPath.c_str(), ".so")) {
             queryPluginsFromPath(pluginPath, results);
         }
     }
diff --git a/cas/1.2/default/SharedLibrary.cpp b/cas/1.2/default/SharedLibrary.cpp
index ffe4bb9..ac5dbcf 100644
--- a/cas/1.2/default/SharedLibrary.cpp
+++ b/cas/1.2/default/SharedLibrary.cpp
@@ -29,7 +29,7 @@
 namespace implementation {
 
 SharedLibrary::SharedLibrary(const String8& path) {
-    mLibHandle = dlopen(path.string(), RTLD_NOW);
+    mLibHandle = dlopen(path.c_str(), RTLD_NOW);
 }
 
 SharedLibrary::~SharedLibrary() {
diff --git a/cas/1.2/default/TypeConvert.cpp b/cas/1.2/default/TypeConvert.cpp
index c4bd0dd..7d27fa1 100644
--- a/cas/1.2/default/TypeConvert.cpp
+++ b/cas/1.2/default/TypeConvert.cpp
@@ -108,7 +108,7 @@
     for (size_t i = 0; i < sessionId.size(); i++) {
         result.appendFormat("%02x ", sessionId[i]);
     }
-    if (result.isEmpty()) {
+    if (result.empty()) {
         result.append("(null)");
     }
     return result;
diff --git a/cas/1.2/default/android.hardware.cas@1.2-service-lazy.rc b/cas/1.2/default/android.hardware.cas@1.2-service-lazy.rc
index d91fdce..8c2a894 100644
--- a/cas/1.2/default/android.hardware.cas@1.2-service-lazy.rc
+++ b/cas/1.2/default/android.hardware.cas@1.2-service-lazy.rc
@@ -7,5 +7,6 @@
     class hal
     user media
     group mediadrm drmrpc
+    capabilities SYS_NICE
     ioprio rt 4
     task_profiles ProcessCapacityHigh
diff --git a/cas/1.2/default/android.hardware.cas@1.2-service.rc b/cas/1.2/default/android.hardware.cas@1.2-service.rc
index b22971a..4b638bc 100644
--- a/cas/1.2/default/android.hardware.cas@1.2-service.rc
+++ b/cas/1.2/default/android.hardware.cas@1.2-service.rc
@@ -2,5 +2,6 @@
     class hal
     user media
     group mediadrm drmrpc
+    capabilities SYS_NICE
     ioprio rt 4
     task_profiles ProcessCapacityHigh
diff --git a/cas/1.2/vts/functional/OWNERS b/cas/1.2/vts/functional/OWNERS
deleted file mode 100644
index 4c55752..0000000
--- a/cas/1.2/vts/functional/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 1344
-quxiangfang@google.com
-hgchen@google.com
diff --git a/cas/OWNERS b/cas/OWNERS
index 473c8f26..f6c60aa 100644
--- a/cas/OWNERS
+++ b/cas/OWNERS
@@ -1 +1,4 @@
-include /tv/input/OWNERS
+# Bug component: 1344
+
+hgchen@google.com
+quxiangfang@google.com
\ No newline at end of file
diff --git a/cas/aidl/OWNERS b/cas/aidl/OWNERS
deleted file mode 100755
index 4c55752..0000000
--- a/cas/aidl/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 1344
-quxiangfang@google.com
-hgchen@google.com
diff --git a/cas/aidl/default/Android.bp b/cas/aidl/default/Android.bp
old mode 100755
new mode 100644
index 3c16d57..06e167c
--- a/cas/aidl/default/Android.bp
+++ b/cas/aidl/default/Android.bp
@@ -21,10 +21,12 @@
 
     shared_libs: [
         "android.hardware.cas-V1-ndk",
+        "libbase",
         "libbinder_ndk",
         "liblog",
         "libutils",
         "libcutils",
+        "libvndksupport",
     ],
     static_libs: [
         "libaidlcommonsupport",
@@ -42,37 +44,44 @@
 
     srcs: ["service.cpp"],
 
+    stl: "c++_static",
     static_libs: [
+        "android.hardware.cas-V1-ndk",
+        "android.hardware.common-V2-ndk",
         "libaidlcommonsupport",
+        "libbase",
         "libcasexampleimpl",
+        "libcutils",
+        "libutils",
     ],
     shared_libs: [
-        "android.hardware.cas-V1-ndk",
         "libbinder_ndk",
         "liblog",
-        "libutils",
-        "libcutils",
     ],
     header_libs: ["media_plugin_headers"],
-    vintf_fragments: ["android.hardware.cas-service.xml"],
 }
 
 cc_binary {
     name: "android.hardware.cas-service.example",
     defaults: ["cas_service_example_defaults"],
-    init_rc: ["cas-default.rc"],
+    // Installed in APEX
+    installable: false,
 }
 
+// TODO(b/297467514) Convert to VAPEX
 cc_binary {
     name: "android.hardware.cas-service.example-lazy",
     defaults: ["cas_service_example_defaults"],
     init_rc: ["cas-default-lazy.rc"],
+    vintf_fragments: ["android.hardware.cas-service.xml"],
     cflags: ["-DLAZY_SERVICE"],
+    overrides: ["com.android.hardware.cas"],
 }
 
 cc_fuzz {
     name: "android.hardware.cas-service_fuzzer",
-    vendor: true,
+    // TODO(b/307611931): avoid fuzzing on vendor until hermiticity issue is fixed
+    // vendor: true,
 
     defaults: ["service_fuzzer_defaults"],
     srcs: ["fuzzer.cpp"],
@@ -81,6 +90,7 @@
         "android.hardware.cas-V1-ndk",
         "libcutils",
         "liblog",
+        "libvndksupport",
     ],
     static_libs: [
         "libaidlcommonsupport",
@@ -91,3 +101,34 @@
         componentid: 1344,
     },
 }
+
+apex {
+    name: "com.android.hardware.cas",
+    manifest: "manifest.json",
+    file_contexts: "file_contexts",
+    key: "com.android.hardware.key",
+    certificate: ":com.android.hardware.certificate",
+    updatable: false,
+    vendor: true,
+
+    binaries: [
+        "android.hardware.cas-service.example",
+    ],
+    prebuilts: [
+        "cas-default.rc",
+        "android.hardware.cas-service.xml",
+    ],
+}
+
+prebuilt_etc {
+    name: "cas-default.rc",
+    src: "cas-default.rc",
+    installable: false,
+}
+
+prebuilt_etc {
+    name: "android.hardware.cas-service.xml",
+    src: "android.hardware.cas-service.xml",
+    sub_dir: "vintf",
+    installable: false,
+}
diff --git a/cas/aidl/default/CasImpl.cpp b/cas/aidl/default/CasImpl.cpp
old mode 100755
new mode 100644
index f08fcc0..9885e16
--- a/cas/aidl/default/CasImpl.cpp
+++ b/cas/aidl/default/CasImpl.cpp
@@ -158,7 +158,7 @@
 
 ScopedAStatus CasImpl::setSessionPrivateData(const vector<uint8_t>& sessionId,
                                              const vector<uint8_t>& pvtData) {
-    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string());
+    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).c_str());
     shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
     if (holder.get() == nullptr) {
         return toStatus(INVALID_OPERATION);
@@ -167,7 +167,7 @@
 }
 
 ScopedAStatus CasImpl::closeSession(const vector<uint8_t>& sessionId) {
-    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string());
+    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).c_str());
     shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
     if (holder.get() == nullptr) {
         return toStatus(INVALID_OPERATION);
@@ -176,7 +176,7 @@
 }
 
 ScopedAStatus CasImpl::processEcm(const vector<uint8_t>& sessionId, const vector<uint8_t>& ecm) {
-    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string());
+    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).c_str());
     shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
     if (holder.get() == nullptr) {
         return toStatus(INVALID_OPERATION);
diff --git a/cas/aidl/default/CasImpl.h b/cas/aidl/default/CasImpl.h
old mode 100755
new mode 100644
diff --git a/cas/aidl/default/DescramblerImpl.cpp b/cas/aidl/default/DescramblerImpl.cpp
old mode 100755
new mode 100644
index a96fd46..0f4e99b
--- a/cas/aidl/default/DescramblerImpl.cpp
+++ b/cas/aidl/default/DescramblerImpl.cpp
@@ -54,7 +54,7 @@
 }
 
 ScopedAStatus DescramblerImpl::setMediaCasSession(const vector<uint8_t>& in_sessionId) {
-    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(in_sessionId).string());
+    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(in_sessionId).c_str());
 
     shared_ptr<DescramblerPlugin> holder = atomic_load(&mPluginHolder);
     if (holder.get() == nullptr) {
@@ -71,7 +71,7 @@
         *_aidl_return = false;
     }
 
-    *_aidl_return = holder->requiresSecureDecoderComponent(String8(in_mime.c_str()));
+    *_aidl_return = holder->requiresSecureDecoderComponent(in_mime.c_str());
     return ScopedAStatus::ok();
 }
 
diff --git a/cas/aidl/default/DescramblerImpl.h b/cas/aidl/default/DescramblerImpl.h
old mode 100755
new mode 100644
diff --git a/cas/aidl/default/FactoryLoader.h b/cas/aidl/default/FactoryLoader.h
old mode 100755
new mode 100644
index 6a562f6..bc3d715
--- a/cas/aidl/default/FactoryLoader.h
+++ b/cas/aidl/default/FactoryLoader.h
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <android-base/strings.h>
 #include <dirent.h>
 #include <dlfcn.h>
 #include <media/cas/CasAPI.h>
@@ -86,17 +87,17 @@
 #else
     String8 dirPath("/vendor/lib/mediacas");
 #endif
-    DIR* pDir = opendir(dirPath.string());
+    DIR* pDir = opendir(dirPath.c_str());
 
     if (pDir == NULL) {
-        ALOGE("Failed to open plugin directory %s", dirPath.string());
+        ALOGE("Failed to open plugin directory %s", dirPath.c_str());
         return false;
     }
 
     struct dirent* pEntry;
     while ((pEntry = readdir(pDir))) {
         String8 pluginPath = dirPath + "/" + pEntry->d_name;
-        if (pluginPath.getPathExtension() == ".so") {
+        if (base::EndsWith(pluginPath.c_str(), ".so")) {
             if (loadFactoryForSchemeFromPath(pluginPath, CA_system_id, library, factory)) {
                 mCASystemIdToLibraryPathMap.add(CA_system_id, pluginPath);
                 closedir(pDir);
@@ -123,10 +124,10 @@
 #else
     String8 dirPath("/vendor/lib/mediacas");
 #endif
-    DIR* pDir = opendir(dirPath.string());
+    DIR* pDir = opendir(dirPath.c_str());
 
     if (pDir == NULL) {
-        ALOGE("Failed to open plugin directory %s", dirPath.string());
+        ALOGE("Failed to open plugin directory %s", dirPath.c_str());
         return false;
     }
 
@@ -135,7 +136,7 @@
     struct dirent* pEntry;
     while ((pEntry = readdir(pDir))) {
         String8 pluginPath = dirPath + "/" + pEntry->d_name;
-        if (pluginPath.getPathExtension() == ".so") {
+        if (base::EndsWith(pluginPath.c_str(), ".so")) {
             queryPluginsFromPath(pluginPath, results);
         }
     }
diff --git a/cas/aidl/default/MediaCasService.cpp b/cas/aidl/default/MediaCasService.cpp
old mode 100755
new mode 100644
diff --git a/cas/aidl/default/MediaCasService.h b/cas/aidl/default/MediaCasService.h
old mode 100755
new mode 100644
diff --git a/cas/aidl/default/SharedLibrary.cpp b/cas/aidl/default/SharedLibrary.cpp
old mode 100755
new mode 100644
index e79f383..c12d17d
--- a/cas/aidl/default/SharedLibrary.cpp
+++ b/cas/aidl/default/SharedLibrary.cpp
@@ -26,7 +26,7 @@
 namespace cas {
 
 SharedLibrary::SharedLibrary(const String8& path) {
-    mLibHandle = dlopen(path.string(), RTLD_NOW);
+    mLibHandle = dlopen(path.c_str(), RTLD_NOW);
 }
 
 SharedLibrary::~SharedLibrary() {
diff --git a/cas/aidl/default/SharedLibrary.h b/cas/aidl/default/SharedLibrary.h
old mode 100755
new mode 100644
diff --git a/cas/aidl/default/TypeConvert.cpp b/cas/aidl/default/TypeConvert.cpp
old mode 100755
new mode 100644
index 4f7005f..1f0a46d
--- a/cas/aidl/default/TypeConvert.cpp
+++ b/cas/aidl/default/TypeConvert.cpp
@@ -98,7 +98,7 @@
     for (auto it = sessionId.begin(); it != sessionId.end(); it++) {
         result.appendFormat("%02x ", *it);
     }
-    if (result.isEmpty()) {
+    if (result.empty()) {
         result.append("(null)");
     }
     return result;
diff --git a/cas/aidl/default/TypeConvert.h b/cas/aidl/default/TypeConvert.h
old mode 100755
new mode 100644
diff --git a/cas/aidl/default/android.hardware.cas-service.xml b/cas/aidl/default/android.hardware.cas-service.xml
old mode 100755
new mode 100644
diff --git a/cas/aidl/default/cas-default-lazy.rc b/cas/aidl/default/cas-default-lazy.rc
old mode 100755
new mode 100644
index 60b59ca..7321cf0
--- a/cas/aidl/default/cas-default-lazy.rc
+++ b/cas/aidl/default/cas-default-lazy.rc
@@ -3,6 +3,7 @@
     class hal
     user media
     group mediadrm drmrpc
+    capabilities SYS_NICE
     ioprio rt 4
     task_profiles ProcessCapacityHigh
     oneshot
diff --git a/cas/aidl/default/cas-default.rc b/cas/aidl/default/cas-default.rc
old mode 100755
new mode 100644
index e00b9c5..0ac7fe5
--- a/cas/aidl/default/cas-default.rc
+++ b/cas/aidl/default/cas-default.rc
@@ -1,7 +1,8 @@
-service vendor.cas-default /vendor/bin/hw/android.hardware.cas-service.example
+service vendor.cas-default /apex/com.android.hardware.cas/bin/hw/android.hardware.cas-service.example
     interface aidl android.hardware.cas.IMediaCasService/default
     class hal
     user media
     group mediadrm drmrpc
+    capabilities SYS_NICE
     ioprio rt 4
     task_profiles ProcessCapacityHigh
diff --git a/cas/aidl/default/file_contexts b/cas/aidl/default/file_contexts
new file mode 100644
index 0000000..98bde53
--- /dev/null
+++ b/cas/aidl/default/file_contexts
@@ -0,0 +1,3 @@
+(/.*)?                                                          u:object_r:vendor_file:s0
+/etc(/.*)?                                                      u:object_r:vendor_configs_file:s0
+/bin/hw/android\.hardware\.cas-service\.example                 u:object_r:hal_cas_default_exec:s0
diff --git a/cas/aidl/default/fuzzer.cpp b/cas/aidl/default/fuzzer.cpp
old mode 100755
new mode 100644
diff --git a/cas/aidl/default/manifest.json b/cas/aidl/default/manifest.json
new file mode 100644
index 0000000..cdcecb2
--- /dev/null
+++ b/cas/aidl/default/manifest.json
@@ -0,0 +1,8 @@
+{
+    "name": "com.android.hardware.cas",
+    "version": 1,
+    // For CAS HAL to open plugins from /vendor/lib/mediacas
+    "requireNativeLibs": [
+        ":mediacas"
+    ]
+}
diff --git a/cas/aidl/default/service.cpp b/cas/aidl/default/service.cpp
old mode 100755
new mode 100644
index bed2f01..076c7bb
--- a/cas/aidl/default/service.cpp
+++ b/cas/aidl/default/service.cpp
@@ -31,6 +31,7 @@
 
 int main() {
     ABinderProcess_setThreadPoolMaxThreadCount(8);
+    ABinderProcess_startThreadPool();
 
     // Setup hwbinder service
     std::shared_ptr<MediaCasService> service = ::ndk::SharedRefBase::make<MediaCasService>();
diff --git a/cas/aidl/vts/functional/OWNERS b/cas/aidl/vts/functional/OWNERS
deleted file mode 100644
index 4c55752..0000000
--- a/cas/aidl/vts/functional/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 1344
-quxiangfang@google.com
-hgchen@google.com
diff --git a/common/OWNERS b/common/OWNERS
new file mode 100644
index 0000000..a07824e
--- /dev/null
+++ b/common/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 298954331
+
+include platform/hardware/interfaces:/OWNERS
diff --git a/common/aidl/Android.bp b/common/aidl/Android.bp
index f3ea8e8..1457b8a 100644
--- a/common/aidl/Android.bp
+++ b/common/aidl/Android.bp
@@ -38,7 +38,7 @@
         },
         rust: {
             enabled: true,
-        }
+        },
     },
     frozen: true,
     versions: [
diff --git a/common/fmq/aidl/Android.bp b/common/fmq/aidl/Android.bp
index 3b022fc..6c37213 100644
--- a/common/fmq/aidl/Android.bp
+++ b/common/fmq/aidl/Android.bp
@@ -43,8 +43,9 @@
             min_sdk_version: "29",
         },
         rust: {
-            // FMQ is not supported in the rust backend
-            enabled: false,
+            // FMQ is not supported in the rust backend, but we need this AIDL interface for
+            // HardwareBuffer.
+            enabled: true,
         },
     },
     frozen: true,
diff --git a/compatibility_matrices/Android.bp b/compatibility_matrices/Android.bp
index 93b5380..eefca39 100644
--- a/compatibility_matrices/Android.bp
+++ b/compatibility_matrices/Android.bp
@@ -82,3 +82,15 @@
         "kernel_config_u_6.1",
     ],
 }
+
+vintf_compatibility_matrix {
+    name: "framework_compatibility_matrix.202404.xml",
+    stem: "compatibility_matrix.202404.xml",
+    srcs: [
+        "compatibility_matrix.202404.xml",
+    ],
+    kernel_configs: [
+        "kernel_config_v_6.1",
+        "kernel_config_v_6.6",
+    ],
+}
diff --git a/compatibility_matrices/Android.mk b/compatibility_matrices/Android.mk
index 6e4c419..72ead58 100644
--- a/compatibility_matrices/Android.mk
+++ b/compatibility_matrices/Android.mk
@@ -56,6 +56,9 @@
 
 endif # DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE
 
+# TODO(b/296875906): use POLICYVERS from Soong
+POLICYVERS ?= 30
+
 LOCAL_ADD_VBMETA_VERSION := true
 LOCAL_ASSEMBLE_VINTF_ENV_VARS := \
     POLICYVERS \
@@ -105,6 +108,13 @@
     framework_compatibility_matrix.8.xml \
     framework_compatibility_matrix.device.xml \
 
+# Only allow the use of the unreleased compatibility matrix when we can use unfrozen
+# interfaces (in the `next` release configuration).
+ifeq ($(RELEASE_AIDL_USE_UNFROZEN),true)
+my_system_matrix_deps += \
+    framework_compatibility_matrix.202404.xml
+endif
+
 my_framework_matrix_deps += \
     $(my_system_matrix_deps)
 
diff --git a/compatibility_matrices/OWNERS b/compatibility_matrices/OWNERS
new file mode 100644
index 0000000..a07824e
--- /dev/null
+++ b/compatibility_matrices/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 298954331
+
+include platform/hardware/interfaces:/OWNERS
diff --git a/compatibility_matrices/bump.py b/compatibility_matrices/bump.py
new file mode 100755
index 0000000..88b7a42
--- /dev/null
+++ b/compatibility_matrices/bump.py
@@ -0,0 +1,158 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2023 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+"""
+Creates the next compatibility matrix.
+
+Requires libvintf Level.h to be updated before executing this script.
+"""
+
+import argparse
+import os
+import pathlib
+import shutil
+import subprocess
+import textwrap
+
+
+def check_call(*args, **kwargs):
+    print(args)
+    subprocess.check_call(*args, **kwargs)
+
+
+def check_output(*args, **kwargs):
+    print(args)
+    return subprocess.check_output(*args, **kwargs)
+
+
+class Bump(object):
+
+    def __init__(self, cmdline_args):
+        self.top = pathlib.Path(os.environ["ANDROID_BUILD_TOP"])
+        self.interfaces_dir = self.top / "hardware/interfaces"
+
+        self.current_level = cmdline_args.current
+        self.current_module_name = f"framework_compatibility_matrix.{self.current_level}.xml"
+        self.current_xml = self.interfaces_dir / f"compatibility_matrices/compatibility_matrix.{self.current_level}.xml"
+
+        self.next_level = cmdline_args.next
+        self.next_module_name = f"framework_compatibility_matrix.{self.next_level}.xml"
+        self.next_xml = self.interfaces_dir / f"compatibility_matrices/compatibility_matrix.{self.next_level}.xml"
+
+        self.level_to_letter = self.get_level_to_letter_mapping()
+        print("Found level mapping in libvintf Level.h:", self.level_to_letter)
+
+    def run(self):
+        self.bump_kernel_configs()
+        self.copy_matrix()
+        self.edit_android_bp()
+        self.edit_android_mk()
+
+    def get_level_to_letter_mapping(self):
+        levels_file = self.top / "system/libvintf/include/vintf/Level.h"
+        with open(levels_file) as f:
+            lines = f.readlines()
+            pairs = [
+                line.split("=", maxsplit=2) for line in lines if "=" in line
+            ]
+            return {
+                level.strip().removesuffix(","): letter.strip()
+                for letter, level in pairs
+            }
+
+    def bump_kernel_configs(self):
+        check_call([
+            self.top / "kernel/configs/tools/bump.py",
+            self.level_to_letter[self.current_level].lower(),
+            self.level_to_letter[self.next_level].lower(),
+        ])
+
+    def copy_matrix(self):
+        shutil.copyfile(self.current_xml, self.next_xml)
+
+    def edit_android_bp(self):
+        android_bp = self.interfaces_dir / "compatibility_matrices/Android.bp"
+
+        with open(android_bp, "r+") as f:
+            if self.next_module_name not in f.read():
+                f.seek(0, 2)  # end of file
+                f.write("\n")
+                f.write(
+                    textwrap.dedent(f"""\
+                        vintf_compatibility_matrix {{
+                            name: "{self.next_module_name}",
+                        }}
+                    """))
+
+        next_kernel_configs = check_output(
+            """grep -rh name: | sed -E 's/^.*"(.*)".*/\\1/g'""",
+            cwd=self.top / "kernel/configs" /
+            self.level_to_letter[self.next_level].lower(),
+            text=True,
+            shell=True,
+        ).splitlines()
+        print(next_kernel_configs)
+
+        check_call([
+            "bpmodify", "-w", "-m", self.next_module_name, "-property", "stem",
+            "-str", self.next_xml.name, android_bp
+        ])
+
+        check_call([
+            "bpmodify", "-w", "-m", self.next_module_name, "-property", "srcs",
+            "-a",
+            self.next_xml.relative_to(android_bp.parent), android_bp
+        ])
+
+        check_call([
+            "bpmodify", "-w", "-m", self.next_module_name, "-property",
+            "kernel_configs", "-a", " ".join(next_kernel_configs), android_bp
+        ])
+
+    def edit_android_mk(self):
+        android_mk = self.interfaces_dir / "compatibility_matrices/Android.mk"
+        with open(android_mk) as f:
+            if self.next_module_name in f.read():
+                return
+            f.seek(0)
+            lines = f.readlines()
+        current_module_line_number = None
+        for line_number, line in enumerate(lines):
+            if self.current_module_name in line:
+                current_module_line_number = line_number
+                break
+        assert current_module_line_number is not None
+        lines.insert(current_module_line_number + 1,
+                     f"    {self.next_module_name} \\\n")
+        with open(android_mk, "w") as f:
+            f.write("".join(lines))
+
+
+def main():
+    parser = argparse.ArgumentParser(description=__doc__)
+    parser.add_argument("current",
+                        type=str,
+                        help="VINTF level of the current version (e.g. 9)")
+    parser.add_argument("next",
+                        type=str,
+                        help="VINTF level of the next version (e.g. 10)")
+    cmdline_args = parser.parse_args()
+
+    Bump(cmdline_args).run()
+
+
+if __name__ == "__main__":
+    main()
diff --git a/compatibility_matrices/compatibility_matrix.202404.xml b/compatibility_matrices/compatibility_matrix.202404.xml
new file mode 100644
index 0000000..2080c69
--- /dev/null
+++ b/compatibility_matrices/compatibility_matrix.202404.xml
@@ -0,0 +1,712 @@
+<compatibility-matrix version="1.0" type="framework" level="202404">
+    <hal format="aidl">
+        <name>android.hardware.audio.core</name>
+        <version>1-2</version>
+        <interface>
+            <name>IModule</name>
+            <instance>default</instance>
+            <instance>a2dp</instance>
+            <instance>bluetooth</instance>
+            <instance>hearing_aid</instance>
+            <instance>msd</instance>
+            <instance>r_submix</instance>
+            <instance>stub</instance>
+            <instance>usb</instance>
+        </interface>
+        <interface>
+            <name>IConfig</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.audio.effect</name>
+        <version>1-2</version>
+        <interface>
+            <name>IFactory</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.audio.sounddose</name>
+        <version>1-2</version>
+        <interface>
+            <name>ISoundDoseFactory</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl" updatable-via-apex="true">
+         <name>android.hardware.authsecret</name>
+         <version>1</version>
+         <interface>
+             <name>IAuthSecret</name>
+             <instance>default</instance>
+         </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.automotive.audiocontrol</name>
+        <version>2-4</version>
+        <interface>
+            <name>IAudioControl</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.automotive.can</name>
+        <version>1</version>
+        <interface>
+            <name>ICanController</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.automotive.evs</name>
+        <version>1-2</version>
+        <interface>
+            <name>IEvsEnumerator</name>
+            <regex-instance>[a-z]+/[0-9]+</regex-instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.macsec</name>
+        <version>1</version>
+        <interface>
+            <name>IMacsecPskPlugin</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.automotive.occupant_awareness</name>
+        <version>1</version>
+        <interface>
+            <name>IOccupantAwareness</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.automotive.vehicle</name>
+        <version>1-3</version>
+        <interface>
+            <name>IVehicle</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.automotive.remoteaccess</name>
+        <version>1-2</version>
+        <interface>
+            <name>IRemoteAccess</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.automotive.ivn</name>
+        <interface>
+            <name>IIvnAndroidDevice</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl" updatable-via-apex="true">
+        <name>android.hardware.biometrics.face</name>
+        <version>3-4</version>
+        <interface>
+            <name>IFace</name>
+            <instance>default</instance>
+            <instance>virtual</instance>
+        </interface>
+    </hal>
+    <hal format="aidl" updatable-via-apex="true">
+        <name>android.hardware.biometrics.fingerprint</name>
+        <version>3-4</version>
+        <interface>
+            <name>IFingerprint</name>
+            <instance>default</instance>
+            <instance>virtual</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.bluetooth</name>
+        <interface>
+            <name>IBluetoothHci</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.bluetooth.audio</name>
+        <version>3-4</version>
+        <interface>
+            <name>IBluetoothAudioProviderFactory</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.bluetooth.ranging</name>
+        <version>1</version>
+        <interface>
+            <name>IBluetoothChannelSounding</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.bluetooth.finder</name>
+        <version>1</version>
+        <interface>
+            <name>IBluetoothFinder</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.bluetooth.lmp_event</name>
+        <version>1</version>
+        <interface>
+            <name>IBluetoothLmpEvent</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.boot</name>
+        <interface>
+            <name>IBootControl</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.broadcastradio</name>
+        <version>1-2</version>
+        <interface>
+            <name>IBroadcastRadio</name>
+            <regex-instance>.*</regex-instance>
+        </interface>
+    </hal>
+    <hal format="aidl" updatable-via-apex="true">
+        <name>android.hardware.camera.provider</name>
+        <version>1-3</version>
+        <interface>
+            <name>ICameraProvider</name>
+            <regex-instance>[^/]+/[0-9]+</regex-instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.cas</name>
+        <interface>
+            <name>IMediaCasService</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.confirmationui</name>
+        <version>1</version>
+        <interface>
+            <name>IConfirmationUI</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.contexthub</name>
+        <version>3</version>
+        <interface>
+            <name>IContextHub</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl" updatable-via-apex="true">
+        <name>android.hardware.drm</name>
+        <version>1</version>
+        <interface>
+            <name>IDrmFactory</name>
+            <regex-instance>.*</regex-instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.dumpstate</name>
+        <interface>
+            <name>IDumpstateDevice</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.gatekeeper</name>
+        <version>1</version>
+        <interface>
+            <name>IGatekeeper</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.gnss</name>
+        <version>2-4</version>
+        <interface>
+            <name>IGnss</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.graphics.allocator</name>
+        <version>1-2</version>
+        <interface>
+            <name>IAllocator</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.graphics.composer3</name>
+        <version>3</version>
+        <interface>
+            <name>IComposer</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.health</name>
+        <version>3</version>
+        <interface>
+            <name>IHealth</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.health.storage</name>
+        <version>1</version>
+        <interface>
+            <name>IStorage</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.identity</name>
+        <version>1-5</version>
+        <interface>
+            <name>IIdentityCredentialStore</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.net.nlinterceptor</name>
+        <interface>
+            <name>IInterceptor</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.oemlock</name>
+        <version>1</version>
+        <interface>
+            <name>IOemLock</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.ir</name>
+        <version>1</version>
+        <interface>
+            <name>IConsumerIr</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.input.processor</name>
+        <version>1</version>
+        <interface>
+            <name>IInputProcessor</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.security.secretkeeper</name>
+        <version>1</version>
+        <interface>
+            <name>ISecretkeeper</name>
+            <instance>default</instance>
+            <instance>nonsecure</instance>
+        </interface>
+    </hal>
+    <hal format="aidl" updatable-via-apex="true">
+        <name>android.hardware.security.keymint</name>
+        <version>1-3</version>
+        <interface>
+            <name>IKeyMintDevice</name>
+            <instance>default</instance>
+            <instance>strongbox</instance>
+        </interface>
+    </hal>
+    <hal format="aidl" updatable-via-apex="true">
+        <name>android.hardware.security.keymint</name>
+        <version>1-3</version>
+        <interface>
+            <name>IRemotelyProvisionedComponent</name>
+            <instance>default</instance>
+            <instance>strongbox</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.light</name>
+        <version>2</version>
+        <interface>
+            <name>ILights</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
+        <name>android.hardware.media.c2</name>
+        <version>1.0-2</version>
+        <interface>
+            <name>IComponentStore</name>
+            <instance>software</instance>
+            <regex-instance>default[0-9]*</regex-instance>
+            <regex-instance>vendor[0-9]*_software</regex-instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
+        <name>android.hardware.media.c2</name>
+        <version>1.0</version>
+        <interface>
+            <name>IConfigurable</name>
+            <instance>default</instance>
+            <instance>software</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.media.c2</name>
+        <version>1</version>
+        <interface>
+            <name>IComponentStore</name>
+            <regex-instance>default[0-9]*</regex-instance>
+            <regex-instance>vendor[0-9]*_software</regex-instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.memtrack</name>
+        <version>1</version>
+        <interface>
+            <name>IMemtrack</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl" updatable-via-apex="true">
+        <name>android.hardware.neuralnetworks</name>
+        <version>1-4</version>
+        <interface>
+            <name>IDevice</name>
+            <regex-instance>.*</regex-instance>
+        </interface>
+    </hal>
+    <hal format="aidl" updatable-via-apex="true">
+        <name>android.hardware.nfc</name>
+        <interface>
+            <name>INfc</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.power</name>
+        <version>5</version>
+        <interface>
+            <name>IPower</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.power.stats</name>
+        <version>2</version>
+        <interface>
+            <name>IPowerStats</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.radio.config</name>
+        <version>3</version>
+        <interface>
+            <name>IRadioConfig</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.radio.data</name>
+        <version>3</version>
+        <interface>
+            <name>IRadioData</name>
+            <instance>slot1</instance>
+            <instance>slot2</instance>
+            <instance>slot3</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.radio.messaging</name>
+        <version>3</version>
+        <interface>
+            <name>IRadioMessaging</name>
+            <instance>slot1</instance>
+            <instance>slot2</instance>
+            <instance>slot3</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.radio.modem</name>
+        <version>3</version>
+        <interface>
+            <name>IRadioModem</name>
+            <instance>slot1</instance>
+            <instance>slot2</instance>
+            <instance>slot3</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.radio.network</name>
+        <version>3</version>
+        <interface>
+            <name>IRadioNetwork</name>
+            <instance>slot1</instance>
+            <instance>slot2</instance>
+            <instance>slot3</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.radio.sim</name>
+        <version>3</version>
+        <interface>
+            <name>IRadioSim</name>
+            <instance>slot1</instance>
+            <instance>slot2</instance>
+            <instance>slot3</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.radio.sap</name>
+        <version>1</version>
+        <interface>
+            <name>ISap</name>
+            <instance>slot1</instance>
+            <instance>slot2</instance>
+            <instance>slot3</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.radio.voice</name>
+        <version>3</version>
+        <interface>
+            <name>IRadioVoice</name>
+            <instance>slot1</instance>
+            <instance>slot2</instance>
+            <instance>slot3</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.radio.ims</name>
+        <version>2</version>
+        <interface>
+            <name>IRadioIms</name>
+            <instance>slot1</instance>
+            <instance>slot2</instance>
+            <instance>slot3</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.radio.ims.media</name>
+        <version>2</version>
+        <interface>
+            <name>IImsMedia</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.rebootescrow</name>
+        <version>1</version>
+        <interface>
+            <name>IRebootEscrow</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.secure_element</name>
+        <version>1</version>
+        <interface>
+            <name>ISecureElement</name>
+            <regex-instance>eSE[1-9][0-9]*</regex-instance>
+            <regex-instance>SIM[1-9][0-9]*</regex-instance>
+        </interface>
+    </hal>
+    <hal format="aidl" updatable-via-apex="true">
+        <name>android.hardware.security.authgraph</name>
+        <version>1</version>
+        <interface>
+            <name>IAuthGraphKeyExchange</name>
+            <instance>nonsecure</instance>
+        </interface>
+    </hal>
+    <hal format="aidl" updatable-via-apex="true">
+        <name>android.hardware.security.secureclock</name>
+        <version>1</version>
+        <interface>
+            <name>ISecureClock</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl" updatable-via-apex="true">
+        <name>android.hardware.security.sharedsecret</name>
+        <version>1</version>
+        <interface>
+            <name>ISharedSecret</name>
+            <instance>default</instance>
+            <instance>strongbox</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.sensors</name>
+        <version>2</version>
+        <interface>
+            <name>ISensors</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+         <name>android.hardware.soundtrigger3</name>
+         <version>1-2</version>
+         <interface>
+             <name>ISoundTriggerHw</name>
+             <instance>default</instance>
+         </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.tetheroffload</name>
+        <version>1</version>
+        <interface>
+            <name>IOffload</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.thermal</name>
+        <version>2</version>
+        <interface>
+            <name>IThermal</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl" updatable-via-apex="true">
+        <name>android.hardware.threadnetwork</name>
+        <version>1</version>
+        <interface>
+            <name>IThreadChip</name>
+            <regex-instance>chip[0-9]+</regex-instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.tv.hdmi.cec</name>
+        <version>1</version>
+        <interface>
+            <name>IHdmiCec</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.tv.hdmi.earc</name>
+        <version>1</version>
+        <interface>
+            <name>IEArc</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.tv.hdmi.connection</name>
+        <version>1</version>
+        <interface>
+            <name>IHdmiConnection</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.tv.tuner</name>
+        <version>1-2</version>
+        <interface>
+            <name>ITuner</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.tv.input</name>
+        <version>1-2</version>
+        <interface>
+            <name>ITvInput</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.usb</name>
+        <version>1-3</version>
+        <interface>
+            <name>IUsb</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.usb.gadget</name>
+        <interface>
+            <name>IUsbGadget</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.vibrator</name>
+        <version>1-2</version>
+        <interface>
+            <name>IVibrator</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.vibrator</name>
+        <version>1-2</version>
+        <interface>
+            <name>IVibratorManager</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.weaver</name>
+        <version>2</version>
+        <interface>
+            <name>IWeaver</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl" updatable-via-apex="true">
+        <name>android.hardware.wifi</name>
+        <version>1-2</version>
+        <interface>
+            <name>IWifi</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl" updatable-via-apex="true">
+        <name>android.hardware.uwb</name>
+        <version>1</version>
+        <interface>
+            <name>IUwb</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.wifi.hostapd</name>
+        <version>1-2</version>
+        <interface>
+            <name>IHostapd</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.wifi.supplicant</name>
+        <version>2-3</version>
+        <interface>
+            <name>ISupplicant</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <!-- The native mapper HAL must exist on the device -->
+    <hal format="native">
+        <name>mapper</name>
+        <version>5.0</version>
+        <interface>
+            <regex-instance>.*</regex-instance>
+        </interface>
+    </hal>
+</compatibility-matrix>
diff --git a/compatibility_matrices/compatibility_matrix.4.xml b/compatibility_matrices/compatibility_matrix.4.xml
index b9fb3f4..952f53d 100644
--- a/compatibility_matrices/compatibility_matrix.4.xml
+++ b/compatibility_matrices/compatibility_matrix.4.xml
@@ -1,5 +1,5 @@
 <compatibility-matrix version="1.0" type="framework" level="4">
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.atrace</name>
         <version>1.0</version>
         <interface>
@@ -7,7 +7,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.audio</name>
         <version>5.0</version>
         <interface>
@@ -15,7 +15,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.audio.effect</name>
         <version>5.0</version>
         <interface>
@@ -23,7 +23,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.authsecret</name>
         <version>1.0</version>
         <interface>
@@ -31,7 +31,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.automotive.audiocontrol</name>
         <version>1.0</version>
         <interface>
@@ -39,7 +39,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.automotive.evs</name>
         <version>1.0</version>
         <interface>
@@ -47,7 +47,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.automotive.vehicle</name>
         <version>2.0</version>
         <interface>
@@ -55,7 +55,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.biometrics.face</name>
         <version>1.0</version>
         <interface>
@@ -63,7 +63,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.biometrics.fingerprint</name>
         <version>2.1</version>
         <interface>
@@ -71,7 +71,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.bluetooth</name>
         <version>1.0</version>
         <interface>
@@ -79,7 +79,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.bluetooth.audio</name>
         <version>2.0</version>
         <interface>
@@ -87,7 +87,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.boot</name>
         <version>1.0</version>
         <interface>
@@ -95,7 +95,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.broadcastradio</name>
         <version>1.0-1</version>
         <interface>
@@ -103,7 +103,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.broadcastradio</name>
         <version>2.0</version>
         <interface>
@@ -111,7 +111,7 @@
             <regex-instance>.*</regex-instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.camera.provider</name>
         <version>2.4-5</version>
         <interface>
@@ -119,7 +119,7 @@
             <regex-instance>[^/]+/[0-9]+</regex-instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.cas</name>
         <version>1.1</version>
         <interface>
@@ -127,7 +127,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.configstore</name>
         <version>1.1</version>
         <interface>
@@ -135,7 +135,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.confirmationui</name>
         <version>1.0</version>
         <interface>
@@ -143,7 +143,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.contexthub</name>
         <version>1.0</version>
         <interface>
@@ -151,7 +151,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.drm</name>
         <version>1.0-2</version>
         <interface>
@@ -163,7 +163,7 @@
             <regex-instance>.*</regex-instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.dumpstate</name>
         <version>1.0</version>
         <interface>
@@ -171,7 +171,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.gatekeeper</name>
         <version>1.0</version>
         <interface>
@@ -179,7 +179,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.gnss</name>
         <version>2.0</version>
         <interface>
@@ -190,7 +190,7 @@
     <!-- Either the AIDL or the HIDL allocator HAL must exist on the device.
          If the HIDL composer HAL exists, it must be at least version 2.0.
          See DeviceManifestTest.GrallocHal -->
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.graphics.allocator</name>
         <version>2.0</version>
         <version>3.0</version>
@@ -199,7 +199,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.graphics.composer</name>
         <version>2.1-3</version>
         <interface>
@@ -207,7 +207,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.graphics.mapper</name>
         <version>2.1</version>
         <version>3.0</version>
@@ -219,7 +219,7 @@
     <!-- Either the AIDL or the HIDL health HAL must exist on the device.
          If the HIDL health HAL exists, it must be at least version 2.0.
          See DeviceManifestTest.HealthHal -->
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.health</name>
         <version>2.0</version>
         <interface>
@@ -227,7 +227,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.health.storage</name>
         <version>1.0</version>
         <interface>
@@ -235,7 +235,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.ir</name>
         <version>1.0</version>
         <interface>
@@ -243,7 +243,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.input.classifier</name>
         <version>1.0</version>
         <interface>
@@ -251,7 +251,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.keymaster</name>
         <version>3.0</version>
         <version>4.0</version>
@@ -260,7 +260,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.keymaster</name>
         <version>4.0</version>
         <interface>
@@ -268,7 +268,7 @@
             <instance>strongbox</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.light</name>
         <version>2.0</version>
         <interface>
@@ -276,16 +276,22 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.media.c2</name>
         <version>1.0</version>
         <interface>
             <name>IComponentStore</name>
+            <instance>software</instance>
             <regex-instance>default[0-9]*</regex-instance>
             <regex-instance>vendor[0-9]*_software</regex-instance>
         </interface>
+        <interface>
+            <name>IConfigurable</name>
+            <instance>default</instance>
+            <instance>software</instance>
+        </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.media.omx</name>
         <version>1.0</version>
         <interface>
@@ -297,7 +303,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.memtrack</name>
         <version>1.0</version>
         <interface>
@@ -305,7 +311,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.neuralnetworks</name>
         <version>1.0-2</version>
         <interface>
@@ -313,7 +319,7 @@
             <regex-instance>.*</regex-instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.nfc</name>
         <version>1.2</version>
         <interface>
@@ -321,7 +327,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.oemlock</name>
         <version>1.0</version>
         <interface>
@@ -329,7 +335,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.power</name>
         <version>1.0-3</version>
         <interface>
@@ -337,7 +343,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.power.stats</name>
         <version>1.0</version>
         <interface>
@@ -345,7 +351,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.radio</name>
         <version>1.4</version>
         <interface>
@@ -355,15 +361,16 @@
             <instance>slot3</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.radio</name>
         <version>1.2</version>
         <interface>
             <name>ISap</name>
             <instance>slot1</instance>
+            <instance>slot2</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.radio.config</name>
         <!--
         Note: Devices launching with target-level 4, if implementing the
@@ -377,7 +384,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.renderscript</name>
         <version>1.0</version>
         <interface>
@@ -385,7 +392,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.secure_element</name>
         <version>1.0</version>
         <interface>
@@ -394,7 +401,7 @@
             <regex-instance>SIM[1-9][0-9]*</regex-instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.sensors</name>
         <version>1.0</version>
         <version>2.0</version>
@@ -403,7 +410,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.soundtrigger</name>
         <version>2.0-2</version>
         <interface>
@@ -411,7 +418,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.tetheroffload.config</name>
         <version>1.0</version>
         <interface>
@@ -419,7 +426,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.tetheroffload.control</name>
         <version>1.0</version>
         <interface>
@@ -427,7 +434,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.thermal</name>
         <version>2.0</version>
         <interface>
@@ -435,7 +442,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.tv.cec</name>
         <version>1.0</version>
         <interface>
@@ -443,7 +450,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.tv.input</name>
         <version>1.0</version>
         <interface>
@@ -451,7 +458,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.usb</name>
         <version>1.0-2</version>
         <interface>
@@ -459,7 +466,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.usb.gadget</name>
         <version>1.0</version>
         <interface>
@@ -467,7 +474,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.vibrator</name>
         <version>1.0-3</version>
         <interface>
@@ -475,7 +482,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.vr</name>
         <version>1.0</version>
         <interface>
@@ -483,7 +490,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.weaver</name>
         <version>1.0</version>
         <interface>
@@ -491,7 +498,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.wifi</name>
         <version>1.0-3</version>
         <interface>
@@ -499,7 +506,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.wifi.hostapd</name>
         <version>1.0-1</version>
         <interface>
@@ -507,7 +514,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.wifi.supplicant</name>
         <version>1.0-2</version>
         <interface>
diff --git a/compatibility_matrices/compatibility_matrix.5.xml b/compatibility_matrices/compatibility_matrix.5.xml
index b374c8c..1cf98b0 100644
--- a/compatibility_matrices/compatibility_matrix.5.xml
+++ b/compatibility_matrices/compatibility_matrix.5.xml
@@ -1,5 +1,5 @@
 <compatibility-matrix version="1.0" type="framework" level="5">
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.atrace</name>
         <version>1.0</version>
         <interface>
@@ -7,7 +7,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.audio</name>
         <version>6.0</version>
         <interface>
@@ -15,7 +15,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.audio.effect</name>
         <version>6.0</version>
         <interface>
@@ -23,7 +23,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.authsecret</name>
         <version>1.0</version>
         <interface>
@@ -31,7 +31,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.automotive.audiocontrol</name>
         <version>1.0</version>
         <version>2.0</version>
@@ -40,7 +40,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.automotive.can</name>
         <version>1.0</version>
         <interface>
@@ -52,7 +52,7 @@
             <regex-instance>.*</regex-instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.automotive.evs</name>
         <version>1.0-1</version>
         <interface>
@@ -61,14 +61,14 @@
             <regex-instance>[a-z]+/[0-9]+</regex-instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.automotive.occupant_awareness</name>
         <interface>
             <name>IOccupantAwareness</name>
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.automotive.sv</name>
         <version>1.0</version>
         <interface>
@@ -76,7 +76,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.automotive.vehicle</name>
         <version>2.0</version>
         <interface>
@@ -84,7 +84,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.biometrics.face</name>
         <version>1.0</version>
         <interface>
@@ -92,7 +92,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.biometrics.fingerprint</name>
         <version>2.1-2</version>
         <interface>
@@ -100,7 +100,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.bluetooth</name>
         <version>1.0-1</version>
         <interface>
@@ -108,7 +108,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.bluetooth.audio</name>
         <version>2.0</version>
         <interface>
@@ -116,7 +116,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.boot</name>
         <version>1.1</version>
         <interface>
@@ -124,7 +124,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.broadcastradio</name>
         <version>1.0-1</version>
         <interface>
@@ -132,7 +132,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.broadcastradio</name>
         <version>2.0</version>
         <interface>
@@ -140,7 +140,7 @@
             <regex-instance>.*</regex-instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.camera.provider</name>
         <version>2.4-6</version>
         <interface>
@@ -148,7 +148,7 @@
             <regex-instance>[^/]+/[0-9]+</regex-instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.cas</name>
         <version>1.1-2</version>
         <interface>
@@ -156,7 +156,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.confirmationui</name>
         <version>1.0</version>
         <interface>
@@ -164,7 +164,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.contexthub</name>
         <version>1.0-1</version>
         <interface>
@@ -172,7 +172,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.drm</name>
         <version>1.3</version>
         <interface>
@@ -184,7 +184,7 @@
             <regex-instance>.*</regex-instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.dumpstate</name>
         <version>1.1</version>
         <interface>
@@ -192,7 +192,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.gatekeeper</name>
         <version>1.0</version>
         <interface>
@@ -200,7 +200,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.gnss</name>
         <version>2.0-1</version>
         <interface>
@@ -211,7 +211,7 @@
     <!-- Either the AIDL or the HIDL allocator HAL must exist on the device.
          If the HIDL composer HAL exists, it must be at least version 2.0.
          See DeviceManifestTest.GrallocHal -->
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.graphics.allocator</name>
         <!-- New, non-Go devices should use 4.0, tested in vts_treble_vintf_vendor_test -->
         <version>2.0</version>
@@ -222,7 +222,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.graphics.composer</name>
         <version>2.1-4</version>
         <interface>
@@ -230,7 +230,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.graphics.mapper</name>
         <!-- New, non-Go devices should use 4.0, tested in vts_treble_vintf_vendor_test -->
         <version>2.1</version>
@@ -244,7 +244,7 @@
     <!-- Either the AIDL or the HIDL health HAL must exist on the device.
          If the HIDL health HAL exists, it must be at least version 2.1.
          See DeviceManifestTest.HealthHal -->
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.health</name>
         <version>2.1</version>
         <interface>
@@ -252,7 +252,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.health.storage</name>
         <version>1.0</version>
         <interface>
@@ -260,7 +260,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.identity</name>
         <!--
           b/178458001: identity V2 is introduced in R, but Android R VINTF does not support AIDL
@@ -274,7 +274,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.ir</name>
         <version>1.0</version>
         <interface>
@@ -282,7 +282,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.input.classifier</name>
         <version>1.0</version>
         <interface>
@@ -290,7 +290,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.keymaster</name>
         <version>3.0</version>
         <version>4.0-1</version>
@@ -299,7 +299,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.keymaster</name>
         <version>4.0-1</version>
         <interface>
@@ -307,23 +307,33 @@
             <instance>strongbox</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.light</name>
         <interface>
             <name>ILights</name>
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.media.c2</name>
         <version>1.0-1</version>
         <interface>
             <name>IComponentStore</name>
+            <instance>software</instance>
             <regex-instance>default[0-9]*</regex-instance>
             <regex-instance>vendor[0-9]*_software</regex-instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
+        <name>android.hardware.media.c2</name>
+        <version>1.0</version>
+        <interface>
+            <name>IConfigurable</name>
+            <instance>default</instance>
+            <instance>software</instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
         <name>android.hardware.media.omx</name>
         <version>1.0</version>
         <interface>
@@ -335,7 +345,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.memtrack</name>
         <version>1.0</version>
         <interface>
@@ -343,7 +353,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.neuralnetworks</name>
         <version>1.0-3</version>
         <interface>
@@ -351,7 +361,7 @@
             <regex-instance>.*</regex-instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.nfc</name>
         <version>1.2</version>
         <interface>
@@ -359,7 +369,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.oemlock</name>
         <version>1.0</version>
         <interface>
@@ -367,14 +377,14 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.power</name>
         <interface>
             <name>IPower</name>
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.power.stats</name>
         <version>1.0</version>
         <interface>
@@ -382,7 +392,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.radio</name>
         <version>1.4</version>
         <version>1.5</version>
@@ -393,15 +403,16 @@
             <instance>slot3</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.radio</name>
         <version>1.2</version>
         <interface>
             <name>ISap</name>
             <instance>slot1</instance>
+            <instance>slot2</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.radio.config</name>
         <!--
         See compatibility_matrix.4.xml on versioning of radio config HAL.
@@ -412,7 +423,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.renderscript</name>
         <version>1.0</version>
         <interface>
@@ -420,14 +431,14 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.rebootescrow</name>
         <interface>
             <name>IRebootEscrow</name>
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.secure_element</name>
         <version>1.0-2</version>
         <interface>
@@ -436,7 +447,7 @@
             <regex-instance>SIM[1-9][0-9]*</regex-instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.sensors</name>
         <version>1.0</version>
         <version>2.0-1</version>
@@ -445,7 +456,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.soundtrigger</name>
         <version>2.0-3</version>
         <interface>
@@ -453,7 +464,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.tetheroffload.config</name>
         <version>1.0</version>
         <interface>
@@ -461,7 +472,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.tetheroffload.control</name>
         <version>1.0</version>
         <interface>
@@ -469,7 +480,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.thermal</name>
         <version>2.0</version>
         <interface>
@@ -477,7 +488,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.tv.cec</name>
         <version>1.0</version>
         <interface>
@@ -485,7 +496,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.tv.input</name>
         <version>1.0</version>
         <interface>
@@ -493,7 +504,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.tv.tuner</name>
         <version>1.0</version>
         <interface>
@@ -501,7 +512,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.usb</name>
         <version>1.0-2</version>
         <interface>
@@ -509,7 +520,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.usb.gadget</name>
         <version>1.0-1</version>
         <interface>
@@ -517,14 +528,14 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.vibrator</name>
         <interface>
             <name>IVibrator</name>
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.vr</name>
         <version>1.0</version>
         <interface>
@@ -532,7 +543,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.weaver</name>
         <version>1.0</version>
         <interface>
@@ -540,7 +551,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.wifi</name>
         <version>1.0-4</version>
         <interface>
@@ -548,7 +559,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.wifi.hostapd</name>
         <version>1.0-2</version>
         <interface>
@@ -556,7 +567,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.wifi.supplicant</name>
         <version>1.0-3</version>
         <interface>
diff --git a/compatibility_matrices/compatibility_matrix.6.xml b/compatibility_matrices/compatibility_matrix.6.xml
index 40ae655..fdd7952 100644
--- a/compatibility_matrices/compatibility_matrix.6.xml
+++ b/compatibility_matrices/compatibility_matrix.6.xml
@@ -1,5 +1,5 @@
 <compatibility-matrix version="1.0" type="framework" level="6">
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.atrace</name>
         <version>1.0</version>
         <interface>
@@ -7,7 +7,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.audio</name>
         <version>6.0</version>
         <version>7.0</version>
@@ -16,7 +16,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.audio.effect</name>
         <version>6.0</version>
         <version>7.0</version>
@@ -25,7 +25,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
          <name>android.hardware.authsecret</name>
          <version>1</version>
          <interface>
@@ -33,7 +33,7 @@
              <instance>default</instance>
          </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.authsecret</name>
         <version>1.0</version>
         <interface>
@@ -41,14 +41,14 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.automotive.audiocontrol</name>
         <interface>
             <name>IAudioControl</name>
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.automotive.can</name>
         <version>1.0</version>
         <interface>
@@ -60,7 +60,7 @@
             <regex-instance>.*</regex-instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.automotive.evs</name>
         <version>1.0-1</version>
         <interface>
@@ -69,7 +69,7 @@
             <regex-instance>[a-z]+/[0-9]+</regex-instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.automotive.occupant_awareness</name>
         <version>1</version>
         <interface>
@@ -77,7 +77,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.automotive.sv</name>
         <version>1.0</version>
         <interface>
@@ -85,7 +85,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.automotive.vehicle</name>
         <version>2.0</version>
         <interface>
@@ -93,7 +93,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.biometrics.face</name>
         <version>1.0</version>
         <interface>
@@ -101,14 +101,14 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.biometrics.face</name>
         <interface>
             <name>IFace</name>
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.biometrics.fingerprint</name>
         <version>2.1-3</version>
         <interface>
@@ -116,14 +116,14 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.biometrics.fingerprint</name>
         <interface>
             <name>IFingerprint</name>
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.bluetooth</name>
         <version>1.0-1</version>
         <interface>
@@ -131,7 +131,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.bluetooth.audio</name>
         <version>2.0-1</version>
         <interface>
@@ -139,7 +139,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.boot</name>
         <version>1.2</version>
         <interface>
@@ -147,7 +147,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.broadcastradio</name>
         <version>1.0-1</version>
         <interface>
@@ -155,7 +155,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.broadcastradio</name>
         <version>2.0</version>
         <interface>
@@ -163,7 +163,7 @@
             <regex-instance>.*</regex-instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.camera.provider</name>
         <version>2.4-7</version>
         <interface>
@@ -171,7 +171,7 @@
             <regex-instance>[^/]+/[0-9]+</regex-instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.cas</name>
         <version>1.1-2</version>
         <interface>
@@ -179,7 +179,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.confirmationui</name>
         <version>1.0</version>
         <interface>
@@ -187,7 +187,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.contexthub</name>
         <version>1.2</version>
         <interface>
@@ -195,7 +195,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.drm</name>
         <version>1.3-4</version>
         <interface>
@@ -207,7 +207,7 @@
             <regex-instance>.*</regex-instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.dumpstate</name>
         <version>1.1</version>
         <interface>
@@ -215,7 +215,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.gatekeeper</name>
         <version>1.0</version>
         <interface>
@@ -223,7 +223,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.gnss</name>
         <version>2.0-1</version>
         <interface>
@@ -231,7 +231,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.gnss</name>
         <interface>
             <name>IGnss</name>
@@ -241,7 +241,7 @@
     <!-- Either the AIDL or the HIDL allocator HAL must exist on the device.
          If the HIDL composer HAL exists, it must be at least version 2.0.
          See DeviceManifestTest.GrallocHal -->
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.graphics.allocator</name>
         <!-- New, non-Go devices should use 4.0, tested in vts_treble_vintf_vendor_test -->
         <version>2.0</version>
@@ -252,7 +252,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.graphics.composer</name>
         <version>2.1-4</version>
         <interface>
@@ -260,7 +260,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.graphics.mapper</name>
         <!-- New, non-Go devices should use 4.0, tested in vts_treble_vintf_vendor_test -->
         <version>2.1</version>
@@ -274,7 +274,7 @@
     <!-- Either the AIDL or the HIDL health HAL must exist on the device.
          If the HIDL health HAL exists, it must be at least version 2.1.
          See DeviceManifestTest.HealthHal -->
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.health</name>
         <version>2.1</version>
         <interface>
@@ -282,7 +282,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.health.storage</name>
         <version>1</version>
         <interface>
@@ -290,7 +290,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.identity</name>
         <version>1-3</version>
         <interface>
@@ -298,7 +298,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.oemlock</name>
         <version>1</version>
         <interface>
@@ -306,7 +306,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.ir</name>
         <version>1.0</version>
         <interface>
@@ -314,7 +314,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.input.classifier</name>
         <version>1.0</version>
         <interface>
@@ -322,7 +322,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.keymaster</name>
         <version>3.0</version>
         <version>4.0-1</version>
@@ -331,7 +331,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.keymaster</name>
         <version>4.0-1</version>
         <interface>
@@ -339,7 +339,7 @@
             <instance>strongbox</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.security.keymint</name>
         <version>1</version>
         <interface>
@@ -348,14 +348,14 @@
             <instance>strongbox</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.security.keymint</name>
         <interface>
             <name>IRemotelyProvisionedComponent</name>
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.light</name>
         <version>1</version>
         <interface>
@@ -363,16 +363,26 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.media.c2</name>
         <version>1.0-2</version>
         <interface>
             <name>IComponentStore</name>
+            <instance>software</instance>
             <regex-instance>default[0-9]*</regex-instance>
             <regex-instance>vendor[0-9]*_software</regex-instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
+        <name>android.hardware.media.c2</name>
+        <version>1.0</version>
+        <interface>
+            <name>IConfigurable</name>
+            <instance>default</instance>
+            <instance>software</instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
         <name>android.hardware.media.omx</name>
         <version>1.0</version>
         <interface>
@@ -384,7 +394,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.memtrack</name>
         <version>1</version>
         <interface>
@@ -392,7 +402,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.neuralnetworks</name>
         <version>1.0-3</version>
         <interface>
@@ -400,14 +410,14 @@
             <regex-instance>.*</regex-instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.neuralnetworks</name>
         <interface>
             <name>IDevice</name>
             <regex-instance>.*</regex-instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.nfc</name>
         <version>1.2</version>
         <interface>
@@ -415,7 +425,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.oemlock</name>
         <version>1.0</version>
         <interface>
@@ -423,7 +433,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.power</name>
         <version>1-2</version>
         <interface>
@@ -431,14 +441,14 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.power.stats</name>
         <interface>
             <name>IPowerStats</name>
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.radio</name>
         <version>1.6</version>
         <interface>
@@ -448,15 +458,16 @@
             <instance>slot3</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.radio</name>
         <version>1.2</version>
         <interface>
             <name>ISap</name>
             <instance>slot1</instance>
+            <instance>slot2</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.radio.config</name>
         <!--
         See compatibility_matrix.4.xml on versioning of radio config HAL.
@@ -467,7 +478,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.radio.config</name>
         <version>1.3</version>
         <interface>
@@ -475,7 +486,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.renderscript</name>
         <version>1.0</version>
         <interface>
@@ -483,7 +494,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.rebootescrow</name>
         <version>1</version>
         <interface>
@@ -491,7 +502,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.secure_element</name>
         <version>1.0-2</version>
         <interface>
@@ -500,7 +511,7 @@
             <regex-instance>SIM[1-9][0-9]*</regex-instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.security.secureclock</name>
         <version>1</version>
         <interface>
@@ -508,7 +519,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.security.sharedsecret</name>
         <version>1</version>
         <interface>
@@ -517,7 +528,7 @@
             <instance>strongbox</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.sensors</name>
         <version>1.0</version>
         <version>2.0-1</version>
@@ -526,7 +537,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.soundtrigger</name>
         <version>2.3</version>
         <interface>
@@ -534,7 +545,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.tetheroffload.config</name>
         <version>1.0</version>
         <interface>
@@ -542,7 +553,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.tetheroffload.control</name>
         <version>1.1</version>
         <interface>
@@ -550,7 +561,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.thermal</name>
         <version>2.0</version>
         <interface>
@@ -558,7 +569,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.tv.cec</name>
         <version>1.0-1</version>
         <interface>
@@ -566,7 +577,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.tv.input</name>
         <version>1.0</version>
         <interface>
@@ -574,7 +585,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.tv.tuner</name>
         <version>1.0-1</version>
         <interface>
@@ -582,7 +593,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.usb</name>
         <version>1.0-3</version>
         <interface>
@@ -590,7 +601,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.usb.gadget</name>
         <version>1.0-2</version>
         <interface>
@@ -598,7 +609,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.vibrator</name>
         <version>1-2</version>
         <interface>
@@ -606,7 +617,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.vibrator</name>
         <version>1-2</version>
         <interface>
@@ -614,7 +625,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.weaver</name>
         <version>1.0</version>
         <interface>
@@ -622,7 +633,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.weaver</name>
         <version>1</version>
         <interface>
@@ -630,7 +641,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.wifi</name>
         <version>1.3-5</version>
         <interface>
@@ -638,7 +649,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.wifi.hostapd</name>
         <version>1.0-3</version>
         <interface>
@@ -646,7 +657,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.wifi.supplicant</name>
         <version>1.2-4</version>
         <interface>
diff --git a/compatibility_matrices/compatibility_matrix.7.xml b/compatibility_matrices/compatibility_matrix.7.xml
index bc5a5c4..8dcc4ae 100644
--- a/compatibility_matrices/compatibility_matrix.7.xml
+++ b/compatibility_matrices/compatibility_matrix.7.xml
@@ -1,5 +1,5 @@
 <compatibility-matrix version="1.0" type="framework" level="7">
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.atrace</name>
         <version>1.0</version>
         <interface>
@@ -7,7 +7,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.audio</name>
         <version>6.0</version>
         <version>7.0-1</version>
@@ -16,7 +16,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.audio.effect</name>
         <version>6.0</version>
         <version>7.0</version>
@@ -25,7 +25,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
          <name>android.hardware.authsecret</name>
          <version>1</version>
          <interface>
@@ -33,7 +33,7 @@
              <instance>default</instance>
          </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.authsecret</name>
         <version>1.0</version>
         <interface>
@@ -41,14 +41,15 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.automotive.audiocontrol</name>
+        <version>1-2</version>
         <interface>
             <name>IAudioControl</name>
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.automotive.can</name>
         <version>1.0</version>
         <interface>
@@ -60,7 +61,7 @@
             <regex-instance>.*</regex-instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.automotive.evs</name>
         <interface>
             <name>IEvsEnumerator</name>
@@ -68,7 +69,7 @@
             <regex-instance>[a-z]+/[0-9]+</regex-instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.automotive.evs</name>
         <version>1.0-1</version>
         <interface>
@@ -77,7 +78,7 @@
             <regex-instance>[a-z]+/[0-9]+</regex-instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.automotive.occupant_awareness</name>
         <version>1</version>
         <interface>
@@ -85,14 +86,14 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.automotive.vehicle</name>
         <interface>
             <name>IVehicle</name>
             <regex-instance>.*</regex-instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.automotive.vehicle</name>
         <version>2.0</version>
         <interface>
@@ -100,7 +101,7 @@
             <regex-instance>.*</regex-instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.biometrics.face</name>
         <version>1.0</version>
         <interface>
@@ -108,7 +109,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.biometrics.face</name>
         <version>2</version>
         <interface>
@@ -116,7 +117,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.biometrics.fingerprint</name>
         <version>2.1-3</version>
         <interface>
@@ -124,7 +125,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.biometrics.fingerprint</name>
         <version>2</version>
         <interface>
@@ -132,7 +133,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.bluetooth</name>
         <version>1.0-1</version>
         <interface>
@@ -140,7 +141,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.bluetooth.audio</name>
         <version>2</version>
         <interface>
@@ -148,7 +149,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.boot</name>
         <version>1.2</version>
         <interface>
@@ -156,7 +157,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.broadcastradio</name>
         <version>1.0-1</version>
         <interface>
@@ -164,7 +165,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.broadcastradio</name>
         <version>2.0</version>
         <interface>
@@ -172,7 +173,7 @@
             <regex-instance>.*</regex-instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.camera.provider</name>
         <version>2.4-7</version>
         <interface>
@@ -180,7 +181,7 @@
             <regex-instance>[^/]+/[0-9]+</regex-instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.camera.provider</name>
         <version>1</version>
         <interface>
@@ -188,7 +189,7 @@
             <regex-instance>[^/]+/[0-9]+</regex-instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.cas</name>
         <version>1.1-2</version>
         <interface>
@@ -196,7 +197,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.confirmationui</name>
         <version>1.0</version>
         <interface>
@@ -204,14 +205,14 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.contexthub</name>
         <interface>
             <name>IContextHub</name>
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.drm</name>
         <version>1</version>
         <interface>
@@ -219,7 +220,7 @@
             <regex-instance>.*</regex-instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.drm</name>
         <version>1.3-4</version>
         <interface>
@@ -231,14 +232,14 @@
             <regex-instance>.*</regex-instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.dumpstate</name>
         <interface>
             <name>IDumpstateDevice</name>
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.gatekeeper</name>
         <version>1.0</version>
         <interface>
@@ -246,7 +247,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.gnss</name>
         <version>2.0-1</version>
         <interface>
@@ -254,7 +255,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.gnss</name>
         <version>2</version>
         <interface>
@@ -262,23 +263,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.gnss.visibility_control</name>
-        <version>1</version>
-        <interface>
-            <name>IGnssVisibilityControl</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.gnss.measurement_corrections</name>
-        <version>1</version>
-        <interface>
-            <name>IMeasurementCorrectionsInterface</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.graphics.allocator</name>
         <!-- New, non-Go devices should use 4.0 or the AIDL hal. -->
         <version>2.0</version>
@@ -289,7 +274,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.graphics.allocator</name>
         <version>1</version>
         <interface>
@@ -300,7 +285,7 @@
     <!-- Either the AIDL or the HIDL composer HAL must exist on the device.
          If the HIDL composer HAL exists, it must be at least version 2.1.
          See DeviceManifestTest.ComposerHal -->
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.graphics.composer</name>
         <version>2.1-4</version>
         <interface>
@@ -308,7 +293,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.graphics.composer3</name>
         <version>1</version>
         <interface>
@@ -316,7 +301,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.graphics.mapper</name>
         <!-- New, non-Go devices should use 4.0, tested in vts_treble_vintf_vendor_test -->
         <version>2.1</version>
@@ -327,7 +312,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.health</name>
         <version>1</version>
         <interface>
@@ -335,7 +320,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.health.storage</name>
         <version>1</version>
         <interface>
@@ -343,7 +328,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.identity</name>
         <version>1-4</version>
         <interface>
@@ -351,14 +336,14 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.net.nlinterceptor</name>
         <interface>
             <name>IInterceptor</name>
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.oemlock</name>
         <version>1</version>
         <interface>
@@ -366,7 +351,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.ir</name>
         <version>1</version>
         <interface>
@@ -374,7 +359,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.input.processor</name>
         <version>1</version>
         <interface>
@@ -382,7 +367,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.keymaster</name>
         <version>3.0</version>
         <version>4.0-1</version>
@@ -391,7 +376,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.keymaster</name>
         <version>4.0-1</version>
         <interface>
@@ -399,7 +384,7 @@
             <instance>strongbox</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.security.keymint</name>
         <version>1-2</version>
         <interface>
@@ -408,7 +393,7 @@
             <instance>strongbox</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.security.keymint</name>
         <version>1-2</version>
         <interface>
@@ -417,7 +402,7 @@
             <instance>strongbox</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.light</name>
         <version>1-2</version>
         <interface>
@@ -425,16 +410,26 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.media.c2</name>
         <version>1.0-2</version>
         <interface>
             <name>IComponentStore</name>
+            <instance>software</instance>
             <regex-instance>default[0-9]*</regex-instance>
             <regex-instance>vendor[0-9]*_software</regex-instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
+        <name>android.hardware.media.c2</name>
+        <version>1.0</version>
+        <interface>
+            <name>IConfigurable</name>
+            <instance>default</instance>
+            <instance>software</instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
         <name>android.hardware.media.omx</name>
         <version>1.0</version>
         <interface>
@@ -446,7 +441,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.memtrack</name>
         <version>1</version>
         <interface>
@@ -454,7 +449,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.neuralnetworks</name>
         <version>1.0-3</version>
         <interface>
@@ -462,7 +457,7 @@
             <regex-instance>.*</regex-instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.neuralnetworks</name>
         <version>1-4</version>
         <interface>
@@ -470,7 +465,7 @@
             <regex-instance>.*</regex-instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.nfc</name>
         <version>1.2</version>
         <interface>
@@ -478,14 +473,14 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.nfc</name>
         <interface>
             <name>INfc</name>
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.oemlock</name>
         <version>1.0</version>
         <interface>
@@ -493,7 +488,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.power</name>
         <version>2-3</version>
         <interface>
@@ -501,14 +496,14 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.power.stats</name>
         <interface>
             <name>IPowerStats</name>
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.radio.config</name>
         <version>1</version>
         <interface>
@@ -516,7 +511,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.radio.data</name>
         <version>1</version>
         <interface>
@@ -526,7 +521,7 @@
             <instance>slot3</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.radio.messaging</name>
         <version>1</version>
         <interface>
@@ -536,7 +531,7 @@
             <instance>slot3</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.radio.modem</name>
         <version>1</version>
         <interface>
@@ -546,7 +541,7 @@
             <instance>slot3</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.radio.network</name>
         <version>1</version>
         <interface>
@@ -556,7 +551,7 @@
             <instance>slot3</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.radio.sim</name>
         <version>1</version>
         <interface>
@@ -566,7 +561,7 @@
             <instance>slot3</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.radio.voice</name>
         <version>1</version>
         <interface>
@@ -576,15 +571,16 @@
             <instance>slot3</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.radio</name>
         <version>1.2</version>
         <interface>
             <name>ISap</name>
             <instance>slot1</instance>
+            <instance>slot2</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.renderscript</name>
         <version>1.0</version>
         <interface>
@@ -592,7 +588,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.rebootescrow</name>
         <version>1</version>
         <interface>
@@ -600,7 +596,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.secure_element</name>
         <version>1.0-2</version>
         <interface>
@@ -609,7 +605,7 @@
             <regex-instance>SIM[1-9][0-9]*</regex-instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.security.secureclock</name>
         <version>1</version>
         <interface>
@@ -617,7 +613,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.security.sharedsecret</name>
         <version>1</version>
         <interface>
@@ -626,14 +622,14 @@
             <instance>strongbox</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.sensors</name>
         <interface>
             <name>ISensors</name>
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.sensors</name>
         <version>1.0</version>
         <version>2.0-1</version>
@@ -642,7 +638,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.soundtrigger</name>
         <version>2.3</version>
         <interface>
@@ -650,7 +646,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
          <name>android.hardware.soundtrigger3</name>
          <version>1</version>
          <interface>
@@ -658,7 +654,7 @@
              <instance>default</instance>
          </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.tetheroffload.config</name>
         <version>1.0</version>
         <interface>
@@ -666,7 +662,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.tetheroffload.control</name>
         <version>1.1</version>
         <interface>
@@ -674,7 +670,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.thermal</name>
         <version>2.0</version>
         <interface>
@@ -682,7 +678,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.tv.cec</name>
         <version>1.0-1</version>
         <interface>
@@ -690,7 +686,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.tv.input</name>
         <version>1.0</version>
         <interface>
@@ -698,7 +694,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.tv.tuner</name>
         <version>1.0-1</version>
         <interface>
@@ -706,7 +702,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.tv.tuner</name>
         <version>1</version>
         <interface>
@@ -714,7 +710,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.usb</name>
         <version>1.0-3</version>
         <interface>
@@ -722,14 +718,14 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.usb</name>
         <interface>
             <name>IUsb</name>
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.usb.gadget</name>
         <version>1.0-2</version>
         <interface>
@@ -737,7 +733,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.vibrator</name>
         <version>1-2</version>
         <interface>
@@ -745,7 +741,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.vibrator</name>
         <version>1-2</version>
         <interface>
@@ -753,7 +749,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.weaver</name>
         <version>1.0</version>
         <interface>
@@ -761,7 +757,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.weaver</name>
         <version>1</version>
         <interface>
@@ -769,7 +765,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.wifi</name>
         <version>1.3-6</version>
         <interface>
@@ -777,7 +773,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.uwb</name>
         <version>1</version>
         <interface>
@@ -785,7 +781,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.wifi.hostapd</name>
         <version>1</version>
         <interface>
@@ -793,7 +789,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.wifi.supplicant</name>
         <interface>
             <name>ISupplicant</name>
diff --git a/compatibility_matrices/compatibility_matrix.8.xml b/compatibility_matrices/compatibility_matrix.8.xml
index 5ea075a..7054bfa 100644
--- a/compatibility_matrices/compatibility_matrix.8.xml
+++ b/compatibility_matrices/compatibility_matrix.8.xml
@@ -1,5 +1,5 @@
 <compatibility-matrix version="1.0" type="framework" level="8">
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.audio</name>
         <version>6.0</version>
         <version>7.0-1</version>
@@ -8,7 +8,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.audio.effect</name>
         <version>6.0</version>
         <version>7.0</version>
@@ -17,7 +17,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.audio.core</name>
         <version>1</version>
         <interface>
@@ -36,7 +36,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.audio.effect</name>
         <version>1</version>
         <interface>
@@ -44,7 +44,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.audio.sounddose</name>
         <version>1</version>
         <interface>
@@ -52,7 +52,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl" updatable-via-apex="true">
          <name>android.hardware.authsecret</name>
          <version>1</version>
          <interface>
@@ -60,7 +60,7 @@
              <instance>default</instance>
          </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.automotive.audiocontrol</name>
         <version>2-3</version>
         <interface>
@@ -68,7 +68,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.automotive.can</name>
         <version>1</version>
         <interface>
@@ -76,7 +76,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.automotive.evs</name>
         <version>1-2</version>
         <interface>
@@ -84,7 +84,7 @@
             <regex-instance>[a-z]+/[0-9]+</regex-instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.automotive.occupant_awareness</name>
         <version>1</version>
         <interface>
@@ -92,7 +92,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.automotive.vehicle</name>
         <version>1-2</version>
         <interface>
@@ -100,29 +100,30 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.automotive.remoteaccess</name>
         <interface>
             <name>IRemoteAccess</name>
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.automotive.ivn</name>
         <interface>
             <name>IIvnAndroidDevice</name>
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl" updatable-via-apex="true">
         <name>android.hardware.biometrics.face</name>
-        <version>3</version>
+        <version>3-4</version>
         <interface>
             <name>IFace</name>
             <instance>default</instance>
+            <instance>virtual</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl" updatable-via-apex="true">
         <name>android.hardware.biometrics.fingerprint</name>
         <version>3</version>
         <interface>
@@ -131,7 +132,7 @@
             <instance>virtual</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.bluetooth</name>
         <version>1.0-1</version>
         <interface>
@@ -139,14 +140,14 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.bluetooth</name>
         <interface>
             <name>IBluetoothHci</name>
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.bluetooth.audio</name>
         <version>3</version>
         <interface>
@@ -154,21 +155,21 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.boot</name>
         <interface>
             <name>IBootControl</name>
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.broadcastradio</name>
         <interface>
             <name>IBroadcastRadio</name>
             <regex-instance>.*</regex-instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true" updatable-via-apex="true">
+    <hal format="aidl" updatable-via-apex="true">
         <name>android.hardware.camera.provider</name>
         <version>1-2</version>
         <interface>
@@ -176,14 +177,14 @@
             <regex-instance>[^/]+/[0-9]+</regex-instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.cas</name>
         <interface>
             <name>IMediaCasService</name>
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.confirmationui</name>
         <version>1</version>
         <interface>
@@ -191,7 +192,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.contexthub</name>
         <version>2</version>
         <interface>
@@ -199,7 +200,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true" updatable-via-apex="true">
+    <hal format="aidl" updatable-via-apex="true">
         <name>android.hardware.drm</name>
         <version>1</version>
         <interface>
@@ -207,14 +208,14 @@
             <regex-instance>.*</regex-instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.dumpstate</name>
         <interface>
             <name>IDumpstateDevice</name>
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.gatekeeper</name>
         <version>1</version>
         <interface>
@@ -222,7 +223,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.gnss</name>
         <version>2-3</version>
         <interface>
@@ -230,23 +231,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.gnss.visibility_control</name>
-        <version>1</version>
-        <interface>
-            <name>IGnssVisibilityControl</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.gnss.measurement_corrections</name>
-        <version>1</version>
-        <interface>
-            <name>IMeasurementCorrectionsInterface</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.graphics.allocator</name>
         <version>1-2</version>
         <interface>
@@ -254,7 +239,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.graphics.composer3</name>
         <version>2</version>
         <interface>
@@ -263,7 +248,7 @@
         </interface>
     </hal>
     <!-- Either the native or the HIDL mapper HAL must exist on the device -->
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.graphics.mapper</name>
         <!-- New, non-Go devices should use 4.0, tested in vts_treble_vintf_vendor_test -->
         <version>2.1</version>
@@ -274,7 +259,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.health</name>
         <version>1-2</version>
         <interface>
@@ -282,7 +267,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.health.storage</name>
         <version>1</version>
         <interface>
@@ -290,7 +275,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.identity</name>
         <version>1-5</version>
         <interface>
@@ -298,14 +283,14 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.net.nlinterceptor</name>
         <interface>
             <name>IInterceptor</name>
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.oemlock</name>
         <version>1</version>
         <interface>
@@ -313,7 +298,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.ir</name>
         <version>1</version>
         <interface>
@@ -321,7 +306,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.input.processor</name>
         <version>1</version>
         <interface>
@@ -329,7 +314,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl" updatable-via-apex="true">
         <name>android.hardware.security.keymint</name>
         <version>1-3</version>
         <interface>
@@ -338,7 +323,7 @@
             <instance>strongbox</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl" updatable-via-apex="true">
         <name>android.hardware.security.keymint</name>
         <version>1-3</version>
         <interface>
@@ -348,7 +333,7 @@
             <instance>widevine</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.light</name>
         <version>2</version>
         <interface>
@@ -356,16 +341,26 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.media.c2</name>
         <version>1.0-2</version>
         <interface>
             <name>IComponentStore</name>
+            <instance>software</instance>
             <regex-instance>default[0-9]*</regex-instance>
             <regex-instance>vendor[0-9]*_software</regex-instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
+        <name>android.hardware.media.c2</name>
+        <version>1.0</version>
+        <interface>
+            <name>IConfigurable</name>
+            <instance>default</instance>
+            <instance>software</instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
         <name>android.hardware.media.omx</name>
         <version>1.0</version>
         <interface>
@@ -377,7 +372,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.memtrack</name>
         <version>1</version>
         <interface>
@@ -385,7 +380,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl" updatable-via-apex="true">
         <name>android.hardware.neuralnetworks</name>
         <version>1-4</version>
         <interface>
@@ -393,14 +388,14 @@
             <regex-instance>.*</regex-instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl" updatable-via-apex="true">
         <name>android.hardware.nfc</name>
         <interface>
             <name>INfc</name>
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.power</name>
         <version>4</version>
         <interface>
@@ -408,7 +403,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.power.stats</name>
         <version>2</version>
         <interface>
@@ -416,7 +411,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.radio.config</name>
         <version>2</version>
         <interface>
@@ -424,7 +419,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.radio.data</name>
         <version>2</version>
         <interface>
@@ -434,7 +429,7 @@
             <instance>slot3</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.radio.messaging</name>
         <version>2</version>
         <interface>
@@ -444,7 +439,7 @@
             <instance>slot3</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.radio.modem</name>
         <version>2</version>
         <interface>
@@ -454,7 +449,7 @@
             <instance>slot3</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.radio.network</name>
         <version>2</version>
         <interface>
@@ -464,7 +459,7 @@
             <instance>slot3</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.radio.sim</name>
         <version>2</version>
         <interface>
@@ -474,7 +469,7 @@
             <instance>slot3</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.radio.sap</name>
         <version>1</version>
         <interface>
@@ -484,7 +479,7 @@
             <instance>slot3</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.radio.voice</name>
         <version>2</version>
         <interface>
@@ -494,7 +489,7 @@
             <instance>slot3</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.radio.ims</name>
         <version>1</version>
         <interface>
@@ -504,7 +499,7 @@
             <instance>slot3</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.radio.ims.media</name>
         <version>1</version>
         <interface>
@@ -512,7 +507,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.renderscript</name>
         <version>1.0</version>
         <interface>
@@ -520,7 +515,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.rebootescrow</name>
         <version>1</version>
         <interface>
@@ -528,7 +523,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.secure_element</name>
         <version>1</version>
         <interface>
@@ -537,7 +532,7 @@
             <regex-instance>SIM[1-9][0-9]*</regex-instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl" updatable-via-apex="true">
         <name>android.hardware.security.secureclock</name>
         <version>1</version>
         <interface>
@@ -545,7 +540,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl" updatable-via-apex="true">
         <name>android.hardware.security.sharedsecret</name>
         <version>1</version>
         <interface>
@@ -554,7 +549,7 @@
             <instance>strongbox</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.sensors</name>
         <version>2</version>
         <interface>
@@ -562,7 +557,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.soundtrigger</name>
         <version>2.3</version>
         <interface>
@@ -570,7 +565,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
          <name>android.hardware.soundtrigger3</name>
          <version>1</version>
          <interface>
@@ -578,7 +573,7 @@
              <instance>default</instance>
          </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.tetheroffload.config</name>
         <version>1.0</version>
         <interface>
@@ -586,7 +581,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl">
         <name>android.hardware.tetheroffload.control</name>
         <version>1.1</version>
         <interface>
@@ -594,7 +589,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.tetheroffload</name>
         <version>1</version>
         <interface>
@@ -602,7 +597,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.thermal</name>
         <version>1</version>
         <interface>
@@ -610,7 +605,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.tv.hdmi.cec</name>
         <version>1</version>
         <interface>
@@ -618,7 +613,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.tv.hdmi.earc</name>
         <version>1</version>
         <interface>
@@ -626,7 +621,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.tv.hdmi.connection</name>
         <version>1</version>
         <interface>
@@ -634,7 +629,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.tv.tuner</name>
         <version>1-2</version>
         <interface>
@@ -642,7 +637,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.tv.input</name>
         <version>1</version>
         <interface>
@@ -650,7 +645,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.usb</name>
         <version>1-2</version>
         <interface>
@@ -658,14 +653,14 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.usb.gadget</name>
         <interface>
             <name>IUsbGadget</name>
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.vibrator</name>
         <version>1-2</version>
         <interface>
@@ -673,7 +668,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.vibrator</name>
         <version>1-2</version>
         <interface>
@@ -681,7 +676,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.weaver</name>
         <version>2</version>
         <interface>
@@ -689,7 +684,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true" updatable-via-apex="true">
+    <hal format="aidl" updatable-via-apex="true">
         <name>android.hardware.wifi</name>
         <version>1</version>
         <interface>
@@ -697,7 +692,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl" updatable-via-apex="true">
         <name>android.hardware.uwb</name>
         <version>1</version>
         <interface>
@@ -705,7 +700,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.wifi.hostapd</name>
         <version>1</version>
         <interface>
@@ -713,7 +708,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl">
         <name>android.hardware.wifi.supplicant</name>
         <version>2</version>
         <interface>
@@ -722,7 +717,7 @@
         </interface>
     </hal>
     <!-- Either the native or the HIDL mapper HAL must exist on the device -->
-    <hal format="native" optional="true">
+    <hal format="native">
         <name>mapper</name>
         <version>5.0</version>
         <interface>
diff --git a/compatibility_matrices/compatibility_matrix.9.xml b/compatibility_matrices/compatibility_matrix.9.xml
deleted file mode 100644
index 188746d..0000000
--- a/compatibility_matrices/compatibility_matrix.9.xml
+++ /dev/null
@@ -1,730 +0,0 @@
-<!-- WARNING: This file is unused in the Android 14 branch. -->
-<compatibility-matrix version="1.0" type="framework" level="9">
-    <hal format="hidl" optional="true">
-        <name>android.hardware.audio</name>
-        <version>6.0</version>
-        <version>7.0-1</version>
-        <interface>
-            <name>IDevicesFactory</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.audio.effect</name>
-        <version>6.0</version>
-        <version>7.0</version>
-        <interface>
-            <name>IEffectsFactory</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.audio.core</name>
-        <version>1</version>
-        <interface>
-            <name>IModule</name>
-            <instance>default</instance>
-            <instance>a2dp</instance>
-            <instance>bluetooth</instance>
-            <instance>hearing_aid</instance>
-            <instance>msd</instance>
-            <instance>r_submix</instance>
-            <instance>stub</instance>
-            <instance>usb</instance>
-        </interface>
-        <interface>
-            <name>IConfig</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.audio.effect</name>
-        <version>1</version>
-        <interface>
-            <name>IFactory</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.audio.sounddose</name>
-        <version>1</version>
-        <interface>
-            <name>ISoundDoseFactory</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-         <name>android.hardware.authsecret</name>
-         <version>1</version>
-         <interface>
-             <name>IAuthSecret</name>
-             <instance>default</instance>
-         </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.automotive.audiocontrol</name>
-        <version>2-3</version>
-        <interface>
-            <name>IAudioControl</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.automotive.can</name>
-        <version>1</version>
-        <interface>
-            <name>ICanController</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.automotive.evs</name>
-        <version>1-2</version>
-        <interface>
-            <name>IEvsEnumerator</name>
-            <regex-instance>[a-z]+/[0-9]+</regex-instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.automotive.occupant_awareness</name>
-        <version>1</version>
-        <interface>
-            <name>IOccupantAwareness</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.automotive.vehicle</name>
-        <version>1-2</version>
-        <interface>
-            <name>IVehicle</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.automotive.remoteaccess</name>
-        <interface>
-            <name>IRemoteAccess</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.automotive.ivn</name>
-        <interface>
-            <name>IIvnAndroidDevice</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.biometrics.face</name>
-        <version>3</version>
-        <interface>
-            <name>IFace</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.biometrics.fingerprint</name>
-        <version>3</version>
-        <interface>
-            <name>IFingerprint</name>
-            <instance>default</instance>
-            <instance>virtual</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.bluetooth</name>
-        <version>1.0-1</version>
-        <interface>
-            <name>IBluetoothHci</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.bluetooth</name>
-        <interface>
-            <name>IBluetoothHci</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.bluetooth.audio</name>
-        <version>3</version>
-        <interface>
-            <name>IBluetoothAudioProviderFactory</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.boot</name>
-        <interface>
-            <name>IBootControl</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.broadcastradio</name>
-        <interface>
-            <name>IBroadcastRadio</name>
-            <regex-instance>.*</regex-instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true" updatable-via-apex="true">
-        <name>android.hardware.camera.provider</name>
-        <version>1-2</version>
-        <interface>
-            <name>ICameraProvider</name>
-            <regex-instance>[^/]+/[0-9]+</regex-instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.cas</name>
-        <interface>
-            <name>IMediaCasService</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.confirmationui</name>
-        <version>1</version>
-        <interface>
-            <name>IConfirmationUI</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.contexthub</name>
-        <version>2</version>
-        <interface>
-            <name>IContextHub</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true" updatable-via-apex="true">
-        <name>android.hardware.drm</name>
-        <version>1</version>
-        <interface>
-            <name>IDrmFactory</name>
-            <regex-instance>.*</regex-instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.dumpstate</name>
-        <interface>
-            <name>IDumpstateDevice</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.gatekeeper</name>
-        <version>1</version>
-        <interface>
-            <name>IGatekeeper</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.gnss</name>
-        <version>2-3</version>
-        <interface>
-            <name>IGnss</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.gnss.visibility_control</name>
-        <version>1</version>
-        <interface>
-            <name>IGnssVisibilityControl</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.gnss.measurement_corrections</name>
-        <version>1</version>
-        <interface>
-            <name>IMeasurementCorrectionsInterface</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.graphics.allocator</name>
-        <version>1-2</version>
-        <interface>
-            <name>IAllocator</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.graphics.composer3</name>
-        <version>2</version>
-        <interface>
-            <name>IComposer</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <!-- Either the native or the HIDL mapper HAL must exist on the device -->
-    <hal format="hidl" optional="true">
-        <name>android.hardware.graphics.mapper</name>
-        <!-- New, non-Go devices should use 4.0, tested in vts_treble_vintf_vendor_test -->
-        <version>2.1</version>
-        <version>3.0</version>
-        <version>4.0</version>
-        <interface>
-            <name>IMapper</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.health</name>
-        <version>1-2</version>
-        <interface>
-            <name>IHealth</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.health.storage</name>
-        <version>1</version>
-        <interface>
-            <name>IStorage</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.identity</name>
-        <version>1-5</version>
-        <interface>
-            <name>IIdentityCredentialStore</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.net.nlinterceptor</name>
-        <interface>
-            <name>IInterceptor</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.oemlock</name>
-        <version>1</version>
-        <interface>
-            <name>IOemLock</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.ir</name>
-        <version>1</version>
-        <interface>
-            <name>IConsumerIr</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.input.processor</name>
-        <version>1</version>
-        <interface>
-            <name>IInputProcessor</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.security.keymint</name>
-        <version>1-3</version>
-        <interface>
-            <name>IKeyMintDevice</name>
-            <instance>default</instance>
-            <instance>strongbox</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.security.keymint</name>
-        <version>1-3</version>
-        <interface>
-            <name>IRemotelyProvisionedComponent</name>
-            <instance>default</instance>
-            <instance>strongbox</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.light</name>
-        <version>2</version>
-        <interface>
-            <name>ILights</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.media.c2</name>
-        <version>1.0-2</version>
-        <interface>
-            <name>IComponentStore</name>
-            <regex-instance>default[0-9]*</regex-instance>
-            <regex-instance>vendor[0-9]*_software</regex-instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.memtrack</name>
-        <version>1</version>
-        <interface>
-            <name>IMemtrack</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.neuralnetworks</name>
-        <version>1-4</version>
-        <interface>
-            <name>IDevice</name>
-            <regex-instance>.*</regex-instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.nfc</name>
-        <interface>
-            <name>INfc</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.power</name>
-        <version>4</version>
-        <interface>
-            <name>IPower</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.power.stats</name>
-        <version>2</version>
-        <interface>
-            <name>IPowerStats</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.radio.config</name>
-        <version>2</version>
-        <interface>
-            <name>IRadioConfig</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.radio.data</name>
-        <version>2</version>
-        <interface>
-            <name>IRadioData</name>
-            <instance>slot1</instance>
-            <instance>slot2</instance>
-            <instance>slot3</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.radio.messaging</name>
-        <version>2</version>
-        <interface>
-            <name>IRadioMessaging</name>
-            <instance>slot1</instance>
-            <instance>slot2</instance>
-            <instance>slot3</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.radio.modem</name>
-        <version>2</version>
-        <interface>
-            <name>IRadioModem</name>
-            <instance>slot1</instance>
-            <instance>slot2</instance>
-            <instance>slot3</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.radio.network</name>
-        <version>2</version>
-        <interface>
-            <name>IRadioNetwork</name>
-            <instance>slot1</instance>
-            <instance>slot2</instance>
-            <instance>slot3</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.radio.sim</name>
-        <version>2</version>
-        <interface>
-            <name>IRadioSim</name>
-            <instance>slot1</instance>
-            <instance>slot2</instance>
-            <instance>slot3</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.radio.sap</name>
-        <version>1</version>
-        <interface>
-            <name>ISap</name>
-            <instance>slot1</instance>
-            <instance>slot2</instance>
-            <instance>slot3</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.radio.voice</name>
-        <version>2</version>
-        <interface>
-            <name>IRadioVoice</name>
-            <instance>slot1</instance>
-            <instance>slot2</instance>
-            <instance>slot3</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.radio.ims</name>
-        <version>1</version>
-        <interface>
-            <name>IRadioIms</name>
-            <instance>slot1</instance>
-            <instance>slot2</instance>
-            <instance>slot3</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.radio.satellite</name>
-        <version>1</version>
-        <interface>
-            <name>IRadioSatellite</name>
-            <instance>slot1</instance>
-            <instance>slot2</instance>
-            <instance>slot3</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.radio.ims.media</name>
-        <version>1</version>
-        <interface>
-            <name>IImsMedia</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.renderscript</name>
-        <version>1.0</version>
-        <interface>
-            <name>IDevice</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.rebootescrow</name>
-        <version>1</version>
-        <interface>
-            <name>IRebootEscrow</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.secure_element</name>
-        <version>1</version>
-        <interface>
-            <name>ISecureElement</name>
-            <regex-instance>eSE[1-9][0-9]*</regex-instance>
-            <regex-instance>SIM[1-9][0-9]*</regex-instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.security.secureclock</name>
-        <version>1</version>
-        <interface>
-            <name>ISecureClock</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.security.sharedsecret</name>
-        <version>1</version>
-        <interface>
-            <name>ISharedSecret</name>
-            <instance>default</instance>
-            <instance>strongbox</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.sensors</name>
-        <version>2</version>
-        <interface>
-            <name>ISensors</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.soundtrigger</name>
-        <version>2.3</version>
-        <interface>
-            <name>ISoundTriggerHw</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-         <name>android.hardware.soundtrigger3</name>
-         <version>1</version>
-         <interface>
-             <name>ISoundTriggerHw</name>
-             <instance>default</instance>
-         </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.tetheroffload.config</name>
-        <version>1.0</version>
-        <interface>
-            <name>IOffloadConfig</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.tetheroffload.control</name>
-        <version>1.1</version>
-        <interface>
-            <name>IOffloadControl</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.tetheroffload</name>
-        <version>1</version>
-        <interface>
-            <name>IOffload</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.thermal</name>
-        <version>1</version>
-        <interface>
-            <name>IThermal</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.tv.hdmi.cec</name>
-        <version>1</version>
-        <interface>
-            <name>IHdmiCec</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.tv.hdmi.earc</name>
-        <version>1</version>
-        <interface>
-            <name>IEArc</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.tv.hdmi.connection</name>
-        <version>1</version>
-        <interface>
-            <name>IHdmiConnection</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.tv.tuner</name>
-        <version>1-2</version>
-        <interface>
-            <name>ITuner</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.tv.input</name>
-        <version>1</version>
-        <interface>
-            <name>ITvInput</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.usb</name>
-        <version>1-2</version>
-        <interface>
-            <name>IUsb</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.usb.gadget</name>
-        <interface>
-            <name>IUsbGadget</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.vibrator</name>
-        <version>1-2</version>
-        <interface>
-            <name>IVibrator</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.vibrator</name>
-        <version>1-2</version>
-        <interface>
-            <name>IVibratorManager</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.weaver</name>
-        <version>2</version>
-        <interface>
-            <name>IWeaver</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true" updatable-via-apex="true">
-        <name>android.hardware.wifi</name>
-        <version>1</version>
-        <interface>
-            <name>IWifi</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.uwb</name>
-        <version>1</version>
-        <interface>
-            <name>IUwb</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.wifi.hostapd</name>
-        <version>1</version>
-        <interface>
-            <name>IHostapd</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.wifi.supplicant</name>
-        <version>2</version>
-        <interface>
-            <name>ISupplicant</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <!-- Either the native or the HIDL mapper HAL must exist on the device -->
-    <hal format="native" optional="true">
-        <name>mapper</name>
-        <version>5.0</version>
-        <interface>
-            <regex-instance>.*</regex-instance>
-        </interface>
-    </hal>
-</compatibility-matrix>
diff --git a/compatibility_matrices/exclude/fcm_exclude.cpp b/compatibility_matrices/exclude/fcm_exclude.cpp
index 3bc1786..46f0e03 100644
--- a/compatibility_matrices/exclude/fcm_exclude.cpp
+++ b/compatibility_matrices/exclude/fcm_exclude.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <functional>
 #include <string>
 #include <vector>
 
@@ -23,9 +24,7 @@
 namespace android::vintf::details {
 
 // The predicate to VintfObject::checkMissingHalsInMatrices.
-bool ShouldCheckMissingHalsInFcm(const std::string& package) {
-    using std::placeholders::_1;
-
+bool ShouldCheckMissingHidlHalsInFcm(const std::string& packageAndVersion) {
     static std::vector<std::string> included_prefixes{
             // Other AOSP HALs (e.g. android.frameworks.*) are not added because only framework
             // matrix is checked.
@@ -50,29 +49,11 @@
             "android.hardware.media.bufferpool@1.0",
             "android.hardware.media.bufferpool@2.0",
             "android.hardware.radio.config@1.2",
-            // AIDL
-            "android.hardware.audio.common",
-            "android.hardware.audio.core.sounddose",
-            "android.hardware.biometrics.common",
-            "android.hardware.camera.metadata",
-            "android.hardware.camera.device",
-            "android.hardware.camera.common",
-            "android.hardware.common",
-            "android.hardware.common.fmq",
-            "android.hardware.graphics.common",
-            "android.hardware.input.common",
-            "android.hardware.keymaster",
-            "android.hardware.media.bufferpool2",
-            "android.hardware.radio",
-            "android.hardware.threadnetwork",
-            "android.hardware.uwb.fira_android",
 
             // Fastboot HAL is only used by recovery. Recovery is owned by OEM. Framework
             // does not depend on this HAL, hence it is not declared in any manifests or matrices.
             "android.hardware.fastboot@1.0",
             "android.hardware.fastboot@1.1",
-            // Fastboot AIDL
-            "android.hardware.fastboot",
 
             // Deprecated HALs.
             // HIDL
@@ -103,14 +84,10 @@
             "android.hardware.thermal@1.0",
             "android.hardware.thermal@1.1",
             "android.hardware.wifi.offload@1.0",
-
-            // Under hardware/interfaces/staging, still in development
-            // AIDL
-            "android.hardware.media.c2",
     };
 
     auto package_has_prefix = [&](const std::string& prefix) {
-        return android::base::StartsWith(package, prefix);
+        return android::base::StartsWith(packageAndVersion, prefix);
     };
 
     // Only check packageAndVersions that are in the include list and not in the exclude list.
@@ -118,7 +95,71 @@
         return false;
     }
 
-    if (std::find(excluded_exact.begin(), excluded_exact.end(), package) != excluded_exact.end()) {
+    if (std::find(excluded_exact.begin(), excluded_exact.end(), packageAndVersion) !=
+        excluded_exact.end()) {
+        return false;
+    }
+
+    return !std::any_of(excluded_prefixes.begin(), excluded_prefixes.end(), package_has_prefix);
+}
+
+// The predicate to VintfObject::checkMissingHalsInMatrices.
+bool ShouldCheckMissingAidlHalsInFcm(const std::string& packageAndVersion) {
+    static std::vector<std::string> included_prefixes{
+            // Other AOSP HALs (e.g. android.frameworks.*) are not added because only framework
+            // matrix is checked.
+            "android.hardware.",
+    };
+
+    static std::vector<std::string> excluded_prefixes{
+            // Packages without top level interfaces (including types-only packages) are exempted.
+            "android.hardware.audio.common@",
+            "android.hardware.biometrics.common@",
+            "android.hardware.camera.metadata@",
+            "android.hardware.camera.device@",
+            "android.hardware.camera.common@",
+            "android.hardware.common@",
+            "android.hardware.common.fmq@",
+            "android.hardware.gnss.measurement_corrections@",
+            "android.hardware.gnss.visibility_control@",
+            "android.hardware.graphics.common@",
+            "android.hardware.input.common@",
+            "android.hardware.keymaster@",
+            "android.hardware.media.bufferpool2@",
+            "android.hardware.radio@",
+            "android.hardware.uwb.fira_android@",
+            "android.hardware.wifi.common@",
+
+            // Test packages are exempted.
+            "android.hardware.tests.",
+
+            // Fastboot HAL is only used by recovery. Recovery is owned by OEM. Framework
+            // does not depend on this HAL, hence it is not declared in any manifests or matrices.
+            "android.hardware.fastboot@",
+    };
+
+    static std::vector<std::string> excluded_exact{
+            // Packages without top level interfaces (including types-only packages) are exempted.
+
+            // AIDL
+            "android.hardware.audio.core.sounddose@1",
+            "android.hardware.audio.core.sounddose@2",
+
+            // Deprecated HALs.
+            "android.hardware.bluetooth.audio@1",
+    };
+
+    auto package_has_prefix = [&](const std::string& prefix) {
+        return android::base::StartsWith(packageAndVersion, prefix);
+    };
+
+    // Only check packageAndVersions that are in the include list and not in the exclude list.
+    if (!std::any_of(included_prefixes.begin(), included_prefixes.end(), package_has_prefix)) {
+        return false;
+    }
+
+    if (std::find(excluded_exact.begin(), excluded_exact.end(), packageAndVersion) !=
+        excluded_exact.end()) {
         return false;
     }
 
diff --git a/compatibility_matrices/exclude/include/vintf/fcm_exclude.h b/compatibility_matrices/exclude/include/vintf/fcm_exclude.h
index f74c217..e7ef4a0 100644
--- a/compatibility_matrices/exclude/include/vintf/fcm_exclude.h
+++ b/compatibility_matrices/exclude/include/vintf/fcm_exclude.h
@@ -24,7 +24,8 @@
 // Determine whether VINTF checks |package| is missing from FCMs.
 // |package| can be a HIDL package and version like
 // "android.hardware.foo@1.0", or an AIDL package name like
-// "android.hardware.foo".
-bool ShouldCheckMissingHalsInFcm(const std::string& package);
+// "android.hardware.foo@1".
+bool ShouldCheckMissingHidlHalsInFcm(const std::string& packageAndVersion);
+bool ShouldCheckMissingAidlHalsInFcm(const std::string& packageAndVersion);
 
 }  // namespace android::vintf::details
diff --git a/configstore/1.0/vts/functional/OWNERS b/configstore/1.0/vts/functional/OWNERS
deleted file mode 100644
index edfa1b0..0000000
--- a/configstore/1.0/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 24939
-lpy@google.com
diff --git a/configstore/OWNERS b/configstore/OWNERS
new file mode 100644
index 0000000..70ad434
--- /dev/null
+++ b/configstore/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 24939
+
+lpy@google.com
diff --git a/contexthub/aidl/Android.bp b/contexthub/aidl/Android.bp
index 814bf3b..cf10529 100644
--- a/contexthub/aidl/Android.bp
+++ b/contexthub/aidl/Android.bp
@@ -34,6 +34,9 @@
         ndk: {
             apps_enabled: false,
         },
+        rust: {
+            enabled: true,
+        },
     },
     versions_with_info: [
         {
@@ -46,6 +49,6 @@
         },
 
     ],
-    frozen: true,
+    frozen: false,
 
 }
diff --git a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/ContextHubInfo.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/ContextHubInfo.aidl
index e573556..c99169e 100644
--- a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/ContextHubInfo.aidl
+++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/ContextHubInfo.aidl
@@ -45,4 +45,5 @@
   byte chreApiMinorVersion;
   char chrePatchVersion;
   String[] supportedPermissions;
+  boolean supportsReliableMessages;
 }
diff --git a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/ContextHubMessage.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/ContextHubMessage.aidl
index e38c251..a6951a8 100644
--- a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/ContextHubMessage.aidl
+++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/ContextHubMessage.aidl
@@ -39,4 +39,6 @@
   int messageType;
   byte[] messageBody;
   String[] permissions;
+  boolean isReliable;
+  int messageSequenceNumber;
 }
diff --git a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/ErrorCode.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/ErrorCode.aidl
new file mode 100644
index 0000000..8924658
--- /dev/null
+++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/ErrorCode.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.contexthub;
+@Backing(type="byte") @VintfStability
+enum ErrorCode {
+  OK = 0,
+  TRANSIENT_ERROR,
+  PERMANENT_ERROR,
+  PERMISSION_DENIED,
+  DESTINATION_NOT_FOUND,
+}
diff --git a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl
index de8d752..7341e0e 100644
--- a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl
+++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl
@@ -48,5 +48,6 @@
   long[] getPreloadedNanoappIds(in int contextHubId);
   void onNanSessionStateChanged(in android.hardware.contexthub.NanSessionStateUpdate update);
   void setTestMode(in boolean enable);
+  void sendMessageDeliveryStatusToHub(in int contextHubId, in android.hardware.contexthub.MessageDeliveryStatus messageDeliveryStatus);
   const int EX_CONTEXT_HUB_UNSPECIFIED = (-1) /* -1 */;
 }
diff --git a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHubCallback.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHubCallback.aidl
index 6163cfc..70f69c6 100644
--- a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHubCallback.aidl
+++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHubCallback.aidl
@@ -39,5 +39,8 @@
   void handleContextHubAsyncEvent(in android.hardware.contexthub.AsyncEventType evt);
   void handleTransactionResult(in int transactionId, in boolean success);
   void handleNanSessionRequest(in android.hardware.contexthub.NanSessionRequest request);
+  void handleMessageDeliveryStatus(in char hostEndpointId, in android.hardware.contexthub.MessageDeliveryStatus messageDeliveryStatus);
+  byte[16] getUuid();
+  String getName();
   const int CONTEXTHUB_NAN_TRANSACTION_TIMEOUT_MS = 10000;
 }
diff --git a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/MessageDeliveryStatus.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/MessageDeliveryStatus.aidl
new file mode 100644
index 0000000..40dac13
--- /dev/null
+++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/MessageDeliveryStatus.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.contexthub;
+@VintfStability
+parcelable MessageDeliveryStatus {
+  int messageSequenceNumber;
+  android.hardware.contexthub.ErrorCode errorCode;
+}
diff --git a/contexthub/aidl/android/hardware/contexthub/ContextHubInfo.aidl b/contexthub/aidl/android/hardware/contexthub/ContextHubInfo.aidl
index c0fa702..42dba10 100644
--- a/contexthub/aidl/android/hardware/contexthub/ContextHubInfo.aidl
+++ b/contexthub/aidl/android/hardware/contexthub/ContextHubInfo.aidl
@@ -33,7 +33,9 @@
     /** Peak MIPs this platform can deliver */
     float peakMips;
 
-    /** The maximum length in bytes of the message that can be sent to the Context Hub. */
+    /**
+     * The maximum length in bytes of a message sent to the Context Hub.
+     */
     int maxSupportedMessageLengthBytes;
 
     /**
@@ -61,4 +63,11 @@
      * are granted in order to communicate with them.
      */
     String[] supportedPermissions;
+
+    /**
+     * True if the Context Hub supports reliable messages. False otherwise, in which case
+     * ContextHubMessage.isReliable must always be set to false. See
+     * ContextHubMessage.isReliable for more information.
+     */
+    boolean supportsReliableMessages;
 }
diff --git a/contexthub/aidl/android/hardware/contexthub/ContextHubMessage.aidl b/contexthub/aidl/android/hardware/contexthub/ContextHubMessage.aidl
index 95d478e..3cd20ca 100644
--- a/contexthub/aidl/android/hardware/contexthub/ContextHubMessage.aidl
+++ b/contexthub/aidl/android/hardware/contexthub/ContextHubMessage.aidl
@@ -50,4 +50,35 @@
      * of the permissions that the sending nanoapp is using.
      */
     String[] permissions;
+
+    /**
+     * Whether the message is reliable.
+     *
+     * For reliable messages, the receiver is expected to acknowledge the reception of
+     * the message by sending a message delivery status back to the sender. Acknowledgment of
+     * the message must be returned within 1 second.
+     *
+     * For reliable messages sent by the host, the Context Hub invokes
+     * IContextHubCallback#handleMessageDeliveryStatus to report the status.
+     *
+     * For reliable messages sent by the Context Hub, the host calls
+     * IContextHub#sendMessageDeliveryStatusToHub to report the status.
+     */
+    boolean isReliable;
+
+    /**
+     * The sequence number for a reliable message. For less than 2^32 messages, each message sent
+     * from a Context Hub will have a unique sequence number generated by the Context Hub, and the
+     * sequence numbers are guaranteed to not be reused for unacknowledged messages. For messages
+     * sent to the Context Hub, sequence numbers are only guaranteed to be unique within the scope
+     * of a given hostEndPoint. The sequence number may be reused if more than 2^32 messages are
+     * sent, due to the size limit of int.
+     *
+     * The sequence number is used only for reliable messages. There is no guarantee of strict
+     * ordering of messages. The recipient may receive messages with gaps between the sequence
+     * numbers. This is not an indication of a missed message.
+     *
+     * See isReliable for more information.
+     */
+    int messageSequenceNumber;
 }
diff --git a/contexthub/aidl/android/hardware/contexthub/ErrorCode.aidl b/contexthub/aidl/android/hardware/contexthub/ErrorCode.aidl
new file mode 100644
index 0000000..22e7ea1
--- /dev/null
+++ b/contexthub/aidl/android/hardware/contexthub/ErrorCode.aidl
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.contexthub;
+
+@VintfStability
+@Backing(type="byte")
+enum ErrorCode {
+    /**
+     * No Error.
+     */
+    OK = 0,
+
+    /**
+     * A generic transient error. The sender may retry the
+     * operation, but there is no guarantee of success.
+     */
+    TRANSIENT_ERROR,
+
+    /**
+     * A generic permanent error. The sender should not retry the operation.
+     */
+    PERMANENT_ERROR,
+
+    /**
+     * The request failed because the sender does not have necessary permissions.
+     * The sender should not retry the operation.
+     */
+    PERMISSION_DENIED,
+
+    /**
+     * The request failed because the destination was not found.
+     * The sender should not retry the operation.
+     */
+    DESTINATION_NOT_FOUND,
+}
diff --git a/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl b/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl
index 9683d2d..b146ff8 100644
--- a/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl
+++ b/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl
@@ -20,6 +20,7 @@
 import android.hardware.contexthub.ContextHubMessage;
 import android.hardware.contexthub.HostEndpointInfo;
 import android.hardware.contexthub.IContextHubCallback;
+import android.hardware.contexthub.MessageDeliveryStatus;
 import android.hardware.contexthub.NanSessionStateUpdate;
 import android.hardware.contexthub.NanoappBinary;
 import android.hardware.contexthub.NanoappInfo;
@@ -147,7 +148,7 @@
 
     /**
      * Register a callback for the HAL implementation to send asynchronous messages to the service
-     * from a Context hub. There can only be one callback registered for a single Context Hub ID.
+     * from a Context hub. Each HAL client can only have one callback for each Context Hub ID.
      *
      * A call to this function when a callback has already been registered must override the
      * previous registration.
@@ -236,6 +237,21 @@
     void setTestMode(in boolean enable);
 
     /**
+     * Sends a message delivery status to the Context Hub in response to receiving a
+     * ContextHubMessage with isReliable=true. Each reliable message should have a
+     * messageDeliveryStatus response. This method sends the message delivery status
+     * back to the Context Hub.
+     *
+     * @param contextHubId The identifier of the Context Hub.
+     * @param messageDeliveryStatus The status to be sent.
+     *
+     * @throws EX_UNSUPPORTED_OPERATION if ContextHubInfo.supportsReliableMessages is false for
+     * this hub.
+     */
+    void sendMessageDeliveryStatusToHub(
+            in int contextHubId, in MessageDeliveryStatus messageDeliveryStatus);
+
+    /**
      * Error codes that are used as service specific errors with the AIDL return
      * value EX_SERVICE_SPECIFIC.
      */
diff --git a/contexthub/aidl/android/hardware/contexthub/IContextHubCallback.aidl b/contexthub/aidl/android/hardware/contexthub/IContextHubCallback.aidl
index bfcb51e..1aa0776 100644
--- a/contexthub/aidl/android/hardware/contexthub/IContextHubCallback.aidl
+++ b/contexthub/aidl/android/hardware/contexthub/IContextHubCallback.aidl
@@ -18,6 +18,7 @@
 
 import android.hardware.contexthub.AsyncEventType;
 import android.hardware.contexthub.ContextHubMessage;
+import android.hardware.contexthub.MessageDeliveryStatus;
 import android.hardware.contexthub.NanSessionRequest;
 import android.hardware.contexthub.NanoappInfo;
 
@@ -91,6 +92,35 @@
     void handleNanSessionRequest(in NanSessionRequest request);
 
     /**
+     * This callback is passed by the Contexthub service to the HAL
+     * implementation to allow the HAL to send the response for a reliable message.
+     * The response is the message delivery status of a recently sent message. See
+     * sendMessageDeliveryStatusToHub() for more details.
+     *
+     * @param hostEndPointId The ID of the host endpoint associated with this message delivery
+     *                       status.
+     * @param messageDeliveryStatus The status to be sent.
+     */
+    void handleMessageDeliveryStatus(
+            in char hostEndpointId, in MessageDeliveryStatus messageDeliveryStatus);
+
+    /**
+     * This callback is passed to the HAL implementation to allow the HAL to request a UUID that
+     * uniquely identifies a client.
+     *
+     * @return a byte array representating the UUID
+     */
+    byte[16] getUuid();
+
+    /**
+     * This callback gets the name of a client implementing this IContextHubCallback interface,
+     * which must be a hard-coded string and does not change at runtime.
+     *
+     * <p>The name provides a human-readable way to identify a client for troubleshooting purpose.
+     */
+    String getName();
+
+    /**
      * Amount of time, in milliseconds, that a handleNanSessionRequest can be pending before the
      * Contexthub service must respond.
      */
diff --git a/contexthub/aidl/android/hardware/contexthub/MessageDeliveryStatus.aidl b/contexthub/aidl/android/hardware/contexthub/MessageDeliveryStatus.aidl
new file mode 100644
index 0000000..ae425b3
--- /dev/null
+++ b/contexthub/aidl/android/hardware/contexthub/MessageDeliveryStatus.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.contexthub;
+
+import android.hardware.contexthub.ErrorCode;
+
+@VintfStability
+parcelable MessageDeliveryStatus {
+    /**
+     * The messageSequenceNumber of the ContextHubMessage to which this status applies.
+     */
+    int messageSequenceNumber;
+
+    /**
+     * The error code associated with this status.
+     */
+    ErrorCode errorCode;
+}
diff --git a/contexthub/aidl/default/Android.bp b/contexthub/aidl/default/Android.bp
index 6ee7407..03213bc 100644
--- a/contexthub/aidl/default/Android.bp
+++ b/contexthub/aidl/default/Android.bp
@@ -29,7 +29,7 @@
     shared_libs: [
         "libbase",
         "libbinder_ndk",
-        "android.hardware.contexthub-V2-ndk",
+        "android.hardware.contexthub-V3-ndk",
     ],
     export_include_dirs: ["include"],
     srcs: [
@@ -50,10 +50,41 @@
     shared_libs: [
         "libbase",
         "libbinder_ndk",
-        "android.hardware.contexthub-V2-ndk",
+        "android.hardware.contexthub-V3-ndk",
     ],
     static_libs: [
         "libcontexthubexampleimpl",
     ],
     srcs: ["main.cpp"],
 }
+
+prebuilt_etc {
+    name: "android.hardware.contexthub-service.example.rc",
+    src: "android.hardware.contexthub-service.example.rc",
+    installable: false,
+}
+
+prebuilt_etc {
+    name: "contexthub-default.xml",
+    src: "contexthub-default.xml",
+    sub_dir: "vintf",
+    installable: false,
+}
+
+apex {
+    name: "com.android.hardware.contexthub",
+    vendor: true,
+    manifest: "apex_manifest.json",
+    file_contexts: "apex_file_contexts",
+    key: "com.android.hardware.key",
+    certificate: ":com.android.hardware.certificate",
+    updatable: false,
+
+    binaries: [
+        "android.hardware.contexthub-service.example",
+    ],
+    prebuilts: [
+        "android.hardware.contexthub-service.example.rc",
+        "contexthub-default.xml",
+    ],
+}
diff --git a/contexthub/aidl/default/ContextHub.cpp b/contexthub/aidl/default/ContextHub.cpp
index 5272957..bd483d7 100644
--- a/contexthub/aidl/default/ContextHub.cpp
+++ b/contexthub/aidl/default/ContextHub.cpp
@@ -16,10 +16,7 @@
 
 #include "contexthub-impl/ContextHub.h"
 
-namespace aidl {
-namespace android {
-namespace hardware {
-namespace contexthub {
+namespace aidl::android::hardware::contexthub {
 
 using ::ndk::ScopedAStatus;
 
@@ -34,10 +31,11 @@
     hub.chrePlatformId = UINT64_C(0x476f6f6754000000);
     hub.chreApiMajorVersion = 1;
     hub.chreApiMinorVersion = 6;
+    hub.supportsReliableMessages = false;
 
     out_contextHubInfos->push_back(hub);
 
-    return ndk::ScopedAStatus::ok();
+    return ScopedAStatus::ok();
 }
 
 // We don't expose any nanoapps for the default impl, therefore all nanoapp-related APIs fail.
@@ -63,14 +61,14 @@
 }
 
 ScopedAStatus ContextHub::onSettingChanged(Setting /* in_setting */, bool /*in_enabled */) {
-    return ndk::ScopedAStatus::ok();
+    return ScopedAStatus::ok();
 }
 
 ScopedAStatus ContextHub::queryNanoapps(int32_t in_contextHubId) {
     if (in_contextHubId == kMockHubId && mCallback != nullptr) {
         std::vector<NanoappInfo> nanoapps;
         mCallback->handleNanoappInfo(nanoapps);
-        return ndk::ScopedAStatus::ok();
+        return ScopedAStatus::ok();
     } else {
         return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
@@ -85,18 +83,18 @@
     for (uint64_t i = 0; i < 10; ++i) {
         out_preloadedNanoappIds->push_back(i);
     }
-    return ndk::ScopedAStatus::ok();
+    return ScopedAStatus::ok();
 }
 
 ScopedAStatus ContextHub::onNanSessionStateChanged(const NanSessionStateUpdate& /*in_update*/) {
-    return ndk::ScopedAStatus::ok();
+    return ScopedAStatus::ok();
 }
 
 ScopedAStatus ContextHub::registerCallback(int32_t in_contextHubId,
                                            const std::shared_ptr<IContextHubCallback>& in_cb) {
     if (in_contextHubId == kMockHubId) {
         mCallback = in_cb;
-        return ndk::ScopedAStatus::ok();
+        return ScopedAStatus::ok();
     } else {
         return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
@@ -108,20 +106,20 @@
         // Return true here to indicate that the HAL has accepted the message.
         // Successful delivery of the message to a nanoapp should be handled at
         // a higher level protocol.
-        return ndk::ScopedAStatus::ok();
+        return ScopedAStatus::ok();
     } else {
         return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
 }
 
 ScopedAStatus ContextHub::setTestMode(bool /* enable */) {
-    return ndk::ScopedAStatus::ok();
+    return ScopedAStatus::ok();
 }
 
 ScopedAStatus ContextHub::onHostEndpointConnected(const HostEndpointInfo& in_info) {
     mConnectedHostEndpoints.insert(in_info.hostEndpointId);
 
-    return ndk::ScopedAStatus::ok();
+    return ScopedAStatus::ok();
 }
 
 ScopedAStatus ContextHub::onHostEndpointDisconnected(char16_t in_hostEndpointId) {
@@ -129,10 +127,13 @@
         mConnectedHostEndpoints.erase(in_hostEndpointId);
     }
 
-    return ndk::ScopedAStatus::ok();
+    return ScopedAStatus::ok();
 }
 
-}  // namespace contexthub
-}  // namespace hardware
-}  // namespace android
-}  // namespace aidl
+ScopedAStatus ContextHub::sendMessageDeliveryStatusToHub(
+        int32_t /* in_contextHubId */,
+        const MessageDeliveryStatus& /* in_messageDeliveryStatus */) {
+    return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+}  // namespace aidl::android::hardware::contexthub
diff --git a/contexthub/aidl/default/android.hardware.contexthub-service.example.rc b/contexthub/aidl/default/android.hardware.contexthub-service.example.rc
new file mode 100644
index 0000000..7d5d2aa
--- /dev/null
+++ b/contexthub/aidl/default/android.hardware.contexthub-service.example.rc
@@ -0,0 +1,4 @@
+service vendor.contexthub-default /apex/com.android.hardware.contexthub/bin/hw/android.hardware.contexthub-service.example
+    class hal
+    user context_hub
+    group context_hub
diff --git a/contexthub/aidl/default/apex_file_contexts b/contexthub/aidl/default/apex_file_contexts
new file mode 100644
index 0000000..c3c67df
--- /dev/null
+++ b/contexthub/aidl/default/apex_file_contexts
@@ -0,0 +1,3 @@
+(/.*)?                                                          u:object_r:vendor_file:s0
+/etc(/.*)?                                                      u:object_r:vendor_configs_file:s0
+/bin/hw/android\.hardware\.contexthub-service\.example          u:object_r:hal_contexthub_default_exec:s0
diff --git a/contexthub/aidl/default/apex_manifest.json b/contexthub/aidl/default/apex_manifest.json
new file mode 100644
index 0000000..aed7081
--- /dev/null
+++ b/contexthub/aidl/default/apex_manifest.json
@@ -0,0 +1,4 @@
+{
+    "name": "com.android.hardware.contexthub",
+    "version": 1
+}
\ No newline at end of file
diff --git a/contexthub/aidl/default/contexthub-default.xml b/contexthub/aidl/default/contexthub-default.xml
index 930f672..2f8ddc8 100644
--- a/contexthub/aidl/default/contexthub-default.xml
+++ b/contexthub/aidl/default/contexthub-default.xml
@@ -1,7 +1,7 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.contexthub</name>
-        <version>2</version>
+        <version>3</version>
         <interface>
             <name>IContextHub</name>
             <instance>default</instance>
diff --git a/contexthub/aidl/default/include/contexthub-impl/ContextHub.h b/contexthub/aidl/default/include/contexthub-impl/ContextHub.h
index 7a2cfd1..72e8b3b 100644
--- a/contexthub/aidl/default/include/contexthub-impl/ContextHub.h
+++ b/contexthub/aidl/default/include/contexthub-impl/ContextHub.h
@@ -49,6 +49,9 @@
 
     ::ndk::ScopedAStatus onHostEndpointDisconnected(char16_t in_hostEndpointId) override;
     ::ndk::ScopedAStatus onNanSessionStateChanged(const NanSessionStateUpdate& in_update) override;
+    ::ndk::ScopedAStatus sendMessageDeliveryStatusToHub(
+            int32_t in_contextHubId,
+            const MessageDeliveryStatus& in_messageDeliveryStatus) override;
 
   private:
     static constexpr uint32_t kMockHubId = 0;
diff --git a/contexthub/aidl/vts/Android.bp b/contexthub/aidl/vts/Android.bp
index 1534b40..b166baf 100644
--- a/contexthub/aidl/vts/Android.bp
+++ b/contexthub/aidl/vts/Android.bp
@@ -32,7 +32,7 @@
         "libbinder",
     ],
     static_libs: [
-        "android.hardware.contexthub-V2-cpp",
+        "android.hardware.contexthub-V3-cpp",
         "VtsHalContexthubUtils",
     ],
     test_suites: [
diff --git a/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp b/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp
index c1cc07c..fd55b80 100644
--- a/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp
+++ b/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp
@@ -36,9 +36,11 @@
 using ::android::hardware::contexthub::AsyncEventType;
 using ::android::hardware::contexthub::ContextHubInfo;
 using ::android::hardware::contexthub::ContextHubMessage;
+using ::android::hardware::contexthub::ErrorCode;
 using ::android::hardware::contexthub::HostEndpointInfo;
 using ::android::hardware::contexthub::IContextHub;
 using ::android::hardware::contexthub::IContextHubCallbackDefault;
+using ::android::hardware::contexthub::MessageDeliveryStatus;
 using ::android::hardware::contexthub::NanoappBinary;
 using ::android::hardware::contexthub::NanoappInfo;
 using ::android::hardware::contexthub::NanoappRpcService;
@@ -48,6 +50,11 @@
 using ::android::hardware::contexthub::vts_utils::kNonExistentAppId;
 using ::android::hardware::contexthub::vts_utils::waitForCallback;
 
+// 6612b522-b717-41c8-b48d-c0b1cc64e142
+constexpr std::array<uint8_t, 16> kUuid = {0x66, 0x12, 0xb5, 0x22, 0xb7, 0x17, 0x41, 0xc8,
+                                           0xb4, 0x8d, 0xc0, 0xb1, 0xcc, 0x64, 0xe1, 0x42};
+const String16 kName{"VtsAidlHalContextHubTargetTest"};
+
 class ContextHubAidl : public testing::TestWithParam<std::tuple<std::string, int32_t>> {
   public:
     virtual void SetUp() override {
@@ -126,6 +133,22 @@
     Status handleNanSessionRequest(const NanSessionRequest& /* request */) override {
         return Status::ok();
     }
+
+    Status handleMessageDeliveryStatus(
+            char16_t /* hostEndPointId */,
+            const MessageDeliveryStatus& /* messageDeliveryStatus */) override {
+        return Status::ok();
+    }
+
+    Status getUuid(std::array<uint8_t, 16>* out_uuid) override {
+        *out_uuid = kUuid;
+        return Status::ok();
+    }
+
+    Status getName(::android::String16* out_name) override {
+        *out_name = kName;
+        return Status::ok();
+    }
 };
 
 TEST_P(ContextHubAidl, TestRegisterCallback) {
@@ -157,6 +180,22 @@
         return Status::ok();
     }
 
+    Status handleMessageDeliveryStatus(
+            char16_t /* hostEndPointId */,
+            const MessageDeliveryStatus& /* messageDeliveryStatus */) override {
+        return Status::ok();
+    }
+
+    Status getUuid(std::array<uint8_t, 16>* out_uuid) override {
+        *out_uuid = kUuid;
+        return Status::ok();
+    }
+
+    Status getName(::android::String16* out_name) override {
+        *out_name = kName;
+        return Status::ok();
+    }
+
     std::promise<std::vector<NanoappInfo>> promise;
 };
 
@@ -223,6 +262,22 @@
         return Status::ok();
     }
 
+    Status handleMessageDeliveryStatus(
+            char16_t /* hostEndPointId */,
+            const MessageDeliveryStatus& /* messageDeliveryStatus */) override {
+        return Status::ok();
+    }
+
+    Status getUuid(std::array<uint8_t, 16>* out_uuid) override {
+        *out_uuid = kUuid;
+        return Status::ok();
+    }
+
+    Status getName(::android::String16* out_name) override {
+        *out_name = kName;
+        return Status::ok();
+    }
+
     uint32_t expectedTransactionId = 0;
     std::promise<bool> promise;
 };
@@ -396,6 +451,20 @@
     }
 }
 
+TEST_P(ContextHubAidl, TestSendMessageDeliveryStatusToHub) {
+    MessageDeliveryStatus messageDeliveryStatus;
+    messageDeliveryStatus.messageSequenceNumber = 123;
+    messageDeliveryStatus.errorCode = ErrorCode::OK;
+
+    Status status = contextHub->sendMessageDeliveryStatusToHub(getHubId(), messageDeliveryStatus);
+    if (status.exceptionCode() == Status::EX_UNSUPPORTED_OPERATION ||
+        status.transactionError() == android::UNKNOWN_TRANSACTION) {
+        GTEST_SKIP() << "Not supported -> old API; or not implemented";
+    } else {
+        EXPECT_TRUE(status.isOk());
+    }
+}
+
 std::string PrintGeneratedTest(const testing::TestParamInfo<ContextHubAidl::ParamType>& info) {
     return std::string("CONTEXT_HUB_ID_") + std::to_string(std::get<1>(info.param));
 }
diff --git a/drm/1.0/default/Android.bp b/drm/1.0/default/Android.bp
index cbdab4f..45aba7b 100644
--- a/drm/1.0/default/Android.bp
+++ b/drm/1.0/default/Android.bp
@@ -134,6 +134,7 @@
     shared_libs: [
         "android.hardware.drm@1.0",
         "android.hidl.memory@1.0",
+        "libbase",
         "libcutils",
         "libhidlbase",
         "libhidlmemory",
diff --git a/drm/1.0/default/DrmPlugin.cpp b/drm/1.0/default/DrmPlugin.cpp
index 809f694..0a0a350 100644
--- a/drm/1.0/default/DrmPlugin.cpp
+++ b/drm/1.0/default/DrmPlugin.cpp
@@ -98,8 +98,7 @@
                 break;
             }
         }
-        _hidl_cb(toStatus(status), toHidlVec(legacyRequest), requestType,
-                 defaultUrl.string());
+        _hidl_cb(toStatus(status), toHidlVec(legacyRequest), requestType, defaultUrl.c_str());
         return Void();
     }
 
@@ -134,8 +133,8 @@
         Vector<KeyValue> infoMapVec;
         for (size_t i = 0; i < legacyInfoMap.size(); i++) {
             KeyValue keyValuePair;
-            keyValuePair.key = String8(legacyInfoMap.keyAt(i));
-            keyValuePair.value = String8(legacyInfoMap.valueAt(i));
+            keyValuePair.key = legacyInfoMap.keyAt(i);
+            keyValuePair.value = legacyInfoMap.valueAt(i);
             infoMapVec.push_back(keyValuePair);
         }
         _hidl_cb(toStatus(status), toHidlVec(infoMapVec));
@@ -219,7 +218,7 @@
         String8 legacyValue;
         status_t status = mLegacyPlugin->getPropertyString(
                 String8(propertyName.c_str()), legacyValue);
-        _hidl_cb(toStatus(status), legacyValue.string());
+        _hidl_cb(toStatus(status), legacyValue.c_str());
         return Void();
     }
 
diff --git a/drm/1.0/default/OWNERS b/drm/1.0/default/OWNERS
deleted file mode 100644
index ecb421c..0000000
--- a/drm/1.0/default/OWNERS
+++ /dev/null
@@ -1,6 +0,0 @@
-edwinwong@google.com
-fredgc@google.com
-jtinker@google.com
-kylealexander@google.com
-rfrias@google.com
-robertshih@google.com
diff --git a/drm/1.0/default/SharedLibrary.cpp b/drm/1.0/default/SharedLibrary.cpp
index 0a942cd..c9b5389 100644
--- a/drm/1.0/default/SharedLibrary.cpp
+++ b/drm/1.0/default/SharedLibrary.cpp
@@ -26,7 +26,7 @@
 namespace helper {
 
 SharedLibrary::SharedLibrary(const String8& path) {
-    mLibHandle = dlopen(path.string(), RTLD_NOW);
+    mLibHandle = dlopen(path.c_str(), RTLD_NOW);
 }
 
 SharedLibrary::~SharedLibrary() {
diff --git a/drm/1.0/default/include/PluginLoader.h b/drm/1.0/default/include/PluginLoader.h
index 0c45fb3..a25dd41 100644
--- a/drm/1.0/default/include/PluginLoader.h
+++ b/drm/1.0/default/include/PluginLoader.h
@@ -18,6 +18,8 @@
 #define PLUGIN_LOADER_H_
 
 #include "SharedLibrary.h"
+
+#include <android-base/strings.h>
 #include <utils/Log.h>
 #include <utils/String8.h>
 #include <utils/Vector.h>
@@ -39,16 +41,16 @@
          */
         String8 pluginDir(dir);
 
-        DIR* pDir = opendir(pluginDir.string());
+        DIR* pDir = opendir(pluginDir.c_str());
         if (pDir == NULL) {
-            ALOGE("Failed to find plugin directory %s", pluginDir.string());
+            ALOGE("Failed to find plugin directory %s", pluginDir.c_str());
         } else {
             struct dirent* pEntry;
             while ((pEntry = readdir(pDir))) {
                 String8 file(pEntry->d_name);
-                if (file.getPathExtension() == ".so") {
+                if (base::EndsWith(file.c_str(), ".so")) {
                     String8 path = pluginDir + "/" + pEntry->d_name;
-                    T *plugin = loadOne(path, entry);
+                    T* plugin = loadOne(path.c_str(), entry);
                     if (plugin) {
                         factories.push(plugin);
                     }
diff --git a/drm/1.0/vts/OWNERS b/drm/1.0/vts/OWNERS
deleted file mode 100644
index ecb421c..0000000
--- a/drm/1.0/vts/OWNERS
+++ /dev/null
@@ -1,6 +0,0 @@
-edwinwong@google.com
-fredgc@google.com
-jtinker@google.com
-kylealexander@google.com
-rfrias@google.com
-robertshih@google.com
diff --git a/drm/1.0/vts/functional/OWNERS b/drm/1.0/vts/functional/OWNERS
deleted file mode 100644
index 0b13790..0000000
--- a/drm/1.0/vts/functional/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Bug component: 49079
-jtinker@google.com
-robertshih@google.com
-edwinwong@google.com
\ No newline at end of file
diff --git a/drm/1.1/vts/OWNERS b/drm/1.1/vts/OWNERS
deleted file mode 100644
index ecb421c..0000000
--- a/drm/1.1/vts/OWNERS
+++ /dev/null
@@ -1,6 +0,0 @@
-edwinwong@google.com
-fredgc@google.com
-jtinker@google.com
-kylealexander@google.com
-rfrias@google.com
-robertshih@google.com
diff --git a/drm/1.1/vts/functional/OWNERS b/drm/1.1/vts/functional/OWNERS
deleted file mode 100644
index 0b13790..0000000
--- a/drm/1.1/vts/functional/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Bug component: 49079
-jtinker@google.com
-robertshih@google.com
-edwinwong@google.com
\ No newline at end of file
diff --git a/drm/1.2/vts/OWNERS b/drm/1.2/vts/OWNERS
deleted file mode 100644
index ecb421c..0000000
--- a/drm/1.2/vts/OWNERS
+++ /dev/null
@@ -1,6 +0,0 @@
-edwinwong@google.com
-fredgc@google.com
-jtinker@google.com
-kylealexander@google.com
-rfrias@google.com
-robertshih@google.com
diff --git a/drm/1.2/vts/functional/OWNERS b/drm/1.2/vts/functional/OWNERS
deleted file mode 100644
index 0b13790..0000000
--- a/drm/1.2/vts/functional/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Bug component: 49079
-jtinker@google.com
-robertshih@google.com
-edwinwong@google.com
\ No newline at end of file
diff --git a/drm/1.3/vts/OWNERS b/drm/1.3/vts/OWNERS
deleted file mode 100644
index 3a0672e..0000000
--- a/drm/1.3/vts/OWNERS
+++ /dev/null
@@ -1,9 +0,0 @@
-conglin@google.com
-edwinwong@google.com
-fredgc@google.com
-jtinker@google.com
-juce@google.com
-kylealexander@google.com
-rfrias@google.com
-robertshih@google.com
-sigquit@google.com
diff --git a/drm/1.4/vts/OWNERS b/drm/1.4/vts/OWNERS
deleted file mode 100644
index 3a0672e..0000000
--- a/drm/1.4/vts/OWNERS
+++ /dev/null
@@ -1,9 +0,0 @@
-conglin@google.com
-edwinwong@google.com
-fredgc@google.com
-jtinker@google.com
-juce@google.com
-kylealexander@google.com
-rfrias@google.com
-robertshih@google.com
-sigquit@google.com
diff --git a/drm/OWNERS b/drm/OWNERS
new file mode 100644
index 0000000..c06472a
--- /dev/null
+++ b/drm/OWNERS
@@ -0,0 +1,12 @@
+# Bug component: 49079
+
+conglin@google.com
+fredgc@google.com
+juce@google.com
+kelzhan@google.com
+kylealexander@google.com
+mattfedd@google.com
+rfrias@google.com
+robertshih@google.com
+sigquit@google.com
+vickymin@google.com
diff --git a/drm/aidl/OWNERS b/drm/aidl/OWNERS
deleted file mode 100644
index fe69725..0000000
--- a/drm/aidl/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 49079
-kelzhan@google.com
-robertshih@google.com
diff --git a/drm/aidl/vts/OWNERS b/drm/aidl/vts/OWNERS
deleted file mode 100644
index fe69725..0000000
--- a/drm/aidl/vts/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 49079
-kelzhan@google.com
-robertshih@google.com
diff --git a/dumpstate/OWNERS b/dumpstate/OWNERS
new file mode 100644
index 0000000..4c9173e
--- /dev/null
+++ b/dumpstate/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 298624585
+
+include platform/frameworks/native:/cmds/dumpstate/OWNERS
diff --git a/dumpstate/aidl/default/Android.bp b/dumpstate/aidl/default/Android.bp
index 45fdc17..a9da69c 100644
--- a/dumpstate/aidl/default/Android.bp
+++ b/dumpstate/aidl/default/Android.bp
@@ -44,3 +44,41 @@
         "-DLOG_TAG=\"android.hardware.dumpstate-service.example\"",
     ],
 }
+
+prebuilt_etc {
+    name: "dumpstate-default.xml",
+    src: "dumpstate-default.xml",
+    sub_dir: "vintf",
+    installable: false,
+}
+
+prebuilt_etc {
+    name: "dumpstate-default.rc",
+    src: ":gen-dumpstate-default.rc-for-apex",
+    installable: false,
+}
+
+genrule {
+    name: "gen-dumpstate-default.rc-for-apex",
+    srcs: ["dumpstate-default.rc"],
+    out: ["dumpstate-default-apex.rc"],
+    cmd: "sed -E 's/\\/vendor\\/bin\\/hw/\\/apex\\/com.android.hardware.dumpstate\\/bin\\/hw/' $(in) > $(out)",
+}
+
+apex {
+    name: "com.android.hardware.dumpstate",
+    vendor: true,
+    manifest: "apex_manifest.json",
+    file_contexts: "apex_file_contexts",
+    key: "com.android.hardware.key",
+    certificate: ":com.android.hardware.certificate",
+    updatable: false,
+
+    binaries: [
+        "android.hardware.dumpstate-service.example",
+    ],
+    prebuilts: [
+        "dumpstate-default.rc",
+        "dumpstate-default.xml",
+    ],
+}
diff --git a/dumpstate/aidl/default/apex_file_contexts b/dumpstate/aidl/default/apex_file_contexts
new file mode 100644
index 0000000..91153a9
--- /dev/null
+++ b/dumpstate/aidl/default/apex_file_contexts
@@ -0,0 +1,3 @@
+(/.*)?                                          u:object_r:vendor_file:s0
+/etc(/.*)?                                      u:object_r:vendor_configs_file:s0
+/bin/hw/android\.hardware\.dumpstate-service\.example u:object_r:hal_dumpstate_default_exec:s0
\ No newline at end of file
diff --git a/dumpstate/aidl/default/apex_manifest.json b/dumpstate/aidl/default/apex_manifest.json
new file mode 100644
index 0000000..32beea4
--- /dev/null
+++ b/dumpstate/aidl/default/apex_manifest.json
@@ -0,0 +1,4 @@
+{
+    "name": "com.android.hardware.dumpstate",
+    "version": 1
+}
\ No newline at end of file
diff --git a/gatekeeper/aidl/Android.bp b/gatekeeper/aidl/Android.bp
index b050f6a..169a7d5 100644
--- a/gatekeeper/aidl/Android.bp
+++ b/gatekeeper/aidl/Android.bp
@@ -25,6 +25,9 @@
         cpp: {
             enabled: false,
         },
+        rust: {
+            enabled: true,
+        },
     },
     versions_with_info: [
         {
diff --git a/gatekeeper/aidl/vts/functional/VtsHalGatekeeperTargetTest.cpp b/gatekeeper/aidl/vts/functional/VtsHalGatekeeperTargetTest.cpp
index c89243b..032f7e2 100644
--- a/gatekeeper/aidl/vts/functional/VtsHalGatekeeperTargetTest.cpp
+++ b/gatekeeper/aidl/vts/functional/VtsHalGatekeeperTargetTest.cpp
@@ -221,6 +221,47 @@
 }
 
 /**
+ * Ensure that passwords containing a NUL byte aren't truncated
+ */
+TEST_P(GatekeeperAidlTest, PasswordIsBinaryData) {
+    GatekeeperEnrollResponse enrollRsp;
+    GatekeeperVerifyResponse verifyRsp;
+    std::vector<uint8_t> rightPassword = {'A', 'B', 'C', '\0', 'D', 'E', 'F'};
+    std::vector<uint8_t> wrongPassword = {'A', 'B', 'C', '\0', '\0', '\0', '\0'};
+
+    ALOGI("Testing Enroll+Verify of password with embedded NUL (expected success)");
+    enrollNewPassword(rightPassword, enrollRsp, true);
+    verifyPassword(rightPassword, enrollRsp.data, 1, verifyRsp, true);
+
+    ALOGI("Testing Verify of wrong password (expected failure)");
+    verifyPassword(wrongPassword, enrollRsp.data, 1, verifyRsp, false);
+
+    ALOGI("PasswordIsBinaryData test done");
+}
+
+/**
+ * Ensure that long passwords aren't truncated
+ */
+TEST_P(GatekeeperAidlTest, LongPassword) {
+    GatekeeperEnrollResponse enrollRsp;
+    GatekeeperVerifyResponse verifyRsp;
+    std::vector<uint8_t> password;
+
+    password.resize(64);  // maximum length used by Android
+    memset(password.data(), 'A', password.size());
+
+    ALOGI("Testing Enroll+Verify of long password (expected success)");
+    enrollNewPassword(password, enrollRsp, true);
+    verifyPassword(password, enrollRsp.data, 1, verifyRsp, true);
+
+    ALOGI("Testing Verify of wrong password (expected failure)");
+    password[password.size() - 1] ^= 1;
+    verifyPassword(password, enrollRsp.data, 1, verifyRsp, false);
+
+    ALOGI("LongPassword test done");
+}
+
+/**
  * Ensure we can securely update password (keep the same
  * secure user_id) if we prove we know old password
  */
diff --git a/gnss/1.0/default/OWNERS b/gnss/1.0/default/OWNERS
deleted file mode 100644
index 6c25bd7..0000000
--- a/gnss/1.0/default/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-wyattriley@google.com
-gomo@google.com
-smalkos@google.com
diff --git a/gnss/1.0/vts/OWNERS b/gnss/1.0/vts/OWNERS
deleted file mode 100644
index 937d70a..0000000
--- a/gnss/1.0/vts/OWNERS
+++ /dev/null
@@ -1,7 +0,0 @@
-wyattriley@google.com
-gomo@google.com
-smalkos@google.com
-
-# VTS team
-yim@google.com
-trong@google.com
\ No newline at end of file
diff --git a/gnss/1.0/vts/functional/OWNERS b/gnss/1.0/vts/functional/OWNERS
deleted file mode 100644
index b831eb4..0000000
--- a/gnss/1.0/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 393449
-yuhany@google.com
diff --git a/gnss/1.1/default/Android.bp b/gnss/1.1/default/Android.bp
index 300e8de..697cb91 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-V3-ndk",
+        "android.hardware.gnss-V4-ndk",
     ],
     static_libs: [
         "android.hardware.gnss@common-default-lib",
diff --git a/gnss/1.1/default/OWNERS b/gnss/1.1/default/OWNERS
deleted file mode 100644
index a3d8577..0000000
--- a/gnss/1.1/default/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-wyattriley@google.com
-gomo@google.com
-smalkos@google.com
-yuhany@google.com
diff --git a/gnss/1.1/vts/OWNERS b/gnss/1.1/vts/OWNERS
deleted file mode 100644
index 3ed36da..0000000
--- a/gnss/1.1/vts/OWNERS
+++ /dev/null
@@ -1,7 +0,0 @@
-wyattriley@google.com
-gomo@google.com
-smalkos@google.com
-yuhany@google.com
-
-# VTS team
-yim@google.com
diff --git a/gnss/1.1/vts/functional/Android.bp b/gnss/1.1/vts/functional/Android.bp
index 2414cbc..f9fcbf1 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-V3-cpp",
+        "android.hardware.gnss-V4-cpp",
     ],
     shared_libs: [
         "android.hardware.gnss.measurement_corrections@1.0",
diff --git a/gnss/1.1/vts/functional/OWNERS b/gnss/1.1/vts/functional/OWNERS
deleted file mode 100644
index b831eb4..0000000
--- a/gnss/1.1/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 393449
-yuhany@google.com
diff --git a/gnss/2.0/default/Android.bp b/gnss/2.0/default/Android.bp
index 83bc2cc..35c2e37 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-V3-ndk",
+        "android.hardware.gnss-V4-ndk",
     ],
     static_libs: [
         "android.hardware.gnss@common-default-lib",
diff --git a/gnss/2.0/default/OWNERS b/gnss/2.0/default/OWNERS
deleted file mode 100644
index 8da956c..0000000
--- a/gnss/2.0/default/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-wyattriley@google.com
-gomo@google.com
-smalkos@google.com
-yuhany@google.com
-aadmal@google.com
diff --git a/gnss/2.0/vts/OWNERS b/gnss/2.0/vts/OWNERS
deleted file mode 100644
index 0a7ce6c..0000000
--- a/gnss/2.0/vts/OWNERS
+++ /dev/null
@@ -1,8 +0,0 @@
-wyattriley@google.com
-gomo@google.com
-smalkos@google.com
-yuhany@google.com
-aadmal@google.com
-
-# VTS team
-yim@google.com
diff --git a/gnss/2.0/vts/functional/Android.bp b/gnss/2.0/vts/functional/Android.bp
index e8db886..0b54308 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-V3-cpp",
+        "android.hardware.gnss-V4-cpp",
     ],
     test_suites: [
         "general-tests",
diff --git a/gnss/2.0/vts/functional/OWNERS b/gnss/2.0/vts/functional/OWNERS
deleted file mode 100644
index b831eb4..0000000
--- a/gnss/2.0/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 393449
-yuhany@google.com
diff --git a/gnss/2.1/default/Android.bp b/gnss/2.1/default/Android.bp
index 4a4ce54..1bb7512 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-V3-ndk",
+        "android.hardware.gnss-V4-ndk",
     ],
     static_libs: [
         "android.hardware.gnss@common-default-lib",
diff --git a/gnss/2.1/default/OWNERS b/gnss/2.1/default/OWNERS
deleted file mode 100644
index b7b4a2e..0000000
--- a/gnss/2.1/default/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-gomo@google.com
-smalkos@google.com
-wyattriley@google.com
-yuhany@google.com
diff --git a/gnss/2.1/vts/OWNERS b/gnss/2.1/vts/OWNERS
deleted file mode 100644
index b7b4a2e..0000000
--- a/gnss/2.1/vts/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-gomo@google.com
-smalkos@google.com
-wyattriley@google.com
-yuhany@google.com
diff --git a/gnss/2.1/vts/functional/Android.bp b/gnss/2.1/vts/functional/Android.bp
index 76f9d07..9906b27 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-V3-cpp",
+        "android.hardware.gnss-V4-cpp",
     ],
     shared_libs: [
         "libvintf",
diff --git a/gnss/2.1/vts/functional/OWNERS b/gnss/2.1/vts/functional/OWNERS
deleted file mode 100644
index b831eb4..0000000
--- a/gnss/2.1/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 393449
-yuhany@google.com
diff --git a/gnss/OWNERS b/gnss/OWNERS
new file mode 100644
index 0000000..57982e7
--- /dev/null
+++ b/gnss/OWNERS
@@ -0,0 +1,8 @@
+# Bug component: 393449
+
+gomo@google.com
+smalkos@google.com
+trong@google.com
+wyattriley@google.com
+yim@google.com
+yuhany@google.com
diff --git a/gnss/aidl/Android.bp b/gnss/aidl/Android.bp
index cb2c001..611c7e0 100644
--- a/gnss/aidl/Android.bp
+++ b/gnss/aidl/Android.bp
@@ -52,6 +52,6 @@
         },
 
     ],
-    frozen: true,
+    frozen: false,
 
 }
diff --git a/gnss/aidl/OWNERS b/gnss/aidl/OWNERS
deleted file mode 100644
index b7b4a2e..0000000
--- a/gnss/aidl/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-gomo@google.com
-smalkos@google.com
-wyattriley@google.com
-yuhany@google.com
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/ElapsedRealtime.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/ElapsedRealtime.aidl
index 559ed29..5d7f51e 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/ElapsedRealtime.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/ElapsedRealtime.aidl
@@ -38,6 +38,6 @@
   int flags;
   long timestampNs;
   double timeUncertaintyNs;
-  const int HAS_TIMESTAMP_NS = 1;
-  const int HAS_TIME_UNCERTAINTY_NS = 2;
+  const int HAS_TIMESTAMP_NS = (1 << 0) /* 1 */;
+  const int HAS_TIME_UNCERTAINTY_NS = (1 << 1) /* 2 */;
 }
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssClock.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssClock.aidl
index a8454dd..63edd44 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssClock.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssClock.aidl
@@ -46,11 +46,11 @@
   double driftUncertaintyNsps;
   int hwClockDiscontinuityCount;
   android.hardware.gnss.GnssSignalType referenceSignalTypeForIsb;
-  const int HAS_LEAP_SECOND = 1;
-  const int HAS_TIME_UNCERTAINTY = 2;
-  const int HAS_FULL_BIAS = 4;
-  const int HAS_BIAS = 8;
-  const int HAS_BIAS_UNCERTAINTY = 16;
-  const int HAS_DRIFT = 32;
-  const int HAS_DRIFT_UNCERTAINTY = 64;
+  const int HAS_LEAP_SECOND = (1 << 0) /* 1 */;
+  const int HAS_TIME_UNCERTAINTY = (1 << 1) /* 2 */;
+  const int HAS_FULL_BIAS = (1 << 2) /* 4 */;
+  const int HAS_BIAS = (1 << 3) /* 8 */;
+  const int HAS_BIAS_UNCERTAINTY = (1 << 4) /* 16 */;
+  const int HAS_DRIFT = (1 << 5) /* 32 */;
+  const int HAS_DRIFT_UNCERTAINTY = (1 << 6) /* 64 */;
 }
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssLocation.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssLocation.aidl
index ed9dcfa..e64d98a 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssLocation.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssLocation.aidl
@@ -47,12 +47,12 @@
   double bearingAccuracyDegrees;
   long timestampMillis;
   android.hardware.gnss.ElapsedRealtime elapsedRealtime;
-  const int HAS_LAT_LONG = 1;
-  const int HAS_ALTITUDE = 2;
-  const int HAS_SPEED = 4;
-  const int HAS_BEARING = 8;
-  const int HAS_HORIZONTAL_ACCURACY = 16;
-  const int HAS_VERTICAL_ACCURACY = 32;
-  const int HAS_SPEED_ACCURACY = 64;
-  const int HAS_BEARING_ACCURACY = 128;
+  const int HAS_LAT_LONG = 0x0001;
+  const int HAS_ALTITUDE = 0x0002;
+  const int HAS_SPEED = 0x0004;
+  const int HAS_BEARING = 0x0008;
+  const int HAS_HORIZONTAL_ACCURACY = 0x0010;
+  const int HAS_VERTICAL_ACCURACY = 0x0020;
+  const int HAS_SPEED_ACCURACY = 0x0040;
+  const int HAS_BEARING_ACCURACY = 0x0080;
 }
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssMeasurement.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssMeasurement.aidl
index 8a44887..a2594af 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssMeasurement.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssMeasurement.aidl
@@ -61,39 +61,39 @@
   double satelliteInterSignalBiasUncertaintyNs;
   android.hardware.gnss.SatellitePvt satellitePvt;
   android.hardware.gnss.CorrelationVector[] correlationVectors;
-  const int HAS_SNR = 1;
-  const int HAS_CARRIER_FREQUENCY = 512;
-  const int HAS_CARRIER_CYCLES = 1024;
-  const int HAS_CARRIER_PHASE = 2048;
-  const int HAS_CARRIER_PHASE_UNCERTAINTY = 4096;
-  const int HAS_AUTOMATIC_GAIN_CONTROL = 8192;
-  const int HAS_FULL_ISB = 65536;
-  const int HAS_FULL_ISB_UNCERTAINTY = 131072;
-  const int HAS_SATELLITE_ISB = 262144;
-  const int HAS_SATELLITE_ISB_UNCERTAINTY = 524288;
-  const int HAS_SATELLITE_PVT = 1048576;
-  const int HAS_CORRELATION_VECTOR = 2097152;
+  const int HAS_SNR = (1 << 0) /* 1 */;
+  const int HAS_CARRIER_FREQUENCY = (1 << 9) /* 512 */;
+  const int HAS_CARRIER_CYCLES = (1 << 10) /* 1024 */;
+  const int HAS_CARRIER_PHASE = (1 << 11) /* 2048 */;
+  const int HAS_CARRIER_PHASE_UNCERTAINTY = (1 << 12) /* 4096 */;
+  const int HAS_AUTOMATIC_GAIN_CONTROL = (1 << 13) /* 8192 */;
+  const int HAS_FULL_ISB = (1 << 16) /* 65536 */;
+  const int HAS_FULL_ISB_UNCERTAINTY = (1 << 17) /* 131072 */;
+  const int HAS_SATELLITE_ISB = (1 << 18) /* 262144 */;
+  const int HAS_SATELLITE_ISB_UNCERTAINTY = (1 << 19) /* 524288 */;
+  const int HAS_SATELLITE_PVT = (1 << 20) /* 1048576 */;
+  const int HAS_CORRELATION_VECTOR = (1 << 21) /* 2097152 */;
   const int STATE_UNKNOWN = 0;
-  const int STATE_CODE_LOCK = 1;
-  const int STATE_BIT_SYNC = 2;
-  const int STATE_SUBFRAME_SYNC = 4;
-  const int STATE_TOW_DECODED = 8;
-  const int STATE_MSEC_AMBIGUOUS = 16;
-  const int STATE_SYMBOL_SYNC = 32;
-  const int STATE_GLO_STRING_SYNC = 64;
-  const int STATE_GLO_TOD_DECODED = 128;
-  const int STATE_BDS_D2_BIT_SYNC = 256;
-  const int STATE_BDS_D2_SUBFRAME_SYNC = 512;
-  const int STATE_GAL_E1BC_CODE_LOCK = 1024;
-  const int STATE_GAL_E1C_2ND_CODE_LOCK = 2048;
-  const int STATE_GAL_E1B_PAGE_SYNC = 4096;
-  const int STATE_SBAS_SYNC = 8192;
-  const int STATE_TOW_KNOWN = 16384;
-  const int STATE_GLO_TOD_KNOWN = 32768;
-  const int STATE_2ND_CODE_LOCK = 65536;
+  const int STATE_CODE_LOCK = (1 << 0) /* 1 */;
+  const int STATE_BIT_SYNC = (1 << 1) /* 2 */;
+  const int STATE_SUBFRAME_SYNC = (1 << 2) /* 4 */;
+  const int STATE_TOW_DECODED = (1 << 3) /* 8 */;
+  const int STATE_MSEC_AMBIGUOUS = (1 << 4) /* 16 */;
+  const int STATE_SYMBOL_SYNC = (1 << 5) /* 32 */;
+  const int STATE_GLO_STRING_SYNC = (1 << 6) /* 64 */;
+  const int STATE_GLO_TOD_DECODED = (1 << 7) /* 128 */;
+  const int STATE_BDS_D2_BIT_SYNC = (1 << 8) /* 256 */;
+  const int STATE_BDS_D2_SUBFRAME_SYNC = (1 << 9) /* 512 */;
+  const int STATE_GAL_E1BC_CODE_LOCK = (1 << 10) /* 1024 */;
+  const int STATE_GAL_E1C_2ND_CODE_LOCK = (1 << 11) /* 2048 */;
+  const int STATE_GAL_E1B_PAGE_SYNC = (1 << 12) /* 4096 */;
+  const int STATE_SBAS_SYNC = (1 << 13) /* 8192 */;
+  const int STATE_TOW_KNOWN = (1 << 14) /* 16384 */;
+  const int STATE_GLO_TOD_KNOWN = (1 << 15) /* 32768 */;
+  const int STATE_2ND_CODE_LOCK = (1 << 16) /* 65536 */;
   const int ADR_STATE_UNKNOWN = 0;
-  const int ADR_STATE_VALID = 1;
-  const int ADR_STATE_RESET = 2;
-  const int ADR_STATE_CYCLE_SLIP = 4;
-  const int ADR_STATE_HALF_CYCLE_RESOLVED = 8;
+  const int ADR_STATE_VALID = (1 << 0) /* 1 */;
+  const int ADR_STATE_RESET = (1 << 1) /* 2 */;
+  const int ADR_STATE_CYCLE_SLIP = (1 << 2) /* 4 */;
+  const int ADR_STATE_HALF_CYCLE_RESOLVED = (1 << 3) /* 8 */;
 }
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssSignalType.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssSignalType.aidl
index 4a49547..a17f933 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssSignalType.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssSignalType.aidl
@@ -42,6 +42,7 @@
   const @utf8InCpp String CODE_TYPE_B = "B";
   const @utf8InCpp String CODE_TYPE_C = "C";
   const @utf8InCpp String CODE_TYPE_D = "D";
+  const @utf8InCpp String CODE_TYPE_E = "E";
   const @utf8InCpp String CODE_TYPE_I = "I";
   const @utf8InCpp String CODE_TYPE_L = "L";
   const @utf8InCpp String CODE_TYPE_M = "M";
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IAGnssRil.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IAGnssRil.aidl
index c782b6f..c8634ec 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IAGnssRil.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IAGnssRil.aidl
@@ -40,8 +40,8 @@
   void setSetId(in android.hardware.gnss.IAGnssRil.SetIdType type, in @utf8InCpp String setid);
   void updateNetworkState(in android.hardware.gnss.IAGnssRil.NetworkAttributes attributes);
   void injectNiSuplMessageData(in byte[] msgData, in int slotIndex);
-  const int NETWORK_CAPABILITY_NOT_METERED = 1;
-  const int NETWORK_CAPABILITY_NOT_ROAMING = 2;
+  const int NETWORK_CAPABILITY_NOT_METERED = 0x01;
+  const int NETWORK_CAPABILITY_NOT_ROAMING = 0x02;
   @Backing(type="int") @VintfStability
   enum AGnssRefLocationType {
     GSM_CELLID = 1,
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnss.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnss.aidl
index 0e6405e..d1aaf2c 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnss.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnss.aidl
@@ -77,19 +77,19 @@
   }
   @Backing(type="int") @VintfStability
   enum GnssAidingData {
-    EPHEMERIS = 1,
-    ALMANAC = 2,
-    POSITION = 4,
-    TIME = 8,
-    IONO = 16,
-    UTC = 32,
-    HEALTH = 64,
-    SVDIR = 128,
-    SVSTEER = 256,
-    SADATA = 512,
-    RTI = 1024,
-    CELLDB_INFO = 32768,
-    ALL = 65535,
+    EPHEMERIS = 0x0001,
+    ALMANAC = 0x0002,
+    POSITION = 0x0004,
+    TIME = 0x0008,
+    IONO = 0x0010,
+    UTC = 0x0020,
+    HEALTH = 0x0040,
+    SVDIR = 0x0080,
+    SVSTEER = 0x0100,
+    SADATA = 0x0200,
+    RTI = 0x0400,
+    CELLDB_INFO = 0x8000,
+    ALL = 0xFFFF,
   }
   @VintfStability
   parcelable PositionModeOptions {
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssBatching.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssBatching.aidl
index d82aa1f..a021f55 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssBatching.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssBatching.aidl
@@ -41,7 +41,7 @@
   void flush();
   void stop();
   void cleanup();
-  const int WAKEUP_ON_FIFO_FULL = 1;
+  const int WAKEUP_ON_FIFO_FULL = 0x01;
   @VintfStability
   parcelable Options {
     long periodNanos;
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 0247182..61710d3 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
@@ -46,22 +46,22 @@
   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;
-  const int CAPABILITY_SINGLE_SHOT = 8;
-  const int CAPABILITY_ON_DEMAND_TIME = 16;
-  const int CAPABILITY_GEOFENCING = 32;
-  const int CAPABILITY_MEASUREMENTS = 64;
-  const int CAPABILITY_NAV_MESSAGES = 128;
-  const int CAPABILITY_LOW_POWER_MODE = 256;
-  const int CAPABILITY_SATELLITE_BLOCKLIST = 512;
-  const int CAPABILITY_MEASUREMENT_CORRECTIONS = 1024;
-  const int CAPABILITY_ANTENNA_INFO = 2048;
-  const int CAPABILITY_CORRELATION_VECTOR = 4096;
-  const int CAPABILITY_SATELLITE_PVT = 8192;
-  const int CAPABILITY_MEASUREMENT_CORRECTIONS_FOR_DRIVING = 16384;
-  const int CAPABILITY_ACCUMULATED_DELTA_RANGE = 32768;
+  const int CAPABILITY_SCHEDULING = (1 << 0) /* 1 */;
+  const int CAPABILITY_MSB = (1 << 1) /* 2 */;
+  const int CAPABILITY_MSA = (1 << 2) /* 4 */;
+  const int CAPABILITY_SINGLE_SHOT = (1 << 3) /* 8 */;
+  const int CAPABILITY_ON_DEMAND_TIME = (1 << 4) /* 16 */;
+  const int CAPABILITY_GEOFENCING = (1 << 5) /* 32 */;
+  const int CAPABILITY_MEASUREMENTS = (1 << 6) /* 64 */;
+  const int CAPABILITY_NAV_MESSAGES = (1 << 7) /* 128 */;
+  const int CAPABILITY_LOW_POWER_MODE = (1 << 8) /* 256 */;
+  const int CAPABILITY_SATELLITE_BLOCKLIST = (1 << 9) /* 512 */;
+  const int CAPABILITY_MEASUREMENT_CORRECTIONS = (1 << 10) /* 1024 */;
+  const int CAPABILITY_ANTENNA_INFO = (1 << 11) /* 2048 */;
+  const int CAPABILITY_CORRELATION_VECTOR = (1 << 12) /* 4096 */;
+  const int CAPABILITY_SATELLITE_PVT = (1 << 13) /* 8192 */;
+  const int CAPABILITY_MEASUREMENT_CORRECTIONS_FOR_DRIVING = (1 << 14) /* 16384 */;
+  const int CAPABILITY_ACCUMULATED_DELTA_RANGE = (1 << 15) /* 32768 */;
   @Backing(type="int") @VintfStability
   enum GnssStatusValue {
     NONE = 0,
@@ -73,10 +73,10 @@
   @Backing(type="int") @VintfStability
   enum GnssSvFlags {
     NONE = 0,
-    HAS_EPHEMERIS_DATA = 1,
-    HAS_ALMANAC_DATA = 2,
-    USED_IN_FIX = 4,
-    HAS_CARRIER_FREQUENCY = 8,
+    HAS_EPHEMERIS_DATA = (1 << 0) /* 1 */,
+    HAS_ALMANAC_DATA = (1 << 1) /* 2 */,
+    USED_IN_FIX = (1 << 2) /* 4 */,
+    HAS_CARRIER_FREQUENCY = (1 << 3) /* 8 */,
   }
   @VintfStability
   parcelable GnssSvInfo {
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssConfiguration.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssConfiguration.aidl
index 1d6399e..70df11a 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssConfiguration.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssConfiguration.aidl
@@ -42,11 +42,11 @@
   void setEmergencySuplPdn(in boolean enable);
   void setEsExtensionSec(in int emergencyExtensionSeconds);
   void setBlocklist(in android.hardware.gnss.BlocklistedSource[] blocklist);
-  const int SUPL_MODE_MSB = 1;
-  const int SUPL_MODE_MSA = 2;
-  const int LPP_PROFILE_USER_PLANE = 1;
-  const int LPP_PROFILE_CONTROL_PLANE = 2;
-  const int GLONASS_POS_PROTOCOL_RRC_CPLANE = 1;
-  const int GLONASS_POS_PROTOCOL_RRLP_UPLANE = 2;
-  const int GLONASS_POS_PROTOCOL_LPP_UPLANE = 4;
+  const int SUPL_MODE_MSB = 0x01;
+  const int SUPL_MODE_MSA = 0x02;
+  const int LPP_PROFILE_USER_PLANE = 0x01;
+  const int LPP_PROFILE_CONTROL_PLANE = 0x02;
+  const int GLONASS_POS_PROTOCOL_RRC_CPLANE = 0x01;
+  const int GLONASS_POS_PROTOCOL_RRLP_UPLANE = 0x02;
+  const int GLONASS_POS_PROTOCOL_LPP_UPLANE = 0x04;
 }
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssGeofenceCallback.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssGeofenceCallback.aidl
index df5dc2d..90f9ebc 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssGeofenceCallback.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssGeofenceCallback.aidl
@@ -41,15 +41,15 @@
   void gnssGeofenceRemoveCb(in int geofenceId, in int status);
   void gnssGeofencePauseCb(in int geofenceId, in int status);
   void gnssGeofenceResumeCb(in int geofenceId, in int status);
-  const int ENTERED = 1;
-  const int EXITED = 2;
-  const int UNCERTAIN = 4;
-  const int UNAVAILABLE = 1;
-  const int AVAILABLE = 2;
+  const int ENTERED = (1 << 0) /* 1 */;
+  const int EXITED = (1 << 1) /* 2 */;
+  const int UNCERTAIN = (1 << 2) /* 4 */;
+  const int UNAVAILABLE = (1 << 0) /* 1 */;
+  const int AVAILABLE = (1 << 1) /* 2 */;
   const int OPERATION_SUCCESS = 0;
-  const int ERROR_TOO_MANY_GEOFENCES = -100;
-  const int ERROR_ID_EXISTS = -101;
-  const int ERROR_ID_UNKNOWN = -102;
-  const int ERROR_INVALID_TRANSITION = -103;
-  const int ERROR_GENERIC = -149;
+  const int ERROR_TOO_MANY_GEOFENCES = (-100) /* -100 */;
+  const int ERROR_ID_EXISTS = (-101) /* -101 */;
+  const int ERROR_ID_UNKNOWN = (-102) /* -102 */;
+  const int ERROR_INVALID_TRANSITION = (-103) /* -103 */;
+  const int ERROR_GENERIC = (-149) /* -149 */;
 }
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssNavigationMessageCallback.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssNavigationMessageCallback.aidl
index c65cff2..f6a8fef 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssNavigationMessageCallback.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssNavigationMessageCallback.aidl
@@ -44,26 +44,31 @@
     int messageId;
     int submessageId;
     byte[] data;
-    const int STATUS_PARITY_PASSED = 1;
-    const int STATUS_PARITY_REBUILT = 2;
+    const int STATUS_PARITY_PASSED = (1 << 0) /* 1 */;
+    const int STATUS_PARITY_REBUILT = (1 << 1) /* 2 */;
     const int STATUS_UNKNOWN = 0;
     @Backing(type="int") @VintfStability
     enum GnssNavigationMessageType {
       UNKNOWN = 0,
-      GPS_L1CA = 257,
-      GPS_L2CNAV = 258,
-      GPS_L5CNAV = 259,
-      SBS = 513,
-      GPS_CNAV2 = 260,
-      GLO_L1CA = 769,
-      QZS_L1CA = 1025,
-      BDS_D1 = 1281,
-      BDS_D2 = 1282,
-      BDS_CNAV1 = 1283,
-      BDS_CNAV2 = 1284,
-      GAL_I = 1537,
-      GAL_F = 1538,
-      IRN_L5CA = 1793,
+      GPS_L1CA = 0x0101,
+      GPS_L2CNAV = 0x0102,
+      GPS_L5CNAV = 0x0103,
+      SBS = 0x0201,
+      GPS_CNAV2 = 0x0104,
+      GLO_L1CA = 0x0301,
+      QZS_L1CA = 0x0401,
+      BDS_D1 = 0x0501,
+      BDS_D2 = 0x0502,
+      BDS_CNAV1 = 0x0503,
+      BDS_CNAV2 = 0x0504,
+      GAL_I = 0x0601,
+      GAL_F = 0x0602,
+      /**
+       * @deprecated Use IRN_L5 instead.
+       */
+      IRN_L5CA = 0x0701,
+      IRN_L5 = 0x0702,
+      IRN_L1 = 0x0703,
     }
   }
 }
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPowerIndicationCallback.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPowerIndicationCallback.aidl
index d35c77f..07b10ad 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPowerIndicationCallback.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPowerIndicationCallback.aidl
@@ -37,10 +37,10 @@
 interface IGnssPowerIndicationCallback {
   void setCapabilitiesCb(in int capabilities);
   oneway void gnssPowerStatsCb(in android.hardware.gnss.GnssPowerStats gnssPowerStats);
-  const int CAPABILITY_TOTAL = 1;
-  const int CAPABILITY_SINGLEBAND_TRACKING = 2;
-  const int CAPABILITY_MULTIBAND_TRACKING = 4;
-  const int CAPABILITY_SINGLEBAND_ACQUISITION = 8;
-  const int CAPABILITY_MULTIBAND_ACQUISITION = 16;
-  const int CAPABILITY_OTHER_MODES = 32;
+  const int CAPABILITY_TOTAL = (1 << 0) /* 1 */;
+  const int CAPABILITY_SINGLEBAND_TRACKING = (1 << 1) /* 2 */;
+  const int CAPABILITY_MULTIBAND_TRACKING = (1 << 2) /* 4 */;
+  const int CAPABILITY_SINGLEBAND_ACQUISITION = (1 << 3) /* 8 */;
+  const int CAPABILITY_MULTIBAND_ACQUISITION = (1 << 4) /* 16 */;
+  const int CAPABILITY_OTHER_MODES = (1 << 5) /* 32 */;
 }
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/SatellitePvt.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/SatellitePvt.aidl
index 5fd411f..ae65f39 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/SatellitePvt.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/SatellitePvt.aidl
@@ -46,9 +46,9 @@
   long timeOfEphemerisSeconds;
   int issueOfDataEphemeris;
   android.hardware.gnss.SatellitePvt.SatelliteEphemerisSource ephemerisSource = android.hardware.gnss.SatellitePvt.SatelliteEphemerisSource.OTHER;
-  const int HAS_POSITION_VELOCITY_CLOCK_INFO = 1;
-  const int HAS_IONO = 2;
-  const int HAS_TROPO = 4;
+  const int HAS_POSITION_VELOCITY_CLOCK_INFO = (1 << 0) /* 1 */;
+  const int HAS_IONO = (1 << 1) /* 2 */;
+  const int HAS_TROPO = (1 << 2) /* 4 */;
   @Backing(type="int") @VintfStability
   enum SatelliteEphemerisSource {
     DEMODULATED = 0,
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsCallback.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsCallback.aidl
index 4126702..61909d0 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsCallback.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsCallback.aidl
@@ -36,7 +36,7 @@
 @VintfStability
 interface IMeasurementCorrectionsCallback {
   void setCapabilitiesCb(in int capabilities);
-  const int CAPABILITY_LOS_SATS = 1;
-  const int CAPABILITY_EXCESS_PATH_LENGTH = 2;
-  const int CAPABILITY_REFLECTING_PLANE = 4;
+  const int CAPABILITY_LOS_SATS = (1 << 0) /* 1 */;
+  const int CAPABILITY_EXCESS_PATH_LENGTH = (1 << 1) /* 2 */;
+  const int CAPABILITY_REFLECTING_PLANE = (1 << 2) /* 4 */;
 }
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/SingleSatCorrection.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/SingleSatCorrection.aidl
index ebbe684..72d32e4 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/SingleSatCorrection.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/SingleSatCorrection.aidl
@@ -44,10 +44,10 @@
   float combinedExcessPathLengthUncertaintyMeters;
   float combinedAttenuationDb;
   android.hardware.gnss.measurement_corrections.SingleSatCorrection.ExcessPathInfo[] excessPathInfos;
-  const int SINGLE_SAT_CORRECTION_HAS_SAT_IS_LOS_PROBABILITY = 1;
-  const int SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH = 2;
-  const int SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH_UNC = 4;
-  const int SINGLE_SAT_CORRECTION_HAS_COMBINED_ATTENUATION = 16;
+  const int SINGLE_SAT_CORRECTION_HAS_SAT_IS_LOS_PROBABILITY = 0x0001;
+  const int SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH = 0x0002;
+  const int SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH_UNC = 0x0004;
+  const int SINGLE_SAT_CORRECTION_HAS_COMBINED_ATTENUATION = 0x0010;
   @VintfStability
   parcelable ExcessPathInfo {
     int excessPathInfoFlags;
@@ -55,9 +55,9 @@
     float excessPathLengthUncertaintyMeters;
     android.hardware.gnss.measurement_corrections.ReflectingPlane reflectingPlane;
     float attenuationDb;
-    const int EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH = 1;
-    const int EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH_UNC = 2;
-    const int EXCESS_PATH_INFO_HAS_REFLECTING_PLANE = 4;
-    const int EXCESS_PATH_INFO_HAS_ATTENUATION = 8;
+    const int EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH = 0x0001;
+    const int EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH_UNC = 0x0002;
+    const int EXCESS_PATH_INFO_HAS_REFLECTING_PLANE = 0x0004;
+    const int EXCESS_PATH_INFO_HAS_ATTENUATION = 0x0008;
   }
 }
diff --git a/gnss/aidl/android/hardware/gnss/GnssSignalType.aidl b/gnss/aidl/android/hardware/gnss/GnssSignalType.aidl
index 241971f..69de750 100644
--- a/gnss/aidl/android/hardware/gnss/GnssSignalType.aidl
+++ b/gnss/aidl/android/hardware/gnss/GnssSignalType.aidl
@@ -46,27 +46,37 @@
     double carrierFrequencyHz;
 
     /**
-     * GNSS signal code type "A" representing GALILEO E1A, GALILEO E6A, IRNSS L5A, IRNSS SA.
+     * GNSS signal code type "A" representing GALILEO E1A, GALILEO E6A, NavIC L5A SPS, NavIC SA SPS,
+     * GLONASS G1a L1OCd, GLONASS G2a L2CSI.
      */
     const @utf8InCpp String CODE_TYPE_A = "A";
 
     /**
-     * GNSS signal code type "B" representing GALILEO E1B, GALILEO E6B, IRNSS L5B, IRNSS SB.
+     * GNSS signal code type "B" representing GALILEO E1B, GALILEO E6B, NavIC L5B RS (D),
+     * NavIC SB RS (D), GLONASS G1a L1OCp, GLONASS G2a L2OCp, QZSS L1Sb.
      */
     const @utf8InCpp String CODE_TYPE_B = "B";
 
     /**
      * GNSS signal code type "C" representing GPS L1 C/A,  GPS L2 C/A, GLONASS G1 C/A,
-     * GLONASS G2 C/A, GALILEO E1C, GALILEO E6C, SBAS L1 C/A, QZSS L1 C/A, IRNSS L5C.
+     * GLONASS G2 C/A, GALILEO E1C, GALILEO E6C, SBAS L1 C/A, QZSS L1 C/A, NavIC L5C RS (P),
+     * NavIC SC RS (P).
      */
     const @utf8InCpp String CODE_TYPE_C = "C";
 
     /**
-     * GNSS signal code type "D" representing BDS B1C D.
+     * GNSS signal code type "D" representing GPS L2 (L1(C/A) + (P2-P1) (semi-codeless)),
+     * QZSS L5S(I), BDS B1C Data, BDS B2a Data, BDS B2b Data, BDS B2 (B2a+B2b) Data, BDS B3a Data,
+     * NavIC L1 Data.
      */
     const @utf8InCpp String CODE_TYPE_D = "D";
 
     /**
+     * GNSS signal code type "E" representing QZSS L1 C/B, QZSS L6E.
+     */
+    const @utf8InCpp String CODE_TYPE_E = "E";
+
+    /**
      * GNSS signal code type "I" representing GPS L5 I, GLONASS G3 I, GALILEO E5a I, GALILEO E5b I,
      * GALILEO E5a+b I, SBAS L5 I, QZSS L5 I, BDS B1 I, BDS B2 I, BDS B3 I.
      */
@@ -74,7 +84,7 @@
 
     /**
      * GNSS signal code type "L" representing GPS L1C (P), GPS L2C (L), QZSS L1C (P), QZSS L2C (L),
-     * LEX(6) L.
+     * QZSS L6P, BDS B1a Pilot.
      */
     const @utf8InCpp String CODE_TYPE_L = "L";
 
@@ -89,7 +99,9 @@
     const @utf8InCpp String CODE_TYPE_N = "N";
 
     /**
-     * GNSS signal code type "P" representing GPS L1P, GPS L2P, GLONASS G1P, GLONASS G2P, BDS B1C P.
+     * GNSS signal code type "P" representing GPS L1P, GPS L2P, GLONASS G1P, GLONASS G2P,
+     * BDS B1C Pilot, BDS B2a Pilot, BDS B2b Pilot, BDS B2 (B2a+B2b) Pilot, BDS B3a Pilot,
+     * QZSS L5S(Q), NavIC L1 Pilot.
      */
     const @utf8InCpp String CODE_TYPE_P = "P";
 
@@ -101,7 +113,7 @@
 
     /**
      * GNSS signal code type "S" represents GPS L1C (D), GPS L2C (M), QZSS L1C (D), QZSS L2C (M),
-     * LEX(6) S.
+     * QZSS L6D, BDS B1a Data.
      */
     const @utf8InCpp String CODE_TYPE_S = "S";
 
@@ -112,9 +124,11 @@
 
     /**
      * GNSS signal code type "X" representing GPS L1C (D+P), GPS L2C (M+L), GPS L5 (I+Q),
-     * GLONASS G3 (I+Q), GALILEO E1 (B+C), GALILEO E5a (I+Q), GALILEO E5b (I+Q), GALILEO E5a+b(I+Q),
-     * GALILEO E6 (B+C), SBAS L5 (I+Q), QZSS L1C (D+P), QZSS L2C (M+L), QZSS L5 (I+Q),
-     * LEX(6) (S+L), BDS B1 (I+Q), BDS B1C (D+P), BDS B2 (I+Q), BDS B3 (I+Q), IRNSS L5 (B+C).
+     * GLONASS G1a L1OCd+L1OCp, GLONASS G2a L2CSI+L2OCp, GLONASS G3 (I+Q), GALILEO E1 (B+C),
+     * GALILEO E5a (I+Q), GALILEO E5b (I+Q), GALILEO E5a+b (I+Q), GALILEO E6 (B+C), SBAS L5 (I+Q),
+     * QZSS L1C (D+P), QZSS L2C (M+L), QZSS L5 (I+Q), QZSS L6 (D+P), BDS B1 (I+Q),
+     * BDS B1C Data+Pilot, BDS B2a Data+Pilot, BDS B2 (I+Q), BDS B2 (B2a+B2b) Data+Pilot,
+     * BDS B3 (I+Q), NavIC L5 (B+C), NavIC S (B+C), NavIC L1 Data+Pilot.
      */
     const @utf8InCpp String CODE_TYPE_X = "X";
 
@@ -124,7 +138,9 @@
     const @utf8InCpp String CODE_TYPE_Y = "Y";
 
     /**
-     * GNSS signal code type "Z" representing GALILEO E1 (A+B+C), GALILEO E6 (A+B+C), QZSS L1-SAIF.
+     * GNSS signal code type "Z" representing GALILEO E1 (A+B+C), GALILEO E6 (A+B+C),
+     * QZSS L1S/L1-SAIF, QZSS L5S (I+Q), QZSS L6 (D+E), BDS B1A Data+Pilot, BDS B2b Data+Pilot,
+     * BDS B3a Data+Pilot.
      */
     const @utf8InCpp String CODE_TYPE_Z = "Z";
 
@@ -142,10 +158,11 @@
      * The value is one of the constant Strings with prefix CODE_TYPE_ defined in this parcelable.
      *
      * This is used to specify the observation descriptor defined in GNSS Observation Data File
-     * Header Section Description in the RINEX standard (Version 3.XX). In RINEX Version 3.03,
-     * in Appendix Table A2 Attributes are listed as uppercase letters (for instance, "A" for
-     * "A channel"). In the future, if for instance a code "G" was added in the official RINEX
-     * standard, "G" could be specified here.
+     * Header Section Description in the RINEX standard (Version 4.00) e.g., in Tables 9-16 (see
+     * https://igs.org/wg/rinex/#documents-formats). In cases where the code type does not align
+     * with the above listed values, the code type from the most recent version of RINEX should be
+     * used. In the future, if for instance a code "G" was added in the official RINEX standard,
+     * "G" could be specified here.
      */
     @utf8InCpp String codeType;
 }
diff --git a/gnss/aidl/android/hardware/gnss/IGnss.aidl b/gnss/aidl/android/hardware/gnss/IGnss.aidl
index aaafe7f..8a22d6e 100644
--- a/gnss/aidl/android/hardware/gnss/IGnss.aidl
+++ b/gnss/aidl/android/hardware/gnss/IGnss.aidl
@@ -217,6 +217,10 @@
      * Starts a location output stream using the IGnssCallback gnssLocationCb(), following the
      * settings from the most recent call to setPositionMode().
      *
+     * When a location output stream is in progress, calling setPositionMode() does not change the
+     * settings of the current location output stream. stop() and start() must be called to make the
+     * new settings effective.
+     *
      * This output must operate independently of any GNSS location batching operations,
      * see the IGnssBatching for details.
      */
@@ -306,6 +310,10 @@
     /**
      * Sets the GnssPositionMode parameter, its associated recurrence value, the time between fixes,
      * requested fix accuracy, time to first fix.
+     *
+     * If a location output stream is in progress, calling this method does not affect the settings
+     * of current location output stream. stop() and start() must be called to make the new settings
+     * effective.
      */
     void setPositionMode(in PositionModeOptions options);
 
diff --git a/gnss/aidl/android/hardware/gnss/IGnssNavigationMessageCallback.aidl b/gnss/aidl/android/hardware/gnss/IGnssNavigationMessageCallback.aidl
index 6990e19..b224b0b 100644
--- a/gnss/aidl/android/hardware/gnss/IGnssNavigationMessageCallback.aidl
+++ b/gnss/aidl/android/hardware/gnss/IGnssNavigationMessageCallback.aidl
@@ -100,8 +100,17 @@
             /** Galileo F/NAV message contained in the structure. */
             GAL_F = 0x0602,
 
-            /** IRNSS L5 C/A message contained in the structure. */
+            /**
+             * NavIC L5 C/A message contained in the structure.
+             * @deprecated Use IRN_L5 instead.
+             */
             IRN_L5CA = 0x0701,
+
+            /** NavIC L5 message contained in the structure. */
+            IRN_L5 = 0x0702,
+
+            /** NavIC L1 message contained in the structure. */
+            IRN_L1 = 0x0703,
         }
 
         /**
@@ -156,9 +165,12 @@
          *
          * - For Beidou CNAV1 this refers to the page type number in the range of 1-63.
          *
-         * - For IRNSS L5 C/A subframe 3 and 4, this value corresponds to the Message Id of the
+         * - For NavIC L5 subframe 3 and 4, this value corresponds to the Message Id of the
          *   navigation message, in the range of 1-63. (Subframe 1 and 2 does not contain a message
          *   type id and this value can be set to -1.)
+         * - For NavIC L1 subframe 3, this value corresponds to the Message Id of the navigation
+         *   message, in the range of 1-63. (Subframe 1 and 2 does not contain a message type id and
+         *   this value can be set to -1.)
          */
         int messageId;
 
@@ -187,8 +199,10 @@
          *
          * - For Beidou CNAV2, the submessage id corresponds to the message type, in the range 1-63.
          *
-         * - For IRNSS L5 C/A, the submessage id corresponds to the subframe number of the
-         *   navigation message, in the range of 1-4.
+         * - For NavIC L5, the submessage id corresponds to the subframe number of the navigation
+         *   message, in the range of 1-4.
+         * - For NavIC L1, the submessage id corresponds to the subframe number of the navigation
+         *   message, in the range of 1-3.
          */
         int submessageId;
 
@@ -196,7 +210,7 @@
          * The data of the reported GNSS message. The bytes (or words) are specified
          * using big endian format (MSB first).
          *
-         * - For GNSS L1 C/A, Beidou D1 & Beidou D2, each subframe contains 10 30-bit
+         * - For GNSS L1 C/A, NavIC L5, Beidou D1 & Beidou D2, each subframe contains 10 30-bit
          *   words. Each word (30 bits) must fit into the last 30 bits in a
          *   4-byte word (skip B31 and B32), with MSB first, for a total of 40
          *   bytes, covering a time period of 6, 6, and 0.6 seconds, respectively.
@@ -228,6 +242,10 @@
          * - For Beidou CNAV2, each subframe consists of 288 data bits, that should be fit into 36
          *   bytes.
          *
+         * - For NavIC L1, subframe #1 consists of 9 data bits that should be fit into 2 bytes (skip
+         *   B10-B16). subframe #2 consists of 600 bits that should be fit into 75 bytes. subframe
+         *   #3 consists of 274 data bits that should be fit into 35 bytes (skip B275-B280).
+         *
          * The data reported here must be the raw data as demodulated by the GNSS receiver, not data
          * received from an external source (i.e. not from a server download.)
          */
diff --git a/gnss/aidl/default/Android.bp b/gnss/aidl/default/Android.bp
index ca5a41f..822e8fc 100644
--- a/gnss/aidl/default/Android.bp
+++ b/gnss/aidl/default/Android.bp
@@ -26,12 +26,7 @@
 cc_binary {
     name: "android.hardware.gnss-service.example",
     relative_install_path: "hw",
-    init_rc: [
-        "gnss-default.rc",
-    ],
-    vintf_fragments: [
-        "gnss-default.xml",
-    ],
+    installable: false, // install APEX instead
     vendor: true,
     cflags: [
         "-Wall",
@@ -50,7 +45,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-V3-ndk",
+        "android.hardware.gnss-V4-ndk",
     ],
     srcs: [
         "AGnssRil.cpp",
@@ -73,3 +68,35 @@
         "android.hardware.gnss@common-default-lib",
     ],
 }
+
+prebuilt_etc {
+    name: "gnss-default.rc",
+    src: "gnss-default.rc",
+    installable: false,
+}
+
+prebuilt_etc {
+    name: "gnss-default.xml",
+    src: "gnss-default.xml",
+    sub_dir: "vintf",
+    installable: false,
+}
+
+apex {
+    name: "com.android.hardware.gnss",
+    manifest: "apex_manifest.json",
+    file_contexts: "apex_file_contexts",
+    key: "com.android.hardware.key",
+    certificate: ":com.android.hardware.certificate",
+    updatable: false,
+    vendor: true,
+
+    binaries: [
+        "android.hardware.gnss-service.example",
+    ],
+    prebuilts: [
+        "gnss-default.rc",
+        "gnss-default.xml",
+        "android.hardware.location.gps.prebuilt.xml", // permission
+    ],
+}
diff --git a/gnss/aidl/default/Gnss.cpp b/gnss/aidl/default/Gnss.cpp
index f1b9cbf..c31f991 100644
--- a/gnss/aidl/default/Gnss.cpp
+++ b/gnss/aidl/default/Gnss.cpp
@@ -115,7 +115,9 @@
     mGnssMeasurementInterface->setLocationEnabled(true);
     this->reportGnssStatusValue(IGnssCallback::GnssStatusValue::SESSION_BEGIN);
     mThread = std::thread([this]() {
-        this->reportSvStatus();
+        if (!mGnssMeasurementEnabled || mMinIntervalMs <= mGnssMeasurementIntervalMs) {
+            this->reportSvStatus();
+        }
         if (!mFirstFixReceived) {
             std::this_thread::sleep_for(std::chrono::milliseconds(TTFF_MILLIS));
             mFirstFixReceived = true;
@@ -124,7 +126,9 @@
             if (!mIsActive) {
                 break;
             }
-            this->reportSvStatus();
+            if (!mGnssMeasurementEnabled || mMinIntervalMs <= mGnssMeasurementIntervalMs) {
+                this->reportSvStatus();
+            }
             this->reportNmea();
 
             auto currentLocation = getLocationFromHW();
@@ -386,4 +390,12 @@
     return ndk::ScopedAStatus::ok();
 }
 
+void Gnss::setGnssMeasurementEnabled(const bool enabled) {
+    mGnssMeasurementEnabled = enabled;
+}
+
+void Gnss::setGnssMeasurementInterval(const long intervalMs) {
+    mGnssMeasurementIntervalMs = intervalMs;
+}
+
 }  // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/Gnss.h b/gnss/aidl/default/Gnss.h
index 00540cd..245d607 100644
--- a/gnss/aidl/default/Gnss.h
+++ b/gnss/aidl/default/Gnss.h
@@ -85,6 +85,8 @@
             override;
 
     void reportSvStatus() const;
+    void setGnssMeasurementEnabled(const bool enabled);
+    void setGnssMeasurementInterval(const long intervalMs);
     std::shared_ptr<GnssConfiguration> mGnssConfiguration;
     std::shared_ptr<GnssPowerIndication> mGnssPowerIndication;
     std::shared_ptr<GnssMeasurementInterface> mGnssMeasurementInterface;
@@ -101,10 +103,12 @@
     static std::shared_ptr<IGnssCallback> sGnssCallback;
 
     std::atomic<long> mMinIntervalMs;
+    std::atomic<long> mGnssMeasurementIntervalMs;
     std::atomic<bool> mIsActive;
     std::atomic<bool> mIsSvStatusActive;
     std::atomic<bool> mIsNmeaActive;
     std::atomic<bool> mFirstFixReceived;
+    std::atomic<bool> mGnssMeasurementEnabled;
     std::thread mThread;
     ::android::hardware::gnss::common::ThreadBlocker mThreadBlocker;
 
diff --git a/gnss/aidl/default/GnssMeasurementInterface.cpp b/gnss/aidl/default/GnssMeasurementInterface.cpp
index aab9e03..f324213 100644
--- a/gnss/aidl/default/GnssMeasurementInterface.cpp
+++ b/gnss/aidl/default/GnssMeasurementInterface.cpp
@@ -35,7 +35,9 @@
 std::shared_ptr<IGnssMeasurementCallback> GnssMeasurementInterface::sCallback = nullptr;
 
 GnssMeasurementInterface::GnssMeasurementInterface()
-    : mIntervalMs(1000), mLocationIntervalMs(1000), mFutures(std::vector<std::future<void>>()) {}
+    : mIntervalMs(1000), mLocationIntervalMs(1000) {
+    mThreads.reserve(2);
+}
 
 GnssMeasurementInterface::~GnssMeasurementInterface() {
     waitForStoppingThreads();
@@ -74,6 +76,7 @@
         stop();
     }
     mIntervalMs = std::max(options.intervalMs, 1000);
+    mGnss->setGnssMeasurementInterval(mIntervalMs);
     start(options.enableCorrVecOutputs, options.enableFullTracking);
 
     return ndk::ScopedAStatus::ok();
@@ -100,12 +103,13 @@
         ALOGD("restarting since measurement has started");
         stop();
     }
-    // Wait for stopping previous thread.
-    waitForStoppingThreads();
 
     mIsActive = true;
-    mThreadBlocker.reset();
-    mThread = std::thread([this, enableCorrVecOutputs, enableFullTracking]() {
+    mGnss->setGnssMeasurementEnabled(true);
+    mThreads.emplace_back(std::thread([this, enableCorrVecOutputs, enableFullTracking]() {
+        waitForStoppingThreads();
+        mThreadBlocker.reset();
+
         int intervalMs;
         do {
             if (!mIsActive) {
@@ -127,22 +131,30 @@
                 auto measurement =
                         Utils::getMockMeasurement(enableCorrVecOutputs, enableFullTracking);
                 this->reportMeasurement(measurement);
-                if (!mLocationEnabled) {
+                if (!mLocationEnabled || mLocationIntervalMs > mIntervalMs) {
                     mGnss->reportSvStatus();
                 }
             }
             intervalMs =
                     (mLocationEnabled) ? std::min(mLocationIntervalMs, mIntervalMs) : mIntervalMs;
         } while (mIsActive && mThreadBlocker.wait_for(std::chrono::milliseconds(intervalMs)));
-    });
+    }));
 }
 
 void GnssMeasurementInterface::stop() {
     ALOGD("stop");
     mIsActive = false;
+    mGnss->setGnssMeasurementEnabled(false);
     mThreadBlocker.notify();
-    if (mThread.joinable()) {
-        mFutures.push_back(std::async(std::launch::async, [this] { mThread.join(); }));
+    for (auto iter = mThreads.begin(); iter != mThreads.end(); ++iter) {
+        if (iter->joinable()) {
+            mFutures.push_back(std::async(std::launch::async, [this, iter] {
+                iter->join();
+                mThreads.erase(iter);
+            }));
+        } else {
+            mThreads.erase(iter);
+        }
     }
 }
 
diff --git a/gnss/aidl/default/GnssMeasurementInterface.h b/gnss/aidl/default/GnssMeasurementInterface.h
index 926a4e7..ea07c9a 100644
--- a/gnss/aidl/default/GnssMeasurementInterface.h
+++ b/gnss/aidl/default/GnssMeasurementInterface.h
@@ -52,7 +52,7 @@
     std::atomic<long> mLocationIntervalMs;
     std::atomic<bool> mIsActive;
     std::atomic<bool> mLocationEnabled;
-    std::thread mThread;
+    std::vector<std::thread> mThreads;
     std::vector<std::future<void>> mFutures;
     ::android::hardware::gnss::common::ThreadBlocker mThreadBlocker;
 
diff --git a/gnss/aidl/default/GnssNavigationMessageInterface.cpp b/gnss/aidl/default/GnssNavigationMessageInterface.cpp
index 75b9624..c262dc6 100644
--- a/gnss/aidl/default/GnssNavigationMessageInterface.cpp
+++ b/gnss/aidl/default/GnssNavigationMessageInterface.cpp
@@ -29,7 +29,9 @@
 
 std::shared_ptr<IGnssNavigationMessageCallback> GnssNavigationMessageInterface::sCallback = nullptr;
 
-GnssNavigationMessageInterface::GnssNavigationMessageInterface() : mMinIntervalMillis(1000) {}
+GnssNavigationMessageInterface::GnssNavigationMessageInterface() : mMinIntervalMillis(1000) {
+    mThreads.reserve(2);
+}
 
 GnssNavigationMessageInterface::~GnssNavigationMessageInterface() {
     waitForStoppingThreads();
@@ -61,11 +63,11 @@
         ALOGD("restarting since nav msg has started");
         stop();
     }
-    // Wait for stopping previous thread.
-    waitForStoppingThreads();
 
     mIsActive = true;
-    mThread = std::thread([this]() {
+    mThreads.emplace_back(std::thread([this]() {
+        waitForStoppingThreads();
+        mThreadBlocker.reset();
         do {
             if (!mIsActive) {
                 break;
@@ -81,15 +83,22 @@
             this->reportMessage(message);
         } while (mIsActive &&
                  mThreadBlocker.wait_for(std::chrono::milliseconds(mMinIntervalMillis)));
-    });
+    }));
 }
 
 void GnssNavigationMessageInterface::stop() {
     ALOGD("stop");
     mIsActive = false;
     mThreadBlocker.notify();
-    if (mThread.joinable()) {
-        mFutures.push_back(std::async(std::launch::async, [this] { mThread.join(); }));
+    for (auto iter = mThreads.begin(); iter != mThreads.end(); ++iter) {
+        if (iter->joinable()) {
+            mFutures.push_back(std::async(std::launch::async, [this, iter] {
+                iter->join();
+                mThreads.erase(iter);
+            }));
+        } else {
+            mThreads.erase(iter);
+        }
     }
 }
 
diff --git a/gnss/aidl/default/GnssNavigationMessageInterface.h b/gnss/aidl/default/GnssNavigationMessageInterface.h
index b335348..e9a7536 100644
--- a/gnss/aidl/default/GnssNavigationMessageInterface.h
+++ b/gnss/aidl/default/GnssNavigationMessageInterface.h
@@ -40,7 +40,7 @@
 
     std::atomic<long> mMinIntervalMillis;
     std::atomic<bool> mIsActive;
-    std::thread mThread;
+    std::vector<std::thread> mThreads;
     std::vector<std::future<void>> mFutures;
     ::android::hardware::gnss::common::ThreadBlocker mThreadBlocker;
 
diff --git a/gnss/aidl/default/apex_file_contexts b/gnss/aidl/default/apex_file_contexts
new file mode 100644
index 0000000..83b01ed
--- /dev/null
+++ b/gnss/aidl/default/apex_file_contexts
@@ -0,0 +1,3 @@
+(/.*)?                                                          u:object_r:vendor_file:s0
+/etc(/.*)?                                                      u:object_r:vendor_configs_file:s0
+/bin/hw/android\.hardware\.gnss-service\.example                u:object_r:hal_gnss_default_exec:s0
diff --git a/gnss/aidl/default/apex_manifest.json b/gnss/aidl/default/apex_manifest.json
new file mode 100644
index 0000000..9b2db23
--- /dev/null
+++ b/gnss/aidl/default/apex_manifest.json
@@ -0,0 +1,4 @@
+{
+    "name": "com.android.hardware.gnss",
+    "version": 1
+}
diff --git a/gnss/aidl/default/gnss-default.rc b/gnss/aidl/default/gnss-default.rc
index fe179c3..d47b3a5 100644
--- a/gnss/aidl/default/gnss-default.rc
+++ b/gnss/aidl/default/gnss-default.rc
@@ -1,4 +1,4 @@
-service vendor.gnss-default /vendor/bin/hw/android.hardware.gnss-service.example
+service vendor.gnss-default /apex/com.android.hardware.gnss/bin/hw/android.hardware.gnss-service.example
     class hal
     user nobody
     group nobody
diff --git a/gnss/aidl/default/gnss-default.xml b/gnss/aidl/default/gnss-default.xml
index 73b841e..c01069e 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>3</version>
+        <version>4</version>
         <interface>
             <name>IGnss</name>
             <instance>default</instance>
diff --git a/gnss/aidl/vts/Android.bp b/gnss/aidl/vts/Android.bp
index 2a09a56..fd1d853 100644
--- a/gnss/aidl/vts/Android.bp
+++ b/gnss/aidl/vts/Android.bp
@@ -51,7 +51,7 @@
         "libbinder",
     ],
     static_libs: [
-        "android.hardware.gnss-V3-cpp",
+        "android.hardware.gnss-V4-cpp",
         "android.hardware.gnss@common-vts-lib",
     ],
     test_suites: [
diff --git a/gnss/aidl/vts/gnss_hal_test_cases.cpp b/gnss/aidl/vts/gnss_hal_test_cases.cpp
index aa8bdfd..9381a0a 100644
--- a/gnss/aidl/vts/gnss_hal_test_cases.cpp
+++ b/gnss/aidl/vts/gnss_hal_test_cases.cpp
@@ -1430,13 +1430,13 @@
         startMeasurementWithInterval(intervals[i], iGnssMeasurement, callback);
 
         std::vector<int> measurementDeltas;
-        std::vector<int> svInfoListTimestampsDeltas;
+        std::vector<int> svInfoListDeltas;
 
         collectMeasurementIntervals(callback, numEvents[i], /* timeoutSeconds= */ 10,
                                     measurementDeltas);
         if (aidl_gnss_hal_->getInterfaceVersion() >= 3) {
-            collectSvInfoListTimestamps(numEvents[i], /* timeoutSeconds= */ 10,
-                                        svInfoListTimestampsDeltas);
+            collectSvInfoListTimestamps(numEvents[i], /* timeoutSeconds= */ 10, svInfoListDeltas);
+            EXPECT_TRUE(aidl_gnss_cb_->sv_info_list_cbq_.size() > 0);
         }
         status = iGnssMeasurement->close();
         ASSERT_TRUE(status.isOk());
@@ -1444,8 +1444,7 @@
         assertMeanAndStdev(intervals[i], measurementDeltas);
 
         if (aidl_gnss_hal_->getInterfaceVersion() >= 3) {
-            assertMeanAndStdev(intervals[i], svInfoListTimestampsDeltas);
-            EXPECT_TRUE(aidl_gnss_cb_->sv_info_list_cbq_.size() > 0);
+            assertMeanAndStdev(intervals[i], svInfoListDeltas);
         }
     }
 }
@@ -1477,13 +1476,25 @@
         auto callback = sp<GnssMeasurementCallbackAidl>::make();
         startMeasurementWithInterval(intervalMs, iGnssMeasurement, callback);
 
-        std::vector<int> deltas;
-        collectMeasurementIntervals(callback, /*numEvents=*/10, /*timeoutSeconds=*/10, deltas);
+        std::vector<int> measurementDeltas;
+        std::vector<int> svInfoListDeltas;
+
+        collectMeasurementIntervals(callback, /*numEvents=*/10, /*timeoutSeconds=*/10,
+                                    measurementDeltas);
+        if (aidl_gnss_hal_->getInterfaceVersion() >= 3) {
+            collectSvInfoListTimestamps(/*numEvents=*/10, /* timeoutSeconds= */ 10,
+                                        svInfoListDeltas);
+            EXPECT_TRUE(aidl_gnss_cb_->sv_info_list_cbq_.size() > 0);
+        }
 
         status = iGnssMeasurement->close();
         ASSERT_TRUE(status.isOk());
 
-        assertMeanAndStdev(locationIntervalMs, deltas);
+        assertMeanAndStdev(locationIntervalMs, measurementDeltas);
+        if (aidl_gnss_hal_->getInterfaceVersion() >= 3) {
+            // Verify the SvStatus interval is 1s (not 2s)
+            assertMeanAndStdev(locationIntervalMs, svInfoListDeltas);
+        }
     }
     StopAndClearLocations();
 }
@@ -1516,16 +1527,37 @@
 
         // Start location and verify the measurements are received at 1Hz
         StartAndCheckFirstLocation(locationIntervalMs, /* lowPowerMode= */ false);
-        std::vector<int> deltas;
-        collectMeasurementIntervals(callback, /*numEvents=*/10, kFirstMeasTimeoutSec, deltas);
-        assertMeanAndStdev(locationIntervalMs, deltas);
+        std::vector<int> measurementDeltas;
+        std::vector<int> svInfoListDeltas;
+        collectMeasurementIntervals(callback, /*numEvents=*/10, kFirstMeasTimeoutSec,
+                                    measurementDeltas);
+        assertMeanAndStdev(locationIntervalMs, measurementDeltas);
+        if (aidl_gnss_hal_->getInterfaceVersion() >= 3) {
+            collectSvInfoListTimestamps(/*numEvents=*/10, /* timeoutSeconds= */ 10,
+                                        svInfoListDeltas);
+            EXPECT_TRUE(aidl_gnss_cb_->sv_info_list_cbq_.size() > 0);
+            // Verify the SvStatus intervals are at 1s interval
+            assertMeanAndStdev(locationIntervalMs, svInfoListDeltas);
+        }
 
         // Stop location request and verify the measurements are received at 2s intervals
         StopAndClearLocations();
-        callback->gnss_data_cbq_.reset();
-        deltas.clear();
-        collectMeasurementIntervals(callback, /*numEvents=*/5, kFirstMeasTimeoutSec, deltas);
-        assertMeanAndStdev(intervalMs, deltas);
+        measurementDeltas.clear();
+        collectMeasurementIntervals(callback, /*numEvents=*/5, kFirstMeasTimeoutSec,
+                                    measurementDeltas);
+        assertMeanAndStdev(intervalMs, measurementDeltas);
+
+        if (aidl_gnss_hal_->getInterfaceVersion() >= 3) {
+            svInfoListDeltas.clear();
+            collectSvInfoListTimestamps(/*numEvents=*/5, /* timeoutSeconds= */ 10,
+                                        svInfoListDeltas);
+            EXPECT_TRUE(aidl_gnss_cb_->sv_info_list_cbq_.size() > 0);
+            // Verify the SvStatus intervals are at 2s interval
+            for (const int& delta : svInfoListDeltas) {
+                ALOGD("svInfoListDelta: %d", delta);
+            }
+            assertMeanAndStdev(intervalMs, svInfoListDeltas);
+        }
 
         status = iGnssMeasurement->close();
         ASSERT_TRUE(status.isOk());
@@ -1587,8 +1619,7 @@
  * TestGnssMeasurementIsFullTracking
  * 1. Start measurement with enableFullTracking=true. Verify the received measurements have
  *    isFullTracking=true.
- * 2. Start measurement with enableFullTracking = false. Verify the received measurements have
- *    isFullTracking=false.
+ * 2. Start measurement with enableFullTracking = false.
  * 3. Do step 1 again.
  */
 TEST_P(GnssHalTest, TestGnssMeasurementIsFullTracking) {
@@ -1675,4 +1706,59 @@
     ASSERT_TRUE(accumulatedDeltaRangeFound);
     status = iGnssMeasurement->close();
     ASSERT_TRUE(status.isOk());
-}
\ No newline at end of file
+}
+
+/*
+ * TestSvStatusIntervals:
+ * 1. start measurement and location with various intervals
+ * 2. verify the SvStatus are received at expected interval
+ */
+TEST_P(GnssHalTest, TestSvStatusIntervals) {
+    if (aidl_gnss_hal_->getInterfaceVersion() <= 2) {
+        return;
+    }
+    ALOGD("TestSvStatusIntervals");
+    sp<IGnssMeasurementInterface> iGnssMeasurement;
+    auto status = aidl_gnss_hal_->getExtensionGnssMeasurement(&iGnssMeasurement);
+    ASSERT_TRUE(status.isOk());
+    ASSERT_TRUE(iGnssMeasurement != nullptr);
+
+    std::vector<int> locationIntervals{1000, 2000, INT_MAX};
+    std::vector<int> measurementIntervals{1000, 2000, INT_MAX};
+
+    for (auto& locationIntervalMs : locationIntervals) {
+        for (auto& measurementIntervalMs : measurementIntervals) {
+            if (locationIntervalMs == INT_MAX && measurementIntervalMs == INT_MAX) {
+                continue;
+            }
+            auto measurementCallback = sp<GnssMeasurementCallbackAidl>::make();
+            // Start measurement
+            if (measurementIntervalMs < INT_MAX) {
+                startMeasurementWithInterval(measurementIntervalMs, iGnssMeasurement,
+                                             measurementCallback);
+            }
+            // Start location
+            if (locationIntervalMs < INT_MAX) {
+                StartAndCheckFirstLocation(locationIntervalMs, /* lowPowerMode= */ false);
+            }
+            ALOGD("location@%d(ms), measurement@%d(ms)", locationIntervalMs, measurementIntervalMs);
+            std::vector<int> svInfoListDeltas;
+            collectSvInfoListTimestamps(/*numEvents=*/5, /* timeoutSeconds= */ 10,
+                                        svInfoListDeltas);
+            EXPECT_TRUE(aidl_gnss_cb_->sv_info_list_cbq_.size() > 0);
+
+            int svStatusInterval = std::min(locationIntervalMs, measurementIntervalMs);
+            assertMeanAndStdev(svStatusInterval, svInfoListDeltas);
+
+            if (locationIntervalMs < INT_MAX) {
+                // Stop location request
+                StopAndClearLocations();
+            }
+            if (measurementIntervalMs < INT_MAX) {
+                // Stop measurement request
+                status = iGnssMeasurement->close();
+                ASSERT_TRUE(status.isOk());
+            }
+        }
+    }
+}
diff --git a/gnss/common/OWNERS b/gnss/common/OWNERS
deleted file mode 100644
index 3ed36da..0000000
--- a/gnss/common/OWNERS
+++ /dev/null
@@ -1,7 +0,0 @@
-wyattriley@google.com
-gomo@google.com
-smalkos@google.com
-yuhany@google.com
-
-# VTS team
-yim@google.com
diff --git a/gnss/common/utils/default/Android.bp b/gnss/common/utils/default/Android.bp
index 4cf17a6..208bc59 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-V3-ndk",
+        "android.hardware.gnss-V4-ndk",
     ],
 }
diff --git a/gnss/common/utils/vts/Android.bp b/gnss/common/utils/vts/Android.bp
index b5325b2..ed5674c 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-V3-cpp",
+        "android.hardware.gnss-V4-cpp",
     ],
     static_libs: [
         "libgtest",
diff --git a/graphics/Android.bp b/graphics/Android.bp
index 2fbcb41..cae5292 100644
--- a/graphics/Android.bp
+++ b/graphics/Android.bp
@@ -39,27 +39,27 @@
 cc_defaults {
     name: "android.hardware.graphics.common-ndk_static",
     static_libs: [
-        "android.hardware.graphics.common-V4-ndk",
+        "android.hardware.graphics.common-V5-ndk",
     ],
 }
 
 cc_defaults {
     name: "android.hardware.graphics.common-ndk_shared",
     shared_libs: [
-        "android.hardware.graphics.common-V4-ndk",
+        "android.hardware.graphics.common-V5-ndk",
     ],
 }
 
 cc_defaults {
     name: "android.hardware.graphics.composer3-ndk_static",
     static_libs: [
-        "android.hardware.graphics.composer3-V2-ndk",
+        "android.hardware.graphics.composer3-V3-ndk",
     ],
 }
 
 cc_defaults {
     name: "android.hardware.graphics.composer3-ndk_shared",
     shared_libs: [
-        "android.hardware.graphics.composer3-V2-ndk",
+        "android.hardware.graphics.composer3-V3-ndk",
     ],
 }
diff --git a/graphics/allocator/aidl/Android.bp b/graphics/allocator/aidl/Android.bp
index a3a2c55..03628b0 100644
--- a/graphics/allocator/aidl/Android.bp
+++ b/graphics/allocator/aidl/Android.bp
@@ -18,7 +18,7 @@
     srcs: ["android/hardware/graphics/allocator/*.aidl"],
     imports: [
         "android.hardware.common-V2",
-        "android.hardware.graphics.common-V4",
+        "android.hardware.graphics.common-V5",
     ],
     stability: "vintf",
     backend: {
@@ -49,7 +49,7 @@
             version: "2",
             imports: [
                 "android.hardware.common-V2",
-                "android.hardware.graphics.common-V4",
+                "android.hardware.graphics.common-V5",
             ],
         },
 
diff --git a/graphics/allocator/aidl/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl b/graphics/allocator/aidl/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl
index 50aa2b7..7194ebe 100644
--- a/graphics/allocator/aidl/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl
+++ b/graphics/allocator/aidl/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl
@@ -23,7 +23,14 @@
 @VintfStability
 parcelable BufferDescriptorInfo {
     /**
-     * The name of the buffer in ASCII. Useful for debugging/tracing.
+     * The name of the buffer in null-terminated ASCII. Useful for debugging/tracing.
+     *
+     * NOTE: While a well behaved client will ensure it passes a null-terminated string
+     *       within the 128-byte limit, the IAllocator service implementation should be
+     *       be defensive against malformed input. As such, it is recommended that
+     *       IAllocator implementations proactively do `name[127] = 0` upon receiving
+     *       an allocation request to enusre that the string is definitely
+     *       null-terminated regardless of what the client sent.
      */
     byte[128] name;
 
diff --git a/graphics/common/aidl/Android.bp b/graphics/common/aidl/Android.bp
index 02334e8..f177a41 100644
--- a/graphics/common/aidl/Android.bp
+++ b/graphics/common/aidl/Android.bp
@@ -15,7 +15,7 @@
         enabled: true,
         support_system_process: true,
     },
-    vndk_use_version: "4",
+    vndk_use_version: "5",
     srcs: [
         "android/hardware/graphics/common/*.aidl",
     ],
@@ -43,7 +43,7 @@
             enabled: true,
         },
     },
-    frozen: true,
+    frozen: false,
     versions_with_info: [
         {
             version: "1",
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/BufferUsage.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/BufferUsage.aidl
index d3ab44f..d42a6d5 100644
--- a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/BufferUsage.aidl
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/BufferUsage.aidl
@@ -35,31 +35,31 @@
 /* @hide */
 @Backing(type="long") @VintfStability
 enum BufferUsage {
-  CPU_READ_MASK = 15,
+  CPU_READ_MASK = 0xf,
   CPU_READ_NEVER = 0,
   CPU_READ_RARELY = 2,
   CPU_READ_OFTEN = 3,
-  CPU_WRITE_MASK = 240,
-  CPU_WRITE_NEVER = 0,
-  CPU_WRITE_RARELY = 32,
-  CPU_WRITE_OFTEN = 48,
-  GPU_TEXTURE = 256,
-  GPU_RENDER_TARGET = 512,
-  COMPOSER_OVERLAY = 2048,
-  COMPOSER_CLIENT_TARGET = 4096,
-  PROTECTED = 16384,
-  COMPOSER_CURSOR = 32768,
-  VIDEO_ENCODER = 65536,
-  CAMERA_OUTPUT = 131072,
-  CAMERA_INPUT = 262144,
-  RENDERSCRIPT = 1048576,
-  VIDEO_DECODER = 4194304,
-  SENSOR_DIRECT_DATA = 8388608,
-  GPU_DATA_BUFFER = 16777216,
-  GPU_CUBE_MAP = 33554432,
-  GPU_MIPMAP_COMPLETE = 67108864,
-  HW_IMAGE_ENCODER = 134217728,
-  FRONT_BUFFER = 4294967296,
-  VENDOR_MASK = -268435456,
-  VENDOR_MASK_HI = -281474976710656,
+  CPU_WRITE_MASK = (0xf << 4) /* 240 */,
+  CPU_WRITE_NEVER = (0 << 4) /* 0 */,
+  CPU_WRITE_RARELY = (2 << 4) /* 32 */,
+  CPU_WRITE_OFTEN = (3 << 4) /* 48 */,
+  GPU_TEXTURE = (1 << 8) /* 256 */,
+  GPU_RENDER_TARGET = (1 << 9) /* 512 */,
+  COMPOSER_OVERLAY = (1 << 11) /* 2048 */,
+  COMPOSER_CLIENT_TARGET = (1 << 12) /* 4096 */,
+  PROTECTED = (1 << 14) /* 16384 */,
+  COMPOSER_CURSOR = (1 << 15) /* 32768 */,
+  VIDEO_ENCODER = (1 << 16) /* 65536 */,
+  CAMERA_OUTPUT = (1 << 17) /* 131072 */,
+  CAMERA_INPUT = (1 << 18) /* 262144 */,
+  RENDERSCRIPT = (1 << 20) /* 1048576 */,
+  VIDEO_DECODER = (1 << 22) /* 4194304 */,
+  SENSOR_DIRECT_DATA = (1 << 23) /* 8388608 */,
+  GPU_DATA_BUFFER = (1 << 24) /* 16777216 */,
+  GPU_CUBE_MAP = (1 << 25) /* 33554432 */,
+  GPU_MIPMAP_COMPLETE = (1 << 26) /* 67108864 */,
+  HW_IMAGE_ENCODER = (1 << 27) /* 134217728 */,
+  FRONT_BUFFER = (1L << 32) /* 4294967296 */,
+  VENDOR_MASK = (0xf << 28) /* -268435456 */,
+  VENDOR_MASK_HI = ((1L * 0xffff) << 48) /* -281474976710656 */,
 }
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/ChromaSiting.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/ChromaSiting.aidl
index b8af644..784fc17 100644
--- a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/ChromaSiting.aidl
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/ChromaSiting.aidl
@@ -39,4 +39,6 @@
   UNKNOWN = 1,
   SITED_INTERSTITIAL = 2,
   COSITED_HORIZONTAL = 3,
+  COSITED_VERTICAL = 4,
+  COSITED_BOTH = 5,
 }
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Dataspace.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Dataspace.aidl
index 563b6c1..6ed5bb2 100644
--- a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Dataspace.aidl
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Dataspace.aidl
@@ -35,65 +35,67 @@
 /* @hide */
 @Backing(type="int") @VintfStability
 enum Dataspace {
-  UNKNOWN = 0,
-  ARBITRARY = 1,
+  UNKNOWN = 0x0,
+  ARBITRARY = 0x1,
   STANDARD_SHIFT = 16,
-  STANDARD_MASK = 4128768,
-  STANDARD_UNSPECIFIED = 0,
-  STANDARD_BT709 = 65536,
-  STANDARD_BT601_625 = 131072,
-  STANDARD_BT601_625_UNADJUSTED = 196608,
-  STANDARD_BT601_525 = 262144,
-  STANDARD_BT601_525_UNADJUSTED = 327680,
-  STANDARD_BT2020 = 393216,
-  STANDARD_BT2020_CONSTANT_LUMINANCE = 458752,
-  STANDARD_BT470M = 524288,
-  STANDARD_FILM = 589824,
-  STANDARD_DCI_P3 = 655360,
-  STANDARD_ADOBE_RGB = 720896,
+  STANDARD_MASK = (63 << 16) /* 4128768 */,
+  STANDARD_UNSPECIFIED = (0 << 16) /* 0 */,
+  STANDARD_BT709 = (1 << 16) /* 65536 */,
+  STANDARD_BT601_625 = (2 << 16) /* 131072 */,
+  STANDARD_BT601_625_UNADJUSTED = (3 << 16) /* 196608 */,
+  STANDARD_BT601_525 = (4 << 16) /* 262144 */,
+  STANDARD_BT601_525_UNADJUSTED = (5 << 16) /* 327680 */,
+  STANDARD_BT2020 = (6 << 16) /* 393216 */,
+  STANDARD_BT2020_CONSTANT_LUMINANCE = (7 << 16) /* 458752 */,
+  STANDARD_BT470M = (8 << 16) /* 524288 */,
+  STANDARD_FILM = (9 << 16) /* 589824 */,
+  STANDARD_DCI_P3 = (10 << 16) /* 655360 */,
+  STANDARD_ADOBE_RGB = (11 << 16) /* 720896 */,
   TRANSFER_SHIFT = 22,
-  TRANSFER_MASK = 130023424,
-  TRANSFER_UNSPECIFIED = 0,
-  TRANSFER_LINEAR = 4194304,
-  TRANSFER_SRGB = 8388608,
-  TRANSFER_SMPTE_170M = 12582912,
-  TRANSFER_GAMMA2_2 = 16777216,
-  TRANSFER_GAMMA2_6 = 20971520,
-  TRANSFER_GAMMA2_8 = 25165824,
-  TRANSFER_ST2084 = 29360128,
-  TRANSFER_HLG = 33554432,
+  TRANSFER_MASK = (31 << 22) /* 130023424 */,
+  TRANSFER_UNSPECIFIED = (0 << 22) /* 0 */,
+  TRANSFER_LINEAR = (1 << 22) /* 4194304 */,
+  TRANSFER_SRGB = (2 << 22) /* 8388608 */,
+  TRANSFER_SMPTE_170M = (3 << 22) /* 12582912 */,
+  TRANSFER_GAMMA2_2 = (4 << 22) /* 16777216 */,
+  TRANSFER_GAMMA2_6 = (5 << 22) /* 20971520 */,
+  TRANSFER_GAMMA2_8 = (6 << 22) /* 25165824 */,
+  TRANSFER_ST2084 = (7 << 22) /* 29360128 */,
+  TRANSFER_HLG = (8 << 22) /* 33554432 */,
   RANGE_SHIFT = 27,
-  RANGE_MASK = 939524096,
-  RANGE_UNSPECIFIED = 0,
-  RANGE_FULL = 134217728,
-  RANGE_LIMITED = 268435456,
-  RANGE_EXTENDED = 402653184,
-  SRGB_LINEAR = 138477568,
-  SCRGB_LINEAR = 406913024,
-  SRGB = 142671872,
-  SCRGB = 411107328,
-  JFIF = 146931712,
-  BT601_625 = 281149440,
-  BT601_525 = 281280512,
-  BT709 = 281083904,
-  DCI_P3_LINEAR = 139067392,
-  DCI_P3 = 155844608,
-  DISPLAY_P3_LINEAR = 139067392,
-  DISPLAY_P3 = 143261696,
-  ADOBE_RGB = 151715840,
-  BT2020_LINEAR = 138805248,
-  BT2020 = 147193856,
-  BT2020_PQ = 163971072,
-  DEPTH = 4096,
-  SENSOR = 4097,
-  BT2020_ITU = 281411584,
-  BT2020_ITU_PQ = 298188800,
-  BT2020_ITU_HLG = 302383104,
-  BT2020_HLG = 168165376,
-  DISPLAY_BT2020 = 142999552,
-  DYNAMIC_DEPTH = 4098,
-  JPEG_APP_SEGMENTS = 4099,
-  HEIF = 4100,
-  JPEG_R = 4101,
-  BT709_FULL_RANGE = 146866176,
+  RANGE_MASK = (7 << 27) /* 939524096 */,
+  RANGE_UNSPECIFIED = (0 << 27) /* 0 */,
+  RANGE_FULL = (1 << 27) /* 134217728 */,
+  RANGE_LIMITED = (2 << 27) /* 268435456 */,
+  RANGE_EXTENDED = (3 << 27) /* 402653184 */,
+  SRGB_LINEAR = (((1 << 16) | (1 << 22)) | (1 << 27)) /* 138477568 */,
+  SCRGB_LINEAR = (((1 << 16) | (1 << 22)) | (3 << 27)) /* 406913024 */,
+  SRGB = (((1 << 16) | (2 << 22)) | (1 << 27)) /* 142671872 */,
+  SCRGB = (((1 << 16) | (2 << 22)) | (3 << 27)) /* 411107328 */,
+  JFIF = (((2 << 16) | (3 << 22)) | (1 << 27)) /* 146931712 */,
+  BT601_625 = (((2 << 16) | (3 << 22)) | (2 << 27)) /* 281149440 */,
+  BT601_525 = (((4 << 16) | (3 << 22)) | (2 << 27)) /* 281280512 */,
+  BT709 = (((1 << 16) | (3 << 22)) | (2 << 27)) /* 281083904 */,
+  DCI_P3_LINEAR = (((10 << 16) | (1 << 22)) | (1 << 27)) /* 139067392 */,
+  DCI_P3 = (((10 << 16) | (5 << 22)) | (1 << 27)) /* 155844608 */,
+  DISPLAY_P3_LINEAR = (((10 << 16) | (1 << 22)) | (1 << 27)) /* 139067392 */,
+  DISPLAY_P3 = (((10 << 16) | (2 << 22)) | (1 << 27)) /* 143261696 */,
+  ADOBE_RGB = (((11 << 16) | (4 << 22)) | (1 << 27)) /* 151715840 */,
+  ADOBE_RGB_LINEAR = (((11 << 16) | (1 << 22)) | (1 << 27)) /* 139132928 */,
+  BT2020_LINEAR = (((6 << 16) | (1 << 22)) | (1 << 27)) /* 138805248 */,
+  BT2020 = (((6 << 16) | (3 << 22)) | (1 << 27)) /* 147193856 */,
+  BT2020_PQ = (((6 << 16) | (7 << 22)) | (1 << 27)) /* 163971072 */,
+  BT2020_LINEAR_EXTENDED = (((6 << 16) | (1 << 22)) | (3 << 27)) /* 407240704 */,
+  DEPTH = 0x1000,
+  SENSOR = 0x1001,
+  BT2020_ITU = (((6 << 16) | (3 << 22)) | (2 << 27)) /* 281411584 */,
+  BT2020_ITU_PQ = (((6 << 16) | (7 << 22)) | (2 << 27)) /* 298188800 */,
+  BT2020_ITU_HLG = (((6 << 16) | (8 << 22)) | (2 << 27)) /* 302383104 */,
+  BT2020_HLG = (((6 << 16) | (8 << 22)) | (1 << 27)) /* 168165376 */,
+  DISPLAY_BT2020 = (((6 << 16) | (2 << 22)) | (1 << 27)) /* 142999552 */,
+  DYNAMIC_DEPTH = 0x1002,
+  JPEG_APP_SEGMENTS = 0x1003,
+  HEIF = 0x1004,
+  JPEG_R = 0x1005,
+  BT709_FULL_RANGE = (((1 << 16) | (3 << 22)) | (1 << 27)) /* 146866176 */,
 }
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/DisplayHotplugEvent.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/DisplayHotplugEvent.aidl
new file mode 100644
index 0000000..63dca0a
--- /dev/null
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/DisplayHotplugEvent.aidl
@@ -0,0 +1,42 @@
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible 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.common;
+@Backing(type="int") @VintfStability
+enum DisplayHotplugEvent {
+  CONNECTED = 0,
+  DISCONNECTED = 1,
+  ERROR_UNKNOWN = (-1) /* -1 */,
+  ERROR_INCOMPATIBLE_CABLE = (-2) /* -2 */,
+  ERROR_TOO_MANY_DISPLAYS = (-3) /* -3 */,
+}
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/HardwareBuffer.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/HardwareBuffer.aidl
index 1817769..0fe9493 100644
--- a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/HardwareBuffer.aidl
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/HardwareBuffer.aidl
@@ -32,7 +32,10 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.graphics.common;
-/* @hide */
+/**
+ * @hide
+ * @deprecated : Use instead android.hardware.HardwareBuffer in frameworks/base
+ */
 @VintfStability
 parcelable HardwareBuffer {
   android.hardware.graphics.common.HardwareBufferDescription description;
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PixelFormat.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PixelFormat.aidl
index 68857e8..ed84a44 100644
--- a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PixelFormat.aidl
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PixelFormat.aidl
@@ -36,36 +36,36 @@
 @Backing(type="int") @VintfStability
 enum PixelFormat {
   UNSPECIFIED = 0,
-  RGBA_8888 = 1,
-  RGBX_8888 = 2,
-  RGB_888 = 3,
-  RGB_565 = 4,
-  BGRA_8888 = 5,
-  YCBCR_422_SP = 16,
-  YCRCB_420_SP = 17,
-  YCBCR_422_I = 20,
-  RGBA_FP16 = 22,
-  RAW16 = 32,
-  BLOB = 33,
-  IMPLEMENTATION_DEFINED = 34,
-  YCBCR_420_888 = 35,
-  RAW_OPAQUE = 36,
-  RAW10 = 37,
-  RAW12 = 38,
-  RGBA_1010102 = 43,
-  Y8 = 538982489,
-  Y16 = 540422489,
-  YV12 = 842094169,
-  DEPTH_16 = 48,
-  DEPTH_24 = 49,
-  DEPTH_24_STENCIL_8 = 50,
-  DEPTH_32F = 51,
-  DEPTH_32F_STENCIL_8 = 52,
-  STENCIL_8 = 53,
-  YCBCR_P010 = 54,
-  HSV_888 = 55,
-  R_8 = 56,
-  R_16_UINT = 57,
-  RG_1616_UINT = 58,
-  RGBA_10101010 = 59,
+  RGBA_8888 = 0x1,
+  RGBX_8888 = 0x2,
+  RGB_888 = 0x3,
+  RGB_565 = 0x4,
+  BGRA_8888 = 0x5,
+  YCBCR_422_SP = 0x10,
+  YCRCB_420_SP = 0x11,
+  YCBCR_422_I = 0x14,
+  RGBA_FP16 = 0x16,
+  RAW16 = 0x20,
+  BLOB = 0x21,
+  IMPLEMENTATION_DEFINED = 0x22,
+  YCBCR_420_888 = 0x23,
+  RAW_OPAQUE = 0x24,
+  RAW10 = 0x25,
+  RAW12 = 0x26,
+  RGBA_1010102 = 0x2B,
+  Y8 = 0x20203859,
+  Y16 = 0x20363159,
+  YV12 = 0x32315659,
+  DEPTH_16 = 0x30,
+  DEPTH_24 = 0x31,
+  DEPTH_24_STENCIL_8 = 0x32,
+  DEPTH_32F = 0x33,
+  DEPTH_32F_STENCIL_8 = 0x34,
+  STENCIL_8 = 0x35,
+  YCBCR_P010 = 0x36,
+  HSV_888 = 0x37,
+  R_8 = 0x38,
+  R_16_UINT = 0x39,
+  RG_1616_UINT = 0x3a,
+  RGBA_10101010 = 0x3b,
 }
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PlaneLayoutComponentType.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PlaneLayoutComponentType.aidl
index 8ba9381..e306751 100644
--- a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PlaneLayoutComponentType.aidl
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PlaneLayoutComponentType.aidl
@@ -35,12 +35,12 @@
 /* @hide */
 @Backing(type="long") @VintfStability
 enum PlaneLayoutComponentType {
-  Y = 1,
-  CB = 2,
-  CR = 4,
-  R = 1024,
-  G = 2048,
-  B = 4096,
-  RAW = 1048576,
-  A = 1073741824,
+  Y = (1 << 0) /* 1 */,
+  CB = (1 << 1) /* 2 */,
+  CR = (1 << 2) /* 4 */,
+  R = (1 << 10) /* 1024 */,
+  G = (1 << 11) /* 2048 */,
+  B = (1 << 12) /* 4096 */,
+  RAW = (1 << 20) /* 1048576 */,
+  A = (1 << 30) /* 1073741824 */,
 }
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Transform.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Transform.aidl
index 986d089..dbed57d 100644
--- a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Transform.aidl
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Transform.aidl
@@ -36,9 +36,9 @@
 @Backing(type="int") @VintfStability
 enum Transform {
   NONE = 0,
-  FLIP_H = 1,
-  FLIP_V = 2,
-  ROT_90 = 4,
-  ROT_180 = 3,
-  ROT_270 = 7,
+  FLIP_H = (1 << 0) /* 1 */,
+  FLIP_V = (1 << 1) /* 2 */,
+  ROT_90 = (1 << 2) /* 4 */,
+  ROT_180 = (FLIP_H | FLIP_V) /* 3 */,
+  ROT_270 = ((FLIP_H | FLIP_V) | ROT_90) /* 7 */,
 }
diff --git a/graphics/common/aidl/android/hardware/graphics/common/BufferUsage.aidl b/graphics/common/aidl/android/hardware/graphics/common/BufferUsage.aidl
index 12bc441..0d1a094 100644
--- a/graphics/common/aidl/android/hardware/graphics/common/BufferUsage.aidl
+++ b/graphics/common/aidl/android/hardware/graphics/common/BufferUsage.aidl
@@ -24,35 +24,47 @@
 @Backing(type="long")
 enum BufferUsage {
     /** bit 0-3 is an enum */
-    CPU_READ_MASK                      = 0xf,
+    CPU_READ_MASK = 0xf,
     /** buffer is never read by CPU */
-    CPU_READ_NEVER                     = 0,
+    CPU_READ_NEVER = 0,
     /** buffer is rarely read by CPU */
-    CPU_READ_RARELY                    = 2,
+    CPU_READ_RARELY = 2,
     /** buffer is often read by CPU */
-    CPU_READ_OFTEN                     = 3,
+    CPU_READ_OFTEN = 3,
 
     /** bit 4-7 is an enum */
-    CPU_WRITE_MASK                     = 0xf << 4,
+    CPU_WRITE_MASK = 0xf << 4,
     /** buffer is never written by CPU */
-    CPU_WRITE_NEVER                    = 0 << 4,
+    CPU_WRITE_NEVER = 0 << 4,
     /** buffer is rarely written by CPU */
-    CPU_WRITE_RARELY                   = 2 << 4,
+    CPU_WRITE_RARELY = 2 << 4,
     /** buffer is often written by CPU */
-    CPU_WRITE_OFTEN                    = 3 << 4,
+    CPU_WRITE_OFTEN = 3 << 4,
 
-    /** buffer is used as a GPU texture */
-    GPU_TEXTURE                        = 1 << 8,
+    /**
+     * Buffer may be used as a GPU texture
+     *
+     * Buffers allocated with this flag must be
+     * texturable both in EGL/GL & Vulkan via
+     * their respective external memory extensions
+     */
+    GPU_TEXTURE = 1 << 8,
 
-    /** buffer is used as a GPU render target */
-    GPU_RENDER_TARGET                  = 1 << 9,
+    /**
+     * Buffer may be used as a GPU render target
+     *
+     * Buffers allocated with this flag must be
+     * renderable both in EGL/GL & Vulkan via
+     * their respective external memory extensions
+     */
+    GPU_RENDER_TARGET = 1 << 9,
 
     /** bit 10 must be zero */
 
     /** buffer is used as a composer HAL overlay layer */
-    COMPOSER_OVERLAY                   = 1 << 11,
+    COMPOSER_OVERLAY = 1 << 11,
     /** buffer is used as a composer HAL client target */
-    COMPOSER_CLIENT_TARGET             = 1 << 12,
+    COMPOSER_CLIENT_TARGET = 1 << 12,
 
     /** bit 13 must be zero */
 
@@ -61,86 +73,86 @@
      * contents (or information derived from the contents) into unprotected
      * memory.
      */
-    PROTECTED                          = 1 << 14,
+    PROTECTED = 1 << 14,
 
     /** buffer is used as a hwcomposer HAL cursor layer */
-    COMPOSER_CURSOR                    = 1 << 15,
+    COMPOSER_CURSOR = 1 << 15,
 
     /** buffer is used as a video encoder input */
-    VIDEO_ENCODER                      = 1 << 16,
+    VIDEO_ENCODER = 1 << 16,
 
     /** buffer is used as a camera HAL output */
-    CAMERA_OUTPUT                      = 1 << 17,
+    CAMERA_OUTPUT = 1 << 17,
 
     /** buffer is used as a camera HAL input */
-    CAMERA_INPUT                       = 1 << 18,
+    CAMERA_INPUT = 1 << 18,
 
     /** bit 19 must be zero */
 
     /** buffer is used as a renderscript allocation */
-    RENDERSCRIPT                       = 1 << 20,
+    RENDERSCRIPT = 1 << 20,
 
     /** bit 21 must be zero */
 
     /** buffer is used as a video decoder output */
-    VIDEO_DECODER                      = 1 << 22,
+    VIDEO_DECODER = 1 << 22,
 
     /** buffer is used as a sensor direct report output */
-    SENSOR_DIRECT_DATA                 = 1 << 23,
+    SENSOR_DIRECT_DATA = 1 << 23,
 
     /**
      * buffer is used as as an OpenGL shader storage or uniform
      * buffer object
      */
-    GPU_DATA_BUFFER                    = 1 << 24,
+    GPU_DATA_BUFFER = 1 << 24,
 
     /** buffer is used as a cube map texture */
-    GPU_CUBE_MAP                       = 1 << 25,
+    GPU_CUBE_MAP = 1 << 25,
 
     /** buffer contains a complete mipmap hierarchy */
-    GPU_MIPMAP_COMPLETE                = 1 << 26,
+    GPU_MIPMAP_COMPLETE = 1 << 26,
 
     /**
      * Buffer is used as input for HEIC encoder.
      */
-    HW_IMAGE_ENCODER                   = 1 << 27,
+    HW_IMAGE_ENCODER = 1 << 27,
 
     /* Bits 28-31 are reserved for vendor usage */
 
     /**
-    * Buffer is used for front-buffer rendering.
-    *
-    * To satisfy an allocation with this usage, the resulting buffer
-    * must operate as equivalent to shared memory for all targets.
-    *
-    * For CPU_USAGE_* other than NEVER, this means the buffer must
-    * "lock in place". The buffers must be directly accessible via mapping.
-    *
-    * For GPU_RENDER_TARGET the buffer must behave equivalent to a
-    * single-buffered EGL surface. For example glFlush must perform
-    * a flush, same as if the default framebuffer was single-buffered.
-    *
-    * For COMPOSER_* the HWC must not perform any caching for this buffer
-    * when submitted for composition. HWCs do not need to do any form
-    * of auto-refresh, and they are allowed to cache composition results between
-    * presents from SF (such as for panel self-refresh), but for any given
-    * present the buffer must be composited from even if it otherwise appears
-    * to be the same as a previous composition.
-    *
-    * If the GPU & HWC supports EGL_SINGLE_BUFFER, then it is recommended that
-    * FRONT_BUFFER usage is supported for the same formats as supported by
-    * EGL_SINGLE_BUFFER. In particular, it is recommended that the following
-    * combination is supported when possible:
-    *    Format = RGBA_8888
-    *    Usage = FRONT_BUFFER | GPU_RENDER_TARGET | COMPOSER_OVERLAY
-    *
-    */
-    FRONT_BUFFER                       = 1L << 32,
+     * Buffer is used for front-buffer rendering.
+     *
+     * To satisfy an allocation with this usage, the resulting buffer
+     * must operate as equivalent to shared memory for all targets.
+     *
+     * For CPU_USAGE_* other than NEVER, this means the buffer must
+     * "lock in place". The buffers must be directly accessible via mapping.
+     *
+     * For GPU_RENDER_TARGET the buffer must behave equivalent to a
+     * single-buffered EGL surface. For example glFlush must perform
+     * a flush, same as if the default framebuffer was single-buffered.
+     *
+     * For COMPOSER_* the HWC must not perform any caching for this buffer
+     * when submitted for composition. HWCs do not need to do any form
+     * of auto-refresh, and they are allowed to cache composition results between
+     * presents from SF (such as for panel self-refresh), but for any given
+     * present the buffer must be composited from even if it otherwise appears
+     * to be the same as a previous composition.
+     *
+     * If the GPU & HWC supports EGL_SINGLE_BUFFER, then it is recommended that
+     * FRONT_BUFFER usage is supported for the same formats as supported by
+     * EGL_SINGLE_BUFFER. In particular, it is recommended that the following
+     * combination is supported when possible:
+     *    Format = RGBA_8888
+     *    Usage = FRONT_BUFFER | GPU_RENDER_TARGET | COMPOSER_OVERLAY
+     *
+     */
+    FRONT_BUFFER = 1L << 32,
 
     /** bits 28-31 are reserved for vendor extensions */
-    VENDOR_MASK                        = 0xf << 28,
+    VENDOR_MASK = 0xf << 28,
 
     /** bits 33-47 must be zero and are reserved for future versions */
     /** bits 48-63 are reserved for vendor extensions */
-    VENDOR_MASK_HI                     = (1L * 0xffff) << 48,
+    VENDOR_MASK_HI = (1L * 0xffff) << 48,
 }
diff --git a/graphics/common/aidl/android/hardware/graphics/common/ChromaSiting.aidl b/graphics/common/aidl/android/hardware/graphics/common/ChromaSiting.aidl
index ac44853..7da45da 100644
--- a/graphics/common/aidl/android/hardware/graphics/common/ChromaSiting.aidl
+++ b/graphics/common/aidl/android/hardware/graphics/common/ChromaSiting.aidl
@@ -37,4 +37,12 @@
      * Cb and Cr are vertically sited interstitially.
      * This is used by 4:2:0 for MPEG-2 frame pictures. */
     COSITED_HORIZONTAL = 3,
+
+    /* Cb and Cr are horizontally sited interstitially with a luma sample.
+     * Cb and Cr are vertically sited coincident. */
+    COSITED_VERTICAL = 4,
+
+    /* Cb and Cr are both horizontally & vertically sited coincident
+     * with a luma sample. */
+    COSITED_BOTH = 5,
 }
diff --git a/graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl b/graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl
index 3ff0a65..79737eb 100644
--- a/graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl
+++ b/graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl
@@ -23,11 +23,26 @@
     /**
      * Default-assumption data space, when not explicitly specified.
      *
-     * It is safest to assume the buffer is an image with sRGB primaries and
-     * encoding ranges, but the consumer and/or the producer of the data may
-     * simply be using defaults. No automatic gamma transform should be
-     * expected, except for a possible display gamma transform when drawn to a
-     * screen.
+     * IAllocator implementations must not assume a particular dataspace interpretation when
+     * allocating a buffer. That is, the dataspace stored on a buffer's metadata must
+     * explicitly be UNKNOWN at the time of allocation. All other vendor implementations (for
+     * example, IComposer) are suggested to assume that the buffer is an image that conforms
+     * to the recommendations outlined by STANDARD_UNSPECIFIED, TRANSFER_UNSPECIFIED, and
+     * RANGE_UNSPECIFIED in order to avoid obviously-broken behavior.
+     *
+     * This means:
+     * - RGB buffers may be assumed to follow sRGB (IEC 61966-2.1)
+     * - YCbCr buffers smaller than 720p may be assumed to follow BT. 601-7
+     * - YCbCr buffers at least 720p may be assumed to follow BT. 709-6
+     * - Y buffers are full range with an undefined transfer and primaries
+     * - All other buffer formats may be treated in an implementation-defined manner
+     *
+     * It is the framework's - and application's - responsibility to communicate
+     * an accurate dataspace for any buffers throughout the system to guarantee
+     * well-defined behavior. For the framework, this means translating UNKNOWN
+     * dataspaces to a chosen default, and setting gralloc metadata on the buffer
+     * accordingly. For the application, this means signaling a defined dataspace
+     * to any framework apis.
      */
     UNKNOWN = 0x0,
 
@@ -544,6 +559,13 @@
     ADOBE_RGB = 11 << 16 | 4 << 22 | 1 << 27, // STANDARD_ADOBE_RGB | TRANSFER_GAMMA2_2 | RANGE_FULL
 
     /**
+     * Adobe RGB LINEAR
+     *
+     * Use full range, linear transfer and Adobe RGB primaries
+     */
+    ADOBE_RGB_LINEAR = 11 << 16 | 1 << 22 | 1 << 27, // STANDARD_ADOBE_RGB | TRANSFER_LINEAR | RANGE_FULL
+
+    /**
      * ITU-R Recommendation 2020 (BT.2020)
      *
      * Ultra High-definition television
@@ -571,6 +593,15 @@
     BT2020_PQ = 6 << 16 | 7 << 22 | 1 << 27, // STANDARD_BT2020 | TRANSFER_ST2084 | RANGE_FULL
 
     /**
+     * ITU-R Recommendation 2020 (BT.2020)
+     *
+     * Ultra High-definition television
+     *
+     * Use extended range, linear transfer and BT2020 standard
+     */
+    BT2020_LINEAR_EXTENDED = 6 << 16 | 1 << 22 | 3 << 27, // STANDARD_BT2020 | TRANSFER_LINEAR | RANGE_EXTENDED
+
+    /**
      * Data spaces for non-color formats
      */
 
diff --git a/graphics/common/aidl/android/hardware/graphics/common/DisplayHotplugEvent.aidl b/graphics/common/aidl/android/hardware/graphics/common/DisplayHotplugEvent.aidl
new file mode 100644
index 0000000..b35ada5
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/DisplayHotplugEvent.aidl
@@ -0,0 +1,46 @@
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.common;
+
+/**
+ * Display hotplug events through onHotplugEvent callback.
+ */
+@VintfStability
+@Backing(type="int")
+enum DisplayHotplugEvent {
+    /**
+     * Display is successfully connected.
+     * Connected may be called more than once and the behavior of subsequent
+     * calls is that SurfaceFlinger queries the display properties again.
+     */
+    CONNECTED = 0,
+
+    /** Display is successfully disconnected */
+    DISCONNECTED = 1,
+
+    /** Display is plugged in, but an unknown error occurred */
+    ERROR_UNKNOWN = -1,
+
+    /** Display is plugged in, but incompatible cable error detected */
+    ERROR_INCOMPATIBLE_CABLE = -2,
+
+    /**
+     * Display is plugged in, but exceeds the max number of
+     * displays that can be simultaneously connected
+     */
+    ERROR_TOO_MANY_DISPLAYS = -3,
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/HardwareBuffer.aidl b/graphics/common/aidl/android/hardware/graphics/common/HardwareBuffer.aidl
index 50306dc..ac95b1c 100644
--- a/graphics/common/aidl/android/hardware/graphics/common/HardwareBuffer.aidl
+++ b/graphics/common/aidl/android/hardware/graphics/common/HardwareBuffer.aidl
@@ -20,11 +20,13 @@
 import android.hardware.graphics.common.HardwareBufferDescription;
 
 /**
- * Stable AIDL counterpart of AHardwareBuffer.
+ * [Deprecated] Stable AIDL counterpart of AHardwareBuffer.
  *
- * @note This is different from the public HardwareBuffer.
- * @sa +ndk libnativewindow#AHardwareBuffer
+ * @note This is different from the public HardwareBuffer. As the public
+         HardwareBuffer now supports being used in stable-aidl interfaces,
+         that is strongly preferred for new usages.
  * @hide
+ * @deprecated: Use instead android.hardware.HardwareBuffer in frameworks/base
  */
 @VintfStability
 parcelable HardwareBuffer {
diff --git a/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h b/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h
index 499d3b9..336d15d 100644
--- a/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h
+++ b/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h
@@ -679,6 +679,10 @@
 
     uint32_t read() { return mData[mDataRead++]; }
 
+    bool isReadSizeValid(uint32_t size) const {
+        return mDataRead * sizeof(uint32_t) + size <= mDataSize;
+    }
+
     int32_t readSigned() {
         int32_t val;
         memcpy(&val, &mData[mDataRead++], sizeof(val));
@@ -760,7 +764,7 @@
     std::unique_ptr<uint32_t[]> mData;
     uint32_t mDataRead;
 
-   private:
+  private:
     std::unique_ptr<CommandQueueType> mQueue;
     uint32_t mDataMaxSize;
 
diff --git a/graphics/composer/2.1/utils/resources/Android.bp b/graphics/composer/2.1/utils/resources/Android.bp
index 9eb23fa..4052003 100644
--- a/graphics/composer/2.1/utils/resources/Android.bp
+++ b/graphics/composer/2.1/utils/resources/Android.bp
@@ -29,20 +29,15 @@
     vendor_available: true,
     shared_libs: [
         "android.hardware.graphics.composer@2.1",
-        "android.hardware.graphics.mapper@2.0",
-        "android.hardware.graphics.mapper@3.0",
-        "android.hardware.graphics.mapper@4.0",
         "libcutils",
         "libhardware", // TODO remove hwcomposer2.h dependency
         "libhidlbase",
         "liblog",
+        "libui",
         "libutils",
     ],
     export_shared_lib_headers: [
         "android.hardware.graphics.composer@2.1",
-        "android.hardware.graphics.mapper@2.0",
-        "android.hardware.graphics.mapper@3.0",
-        "android.hardware.graphics.mapper@4.0",
         "libhardware",
         "libhidlbase",
         "liblog",
diff --git a/graphics/composer/2.1/utils/resources/ComposerResources.cpp b/graphics/composer/2.1/utils/resources/ComposerResources.cpp
index e52bf71..80bfb7a 100644
--- a/graphics/composer/2.1/utils/resources/ComposerResources.cpp
+++ b/graphics/composer/2.1/utils/resources/ComposerResources.cpp
@@ -18,6 +18,8 @@
 
 #include "composer-resources/2.1/ComposerResources.h"
 
+#include <ui/GraphicBufferMapper.h>
+
 namespace android {
 namespace hardware {
 namespace graphics {
@@ -25,23 +27,10 @@
 namespace V2_1 {
 namespace hal {
 
+ComposerHandleImporter::ComposerHandleImporter() : mMapper{GraphicBufferMapper::get()} {}
+
 bool ComposerHandleImporter::init() {
-    mMapper4 = mapper::V4_0::IMapper::getService();
-    if (mMapper4) {
-        return true;
-    }
-    ALOGI_IF(!mMapper4, "failed to get mapper 4.0 service, falling back to mapper 3.0");
-
-    mMapper3 = mapper::V3_0::IMapper::getService();
-    if (mMapper3) {
-        return true;
-    }
-    ALOGI_IF(!mMapper3, "failed to get mapper 3.0 service, falling back to mapper 2.0");
-
-    mMapper2 = mapper::V2_0::IMapper::getService();
-    ALOGE_IF(!mMapper2, "failed to get mapper 2.0 service");
-
-    return mMapper2 != nullptr;
+    return true;
 }
 
 Error ComposerHandleImporter::importBuffer(const native_handle_t* rawHandle,
@@ -51,51 +40,17 @@
         return Error::NONE;
     }
 
-    const native_handle_t* bufferHandle;
-    if (mMapper2) {
-        mapper::V2_0::Error error;
-        mMapper2->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBufferHandle) {
-            error = tmpError;
-            bufferHandle = static_cast<const native_handle_t*>(tmpBufferHandle);
-        });
-        if (error != mapper::V2_0::Error::NONE) {
-            return Error::NO_RESOURCES;
-        }
+    status_t status = mMapper.importBufferNoValidate(rawHandle, outBufferHandle);
+    if (status == STATUS_OK) {
+        return Error::NONE;
+    } else {
+        return Error::NO_RESOURCES;
     }
-    if (mMapper3) {
-        mapper::V3_0::Error error;
-        mMapper3->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBufferHandle) {
-            error = tmpError;
-            bufferHandle = static_cast<const native_handle_t*>(tmpBufferHandle);
-        });
-        if (error != mapper::V3_0::Error::NONE) {
-            return Error::NO_RESOURCES;
-        }
-    }
-    if (mMapper4) {
-        mapper::V4_0::Error error;
-        mMapper4->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBufferHandle) {
-            error = tmpError;
-            bufferHandle = static_cast<const native_handle_t*>(tmpBufferHandle);
-        });
-        if (error != mapper::V4_0::Error::NONE) {
-            return Error::NO_RESOURCES;
-        }
-    }
-
-    *outBufferHandle = bufferHandle;
-    return Error::NONE;
 }
 
 void ComposerHandleImporter::freeBuffer(const native_handle_t* bufferHandle) {
     if (bufferHandle) {
-        if (mMapper2) {
-            mMapper2->freeBuffer(static_cast<void*>(const_cast<native_handle_t*>(bufferHandle)));
-        } else if (mMapper3) {
-            mMapper3->freeBuffer(static_cast<void*>(const_cast<native_handle_t*>(bufferHandle)));
-        } else if (mMapper4) {
-            mMapper4->freeBuffer(static_cast<void*>(const_cast<native_handle_t*>(bufferHandle)));
-        }
+        mMapper.freeBuffer(bufferHandle);
     }
 }
 
diff --git a/graphics/composer/2.1/utils/resources/include/composer-resources/2.1/ComposerResources.h b/graphics/composer/2.1/utils/resources/include/composer-resources/2.1/ComposerResources.h
index de78a59..9838118 100644
--- a/graphics/composer/2.1/utils/resources/include/composer-resources/2.1/ComposerResources.h
+++ b/graphics/composer/2.1/utils/resources/include/composer-resources/2.1/ComposerResources.h
@@ -27,12 +27,10 @@
 
 #include <android/hardware/graphics/composer/2.1/types.h>
 
-#include <android/hardware/graphics/mapper/2.0/IMapper.h>
-#include <android/hardware/graphics/mapper/3.0/IMapper.h>
-#include <android/hardware/graphics/mapper/4.0/IMapper.h>
 #include <log/log.h>
 
 namespace android {
+class GraphicBufferMapper;
 namespace hardware {
 namespace graphics {
 namespace composer {
@@ -42,6 +40,7 @@
 // wrapper for IMapper to import buffers and sideband streams
 class ComposerHandleImporter {
   public:
+    ComposerHandleImporter();
     bool init();
 
     Error importBuffer(const native_handle_t* rawHandle, const native_handle_t** outBufferHandle);
@@ -50,9 +49,7 @@
     void freeStream(const native_handle_t* streamHandle);
 
   private:
-    sp<mapper::V2_0::IMapper> mMapper2;
-    sp<mapper::V3_0::IMapper> mMapper3;
-    sp<mapper::V4_0::IMapper> mMapper4;
+    GraphicBufferMapper& mMapper;
 };
 
 class ComposerHandleCache {
diff --git a/graphics/composer/2.1/utils/vts/Android.bp b/graphics/composer/2.1/utils/vts/Android.bp
index 7b6a0e6..3bc127f 100644
--- a/graphics/composer/2.1/utils/vts/Android.bp
+++ b/graphics/composer/2.1/utils/vts/Android.bp
@@ -26,7 +26,6 @@
 cc_library_static {
     name: "android.hardware.graphics.composer@2.1-vts",
     defaults: [
-        "android.hardware.graphics.allocator-ndk_static",
         "hidl_defaults",
     ],
     srcs: [
@@ -34,18 +33,15 @@
         "GraphicsComposerCallback.cpp",
         "TestCommandReader.cpp",
     ],
+    shared_libs: [
+        "libui",
+    ],
     static_libs: [
         "android.hardware.graphics.composer@2.1",
-        "android.hardware.graphics.mapper@2.0-vts",
-        "android.hardware.graphics.mapper@3.0-vts",
-        "android.hardware.graphics.mapper@4.0-vts",
         "libgtest",
     ],
     export_static_lib_headers: [
         "android.hardware.graphics.composer@2.1",
-        "android.hardware.graphics.mapper@2.0-vts",
-        "android.hardware.graphics.mapper@3.0-vts",
-        "android.hardware.graphics.mapper@4.0-vts",
     ],
     header_libs: [
         "android.hardware.graphics.composer@2.1-command-buffer",
diff --git a/graphics/composer/2.1/utils/vts/ComposerVts.cpp b/graphics/composer/2.1/utils/vts/ComposerVts.cpp
index 4603dd1..8b89784 100644
--- a/graphics/composer/2.1/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.1/utils/vts/ComposerVts.cpp
@@ -308,113 +308,6 @@
     writer->reset();
 }
 
-NativeHandleWrapper::~NativeHandleWrapper() {
-    if (mHandle) {
-        mGralloc.freeBuffer(mHandle);
-    }
-}
-
-Gralloc::Gralloc() {
-    [this] {
-        ASSERT_NO_FATAL_FAILURE(mGralloc4 = std::make_shared<Gralloc4>(
-                                        /*aidlAllocatorServiceName*/ IAllocator::descriptor +
-                                                std::string("/default"),
-                                        /*hidlAllocatorServiceName*/ "default",
-                                        /*mapperServiceName*/ "default",
-                                        /*errOnFailure=*/false));
-        if (!mGralloc4->hasAllocator() || mGralloc4->getMapper() == nullptr) {
-            mGralloc4 = nullptr;
-            ASSERT_NO_FATAL_FAILURE(mGralloc3 = std::make_shared<Gralloc3>("default", "default",
-                                                                           /*errOnFailure=*/false));
-            if (mGralloc3->getAllocator() == nullptr || mGralloc3->getMapper() == nullptr) {
-                mGralloc3 = nullptr;
-                ASSERT_NO_FATAL_FAILURE(mGralloc2 = std::make_shared<Gralloc2>());
-            }
-        }
-    }();
-}
-
-const NativeHandleWrapper Gralloc::allocate(uint32_t width, uint32_t height, uint32_t layerCount,
-                                            PixelFormat format, uint64_t usage, bool import,
-                                            uint32_t* outStride) {
-    const native_handle_t* handle;
-    if (mGralloc4) {
-        IMapper4::BufferDescriptorInfo info{};
-        info.width = width;
-        info.height = height;
-        info.layerCount = layerCount;
-        info.format = static_cast<android::hardware::graphics::common::V1_2::PixelFormat>(format);
-        info.usage = usage;
-        handle = mGralloc4->allocate(info, import, outStride);
-    } else if (mGralloc3) {
-        IMapper3::BufferDescriptorInfo info{};
-        info.width = width;
-        info.height = height;
-        info.layerCount = layerCount;
-        info.format = static_cast<android::hardware::graphics::common::V1_2::PixelFormat>(format);
-        info.usage = usage;
-        handle = mGralloc3->allocate(info, import, outStride);
-    } else {
-        IMapper2::BufferDescriptorInfo info{};
-        info.width = width;
-        info.height = height;
-        info.layerCount = layerCount;
-        info.format = format;
-        info.usage = usage;
-        handle = mGralloc2->allocate(info, import, outStride);
-    }
-    return NativeHandleWrapper(*this, handle);
-}
-
-void* Gralloc::lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
-                    const AccessRegion& accessRegionRect, int acquireFence) {
-    if (mGralloc4) {
-        IMapper4::Rect accessRegion;
-        accessRegion.left = accessRegionRect.left;
-        accessRegion.top = accessRegionRect.top;
-        accessRegion.width = accessRegionRect.width;
-        accessRegion.height = accessRegionRect.height;
-        return mGralloc4->lock(bufferHandle, cpuUsage, accessRegion, acquireFence);
-    } else if (mGralloc3) {
-        IMapper3::Rect accessRegion;
-        accessRegion.left = accessRegionRect.left;
-        accessRegion.top = accessRegionRect.top;
-        accessRegion.width = accessRegionRect.width;
-        accessRegion.height = accessRegionRect.height;
-        int32_t bytesPerPixel;
-        int32_t bytesPerStride;
-        return mGralloc3->lock(bufferHandle, cpuUsage, accessRegion, acquireFence, &bytesPerPixel,
-                               &bytesPerStride);
-    } else {
-        IMapper2::Rect accessRegion;
-        accessRegion.left = accessRegionRect.left;
-        accessRegion.top = accessRegionRect.top;
-        accessRegion.width = accessRegionRect.width;
-        accessRegion.height = accessRegionRect.height;
-        return mGralloc2->lock(bufferHandle, cpuUsage, accessRegion, acquireFence);
-    }
-}
-
-int Gralloc::unlock(const native_handle_t* bufferHandle) {
-    if (mGralloc4) {
-        return mGralloc4->unlock(bufferHandle);
-    } else if (mGralloc3) {
-        return mGralloc3->unlock(bufferHandle);
-    } else {
-        return mGralloc2->unlock(bufferHandle);
-    }
-}
-
-void Gralloc::freeBuffer(const native_handle_t* bufferHandle) {
-    if (mGralloc4) {
-        mGralloc4->freeBuffer(bufferHandle);
-    } else if (mGralloc3) {
-        mGralloc3->freeBuffer(bufferHandle);
-    } else {
-        mGralloc2->freeBuffer(bufferHandle);
-    }
-}
-
 }  // namespace vts
 }  // namespace V2_1
 }  // namespace composer
diff --git a/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h
index f8ea661..c0aacb5 100644
--- a/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h
+++ b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h
@@ -25,9 +25,6 @@
 #include <android/hardware/graphics/composer/2.1/IComposer.h>
 #include <composer-command-buffer/2.1/ComposerCommandBuffer.h>
 #include <composer-vts/2.1/TestCommandReader.h>
-#include <mapper-vts/2.0/MapperVts.h>
-#include <mapper-vts/3.0/MapperVts.h>
-#include <mapper-vts/4.0/MapperVts.h>
 #include <utils/StrongPointer.h>
 
 #include "gtest/gtest.h"
@@ -43,13 +40,6 @@
 using android::hardware::graphics::common::V1_0::Dataspace;
 using android::hardware::graphics::common::V1_0::Hdr;
 using android::hardware::graphics::common::V1_0::PixelFormat;
-using IMapper2 = android::hardware::graphics::mapper::V2_0::IMapper;
-using IMapper3 = android::hardware::graphics::mapper::V3_0::IMapper;
-using IMapper4 = android::hardware::graphics::mapper::V4_0::IMapper;
-using Gralloc2 = android::hardware::graphics::mapper::V2_0::vts::Gralloc;
-using Gralloc3 = android::hardware::graphics::mapper::V3_0::vts::Gralloc;
-using Gralloc4 = android::hardware::graphics::mapper::V4_0::vts::Gralloc;
-using IAllocator = aidl::android::hardware::graphics::allocator::IAllocator;
 
 class ComposerClient;
 
@@ -129,52 +119,6 @@
     const sp<IComposerClient> mClient;
 };
 
-class AccessRegion {
-  public:
-    int32_t left;
-    int32_t top;
-    int32_t width;
-    int32_t height;
-};
-
-class Gralloc;
-
-// RAII wrapper around native_handle_t*
-class NativeHandleWrapper {
-  public:
-    NativeHandleWrapper(Gralloc& gralloc, const native_handle_t* handle)
-        : mGralloc(gralloc), mHandle(handle) {}
-
-    ~NativeHandleWrapper();
-
-    const native_handle_t* get() { return mHandle; }
-
-  private:
-    Gralloc& mGralloc;
-    const native_handle_t* mHandle;
-};
-
-class Gralloc {
-  public:
-    explicit Gralloc();
-
-    const NativeHandleWrapper allocate(uint32_t width, uint32_t height, uint32_t layerCount,
-                                       PixelFormat format, uint64_t usage, bool import = true,
-                                       uint32_t* outStride = nullptr);
-
-    void* lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
-               const AccessRegion& accessRegionRect, int acquireFence);
-
-    int unlock(const native_handle_t* bufferHandle);
-
-    void freeBuffer(const native_handle_t* bufferHandle);
-
-  protected:
-    std::shared_ptr<Gralloc2> mGralloc2 = nullptr;
-    std::shared_ptr<Gralloc3> mGralloc3 = nullptr;
-    std::shared_ptr<Gralloc4> mGralloc4 = nullptr;
-};
-
 }  // namespace vts
 }  // namespace V2_1
 }  // namespace composer
diff --git a/graphics/composer/2.1/vts/functional/Android.bp b/graphics/composer/2.1/vts/functional/Android.bp
index 0f6d7e8..0706341 100644
--- a/graphics/composer/2.1/vts/functional/Android.bp
+++ b/graphics/composer/2.1/vts/functional/Android.bp
@@ -27,7 +27,6 @@
     name: "VtsHalGraphicsComposerV2_1TargetTest",
     defaults: [
         "VtsHalTargetTestDefaults",
-        "android.hardware.graphics.allocator-ndk_static",
     ],
     tidy_timeout_srcs: ["VtsHalGraphicsComposerV2_1TargetTest.cpp"],
     srcs: ["VtsHalGraphicsComposerV2_1TargetTest.cpp"],
@@ -38,22 +37,12 @@
         "libbinder_ndk",
         "libfmq",
         "libsync",
+        "libui",
         "android.hardware.common-V2-ndk",
-        "android.hardware.graphics.mapper@2.0",
-        "android.hardware.graphics.mapper@2.1",
-        "android.hardware.graphics.mapper@3.0",
-        "android.hardware.graphics.mapper@4.0",
     ],
     static_libs: [
-        "android.hardware.graphics.allocator@2.0",
-        "android.hardware.graphics.allocator@3.0",
-        "android.hardware.graphics.allocator@4.0",
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.composer@2.1-vts",
-        "android.hardware.graphics.mapper@2.0-vts",
-        "android.hardware.graphics.mapper@2.1-vts",
-        "android.hardware.graphics.mapper@3.0-vts",
-        "android.hardware.graphics.mapper@4.0-vts",
         "libaidlcommonsupport",
     ],
     header_libs: [
diff --git a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
index 9444d89..a1992b9 100644
--- a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
+++ b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
@@ -25,9 +25,7 @@
 #include <hardware/hwcomposer2.h>
 #include <hidl/GtestPrinter.h>
 #include <hidl/ServiceManagement.h>
-#include <mapper-vts/2.0/MapperVts.h>
-#include <mapper-vts/3.0/MapperVts.h>
-#include <mapper-vts/4.0/MapperVts.h>
+#include <ui/GraphicBuffer.h>
 
 #include <unistd.h>
 
@@ -52,7 +50,6 @@
 using android::hardware::graphics::common::V1_0::Dataspace;
 using android::hardware::graphics::common::V1_0::PixelFormat;
 using android::hardware::graphics::common::V1_0::Transform;
-using GrallocError = android::hardware::graphics::mapper::V2_0::Error;
 
 class GraphicsComposerHidlTest : public ::testing::TestWithParam<std::string> {
   protected:
@@ -318,6 +315,8 @@
  * required client targets.
  */
 TEST_P(GraphicsComposerHidlTest, GetClientTargetSupport) {
+    ASSERT_NO_FATAL_FAILURE(
+            mComposerClient->setPowerMode(mPrimaryDisplay, IComposerClient::PowerMode::ON));
     std::vector<Config> configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay);
     for (auto config : configs) {
         int32_t width = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config,
@@ -651,7 +650,6 @@
     void SetUp() override {
         ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::SetUp());
 
-        ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>());
         Config activeConfig = mComposerClient->getActiveConfig(mPrimaryDisplay);
         mDisplayWidth = mComposerClient->getDisplayAttribute(mPrimaryDisplay, activeConfig,
                                                              IComposerClient::Attribute::WIDTH);
@@ -666,13 +664,17 @@
         ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::TearDown());
     }
 
-    NativeHandleWrapper allocate() { return allocate(mDisplayWidth, mDisplayHeight); }
+    sp<GraphicBuffer> allocate() { return allocate(mDisplayWidth, mDisplayHeight); }
 
-    NativeHandleWrapper allocate(uint32_t width, uint32_t height) {
-        uint64_t usage =
+    sp<GraphicBuffer> allocate(int32_t width, int32_t height) {
+        auto result = sp<GraphicBuffer>::make(
+                width, height, static_cast<int32_t>(PixelFormat::RGBA_8888), /*layerCount*/ 1,
                 static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN |
-                                      BufferUsage::COMPOSER_OVERLAY);
-        return mGralloc->allocate(width, height, 1, PixelFormat::RGBA_8888, usage);
+                                      BufferUsage::COMPOSER_OVERLAY));
+        if (result->initCheck() != STATUS_OK) {
+            return nullptr;
+        }
+        return result;
     }
 
     void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); }
@@ -681,9 +683,6 @@
     std::unique_ptr<TestCommandReader> mReader;
     int32_t mDisplayWidth;
     int32_t mDisplayHeight;
-
-   private:
-     std::unique_ptr<Gralloc> mGralloc;
 };
 
 /**
@@ -729,11 +728,11 @@
         display = mComposerClient->createVirtualDisplay(64, 64, PixelFormat::IMPLEMENTATION_DEFINED,
                                                         kBufferSlotCount, &format));
 
-    std::unique_ptr<NativeHandleWrapper> handle;
-    ASSERT_NO_FATAL_FAILURE(handle.reset(new NativeHandleWrapper(allocate())));
+    auto handle = allocate();
+    ASSERT_TRUE(handle);
 
     mWriter->selectDisplay(display);
-    mWriter->setOutputBuffer(0, handle->get(), -1);
+    mWriter->setOutputBuffer(0, handle->handle, -1);
     execute();
 }
 
@@ -802,7 +801,7 @@
     mWriter->setLayerZOrder(10);
     mWriter->setLayerBlendMode(IComposerClient::BlendMode::NONE);
     mWriter->setLayerSurfaceDamage(std::vector<IComposerClient::Rect>(1, displayFrame));
-    mWriter->setLayerBuffer(0, handle.get(), -1);
+    mWriter->setLayerBuffer(0, handle->handle, -1);
     mWriter->setLayerDataspace(Dataspace::UNKNOWN);
 
     mWriter->validateDisplay();
@@ -820,7 +819,7 @@
     mWriter->selectLayer(layer);
     auto handle2 = allocate();
     ASSERT_NE(nullptr, handle2.get());
-    mWriter->setLayerBuffer(0, handle2.get(), -1);
+    mWriter->setLayerBuffer(0, handle2->handle, -1);
     mWriter->setLayerSurfaceDamage(std::vector<IComposerClient::Rect>(1, {0, 0, 10, 10}));
     mWriter->presentDisplay();
     execute();
@@ -840,7 +839,7 @@
 
     mWriter->selectDisplay(mPrimaryDisplay);
     mWriter->selectLayer(layer);
-    mWriter->setLayerBuffer(0, handle.get(), -1);
+    mWriter->setLayerBuffer(0, handle->handle, -1);
     mWriter->setLayerCompositionType(IComposerClient::Composition::CURSOR);
     mWriter->setLayerDisplayFrame(displayFrame);
     mWriter->setLayerPlaneAlpha(1);
@@ -881,7 +880,7 @@
 
     mWriter->selectDisplay(mPrimaryDisplay);
     mWriter->selectLayer(layer);
-    mWriter->setLayerBuffer(0, handle.get(), -1);
+    mWriter->setLayerBuffer(0, handle->handle, -1);
     execute();
 }
 
@@ -905,7 +904,7 @@
     mWriter->selectLayer(layer);
     mWriter->setLayerCompositionType(IComposerClient::Composition::DEVICE);
     mWriter->setLayerDisplayFrame(displayFrame);
-    mWriter->setLayerBuffer(0, handle1.get(), -1);
+    mWriter->setLayerBuffer(0, handle1->handle, -1);
     mWriter->setLayerDataspace(Dataspace::UNKNOWN);
     mWriter->validateDisplay();
     execute();
@@ -928,7 +927,7 @@
     mWriter->selectLayer(layer);
     mWriter->setLayerCompositionType(IComposerClient::Composition::DEVICE);
     mWriter->setLayerDisplayFrame(displayFrame);
-    mWriter->setLayerBuffer(1, handle2.get(), -1);
+    mWriter->setLayerBuffer(1, handle2->handle, -1);
     mWriter->setLayerDataspace(Dataspace::UNKNOWN);
     mWriter->validateDisplay();
     execute();
@@ -951,7 +950,7 @@
     mWriter->selectLayer(layer);
     mWriter->setLayerCompositionType(IComposerClient::Composition::DEVICE);
     mWriter->setLayerDisplayFrame(displayFrame);
-    mWriter->setLayerBuffer(2, handle3.get(), -1);
+    mWriter->setLayerBuffer(2, handle3->handle, -1);
     mWriter->setLayerDataspace(Dataspace::UNKNOWN);
     mWriter->validateDisplay();
     execute();
@@ -968,10 +967,10 @@
     // Ensure we can clear multiple buffer slots and then restore the active buffer at the end
     mWriter->selectDisplay(mPrimaryDisplay);
     mWriter->selectLayer(layer);
-    mWriter->setLayerBuffer(0, clearSlotBuffer.get(), -1);
+    mWriter->setLayerBuffer(0, clearSlotBuffer->handle, -1);
     mWriter->selectDisplay(mPrimaryDisplay);
     mWriter->selectLayer(layer);
-    mWriter->setLayerBuffer(1, clearSlotBuffer.get(), -1);
+    mWriter->setLayerBuffer(1, clearSlotBuffer->handle, -1);
     mWriter->selectDisplay(mPrimaryDisplay);
     mWriter->selectLayer(layer);
     mWriter->setLayerBuffer(2, nullptr, -1);
@@ -1113,7 +1112,7 @@
 
     mWriter->selectDisplay(mPrimaryDisplay);
     mWriter->selectLayer(layer);
-    mWriter->setLayerSidebandStream(handle.get());
+    mWriter->setLayerSidebandStream(handle->handle);
     execute();
 }
 
diff --git a/graphics/composer/2.2/utils/vts/Android.bp b/graphics/composer/2.2/utils/vts/Android.bp
index d11592f..a923923 100644
--- a/graphics/composer/2.2/utils/vts/Android.bp
+++ b/graphics/composer/2.2/utils/vts/Android.bp
@@ -26,7 +26,6 @@
 cc_library_static {
     name: "android.hardware.graphics.composer@2.2-vts",
     defaults: [
-        "android.hardware.graphics.allocator-ndk_static",
         "android.hardware.graphics.composer3-ndk_static",
         "hidl_defaults",
         "librenderengine_deps",
@@ -42,7 +41,6 @@
     static_libs: [
         "android.hardware.graphics.composer@2.1-vts",
         "android.hardware.graphics.composer@2.2",
-        "android.hardware.graphics.mapper@2.1-vts",
         "libarect",
         "libgtest",
         "libmath",
@@ -50,15 +48,10 @@
         "librenderengine",
         "libshaders",
         "libtonemap",
-        "android.hardware.graphics.mapper@3.0",
-        "android.hardware.graphics.mapper@3.0-vts",
-        "android.hardware.graphics.mapper@4.0",
-        "android.hardware.graphics.mapper@4.0-vts",
     ],
     export_static_lib_headers: [
         "android.hardware.graphics.composer@2.1-vts",
         "android.hardware.graphics.composer@2.2",
-        "android.hardware.graphics.mapper@2.1-vts",
     ],
     header_libs: [
         "android.hardware.graphics.composer@2.2-command-buffer",
diff --git a/graphics/composer/2.2/utils/vts/ComposerVts.cpp b/graphics/composer/2.2/utils/vts/ComposerVts.cpp
index d4f0281..d041064 100644
--- a/graphics/composer/2.2/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.2/utils/vts/ComposerVts.cpp
@@ -179,66 +179,6 @@
     return matrix;
 }
 
-Gralloc::Gralloc() {
-    [this] {
-        ALOGD("Attempting to initialize gralloc4");
-        ASSERT_NO_FATAL_FAILURE(mGralloc4 = std::make_shared<Gralloc4>(
-                                        /*aidlAllocatorServiceName*/ IAllocator::descriptor +
-                                                std::string("/default"),
-                                        /*hidlAllocatorServiceName*/ "default",
-                                        /*mapperServiceName*/ "default",
-                                        /*errOnFailure=*/false));
-        if (mGralloc4->getMapper() == nullptr || !mGralloc4->hasAllocator()) {
-            mGralloc4 = nullptr;
-            ALOGD("Failed to initialize gralloc4, initializing gralloc3");
-            ASSERT_NO_FATAL_FAILURE(mGralloc3 = std::make_shared<Gralloc3>("default", "default",
-                                                                           /*errOnFailure=*/false));
-            if (mGralloc3->getMapper() == nullptr || mGralloc3->getAllocator() == nullptr) {
-                mGralloc3 = nullptr;
-                ALOGD("Failed to initialize gralloc3, initializing gralloc2_1");
-                mGralloc2_1 = std::make_shared<Gralloc2_1>(/*errOnFailure*/ false);
-                if (!mGralloc2_1->getMapper()) {
-                    mGralloc2_1 = nullptr;
-                    ALOGD("Failed to initialize gralloc2_1, initializing gralloc2");
-                    ASSERT_NO_FATAL_FAILURE(mGralloc2 = std::make_shared<Gralloc2>());
-                }
-            }
-        }
-    }();
-}
-
-bool Gralloc::validateBufferSize(const native_handle_t* bufferHandle, uint32_t width,
-                                 uint32_t height, uint32_t layerCount, PixelFormat format,
-                                 uint64_t usage, uint32_t stride) {
-    if (mGralloc4) {
-        IMapper4::BufferDescriptorInfo info{};
-        info.width = width;
-        info.height = height;
-        info.layerCount = layerCount;
-        info.format = static_cast<android::hardware::graphics::common::V1_2::PixelFormat>(format);
-        info.usage = usage;
-        return mGralloc4->validateBufferSize(bufferHandle, info, stride);
-    } else if (mGralloc3) {
-        IMapper3::BufferDescriptorInfo info{};
-        info.width = width;
-        info.height = height;
-        info.layerCount = layerCount;
-        info.format = static_cast<android::hardware::graphics::common::V1_2::PixelFormat>(format);
-        info.usage = usage;
-        return mGralloc3->validateBufferSize(bufferHandle, info, stride);
-    } else if (mGralloc2_1) {
-        IMapper2_1::BufferDescriptorInfo info{};
-        info.width = width;
-        info.height = height;
-        info.layerCount = layerCount;
-        info.format = static_cast<android::hardware::graphics::common::V1_1::PixelFormat>(format);
-        info.usage = usage;
-        return mGralloc2_1->validateBufferSize(bufferHandle, info, stride);
-    } else {
-        return true;
-    }
-}
-
 }  // namespace vts
 }  // namespace V2_2
 }  // namespace composer
diff --git a/graphics/composer/2.2/utils/vts/ReadbackVts.cpp b/graphics/composer/2.2/utils/vts/ReadbackVts.cpp
index a1794af..9ba34f1 100644
--- a/graphics/composer/2.2/utils/vts/ReadbackVts.cpp
+++ b/graphics/composer/2.2/utils/vts/ReadbackVts.cpp
@@ -187,12 +187,11 @@
 }
 
 ReadbackBuffer::ReadbackBuffer(Display display, const std::shared_ptr<ComposerClient>& client,
-                               const std::shared_ptr<Gralloc>& gralloc, uint32_t width,
-                               uint32_t height, PixelFormat pixelFormat, Dataspace dataspace) {
+                               uint32_t width, uint32_t height, PixelFormat pixelFormat,
+                               Dataspace dataspace) {
     mDisplay = display;
 
     mComposerClient = client;
-    mGralloc = gralloc;
 
     mPixelFormat = pixelFormat;
     mDataspace = dataspace;
@@ -202,20 +201,12 @@
     mLayerCount = 1;
     mFormat = mPixelFormat;
     mUsage = static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::GPU_TEXTURE);
-
-    mAccessRegion.top = 0;
-    mAccessRegion.left = 0;
-    mAccessRegion.width = width;
-    mAccessRegion.height = height;
 }
 
 void ReadbackBuffer::setReadbackBuffer() {
-    mBufferHandle.reset(new Gralloc::NativeHandleWrapper(
-            mGralloc->allocate(mWidth, mHeight, mLayerCount, mFormat, mUsage,
-                               /*import*/ true, &mStride)));
-    ASSERT_NE(false, mGralloc->validateBufferSize(mBufferHandle->get(), mWidth, mHeight,
-                                                  mLayerCount, mFormat, mUsage, mStride));
-    ASSERT_NO_FATAL_FAILURE(mComposerClient->setReadbackBuffer(mDisplay, mBufferHandle->get(), -1));
+    mBuffer = sp<GraphicBuffer>::make(mWidth, mHeight, (int32_t)mFormat, mLayerCount, mUsage);
+    ASSERT_EQ(STATUS_OK, mBuffer->initCheck());
+    ASSERT_NO_FATAL_FAILURE(mComposerClient->setReadbackBuffer(mDisplay, mBuffer->handle, -1));
 }
 
 void ReadbackBuffer::checkReadbackBuffer(std::vector<IComposerClient::Color> expectedColors) {
@@ -223,15 +214,14 @@
     int32_t fenceHandle;
     ASSERT_NO_FATAL_FAILURE(mComposerClient->getReadbackBufferFence(mDisplay, &fenceHandle));
 
-    void* bufData = mGralloc->lock(mBufferHandle->get(), mUsage, mAccessRegion, fenceHandle);
+    void* bufData = nullptr;
+    int32_t stride = mBuffer->stride;
+    status_t status = mBuffer->lockAsync(mUsage, &bufData, fenceHandle);
+    ASSERT_EQ(STATUS_OK, status);
     ASSERT_TRUE(mPixelFormat == PixelFormat::RGB_888 || mPixelFormat == PixelFormat::RGBA_8888);
-    ReadbackHelper::compareColorBuffers(expectedColors, bufData, mStride, mWidth, mHeight,
+    ReadbackHelper::compareColorBuffers(expectedColors, bufData, stride, mWidth, mHeight,
                                         mPixelFormat);
-    int32_t unlockFence = mGralloc->unlock(mBufferHandle->get());
-    if (unlockFence != -1) {
-        sync_wait(unlockFence, -1);
-        close(unlockFence);
-    }
+    EXPECT_EQ(STATUS_OK, mBuffer->unlock());
 }
 
 void TestColorLayer::write(const std::shared_ptr<CommandWriterBase>& writer) {
@@ -251,12 +241,10 @@
 }
 
 TestBufferLayer::TestBufferLayer(const std::shared_ptr<ComposerClient>& client,
-                                 const std::shared_ptr<Gralloc>& gralloc,
                                  TestRenderEngine& renderEngine, Display display, int32_t width,
                                  int32_t height, PixelFormat format,
                                  IComposerClient::Composition composition)
     : TestLayer{client, display}, mRenderEngine(renderEngine) {
-    mGralloc = gralloc;
     mComposition = composition;
     mWidth = width;
     mHeight = height;
@@ -265,11 +253,6 @@
     mUsage = static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
                                    BufferUsage::COMPOSER_OVERLAY | BufferUsage::GPU_TEXTURE);
 
-    mAccessRegion.top = 0;
-    mAccessRegion.left = 0;
-    mAccessRegion.width = width;
-    mAccessRegion.height = height;
-
     setSourceCrop({0, 0, (float)width, (float)height});
 }
 
@@ -277,15 +260,13 @@
     TestLayer::write(writer);
     writer->setLayerCompositionType(mComposition);
     writer->setLayerVisibleRegion(std::vector<IComposerClient::Rect>(1, mDisplayFrame));
-    if (mBufferHandle != nullptr) writer->setLayerBuffer(0, mBufferHandle->get(), mFillFence);
+    if (mBuffer) writer->setLayerBuffer(0, mBuffer->handle, -1);
 }
 
 LayerSettings TestBufferLayer::toRenderEngineLayerSettings() {
     LayerSettings layerSettings = TestLayer::toRenderEngineLayerSettings();
     layerSettings.source.buffer.buffer = std::make_shared<renderengine::impl::ExternalTexture>(
-            new GraphicBuffer(mBufferHandle->get(), GraphicBuffer::CLONE_HANDLE, mWidth, mHeight,
-                              static_cast<int32_t>(mFormat), 1, mUsage, mStride),
-            mRenderEngine.getInternalRenderEngine(),
+            mBuffer, mRenderEngine.getInternalRenderEngine(),
             renderengine::impl::ExternalTexture::Usage::READABLE);
 
     layerSettings.source.buffer.usePremultipliedAlpha =
@@ -304,24 +285,18 @@
 }
 
 void TestBufferLayer::fillBuffer(std::vector<IComposerClient::Color> expectedColors) {
-    void* bufData = mGralloc->lock(mBufferHandle->get(), mUsage, mAccessRegion, -1);
-    ASSERT_NO_FATAL_FAILURE(
-            ReadbackHelper::fillBuffer(mWidth, mHeight, mStride, bufData, mFormat, expectedColors));
-    mFillFence = mGralloc->unlock(mBufferHandle->get());
-    if (mFillFence != -1) {
-        sync_wait(mFillFence, -1);
-        close(mFillFence);
-    }
+    void* bufData = nullptr;
+    status_t status = mBuffer->lock(mUsage, &bufData);
+    ASSERT_EQ(STATUS_OK, status);
+    ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(mWidth, mHeight, mBuffer->stride, bufData,
+                                                       mFormat, expectedColors));
+    EXPECT_EQ(STATUS_OK, mBuffer->unlock());
 }
 
 void TestBufferLayer::setBuffer(std::vector<IComposerClient::Color> colors) {
-    mBufferHandle.reset(new Gralloc::NativeHandleWrapper(
-            mGralloc->allocate(mWidth, mHeight, mLayerCount, mFormat, mUsage,
-                               /*import*/ true, &mStride)));
-    ASSERT_NE(nullptr, mBufferHandle->get());
+    mBuffer = sp<GraphicBuffer>::make(mWidth, mHeight, (int32_t)mFormat, mLayerCount, mUsage);
+    ASSERT_EQ(STATUS_OK, mBuffer->initCheck());
     ASSERT_NO_FATAL_FAILURE(fillBuffer(colors));
-    ASSERT_NE(false, mGralloc->validateBufferSize(mBufferHandle->get(), mWidth, mHeight,
-                                                  mLayerCount, mFormat, mUsage, mStride));
 }
 
 void TestBufferLayer::setDataspace(Dataspace dataspace,
diff --git a/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp b/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
index 1700b2a..6960d06 100644
--- a/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
+++ b/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
@@ -24,7 +24,6 @@
 namespace V2_2 {
 namespace vts {
 
-using mapper::V2_1::IMapper;
 using renderengine::DisplaySettings;
 using renderengine::LayerSettings;
 using renderengine::RenderEngineCreationArgs;
@@ -72,7 +71,7 @@
     auto texture = std::make_shared<renderengine::impl::ExternalTexture>(
             mGraphicBuffer, *mRenderEngine, renderengine::impl::ExternalTexture::Usage::WRITEABLE);
     auto result = mRenderEngine
-                          ->drawLayers(mDisplaySettings, compositionLayers, texture, true,
+                          ->drawLayers(mDisplaySettings, compositionLayers, texture,
                                        std::move(bufferFence))
                           .get();
     if (result.ok()) {
diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
index 02d7bdb..3e26d94 100644
--- a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
+++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
@@ -26,7 +26,6 @@
 #include <android/hardware/graphics/composer/2.2/IComposerClient.h>
 #include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
 #include <composer-vts/2.1/ComposerVts.h>
-#include <mapper-vts/2.1/MapperVts.h>
 #include <utils/StrongPointer.h>
 
 namespace android {
@@ -41,14 +40,6 @@
 using common::V1_1::Dataspace;
 using common::V1_1::PixelFormat;
 using common::V1_1::RenderIntent;
-using IMapper2_1 = android::hardware::graphics::mapper::V2_1::IMapper;
-using IMapper3 = android::hardware::graphics::mapper::V3_0::IMapper;
-using IMapper4 = android::hardware::graphics::mapper::V4_0::IMapper;
-using Gralloc2 = android::hardware::graphics::mapper::V2_0::vts::Gralloc;
-using Gralloc2_1 = android::hardware::graphics::mapper::V2_1::vts::Gralloc;
-using Gralloc3 = android::hardware::graphics::mapper::V3_0::vts::Gralloc;
-using Gralloc4 = android::hardware::graphics::mapper::V4_0::vts::Gralloc;
-using IAllocator = aidl::android::hardware::graphics::allocator::IAllocator;
 
 class ComposerClient;
 
@@ -92,28 +83,6 @@
     const sp<IComposerClient> mClient;
 };
 
-class Gralloc : public V2_1::vts::Gralloc {
-  public:
-    using NativeHandleWrapper = V2_1::vts::NativeHandleWrapper;
-
-    Gralloc();
-    const NativeHandleWrapper allocate(uint32_t width, uint32_t height, uint32_t layerCount,
-                                       PixelFormat format, uint64_t usage, bool import = true,
-                                       uint32_t* outStride = nullptr) {
-        return V2_1::vts::Gralloc::allocate(
-                width, height, layerCount,
-                static_cast<android::hardware::graphics::common::V1_0::PixelFormat>(format), usage,
-                import, outStride);
-    }
-
-    bool validateBufferSize(const native_handle_t* bufferHandle, uint32_t width, uint32_t height,
-                            uint32_t layerCount, PixelFormat format, uint64_t usage,
-                            uint32_t stride);
-
-  protected:
-    std::shared_ptr<Gralloc2_1> mGralloc2_1 = nullptr;
-};
-
 }  // namespace vts
 }  // namespace V2_2
 }  // namespace composer
diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h
index 58efde9..aa6932a 100644
--- a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h
+++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h
@@ -22,7 +22,6 @@
 #include <composer-vts/2.1/GraphicsComposerCallback.h>
 #include <composer-vts/2.1/TestCommandReader.h>
 #include <composer-vts/2.2/ComposerVts.h>
-#include <mapper-vts/2.1/MapperVts.h>
 #include <renderengine/RenderEngine.h>
 
 #include <memory>
@@ -38,12 +37,9 @@
 using common::V1_1::BufferUsage;
 using common::V1_1::Dataspace;
 using common::V1_1::PixelFormat;
-using IMapper2_1 = mapper::V2_1::IMapper;
-using Gralloc2_1 = mapper::V2_1::vts::Gralloc;
 using renderengine::LayerSettings;
 using V2_1::Display;
 using V2_1::Layer;
-using V2_1::vts::AccessRegion;
 using V2_1::vts::TestCommandReader;
 
 static const IComposerClient::Color BLACK = {0, 0, 0, 0xff};
@@ -113,9 +109,8 @@
 class TestBufferLayer : public TestLayer {
   public:
     TestBufferLayer(
-            const std::shared_ptr<ComposerClient>& client, const std::shared_ptr<Gralloc>& gralloc,
-            TestRenderEngine& renderEngine, Display display, int32_t width, int32_t height,
-            PixelFormat format,
+            const std::shared_ptr<ComposerClient>& client, TestRenderEngine& renderEngine,
+            Display display, int32_t width, int32_t height, PixelFormat format,
             IComposerClient::Composition composition = IComposerClient::Composition::DEVICE);
 
     void write(const std::shared_ptr<CommandWriterBase>& writer) override;
@@ -135,15 +130,11 @@
     uint32_t mLayerCount;
     PixelFormat mFormat;
     uint64_t mUsage;
-    AccessRegion mAccessRegion;
-    uint32_t mStride;
 
   protected:
     IComposerClient::Composition mComposition;
-    std::shared_ptr<Gralloc> mGralloc;
     TestRenderEngine& mRenderEngine;
-    int32_t mFillFence;
-    std::unique_ptr<Gralloc::NativeHandleWrapper> mBufferHandle;
+    sp<GraphicBuffer> mBuffer;
 };
 
 class ReadbackHelper {
@@ -179,9 +170,8 @@
 
 class ReadbackBuffer {
   public:
-    ReadbackBuffer(Display display, const std::shared_ptr<ComposerClient>& client,
-                   const std::shared_ptr<Gralloc>& gralloc, uint32_t width, uint32_t height,
-                   PixelFormat pixelFormat, Dataspace dataspace);
+    ReadbackBuffer(Display display, const std::shared_ptr<ComposerClient>& client, uint32_t width,
+                   uint32_t height, PixelFormat pixelFormat, Dataspace dataspace);
 
     void setReadbackBuffer();
 
@@ -193,13 +183,10 @@
     uint32_t mLayerCount;
     PixelFormat mFormat;
     uint64_t mUsage;
-    AccessRegion mAccessRegion;
-    uint32_t mStride;
-    std::unique_ptr<Gralloc::NativeHandleWrapper> mBufferHandle = nullptr;
+    sp<GraphicBuffer> mBuffer;
     PixelFormat mPixelFormat;
     Dataspace mDataspace;
     Display mDisplay;
-    std::shared_ptr<Gralloc> mGralloc;
     std::shared_ptr<ComposerClient> mComposerClient;
 };
 
diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h
index 26027d3..09b89ff 100644
--- a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h
+++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h
@@ -22,7 +22,6 @@
 #include <renderengine/ExternalTexture.h>
 #include <renderengine/RenderEngine.h>
 #include <ui/GraphicBuffer.h>
-#include <ui/GraphicBufferAllocator.h>
 #include <ui/PixelFormat.h>
 #include <ui/Rect.h>
 #include <ui/Region.h>
@@ -34,10 +33,8 @@
 namespace V2_2 {
 namespace vts {
 
-using mapper::V2_1::IMapper;
 using renderengine::DisplaySettings;
 using renderengine::RenderEngineCreationArgs;
-using vts::Gralloc;
 
 class TestRenderEngine {
   public:
diff --git a/graphics/composer/2.2/vts/functional/Android.bp b/graphics/composer/2.2/vts/functional/Android.bp
index 3476376..a781712 100644
--- a/graphics/composer/2.2/vts/functional/Android.bp
+++ b/graphics/composer/2.2/vts/functional/Android.bp
@@ -27,7 +27,6 @@
     name: "VtsHalGraphicsComposerV2_2TargetTest",
     defaults: [
         "VtsHalTargetTestDefaults",
-        "android.hardware.graphics.allocator-ndk_static",
         "android.hardware.graphics.composer3-ndk_static",
         "librenderengine_deps",
     ],
@@ -54,24 +53,13 @@
         "libsync",
         "libui",
         "android.hardware.common-V2-ndk",
-        "android.hardware.graphics.mapper@2.0",
-        "android.hardware.graphics.mapper@2.1",
-        "android.hardware.graphics.mapper@3.0",
-        "android.hardware.graphics.mapper@4.0",
     ],
     static_libs: [
-        "android.hardware.graphics.allocator@2.0",
-        "android.hardware.graphics.allocator@3.0",
-        "android.hardware.graphics.allocator@4.0",
         "android.hardware.graphics.common@1.1",
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.composer@2.1-vts",
         "android.hardware.graphics.composer@2.2",
         "android.hardware.graphics.composer@2.2-vts",
-        "android.hardware.graphics.mapper@2.0-vts",
-        "android.hardware.graphics.mapper@2.1-vts",
-        "android.hardware.graphics.mapper@3.0-vts",
-        "android.hardware.graphics.mapper@4.0-vts",
         "libaidlcommonsupport",
         "libgtest",
         "librenderengine",
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
index e2a0f4d..74d2f03 100644
--- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
+++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
@@ -26,7 +26,6 @@
 #include <hidl/GtestPrinter.h>
 #include <hidl/ServiceManagement.h>
 #include <ui/GraphicBuffer.h>
-#include <ui/GraphicBufferAllocator.h>
 #include <ui/PixelFormat.h>
 #include <ui/Rect.h>
 #include <ui/Region.h>
@@ -45,9 +44,7 @@
 using common::V1_1::PixelFormat;
 using V2_1::Config;
 using V2_1::Display;
-using V2_1::vts::NativeHandleWrapper;
 using V2_1::vts::TestCommandReader;
-using vts::Gralloc;
 
 class GraphicsCompositionTestBase : public ::testing::Test {
   protected:
@@ -79,20 +76,19 @@
         // set up command writer/reader and gralloc
         mWriter = std::make_shared<CommandWriterBase>(1024);
         mReader = std::make_unique<TestCommandReader>();
-        mGralloc = std::make_shared<Gralloc>();
 
         ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::ON));
 
         ASSERT_NO_FATAL_FAILURE(
                 mTestRenderEngine = std::unique_ptr<TestRenderEngine>(new TestRenderEngine(
                         renderengine::RenderEngineCreationArgs::Builder()
-                            .setPixelFormat(static_cast<int>(ui::PixelFormat::RGBA_8888))
-                            .setImageCacheSize(TestRenderEngine::sMaxFrameBufferAcquireBuffers)
-                            .setUseColorManagerment(true)
-                            .setEnableProtectedContext(false)
-                            .setPrecacheToneMapperShaderOnly(false)
-                            .setContextPriority(renderengine::RenderEngine::ContextPriority::HIGH)
-                            .build())));
+                                .setPixelFormat(static_cast<int>(ui::PixelFormat::RGBA_8888))
+                                .setImageCacheSize(TestRenderEngine::sMaxFrameBufferAcquireBuffers)
+                                .setEnableProtectedContext(false)
+                                .setPrecacheToneMapperShaderOnly(false)
+                                .setContextPriority(
+                                        renderengine::RenderEngine::ContextPriority::HIGH)
+                                .build())));
 
         renderengine::DisplaySettings clientCompositionDisplay;
         clientCompositionDisplay.physicalDisplay = Rect(mDisplayWidth, mDisplayHeight);
@@ -143,7 +139,6 @@
     std::vector<ColorMode> mTestColorModes;
     std::shared_ptr<CommandWriterBase> mWriter;
     std::unique_ptr<TestCommandReader> mReader;
-    std::shared_ptr<Gralloc> mGralloc;
     std::unique_ptr<TestRenderEngine> mTestRenderEngine;
 
     bool mHasReadbackBuffer;
@@ -220,7 +215,7 @@
         std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
         ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE);
 
-        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
                                       mDisplayHeight, mPixelFormat, mDataspace);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
@@ -272,7 +267,7 @@
 
         mWriter->selectDisplay(mPrimaryDisplay);
 
-        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
                                       mDisplayHeight, mPixelFormat, mDataspace);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
         std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
@@ -285,9 +280,9 @@
                                        {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight},
                                        BLUE);
 
-        auto layer = std::make_shared<TestBufferLayer>(
-                mComposerClient, mGralloc, *mTestRenderEngine, mPrimaryDisplay, mDisplayWidth,
-                mDisplayHeight, PixelFormat::RGBA_8888);
+        auto layer = std::make_shared<TestBufferLayer>(mComposerClient, *mTestRenderEngine,
+                                                       mPrimaryDisplay, mDisplayWidth,
+                                                       mDisplayHeight, PixelFormat::RGBA_8888);
         layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
         layer->setZOrder(10);
         layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
@@ -352,15 +347,16 @@
         // This following buffer call should have no effect
         uint64_t usage =
                 static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN);
-        NativeHandleWrapper bufferHandle =
-                mGralloc->allocate(mDisplayWidth, mDisplayHeight, 1, PixelFormat::RGBA_8888, usage);
-        mWriter->setLayerBuffer(0, bufferHandle.get(), -1);
+        sp<GraphicBuffer> buffer = sp<GraphicBuffer>::make(
+                mDisplayWidth, mDisplayHeight, (int32_t)PixelFormat::RGBA_8888, 1, usage);
+        ASSERT_EQ(STATUS_OK, buffer->initCheck());
+        mWriter->setLayerBuffer(0, buffer->handle, -1);
 
         // expected color for each pixel
         std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
         ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE);
 
-        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
                                       mDisplayHeight, mPixelFormat, mDataspace);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
@@ -419,16 +415,16 @@
                                        {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight},
                                        BLUE);
 
-        auto layer = std::make_shared<TestBufferLayer>(
-                mComposerClient, mGralloc, *mTestRenderEngine, mPrimaryDisplay, mDisplayWidth,
-                mDisplayHeight, PixelFormat::RGBA_FP16);
+        auto layer = std::make_shared<TestBufferLayer>(mComposerClient, *mTestRenderEngine,
+                                                       mPrimaryDisplay, mDisplayWidth,
+                                                       mDisplayHeight, PixelFormat::RGBA_FP16);
         layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
         layer->setZOrder(10);
         layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
 
         std::vector<std::shared_ptr<TestLayer>> layers = {layer};
 
-        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
                                       mDisplayHeight, mPixelFormat, mDataspace);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
         writeLayers(layers);
@@ -462,25 +458,20 @@
             }
 
             // create client target buffer
-            uint32_t clientStride;
-            NativeHandleWrapper clientBufferHandle =
-                    mGralloc->allocate(layer->mWidth, layer->mHeight, layer->mLayerCount,
-                                       clientFormat, clientUsage, /*import*/ true, &clientStride);
-            ASSERT_NE(nullptr, clientBufferHandle.get());
+            sp<GraphicBuffer> clientBuffer =
+                    sp<GraphicBuffer>::make(layer->mWidth, layer->mHeight, (int32_t)clientFormat,
+                                            layer->mLayerCount, clientUsage);
+            ASSERT_EQ(STATUS_OK, clientBuffer->initCheck());
 
-            void* clientBufData =
-                    mGralloc->lock(clientBufferHandle.get(), clientUsage, layer->mAccessRegion, -1);
+            void* clientBufData = nullptr;
+            ASSERT_EQ(STATUS_OK, clientBuffer->lock(clientUsage, &clientBufData));
 
             ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(layer->mWidth, layer->mHeight,
-                                                               clientStride, clientBufData,
+                                                               clientBuffer->stride, clientBufData,
                                                                clientFormat, expectedColors));
-            int clientFence = mGralloc->unlock(clientBufferHandle.get());
-            if (clientFence != -1) {
-                sync_wait(clientFence, -1);
-                close(clientFence);
-            }
+            clientBuffer->unlock();
 
-            mWriter->setClientTarget(0, clientBufferHandle.get(), clientFence, clientDataspace,
+            mWriter->setClientTarget(0, clientBuffer->handle, -1, clientDataspace,
                                      std::vector<IComposerClient::Rect>(1, damage));
 
             layer->setToClientComposition(mWriter);
@@ -531,12 +522,12 @@
         ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
                                        {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, RED);
 
-        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
                                       mDisplayHeight, mPixelFormat, mDataspace);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
         auto deviceLayer = std::make_shared<TestBufferLayer>(
-                mComposerClient, mGralloc, *mTestRenderEngine, mPrimaryDisplay, mDisplayWidth,
+                mComposerClient, *mTestRenderEngine, mPrimaryDisplay, mDisplayWidth,
                 mDisplayHeight / 2, PixelFormat::RGBA_8888);
         std::vector<IComposerClient::Color> deviceColors(deviceLayer->mWidth *
                                                          deviceLayer->mHeight);
@@ -573,8 +564,8 @@
         }
 
         auto clientLayer = std::make_shared<TestBufferLayer>(
-                mComposerClient, mGralloc, *mTestRenderEngine, mPrimaryDisplay, clientWidth,
-                clientHeight, PixelFormat::RGBA_FP16, IComposerClient::Composition::DEVICE);
+                mComposerClient, *mTestRenderEngine, mPrimaryDisplay, clientWidth, clientHeight,
+                PixelFormat::RGBA_FP16, IComposerClient::Composition::DEVICE);
         IComposerClient::Rect clientFrame = {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight};
         clientLayer->setDisplayFrame(clientFrame);
         clientLayer->setZOrder(0);
@@ -590,27 +581,22 @@
         }
         // create client target buffer
         ASSERT_EQ(1, mReader->mCompositionChanges[0].second);
-        uint32_t clientStride;
-        NativeHandleWrapper clientBufferHandle =
-                mGralloc->allocate(mDisplayWidth, mDisplayHeight, clientLayer->mLayerCount,
-                                   clientFormat, clientUsage, /*import*/ true, &clientStride);
-        ASSERT_NE(nullptr, clientBufferHandle.get());
+        sp<GraphicBuffer> clientBuffer =
+                sp<GraphicBuffer>::make(mDisplayWidth, mDisplayHeight, (int32_t)clientFormat,
+                                        clientLayer->mLayerCount, clientUsage);
+        ASSERT_EQ(STATUS_OK, clientBuffer->initCheck());
 
-        void* clientBufData = mGralloc->lock(clientBufferHandle.get(), clientUsage,
-                                             {0, 0, mDisplayWidth, mDisplayHeight}, -1);
+        void* clientBufData = nullptr;
+        ASSERT_EQ(STATUS_OK, clientBuffer->lock(clientUsage, &clientBufData));
 
         std::vector<IComposerClient::Color> clientColors(mDisplayWidth * mDisplayHeight);
         ReadbackHelper::fillColorsArea(clientColors, mDisplayWidth, clientFrame, RED);
         ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(mDisplayWidth, mDisplayHeight,
-                                                           clientStride, clientBufData,
+                                                           clientBuffer->stride, clientBufData,
                                                            clientFormat, clientColors));
-        int clientFence = mGralloc->unlock(clientBufferHandle.get());
-        if (clientFence != -1) {
-            sync_wait(clientFence, -1);
-            close(clientFence);
-        }
+        EXPECT_EQ(STATUS_OK, clientBuffer->unlock());
 
-        mWriter->setClientTarget(0, clientBufferHandle.get(), clientFence, clientDataspace,
+        mWriter->setClientTarget(0, clientBuffer->handle, -1, clientDataspace,
                                  std::vector<IComposerClient::Rect>(1, clientFrame));
         clientLayer->setToClientComposition(mWriter);
         mWriter->validateDisplay();
@@ -655,9 +641,9 @@
         std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
         ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
 
-        auto layer = std::make_shared<TestBufferLayer>(
-                mComposerClient, mGralloc, *mTestRenderEngine, mPrimaryDisplay, mDisplayWidth,
-                mDisplayHeight, PixelFormat::RGBA_8888);
+        auto layer = std::make_shared<TestBufferLayer>(mComposerClient, *mTestRenderEngine,
+                                                       mPrimaryDisplay, mDisplayWidth,
+                                                       mDisplayHeight, PixelFormat::RGBA_8888);
         layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
         layer->setZOrder(10);
         layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
@@ -665,7 +651,7 @@
 
         std::vector<std::shared_ptr<TestLayer>> layers = {layer};
 
-        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
                                       mDisplayHeight, mPixelFormat, mDataspace);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
@@ -742,7 +728,7 @@
 
         std::vector<std::shared_ptr<TestLayer>> layers = {layer};
 
-        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
                                       mDisplayHeight, mPixelFormat, mDataspace);
 
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
@@ -803,9 +789,9 @@
                                        {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight},
                                        BLUE);
 
-        auto layer = std::make_shared<TestBufferLayer>(
-                mComposerClient, mGralloc, *mTestRenderEngine, mPrimaryDisplay, mDisplayWidth,
-                mDisplayHeight, PixelFormat::RGBA_8888);
+        auto layer = std::make_shared<TestBufferLayer>(mComposerClient, *mTestRenderEngine,
+                                                       mPrimaryDisplay, mDisplayWidth,
+                                                       mDisplayHeight, PixelFormat::RGBA_8888);
         layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
         layer->setZOrder(10);
         layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
@@ -819,7 +805,7 @@
         // update expected colors to match crop
         ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
                                        {0, 0, mDisplayWidth, mDisplayHeight}, BLUE);
-        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
                                       mDisplayHeight, mPixelFormat, mDataspace);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
         writeLayers(layers);
@@ -886,7 +872,7 @@
         ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, blueRect, BLUE);
         ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
 
-        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
                                       mDisplayHeight, mPixelFormat, mDataspace);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
@@ -955,9 +941,9 @@
         backgroundLayer->setZOrder(0);
         backgroundLayer->setColor(mBackgroundColor);
 
-        auto layer = std::make_shared<TestBufferLayer>(
-                mComposerClient, mGralloc, *mTestRenderEngine, mPrimaryDisplay, mDisplayWidth,
-                mDisplayHeight, PixelFormat::RGBA_8888);
+        auto layer = std::make_shared<TestBufferLayer>(mComposerClient, *mTestRenderEngine,
+                                                       mPrimaryDisplay, mDisplayWidth,
+                                                       mDisplayHeight, PixelFormat::RGBA_8888);
         layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
         layer->setZOrder(10);
         layer->setDataspace(Dataspace::UNKNOWN, mWriter);
@@ -1043,7 +1029,7 @@
         setUpLayers(IComposerClient::BlendMode::NONE);
         setExpectedColors(expectedColors);
 
-        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
                                       mDisplayHeight, mPixelFormat, mDataspace);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
         writeLayers(mLayers);
@@ -1102,7 +1088,7 @@
         setUpLayers(IComposerClient::BlendMode::COVERAGE);
         setExpectedColors(expectedColors);
 
-        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
                                       mDisplayHeight, mPixelFormat, mDataspace);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
         writeLayers(mLayers);
@@ -1153,7 +1139,7 @@
         setUpLayers(IComposerClient::BlendMode::PREMULTIPLIED);
         setExpectedColors(expectedColors);
 
-        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
                                       mDisplayHeight, mPixelFormat, mDataspace);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
         writeLayers(mLayers);
@@ -1193,7 +1179,7 @@
         IComposerClient::Rect blueRect = {mSideLength / 2, mSideLength / 2, mSideLength,
                                           mSideLength};
 
-        mLayer = std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, *mTestRenderEngine,
+        mLayer = std::make_shared<TestBufferLayer>(mComposerClient, *mTestRenderEngine,
                                                    mPrimaryDisplay, mSideLength, mSideLength,
                                                    PixelFormat::RGBA_8888);
         mLayer->setDisplayFrame({0, 0, mSideLength, mSideLength});
@@ -1236,7 +1222,7 @@
             GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
             return;
         }
-        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
                                       mDisplayHeight, mPixelFormat, mDataspace);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
         mLayer->setTransform(Transform::FLIP_H);
@@ -1291,7 +1277,7 @@
             GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
             return;
         }
-        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
                                       mDisplayHeight, mPixelFormat, mDataspace);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
@@ -1346,7 +1332,7 @@
             GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
             return;
         }
-        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
                                       mDisplayHeight, mPixelFormat, mDataspace);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
index 13ae089..cd4cb58 100644
--- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
+++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
@@ -18,14 +18,13 @@
 
 #include <android-base/logging.h>
 #include <android-base/properties.h>
-#include <android/hardware/graphics/mapper/2.0/IMapper.h>
 #include <composer-vts/2.1/GraphicsComposerCallback.h>
 #include <composer-vts/2.1/TestCommandReader.h>
 #include <composer-vts/2.2/ComposerVts.h>
 #include <gtest/gtest.h>
 #include <hidl/GtestPrinter.h>
 #include <hidl/ServiceManagement.h>
-#include <mapper-vts/2.0/MapperVts.h>
+#include <ui/GraphicBuffer.h>
 
 namespace android {
 namespace hardware {
@@ -40,7 +39,6 @@
 using common::V1_1::Dataspace;
 using common::V1_1::PixelFormat;
 using common::V1_1::RenderIntent;
-using V2_1::vts::NativeHandleWrapper;
 
 class GraphicsComposerHidlTest : public ::testing::TestWithParam<std::string> {
   protected:
@@ -141,8 +139,6 @@
     void SetUp() override {
         ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::SetUp());
 
-        ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>());
-
         mWriter = std::make_unique<CommandWriterBase>(1024);
         mReader = std::make_unique<V2_1::vts::TestCommandReader>();
     }
@@ -152,20 +148,10 @@
         ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::TearDown());
     }
 
-    NativeHandleWrapper allocate() {
-        uint64_t usage =
-                static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);
-        return mGralloc->allocate(/*width*/ 64, /*height*/ 64, /*layerCount*/ 1,
-                                  PixelFormat::RGBA_8888, usage);
-    }
-
     void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); }
 
     std::unique_ptr<CommandWriterBase> mWriter;
     std::unique_ptr<V2_1::vts::TestCommandReader> mReader;
-
-   private:
-    std::unique_ptr<Gralloc> mGralloc;
 };
 
 /**
@@ -270,6 +256,8 @@
  * required client targets.
  */
 TEST_P(GraphicsComposerHidlTest, GetClientTargetSupport_2_2) {
+    ASSERT_NO_FATAL_FAILURE(
+            mComposerClient->setPowerMode_2_2(mPrimaryDisplay, IComposerClient::PowerMode::ON));
     std::vector<Config> configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay);
     for (auto config : configs) {
         int32_t width = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config,
@@ -437,13 +425,11 @@
     uint64_t usage =
             static_cast<uint64_t>(BufferUsage::COMPOSER_OVERLAY | BufferUsage::CPU_READ_OFTEN);
 
-    std::unique_ptr<Gralloc> gralloc;
-    std::unique_ptr<NativeHandleWrapper> buffer;
-    ASSERT_NO_FATAL_FAILURE(gralloc = std::make_unique<Gralloc>());
-    ASSERT_NO_FATAL_FAILURE(buffer.reset(new NativeHandleWrapper(
-            gralloc->allocate(mDisplayWidth, mDisplayHeight, 1, mReadbackPixelFormat, usage))));
+    sp<GraphicBuffer> buffer = sp<GraphicBuffer>::make(mDisplayWidth, mDisplayHeight,
+                                                       (int32_t)mReadbackPixelFormat, 1, usage);
+    ASSERT_EQ(STATUS_OK, buffer->initCheck());
 
-    mComposerClient->setReadbackBuffer(mPrimaryDisplay, buffer->get(), -1);
+    mComposerClient->setReadbackBuffer(mPrimaryDisplay, buffer->handle, -1);
 }
 
 /**
@@ -460,14 +446,12 @@
     uint64_t usage =
             static_cast<uint64_t>(BufferUsage::COMPOSER_OVERLAY | BufferUsage::CPU_READ_OFTEN);
 
-    std::unique_ptr<Gralloc> gralloc;
-    std::unique_ptr<NativeHandleWrapper> buffer;
-    ASSERT_NO_FATAL_FAILURE(gralloc = std::make_unique<Gralloc>());
-    ASSERT_NO_FATAL_FAILURE(buffer.reset(new NativeHandleWrapper(
-            gralloc->allocate(mDisplayWidth, mDisplayHeight, 1, mReadbackPixelFormat, usage))));
+    sp<GraphicBuffer> buffer = sp<GraphicBuffer>::make(mDisplayWidth, mDisplayHeight,
+                                                       (int32_t)mReadbackPixelFormat, 1, usage);
+    ASSERT_EQ(STATUS_OK, buffer->initCheck());
 
-    Error error =
-            mComposerClient->getRaw()->setReadbackBuffer(mInvalidDisplayId, buffer->get(), nullptr);
+    Error error = mComposerClient->getRaw()->setReadbackBuffer(mInvalidDisplayId, buffer->handle,
+                                                               nullptr);
     ASSERT_EQ(Error::BAD_DISPLAY, error);
 }
 
diff --git a/graphics/composer/2.3/utils/vts/Android.bp b/graphics/composer/2.3/utils/vts/Android.bp
index b372804..99429db 100644
--- a/graphics/composer/2.3/utils/vts/Android.bp
+++ b/graphics/composer/2.3/utils/vts/Android.bp
@@ -26,7 +26,6 @@
 cc_library_static {
     name: "android.hardware.graphics.composer@2.3-vts",
     defaults: [
-        "android.hardware.graphics.allocator-ndk_static",
         "hidl_defaults",
     ],
     srcs: [
diff --git a/graphics/composer/2.3/vts/functional/Android.bp b/graphics/composer/2.3/vts/functional/Android.bp
index 13f2b11..0d3c27d 100644
--- a/graphics/composer/2.3/vts/functional/Android.bp
+++ b/graphics/composer/2.3/vts/functional/Android.bp
@@ -27,7 +27,6 @@
     name: "VtsHalGraphicsComposerV2_3TargetTest",
     defaults: [
         "VtsHalTargetTestDefaults",
-        "android.hardware.graphics.allocator-ndk_static",
     ],
     tidy_timeout_srcs: ["VtsHalGraphicsComposerV2_3TargetTest.cpp"],
     srcs: ["VtsHalGraphicsComposerV2_3TargetTest.cpp"],
@@ -40,25 +39,14 @@
         "libhidlbase",
         "libsync",
         "android.hardware.common-V2-ndk",
-        "android.hardware.graphics.mapper@2.0",
-        "android.hardware.graphics.mapper@2.1",
-        "android.hardware.graphics.mapper@3.0",
-        "android.hardware.graphics.mapper@4.0",
     ],
     static_libs: [
-        "android.hardware.graphics.allocator@2.0",
-        "android.hardware.graphics.allocator@3.0",
-        "android.hardware.graphics.allocator@4.0",
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.composer@2.1-vts",
         "android.hardware.graphics.composer@2.2",
         "android.hardware.graphics.composer@2.2-vts",
         "android.hardware.graphics.composer@2.3",
         "android.hardware.graphics.composer@2.3-vts",
-        "android.hardware.graphics.mapper@2.0-vts",
-        "android.hardware.graphics.mapper@2.1-vts",
-        "android.hardware.graphics.mapper@3.0-vts",
-        "android.hardware.graphics.mapper@4.0-vts",
         "libaidlcommonsupport",
     ],
     header_libs: [
diff --git a/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp b/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
index ecfe66c..f99c72d 100644
--- a/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
+++ b/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
@@ -21,7 +21,6 @@
 
 #include <android-base/logging.h>
 #include <android-base/properties.h>
-#include <android/hardware/graphics/mapper/2.0/IMapper.h>
 #include <composer-command-buffer/2.3/ComposerCommandBuffer.h>
 #include <composer-vts/2.1/GraphicsComposerCallback.h>
 #include <composer-vts/2.1/TestCommandReader.h>
@@ -29,7 +28,6 @@
 #include <gtest/gtest.h>
 #include <hidl/GtestPrinter.h>
 #include <hidl/ServiceManagement.h>
-#include <mapper-vts/2.0/MapperVts.h>
 
 namespace android {
 namespace hardware {
@@ -43,7 +41,6 @@
 using common::V1_2::ColorMode;
 using common::V1_2::Dataspace;
 using common::V1_2::PixelFormat;
-using V2_2::vts::Gralloc;
 
 class GraphicsComposerHidlTest : public ::testing::TestWithParam<std::string> {
   protected:
@@ -128,8 +125,6 @@
     void SetUp() override {
         ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::SetUp());
 
-        ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>());
-
         mWriter = std::make_unique<CommandWriterBase>(1024);
         mReader = std::make_unique<V2_1::vts::TestCommandReader>();
     }
@@ -143,9 +138,6 @@
 
     std::unique_ptr<CommandWriterBase> mWriter;
     std::unique_ptr<V2_1::vts::TestCommandReader> mReader;
-
-   private:
-    std::unique_ptr<Gralloc> mGralloc;
 };
 
 /**
@@ -282,6 +274,8 @@
  * Test IComposerClient::getClientTargetSupport_2_3
  */
 TEST_P(GraphicsComposerHidlTest, GetClientTargetSupport_2_3) {
+    ASSERT_NO_FATAL_FAILURE(
+            mComposerClient->setPowerMode_2_2(mPrimaryDisplay, IComposerClient::PowerMode::ON));
     std::vector<V2_1::Config> configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay);
     for (auto config : configs) {
         int32_t width = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config,
diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerCommandEngine.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerCommandEngine.h
index 697d6b8..3b5ce5a 100644
--- a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerCommandEngine.h
+++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerCommandEngine.h
@@ -90,6 +90,9 @@
         }
 
         const uint32_t keySize = read();
+        if (!isReadSizeValid(keySize)) {
+            return false;
+        }
         std::string key;
         key.resize(keySize);
         readBlob(keySize, key.data());
@@ -97,6 +100,9 @@
         const bool mandatory = read();
 
         const uint32_t valueSize = read();
+        if (!isReadSizeValid(valueSize)) {
+            return false;
+        }
         std::vector<uint8_t> value(valueSize);
         readBlob(valueSize, value.data());
 
diff --git a/graphics/composer/2.4/utils/vts/Android.bp b/graphics/composer/2.4/utils/vts/Android.bp
index d2b2ffa..c39b5eb1 100644
--- a/graphics/composer/2.4/utils/vts/Android.bp
+++ b/graphics/composer/2.4/utils/vts/Android.bp
@@ -26,7 +26,6 @@
 cc_library_static {
     name: "android.hardware.graphics.composer@2.4-vts",
     defaults: [
-        "android.hardware.graphics.allocator-ndk_static",
         "hidl_defaults",
     ],
     srcs: [
diff --git a/graphics/composer/2.4/vts/functional/Android.bp b/graphics/composer/2.4/vts/functional/Android.bp
index b4ab259..52624b4 100644
--- a/graphics/composer/2.4/vts/functional/Android.bp
+++ b/graphics/composer/2.4/vts/functional/Android.bp
@@ -27,7 +27,6 @@
     name: "VtsHalGraphicsComposerV2_4TargetTest",
     defaults: [
         "VtsHalTargetTestDefaults",
-        "android.hardware.graphics.allocator-ndk_static",
     ],
     tidy_timeout_srcs: ["VtsHalGraphicsComposerV2_4TargetTest.cpp"],
     srcs: ["VtsHalGraphicsComposerV2_4TargetTest.cpp"],
@@ -38,16 +37,10 @@
         "libbinder_ndk",
         "libfmq",
         "libsync",
+        "libui",
         "android.hardware.common-V2-ndk",
-        "android.hardware.graphics.mapper@2.0",
-        "android.hardware.graphics.mapper@2.1",
-        "android.hardware.graphics.mapper@3.0",
-        "android.hardware.graphics.mapper@4.0",
     ],
     static_libs: [
-        "android.hardware.graphics.allocator@2.0",
-        "android.hardware.graphics.allocator@3.0",
-        "android.hardware.graphics.allocator@4.0",
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.composer@2.1-vts",
         "android.hardware.graphics.composer@2.2",
@@ -56,10 +49,6 @@
         "android.hardware.graphics.composer@2.3-vts",
         "android.hardware.graphics.composer@2.4",
         "android.hardware.graphics.composer@2.4-vts",
-        "android.hardware.graphics.mapper@2.0-vts",
-        "android.hardware.graphics.mapper@2.1-vts",
-        "android.hardware.graphics.mapper@3.0-vts",
-        "android.hardware.graphics.mapper@4.0-vts",
         "libaidlcommonsupport",
     ],
     header_libs: [
diff --git a/graphics/composer/2.4/vts/functional/AndroidTest.xml b/graphics/composer/2.4/vts/functional/AndroidTest.xml
index 773db93..7626995 100644
--- a/graphics/composer/2.4/vts/functional/AndroidTest.xml
+++ b/graphics/composer/2.4/vts/functional/AndroidTest.xml
@@ -31,6 +31,6 @@
     <test class="com.android.tradefed.testtype.GTest" >
         <option name="native-test-device-path" value="/data/local/tmp" />
         <option name="module-name" value="VtsHalGraphicsComposerV2_4TargetTest" />
-        <option name="native-test-timeout" value="900000"/>
+        <option name="native-test-timeout" value="1800000"/>
     </test>
 </configuration>
diff --git a/graphics/composer/2.4/vts/functional/TEST_MAPPING b/graphics/composer/2.4/vts/functional/TEST_MAPPING
new file mode 100644
index 0000000..aedac5b
--- /dev/null
+++ b/graphics/composer/2.4/vts/functional/TEST_MAPPING
@@ -0,0 +1,13 @@
+{
+  "presubmit": [
+    {
+      "name": "VtsHalGraphicsComposerV2_4TargetTest"
+    }
+  ],
+  "kernel-presubmit": [
+    {
+      "name": "VtsHalGraphicsComposerV2_4TargetTest"
+    }
+  ]
+}
+
diff --git a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
index 35225d9..7ae917b 100644
--- a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
+++ b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
@@ -22,7 +22,6 @@
 
 #include <android-base/logging.h>
 #include <android-base/properties.h>
-#include <android/hardware/graphics/mapper/2.0/IMapper.h>
 #include <composer-command-buffer/2.4/ComposerCommandBuffer.h>
 #include <composer-vts/2.4/ComposerVts.h>
 #include <composer-vts/2.4/GraphicsComposerCallback.h>
@@ -30,9 +29,7 @@
 #include <gtest/gtest.h>
 #include <hidl/GtestPrinter.h>
 #include <hidl/ServiceManagement.h>
-#include <mapper-vts/2.0/MapperVts.h>
-#include <mapper-vts/3.0/MapperVts.h>
-#include <mapper-vts/4.0/MapperVts.h>
+#include <ui/GraphicBuffer.h>
 #include <utils/Timers.h>
 
 namespace android {
@@ -51,9 +48,7 @@
 using common::V1_2::Dataspace;
 using common::V1_2::PixelFormat;
 using V2_1::Layer;
-using V2_1::vts::NativeHandleWrapper;
 using V2_2::Transform;
-using V2_2::vts::Gralloc;
 
 using ContentType = IComposerClient::ContentType;
 using DisplayCapability = IComposerClient::DisplayCapability;
@@ -103,8 +98,6 @@
         }
         mComposerCallback->setVsyncAllowed(false);
 
-        ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>());
-
         mWriter = std::make_unique<CommandWriterBase>(1024);
         mReader = std::make_unique<TestCommandReader>();
     }
@@ -157,12 +150,15 @@
 
     void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); }
 
-    NativeHandleWrapper allocate(int32_t width, int32_t height) {
-        return mGralloc->allocate(
-                width, height, /*layerCount*/ 1,
-                static_cast<common::V1_1::PixelFormat>(PixelFormat::RGBA_8888),
+    sp<GraphicBuffer> allocate(int32_t width, int32_t height) {
+        auto result = sp<GraphicBuffer>::make(
+                width, height, static_cast<int32_t>(PixelFormat::RGBA_8888), /*layerCount*/ 1,
                 static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN |
                                       BufferUsage::COMPOSER_OVERLAY));
+        if (result->initCheck() != STATUS_OK) {
+            return nullptr;
+        }
+        return result;
     }
 
     struct TestParameters {
@@ -256,7 +252,6 @@
     std::unique_ptr<CommandWriterBase> mWriter;
     std::unique_ptr<TestCommandReader> mReader;
     sp<GraphicsComposerCallback> mComposerCallback;
-    std::unique_ptr<Gralloc> mGralloc;
 };
 
 TEST_P(GraphicsComposerHidlTest, getDisplayCapabilitiesBadDisplay) {
@@ -458,7 +453,7 @@
         mWriter->setLayerBlendMode(IComposerClient::BlendMode::NONE);
         mWriter->setLayerSurfaceDamage(
                 std::vector<IComposerClient::Rect>(1, display.getFrameRect()));
-        mWriter->setLayerBuffer(0, handle.get(), -1);
+        mWriter->setLayerBuffer(0, handle->handle, -1);
         mWriter->setLayerDataspace(Dataspace::UNKNOWN);
 
         mWriter->validateDisplay();
@@ -476,7 +471,7 @@
         ASSERT_NE(nullptr, handle.get());
 
         mWriter->selectLayer(layer);
-        mWriter->setLayerBuffer(0, handle.get(), -1);
+        mWriter->setLayerBuffer(0, handle->handle, -1);
         mWriter->setLayerSurfaceDamage(std::vector<IComposerClient::Rect>(1, {0, 0, 10, 10}));
         mWriter->validateDisplay();
         execute();
@@ -544,10 +539,12 @@
                       setActiveConfigWithConstraints(display, config2, constraints, &timeline));
 
             EXPECT_TRUE(timeline.newVsyncAppliedTimeNanos >= constraints.desiredTimeNanos);
-            // Refresh rate should change within a reasonable time
-            constexpr std::chrono::nanoseconds kReasonableTimeForChange = 1s;  // 1 second
-            EXPECT_TRUE(timeline.newVsyncAppliedTimeNanos - constraints.desiredTimeNanos <=
-                        kReasonableTimeForChange.count());
+            if (configGroup1 == configGroup2) {
+                // Refresh rate should change within a reasonable time
+                constexpr std::chrono::nanoseconds kReasonableTimeForChange = 1s;
+                EXPECT_TRUE(timeline.newVsyncAppliedTimeNanos - constraints.desiredTimeNanos <=
+                            kReasonableTimeForChange.count());
+            }
 
             if (timeline.refreshRequired) {
                 if (params.refreshMiss) {
diff --git a/graphics/composer/aidl/Android.bp b/graphics/composer/aidl/Android.bp
index 40448ec..5699895 100644
--- a/graphics/composer/aidl/Android.bp
+++ b/graphics/composer/aidl/Android.bp
@@ -31,14 +31,14 @@
         enabled: true,
         support_system_process: true,
     },
-    frozen: true,
+    frozen: false,
     vndk_use_version: "1",
     srcs: [
         "android/hardware/graphics/composer3/*.aidl",
     ],
     stability: "vintf",
     imports: [
-        "android.hardware.graphics.common-V4",
+        "android.hardware.graphics.common-V5",
         "android.hardware.common-V2",
     ],
     backend: {
@@ -54,19 +54,22 @@
                 enabled: true,
             },
         },
+        rust: {
+            enabled: true,
+        },
     },
     versions_with_info: [
         {
             version: "1",
             imports: [
-                "android.hardware.graphics.common-V4",
+                "android.hardware.graphics.common-V5",
                 "android.hardware.common-V2",
             ],
         },
         {
             version: "2",
             imports: [
-                "android.hardware.graphics.common-V4",
+                "android.hardware.graphics.common-V5",
                 "android.hardware.common-V2",
             ],
         },
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Capability.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Capability.aidl
index f02f8aa..ee004d6 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Capability.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Capability.aidl
@@ -45,4 +45,5 @@
   BOOT_DISPLAY_CONFIG = 5,
   HDR_OUTPUT_CONVERSION_CONFIG = 6,
   REFRESH_RATE_CHANGED_CALLBACK_DEBUG = 7,
+  LAYER_LIFECYCLE_BATCH_COMMAND = 8,
 }
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ClientTarget.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ClientTarget.aidl
index 7632707..06ed922 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ClientTarget.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ClientTarget.aidl
@@ -37,4 +37,5 @@
   android.hardware.graphics.composer3.Buffer buffer;
   android.hardware.graphics.common.Dataspace dataspace;
   android.hardware.graphics.common.Rect[] damage;
+  float hdrSdrRatio = 1.0f;
 }
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayCapability.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayCapability.aidl
index 6eba887..0e2d72b 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayCapability.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayCapability.aidl
@@ -42,4 +42,5 @@
   AUTO_LOW_LATENCY_MODE = 5,
   SUSPEND = 6,
   DISPLAY_IDLE_TIMER = 7,
+  MULTI_THREADED_PRESENT = 8,
 }
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayCommand.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayCommand.aidl
index 662240e..cce35e7 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayCommand.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayCommand.aidl
@@ -45,4 +45,5 @@
   boolean acceptDisplayChanges;
   boolean presentDisplay;
   boolean presentOrValidateDisplay;
+  int frameIntervalNs;
 }
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayConfiguration.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayConfiguration.aidl
new file mode 100644
index 0000000..040afd7
--- /dev/null
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayConfiguration.aidl
@@ -0,0 +1,48 @@
+/**
+ * Copyright 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible 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 DisplayConfiguration {
+  int configId;
+  int width;
+  int height;
+  @nullable android.hardware.graphics.composer3.DisplayConfiguration.Dpi dpi;
+  int configGroup;
+  int vsyncPeriod;
+  @nullable android.hardware.graphics.composer3.VrrConfig vrrConfig;
+  parcelable Dpi {
+    float x;
+    float y;
+  }
+}
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayRequest.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayRequest.aidl
index 00598eb..e6db116 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayRequest.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayRequest.aidl
@@ -37,12 +37,12 @@
   long display;
   int mask;
   android.hardware.graphics.composer3.DisplayRequest.LayerRequest[] layerRequests;
-  const int FLIP_CLIENT_TARGET = (1 << 0);
-  const int WRITE_CLIENT_TARGET_TO_OUTPUT = (1 << 1);
+  const int FLIP_CLIENT_TARGET = (1 << 0) /* 1 */;
+  const int WRITE_CLIENT_TARGET_TO_OUTPUT = (1 << 1) /* 2 */;
   @VintfStability
   parcelable LayerRequest {
     long layer;
     int mask;
-    const int CLEAR_CLIENT_TARGET = (1 << 0);
+    const int CLEAR_CLIENT_TARGET = (1 << 0) /* 1 */;
   }
 }
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/FormatColorComponent.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/FormatColorComponent.aidl
index 1990350..89dae83 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/FormatColorComponent.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/FormatColorComponent.aidl
@@ -34,8 +34,8 @@
 package android.hardware.graphics.composer3;
 @Backing(type="byte") @VintfStability
 enum FormatColorComponent {
-  FORMAT_COMPONENT_0 = (1 << 0),
-  FORMAT_COMPONENT_1 = (1 << 1),
-  FORMAT_COMPONENT_2 = (1 << 2),
-  FORMAT_COMPONENT_3 = (1 << 3),
+  FORMAT_COMPONENT_0 = (1 << 0) /* 1 */,
+  FORMAT_COMPONENT_1 = (1 << 1) /* 2 */,
+  FORMAT_COMPONENT_2 = (1 << 2) /* 4 */,
+  FORMAT_COMPONENT_3 = (1 << 3) /* 8 */,
 }
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerCallback.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerCallback.aidl
index 2c08cbe..e64bd52 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerCallback.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerCallback.aidl
@@ -34,6 +34,9 @@
 package android.hardware.graphics.composer3;
 @VintfStability
 interface IComposerCallback {
+  /**
+   * @deprecated : Use instead onHotplugEvent
+   */
   void onHotplug(long display, boolean connected);
   oneway void onRefresh(long display);
   oneway void onSeamlessPossible(long display);
@@ -41,4 +44,5 @@
   oneway void onVsyncPeriodTimingChanged(long display, in android.hardware.graphics.composer3.VsyncPeriodChangeTimeline updatedTimeline);
   oneway void onVsyncIdle(long display);
   oneway void onRefreshRateChangedDebug(in android.hardware.graphics.composer3.RefreshRateChangedDebugData data);
+  void onHotplugEvent(long display, android.hardware.graphics.common.DisplayHotplugEvent event);
 }
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 cb85a88..bc27cc7 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
@@ -42,8 +42,14 @@
   int getActiveConfig(long display);
   android.hardware.graphics.composer3.ColorMode[] getColorModes(long display);
   float[] getDataspaceSaturationMatrix(android.hardware.graphics.common.Dataspace dataspace);
+  /**
+   * @deprecated use getDisplayConfigurations instead. Returns a display attribute value for a particular display configuration. For legacy support getDisplayAttribute should return valid values for any requested DisplayAttribute, and for all of the configs obtained either through getDisplayConfigs or getDisplayConfigurations.
+   */
   int getDisplayAttribute(long display, int config, android.hardware.graphics.composer3.DisplayAttribute attribute);
   android.hardware.graphics.composer3.DisplayCapability[] getDisplayCapabilities(long display);
+  /**
+   * @deprecated use getDisplayConfigurations instead. For legacy support getDisplayConfigs should return at least one valid config. All the configs returned from the getDisplayConfigs should also be returned from getDisplayConfigurations.
+   */
   int[] getDisplayConfigs(long display);
   android.hardware.graphics.composer3.DisplayConnectionType getDisplayConnectionType(long display);
   android.hardware.graphics.composer3.DisplayIdentification getDisplayIdentificationData(long display);
@@ -79,6 +85,8 @@
   android.hardware.graphics.common.HdrConversionCapability[] getHdrConversionCapabilities();
   android.hardware.graphics.common.Hdr setHdrConversionStrategy(in android.hardware.graphics.common.HdrConversionStrategy conversionStrategy);
   void setRefreshRateChangedCallbackDebugEnabled(long display, boolean enabled);
+  android.hardware.graphics.composer3.DisplayConfiguration[] getDisplayConfigurations(long display, int maxFrameIntervalNs);
+  oneway void notifyExpectedPresent(long display, in android.hardware.graphics.composer3.ClockMonotonicTimestamp expectedPresentTime, int frameIntervalNs);
   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/LayerCommand.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LayerCommand.aidl
index 6d32218..87c8c18 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LayerCommand.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LayerCommand.aidl
@@ -55,4 +55,6 @@
   @nullable android.hardware.graphics.composer3.PerFrameMetadataBlob[] perFrameMetadataBlob;
   @nullable android.hardware.graphics.common.Rect[] blockingRegion;
   @nullable int[] bufferSlotsToClear;
+  android.hardware.graphics.composer3.LayerLifecycleBatchCommandType layerLifecycleBatchCommandType;
+  int newBufferSlotCount;
 }
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LayerLifecycleBatchCommandType.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LayerLifecycleBatchCommandType.aidl
new file mode 100644
index 0000000..ac78cd5
--- /dev/null
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LayerLifecycleBatchCommandType.aidl
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible 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;
+@Backing(type="int") @VintfStability
+enum LayerLifecycleBatchCommandType {
+  MODIFY = 0,
+  CREATE = 1,
+  DESTROY = 2,
+}
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/RefreshRateChangedDebugData.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/RefreshRateChangedDebugData.aidl
index 2b9801a..e9305e1 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/RefreshRateChangedDebugData.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/RefreshRateChangedDebugData.aidl
@@ -36,4 +36,5 @@
 parcelable RefreshRateChangedDebugData {
   long display;
   int vsyncPeriodNanos;
+  int refreshPeriodNanos;
 }
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/VrrConfig.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/VrrConfig.aidl
new file mode 100644
index 0000000..7377b4b
--- /dev/null
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/VrrConfig.aidl
@@ -0,0 +1,48 @@
+/**
+ * Copyright 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible 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 VrrConfig {
+  int minFrameIntervalNs;
+  @nullable android.hardware.graphics.composer3.VrrConfig.FrameIntervalPowerHint[] frameIntervalPowerHints;
+  @nullable android.hardware.graphics.composer3.VrrConfig.NotifyExpectedPresentConfig notifyExpectedPresentConfig;
+  parcelable FrameIntervalPowerHint {
+    int frameIntervalNs;
+    int averageRefreshPeriodNs;
+  }
+  parcelable NotifyExpectedPresentConfig {
+    int headsUpNs;
+    int timeoutNs;
+  }
+}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/Capability.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/Capability.aidl
index 4638610..1dfc074 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/Capability.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/Capability.aidl
@@ -86,4 +86,14 @@
      * @see IComposerCallback.onRefreshRateChangedDebug
      */
     REFRESH_RATE_CHANGED_CALLBACK_DEBUG = 7,
+
+    /**
+     * Specifies that the device HAL supports the batching of layer creation and destruction
+     * for better performance.
+     *
+     * @see IComposerClient.executeCommands
+     * @see LayerCommand.layerLifecycleBatchCommandType
+     * @see LayerCommand.newBufferSlotCount
+     */
+    LAYER_LIFECYCLE_BATCH_COMMAND = 8,
 }
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/ClientTarget.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/ClientTarget.aidl
index 56488d5..bc9f63a 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/ClientTarget.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/ClientTarget.aidl
@@ -36,4 +36,14 @@
      * The surface damage regions.
      */
     Rect[] damage;
+
+    /**
+     * The HDR/SDR ratio.
+     * Only meaningful for extended_range client targets to communicate the amount of HDR heaedroom
+     * inside the client target. For floating point client targets, this means that for each color
+     * channel the maximum SDR luminance is 1.0, and the maximum display relative luminance is
+     * the hdrSdrRatio.
+     * Note that this ratio is meant to be >= 1.0.
+     */
+    float hdrSdrRatio = 1.0f;
 }
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/ClientTargetPropertyWithBrightness.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/ClientTargetPropertyWithBrightness.aidl
index ea54a89..0bd72a3 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/ClientTargetPropertyWithBrightness.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/ClientTargetPropertyWithBrightness.aidl
@@ -39,14 +39,12 @@
     /**
      * The stage in which dimming operations should be performed when compositing
      * the client target.
+     *
      * Note that with a COLORIMETRIC RenderIntent, DimmingSpace must be LINEAR. That is, dimming
-     * is defined to occur in linear space.
-     * However, some composer implementations may, with other vendor-defined RenderIntents,
-     * configure their hardware such as image quality adjustments is intended to occur after
-     * composition. In this scenario, if the dimming operation were applied in linear space,
-     * then the resulting dimming operation may comepl those image quality adjustments to
-     * incorrectly alter the gamma curve. To avoid this issue, those implementations must opt to
-     * dim in gamma space.
+     * is defined to occur in linear space. However, some composer implementations may, with
+     * other vendor-defined RenderIntents, apply certain image quality adjustments that are
+     * sensitive to gamma shift when dimming in linear space. To avoid this issue, those
+     * implementations must opt to dim in gamma space.
      */
     DimmingStage dimmingStage;
 }
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayCapability.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayCapability.aidl
index f4b2984..7154d74 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayCapability.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayCapability.aidl
@@ -80,4 +80,20 @@
      * IComposerCallback.onVsyncIdle.
      */
     DISPLAY_IDLE_TIMER = 7,
+    /**
+     * Indicates that both the composer HAL implementation and the given display
+     * support calling executeCommands concurrently from separate threads.
+     * executeCommands for a particular display will never run concurrently to
+     * any other executeCommands for the same display. In addition, the
+     * CommandResultPayload must only reference displays included in the
+     * DisplayCommands passed to executeCommands. Displays referenced from
+     * separate threads must have minimal interference with one another. If a
+     * HWC-managed display has this capability, SurfaceFlinger can run
+     * executeCommands for this display concurrently with other displays with the
+     * same capability.
+     * @see IComposerClient.executeCommands
+     * @see DisplayCommand.presentDisplay
+     * @see DisplayCommand.validateDisplay
+     */
+    MULTI_THREADED_PRESENT = 8,
 }
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayCommand.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayCommand.aidl
index 4f69aee..02c1389 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayCommand.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayCommand.aidl
@@ -174,4 +174,15 @@
      * or perform a VALIDATE_DISPLAY action instead.
      */
     boolean presentOrValidateDisplay;
+
+    /**
+     * If a value greater than 0 is set, it provides a hint about the next frame(s)
+     * cadence. This parameter represents the time in nanoseconds of when to expect the
+     * next frames to arrive. For example. frameIntervalNs=33333333 indicates that the
+     * cadence of the next frames is 30Hz.
+     *
+     * The implementation should take the necessary steps to present the next frames as
+     * close as possible to the cadence.
+     */
+    int frameIntervalNs;
 }
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayConfiguration.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayConfiguration.aidl
new file mode 100644
index 0000000..09c42dc
--- /dev/null
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayConfiguration.aidl
@@ -0,0 +1,70 @@
+/**
+ * Copyright 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.VrrConfig;
+
+@VintfStability
+parcelable DisplayConfiguration {
+    /**
+     * The config id, to be used with IComposerClient.setActiveConfig.
+     */
+    int configId;
+
+    /**
+     * Dimensions in pixels
+     */
+    int width;
+    int height;
+
+    /**
+     * Dots per inch.
+     * If the DPI for a configuration is unavailable or is
+     * considered unreliable, the device may set null instead.
+     */
+    parcelable Dpi {
+        float x;
+        float y;
+    }
+    @nullable Dpi dpi;
+
+    /**
+     * The configuration group ID this config is associated to.
+     * Switching between configurations within the same group may be
+     * done seamlessly in some conditions via
+     * setActiveConfigWithConstraints. Configurations which share the
+     * same config group are similar in all attributes except for the
+     * vsync period.
+     */
+    int configGroup;
+
+    /**
+     * Vsync period in nanoseconds. This period represents the internal
+     * frequency of the display. IComposerCallback.onVsync is expected
+     * to be called on each vsync event. For non-VRR configurations, a
+     * frame can be presented on each vsync event.
+     *
+     * A present fence, retrieved from CommandResultPayload.presentFence
+     * must be signaled on a vsync boundary.
+     */
+    int vsyncPeriod;
+
+    /**
+     * Represents the specific configurations for VRR (Variable Refresh Rate) display modes.
+     * Non-VRR modes should set this to null.
+     */
+    @nullable VrrConfig vrrConfig;
+}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerCallback.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerCallback.aidl
index f4384b7..96eccd7 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerCallback.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerCallback.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.graphics.composer3;
 
+import android.hardware.graphics.common.DisplayHotplugEvent;
 import android.hardware.graphics.composer3.RefreshRateChangedDebugData;
 import android.hardware.graphics.composer3.VsyncPeriodChangeTimeline;
 
@@ -38,6 +39,7 @@
      * @param display is the display that triggers the hotplug event.
      * @param connected indicates whether the display is connected or
      *        disconnected.
+     * @deprecated: Use instead onHotplugEvent
      */
     void onHotplug(long display, boolean connected);
 
@@ -118,4 +120,23 @@
      * @param data is the data for the callback when refresh rate changed.
      */
     oneway void onRefreshRateChangedDebug(in RefreshRateChangedDebugData data);
+
+    /**
+     * Notifies the client that a DisplayHotplugEvent has occurred for the
+     * given display. Every active display (even a built-in physical display)
+     * must trigger at least one hotplug notification, even if it only occurs
+     * immediately after callback registration.
+     *
+     * Displays which have been connected are assumed to be in PowerMode.OFF,
+     * and the onVsync callback should not be called for a display until vsync
+     * has been enabled with setVsyncEnabled.
+     *
+     * The client may call back into the device while the callback is in
+     * progress. The device must serialize calls to this callback such that
+     * only one thread is calling it at a time.
+     *
+     * @param display is the display that triggers the hotplug event.
+     * @param event is the type of event that occurred.
+     */
+    void onHotplugEvent(long display, DisplayHotplugEvent event);
 }
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerClient.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerClient.aidl
index 4e77f86..213e8e9 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerClient.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerClient.aidl
@@ -22,12 +22,14 @@
 import android.hardware.graphics.common.HdrConversionStrategy;
 import android.hardware.graphics.common.Transform;
 import android.hardware.graphics.composer3.ClientTargetProperty;
+import android.hardware.graphics.composer3.ClockMonotonicTimestamp;
 import android.hardware.graphics.composer3.ColorMode;
 import android.hardware.graphics.composer3.CommandResultPayload;
 import android.hardware.graphics.composer3.ContentType;
 import android.hardware.graphics.composer3.DisplayAttribute;
 import android.hardware.graphics.composer3.DisplayCapability;
 import android.hardware.graphics.composer3.DisplayCommand;
+import android.hardware.graphics.composer3.DisplayConfiguration;
 import android.hardware.graphics.composer3.DisplayConnectionType;
 import android.hardware.graphics.composer3.DisplayContentSample;
 import android.hardware.graphics.composer3.DisplayContentSamplingAttributes;
@@ -234,9 +236,18 @@
     float[] getDataspaceSaturationMatrix(android.hardware.graphics.common.Dataspace dataspace);
 
     /**
+     * @deprecated use getDisplayConfigurations instead.
+     *
      * Returns a display attribute value for a particular display
      * configuration.
      *
+     * For legacy support getDisplayAttribute should return valid values for any requested
+     * DisplayAttribute, and for all of the configs obtained either through getDisplayConfigs
+     * or getDisplayConfigurations.
+     *
+     * @see getDisplayConfigurations
+     * @see getDisplayConfigs
+     *
      * @param display is the display to query.
      * @param config is the display configuration for which to return
      *        attribute values.
@@ -263,15 +274,12 @@
     DisplayCapability[] getDisplayCapabilities(long display);
 
     /**
-     * Returns handles for all of the valid display configurations on this
-     * display.
-     * This should never return INVALID_CONFIGURATION as a valid value.
+     * @deprecated use getDisplayConfigurations instead.
+     * For legacy support getDisplayConfigs should return at least one valid config.
+     * All the configs returned from the getDisplayConfigs should also be returned
+     * from getDisplayConfigurations.
      *
-     * @param display is the display to query.
-     *
-     * @return is an array of configuration handles.
-     *
-     * @exception EX_BAD_DISPLAY when an invalid display handle was passed in.
+     * @see getDisplayConfigurations
      */
     int[] getDisplayConfigs(long display);
 
@@ -864,4 +872,45 @@
      *        false when refresh rate callback is disabled.
      */
     void setRefreshRateChangedCallbackDebugEnabled(long display, boolean enabled);
+
+    /**
+     * Returns all of the valid display configurations.
+     * getDisplayConfigurations is the superset of getDisplayConfigs and
+     * getDisplayConfigs should return at least one config.
+     *
+     * @param display is the display for which the configurations are requested.
+     * @param maxFrameIntervalNs refers to the largest frameInterval to be set for
+     * VrrConfig.frameIntervalPowerHints in nanoseconds
+     *
+     * @see getDisplayConfigs
+     */
+    DisplayConfiguration[] getDisplayConfigurations(long display, int maxFrameIntervalNs);
+
+    /**
+     * Provides an early hint for a frame that is likely to be presented.
+     * This is used for the implementation to take the necessary steps to ensure that
+     * the next frame(s) could be presented as close as possible to the expectedPresentTime and
+     * according to the frameIntervalNs cadence.
+     * See DisplayCommand.expectedPresentTime and DisplayCommand.frameIntervalNs.
+     *
+     * The framework will call this function based on the parameters specified in
+     * DisplayConfiguration.VrrConfig:
+     * - notifyExpectedPresentConfig.timeoutNs specifies the idle time from the previous
+     * present command where the framework must send the early hint for the next frame.
+     * - notifyExpectedPresentConfig.headsUpNs specifies minimal time that framework must send
+     * the early hint before the next frame.
+     *
+     * The framework can omit calling this API when the next present command matches
+     * the cadence of the previous present command frameIntervalNs.
+     *
+     * If DisplayConfiguration.notifyExpectedPresentConfig is null, this function will never be
+     * called.
+     *
+     * @param display is the display for which the notifyExpectedPresent is called.
+     * @param expectedPresentTime is the expectedPresentTime that will be provided in the next
+     * present command
+     * @param frameIntervalNs is a hint about the cadence of the next frames in nanoseconds.
+     */
+    oneway void notifyExpectedPresent(
+            long display, in ClockMonotonicTimestamp expectedPresentTime, int frameIntervalNs);
 }
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/LayerCommand.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/LayerCommand.aidl
index fd50be9..e961c48 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/LayerCommand.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/LayerCommand.aidl
@@ -23,6 +23,7 @@
 import android.hardware.graphics.composer3.Buffer;
 import android.hardware.graphics.composer3.Color;
 import android.hardware.graphics.composer3.LayerBrightness;
+import android.hardware.graphics.composer3.LayerLifecycleBatchCommandType;
 import android.hardware.graphics.composer3.ParcelableBlendMode;
 import android.hardware.graphics.composer3.ParcelableComposition;
 import android.hardware.graphics.composer3.ParcelableDataspace;
@@ -265,4 +266,17 @@
      * be freed.
      */
     @nullable int[] bufferSlotsToClear;
+
+    /**
+     * Specifies if this layer command is on type modify, create or destroy.
+     * This command is replacing the older IComposerClient.createLayer and destroyLayer
+     * and making it more efficient with reduced aidls to the HAL.
+     * The HAL will report the errors by setting CommandResultPayload::CommandError.
+     */
+    LayerLifecycleBatchCommandType layerLifecycleBatchCommandType;
+
+    /**
+     * Specifies the number of buffer slot to be reserved.
+     */
+    int newBufferSlotCount;
 }
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/LayerLifecycleBatchCommandType.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/LayerLifecycleBatchCommandType.aidl
new file mode 100644
index 0000000..e619712
--- /dev/null
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/LayerLifecycleBatchCommandType.aidl
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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;
+
+/**
+ * Possible batch command types for a given layer.
+ */
+@VintfStability
+@Backing(type="int")
+enum LayerLifecycleBatchCommandType {
+    /**
+     * Layer attributes are being modified for already created layer.
+     */
+    MODIFY = 0,
+    /**
+     * This indicates that the current LayerCommand should also create the layer,
+     * before processing the other attributes in the LayerCommand.
+     */
+    CREATE = 1,
+    /**
+     * This indicates that the current LayerCommand should also destroy the layer,
+     * before processing the other attributes in the LayerCommand.
+     */
+    DESTROY = 2,
+}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/RefreshRateChangedDebugData.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/RefreshRateChangedDebugData.aidl
index c1f78d6..11c0112 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/RefreshRateChangedDebugData.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/RefreshRateChangedDebugData.aidl
@@ -27,4 +27,15 @@
      * The display vsync period in nanoseconds.
      */
     int vsyncPeriodNanos;
+
+    /**
+     * The refresh period of the display in nanoseconds.
+     * On VRR (Variable Refresh Rate) displays, refreshPeriodNanos can be different from the
+     * vsyncPeriodNanos because not every vsync cycle of the display is a refresh cycle.
+     * This should be set to the current refresh period.
+     * On non-VRR displays this value should be equal to vsyncPeriodNanos
+     *
+     * @see vsyncPeriodNanos
+     */
+    int refreshPeriodNanos;
 }
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/VrrConfig.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/VrrConfig.aidl
new file mode 100644
index 0000000..99c1c62
--- /dev/null
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/VrrConfig.aidl
@@ -0,0 +1,66 @@
+/**
+ * Copyright 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.composer3;
+
+@VintfStability
+parcelable VrrConfig {
+    /**
+     * The minimal time (in nanoseconds) that needs to pass between the previously presented frame
+     * and when the next frame can be presented.
+     */
+    int minFrameIntervalNs;
+
+    /**
+     * An optional mapping between frame intervals, and the physical display refresh period on
+     * average. This provides useful information to the framework when picking a specific frame rate
+     * (which is a divisor of the vsync rate) about the real display refresh rate, which could be
+     * used for power optimizations. The implementation should populate this map for frame rates
+     * that requires the display to run at a higher refresh rate due to self refresh frames. The
+     * lowest frame rate provided should be according to the parameter `maxFrameIntervalNs`
+     * specified in IComposerClient.getDisplayConfigurations, as the framework would generally not
+     * try to run at a lower frame rate.
+     */
+    parcelable FrameIntervalPowerHint {
+        int frameIntervalNs;
+        int averageRefreshPeriodNs;
+    }
+    @nullable FrameIntervalPowerHint[] frameIntervalPowerHints;
+
+    parcelable NotifyExpectedPresentConfig {
+        /**
+         * The minimal time in nanoseconds that IComposerClient.notifyExpectedPresent needs to be
+         * called ahead of an expectedPresentTime provided on a presentDisplay command.
+         */
+        int headsUpNs;
+
+        /**
+         * The time in nanoseconds that represents a timeout from the previous presentDisplay, which
+         * after this point the display needs a call to IComposerClient.notifyExpectedPresent before
+         * sending the next frame.
+         * If set to 0, hint is sent for every frame.
+         * IComposerClient.notifyExpectedPresent for timeout.
+         */
+        int timeoutNs;
+    }
+
+    /**
+     * Parameters for when to call IComposerClient.notifyExpectedPresent.
+     *
+     * When set to null, the framework will not call IComposerClient.notifyExpectedPresent.
+     */
+    @nullable NotifyExpectedPresentConfig notifyExpectedPresentConfig;
+}
diff --git a/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h
index 2e902e5..a1ccbfe 100644
--- a/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h
+++ b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h
@@ -29,6 +29,7 @@
 #include <aidl/android/hardware/graphics/composer3/Composition.h>
 #include <aidl/android/hardware/graphics/composer3/DisplayBrightness.h>
 #include <aidl/android/hardware/graphics/composer3/LayerBrightness.h>
+#include <aidl/android/hardware/graphics/composer3/LayerLifecycleBatchCommandType.h>
 #include <aidl/android/hardware/graphics/composer3/PerFrameMetadata.h>
 #include <aidl/android/hardware/graphics/composer3/PerFrameMetadataBlob.h>
 
@@ -83,11 +84,13 @@
     }
 
     void setClientTarget(int64_t display, uint32_t slot, const native_handle_t* target,
-                         int acquireFence, Dataspace dataspace, const std::vector<Rect>& damage) {
+                         int acquireFence, Dataspace dataspace, const std::vector<Rect>& damage,
+                         float hdrSdrRatio) {
         ClientTarget clientTargetCommand;
         clientTargetCommand.buffer = getBufferCommand(slot, target, acquireFence);
         clientTargetCommand.dataspace = dataspace;
         clientTargetCommand.damage.assign(damage.begin(), damage.end());
+        clientTargetCommand.hdrSdrRatio = hdrSdrRatio;
         getDisplayCommand(display).clientTarget.emplace(std::move(clientTargetCommand));
     }
 
@@ -97,18 +100,31 @@
                 getBufferCommand(slot, buffer, releaseFence));
     }
 
+    void setLayerLifecycleBatchCommandType(int64_t display, int64_t layer,
+                                           LayerLifecycleBatchCommandType cmd) {
+        getLayerCommand(display, layer).layerLifecycleBatchCommandType = cmd;
+    }
+
+    void setNewBufferSlotCount(int64_t display, int64_t layer, int32_t newBufferSlotToCount) {
+        getLayerCommand(display, layer).newBufferSlotCount = newBufferSlotToCount;
+    }
+
     void validateDisplay(int64_t display,
-                         std::optional<ClockMonotonicTimestamp> expectedPresentTime) {
+                         std::optional<ClockMonotonicTimestamp> expectedPresentTime,
+                         int32_t frameIntervalNs) {
         auto& command = getDisplayCommand(display);
         command.expectedPresentTime = expectedPresentTime;
         command.validateDisplay = true;
+        command.frameIntervalNs = frameIntervalNs;
     }
 
     void presentOrvalidateDisplay(int64_t display,
-                                  std::optional<ClockMonotonicTimestamp> expectedPresentTime) {
+                                  std::optional<ClockMonotonicTimestamp> expectedPresentTime,
+                                  int32_t frameIntervalNs) {
         auto& command = getDisplayCommand(display);
         command.expectedPresentTime = expectedPresentTime;
         command.presentOrValidateDisplay = true;
+        command.frameIntervalNs = frameIntervalNs;
     }
 
     void acceptDisplayChanges(int64_t display) {
diff --git a/graphics/composer/aidl/vts/Android.bp b/graphics/composer/aidl/vts/Android.bp
index 60360fd..d71999d 100644
--- a/graphics/composer/aidl/vts/Android.bp
+++ b/graphics/composer/aidl/vts/Android.bp
@@ -54,13 +54,6 @@
         "libgui",
         "libhidlbase",
         "libprocessgroup",
-        "android.hardware.graphics.mapper@2.0",
-        "android.hardware.graphics.mapper@2.1",
-        "android.hardware.graphics.mapper@3.0",
-        "android.hardware.graphics.mapper@4.0",
-        "android.hardware.graphics.allocator@2.0",
-        "android.hardware.graphics.allocator@3.0",
-        "android.hardware.graphics.allocator@4.0",
         "libvndksupport",
     ],
     header_libs: [
@@ -70,13 +63,6 @@
         "android.hardware.graphics.common@1.2",
         "android.hardware.common-V2-ndk",
         "android.hardware.common.fmq-V1-ndk",
-        "android.hardware.graphics.allocator@2.0",
-        "android.hardware.graphics.allocator@3.0",
-        "android.hardware.graphics.allocator@4.0",
-        "android.hardware.graphics.mapper@2.0-vts",
-        "android.hardware.graphics.mapper@2.1-vts",
-        "android.hardware.graphics.mapper@3.0-vts",
-        "android.hardware.graphics.mapper@4.0-vts",
         "libaidlcommonsupport",
         "libarect",
         "libbase",
diff --git a/graphics/composer/aidl/vts/GraphicsComposerCallback.cpp b/graphics/composer/aidl/vts/GraphicsComposerCallback.cpp
index 7b3a2b4..544f692 100644
--- a/graphics/composer/aidl/vts/GraphicsComposerCallback.cpp
+++ b/graphics/composer/aidl/vts/GraphicsComposerCallback.cpp
@@ -17,6 +17,7 @@
 #include "GraphicsComposerCallback.h"
 #include <log/log_main.h>
 #include <utils/Timers.h>
+#include <cinttypes>
 
 #pragma push_macro("LOG_TAG")
 #undef LOG_TAG
@@ -193,4 +194,18 @@
     return ::ndk::ScopedAStatus::ok();
 }
 
+::ndk::ScopedAStatus GraphicsComposerCallback::onHotplugEvent(int64_t in_display,
+                                                              common::DisplayHotplugEvent event) {
+    switch (event) {
+        case common::DisplayHotplugEvent::CONNECTED:
+            return onHotplug(in_display, true);
+        case common::DisplayHotplugEvent::DISCONNECTED:
+            return onHotplug(in_display, false);
+        default:
+            ALOGE("%s(): display:%" PRIu64 ", event:%d", __func__, in_display,
+                  static_cast<int32_t>(event));
+            return ::ndk::ScopedAStatus::ok();
+    }
+}
+
 }  // namespace aidl::android::hardware::graphics::composer3::vts
diff --git a/graphics/composer/aidl/vts/GraphicsComposerCallback.h b/graphics/composer/aidl/vts/GraphicsComposerCallback.h
index 13e992a..7a8d4a3 100644
--- a/graphics/composer/aidl/vts/GraphicsComposerCallback.h
+++ b/graphics/composer/aidl/vts/GraphicsComposerCallback.h
@@ -63,6 +63,8 @@
     virtual ::ndk::ScopedAStatus onVsyncIdle(int64_t in_display) override;
     virtual ::ndk::ScopedAStatus onRefreshRateChangedDebug(
             const RefreshRateChangedDebugData&) override;
+    virtual ::ndk::ScopedAStatus onHotplugEvent(int64_t in_display,
+                                                common::DisplayHotplugEvent) override;
 
     mutable std::mutex mMutex;
     // the set of all currently connected displays
diff --git a/graphics/composer/aidl/vts/ReadbackVts.cpp b/graphics/composer/aidl/vts/ReadbackVts.cpp
index abb58e2..c72ec69 100644
--- a/graphics/composer/aidl/vts/ReadbackVts.cpp
+++ b/graphics/composer/aidl/vts/ReadbackVts.cpp
@@ -35,6 +35,7 @@
     writer.setLayerPlaneAlpha(mDisplay, mLayer, mAlpha);
     writer.setLayerBlendMode(mDisplay, mLayer, mBlendMode);
     writer.setLayerBrightness(mDisplay, mLayer, mBrightness);
+    writer.setLayerDataspace(mDisplay, mLayer, mDataspace);
 }
 
 std::string ReadbackHelper::getColorModeString(ColorMode mode) {
@@ -99,6 +100,7 @@
 
     layerSettings.geometry.positionTransform = scale * translation;
     layerSettings.whitePointNits = mWhitePointNits;
+    layerSettings.sourceDataspace = static_cast<::android::ui::Dataspace>(mDataspace);
 
     return layerSettings;
 }
@@ -189,6 +191,23 @@
     }
 }
 
+void ReadbackHelper::compareColorBuffers(void* expectedBuffer, void* actualBuffer,
+                                         const uint32_t stride, const uint32_t width,
+                                         const uint32_t height, common::PixelFormat pixelFormat) {
+    const int32_t bytesPerPixel = ReadbackHelper::GetBytesPerPixel(pixelFormat);
+    ASSERT_NE(-1, bytesPerPixel);
+    for (int row = 0; row < height; row++) {
+        for (int col = 0; col < width; col++) {
+            int offset = (row * static_cast<int32_t>(stride) + col) * bytesPerPixel;
+            uint8_t* expectedColor = (uint8_t*)expectedBuffer + offset;
+            uint8_t* actualColor = (uint8_t*)actualBuffer + offset;
+            ASSERT_EQ(expectedColor[0], actualColor[0]);
+            ASSERT_EQ(expectedColor[1], actualColor[1]);
+            ASSERT_EQ(expectedColor[2], actualColor[2]);
+        }
+    }
+}
+
 ReadbackBuffer::ReadbackBuffer(int64_t display, const std::shared_ptr<VtsComposerClient>& client,
                                int32_t width, int32_t height, common::PixelFormat pixelFormat,
                                common::Dataspace dataspace)
@@ -248,6 +267,15 @@
     EXPECT_EQ(::android::OK, status);
 }
 
+::android::sp<::android::GraphicBuffer> ReadbackBuffer::getBuffer() {
+    const auto& [fenceStatus, bufferFence] = mComposerClient->getReadbackBufferFence(mDisplay);
+    EXPECT_TRUE(fenceStatus.isOk());
+    if (bufferFence.get() != -1) {
+        sync_wait(bufferFence.get(), -1);
+    }
+    return mGraphicBuffer;
+}
+
 void TestColorLayer::write(ComposerClientWriter& writer) {
     TestLayer::write(writer);
     writer.setLayerCompositionType(mDisplay, mLayer, Composition::SOLID_COLOR);
@@ -265,8 +293,8 @@
 TestBufferLayer::TestBufferLayer(const std::shared_ptr<VtsComposerClient>& client,
                                  TestRenderEngine& renderEngine, int64_t display, uint32_t width,
                                  uint32_t height, common::PixelFormat format,
-                                 Composition composition)
-    : TestLayer{client, display}, mRenderEngine(renderEngine) {
+                                 ComposerClientWriter& writer, Composition composition)
+    : TestLayer{client, display, writer}, mRenderEngine(renderEngine) {
     mComposition = composition;
     mWidth = width;
     mHeight = height;
@@ -344,10 +372,6 @@
             "TestBufferLayer");
 }
 
-void TestBufferLayer::setDataspace(common::Dataspace dataspace, ComposerClientWriter& writer) {
-    writer.setLayerDataspace(mDisplay, mLayer, dataspace);
-}
-
 void TestBufferLayer::setToClientComposition(ComposerClientWriter& writer) {
     writer.setLayerCompositionType(mDisplay, mLayer, Composition::CLIENT);
 }
diff --git a/graphics/composer/aidl/vts/ReadbackVts.h b/graphics/composer/aidl/vts/ReadbackVts.h
index ee9f0d5..8ac0f4b 100644
--- a/graphics/composer/aidl/vts/ReadbackVts.h
+++ b/graphics/composer/aidl/vts/ReadbackVts.h
@@ -20,7 +20,6 @@
 #include <android-base/unique_fd.h>
 #include <android/hardware/graphics/composer3/ComposerClientReader.h>
 #include <android/hardware/graphics/composer3/ComposerClientWriter.h>
-#include <mapper-vts/2.1/MapperVts.h>
 #include <renderengine/RenderEngine.h>
 #include <ui/GraphicBuffer.h>
 #include <memory>
@@ -32,7 +31,6 @@
 using ::android::renderengine::LayerSettings;
 using common::Dataspace;
 using common::PixelFormat;
-using IMapper2_1 = ::android::hardware::graphics::mapper::V2_1::IMapper;
 
 static const Color BLACK = {0.0f, 0.0f, 0.0f, 1.0f};
 static const Color RED = {1.0f, 0.0f, 0.0f, 1.0f};
@@ -44,14 +42,18 @@
 static const Color GREEN = {0.0f, 1.0f, 0.0f, 1.0f};
 static const Color BLUE = {0.0f, 0.0f, 1.0f, 1.0f};
 static const Color WHITE = {1.0f, 1.0f, 1.0f, 1.0f};
+static const Color LIGHT_RED = {0.5f, 0.0f, 0.0f, 1.0f};
+static const Color LIGHT_GREEN = {0.0f, 0.5f, 0.0f, 1.0f};
+static const Color LIGHT_BLUE = {0.0f, 0.0f, 0.5f, 1.0f};
 
 class TestRenderEngine;
 
 class TestLayer {
   public:
-    TestLayer(const std::shared_ptr<VtsComposerClient>& client, int64_t display)
+    TestLayer(const std::shared_ptr<VtsComposerClient>& client, int64_t display,
+              ComposerClientWriter& writer)
         : mDisplay(display) {
-        const auto& [status, layer] = client->createLayer(display, kBufferSlotCount);
+        const auto& [status, layer] = client->createLayer(display, kBufferSlotCount, &writer);
         EXPECT_TRUE(status.isOk());
         mLayer = layer;
     }
@@ -73,6 +75,8 @@
         mSurfaceDamage = std::move(surfaceDamage);
     }
 
+    void setDataspace(Dataspace dataspace) { mDataspace = dataspace; }
+
     void setTransform(Transform transform) { mTransform = transform; }
     void setAlpha(float alpha) { mAlpha = alpha; }
     void setBlendMode(BlendMode blendMode) { mBlendMode = blendMode; }
@@ -100,12 +104,14 @@
     float mAlpha = 1.0;
     BlendMode mBlendMode = BlendMode::NONE;
     uint32_t mZOrder = 0;
+    Dataspace mDataspace = Dataspace::UNKNOWN;
 };
 
 class TestColorLayer : public TestLayer {
   public:
-    TestColorLayer(const std::shared_ptr<VtsComposerClient>& client, int64_t display)
-        : TestLayer{client, display} {}
+    TestColorLayer(const std::shared_ptr<VtsComposerClient>& client, int64_t display,
+                   ComposerClientWriter& writer)
+        : TestLayer{client, display, writer} {}
 
     void write(ComposerClientWriter& writer) override;
 
@@ -121,7 +127,7 @@
   public:
     TestBufferLayer(const std::shared_ptr<VtsComposerClient>& client,
                     TestRenderEngine& renderEngine, int64_t display, uint32_t width,
-                    uint32_t height, common::PixelFormat format,
+                    uint32_t height, common::PixelFormat format, ComposerClientWriter& writer,
                     Composition composition = Composition::DEVICE);
 
     void write(ComposerClientWriter& writer) override;
@@ -132,8 +138,6 @@
 
     void setBuffer(std::vector<Color> colors);
 
-    void setDataspace(Dataspace dataspace, ComposerClientWriter& writer);
-
     void setToClientComposition(ComposerClientWriter& writer);
 
     uint32_t getWidth() const { return mWidth; }
@@ -187,6 +191,9 @@
     static void compareColorBuffers(const std::vector<Color>& expectedColors, void* bufferData,
                                     const uint32_t stride, const uint32_t width,
                                     const uint32_t height, PixelFormat pixelFormat);
+    static void compareColorBuffers(void* expectedBuffer, void* actualBuffer, const uint32_t stride,
+                                    const uint32_t width, const uint32_t height,
+                                    PixelFormat pixelFormat);
 };
 
 class ReadbackBuffer {
@@ -198,6 +205,8 @@
 
     void checkReadbackBuffer(const std::vector<Color>& expectedColors);
 
+    ::android::sp<::android::GraphicBuffer> getBuffer();
+
   protected:
     uint32_t mWidth;
     uint32_t mHeight;
diff --git a/graphics/composer/aidl/vts/RenderEngineVts.cpp b/graphics/composer/aidl/vts/RenderEngineVts.cpp
index 66779c8..4e7f773 100644
--- a/graphics/composer/aidl/vts/RenderEngineVts.cpp
+++ b/graphics/composer/aidl/vts/RenderEngineVts.cpp
@@ -19,7 +19,6 @@
 
 namespace aidl::android::hardware::graphics::composer3::vts {
 
-using ::android::hardware::graphics::mapper::V2_1::IMapper;
 using ::android::renderengine::DisplaySettings;
 using ::android::renderengine::LayerSettings;
 using ::android::renderengine::RenderEngineCreationArgs;
@@ -67,7 +66,7 @@
             mGraphicBuffer, *mRenderEngine,
             ::android::renderengine::impl::ExternalTexture::Usage::WRITEABLE);
     auto result = mRenderEngine
-                          ->drawLayers(mDisplaySettings, compositionLayers, texture, true,
+                          ->drawLayers(mDisplaySettings, compositionLayers, texture,
                                        std::move(bufferFence))
                           .get();
     if (result.ok()) {
@@ -90,4 +89,32 @@
     ASSERT_EQ(::android::OK, mGraphicBuffer->unlock());
 }
 
+void TestRenderEngine::checkColorBuffer(const ::android::sp<::android::GraphicBuffer>& buffer) {
+    ASSERT_EQ(mGraphicBuffer->getWidth(), buffer->getWidth());
+    ASSERT_EQ(mGraphicBuffer->getHeight(), buffer->getHeight());
+    void* renderedBufferData;
+    int32_t bytesPerPixel = -1;
+    int32_t bytesPerStride = -1;
+    ASSERT_EQ(0, mGraphicBuffer->lock(static_cast<uint32_t>(mGraphicBuffer->getUsage()),
+                                      &renderedBufferData, &bytesPerPixel, &bytesPerStride));
+    const uint32_t renderedStride = (bytesPerPixel > 0 && bytesPerStride > 0)
+                                            ? static_cast<uint32_t>(bytesPerStride / bytesPerPixel)
+                                            : mGraphicBuffer->getStride();
+
+    void* bufferData;
+    ASSERT_EQ(0, buffer->lock(static_cast<uint32_t>(buffer->getUsage()), &bufferData,
+                              &bytesPerPixel, &bytesPerStride));
+    const uint32_t bufferStride = (bytesPerPixel > 0 && bytesPerStride > 0)
+                                          ? static_cast<uint32_t>(bytesPerStride / bytesPerPixel)
+                                          : buffer->getStride();
+
+    ASSERT_EQ(renderedStride, bufferStride);
+
+    ReadbackHelper::compareColorBuffers(renderedBufferData, bufferData, bufferStride,
+                                        mGraphicBuffer->getWidth(), mGraphicBuffer->getHeight(),
+                                        mFormat);
+    ASSERT_EQ(::android::OK, buffer->unlock());
+    ASSERT_EQ(::android::OK, mGraphicBuffer->unlock());
+}
+
 }  // namespace aidl::android::hardware::graphics::composer3::vts
diff --git a/graphics/composer/aidl/vts/RenderEngineVts.h b/graphics/composer/aidl/vts/RenderEngineVts.h
index 43d3a42..bbe508f 100644
--- a/graphics/composer/aidl/vts/RenderEngineVts.h
+++ b/graphics/composer/aidl/vts/RenderEngineVts.h
@@ -15,13 +15,11 @@
  */
 #pragma once
 
-#include <mapper-vts/2.1/MapperVts.h>
 #include <math/half.h>
 #include <math/vec3.h>
 #include <renderengine/ExternalTexture.h>
 #include <renderengine/RenderEngine.h>
 #include <ui/GraphicBuffer.h>
-#include <ui/GraphicBufferAllocator.h>
 #include <ui/PixelFormat.h>
 #include <ui/Rect.h>
 #include <ui/Region.h>
@@ -29,7 +27,6 @@
 
 namespace aidl::android::hardware::graphics::composer3::vts {
 
-using ::android::hardware::graphics::mapper::V2_1::IMapper;
 using ::android::renderengine::DisplaySettings;
 using ::android::renderengine::ExternalTexture;
 using ::android::renderengine::RenderEngineCreationArgs;
@@ -48,6 +45,7 @@
     };
     void drawLayers();
     void checkColorBuffer(const std::vector<Color>& expectedColors);
+    void checkColorBuffer(const ::android::sp<::android::GraphicBuffer>& buffer);
 
     ::android::renderengine::RenderEngine& getInternalRenderEngine() { return *mRenderEngine; }
 
diff --git a/graphics/composer/aidl/vts/VtsComposerClient.cpp b/graphics/composer/aidl/vts/VtsComposerClient.cpp
index 25b0ca0..89ba2e6 100644
--- a/graphics/composer/aidl/vts/VtsComposerClient.cpp
+++ b/graphics/composer/aidl/vts/VtsComposerClient.cpp
@@ -33,6 +33,14 @@
         mComposer = IComposer::fromBinder(binder);
         ALOGE_IF(mComposer == nullptr, "Failed to acquire the composer from the binder");
     }
+
+    const auto& [status, capabilities] = getCapabilities();
+    EXPECT_TRUE(status.isOk());
+    if (std::any_of(capabilities.begin(), capabilities.end(), [&](const Capability& cap) {
+            return cap == Capability::LAYER_LIFECYCLE_BATCH_COMMAND;
+        })) {
+        mSupportsBatchedCreateLayer = true;
+    }
 }
 
 ScopedAStatus VtsComposerClient::createClient() {
@@ -54,12 +62,15 @@
     return mComposerClient->registerCallback(mComposerCallback);
 }
 
-bool VtsComposerClient::tearDown() {
-    return verifyComposerCallbackParams() && destroyAllLayers();
+bool VtsComposerClient::tearDown(ComposerClientWriter* writer) {
+    return verifyComposerCallbackParams() && destroyAllLayers(writer);
 }
 
-std::pair<ScopedAStatus, int32_t> VtsComposerClient::getInterfaceVersion() {
+std::pair<ScopedAStatus, int32_t> VtsComposerClient::getInterfaceVersion() const {
     int32_t version = 1;
+    if (!mComposerClient) {
+        return {ScopedAStatus{nullptr}, version};
+    }
     auto status = mComposerClient->getInterfaceVersion(&version);
     return {std::move(status), version};
 }
@@ -86,7 +97,16 @@
 }
 
 std::pair<ScopedAStatus, int64_t> VtsComposerClient::createLayer(int64_t display,
-                                                                 int32_t bufferSlotCount) {
+                                                                 int32_t bufferSlotCount,
+                                                                 ComposerClientWriter* writer) {
+    if (mSupportsBatchedCreateLayer) {
+        int64_t layer = mNextLayerHandle++;
+        writer->setLayerLifecycleBatchCommandType(display, layer,
+                                                  LayerLifecycleBatchCommandType::CREATE);
+        writer->setNewBufferSlotCount(display, layer, bufferSlotCount);
+        return {addLayerToDisplayResources(display, layer), layer};
+    }
+
     int64_t outLayer;
     auto status = mComposerClient->createLayer(display, bufferSlotCount, &outLayer);
 
@@ -96,14 +116,20 @@
     return {addLayerToDisplayResources(display, outLayer), outLayer};
 }
 
-ScopedAStatus VtsComposerClient::destroyLayer(int64_t display, int64_t layer) {
-    auto status = mComposerClient->destroyLayer(display, layer);
-
-    if (!status.isOk()) {
-        return status;
+ScopedAStatus VtsComposerClient::destroyLayer(int64_t display, int64_t layer,
+                                              ComposerClientWriter* writer) {
+    if (mSupportsBatchedCreateLayer) {
+        writer->setLayerLifecycleBatchCommandType(display, layer,
+                                                  LayerLifecycleBatchCommandType::DESTROY);
+    } else {
+        auto status = mComposerClient->destroyLayer(display, layer);
+        if (!status.isOk()) {
+            return status;
+        }
     }
+
     removeLayerFromDisplayResources(display, layer);
-    return status;
+    return ScopedAStatus::ok();
 }
 
 std::pair<ScopedAStatus, int32_t> VtsComposerClient::getActiveConfig(int64_t display) {
@@ -295,7 +321,31 @@
 std::pair<ScopedAStatus, std::vector<int32_t>> VtsComposerClient::getDisplayConfigs(
         int64_t display) {
     std::vector<int32_t> outConfigs;
-    return {mComposerClient->getDisplayConfigs(display, &outConfigs), outConfigs};
+    if (!getDisplayConfigurationSupported()) {
+        return {mComposerClient->getDisplayConfigs(display, &outConfigs), outConfigs};
+    }
+
+    auto [status, configs] = getDisplayConfigurations(display);
+    if (!status.isOk()) {
+        return {std::move(status), outConfigs};
+    }
+    for (const auto& config : configs) {
+        outConfigs.emplace_back(config.configId);
+    }
+    return {std::move(status), outConfigs};
+}
+
+std::pair<ScopedAStatus, std::vector<DisplayConfiguration>>
+VtsComposerClient::getDisplayConfigurations(int64_t display) {
+    std::vector<DisplayConfiguration> outConfigs;
+    return {mComposerClient->getDisplayConfigurations(display, kMaxFrameIntervalNs, &outConfigs),
+            outConfigs};
+}
+
+ScopedAStatus VtsComposerClient::notifyExpectedPresent(int64_t display,
+                                                       ClockMonotonicTimestamp expectedPresentTime,
+                                                       int frameIntervalNs) {
+    return mComposerClient->notifyExpectedPresent(display, expectedPresentTime, frameIntervalNs);
 }
 
 std::pair<ScopedAStatus, int32_t> VtsComposerClient::getDisplayVsyncPeriod(int64_t display) {
@@ -439,31 +489,41 @@
         vtsDisplays.reserve(displays.size());
         for (int64_t display : displays) {
             auto vtsDisplay = VtsDisplay{display};
-            auto configs = getDisplayConfigs(display);
-            if (!configs.first.isOk()) {
-                ALOGE("Unable to get the displays for test, failed to get the configs "
-                      "for display %" PRId64,
-                      display);
-                return {std::move(configs.first), vtsDisplays};
-            }
-            for (int config : configs.second) {
-                auto status = addDisplayConfig(&vtsDisplay, config);
+            if (getDisplayConfigurationSupported()) {
+                auto [status, configs] = getDisplayConfigurations(display);
                 if (!status.isOk()) {
-                    ALOGE("Unable to get the displays for test, failed to add config "
+                    ALOGE("Unable to get the displays for test, failed to get the DisplayConfigs "
                           "for display %" PRId64,
                           display);
                     return {std::move(status), vtsDisplays};
                 }
+                addDisplayConfigs(&vtsDisplay, configs);
+            } else {
+                auto [status, configs] = getDisplayConfigs(display);
+                if (!status.isOk()) {
+                    ALOGE("Unable to get the displays for test, failed to get the configs "
+                          "for display %" PRId64,
+                          display);
+                    return {std::move(status), vtsDisplays};
+                }
+                for (int config : configs) {
+                    status = addDisplayConfigLegacy(&vtsDisplay, config);
+                    if (!status.isOk()) {
+                        ALOGE("Unable to get the displays for test, failed to add config "
+                              "for display %" PRId64,
+                              display);
+                        return {std::move(status), vtsDisplays};
+                    }
+                }
             }
-
-            auto config = getActiveConfig(display);
-            if (!config.first.isOk()) {
+            auto activeConfig = getActiveConfig(display);
+            if (!activeConfig.first.isOk()) {
                 ALOGE("Unable to get the displays for test, failed to get active config "
-                      "for display %" PRId64, display);
-                return {std::move(config.first), vtsDisplays};
+                      "for display %" PRId64,
+                      display);
+                return {std::move(activeConfig.first), vtsDisplays};
             }
-
-            auto status = updateDisplayProperties(&vtsDisplay, config.second);
+            auto status = updateDisplayProperties(&vtsDisplay, activeConfig.second);
             if (!status.isOk()) {
                 ALOGE("Unable to get the displays for test, "
                       "failed to update the properties "
@@ -480,39 +540,54 @@
     }
 }
 
-ScopedAStatus VtsComposerClient::addDisplayConfig(VtsDisplay* vtsDisplay, int32_t config) {
-    const auto width =
-            getDisplayAttribute(vtsDisplay->getDisplayId(), config, DisplayAttribute::WIDTH);
-    const auto height =
-            getDisplayAttribute(vtsDisplay->getDisplayId(), config, DisplayAttribute::HEIGHT);
+void VtsComposerClient::addDisplayConfigs(VtsDisplay* vtsDisplay,
+                                          const std::vector<DisplayConfiguration>& configs) {
+    for (const auto& config : configs) {
+        vtsDisplay->addDisplayConfig(config.configId,
+                                     {config.vsyncPeriod, config.configGroup, config.vrrConfig});
+    }
+}
+
+ScopedAStatus VtsComposerClient::addDisplayConfigLegacy(VtsDisplay* vtsDisplay, int32_t config) {
     const auto vsyncPeriod =
             getDisplayAttribute(vtsDisplay->getDisplayId(), config, DisplayAttribute::VSYNC_PERIOD);
     const auto configGroup =
             getDisplayAttribute(vtsDisplay->getDisplayId(), config, DisplayAttribute::CONFIG_GROUP);
-    if (width.first.isOk() && height.first.isOk() && vsyncPeriod.first.isOk() &&
-        configGroup.first.isOk()) {
+    if (vsyncPeriod.first.isOk() && configGroup.first.isOk()) {
         vtsDisplay->addDisplayConfig(config, {vsyncPeriod.second, configGroup.second});
         return ScopedAStatus::ok();
     }
 
-    LOG(ERROR) << "Failed to update display property for width: " << width.first.isOk()
-               << ", height: " << height.first.isOk() << ", vsync: " << vsyncPeriod.first.isOk()
+    LOG(ERROR) << "Failed to update display property vsync: " << vsyncPeriod.first.isOk()
                << ", config: " << configGroup.first.isOk();
     return ScopedAStatus::fromServiceSpecificError(IComposerClient::EX_BAD_CONFIG);
 }
 
 ScopedAStatus VtsComposerClient::updateDisplayProperties(VtsDisplay* vtsDisplay, int32_t config) {
-    const auto width =
-            getDisplayAttribute(vtsDisplay->getDisplayId(), config, DisplayAttribute::WIDTH);
-    const auto height =
-            getDisplayAttribute(vtsDisplay->getDisplayId(), config, DisplayAttribute::HEIGHT);
-    if (width.first.isOk() && height.first.isOk()) {
-        vtsDisplay->setDimensions(width.second, height.second);
-        return ScopedAStatus::ok();
-    }
+    if (getDisplayConfigurationSupported()) {
+        auto [status, configs] = getDisplayConfigurations(vtsDisplay->getDisplayId());
+        if (status.isOk()) {
+            for (const auto& displayConfig : configs) {
+                if (displayConfig.configId == config) {
+                    vtsDisplay->setDimensions(displayConfig.width, displayConfig.height);
+                    return ScopedAStatus::ok();
+                }
+            }
+        }
+        LOG(ERROR) << "Failed to update display property with DisplayConfig";
+    } else {
+        const auto width =
+                getDisplayAttribute(vtsDisplay->getDisplayId(), config, DisplayAttribute::WIDTH);
+        const auto height =
+                getDisplayAttribute(vtsDisplay->getDisplayId(), config, DisplayAttribute::HEIGHT);
+        if (width.first.isOk() && height.first.isOk()) {
+            vtsDisplay->setDimensions(width.second, height.second);
+            return ScopedAStatus::ok();
+        }
 
-    LOG(ERROR) << "Failed to update display property for width: " << width.first.isOk()
-               << ", height: " << height.first.isOk();
+        LOG(ERROR) << "Failed to update display property for width: " << width.first.isOk()
+                   << ", height: " << height.first.isOk();
+    }
     return ScopedAStatus::fromServiceSpecificError(IComposerClient::EX_BAD_CONFIG);
 }
 
@@ -576,7 +651,14 @@
     return isValid;
 }
 
-bool VtsComposerClient::destroyAllLayers() {
+bool VtsComposerClient::getDisplayConfigurationSupported() const {
+    auto [status, interfaceVersion] = getInterfaceVersion();
+    EXPECT_TRUE(status.isOk());
+    // getDisplayConfigurations api is supported starting interface version 3
+    return interfaceVersion >= 3;
+}
+
+bool VtsComposerClient::destroyAllLayers(ComposerClientWriter* writer) {
     std::unordered_map<int64_t, DisplayResource> physicalDisplays;
     while (!mDisplayResources.empty()) {
         const auto& it = mDisplayResources.begin();
@@ -584,7 +666,7 @@
 
         while (!resource.layers.empty()) {
             auto layer = *resource.layers.begin();
-            const auto status = destroyLayer(display, layer);
+            const auto status = destroyLayer(display, layer, writer);
             if (!status.isOk()) {
                 ALOGE("Unable to destroy all the layers, failed at layer %" PRId64 " with error %s",
                       layer, status.getDescription().c_str());
diff --git a/graphics/composer/aidl/vts/VtsComposerClient.h b/graphics/composer/aidl/vts/VtsComposerClient.h
index ea3318c..fabc82a 100644
--- a/graphics/composer/aidl/vts/VtsComposerClient.h
+++ b/graphics/composer/aidl/vts/VtsComposerClient.h
@@ -25,6 +25,7 @@
 #include <android/binder_manager.h>
 #include <android/binder_process.h>
 #include <android/hardware/graphics/composer3/ComposerClientReader.h>
+#include <android/hardware/graphics/composer3/ComposerClientWriter.h>
 #include <binder/ProcessState.h>
 #include <gtest/gtest.h>
 #include <ui/Fence.h>
@@ -59,9 +60,9 @@
 
     ScopedAStatus createClient();
 
-    bool tearDown();
+    bool tearDown(ComposerClientWriter*);
 
-    std::pair<ScopedAStatus, int32_t> getInterfaceVersion();
+    std::pair<ScopedAStatus, int32_t> getInterfaceVersion() const;
 
     std::pair<ScopedAStatus, VirtualDisplay> createVirtualDisplay(int32_t width, int32_t height,
                                                                   PixelFormat pixelFormat,
@@ -69,9 +70,10 @@
 
     ScopedAStatus destroyVirtualDisplay(int64_t display);
 
-    std::pair<ScopedAStatus, int64_t> createLayer(int64_t display, int32_t bufferSlotCount);
+    std::pair<ScopedAStatus, int64_t> createLayer(int64_t display, int32_t bufferSlotCount,
+                                                  ComposerClientWriter*);
 
-    ScopedAStatus destroyLayer(int64_t display, int64_t layer);
+    ScopedAStatus destroyLayer(int64_t display, int64_t layer, ComposerClientWriter*);
 
     std::pair<ScopedAStatus, int32_t> getActiveConfig(int64_t display);
 
@@ -142,6 +144,13 @@
 
     std::pair<ScopedAStatus, std::vector<int32_t>> getDisplayConfigs(int64_t display);
 
+    std::pair<ScopedAStatus, std::vector<DisplayConfiguration>> getDisplayConfigurations(
+            int64_t display);
+
+    ScopedAStatus notifyExpectedPresent(int64_t display,
+                                        ClockMonotonicTimestamp expectedPresentTime,
+                                        int frameIntervalNs);
+
     std::pair<ScopedAStatus, int32_t> getDisplayVsyncPeriod(int64_t display);
 
     ScopedAStatus setAutoLowLatencyMode(int64_t display, bool isEnabled);
@@ -189,8 +198,13 @@
 
     std::vector<RefreshRateChangedDebugData> takeListOfRefreshRateChangedDebugData();
 
+    static constexpr int32_t kMaxFrameIntervalNs = 50000000;  // 20fps
+    static constexpr int32_t kNoFrameIntervalNs = 0;
+
   private:
-    ScopedAStatus addDisplayConfig(VtsDisplay* vtsDisplay, int32_t config);
+    void addDisplayConfigs(VtsDisplay*, const std::vector<DisplayConfiguration>&);
+    ScopedAStatus addDisplayConfigLegacy(VtsDisplay*, int32_t config);
+    bool getDisplayConfigurationSupported() const;
     ScopedAStatus updateDisplayProperties(VtsDisplay* vtsDisplay, int32_t config);
 
     ScopedAStatus addDisplayToDisplayResources(int64_t display, bool isVirtual);
@@ -199,7 +213,7 @@
 
     void removeLayerFromDisplayResources(int64_t display, int64_t layer);
 
-    bool destroyAllLayers();
+    bool destroyAllLayers(ComposerClientWriter*);
 
     bool verifyComposerCallbackParams();
 
@@ -217,6 +231,8 @@
     std::shared_ptr<IComposerClient> mComposerClient;
     std::shared_ptr<GraphicsComposerCallback> mComposerCallback;
     std::unordered_map<int64_t, DisplayResource> mDisplayResources;
+    bool mSupportsBatchedCreateLayer = false;
+    std::atomic<int64_t> mNextLayerHandle = 1;
 };
 
 class VtsDisplay {
@@ -241,10 +257,14 @@
     int32_t getDisplayHeight() const { return mDisplayHeight; }
 
     struct DisplayConfig {
-        DisplayConfig(int32_t vsyncPeriod_, int32_t configGroup_)
-            : vsyncPeriod(vsyncPeriod_), configGroup(configGroup_) {}
+        DisplayConfig(int32_t vsyncPeriod_, int32_t configGroup_,
+                      std::optional<VrrConfig> vrrConfig_ = {})
+            : vsyncPeriod(vsyncPeriod_),
+              configGroup(configGroup_),
+              vrrConfig(std::move(vrrConfig_)) {}
         int32_t vsyncPeriod;
         int32_t configGroup;
+        std::optional<VrrConfig> vrrConfig;
     };
 
     void addDisplayConfig(int32_t config, DisplayConfig displayConfig) {
diff --git a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
index 9b849cc..3f82925 100644
--- a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
+++ b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
@@ -64,16 +64,15 @@
                         ::android::renderengine::RenderEngineCreationArgs::Builder()
                                 .setPixelFormat(static_cast<int>(common::PixelFormat::RGBA_8888))
                                 .setImageCacheSize(TestRenderEngine::sMaxFrameBufferAcquireBuffers)
-                                .setUseColorManagerment(true)
                                 .setEnableProtectedContext(false)
                                 .setPrecacheToneMapperShaderOnly(false)
                                 .setContextPriority(::android::renderengine::RenderEngine::
                                                             ContextPriority::HIGH)
                                 .build())));
 
-        ::android::renderengine::DisplaySettings clientCompositionDisplay;
-        clientCompositionDisplay.physicalDisplay = Rect(getDisplayWidth(), getDisplayHeight());
-        clientCompositionDisplay.clip = clientCompositionDisplay.physicalDisplay;
+        mClientCompositionDisplaySettings.physicalDisplay =
+                Rect(getDisplayWidth(), getDisplayHeight());
+        mClientCompositionDisplaySettings.clip = mClientCompositionDisplaySettings.physicalDisplay;
 
         mTestRenderEngine->initGraphicBuffer(
                 static_cast<uint32_t>(getDisplayWidth()), static_cast<uint32_t>(getDisplayHeight()),
@@ -82,12 +81,13 @@
                         static_cast<uint64_t>(common::BufferUsage::CPU_READ_OFTEN) |
                         static_cast<uint64_t>(common::BufferUsage::CPU_WRITE_OFTEN) |
                         static_cast<uint64_t>(common::BufferUsage::GPU_RENDER_TARGET)));
-        mTestRenderEngine->setDisplaySettings(clientCompositionDisplay);
+        mTestRenderEngine->setDisplaySettings(mClientCompositionDisplaySettings);
     }
 
     void TearDown() override {
+        ASSERT_FALSE(mDisplays.empty());
         ASSERT_TRUE(mComposerClient->setPowerMode(getPrimaryDisplayId(), PowerMode::OFF).isOk());
-        ASSERT_TRUE(mComposerClient->tearDown());
+        ASSERT_TRUE(mComposerClient->tearDown(mWriter.get()));
         mComposerClient.reset();
         const auto errors = mReader.takeErrors();
         ASSERT_TRUE(mReader.takeErrors().empty());
@@ -164,6 +164,7 @@
     std::unique_ptr<TestRenderEngine> mTestRenderEngine;
     common::PixelFormat mPixelFormat;
     common::Dataspace mDataspace;
+    ::android::renderengine::DisplaySettings mClientCompositionDisplaySettings;
 
     static constexpr uint32_t kClientTargetSlotCount = 64;
 
@@ -201,7 +202,8 @@
             return;
         }
 
-        auto layer = std::make_shared<TestColorLayer>(mComposerClient, getPrimaryDisplayId());
+        auto layer =
+                std::make_shared<TestColorLayer>(mComposerClient, getPrimaryDisplayId(), *mWriter);
         common::Rect coloredSquare({0, 0, getDisplayWidth(), getDisplayHeight()});
         layer->setColor(BLUE);
         layer->setDisplayFrame(coloredSquare);
@@ -220,7 +222,8 @@
 
         writeLayers(layers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp,
+                                 VtsComposerClient::kNoFrameIntervalNs);
         execute();
         // if hwc cannot handle and asks for composition change,
         // just succeed the test
@@ -269,17 +272,18 @@
 
         auto layer = std::make_shared<TestBufferLayer>(
                 mComposerClient, *mTestRenderEngine, getPrimaryDisplayId(), getDisplayWidth(),
-                getDisplayHeight(), common::PixelFormat::RGBA_8888);
+                getDisplayHeight(), common::PixelFormat::RGBA_8888, *mWriter);
         layer->setDisplayFrame({0, 0, getDisplayWidth(), getDisplayHeight()});
         layer->setZOrder(10);
-        layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), *mWriter);
+        layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode));
         ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors));
 
         std::vector<std::shared_ptr<TestLayer>> layers = {layer};
 
         writeLayers(layers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp,
+                                 VtsComposerClient::kNoFrameIntervalNs);
         execute();
 
         if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
@@ -313,7 +317,8 @@
             return;
         }
 
-        auto layer = std::make_shared<TestColorLayer>(mComposerClient, getPrimaryDisplayId());
+        auto layer =
+                std::make_shared<TestColorLayer>(mComposerClient, getPrimaryDisplayId(), *mWriter);
         common::Rect coloredSquare({0, 0, getDisplayWidth(), getDisplayHeight()});
         layer->setColor(BLUE);
         layer->setDisplayFrame(coloredSquare);
@@ -338,7 +343,8 @@
                                       getDisplayHeight(), mPixelFormat, mDataspace);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
-        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp,
+                                 VtsComposerClient::kNoFrameIntervalNs);
         execute();
 
         if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
@@ -451,12 +457,12 @@
                 expectedColors, getDisplayWidth(),
                 {0, getDisplayHeight() / 2, getDisplayWidth(), getDisplayHeight()}, BLUE);
 
-        auto layer = std::make_shared<TestBufferLayer>(mComposerClient, *mTestRenderEngine,
-                                                       getPrimaryDisplayId(), getDisplayWidth(),
-                                                       getDisplayHeight(), PixelFormat::RGBA_FP16);
+        auto layer = std::make_shared<TestBufferLayer>(
+                mComposerClient, *mTestRenderEngine, getPrimaryDisplayId(), getDisplayWidth(),
+                getDisplayHeight(), PixelFormat::RGBA_FP16, *mWriter);
         layer->setDisplayFrame({0, 0, getDisplayWidth(), getDisplayHeight()});
         layer->setZOrder(10);
-        layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), *mWriter);
+        layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode));
 
         std::vector<std::shared_ptr<TestLayer>> layers = {layer};
 
@@ -465,7 +471,8 @@
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
         writeLayers(layers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp,
+                                 VtsComposerClient::kNoFrameIntervalNs);
         execute();
 
         auto changedCompositionTypes = mReader.takeChangedCompositionTypes(getPrimaryDisplayId());
@@ -496,9 +503,10 @@
             const auto unlockStatus = graphicBuffer->unlockAsync(&clientFence);
             ASSERT_EQ(::android::OK, unlockStatus);
             mWriter->setClientTarget(getPrimaryDisplayId(), /*slot*/ 0, buffer, clientFence,
-                                     clientDataspace, std::vector<common::Rect>(1, damage));
+                                     clientDataspace, std::vector<common::Rect>(1, damage), 1.f);
             layer->setToClientComposition(*mWriter);
-            mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+            mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp,
+                                     VtsComposerClient::kNoFrameIntervalNs);
             execute();
             changedCompositionTypes = mReader.takeChangedCompositionTypes(getPrimaryDisplayId());
             ASSERT_TRUE(changedCompositionTypes.empty());
@@ -545,7 +553,7 @@
 
         auto deviceLayer = std::make_shared<TestBufferLayer>(
                 mComposerClient, *mTestRenderEngine, getPrimaryDisplayId(), getDisplayWidth(),
-                getDisplayHeight() / 2, PixelFormat::RGBA_8888);
+                getDisplayHeight() / 2, PixelFormat::RGBA_8888, *mWriter);
         std::vector<Color> deviceColors(deviceLayer->getWidth() * deviceLayer->getHeight());
         ReadbackHelper::fillColorsArea(deviceColors, static_cast<int32_t>(deviceLayer->getWidth()),
                                        {0, 0, static_cast<int32_t>(deviceLayer->getWidth()),
@@ -554,7 +562,7 @@
         deviceLayer->setDisplayFrame({0, 0, static_cast<int32_t>(deviceLayer->getWidth()),
                                       static_cast<int32_t>(deviceLayer->getHeight())});
         deviceLayer->setZOrder(10);
-        deviceLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), *mWriter);
+        deviceLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode));
         ASSERT_NO_FATAL_FAILURE(deviceLayer->setBuffer(deviceColors));
         deviceLayer->write(*mWriter);
 
@@ -569,13 +577,14 @@
 
         auto clientLayer = std::make_shared<TestBufferLayer>(
                 mComposerClient, *mTestRenderEngine, getPrimaryDisplayId(), clientWidth,
-                clientHeight, PixelFormat::RGBA_FP16, Composition::DEVICE);
+                clientHeight, PixelFormat::RGBA_FP16, *mWriter, Composition::DEVICE);
         common::Rect clientFrame = {0, getDisplayHeight() / 2, getDisplayWidth(),
                                     getDisplayHeight()};
         clientLayer->setDisplayFrame(clientFrame);
         clientLayer->setZOrder(0);
         clientLayer->write(*mWriter);
-        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp,
+                                 VtsComposerClient::kNoFrameIntervalNs);
         execute();
 
         auto changedCompositionTypes = mReader.takeChangedCompositionTypes(getPrimaryDisplayId());
@@ -602,9 +611,10 @@
         const auto unlockStatus = graphicBuffer->unlockAsync(&clientFence);
         ASSERT_EQ(::android::OK, unlockStatus);
         mWriter->setClientTarget(getPrimaryDisplayId(), /*slot*/ 0, buffer, clientFence,
-                                 clientDataspace, std::vector<common::Rect>(1, clientFrame));
+                                 clientDataspace, std::vector<common::Rect>(1, clientFrame), 1.f);
         clientLayer->setToClientComposition(*mWriter);
-        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp,
+                                 VtsComposerClient::kNoFrameIntervalNs);
         execute();
         changedCompositionTypes = mReader.takeChangedCompositionTypes(getPrimaryDisplayId());
         ASSERT_TRUE(changedCompositionTypes.empty());
@@ -636,12 +646,12 @@
                 static_cast<size_t>(getDisplayWidth() * getDisplayHeight()));
         ReadbackHelper::fillColorsArea(expectedColors, getDisplayWidth(), redRect, RED);
 
-        auto layer = std::make_shared<TestBufferLayer>(mComposerClient, *mTestRenderEngine,
-                                                       getPrimaryDisplayId(), getDisplayWidth(),
-                                                       getDisplayHeight(), PixelFormat::RGBA_8888);
+        auto layer = std::make_shared<TestBufferLayer>(
+                mComposerClient, *mTestRenderEngine, getPrimaryDisplayId(), getDisplayWidth(),
+                getDisplayHeight(), PixelFormat::RGBA_8888, *mWriter);
         layer->setDisplayFrame({0, 0, getDisplayWidth(), getDisplayHeight()});
         layer->setZOrder(10);
-        layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), *mWriter);
+        layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode));
         ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors));
 
         std::vector<std::shared_ptr<TestLayer>> layers = {layer};
@@ -652,7 +662,8 @@
 
         writeLayers(layers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp,
+                                 VtsComposerClient::kNoFrameIntervalNs);
         execute();
         if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
             GTEST_SUCCEED();
@@ -680,7 +691,8 @@
 
         writeLayers(layers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp,
+                                 VtsComposerClient::kNoFrameIntervalNs);
         execute();
         ASSERT_TRUE(mReader.takeErrors().empty());
         ASSERT_TRUE(mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty());
@@ -705,7 +717,8 @@
             return;
         }
 
-        auto layer = std::make_shared<TestColorLayer>(mComposerClient, getPrimaryDisplayId());
+        auto layer =
+                std::make_shared<TestColorLayer>(mComposerClient, getPrimaryDisplayId(), *mWriter);
         layer->setColor(RED);
         layer->setDisplayFrame({0, 0, getDisplayWidth(), getDisplayHeight()});
         layer->setZOrder(10);
@@ -721,7 +734,8 @@
 
         writeLayers(layers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp,
+                                 VtsComposerClient::kNoFrameIntervalNs);
         execute();
         if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
             GTEST_SUCCEED();
@@ -764,12 +778,12 @@
                 expectedColors, getDisplayWidth(),
                 {0, getDisplayHeight() / 2, getDisplayWidth(), getDisplayHeight()}, BLUE);
 
-        auto layer = std::make_shared<TestBufferLayer>(mComposerClient, *mTestRenderEngine,
-                                                       getPrimaryDisplayId(), getDisplayWidth(),
-                                                       getDisplayHeight(), PixelFormat::RGBA_8888);
+        auto layer = std::make_shared<TestBufferLayer>(
+                mComposerClient, *mTestRenderEngine, getPrimaryDisplayId(), getDisplayWidth(),
+                getDisplayHeight(), PixelFormat::RGBA_8888, *mWriter);
         layer->setDisplayFrame({0, 0, getDisplayWidth(), getDisplayHeight()});
         layer->setZOrder(10);
-        layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), *mWriter);
+        layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode));
         layer->setSourceCrop({0, static_cast<float>(getDisplayHeight() / 2),
                               static_cast<float>(getDisplayWidth()),
                               static_cast<float>(getDisplayHeight())});
@@ -785,7 +799,8 @@
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
         writeLayers(layers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp,
+                                 VtsComposerClient::kNoFrameIntervalNs);
         execute();
         if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
             GTEST_SUCCEED();
@@ -817,11 +832,13 @@
 
         common::Rect redRect = {0, 0, getDisplayWidth(), getDisplayHeight() / 2};
         common::Rect blueRect = {0, getDisplayHeight() / 4, getDisplayWidth(), getDisplayHeight()};
-        auto redLayer = std::make_shared<TestColorLayer>(mComposerClient, getPrimaryDisplayId());
+        auto redLayer =
+                std::make_shared<TestColorLayer>(mComposerClient, getPrimaryDisplayId(), *mWriter);
         redLayer->setColor(RED);
         redLayer->setDisplayFrame(redRect);
 
-        auto blueLayer = std::make_shared<TestColorLayer>(mComposerClient, getPrimaryDisplayId());
+        auto blueLayer =
+                std::make_shared<TestColorLayer>(mComposerClient, getPrimaryDisplayId(), *mWriter);
         blueLayer->setColor(BLUE);
         blueLayer->setDisplayFrame(blueRect);
         blueLayer->setZOrder(5);
@@ -843,7 +860,8 @@
 
         writeLayers(layers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp,
+                                 VtsComposerClient::kNoFrameIntervalNs);
         execute();
         if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
             GTEST_SUCCEED();
@@ -865,7 +883,8 @@
 
         writeLayers(layers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp,
+                                 VtsComposerClient::kNoFrameIntervalNs);
         execute();
         ASSERT_TRUE(mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty());
         ASSERT_TRUE(mReader.takeErrors().empty());
@@ -901,14 +920,14 @@
         static constexpr float kMaxBrightnessNits = 300.f;
 
         const auto redLayer =
-                std::make_shared<TestColorLayer>(mComposerClient, getPrimaryDisplayId());
+                std::make_shared<TestColorLayer>(mComposerClient, getPrimaryDisplayId(), *mWriter);
         redLayer->setColor(RED);
         redLayer->setDisplayFrame(redRect);
         redLayer->setWhitePointNits(kMaxBrightnessNits);
         redLayer->setBrightness(1.f);
 
         const auto dimmerRedLayer =
-                std::make_shared<TestColorLayer>(mComposerClient, getPrimaryDisplayId());
+                std::make_shared<TestColorLayer>(mComposerClient, getPrimaryDisplayId(), *mWriter);
         dimmerRedLayer->setColor(RED);
         dimmerRedLayer->setDisplayFrame(dimmerRedRect);
         // Intentionally use a small dimming ratio as some implementations may be more likely to
@@ -930,7 +949,8 @@
 
         writeLayers(layers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp,
+                                 VtsComposerClient::kNoFrameIntervalNs);
         execute();
         if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
             GTEST_SUCCEED()
@@ -978,17 +998,17 @@
                                        mTopLayerColor);
 
         auto backgroundLayer =
-                std::make_shared<TestColorLayer>(mComposerClient, getPrimaryDisplayId());
+                std::make_shared<TestColorLayer>(mComposerClient, getPrimaryDisplayId(), *mWriter);
         backgroundLayer->setDisplayFrame({0, 0, getDisplayWidth(), getDisplayHeight()});
         backgroundLayer->setZOrder(0);
         backgroundLayer->setColor(mBackgroundColor);
 
-        auto layer = std::make_shared<TestBufferLayer>(mComposerClient, *mTestRenderEngine,
-                                                       getPrimaryDisplayId(), getDisplayWidth(),
-                                                       getDisplayHeight(), PixelFormat::RGBA_8888);
+        auto layer = std::make_shared<TestBufferLayer>(
+                mComposerClient, *mTestRenderEngine, getPrimaryDisplayId(), getDisplayWidth(),
+                getDisplayHeight(), PixelFormat::RGBA_8888, *mWriter);
         layer->setDisplayFrame({0, 0, getDisplayWidth(), getDisplayHeight()});
         layer->setZOrder(10);
-        layer->setDataspace(Dataspace::UNKNOWN, *mWriter);
+        layer->setDataspace(Dataspace::UNKNOWN);
         ASSERT_NO_FATAL_FAILURE(layer->setBuffer(topLayerPixelColors));
 
         layer->setBlendMode(blendMode);
@@ -1065,7 +1085,8 @@
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
         writeLayers(mLayers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp,
+                                 VtsComposerClient::kNoFrameIntervalNs);
         execute();
         if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
             GTEST_SUCCEED();
@@ -1110,7 +1131,8 @@
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
         writeLayers(mLayers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp,
+                                 VtsComposerClient::kNoFrameIntervalNs);
         execute();
         if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
             GTEST_SUCCEED();
@@ -1150,7 +1172,8 @@
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
         writeLayers(mLayers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp,
+                                 VtsComposerClient::kNoFrameIntervalNs);
         execute();
         if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
             GTEST_SUCCEED();
@@ -1173,7 +1196,7 @@
         GraphicsCompositionTest::SetUp();
 
         auto backgroundLayer =
-                std::make_shared<TestColorLayer>(mComposerClient, getPrimaryDisplayId());
+                std::make_shared<TestColorLayer>(mComposerClient, getPrimaryDisplayId(), *mWriter);
         backgroundLayer->setColor({0.0f, 0.0f, 0.0f, 0.0f});
         backgroundLayer->setDisplayFrame({0, 0, getDisplayWidth(), getDisplayHeight()});
         backgroundLayer->setZOrder(0);
@@ -1185,7 +1208,7 @@
 
         mLayer = std::make_shared<TestBufferLayer>(mComposerClient, *mTestRenderEngine,
                                                    getPrimaryDisplayId(), mSideLength, mSideLength,
-                                                   PixelFormat::RGBA_8888);
+                                                   PixelFormat::RGBA_8888, *mWriter);
         mLayer->setDisplayFrame({0, 0, mSideLength, mSideLength});
         mLayer->setZOrder(10);
 
@@ -1223,7 +1246,7 @@
                                       getDisplayHeight(), mPixelFormat, mDataspace);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
         mLayer->setTransform(Transform::FLIP_H);
-        mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), *mWriter);
+        mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode));
 
         std::vector<Color> expectedColors(
                 static_cast<size_t>(getDisplayWidth() * getDisplayHeight()));
@@ -1234,7 +1257,8 @@
 
         writeLayers(mLayers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp,
+                                 VtsComposerClient::kNoFrameIntervalNs);
         execute();
         if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
             GTEST_SUCCEED();
@@ -1269,7 +1293,7 @@
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
         mLayer->setTransform(Transform::FLIP_V);
-        mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), *mWriter);
+        mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode));
 
         std::vector<Color> expectedColors(
                 static_cast<size_t>(getDisplayWidth() * getDisplayHeight()));
@@ -1280,7 +1304,8 @@
 
         writeLayers(mLayers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp,
+                                 VtsComposerClient::kNoFrameIntervalNs);
         execute();
         if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
             GTEST_SUCCEED();
@@ -1314,7 +1339,7 @@
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
         mLayer->setTransform(Transform::ROT_180);
-        mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), *mWriter);
+        mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode));
 
         std::vector<Color> expectedColors(
                 static_cast<size_t>(getDisplayWidth() * getDisplayHeight()));
@@ -1326,7 +1351,8 @@
 
         writeLayers(mLayers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+        mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp,
+                                 VtsComposerClient::kNoFrameIntervalNs);
         execute();
         if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
             GTEST_SUCCEED();
@@ -1343,6 +1369,101 @@
     }
 }
 
+class GraphicsColorManagementCompositionTest
+    : public GraphicsCompositionTestBase,
+      public testing::WithParamInterface<std::tuple<std::string, Dataspace, Dataspace, Dataspace>> {
+  public:
+    void SetUp() override {
+        SetUpBase(std::get<0>(GetParam()));
+        // for some reason only sRGB reliably works
+        mTestColorModes.erase(
+                std::remove_if(mTestColorModes.begin(), mTestColorModes.end(),
+                               [](ColorMode mode) { return mode != ColorMode::SRGB; }),
+                mTestColorModes.end());
+        auto standard = std::get<1>(GetParam());
+        auto transfer = std::get<2>(GetParam());
+        auto range = std::get<3>(GetParam());
+
+        mLayerDataspace = static_cast<Dataspace>(static_cast<int32_t>(standard) |
+                                                 static_cast<int32_t>(transfer) |
+                                                 static_cast<int32_t>(range));
+        ALOGD("Invoking test for dataspace: {%s, %s, %s}", toString(standard).c_str(),
+              toString(transfer).c_str(), toString(range).c_str());
+    }
+
+    void makeLayer() {
+        mLayer = std::make_shared<TestBufferLayer>(
+                mComposerClient, *mTestRenderEngine, getPrimaryDisplayId(), getDisplayWidth(),
+                getDisplayHeight(), common::PixelFormat::RGBA_8888, *mWriter);
+        mLayer->setDisplayFrame({0, 0, getDisplayWidth(), getDisplayHeight()});
+        mLayer->setZOrder(10);
+        mLayer->setAlpha(1.f);
+        mLayer->setDataspace(mLayerDataspace);
+    }
+
+    void fillColor(Color color) {
+        std::vector<Color> baseColors(static_cast<size_t>(getDisplayWidth() * getDisplayHeight()));
+        ReadbackHelper::fillColorsArea(baseColors, getDisplayWidth(),
+                                       common::Rect{.left = 0,
+                                                    .top = 0,
+                                                    .right = getDisplayWidth(),
+                                                    .bottom = getDisplayHeight()},
+                                       color);
+        ASSERT_NO_FATAL_FAILURE(mLayer->setBuffer(baseColors));
+    }
+
+    Dataspace mLayerDataspace;
+    std::shared_ptr<TestBufferLayer> mLayer;
+};
+
+TEST_P(GraphicsColorManagementCompositionTest, ColorConversion) {
+    for (ColorMode mode : mTestColorModes) {
+        EXPECT_TRUE(mComposerClient
+                            ->setColorMode(getPrimaryDisplayId(), mode, RenderIntent::COLORIMETRIC)
+                            .isOk());
+
+        bool isSupported;
+        ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer());
+        if (!isSupported) {
+            GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+            return;
+        }
+
+        mClientCompositionDisplaySettings.outputDataspace =
+                static_cast<::android::ui::Dataspace>(mDataspace);
+        mTestRenderEngine->setDisplaySettings(mClientCompositionDisplaySettings);
+
+        makeLayer();
+        for (auto color : {LIGHT_RED, LIGHT_GREEN, LIGHT_BLUE}) {
+            ALOGD("Testing color: %f, %f, %f, %f with color mode: %d", color.r, color.g, color.b,
+                  color.a, mode);
+            ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
+                                          getDisplayHeight(), mPixelFormat, mDataspace);
+            ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+            fillColor(color);
+            writeLayers({mLayer});
+            EXPECT_TRUE(mComposerClient->setPowerMode(getPrimaryDisplayId(), PowerMode::ON).isOk());
+
+            ASSERT_TRUE(mReader.takeErrors().empty());
+            mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp,
+                                     VtsComposerClient::kNoFrameIntervalNs);
+            execute();
+            if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
+                continue;
+            }
+            ASSERT_TRUE(mReader.takeErrors().empty());
+            mWriter->presentDisplay(getPrimaryDisplayId());
+            execute();
+            ASSERT_TRUE(mReader.takeErrors().empty());
+
+            mTestRenderEngine->setRenderLayers({mLayer});
+            ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+            ASSERT_NO_FATAL_FAILURE(
+                    mTestRenderEngine->checkColorBuffer(readbackBuffer.getBuffer()));
+        }
+    }
+}
+
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsCompositionTest);
 INSTANTIATE_TEST_SUITE_P(
         PerInstance, GraphicsCompositionTest,
@@ -1361,5 +1482,17 @@
         testing::ValuesIn(::android::getAidlHalInstanceNames(IComposer::descriptor)),
         ::android::PrintInstanceNameToString);
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsColorManagementCompositionTest);
+INSTANTIATE_TEST_SUITE_P(PerInstance, GraphicsColorManagementCompositionTest,
+                         testing::Combine(testing::ValuesIn(::android::getAidlHalInstanceNames(
+                                                  IComposer::descriptor)),
+                                          // Only check sRGB, but verify that extended range
+                                          // doesn't trigger any gamma shifts
+                                          testing::Values(Dataspace::STANDARD_BT709),
+                                          testing::Values(Dataspace::TRANSFER_SRGB),
+                                          // Don't test limited range until we send YUV overlays
+                                          testing::Values(Dataspace::RANGE_FULL,
+                                                          Dataspace::RANGE_EXTENDED)));
+
 }  // namespace
 }  // namespace aidl::android::hardware::graphics::composer3::vts
diff --git a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
index 323e358..5e45fd9 100644
--- a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
+++ b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
@@ -34,6 +34,7 @@
 #include <ui/PixelFormat.h>
 #include <algorithm>
 #include <iterator>
+#include <mutex>
 #include <numeric>
 #include <string>
 #include <thread>
@@ -45,7 +46,6 @@
 #define LOG_TAG "VtsHalGraphicsComposer3_TargetTest"
 
 namespace aidl::android::hardware::graphics::composer3::vts {
-namespace {
 
 using namespace std::chrono_literals;
 
@@ -70,7 +70,7 @@
     }
 
     void TearDown() override {
-        ASSERT_TRUE(mComposerClient->tearDown());
+        ASSERT_TRUE(mComposerClient->tearDown(nullptr));
         mComposerClient.reset();
     }
 
@@ -832,36 +832,58 @@
 }
 
 TEST_P(GraphicsComposerAidlTest, CreateLayer) {
+    if (hasCapability(Capability::LAYER_LIFECYCLE_BATCH_COMMAND)) {
+        GTEST_SKIP() << "Create layer will be tested in GraphicsComposerAidlBatchedCommandTest";
+        return;
+    }
+
     const auto& [status, layer] =
-            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
+            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount, nullptr);
 
     EXPECT_TRUE(status.isOk());
-    EXPECT_TRUE(mComposerClient->destroyLayer(getPrimaryDisplayId(), layer).isOk());
+    EXPECT_TRUE(mComposerClient->destroyLayer(getPrimaryDisplayId(), layer, nullptr).isOk());
 }
 
 TEST_P(GraphicsComposerAidlTest, CreateLayer_BadDisplay) {
-    const auto& [status, _] = mComposerClient->createLayer(getInvalidDisplayId(), kBufferSlotCount);
+    if (hasCapability(Capability::LAYER_LIFECYCLE_BATCH_COMMAND)) {
+        GTEST_SKIP() << "Create layer will be tested in GraphicsComposerAidlBatchedCommandTest";
+        return;
+    }
+
+    const auto& [status, _] =
+            mComposerClient->createLayer(getInvalidDisplayId(), kBufferSlotCount, nullptr);
 
     EXPECT_FALSE(status.isOk());
     EXPECT_NO_FATAL_FAILURE(assertServiceSpecificError(status, IComposerClient::EX_BAD_DISPLAY));
 }
 
 TEST_P(GraphicsComposerAidlTest, DestroyLayer_BadDisplay) {
+    if (hasCapability(Capability::LAYER_LIFECYCLE_BATCH_COMMAND)) {
+        GTEST_SKIP() << "Destroy layer will be tested in GraphicsComposerAidlBatchedCommandTest";
+        return;
+    }
+
     const auto& [status, layer] =
-            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
+            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount, nullptr);
     EXPECT_TRUE(status.isOk());
 
-    const auto& destroyStatus = mComposerClient->destroyLayer(getInvalidDisplayId(), layer);
+    const auto& destroyStatus =
+            mComposerClient->destroyLayer(getInvalidDisplayId(), layer, nullptr);
 
     EXPECT_FALSE(destroyStatus.isOk());
     EXPECT_NO_FATAL_FAILURE(
             assertServiceSpecificError(destroyStatus, IComposerClient::EX_BAD_DISPLAY));
-    ASSERT_TRUE(mComposerClient->destroyLayer(getPrimaryDisplayId(), layer).isOk());
+    ASSERT_TRUE(mComposerClient->destroyLayer(getPrimaryDisplayId(), layer, nullptr).isOk());
 }
 
 TEST_P(GraphicsComposerAidlTest, DestroyLayer_BadLayerError) {
+    if (hasCapability(Capability::LAYER_LIFECYCLE_BATCH_COMMAND)) {
+        GTEST_SKIP() << "Destroy layer will be tested in GraphicsComposerAidlBatchedCommandTest";
+        return;
+    }
+
     // We haven't created any layers yet, so any id should be invalid
-    const auto& status = mComposerClient->destroyLayer(getPrimaryDisplayId(), /*layer*/ 1);
+    const auto& status = mComposerClient->destroyLayer(getPrimaryDisplayId(), /*layer*/ 1, nullptr);
 
     EXPECT_FALSE(status.isOk());
     EXPECT_NO_FATAL_FAILURE(assertServiceSpecificError(status, IComposerClient::EX_BAD_LAYER));
@@ -891,39 +913,6 @@
     EXPECT_TRUE(status.isOk());
 }
 
-TEST_P(GraphicsComposerAidlTest, GetOverlaySupport) {
-    if (getInterfaceVersion() <= 1) {
-        GTEST_SUCCEED() << "Device does not support the new API for overlay support";
-        return;
-    }
-
-    const auto& [status, properties] = 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());
-    for (const auto& i : properties.combinations) {
-        for (const auto standard : i.standards) {
-            const auto val = static_cast<int32_t>(standard) &
-                             static_cast<int32_t>(common::Dataspace::STANDARD_MASK);
-            ASSERT_TRUE(val == static_cast<int32_t>(standard));
-        }
-        for (const auto transfer : i.transfers) {
-            const auto val = static_cast<int32_t>(transfer) &
-                             static_cast<int32_t>(common::Dataspace::TRANSFER_MASK);
-            ASSERT_TRUE(val == static_cast<int32_t>(transfer));
-        }
-        for (const auto range : i.ranges) {
-            const auto val = static_cast<int32_t>(range) &
-                             static_cast<int32_t>(common::Dataspace::RANGE_MASK);
-            ASSERT_TRUE(val == static_cast<int32_t>(range));
-        }
-    }
-}
-
 TEST_P(GraphicsComposerAidlTest, GetDisplayPhysicalOrientation_BadDisplay) {
     const auto& [status, _] = mComposerClient->getDisplayPhysicalOrientation(getInvalidDisplayId());
 
@@ -1169,35 +1158,270 @@
     EXPECT_NO_FATAL_FAILURE(assertServiceSpecificError(status, IComposerClient::EX_BAD_PARAMETER));
 }
 
+/*
+ * Test that no two display configs are exactly the same.
+ */
+TEST_P(GraphicsComposerAidlTest, GetDisplayConfigNoRepetitions) {
+    for (const auto& display : mDisplays) {
+        const auto& [status, configs] = mComposerClient->getDisplayConfigs(display.getDisplayId());
+        for (std::vector<int>::size_type i = 0; i < configs.size(); i++) {
+            for (std::vector<int>::size_type j = i + 1; j < configs.size(); j++) {
+                const auto& [widthStatus1, width1] = mComposerClient->getDisplayAttribute(
+                        display.getDisplayId(), configs[i], DisplayAttribute::WIDTH);
+                const auto& [heightStatus1, height1] = mComposerClient->getDisplayAttribute(
+                        display.getDisplayId(), configs[i], DisplayAttribute::HEIGHT);
+                const auto& [vsyncPeriodStatus1, vsyncPeriod1] =
+                        mComposerClient->getDisplayAttribute(display.getDisplayId(), configs[i],
+                                                             DisplayAttribute::VSYNC_PERIOD);
+                const auto& [groupStatus1, group1] = mComposerClient->getDisplayAttribute(
+                        display.getDisplayId(), configs[i], DisplayAttribute::CONFIG_GROUP);
+
+                const auto& [widthStatus2, width2] = mComposerClient->getDisplayAttribute(
+                        display.getDisplayId(), configs[j], DisplayAttribute::WIDTH);
+                const auto& [heightStatus2, height2] = mComposerClient->getDisplayAttribute(
+                        display.getDisplayId(), configs[j], DisplayAttribute::HEIGHT);
+                const auto& [vsyncPeriodStatus2, vsyncPeriod2] =
+                        mComposerClient->getDisplayAttribute(display.getDisplayId(), configs[j],
+                                                             DisplayAttribute::VSYNC_PERIOD);
+                const auto& [groupStatus2, group2] = mComposerClient->getDisplayAttribute(
+                        display.getDisplayId(), configs[j], DisplayAttribute::CONFIG_GROUP);
+
+                ASSERT_FALSE(width1 == width2 && height1 == height2 &&
+                             vsyncPeriod1 == vsyncPeriod2 && group1 == group2);
+            }
+        }
+    }
+}
+
+TEST_P(GraphicsComposerAidlTest, LayerLifecycleCapabilityNotSupportedOnOldVersions) {
+    if (hasCapability(Capability::LAYER_LIFECYCLE_BATCH_COMMAND)) {
+        EXPECT_GE(getInterfaceVersion(), 3);
+    }
+}
+
+class GraphicsComposerAidlV2Test : public GraphicsComposerAidlTest {
+  protected:
+    void SetUp() override {
+        GraphicsComposerAidlTest::SetUp();
+        if (getInterfaceVersion() <= 1) {
+            GTEST_SKIP() << "Device interface version is expected to be >= 2";
+        }
+    }
+};
+
+TEST_P(GraphicsComposerAidlV2Test, GetOverlaySupport) {
+    const auto& [status, properties] = 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());
+    for (const auto& i : properties.combinations) {
+        for (const auto standard : i.standards) {
+            const auto val = static_cast<int32_t>(standard) &
+                             static_cast<int32_t>(common::Dataspace::STANDARD_MASK);
+            ASSERT_TRUE(val == static_cast<int32_t>(standard));
+        }
+        for (const auto transfer : i.transfers) {
+            const auto val = static_cast<int32_t>(transfer) &
+                             static_cast<int32_t>(common::Dataspace::TRANSFER_MASK);
+            ASSERT_TRUE(val == static_cast<int32_t>(transfer));
+        }
+        for (const auto range : i.ranges) {
+            const auto val = static_cast<int32_t>(range) &
+                             static_cast<int32_t>(common::Dataspace::RANGE_MASK);
+            ASSERT_TRUE(val == static_cast<int32_t>(range));
+        }
+    }
+}
+
+class GraphicsComposerAidlV3Test : public GraphicsComposerAidlTest {
+  protected:
+    void SetUp() override {
+        GraphicsComposerAidlTest::SetUp();
+        if (getInterfaceVersion() <= 2) {
+            GTEST_SKIP() << "Device interface version is expected to be >= 3";
+        }
+    }
+};
+
+TEST_P(GraphicsComposerAidlV3Test, GetDisplayConfigurations) {
+    for (const auto& display : mDisplays) {
+        const auto& [status, displayConfigurations] =
+                mComposerClient->getDisplayConfigurations(display.getDisplayId());
+        EXPECT_TRUE(status.isOk());
+        EXPECT_FALSE(displayConfigurations.empty());
+
+        for (const auto& displayConfig : displayConfigurations) {
+            EXPECT_NE(-1, displayConfig.width);
+            EXPECT_NE(-1, displayConfig.height);
+            EXPECT_NE(-1, displayConfig.vsyncPeriod);
+            EXPECT_NE(-1, displayConfig.configGroup);
+            if (displayConfig.dpi) {
+                EXPECT_NE(-1.f, displayConfig.dpi->x);
+                EXPECT_NE(-1.f, displayConfig.dpi->y);
+            }
+            if (displayConfig.vrrConfig) {
+                const auto& vrrConfig = *displayConfig.vrrConfig;
+                EXPECT_GE(vrrConfig.minFrameIntervalNs, displayConfig.vsyncPeriod);
+
+                EXPECT_EQ(1, std::count_if(
+                                     displayConfigurations.cbegin(), displayConfigurations.cend(),
+                                     [displayConfig](const auto& config) {
+                                         return config.configGroup == displayConfig.configGroup;
+                                     }))
+                        << "There should be only one VRR mode in one ConfigGroup";
+
+                const auto verifyFrameIntervalIsDivisorOfVsync = [&](int32_t frameIntervalNs) {
+                    constexpr auto kThreshold = 0.05f;  // 5%
+                    const auto ratio =
+                            static_cast<float>(frameIntervalNs) / displayConfig.vsyncPeriod;
+                    return ratio - std::round(ratio) <= kThreshold;
+                };
+
+                EXPECT_TRUE(verifyFrameIntervalIsDivisorOfVsync(vrrConfig.minFrameIntervalNs));
+
+                if (vrrConfig.frameIntervalPowerHints) {
+                    const auto& frameIntervalPowerHints = *vrrConfig.frameIntervalPowerHints;
+                    EXPECT_FALSE(frameIntervalPowerHints.empty());
+
+                    const auto minFrameInterval = *min_element(frameIntervalPowerHints.cbegin(),
+                                                               frameIntervalPowerHints.cend());
+                    EXPECT_LE(minFrameInterval->frameIntervalNs,
+                              VtsComposerClient::kMaxFrameIntervalNs);
+
+                    EXPECT_TRUE(std::all_of(frameIntervalPowerHints.cbegin(),
+                                            frameIntervalPowerHints.cend(),
+                                            [&](const auto& frameIntervalPowerHint) {
+                                                return verifyFrameIntervalIsDivisorOfVsync(
+                                                        frameIntervalPowerHint->frameIntervalNs);
+                                            }));
+                }
+
+                if (vrrConfig.notifyExpectedPresentConfig) {
+                    const auto& notifyExpectedPresentConfig =
+                            *vrrConfig.notifyExpectedPresentConfig;
+                    EXPECT_GE(notifyExpectedPresentConfig.headsUpNs, 0);
+                    EXPECT_GE(notifyExpectedPresentConfig.timeoutNs, 0);
+                }
+            }
+        }
+    }
+}
+
+TEST_P(GraphicsComposerAidlV3Test, GetDisplayConfigsIsSubsetOfGetDisplayConfigurations) {
+    for (const auto& display : mDisplays) {
+        const auto& [status, displayConfigurations] =
+                mComposerClient->getDisplayConfigurations(display.getDisplayId());
+        EXPECT_TRUE(status.isOk());
+
+        const auto& [legacyConfigStatus, legacyConfigs] =
+                mComposerClient->getDisplayConfigs(display.getDisplayId());
+        EXPECT_TRUE(legacyConfigStatus.isOk());
+        EXPECT_FALSE(legacyConfigs.empty());
+        EXPECT_TRUE(legacyConfigs.size() <= displayConfigurations.size());
+
+        for (const auto legacyConfigId : legacyConfigs) {
+            const auto& legacyWidth = mComposerClient->getDisplayAttribute(
+                    display.getDisplayId(), legacyConfigId, DisplayAttribute::WIDTH);
+            const auto& legacyHeight = mComposerClient->getDisplayAttribute(
+                    display.getDisplayId(), legacyConfigId, DisplayAttribute::HEIGHT);
+            const auto& legacyVsyncPeriod = mComposerClient->getDisplayAttribute(
+                    display.getDisplayId(), legacyConfigId, DisplayAttribute::VSYNC_PERIOD);
+            const auto& legacyConfigGroup = mComposerClient->getDisplayAttribute(
+                    display.getDisplayId(), legacyConfigId, DisplayAttribute::CONFIG_GROUP);
+            const auto& legacyDpiX = mComposerClient->getDisplayAttribute(
+                    display.getDisplayId(), legacyConfigId, DisplayAttribute::DPI_X);
+            const auto& legacyDpiY = mComposerClient->getDisplayAttribute(
+                    display.getDisplayId(), legacyConfigId, DisplayAttribute::DPI_Y);
+
+            EXPECT_TRUE(legacyWidth.first.isOk() && legacyHeight.first.isOk() &&
+                        legacyVsyncPeriod.first.isOk() && legacyConfigGroup.first.isOk());
+
+            EXPECT_TRUE(std::any_of(
+                    displayConfigurations.begin(), displayConfigurations.end(),
+                    [&](const auto& displayConfiguration) {
+                        const bool requiredAttributesPredicate =
+                                displayConfiguration.configId == legacyConfigId &&
+                                displayConfiguration.width == legacyWidth.second &&
+                                displayConfiguration.height == legacyHeight.second &&
+                                displayConfiguration.vsyncPeriod == legacyVsyncPeriod.second &&
+                                displayConfiguration.configGroup == legacyConfigGroup.second;
+
+                        if (!requiredAttributesPredicate) {
+                            // Required attributes did not match
+                            return false;
+                        }
+
+                        // Check optional attributes
+                        const auto& [legacyDpiXStatus, legacyDpiXValue] = legacyDpiX;
+                        const auto& [legacyDpiYStatus, legacyDpiYValue] = legacyDpiY;
+                        if (displayConfiguration.dpi) {
+                            if (!legacyDpiXStatus.isOk() || !legacyDpiYStatus.isOk()) {
+                                // getDisplayAttribute failed for optional attributes
+                                return false;
+                            }
+
+                            // DPI values in DisplayConfigurations are not scaled (* 1000.f)
+                            // the way they are in the legacy DisplayConfigs.
+                            constexpr float kEpsilon = 0.001f;
+                            return std::abs(displayConfiguration.dpi->x -
+                                            legacyDpiXValue / 1000.f) < kEpsilon &&
+                                   std::abs(displayConfiguration.dpi->y -
+                                            legacyDpiYValue / 1000.f) < kEpsilon;
+                        } else {
+                            return !legacyDpiXStatus.isOk() && !legacyDpiYStatus.isOk() &&
+                                   EX_SERVICE_SPECIFIC == legacyDpiXStatus.getExceptionCode() &&
+                                   EX_SERVICE_SPECIFIC == legacyDpiYStatus.getExceptionCode() &&
+                                   IComposerClient::EX_UNSUPPORTED ==
+                                           legacyDpiXStatus.getServiceSpecificError() &&
+                                   IComposerClient::EX_UNSUPPORTED ==
+                                           legacyDpiYStatus.getServiceSpecificError();
+                        }
+                    }));
+        }
+    }
+}
+
+// TODO(b/291792736) Add detailed VTS test cases for NotifyExpectedPresent
+TEST_P(GraphicsComposerAidlV3Test, NotifyExpectedPresent) {
+    for (const auto& display : mDisplays) {
+        EXPECT_TRUE(mComposerClient
+                            ->notifyExpectedPresent(display.getDisplayId(),
+                                                    ClockMonotonicTimestamp{0},
+                                                    std::chrono::nanoseconds{8ms}.count())
+                            .isOk());
+    }
+}
+
 // Tests for Command.
 class GraphicsComposerAidlCommandTest : public GraphicsComposerAidlTest {
   protected:
     void TearDown() override {
-        const auto errors = mReader.takeErrors();
+        ASSERT_FALSE(mDisplays.empty());
         ASSERT_TRUE(mReader.takeErrors().empty());
         ASSERT_TRUE(mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty());
 
+        ASSERT_TRUE(mComposerClient->tearDown(&getWriter(getPrimaryDisplayId())));
         ASSERT_NO_FATAL_FAILURE(GraphicsComposerAidlTest::TearDown());
     }
 
     void execute() {
         std::vector<CommandResultPayload> payloads;
         for (auto& [_, writer] : mWriters) {
-            auto commands = writer.takePendingCommands();
-            if (commands.empty()) {
-                continue;
-            }
-
-            auto [status, results] = mComposerClient->executeCommands(commands);
-            ASSERT_TRUE(status.isOk()) << "executeCommands failed " << status.getDescription();
-
-            payloads.reserve(payloads.size() + results.size());
-            payloads.insert(payloads.end(), std::make_move_iterator(results.begin()),
-                            std::make_move_iterator(results.end()));
+            executeInternal(writer, payloads);
         }
         mReader.parse(std::move(payloads));
     }
 
+    void execute(ComposerClientWriter& writer, ComposerClientReader& reader) {
+        std::vector<CommandResultPayload> payloads;
+        executeInternal(writer, payloads);
+        reader.parse(std::move(payloads));
+    }
+
     static inline auto toTimePoint(nsecs_t time) {
         return std::chrono::time_point<std::chrono::steady_clock>(std::chrono::nanoseconds(time));
     }
@@ -1268,10 +1492,10 @@
                                            RenderIntent::COLORIMETRIC)
                             .isOk());
 
-        const auto& [status, layer] =
-                mComposerClient->createLayer(display.getDisplayId(), kBufferSlotCount);
-        EXPECT_TRUE(status.isOk());
         auto& writer = getWriter(display.getDisplayId());
+        const auto& [status, layer] =
+                mComposerClient->createLayer(display.getDisplayId(), kBufferSlotCount, &writer);
+        EXPECT_TRUE(status.isOk());
         {
             const auto buffer = allocate(::android::PIXEL_FORMAT_RGBA_8888);
             ASSERT_NE(nullptr, buffer);
@@ -1284,7 +1508,8 @@
                                   /*acquireFence*/ -1);
             writer.setLayerDataspace(display.getDisplayId(), layer, common::Dataspace::UNKNOWN);
 
-            writer.validateDisplay(display.getDisplayId(), ComposerClientWriter::kNoTimestamp);
+            writer.validateDisplay(display.getDisplayId(), ComposerClientWriter::kNoTimestamp,
+                                   VtsComposerClient::kNoFrameIntervalNs);
             execute();
             ASSERT_TRUE(mReader.takeErrors().empty());
 
@@ -1301,7 +1526,8 @@
                                   /*acquireFence*/ -1);
             writer.setLayerSurfaceDamage(display.getDisplayId(), layer,
                                          std::vector<Rect>(1, {0, 0, 10, 10}));
-            writer.validateDisplay(display.getDisplayId(), ComposerClientWriter::kNoTimestamp);
+            writer.validateDisplay(display.getDisplayId(), ComposerClientWriter::kNoTimestamp,
+                                   VtsComposerClient::kNoFrameIntervalNs);
             execute();
             ASSERT_TRUE(mReader.takeErrors().empty());
 
@@ -1309,13 +1535,14 @@
             execute();
         }
 
-        EXPECT_TRUE(mComposerClient->destroyLayer(display.getDisplayId(), layer).isOk());
+        EXPECT_TRUE(mComposerClient->destroyLayer(display.getDisplayId(), layer, &writer).isOk());
     }
 
     sp<::android::Fence> presentAndGetFence(
             std::optional<ClockMonotonicTimestamp> expectedPresentTime) {
         auto& writer = getWriter(getPrimaryDisplayId());
-        writer.validateDisplay(getPrimaryDisplayId(), expectedPresentTime);
+        writer.validateDisplay(getPrimaryDisplayId(), expectedPresentTime,
+                               VtsComposerClient::kNoFrameIntervalNs);
         execute();
         EXPECT_TRUE(mReader.takeErrors().empty());
 
@@ -1343,15 +1570,16 @@
     }
 
     int64_t createOnScreenLayer(Composition composition = Composition::DEVICE) {
+        auto& writer = getWriter(getPrimaryDisplayId());
         const auto& [status, layer] =
-                mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
+                mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount, &writer);
         EXPECT_TRUE(status.isOk());
         Rect displayFrame{0, 0, getPrimaryDisplay().getDisplayWidth(),
                           getPrimaryDisplay().getDisplayHeight()};
         FRect cropRect{0, 0, (float)getPrimaryDisplay().getDisplayWidth(),
                        (float)getPrimaryDisplay().getDisplayHeight()};
         configureLayer(getPrimaryDisplay(), layer, composition, displayFrame, cropRect);
-        auto& writer = getWriter(getPrimaryDisplayId());
+
         writer.setLayerDataspace(getPrimaryDisplayId(), layer, common::Dataspace::UNKNOWN);
         return layer;
     }
@@ -1522,6 +1750,7 @@
     // clang-format on
 
     ComposerClientWriter& getWriter(int64_t display) {
+        std::lock_guard guard{mWritersMutex};
         auto [it, _] = mWriters.try_emplace(display, display);
         return it->second;
     }
@@ -1529,7 +1758,27 @@
     ComposerClientReader mReader;
 
   private:
-    std::unordered_map<int64_t, ComposerClientWriter> mWriters;
+    void executeInternal(ComposerClientWriter& writer,
+                         std::vector<CommandResultPayload>& payloads) {
+        auto commands = writer.takePendingCommands();
+        if (commands.empty()) {
+            return;
+        }
+
+        auto [status, results] = mComposerClient->executeCommands(commands);
+        ASSERT_TRUE(status.isOk()) << "executeCommands failed " << status.getDescription();
+
+        payloads.reserve(payloads.size() + results.size());
+        payloads.insert(payloads.end(), std::make_move_iterator(results.begin()),
+                        std::make_move_iterator(results.end()));
+    }
+
+    // Guards access to the map itself. Callers must ensure not to attempt to
+    // - modify the same writer from multiple threads
+    // - insert a new writer into the map during concurrent access, which would invalidate
+    //   references from other threads
+    std::mutex mWritersMutex;
+    std::unordered_map<int64_t, ComposerClientWriter> mWriters GUARDED_BY(mWritersMutex);
 };
 
 TEST_P(GraphicsComposerAidlCommandTest, SetColorTransform) {
@@ -1539,10 +1788,10 @@
 }
 
 TEST_P(GraphicsComposerAidlCommandTest, SetLayerColorTransform) {
-    const auto& [status, layer] =
-            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
-    EXPECT_TRUE(status.isOk());
     auto& writer = getWriter(getPrimaryDisplayId());
+    const auto& [status, layer] =
+            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount, &writer);
+    EXPECT_TRUE(status.isOk());
     writer.setLayerColorTransform(getPrimaryDisplayId(), layer, kIdentity.data());
     execute();
 
@@ -1610,7 +1859,7 @@
 
     auto& writer = getWriter(getPrimaryDisplayId());
     writer.setClientTarget(getPrimaryDisplayId(), /*slot*/ 0, nullptr, /*acquireFence*/ -1,
-                           Dataspace::UNKNOWN, std::vector<Rect>());
+                           Dataspace::UNKNOWN, std::vector<Rect>(), 1.0f);
 
     execute();
 }
@@ -1637,20 +1886,23 @@
 
 TEST_P(GraphicsComposerAidlCommandTest, ValidDisplay) {
     auto& writer = getWriter(getPrimaryDisplayId());
-    writer.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+    writer.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp,
+                           VtsComposerClient::kNoFrameIntervalNs);
     execute();
 }
 
 TEST_P(GraphicsComposerAidlCommandTest, AcceptDisplayChanges) {
     auto& writer = getWriter(getPrimaryDisplayId());
-    writer.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+    writer.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp,
+                           VtsComposerClient::kNoFrameIntervalNs);
     writer.acceptDisplayChanges(getPrimaryDisplayId());
     execute();
 }
 
 TEST_P(GraphicsComposerAidlCommandTest, PresentDisplay) {
     auto& writer = getWriter(getPrimaryDisplayId());
-    writer.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+    writer.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp,
+                           VtsComposerClient::kNoFrameIntervalNs);
     writer.presentDisplay(getPrimaryDisplayId());
     execute();
 }
@@ -1663,10 +1915,6 @@
  * surface damage have been set
  */
 TEST_P(GraphicsComposerAidlCommandTest, PresentDisplayNoLayerStateChanges) {
-    if (!hasCapability(Capability::SKIP_VALIDATE)) {
-        GTEST_SUCCEED() << "Device does not have skip validate capability, skipping";
-        return;
-    }
     EXPECT_TRUE(mComposerClient->setPowerMode(getPrimaryDisplayId(), PowerMode::ON).isOk());
 
     const auto& [renderIntentsStatus, renderIntents] =
@@ -1682,7 +1930,7 @@
         ASSERT_NE(nullptr, handle);
 
         const auto& [layerStatus, layer] =
-                mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
+                mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount, &writer);
         EXPECT_TRUE(layerStatus.isOk());
 
         Rect displayFrame{0, 0, getPrimaryDisplay().getDisplayWidth(),
@@ -1693,7 +1941,8 @@
         writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, handle,
                               /*acquireFence*/ -1);
         writer.setLayerDataspace(getPrimaryDisplayId(), layer, Dataspace::UNKNOWN);
-        writer.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+        writer.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp,
+                               VtsComposerClient::kNoFrameIntervalNs);
         execute();
         if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
             GTEST_SUCCEED() << "Composition change requested, skipping test";
@@ -1718,15 +1967,15 @@
 }
 
 TEST_P(GraphicsComposerAidlCommandTest, SetLayerCursorPosition) {
+    auto& writer = getWriter(getPrimaryDisplayId());
     const auto& [layerStatus, layer] =
-            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
+            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount, &writer);
     EXPECT_TRUE(layerStatus.isOk());
 
     const auto buffer = allocate(::android::PIXEL_FORMAT_RGBA_8888);
     const auto handle = buffer->handle;
     ASSERT_NE(nullptr, handle);
 
-    auto& writer = getWriter(getPrimaryDisplayId());
     writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, handle, /*acquireFence*/ -1);
 
     Rect displayFrame{0, 0, getPrimaryDisplay().getDisplayWidth(),
@@ -1735,7 +1984,8 @@
                    (float)getPrimaryDisplay().getDisplayHeight()};
     configureLayer(getPrimaryDisplay(), layer, Composition::CURSOR, displayFrame, cropRect);
     writer.setLayerDataspace(getPrimaryDisplayId(), layer, Dataspace::UNKNOWN);
-    writer.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+    writer.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp,
+                           VtsComposerClient::kNoFrameIntervalNs);
 
     execute();
 
@@ -1750,7 +2000,8 @@
     execute();
 
     writer.setLayerCursorPosition(getPrimaryDisplayId(), layer, /*x*/ 0, /*y*/ 0);
-    writer.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+    writer.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp,
+                           VtsComposerClient::kNoFrameIntervalNs);
     writer.presentDisplay(getPrimaryDisplayId());
     execute();
 }
@@ -1760,66 +2011,19 @@
     const auto handle = buffer->handle;
     ASSERT_NE(nullptr, handle);
 
-    const auto& [layerStatus, layer] =
-            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
-    EXPECT_TRUE(layerStatus.isOk());
     auto& writer = getWriter(getPrimaryDisplayId());
+    const auto& [layerStatus, layer] =
+            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount, &writer);
+    EXPECT_TRUE(layerStatus.isOk());
     writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, handle, /*acquireFence*/ -1);
     execute();
 }
 
-TEST_P(GraphicsComposerAidlCommandTest, SetLayerBufferSlotsToClear) {
-    // Older HAL versions use a backwards compatible way of clearing buffer slots
-    const auto& [versionStatus, version] = mComposerClient->getInterfaceVersion();
-    ASSERT_TRUE(versionStatus.isOk());
-    if (version <= 1) {
-        GTEST_SUCCEED() << "HAL at version 1 or lower does not have "
-                           "LayerCommand::bufferSlotsToClear.";
-        return;
-    }
-
-    const auto& [layerStatus, layer] =
-            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
-    EXPECT_TRUE(layerStatus.isOk());
-    auto& writer = getWriter(getPrimaryDisplayId());
-
-    // setup 3 buffers in the buffer cache, with the last buffer being active
-    // then emulate the Android platform code that clears all 3 buffer slots
-
-    const auto buffer1 = allocate(::android::PIXEL_FORMAT_RGBA_8888);
-    ASSERT_NE(nullptr, buffer1);
-    const auto handle1 = buffer1->handle;
-    writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, handle1, /*acquireFence*/ -1);
-    execute();
-    ASSERT_TRUE(mReader.takeErrors().empty());
-
-    const auto buffer2 = allocate(::android::PIXEL_FORMAT_RGBA_8888);
-    ASSERT_NE(nullptr, buffer2);
-    const auto handle2 = buffer2->handle;
-    writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 1, handle2, /*acquireFence*/ -1);
-    execute();
-    ASSERT_TRUE(mReader.takeErrors().empty());
-
-    const auto buffer3 = allocate(::android::PIXEL_FORMAT_RGBA_8888);
-    ASSERT_NE(nullptr, buffer3);
-    const auto handle3 = buffer3->handle;
-    writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 2, handle3, /*acquireFence*/ -1);
-    execute();
-    ASSERT_TRUE(mReader.takeErrors().empty());
-
-    // Ensure we can clear all 3 buffer slots, even the active buffer - it is assumed the
-    // current active buffer's slot will be cleared, but still remain the active buffer and no
-    // errors will occur.
-    writer.setLayerBufferSlotsToClear(getPrimaryDisplayId(), layer, {0, 1, 2});
-    execute();
-    ASSERT_TRUE(mReader.takeErrors().empty());
-}
-
 TEST_P(GraphicsComposerAidlCommandTest, SetLayerBufferMultipleTimes) {
-    const auto& [layerStatus, layer] =
-            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
-    EXPECT_TRUE(layerStatus.isOk());
     auto& writer = getWriter(getPrimaryDisplayId());
+    const auto& [layerStatus, layer] =
+            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount, &writer);
+    EXPECT_TRUE(layerStatus.isOk());
 
     // Setup 3 buffers in the buffer cache, with the last buffer being active. Then, emulate the
     // Android platform code that clears all 3 buffer slots by setting all but the active buffer
@@ -1867,14 +2071,14 @@
 }
 
 TEST_P(GraphicsComposerAidlCommandTest, SetLayerSurfaceDamage) {
+    auto& writer = getWriter(getPrimaryDisplayId());
     const auto& [layerStatus, layer] =
-            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
+            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount, &writer);
     EXPECT_TRUE(layerStatus.isOk());
 
     Rect empty{0, 0, 0, 0};
     Rect unit{0, 0, 1, 1};
 
-    auto& writer = getWriter(getPrimaryDisplayId());
     writer.setLayerSurfaceDamage(getPrimaryDisplayId(), layer, std::vector<Rect>(1, empty));
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
@@ -1889,14 +2093,14 @@
 }
 
 TEST_P(GraphicsComposerAidlCommandTest, SetLayerBlockingRegion) {
+    auto& writer = getWriter(getPrimaryDisplayId());
     const auto& [layerStatus, layer] =
-            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
+            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount, &writer);
     EXPECT_TRUE(layerStatus.isOk());
 
     Rect empty{0, 0, 0, 0};
     Rect unit{0, 0, 1, 1};
 
-    auto& writer = getWriter(getPrimaryDisplayId());
     writer.setLayerBlockingRegion(getPrimaryDisplayId(), layer, std::vector<Rect>(1, empty));
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
@@ -1911,11 +2115,11 @@
 }
 
 TEST_P(GraphicsComposerAidlCommandTest, SetLayerBlendMode) {
+    auto& writer = getWriter(getPrimaryDisplayId());
     const auto& [layerStatus, layer] =
-            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
+            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount, &writer);
     EXPECT_TRUE(layerStatus.isOk());
 
-    auto& writer = getWriter(getPrimaryDisplayId());
     writer.setLayerBlendMode(getPrimaryDisplayId(), layer, BlendMode::NONE);
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
@@ -1930,11 +2134,11 @@
 }
 
 TEST_P(GraphicsComposerAidlCommandTest, SetLayerColor) {
+    auto& writer = getWriter(getPrimaryDisplayId());
     const auto& [layerStatus, layer] =
-            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
+            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount, &writer);
     EXPECT_TRUE(layerStatus.isOk());
 
-    auto& writer = getWriter(getPrimaryDisplayId());
     writer.setLayerColor(getPrimaryDisplayId(), layer, Color{1.0f, 1.0f, 1.0f, 1.0f});
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
@@ -1945,11 +2149,11 @@
 }
 
 TEST_P(GraphicsComposerAidlCommandTest, SetLayerCompositionType) {
+    auto& writer = getWriter(getPrimaryDisplayId());
     const auto& [layerStatus, layer] =
-            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
+            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount, &writer);
     EXPECT_TRUE(layerStatus.isOk());
 
-    auto& writer = getWriter(getPrimaryDisplayId());
     writer.setLayerCompositionType(getPrimaryDisplayId(), layer, Composition::CLIENT);
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
@@ -1968,8 +2172,9 @@
 
 TEST_P(GraphicsComposerAidlCommandTest, DisplayDecoration) {
     for (VtsDisplay& display : mDisplays) {
+        auto& writer = getWriter(display.getDisplayId());
         const auto [layerStatus, layer] =
-                mComposerClient->createLayer(display.getDisplayId(), kBufferSlotCount);
+                mComposerClient->createLayer(display.getDisplayId(), kBufferSlotCount, &writer);
         EXPECT_TRUE(layerStatus.isOk());
 
         const auto [error, support] =
@@ -1992,11 +2197,11 @@
         }
 
         configureLayer(display, layer, Composition::DISPLAY_DECORATION, display.getFrameRect(),
-                          display.getCrop());
-        auto& writer = getWriter(display.getDisplayId());
+                       display.getCrop());
         writer.setLayerBuffer(display.getDisplayId(), layer, /*slot*/ 0, decorBuffer->handle,
                               /*acquireFence*/ -1);
-        writer.validateDisplay(display.getDisplayId(), ComposerClientWriter::kNoTimestamp);
+        writer.validateDisplay(display.getDisplayId(), ComposerClientWriter::kNoTimestamp,
+                               VtsComposerClient::kNoFrameIntervalNs);
         execute();
         if (support) {
             ASSERT_TRUE(mReader.takeErrors().empty());
@@ -2009,31 +2214,31 @@
 }
 
 TEST_P(GraphicsComposerAidlCommandTest, SetLayerDataspace) {
+    auto& writer = getWriter(getPrimaryDisplayId());
     const auto& [layerStatus, layer] =
-            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
+            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount, &writer);
     EXPECT_TRUE(layerStatus.isOk());
 
-    auto& writer = getWriter(getPrimaryDisplayId());
     writer.setLayerDataspace(getPrimaryDisplayId(), layer, Dataspace::UNKNOWN);
     execute();
 }
 
 TEST_P(GraphicsComposerAidlCommandTest, SetLayerDisplayFrame) {
+    auto& writer = getWriter(getPrimaryDisplayId());
     const auto& [layerStatus, layer] =
-            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
+            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount, &writer);
     EXPECT_TRUE(layerStatus.isOk());
 
-    auto& writer = getWriter(getPrimaryDisplayId());
     writer.setLayerDisplayFrame(getPrimaryDisplayId(), layer, Rect{0, 0, 1, 1});
     execute();
 }
 
 TEST_P(GraphicsComposerAidlCommandTest, SetLayerPlaneAlpha) {
+    auto& writer = getWriter(getPrimaryDisplayId());
     const auto& [layerStatus, layer] =
-            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
+            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount, &writer);
     EXPECT_TRUE(layerStatus.isOk());
 
-    auto& writer = getWriter(getPrimaryDisplayId());
     writer.setLayerPlaneAlpha(getPrimaryDisplayId(), layer, /*alpha*/ 0.0f);
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
@@ -2053,31 +2258,31 @@
     const auto handle = buffer->handle;
     ASSERT_NE(nullptr, handle);
 
+    auto& writer = getWriter(getPrimaryDisplayId());
     const auto& [layerStatus, layer] =
-            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
+            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount, &writer);
     EXPECT_TRUE(layerStatus.isOk());
 
-    auto& writer = getWriter(getPrimaryDisplayId());
     writer.setLayerSidebandStream(getPrimaryDisplayId(), layer, handle);
     execute();
 }
 
 TEST_P(GraphicsComposerAidlCommandTest, SetLayerSourceCrop) {
+    auto& writer = getWriter(getPrimaryDisplayId());
     const auto& [layerStatus, layer] =
-            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
+            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount, &writer);
     EXPECT_TRUE(layerStatus.isOk());
 
-    auto& writer = getWriter(getPrimaryDisplayId());
     writer.setLayerSourceCrop(getPrimaryDisplayId(), layer, FRect{0.0f, 0.0f, 1.0f, 1.0f});
     execute();
 }
 
 TEST_P(GraphicsComposerAidlCommandTest, SetLayerTransform) {
+    auto& writer = getWriter(getPrimaryDisplayId());
     const auto& [layerStatus, layer] =
-            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
+            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount, &writer);
     EXPECT_TRUE(layerStatus.isOk());
 
-    auto& writer = getWriter(getPrimaryDisplayId());
     writer.setLayerTransform(getPrimaryDisplayId(), layer, static_cast<Transform>(0));
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
@@ -2116,14 +2321,14 @@
 }
 
 TEST_P(GraphicsComposerAidlCommandTest, SetLayerVisibleRegion) {
+    auto& writer = getWriter(getPrimaryDisplayId());
     const auto& [layerStatus, layer] =
-            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
+            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount, &writer);
     EXPECT_TRUE(layerStatus.isOk());
 
     Rect empty{0, 0, 0, 0};
     Rect unit{0, 0, 1, 1};
 
-    auto& writer = getWriter(getPrimaryDisplayId());
     writer.setLayerVisibleRegion(getPrimaryDisplayId(), layer, std::vector<Rect>(1, empty));
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
@@ -2138,11 +2343,12 @@
 }
 
 TEST_P(GraphicsComposerAidlCommandTest, SetLayerZOrder) {
+    auto& writer = getWriter(getPrimaryDisplayId());
+
     const auto& [layerStatus, layer] =
-            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
+            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount, &writer);
     EXPECT_TRUE(layerStatus.isOk());
 
-    auto& writer = getWriter(getPrimaryDisplayId());
     writer.setLayerZOrder(getPrimaryDisplayId(), layer, /*z*/ 10);
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
@@ -2153,8 +2359,9 @@
 }
 
 TEST_P(GraphicsComposerAidlCommandTest, SetLayerPerFrameMetadata) {
+    auto& writer = getWriter(getPrimaryDisplayId());
     const auto& [layerStatus, layer] =
-            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
+            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount, &writer);
     EXPECT_TRUE(layerStatus.isOk());
 
     /**
@@ -2169,7 +2376,6 @@
      *  white (D65)     0.3127  0.3290
      */
 
-    auto& writer = getWriter(getPrimaryDisplayId());
     std::vector<PerFrameMetadata> aidlMetadata;
     aidlMetadata.push_back({PerFrameMetadataKey::DISPLAY_RED_PRIMARY_X, 0.680f});
     aidlMetadata.push_back({PerFrameMetadataKey::DISPLAY_RED_PRIMARY_Y, 0.320f});
@@ -2189,18 +2395,19 @@
     const auto errors = mReader.takeErrors();
     if (errors.size() == 1 && errors[0].errorCode == EX_UNSUPPORTED_OPERATION) {
         GTEST_SUCCEED() << "SetLayerPerFrameMetadata is not supported";
-        EXPECT_TRUE(mComposerClient->destroyLayer(getPrimaryDisplayId(), layer).isOk());
+        EXPECT_TRUE(mComposerClient->destroyLayer(getPrimaryDisplayId(), layer, &writer).isOk());
         return;
     }
 
-    EXPECT_TRUE(mComposerClient->destroyLayer(getPrimaryDisplayId(), layer).isOk());
+    EXPECT_TRUE(mComposerClient->destroyLayer(getPrimaryDisplayId(), layer, &writer).isOk());
 }
 
 TEST_P(GraphicsComposerAidlCommandTest, setLayerBrightness) {
-    const auto& [layerStatus, layer] =
-            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
-
     auto& writer = getWriter(getPrimaryDisplayId());
+
+    const auto& [layerStatus, layer] =
+            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount, &writer);
+
     writer.setLayerBrightness(getPrimaryDisplayId(), layer, 0.2f);
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
@@ -2406,12 +2613,69 @@
     EXPECT_TRUE(mComposerClient->setPowerMode(getPrimaryDisplayId(), PowerMode::OFF).isOk());
 }
 
-TEST_P(GraphicsComposerAidlCommandTest, SetRefreshRateChangedCallbackDebug_Unsupported) {
-    if (getInterfaceVersion() <= 1) {
-        GTEST_SUCCEED() << "Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG is "
-                           "not supported on older version of the service";
-        return;
+class GraphicsComposerAidlCommandV2Test : public GraphicsComposerAidlCommandTest {
+  protected:
+    void SetUp() override {
+        GraphicsComposerAidlTest::SetUp();
+        if (getInterfaceVersion() <= 1) {
+            GTEST_SKIP() << "Device interface version is expected to be >= 2";
+        }
     }
+};
+/**
+ * Test Capability::SKIP_VALIDATE
+ *
+ * Capability::SKIP_VALIDATE has been deprecated and should not be enabled.
+ */
+TEST_P(GraphicsComposerAidlCommandV2Test, SkipValidateDeprecatedTest) {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+    ASSERT_FALSE(hasCapability(Capability::SKIP_VALIDATE))
+            << "Found Capability::SKIP_VALIDATE capability.";
+#pragma clang diagnostic pop
+}
+
+TEST_P(GraphicsComposerAidlCommandV2Test, SetLayerBufferSlotsToClear) {
+    auto& writer = getWriter(getPrimaryDisplayId());
+    // Older HAL versions use a backwards compatible way of clearing buffer slots
+    // HAL at version 1 or lower does not have LayerCommand::bufferSlotsToClear
+    const auto& [layerStatus, layer] =
+            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount, &writer);
+    EXPECT_TRUE(layerStatus.isOk());
+
+    // setup 3 buffers in the buffer cache, with the last buffer being active
+    // then emulate the Android platform code that clears all 3 buffer slots
+
+    const auto buffer1 = allocate(::android::PIXEL_FORMAT_RGBA_8888);
+    ASSERT_NE(nullptr, buffer1);
+    const auto handle1 = buffer1->handle;
+    writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, handle1, /*acquireFence*/ -1);
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+
+    const auto buffer2 = allocate(::android::PIXEL_FORMAT_RGBA_8888);
+    ASSERT_NE(nullptr, buffer2);
+    const auto handle2 = buffer2->handle;
+    writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 1, handle2, /*acquireFence*/ -1);
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+
+    const auto buffer3 = allocate(::android::PIXEL_FORMAT_RGBA_8888);
+    ASSERT_NE(nullptr, buffer3);
+    const auto handle3 = buffer3->handle;
+    writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 2, handle3, /*acquireFence*/ -1);
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+
+    // Ensure we can clear all 3 buffer slots, even the active buffer - it is assumed the
+    // current active buffer's slot will be cleared, but still remain the active buffer and no
+    // errors will occur.
+    writer.setLayerBufferSlotsToClear(getPrimaryDisplayId(), layer, {0, 1, 2});
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+}
+
+TEST_P(GraphicsComposerAidlCommandV2Test, SetRefreshRateChangedCallbackDebug_Unsupported) {
     if (!hasCapability(Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG)) {
         auto status = mComposerClient->setRefreshRateChangedCallbackDebugEnabled(
                 getPrimaryDisplayId(), /*enabled*/ true);
@@ -2427,46 +2691,50 @@
     }
 }
 
-TEST_P(GraphicsComposerAidlCommandTest, SetRefreshRateChangedCallbackDebug_Enabled) {
-    if (getInterfaceVersion() <= 1) {
-        GTEST_SUCCEED() << "Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG is "
-                           "not supported on older version of the service";
-        return;
-    }
+TEST_P(GraphicsComposerAidlCommandV2Test, SetRefreshRateChangedCallbackDebug_Enabled) {
     if (!hasCapability(Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG)) {
         GTEST_SUCCEED() << "Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG is not supported";
         return;
     }
 
-    const auto displayId = getPrimaryDisplayId();
-    EXPECT_TRUE(mComposerClient->setPowerMode(displayId, PowerMode::ON).isOk());
-    // Enable the callback
-    ASSERT_TRUE(mComposerClient
-                        ->setRefreshRateChangedCallbackDebugEnabled(displayId,
-                                                                    /*enabled*/ true)
-                        .isOk());
-    std::this_thread::sleep_for(100ms);
+    for (VtsDisplay& display : mDisplays) {
+        const auto displayId = display.getDisplayId();
+        EXPECT_TRUE(mComposerClient->setPowerMode(displayId, PowerMode::ON).isOk());
+        // Enable the callback
+        ASSERT_TRUE(mComposerClient
+                            ->setRefreshRateChangedCallbackDebugEnabled(displayId,
+                                                                        /*enabled*/ true)
+                            .isOk());
+        std::this_thread::sleep_for(100ms);
 
-    const auto displayFilter = [displayId](auto refreshRateChangedDebugData) {
-        return displayId == refreshRateChangedDebugData.display;
-    };
+        const auto [status, configId] = mComposerClient->getActiveConfig(display.getDisplayId());
+        EXPECT_TRUE(status.isOk());
 
-    // Check that we immediately got a callback
-    EXPECT_TRUE(checkIfCallbackRefreshRateChangedDebugEnabledReceived(displayFilter));
+        const auto displayFilter = [&](auto refreshRateChangedDebugData) {
+            bool nonVrrRateMatching = true;
+            if (std::optional<VrrConfig> vrrConfigOpt =
+                        display.getDisplayConfig(configId).vrrConfig;
+                getInterfaceVersion() >= 3 && !vrrConfigOpt) {
+                nonVrrRateMatching = refreshRateChangedDebugData.refreshPeriodNanos ==
+                                     refreshRateChangedDebugData.vsyncPeriodNanos;
+            }
+            const bool isDisplaySame =
+                    display.getDisplayId() == refreshRateChangedDebugData.display;
+            return nonVrrRateMatching && isDisplaySame;
+        };
 
-    ASSERT_TRUE(mComposerClient
-                        ->setRefreshRateChangedCallbackDebugEnabled(displayId,
-                                                                    /*enabled*/ false)
-                        .isOk());
+        // Check that we immediately got a callback
+        EXPECT_TRUE(checkIfCallbackRefreshRateChangedDebugEnabledReceived(displayFilter));
+
+        ASSERT_TRUE(mComposerClient
+                            ->setRefreshRateChangedCallbackDebugEnabled(displayId,
+                                                                        /*enabled*/ false)
+                            .isOk());
+    }
 }
 
-TEST_P(GraphicsComposerAidlCommandTest,
+TEST_P(GraphicsComposerAidlCommandV2Test,
        SetRefreshRateChangedCallbackDebugEnabled_noCallbackWhenIdle) {
-    if (getInterfaceVersion() <= 1) {
-        GTEST_SUCCEED() << "Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG is "
-                           "not supported on older version of the service";
-        return;
-    }
     if (!hasCapability(Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG)) {
         GTEST_SUCCEED() << "Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG is not supported";
         return;
@@ -2522,13 +2790,8 @@
                         .isOk());
 }
 
-TEST_P(GraphicsComposerAidlCommandTest,
+TEST_P(GraphicsComposerAidlCommandV2Test,
        SetRefreshRateChangedCallbackDebugEnabled_SetActiveConfigWithConstraints) {
-    if (getInterfaceVersion() <= 1) {
-        GTEST_SUCCEED() << "Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG is "
-                           "not supported on older version of the service";
-        return;
-    }
     if (!hasCapability(Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG)) {
         GTEST_SUCCEED() << "Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG is not supported";
         return;
@@ -2596,53 +2859,220 @@
     }
 }
 
-/*
- * Test that no two display configs are exactly the same.
- */
-TEST_P(GraphicsComposerAidlTest, GetDisplayConfigNoRepetitions) {
-    for (const auto& display : mDisplays) {
-        const auto& [status, configs] = mComposerClient->getDisplayConfigs(display.getDisplayId());
-        for (std::vector<int>::size_type i = 0; i < configs.size(); i++) {
-            for (std::vector<int>::size_type j = i + 1; j < configs.size(); j++) {
-                const auto& [widthStatus1, width1] = mComposerClient->getDisplayAttribute(
-                        display.getDisplayId(), configs[i], DisplayAttribute::WIDTH);
-                const auto& [heightStatus1, height1] = mComposerClient->getDisplayAttribute(
-                        display.getDisplayId(), configs[i], DisplayAttribute::HEIGHT);
-                const auto& [vsyncPeriodStatus1, vsyncPeriod1] =
-                        mComposerClient->getDisplayAttribute(display.getDisplayId(), configs[i],
-                                                             DisplayAttribute::VSYNC_PERIOD);
-                const auto& [groupStatus1, group1] = mComposerClient->getDisplayAttribute(
-                        display.getDisplayId(), configs[i], DisplayAttribute::CONFIG_GROUP);
-
-                const auto& [widthStatus2, width2] = mComposerClient->getDisplayAttribute(
-                        display.getDisplayId(), configs[j], DisplayAttribute::WIDTH);
-                const auto& [heightStatus2, height2] = mComposerClient->getDisplayAttribute(
-                        display.getDisplayId(), configs[j], DisplayAttribute::HEIGHT);
-                const auto& [vsyncPeriodStatus2, vsyncPeriod2] =
-                        mComposerClient->getDisplayAttribute(display.getDisplayId(), configs[j],
-                                                             DisplayAttribute::VSYNC_PERIOD);
-                const auto& [groupStatus2, group2] = mComposerClient->getDisplayAttribute(
-                        display.getDisplayId(), configs[j], DisplayAttribute::CONFIG_GROUP);
-
-                ASSERT_FALSE(width1 == width2 && height1 == height2 &&
-                             vsyncPeriod1 == vsyncPeriod2 && group1 == group2);
-            }
+TEST_P(GraphicsComposerAidlCommandTest, MultiThreadedPresent) {
+    std::vector<VtsDisplay*> displays;
+    for (auto& display : mDisplays) {
+        if (hasDisplayCapability(display.getDisplayId(),
+                                 DisplayCapability::MULTI_THREADED_PRESENT)) {
+            displays.push_back(&display);
         }
     }
+
+    const size_t numDisplays = displays.size();
+    if (numDisplays <= 1u) {
+        GTEST_SKIP();
+    }
+
+    // When multi-threaded, use a reader per display. As with mWriters, this mutex
+    // guards access to the map.
+    std::mutex readersMutex;
+    std::unordered_map<int64_t, ComposerClientReader> readers;
+    std::vector<std::thread> threads;
+    threads.reserve(numDisplays);
+
+    // Each display will have a layer to present. This maps from the display to
+    // the layer, so we can properly destroy each layer at the end.
+    std::unordered_map<int64_t, int64_t> layers;
+
+    for (auto* const display : displays) {
+        const int64_t displayId = display->getDisplayId();
+
+        // Ensure that all writers and readers have been added to their respective
+        // maps initially, so that the following loop never modifies the maps. The
+        // maps are accessed from different threads, and if the maps were modified,
+        // this would invalidate their iterators, and therefore references to the
+        // writers and readers.
+        auto& writer = getWriter(displayId);
+        {
+            std::lock_guard guard{readersMutex};
+            readers.try_emplace(displayId, displayId);
+        }
+
+        EXPECT_TRUE(mComposerClient->setPowerMode(displayId, PowerMode::ON).isOk());
+
+        const auto& [status, layer] =
+                mComposerClient->createLayer(displayId, kBufferSlotCount, &writer);
+        const auto buffer = allocate(::android::PIXEL_FORMAT_RGBA_8888);
+        ASSERT_NE(nullptr, buffer);
+        ASSERT_EQ(::android::OK, buffer->initCheck());
+        ASSERT_NE(nullptr, buffer->handle);
+
+        configureLayer(*display, layer, Composition::DEVICE, display->getFrameRect(),
+                       display->getCrop());
+        writer.setLayerBuffer(displayId, layer, /*slot*/ 0, buffer->handle,
+                              /*acquireFence*/ -1);
+        writer.setLayerDataspace(displayId, layer, common::Dataspace::UNKNOWN);
+        layers.try_emplace(displayId, layer);
+    }
+
+    for (auto* const display : displays) {
+        const int64_t displayId = display->getDisplayId();
+        auto& writer = getWriter(displayId);
+        std::unique_lock lock{readersMutex};
+        auto& reader = readers.at(displayId);
+        lock.unlock();
+
+        writer.validateDisplay(displayId, ComposerClientWriter::kNoTimestamp,
+                               VtsComposerClient::kNoFrameIntervalNs);
+        execute(writer, reader);
+
+        threads.emplace_back([this, displayId, &readers, &readersMutex]() {
+            auto& writer = getWriter(displayId);
+            std::unique_lock lock{readersMutex};
+            ComposerClientReader& reader = readers.at(displayId);
+            lock.unlock();
+
+            writer.presentDisplay(displayId);
+            execute(writer, reader);
+            ASSERT_TRUE(reader.takeErrors().empty());
+
+            auto presentFence = reader.takePresentFence(displayId);
+            // take ownership
+            const int fenceOwner = presentFence.get();
+            *presentFence.getR() = -1;
+            EXPECT_NE(-1, fenceOwner);
+            const auto presentFence2 = sp<::android::Fence>::make(fenceOwner);
+            presentFence2->waitForever(LOG_TAG);
+        });
+    }
+
+    for (auto& thread : threads) {
+        thread.join();
+    }
+
+    for (auto& [displayId, layer] : layers) {
+        auto& writer = getWriter(displayId);
+        EXPECT_TRUE(mComposerClient->destroyLayer(displayId, layer, &writer).isOk());
+    }
+
+    std::lock_guard guard{readersMutex};
+    for (auto& [displayId, reader] : readers) {
+        ASSERT_TRUE(reader.takeErrors().empty());
+        ASSERT_TRUE(reader.takeChangedCompositionTypes(displayId).empty());
+    }
 }
 
-/**
- * Test Capability::SKIP_VALIDATE
- *
- * Capability::SKIP_VALIDATE has been deprecated and should not be enabled.
- */
-TEST_P(GraphicsComposerAidlCommandTest, SkipValidateDeprecatedTest) {
-    if (getInterfaceVersion() <= 1) {
-        GTEST_SUCCEED() << "HAL at version 1 or lower can contain Capability::SKIP_VALIDATE.";
+class GraphicsComposerAidlCommandV3Test : public GraphicsComposerAidlCommandTest {
+  protected:
+    void SetUp() override {
+        GraphicsComposerAidlTest::SetUp();
+        if (getInterfaceVersion() <= 2) {
+            GTEST_SKIP() << "Device interface version is expected to be >= 3";
+        }
+    }
+};
+
+TEST_P(GraphicsComposerAidlCommandV3Test, CreateBatchedCommand) {
+    if (!hasCapability(Capability::LAYER_LIFECYCLE_BATCH_COMMAND)) {
+        GTEST_SKIP() << "LAYER_LIFECYCLE_BATCH_COMMAND not supported by the implementation";
         return;
     }
-    ASSERT_FALSE(hasCapability(Capability::SKIP_VALIDATE))
-            << "Found Capability::SKIP_VALIDATE capability.";
+
+    auto& writer = getWriter(getPrimaryDisplayId());
+    int64_t layer = 5;
+    writer.setLayerLifecycleBatchCommandType(getPrimaryDisplayId(), layer,
+                                             LayerLifecycleBatchCommandType::CREATE);
+    writer.setNewBufferSlotCount(getPrimaryDisplayId(), layer, 1);
+    writer.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp,
+                           VtsComposerClient::kNoFrameIntervalNs);
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+}
+
+TEST_P(GraphicsComposerAidlCommandV3Test, CreateBatchedCommand_BadDisplay) {
+    if (!hasCapability(Capability::LAYER_LIFECYCLE_BATCH_COMMAND)) {
+        GTEST_SKIP() << "LAYER_LIFECYCLE_BATCH_COMMAND not supported by the implementation";
+        return;
+    }
+
+    auto& writer = getWriter(getPrimaryDisplayId());
+    int64_t layer = 5;
+    writer.setLayerLifecycleBatchCommandType(getInvalidDisplayId(), layer,
+                                             LayerLifecycleBatchCommandType::CREATE);
+    writer.setNewBufferSlotCount(getPrimaryDisplayId(), layer, 1);
+    writer.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp,
+                           VtsComposerClient::kNoFrameIntervalNs);
+    execute();
+    const auto errors = mReader.takeErrors();
+    ASSERT_TRUE(errors.size() == 1 && errors[0].errorCode == IComposerClient::EX_BAD_DISPLAY);
+}
+
+TEST_P(GraphicsComposerAidlCommandV3Test, DestroyBatchedCommand) {
+    if (!hasCapability(Capability::LAYER_LIFECYCLE_BATCH_COMMAND)) {
+        GTEST_SKIP() << "LAYER_LIFECYCLE_BATCH_COMMAND not supported by the implementation";
+        return;
+    }
+
+    auto& writer = getWriter(getPrimaryDisplayId());
+    int64_t layer = 5;
+    writer.setLayerLifecycleBatchCommandType(getPrimaryDisplayId(), layer,
+                                             LayerLifecycleBatchCommandType::CREATE);
+    writer.setNewBufferSlotCount(getPrimaryDisplayId(), layer, 1);
+    writer.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp,
+                           VtsComposerClient::kNoFrameIntervalNs);
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+    writer.setLayerLifecycleBatchCommandType(getPrimaryDisplayId(), layer,
+                                             LayerLifecycleBatchCommandType::DESTROY);
+    layer++;
+    writer.setLayerLifecycleBatchCommandType(getPrimaryDisplayId(), layer,
+                                             LayerLifecycleBatchCommandType::CREATE);
+    writer.setNewBufferSlotCount(getPrimaryDisplayId(), layer, 1);
+
+    execute();
+    const auto errors = mReader.takeErrors();
+    ASSERT_TRUE(errors.size() == 1 && errors[0].errorCode == IComposerClient::EX_BAD_DISPLAY);
+}
+
+TEST_P(GraphicsComposerAidlCommandV3Test, DestroyBatchedCommand_BadDisplay) {
+    if (!hasCapability(Capability::LAYER_LIFECYCLE_BATCH_COMMAND)) {
+        GTEST_SKIP() << "LAYER_LIFECYCLE_BATCH_COMMAND not supported by the implementation";
+        return;
+    }
+
+    auto& writer = getWriter(getPrimaryDisplayId());
+    int64_t layer = 5;
+    writer.setLayerLifecycleBatchCommandType(getPrimaryDisplayId(), layer,
+                                             LayerLifecycleBatchCommandType::CREATE);
+    writer.setNewBufferSlotCount(getPrimaryDisplayId(), layer, 1);
+    writer.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp,
+                           VtsComposerClient::kNoFrameIntervalNs);
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+    writer.setLayerLifecycleBatchCommandType(getInvalidDisplayId(), layer,
+                                             LayerLifecycleBatchCommandType::DESTROY);
+    layer++;
+    writer.setLayerLifecycleBatchCommandType(getInvalidDisplayId(), layer,
+                                             LayerLifecycleBatchCommandType::CREATE);
+    writer.setNewBufferSlotCount(getPrimaryDisplayId(), layer, 1);
+
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+}
+
+TEST_P(GraphicsComposerAidlCommandV3Test, NoCreateDestroyBatchedCommandIncorrectLayer) {
+    if (!hasCapability(Capability::LAYER_LIFECYCLE_BATCH_COMMAND)) {
+        GTEST_SKIP() << "LAYER_LIFECYCLE_BATCH_COMMAND not supported by the implementation";
+        return;
+    }
+
+    auto& writer = getWriter(getPrimaryDisplayId());
+    int64_t layer = 5;
+    writer.setLayerLifecycleBatchCommandType(getPrimaryDisplayId(), layer,
+                                             LayerLifecycleBatchCommandType::DESTROY);
+    execute();
+    const auto errors = mReader.takeErrors();
+    ASSERT_TRUE(errors.size() == 1 && errors[0].errorCode == IComposerClient::EX_BAD_LAYER);
 }
 
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsComposerAidlCommandTest);
@@ -2650,13 +3080,31 @@
         PerInstance, GraphicsComposerAidlCommandTest,
         testing::ValuesIn(::android::getAidlHalInstanceNames(IComposer::descriptor)),
         ::android::PrintInstanceNameToString);
-
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsComposerAidlTest);
 INSTANTIATE_TEST_SUITE_P(
         PerInstance, GraphicsComposerAidlTest,
         testing::ValuesIn(::android::getAidlHalInstanceNames(IComposer::descriptor)),
         ::android::PrintInstanceNameToString);
-}  // namespace
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsComposerAidlV2Test);
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, GraphicsComposerAidlV2Test,
+        testing::ValuesIn(::android::getAidlHalInstanceNames(IComposer::descriptor)),
+        ::android::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsComposerAidlV3Test);
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, GraphicsComposerAidlV3Test,
+        testing::ValuesIn(::android::getAidlHalInstanceNames(IComposer::descriptor)),
+        ::android::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsComposerAidlCommandV2Test);
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, GraphicsComposerAidlCommandV2Test,
+        testing::ValuesIn(::android::getAidlHalInstanceNames(IComposer::descriptor)),
+        ::android::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsComposerAidlCommandV3Test);
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, GraphicsComposerAidlCommandV3Test,
+        testing::ValuesIn(::android::getAidlHalInstanceNames(IComposer::descriptor)),
+        ::android::PrintInstanceNameToString);
 }  // namespace aidl::android::hardware::graphics::composer3::vts
 
 int main(int argc, char** argv) {
diff --git a/graphics/mapper/4.0/utils/vts/Android.bp b/graphics/mapper/4.0/utils/vts/Android.bp
index 51e871b..7815d41 100644
--- a/graphics/mapper/4.0/utils/vts/Android.bp
+++ b/graphics/mapper/4.0/utils/vts/Android.bp
@@ -47,7 +47,7 @@
     ],
     export_static_lib_headers: [
         "android.hardware.graphics.allocator@4.0",
-        "android.hardware.graphics.common-V4-ndk",
+        "android.hardware.graphics.common-V5-ndk",
         "android.hardware.graphics.mapper@4.0",
     ],
     export_include_dirs: ["include"],
diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
index e4a84e1..bae362f 100644
--- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
+++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
@@ -677,7 +677,7 @@
 
     const native_handle_t* clonedBufferHandle;
     ASSERT_NO_FATAL_FAILURE(clonedBufferHandle = mGralloc->allocate(mDummyDescriptorInfo, false));
-    error = mGralloc->getMapper()->freeBuffer(invalidHandle);
+    error = mGralloc->getMapper()->freeBuffer(const_cast<native_handle_t*>(clonedBufferHandle));
     EXPECT_EQ(Error::BAD_BUFFER, error)
             << "freeBuffer with un-imported handle did not fail with BAD_BUFFER";
 
@@ -2223,11 +2223,14 @@
     // Keep optional metadata types below and populate the encoded metadata vec
     // with some arbitrary different metadata because the common gralloc4::decode*()
     // functions do not distinguish between an empty vec and bad value.
-    ASSERT_EQ(NO_ERROR, gralloc4::encodeDataspace(Dataspace::SRGB_LINEAR, &vec));
-    ASSERT_EQ(Error::UNSUPPORTED,
-              mGralloc->set(bufferHandle, gralloc4::MetadataType_Smpte2086, vec));
-    ASSERT_EQ(Error::UNSUPPORTED,
-              mGralloc->set(bufferHandle, gralloc4::MetadataType_Cta861_3, vec));
+    if (base::GetIntProperty("ro.vendor.api_level", __ANDROID_API_FUTURE__) >= __ANDROID_API_T__) {
+        // Some old grallocs shipped with broken validation.
+        ASSERT_EQ(NO_ERROR, gralloc4::encodeDataspace(Dataspace::SRGB_LINEAR, &vec));
+        ASSERT_EQ(Error::UNSUPPORTED,
+                  mGralloc->set(bufferHandle, gralloc4::MetadataType_Smpte2086, vec));
+        ASSERT_EQ(Error::UNSUPPORTED,
+                  mGralloc->set(bufferHandle, gralloc4::MetadataType_Cta861_3, vec));
+    }
 }
 
 /**
diff --git a/graphics/mapper/stable-c/implutils/include/android/hardware/graphics/mapper/utils/IMapperProvider.h b/graphics/mapper/stable-c/implutils/include/android/hardware/graphics/mapper/utils/IMapperProvider.h
index 957fdc9..c4d1a0d 100644
--- a/graphics/mapper/stable-c/implutils/include/android/hardware/graphics/mapper/utils/IMapperProvider.h
+++ b/graphics/mapper/stable-c/implutils/include/android/hardware/graphics/mapper/utils/IMapperProvider.h
@@ -106,15 +106,15 @@
     static_assert(std::is_constructible_v<IMPL>, "Implementation must have a no-args constructor");
 
     std::once_flag mLoadOnceFlag;
-    std::optional<IMPL> mImpl;
-    AIMapper mMapper = {};
+    IMPL* _Nullable mImpl;
+    AIMapper* _Nullable mMapper;
 
     static IMPL& impl() {
         return *reinterpret_cast<IMapperProvider<IMPL>*>(provider::sIMapperInstance)->mImpl;
     }
 
     void bindV5() {
-        mMapper.v5 = {
+        mMapper->v5 = {
                 .importBuffer = [](const native_handle_t* _Nonnull handle,
                                    buffer_handle_t _Nullable* _Nonnull outBufferHandle)
                         -> AIMapper_Error { return impl().importBuffer(handle, outBufferHandle); },
@@ -208,13 +208,14 @@
             LOG_ALWAYS_FATAL_IF(provider::sIMapperInstance != nullptr,
                                 "AIMapper implementation already loaded!");
             provider::sIMapperInstance = this;
-            mImpl.emplace();
-            mMapper.version = IMPL::version;
+            mImpl = new IMPL();
+            mMapper = new AIMapper();
+            mMapper->version = IMPL::version;
             if (IMPL::version >= AIMAPPER_VERSION_5) {
                 bindV5();
             }
         });
-        *outImplementation = &mMapper;
+        *outImplementation = mMapper;
         return AIMAPPER_ERROR_NONE;
     }
 };
diff --git a/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp b/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp
index 2c06353..b329de2 100644
--- a/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp
+++ b/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp
@@ -1371,6 +1371,28 @@
     EXPECT_EQ(buffer->info().usage, *value);
 }
 
+TEST_P(GraphicsMapperStableCTests, GetUsage64) {
+    BufferDescriptorInfo info{
+            .name = {"VTS_TEMP"},
+            .width = 64,
+            .height = 64,
+            .layerCount = 1,
+            .format = PixelFormat::RGBA_8888,
+            .usage = BufferUsage::FRONT_BUFFER | BufferUsage::GPU_RENDER_TARGET |
+                     BufferUsage::COMPOSER_OVERLAY | BufferUsage::GPU_TEXTURE,
+            .reservedSize = 0,
+    };
+    if (!isSupported(info)) {
+        GTEST_SKIP();
+    }
+    auto buffer = allocate(info);
+    auto bufferHandle = buffer->import();
+    auto value = getStandardMetadata<StandardMetadataType::USAGE>(*bufferHandle);
+    ASSERT_TRUE(value.has_value());
+    using T = std::underlying_type_t<BufferUsage>;
+    EXPECT_EQ(static_cast<T>(buffer->info().usage), static_cast<T>(*value));
+}
+
 TEST_P(GraphicsMapperStableCTests, GetAllocationSize) {
     auto buffer = allocateGeneric();
     auto bufferHandle = buffer->import();
diff --git a/health/1.0/default/convert.cpp b/health/1.0/default/convert.cpp
index 3680d4d..e12e197 100644
--- a/health/1.0/default/convert.cpp
+++ b/health/1.0/default/convert.cpp
@@ -26,19 +26,18 @@
     config.periodicChoresIntervalFast = hc->periodic_chores_interval_fast;
     config.periodicChoresIntervalSlow = hc->periodic_chores_interval_slow;
 
-    config.batteryStatusPath        = hc->batteryStatusPath.string();
-    config.batteryHealthPath        = hc->batteryHealthPath.string();
-    config.batteryPresentPath       = hc->batteryPresentPath.string();
-    config.batteryCapacityPath      = hc->batteryCapacityPath.string();
-    config.batteryVoltagePath       = hc->batteryVoltagePath.string();
-    config.batteryTemperaturePath   = hc->batteryTemperaturePath.string();
-    config.batteryTechnologyPath    = hc->batteryTechnologyPath.string();
-    config.batteryCurrentNowPath    = hc->batteryCurrentNowPath.string();
-    config.batteryCurrentAvgPath    = hc->batteryCurrentAvgPath.string();
-    config.batteryChargeCounterPath = hc->batteryChargeCounterPath.string();
-    config.batteryFullChargePath    = hc->batteryFullChargePath.string();
-    config.batteryCycleCountPath    = hc->batteryCycleCountPath.string();
-
+    config.batteryStatusPath = hc->batteryStatusPath.c_str();
+    config.batteryHealthPath = hc->batteryHealthPath.c_str();
+    config.batteryPresentPath = hc->batteryPresentPath.c_str();
+    config.batteryCapacityPath = hc->batteryCapacityPath.c_str();
+    config.batteryVoltagePath = hc->batteryVoltagePath.c_str();
+    config.batteryTemperaturePath = hc->batteryTemperaturePath.c_str();
+    config.batteryTechnologyPath = hc->batteryTechnologyPath.c_str();
+    config.batteryCurrentNowPath = hc->batteryCurrentNowPath.c_str();
+    config.batteryCurrentAvgPath = hc->batteryCurrentAvgPath.c_str();
+    config.batteryChargeCounterPath = hc->batteryChargeCounterPath.c_str();
+    config.batteryFullChargePath = hc->batteryFullChargePath.c_str();
+    config.batteryCycleCountPath = hc->batteryCycleCountPath.c_str();
 }
 
 void convertFromHealthConfig(const HealthConfig& c, struct healthd_config *hc) {
@@ -118,7 +117,7 @@
     info.batteryCycleCount      = p->batteryCycleCount;
     info.batteryFullCharge      = p->batteryFullCharge;
     info.batteryChargeCounter   = p->batteryChargeCounter;
-    info.batteryTechnology      = p->batteryTechnology;
+    info.batteryTechnology      = p->batteryTechnology.c_str();
 }
 
 void convertFromHealthInfo(const HealthInfo& info,
diff --git a/health/2.0/README.md b/health/2.0/README.md
index 8a7c922..1c636c7 100644
--- a/health/2.0/README.md
+++ b/health/2.0/README.md
@@ -1,181 +1,7 @@
-# Implement the 2.1 HAL instead!
+# Deprecated.
 
-It is strongly recommended that you implement the 2.1 HAL directly. See
-`hardware/interfaces/health/2.1/README.md` for more details.
+Health HIDL HAL 2.0 is deprecated and subject to removal. Please
+implement the Health AIDL HAL instead.
 
-# Upgrading from Health 1.0 HAL
-
-1. Remove `android.hardware.health@1.0*` from `PRODUCT_PACKAGES`
-   in `device/<manufacturer>/<device>/device.mk`
-
-1. If the device does not have a vendor-specific `libhealthd` AND does not
-   implement storage-related APIs, just do the following:
-
-   ```mk
-   PRODUCT_PACKAGES += android.hardware.health@2.0-service
-   ```
-
-   Otherwise, continue to the next step.
-
-1. Create directory
-   `device/<manufacturer>/<device>/health`
-
-1. Create `device/<manufacturer>/<device>/health/Android.bp`
-   (or equivalent `device/<manufacturer>/<device>/health/Android.mk`)
-
-    ```bp
-    cc_binary {
-        name: "android.hardware.health@2.0-service.<device>",
-        init_rc: ["android.hardware.health@2.0-service.<device>.rc"],
-        proprietary: true,
-        relative_install_path: "hw",
-        srcs: [
-            "HealthService.cpp",
-        ],
-
-        cflags: [
-            "-Wall",
-            "-Werror",
-        ],
-
-        static_libs: [
-            "android.hardware.health@2.0-impl",
-            "android.hardware.health@1.0-convert",
-            "libhealthservice",
-            "libbatterymonitor",
-        ],
-
-        shared_libs: [
-            "libbase",
-            "libcutils",
-            "libhidlbase",
-            "libutils",
-            "android.hardware.health@2.0",
-        ],
-
-        header_libs: ["libhealthd_headers"],
-
-        overrides: [
-            "healthd",
-        ],
-    }
-    ```
-
-    1. (recommended) To remove `healthd` from the build, keep "overrides" section.
-    1. To keep `healthd` in the build, remove "overrides" section.
-
-1. Create `device/<manufacturer>/<device>/health/android.hardware.health@2.0-service.<device>.rc`
-
-    ```rc
-    service vendor.health-hal-2-0 /vendor/bin/hw/android.hardware.health@2.0-service.<device>
-        class hal
-        user system
-        group system
-        capabilities WAKE_ALARM
-        file /dev/kmsg w
-    ```
-
-1. Create `device/<manufacturer>/<device>/health/HealthService.cpp`:
-
-    ```c++
-    #include <health2/service.h>
-    int main() { return health_service_main(); }
-    ```
-
-1. `libhealthd` dependency:
-
-    1. If the device has a vendor-specific `libhealthd.<soc>`, add it to static_libs.
-
-    1. If the device does not have a vendor-specific `libhealthd`, add the following
-        lines to `HealthService.cpp`:
-
-        ```c++
-        #include <healthd/healthd.h>
-        void healthd_board_init(struct healthd_config*) {}
-
-        int healthd_board_battery_update(struct android::BatteryProperties*) {
-            // return 0 to log periodic polled battery status to kernel log
-            return 0;
-        }
-        ```
-
-1. Storage related APIs:
-
-    1. If the device does not implement `IHealth.getDiskStats` and
-        `IHealth.getStorageInfo`, add `libhealthstoragedefault` to `static_libs`.
-
-    1. If the device implements one of these two APIs, add and implement the
-        following functions in `HealthService.cpp`:
-
-        ```c++
-        void get_storage_info(std::vector<struct StorageInfo>& info) {
-            // ...
-        }
-        void get_disk_stats(std::vector<struct DiskStats>& stats) {
-            // ...
-        }
-        ```
-
-1. Update necessary SELinux permissions. For example,
-
-    ```
-    # device/<manufacturer>/<device>/sepolicy/vendor/file_contexts
-    /vendor/bin/hw/android\.hardware\.health@2\.0-service\.<device> u:object_r:hal_health_default_exec:s0
-
-    # device/<manufacturer>/<device>/sepolicy/vendor/hal_health_default.te
-    # Add device specific permissions to hal_health_default domain, especially
-    # if a device-specific libhealthd is used and/or device-specific storage related
-    # APIs are implemented.
-    ```
-
-1. Implementing health HAL in recovery. The health HAL is used for battery
-status checks during OTA for non-A/B devices. If the health HAL is not
-implemented in recovery, `is_battery_ok()` will always return `true`.
-
-    1. If the device does not have a vendor-specific `libhealthd`, nothing needs to
-    be done. A "backup" implementation is provided in
-    `android.hardware.health@2.0-impl-default`, which is always installed to recovery
-    image by default.
-
-    1. If the device does have a vendor-specific `libhealthd`, implement the following
-    module and include it in `PRODUCT_PACKAGES` (replace `<device>` with appropriate
-    strings):
-
-    ```bp
-    // Android.bp
-    cc_library_shared {
-        name: "android.hardware.health@2.0-impl-<device>",
-        recovery_available: true,
-        relative_install_path: "hw",
-        static_libs: [
-            "android.hardware.health@2.0-impl",
-            "libhealthd.<device>"
-            // Include the following or implement device-specific storage APIs
-            "libhealthstoragedefault",
-        ],
-        srcs: [
-            "HealthImpl.cpp",
-        ],
-        overrides: [
-            "android.hardware.health@2.0-impl-default",
-        ],
-    }
-    ```
-
-    ```c++
-    // HealthImpl.cpp
-    #include <health2/Health.h>
-    #include <healthd/healthd.h>
-    using android::hardware::health::V2_0::IHealth;
-    using android::hardware::health::V2_0::implementation::Health;
-    extern "C" IHealth* HIDL_FETCH_IHealth(const char* name) {
-        const static std::string providedInstance{"default"};
-        if (providedInstance != name) return nullptr;
-        return Health::initInstance(&gHealthdConfig).get();
-    }
-    ```
-
-    ```mk
-    # device.mk
-    PRODUCT_PACKAGES += android.hardware.health@2.0-impl-<device>
-    ```
+See [`hardware/interfaces/health/aidl/README.md`](../aidl/README.md) for
+details.
diff --git a/health/2.0/default/Android.bp b/health/2.0/default/Android.bp
deleted file mode 100644
index 73cd553..0000000
--- a/health/2.0/default/Android.bp
+++ /dev/null
@@ -1,72 +0,0 @@
-package {
-    // See: http://go/android-license-faq
-    // A large-scale-change added 'default_applicable_licenses' to import
-    // all of the 'license_kinds' from "hardware_interfaces_license"
-    // to get the below license kinds:
-    //   SPDX-license-identifier-Apache-2.0
-    default_applicable_licenses: ["hardware_interfaces_license"],
-}
-
-cc_defaults {
-    name: "android.hardware.health@2.0-impl_defaults",
-
-    recovery_available: true,
-    cflags: [
-        "-Wall",
-        "-Werror",
-    ],
-
-    shared_libs: [
-        "libbase",
-        "libhidlbase",
-        "liblog",
-        "libutils",
-        "libcutils",
-        "android.hardware.health@2.0",
-    ],
-
-    static_libs: [
-        "libbatterymonitor",
-        "android.hardware.health@1.0-convert",
-    ],
-}
-
-// Helper library for implementing health HAL. It is recommended that a health
-// service or passthrough HAL link to this library.
-cc_library_static {
-    name: "android.hardware.health@2.0-impl",
-    defaults: ["android.hardware.health@2.0-impl_defaults"],
-
-    vendor_available: true,
-    srcs: [
-        "Health.cpp",
-        "healthd_common_adapter.cpp",
-    ],
-
-    whole_static_libs: [
-        "libhealthloop",
-    ],
-
-    export_include_dirs: ["include"],
-}
-
-// Default passthrough implementation for recovery. Vendors can implement
-// android.hardware.health@2.0-impl-recovery-<device> to customize the behavior
-// of the HAL in recovery.
-// The implementation does NOT start the uevent loop for polling.
-cc_library_shared {
-    name: "android.hardware.health@2.0-impl-default",
-    defaults: ["android.hardware.health@2.0-impl_defaults"],
-
-    recovery_available: true,
-    relative_install_path: "hw",
-
-    static_libs: [
-        "android.hardware.health@2.0-impl",
-        "libhealthstoragedefault",
-    ],
-
-    srcs: [
-        "HealthImplDefault.cpp",
-    ],
-}
diff --git a/health/2.0/default/Health.cpp b/health/2.0/default/Health.cpp
deleted file mode 100644
index 65eada8..0000000
--- a/health/2.0/default/Health.cpp
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#define LOG_TAG "android.hardware.health@2.0-impl"
-#include <android-base/logging.h>
-
-#include <android-base/file.h>
-#include <android/hardware/health/2.0/types.h>
-#include <health2/Health.h>
-
-#include <hal_conversion.h>
-#include <hidl/HidlTransportSupport.h>
-
-using HealthInfo_1_0 = android::hardware::health::V1_0::HealthInfo;
-using android::hardware::health::V1_0::hal_conversion::convertFromHealthInfo;
-
-extern void healthd_battery_update_internal(bool);
-
-namespace android {
-namespace hardware {
-namespace health {
-namespace V2_0 {
-namespace implementation {
-
-sp<Health> Health::instance_;
-
-Health::Health(struct healthd_config* c) {
-    // TODO(b/69268160): remove when libhealthd is removed.
-    healthd_board_init(c);
-    battery_monitor_ = std::make_unique<BatteryMonitor>();
-    battery_monitor_->init(c);
-}
-
-// Methods from IHealth follow.
-Return<Result> Health::registerCallback(const sp<IHealthInfoCallback>& callback) {
-    if (callback == nullptr) {
-        return Result::SUCCESS;
-    }
-
-    {
-        std::lock_guard<decltype(callbacks_lock_)> lock(callbacks_lock_);
-        callbacks_.push_back(callback);
-        // unlock
-    }
-
-    auto linkRet = callback->linkToDeath(this, 0u /* cookie */);
-    if (!linkRet.withDefault(false)) {
-        LOG(WARNING) << __func__ << "Cannot link to death: "
-                     << (linkRet.isOk() ? "linkToDeath returns false" : linkRet.description());
-        // ignore the error
-    }
-
-    return updateAndNotify(callback);
-}
-
-bool Health::unregisterCallbackInternal(const sp<IBase>& callback) {
-    if (callback == nullptr) return false;
-
-    bool removed = false;
-    std::lock_guard<decltype(callbacks_lock_)> lock(callbacks_lock_);
-    for (auto it = callbacks_.begin(); it != callbacks_.end();) {
-        if (interfacesEqual(*it, callback)) {
-            it = callbacks_.erase(it);
-            removed = true;
-        } else {
-            ++it;
-        }
-    }
-    (void)callback->unlinkToDeath(this).isOk();  // ignore errors
-    return removed;
-}
-
-Return<Result> Health::unregisterCallback(const sp<IHealthInfoCallback>& callback) {
-    return unregisterCallbackInternal(callback) ? Result::SUCCESS : Result::NOT_FOUND;
-}
-
-template <typename T>
-void getProperty(const std::unique_ptr<BatteryMonitor>& monitor, int id, T defaultValue,
-                 const std::function<void(Result, T)>& callback) {
-    struct BatteryProperty prop;
-    T ret = defaultValue;
-    Result result = Result::SUCCESS;
-    status_t err = monitor->getProperty(static_cast<int>(id), &prop);
-    if (err != OK) {
-        LOG(DEBUG) << "getProperty(" << id << ")"
-                   << " fails: (" << err << ") " << strerror(-err);
-    } else {
-        ret = static_cast<T>(prop.valueInt64);
-    }
-    switch (err) {
-        case OK:
-            result = Result::SUCCESS;
-            break;
-        case NAME_NOT_FOUND:
-            result = Result::NOT_SUPPORTED;
-            break;
-        default:
-            result = Result::UNKNOWN;
-            break;
-    }
-    callback(result, static_cast<T>(ret));
-}
-
-Return<void> Health::getChargeCounter(getChargeCounter_cb _hidl_cb) {
-    getProperty<int32_t>(battery_monitor_, BATTERY_PROP_CHARGE_COUNTER, 0, _hidl_cb);
-    return Void();
-}
-
-Return<void> Health::getCurrentNow(getCurrentNow_cb _hidl_cb) {
-    getProperty<int32_t>(battery_monitor_, BATTERY_PROP_CURRENT_NOW, 0, _hidl_cb);
-    return Void();
-}
-
-Return<void> Health::getCurrentAverage(getCurrentAverage_cb _hidl_cb) {
-    getProperty<int32_t>(battery_monitor_, BATTERY_PROP_CURRENT_AVG, 0, _hidl_cb);
-    return Void();
-}
-
-Return<void> Health::getCapacity(getCapacity_cb _hidl_cb) {
-    getProperty<int32_t>(battery_monitor_, BATTERY_PROP_CAPACITY, 0, _hidl_cb);
-    return Void();
-}
-
-Return<void> Health::getEnergyCounter(getEnergyCounter_cb _hidl_cb) {
-    getProperty<int64_t>(battery_monitor_, BATTERY_PROP_ENERGY_COUNTER, 0, _hidl_cb);
-    return Void();
-}
-
-Return<void> Health::getChargeStatus(getChargeStatus_cb _hidl_cb) {
-    getProperty(battery_monitor_, BATTERY_PROP_BATTERY_STATUS, BatteryStatus::UNKNOWN, _hidl_cb);
-    return Void();
-}
-
-Return<Result> Health::update() {
-    if (!healthd_mode_ops || !healthd_mode_ops->battery_update) {
-        LOG(WARNING) << "health@2.0: update: not initialized. "
-                     << "update() should not be called in charger";
-        return Result::UNKNOWN;
-    }
-
-    // Retrieve all information and call healthd_mode_ops->battery_update, which calls
-    // notifyListeners.
-    battery_monitor_->updateValues();
-    const HealthInfo_1_0& health_info = battery_monitor_->getHealthInfo_1_0();
-    struct BatteryProperties props;
-    convertFromHealthInfo(health_info, &props);
-    bool log = (healthd_board_battery_update(&props) == 0);
-    if (log) {
-        battery_monitor_->logValues();
-    }
-    healthd_mode_ops->battery_update(&props);
-    bool chargerOnline = battery_monitor_->isChargerOnline();
-
-    // adjust uevent / wakealarm periods
-    healthd_battery_update_internal(chargerOnline);
-
-    return Result::SUCCESS;
-}
-
-Return<Result> Health::updateAndNotify(const sp<IHealthInfoCallback>& callback) {
-    std::lock_guard<decltype(callbacks_lock_)> lock(callbacks_lock_);
-    std::vector<sp<IHealthInfoCallback>> storedCallbacks{std::move(callbacks_)};
-    callbacks_.clear();
-    if (callback != nullptr) {
-        callbacks_.push_back(callback);
-    }
-    Return<Result> result = update();
-    callbacks_ = std::move(storedCallbacks);
-    return result;
-}
-
-void Health::notifyListeners(HealthInfo* healthInfo) {
-    std::vector<StorageInfo> info;
-    get_storage_info(info);
-
-    std::vector<DiskStats> stats;
-    get_disk_stats(stats);
-
-    int32_t currentAvg = 0;
-
-    struct BatteryProperty prop;
-    status_t ret = battery_monitor_->getProperty(BATTERY_PROP_CURRENT_AVG, &prop);
-    if (ret == OK) {
-        currentAvg = static_cast<int32_t>(prop.valueInt64);
-    }
-
-    healthInfo->batteryCurrentAverage = currentAvg;
-    healthInfo->diskStats = stats;
-    healthInfo->storageInfos = info;
-
-    std::lock_guard<decltype(callbacks_lock_)> lock(callbacks_lock_);
-    for (auto it = callbacks_.begin(); it != callbacks_.end();) {
-        auto ret = (*it)->healthInfoChanged(*healthInfo);
-        if (!ret.isOk() && ret.isDeadObject()) {
-            it = callbacks_.erase(it);
-        } else {
-            ++it;
-        }
-    }
-}
-
-Return<void> Health::debug(const hidl_handle& handle, const hidl_vec<hidl_string>&) {
-    if (handle != nullptr && handle->numFds >= 1) {
-        int fd = handle->data[0];
-        battery_monitor_->dumpState(fd);
-
-        getHealthInfo([fd](auto res, const auto& info) {
-            android::base::WriteStringToFd("\ngetHealthInfo -> ", fd);
-            if (res == Result::SUCCESS) {
-                android::base::WriteStringToFd(toString(info), fd);
-            } else {
-                android::base::WriteStringToFd(toString(res), fd);
-            }
-            android::base::WriteStringToFd("\n", fd);
-        });
-
-        fsync(fd);
-    }
-    return Void();
-}
-
-Return<void> Health::getStorageInfo(getStorageInfo_cb _hidl_cb) {
-    std::vector<struct StorageInfo> info;
-    get_storage_info(info);
-    hidl_vec<struct StorageInfo> info_vec(info);
-    if (!info.size()) {
-        _hidl_cb(Result::NOT_SUPPORTED, info_vec);
-    } else {
-        _hidl_cb(Result::SUCCESS, info_vec);
-    }
-    return Void();
-}
-
-Return<void> Health::getDiskStats(getDiskStats_cb _hidl_cb) {
-    std::vector<struct DiskStats> stats;
-    get_disk_stats(stats);
-    hidl_vec<struct DiskStats> stats_vec(stats);
-    if (!stats.size()) {
-        _hidl_cb(Result::NOT_SUPPORTED, stats_vec);
-    } else {
-        _hidl_cb(Result::SUCCESS, stats_vec);
-    }
-    return Void();
-}
-
-Return<void> Health::getHealthInfo(getHealthInfo_cb _hidl_cb) {
-    using android::hardware::health::V1_0::hal_conversion::convertToHealthInfo;
-
-    updateAndNotify(nullptr);
-    HealthInfo healthInfo = battery_monitor_->getHealthInfo_2_0();
-
-    std::vector<StorageInfo> info;
-    get_storage_info(info);
-
-    std::vector<DiskStats> stats;
-    get_disk_stats(stats);
-
-    int32_t currentAvg = 0;
-
-    struct BatteryProperty prop;
-    status_t ret = battery_monitor_->getProperty(BATTERY_PROP_CURRENT_AVG, &prop);
-    if (ret == OK) {
-        currentAvg = static_cast<int32_t>(prop.valueInt64);
-    }
-
-    healthInfo.batteryCurrentAverage = currentAvg;
-    healthInfo.diskStats = stats;
-    healthInfo.storageInfos = info;
-
-    _hidl_cb(Result::SUCCESS, healthInfo);
-    return Void();
-}
-
-void Health::serviceDied(uint64_t /* cookie */, const wp<IBase>& who) {
-    (void)unregisterCallbackInternal(who.promote());
-}
-
-sp<IHealth> Health::initInstance(struct healthd_config* c) {
-    if (instance_ == nullptr) {
-        instance_ = new Health(c);
-    }
-    return instance_;
-}
-
-sp<Health> Health::getImplementation() {
-    CHECK(instance_ != nullptr);
-    return instance_;
-}
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace health
-}  // namespace hardware
-}  // namespace android
diff --git a/health/2.0/default/HealthImplDefault.cpp b/health/2.0/default/HealthImplDefault.cpp
deleted file mode 100644
index 08fee9e..0000000
--- a/health/2.0/default/HealthImplDefault.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <health2/Health.h>
-#include <healthd/healthd.h>
-
-using android::hardware::health::V2_0::IHealth;
-using android::hardware::health::V2_0::implementation::Health;
-
-static struct healthd_config gHealthdConfig = {
-    .energyCounter = nullptr,
-    .boot_min_cap = 0,
-    .screen_on = nullptr};
-
-void healthd_board_init(struct healthd_config*) {
-    // use defaults
-}
-
-int healthd_board_battery_update(struct android::BatteryProperties*) {
-    // return 0 to log periodic polled battery status to kernel log
-    return 0;
-}
-
-void healthd_mode_default_impl_init(struct healthd_config*) {
-    // noop
-}
-
-int healthd_mode_default_impl_preparetowait(void) {
-    return -1;
-}
-
-void healthd_mode_default_impl_heartbeat(void) {
-    // noop
-}
-
-void healthd_mode_default_impl_battery_update(struct android::BatteryProperties*) {
-    // noop
-}
-
-static struct healthd_mode_ops healthd_mode_default_impl_ops = {
-    .init = healthd_mode_default_impl_init,
-    .preparetowait = healthd_mode_default_impl_preparetowait,
-    .heartbeat = healthd_mode_default_impl_heartbeat,
-    .battery_update = healthd_mode_default_impl_battery_update,
-};
-
-extern "C" IHealth* HIDL_FETCH_IHealth(const char* name) {
-    const static std::string providedInstance{"backup"};
-    healthd_mode_ops = &healthd_mode_default_impl_ops;
-    if (providedInstance == name) {
-        // use defaults
-        // Health class stores static instance
-        return Health::initInstance(&gHealthdConfig).get();
-    }
-    return nullptr;
-}
diff --git a/health/2.0/default/healthd_common_adapter.cpp b/health/2.0/default/healthd_common_adapter.cpp
deleted file mode 100644
index 0b5d869..0000000
--- a/health/2.0/default/healthd_common_adapter.cpp
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// Support legacy functions in healthd/healthd.h using healthd_mode_ops.
-// New code should use HealthLoop directly instead.
-
-#include <memory>
-
-#include <cutils/klog.h>
-#include <health/HealthLoop.h>
-#include <health2/Health.h>
-#include <healthd/healthd.h>
-
-using android::hardware::health::HealthLoop;
-using android::hardware::health::V2_0::implementation::Health;
-
-struct healthd_mode_ops* healthd_mode_ops = nullptr;
-
-// Adapter of HealthLoop to use legacy healthd_mode_ops.
-class HealthLoopAdapter : public HealthLoop {
-   public:
-    // Expose internal functions, assuming clients calls them in the same thread
-    // where StartLoop is called.
-    int RegisterEvent(int fd, BoundFunction func, EventWakeup wakeup) {
-        return HealthLoop::RegisterEvent(fd, func, wakeup);
-    }
-    void AdjustWakealarmPeriods(bool charger_online) {
-        return HealthLoop::AdjustWakealarmPeriods(charger_online);
-    }
-   protected:
-    void Init(healthd_config* config) override { healthd_mode_ops->init(config); }
-    void Heartbeat() override { healthd_mode_ops->heartbeat(); }
-    int PrepareToWait() override { return healthd_mode_ops->preparetowait(); }
-    void ScheduleBatteryUpdate() override { Health::getImplementation()->update(); }
-};
-static std::unique_ptr<HealthLoopAdapter> health_loop;
-
-int healthd_register_event(int fd, void (*handler)(uint32_t), EventWakeup wakeup) {
-    if (!health_loop) return -1;
-
-    auto wrapped_handler = [handler](auto*, uint32_t epevents) { handler(epevents); };
-    return health_loop->RegisterEvent(fd, wrapped_handler, wakeup);
-}
-
-void healthd_battery_update_internal(bool charger_online) {
-    if (!health_loop) return;
-    health_loop->AdjustWakealarmPeriods(charger_online);
-}
-
-int healthd_main() {
-    if (!healthd_mode_ops) {
-        KLOG_ERROR("healthd ops not set, exiting\n");
-        exit(1);
-    }
-
-    health_loop = std::make_unique<HealthLoopAdapter>();
-
-    int ret = health_loop->StartLoop();
-
-    // Should not reach here. The following will exit().
-    health_loop.reset();
-
-    return ret;
-}
diff --git a/health/2.0/default/include/health2/Health.h b/health/2.0/default/include/health2/Health.h
deleted file mode 100644
index 6410474..0000000
--- a/health/2.0/default/include/health2/Health.h
+++ /dev/null
@@ -1,79 +0,0 @@
-#ifndef ANDROID_HARDWARE_HEALTH_V2_0_HEALTH_H
-#define ANDROID_HARDWARE_HEALTH_V2_0_HEALTH_H
-
-#include <memory>
-#include <vector>
-
-#include <android/hardware/health/1.0/types.h>
-#include <android/hardware/health/2.0/IHealth.h>
-#include <healthd/BatteryMonitor.h>
-#include <hidl/Status.h>
-
-using android::hardware::health::V2_0::StorageInfo;
-using android::hardware::health::V2_0::DiskStats;
-
-void get_storage_info(std::vector<struct StorageInfo>& info);
-void get_disk_stats(std::vector<struct DiskStats>& stats);
-
-namespace android {
-namespace hardware {
-namespace health {
-namespace V2_0 {
-namespace implementation {
-
-using V1_0::BatteryStatus;
-
-using ::android::hidl::base::V1_0::IBase;
-
-struct Health : public IHealth, hidl_death_recipient {
-   public:
-    static sp<IHealth> initInstance(struct healthd_config* c);
-    // Should only be called by implementation itself (-impl, -service).
-    // Clients should not call this function. Instead, initInstance() initializes and returns the
-    // global instance that has fewer functions.
-    static sp<Health> getImplementation();
-
-    Health(struct healthd_config* c);
-
-    void notifyListeners(HealthInfo* info);
-
-    // Methods from IHealth follow.
-    Return<Result> registerCallback(const sp<IHealthInfoCallback>& callback) override;
-    Return<Result> unregisterCallback(const sp<IHealthInfoCallback>& callback) override;
-    Return<Result> update() override;
-    Return<void> getChargeCounter(getChargeCounter_cb _hidl_cb) override;
-    Return<void> getCurrentNow(getCurrentNow_cb _hidl_cb) override;
-    Return<void> getCurrentAverage(getCurrentAverage_cb _hidl_cb) override;
-    Return<void> getCapacity(getCapacity_cb _hidl_cb) override;
-    Return<void> getEnergyCounter(getEnergyCounter_cb _hidl_cb) override;
-    Return<void> getChargeStatus(getChargeStatus_cb _hidl_cb) override;
-    Return<void> getStorageInfo(getStorageInfo_cb _hidl_cb) override;
-    Return<void> getDiskStats(getDiskStats_cb _hidl_cb) override;
-    Return<void> getHealthInfo(getHealthInfo_cb _hidl_cb) override;
-
-    // Methods from ::android::hidl::base::V1_0::IBase follow.
-    Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) override;
-
-    void serviceDied(uint64_t cookie, const wp<IBase>& /* who */) override;
-
-   private:
-    static sp<Health> instance_;
-
-    std::recursive_mutex callbacks_lock_;
-    std::vector<sp<IHealthInfoCallback>> callbacks_;
-    std::unique_ptr<BatteryMonitor> battery_monitor_;
-
-    bool unregisterCallbackInternal(const sp<IBase>& cb);
-
-    // update() and only notify the given callback, but none of the other callbacks.
-    // If cb is null, do not notify any callback at all.
-    Return<Result> updateAndNotify(const sp<IHealthInfoCallback>& cb);
-};
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace health
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_HEALTH_V2_0_HEALTH_H
diff --git a/health/2.0/utils/README.md b/health/2.0/utils/README.md
index c59b3f3..3fc8dab 100644
--- a/health/2.0/utils/README.md
+++ b/health/2.0/utils/README.md
@@ -6,25 +6,3 @@
 calling `IHealth::getService()` directly.
 
 Its Java equivalent can be found in `BatteryService.HealthServiceWrapper`.
-
-# libhealthservice
-
-Common code for all (hwbinder) services of the health HAL, including healthd and
-vendor health service `android.hardware.health@2.0-service(.<vendor>)`. `main()` in
-those binaries calls `health_service_main()` directly.
-
-# libhealthstoragedefault
-
-Default implementation for storage related APIs for (hwbinder) services of the
-health HAL. If an implementation of the health HAL do not wish to provide any
-storage info, include this library. Otherwise, it should implement the following
-two functions:
-
-```c++
-void get_storage_info(std::vector<struct StorageInfo>& info) {
-    // ...
-}
-void get_disk_stats(std::vector<struct DiskStats>& stats) {
-    // ...
-}
-```
diff --git a/health/2.0/utils/libhealthhalutils/HealthHalUtils.cpp b/health/2.0/utils/libhealthhalutils/HealthHalUtils.cpp
index 3c353e6..67f0ecc 100644
--- a/health/2.0/utils/libhealthhalutils/HealthHalUtils.cpp
+++ b/health/2.0/utils/libhealthhalutils/HealthHalUtils.cpp
@@ -24,34 +24,14 @@
 namespace health {
 namespace V2_0 {
 
+// Deprecated. Kept to minimize migration cost.
+// The function can be removed once Health 2.1 is removed
+// (i.e. compatibility_matrix.7.xml is the lowest supported level).
 sp<IHealth> get_health_service() {
-    // For the core and vendor variant, the "backup" instance points to healthd,
-    // which is removed.
-    // For the recovery variant, the "backup" instance has a different
-    // meaning. It points to android.hardware.health@2.0-impl-default.recovery
-    // which was assumed by OEMs to be always installed when a
-    // vendor-specific libhealthd is not necessary. Hence, its behavior
-    // is kept. See health/2.0/README.md.
-    // android.hardware.health@2.0-impl-default.recovery, and subsequently the
-    // special handling of recovery mode below, can be removed once health@2.1
-    // is the minimum required version (i.e. compatibility matrix level 5 is the
-    // minimum supported level). Health 2.1 requires OEMs to install the
+    // Health 2.1 requires OEMs to install the
     // implementation to the recovery partition when it is necessary (i.e. on
     // non-A/B devices, where IsBatteryOk() is needed in recovery).
-    for (auto&& instanceName :
-#ifdef __ANDROID_RECOVERY__
-         { "default", "backup" }
-#else
-         {"default"}
-#endif
-    ) {
-        auto ret = IHealth::getService(instanceName);
-        if (ret != nullptr) {
-            return ret;
-        }
-        LOG(INFO) << "health: cannot get " << instanceName << " service";
-    }
-    return nullptr;
+    return IHealth::getService();
 }
 
 }  // namespace V2_0
diff --git a/health/2.0/utils/libhealthservice/Android.bp b/health/2.0/utils/libhealthservice/Android.bp
deleted file mode 100644
index 8023692..0000000
--- a/health/2.0/utils/libhealthservice/Android.bp
+++ /dev/null
@@ -1,38 +0,0 @@
-// Reasonable defaults for android.hardware.health@2.0-service.<device>.
-// Vendor service can customize by implementing functions defined in
-// libhealthd and libhealthstoragedefault.
-
-
-package {
-    // See: http://go/android-license-faq
-    // A large-scale-change added 'default_applicable_licenses' to import
-    // all of the 'license_kinds' from "hardware_interfaces_license"
-    // to get the below license kinds:
-    //   SPDX-license-identifier-Apache-2.0
-    default_applicable_licenses: ["hardware_interfaces_license"],
-}
-
-cc_library_static {
-    name: "libhealthservice",
-    vendor_available: true,
-    srcs: ["HealthServiceCommon.cpp"],
-
-    export_include_dirs: ["include"],
-
-    cflags: [
-        "-Wall",
-        "-Werror",
-    ],
-    shared_libs: [
-        "android.hardware.health@2.0",
-    ],
-    static_libs: [
-        "android.hardware.health@2.0-impl",
-        "android.hardware.health@1.0-convert",
-    ],
-    export_static_lib_headers: [
-        "android.hardware.health@1.0-convert",
-    ],
-    header_libs: ["libhealthd_headers"],
-    export_header_lib_headers: ["libhealthd_headers"],
-}
diff --git a/health/2.0/utils/libhealthservice/HealthServiceCommon.cpp b/health/2.0/utils/libhealthservice/HealthServiceCommon.cpp
deleted file mode 100644
index 039570a..0000000
--- a/health/2.0/utils/libhealthservice/HealthServiceCommon.cpp
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "health@2.0/"
-#include <android-base/logging.h>
-
-#include <android/hardware/health/1.0/types.h>
-#include <hal_conversion.h>
-#include <health2/Health.h>
-#include <health2/service.h>
-#include <healthd/healthd.h>
-#include <hidl/HidlTransportSupport.h>
-#include <hwbinder/IPCThreadState.h>
-
-using android::hardware::IPCThreadState;
-using android::hardware::configureRpcThreadpool;
-using android::hardware::handleTransportPoll;
-using android::hardware::setupTransportPolling;
-using android::hardware::health::V2_0::HealthInfo;
-using android::hardware::health::V1_0::hal_conversion::convertToHealthInfo;
-using android::hardware::health::V2_0::IHealth;
-using android::hardware::health::V2_0::implementation::Health;
-
-extern int healthd_main(void);
-
-static int gBinderFd = -1;
-static std::string gInstanceName;
-
-static void binder_event(uint32_t /*epevents*/) {
-    if (gBinderFd >= 0) handleTransportPoll(gBinderFd);
-}
-
-void healthd_mode_service_2_0_init(struct healthd_config* config) {
-    LOG(INFO) << LOG_TAG << gInstanceName << " Hal is starting up...";
-
-    gBinderFd = setupTransportPolling();
-
-    if (gBinderFd >= 0) {
-        if (healthd_register_event(gBinderFd, binder_event))
-            LOG(ERROR) << LOG_TAG << gInstanceName << ": Register for binder events failed";
-    }
-
-    android::sp<IHealth> service = Health::initInstance(config);
-    CHECK_EQ(service->registerAsService(gInstanceName), android::OK)
-        << LOG_TAG << gInstanceName << ": Failed to register HAL";
-
-    LOG(INFO) << LOG_TAG << gInstanceName << ": Hal init done";
-}
-
-int healthd_mode_service_2_0_preparetowait(void) {
-    IPCThreadState::self()->flushCommands();
-    return -1;
-}
-
-void healthd_mode_service_2_0_heartbeat(void) {
-    // noop
-}
-
-void healthd_mode_service_2_0_battery_update(struct android::BatteryProperties* prop) {
-    HealthInfo info;
-    convertToHealthInfo(prop, info.legacy);
-    Health::getImplementation()->notifyListeners(&info);
-}
-
-static struct healthd_mode_ops healthd_mode_service_2_0_ops = {
-    .init = healthd_mode_service_2_0_init,
-    .preparetowait = healthd_mode_service_2_0_preparetowait,
-    .heartbeat = healthd_mode_service_2_0_heartbeat,
-    .battery_update = healthd_mode_service_2_0_battery_update,
-};
-
-int health_service_main(const char* instance) {
-    gInstanceName = instance;
-    if (gInstanceName.empty()) {
-        gInstanceName = "default";
-    }
-    healthd_mode_ops = &healthd_mode_service_2_0_ops;
-    LOG(INFO) << LOG_TAG << gInstanceName << ": Hal starting main loop...";
-    return healthd_main();
-}
diff --git a/health/2.0/utils/libhealthservice/include/health2/service.h b/health/2.0/utils/libhealthservice/include/health2/service.h
deleted file mode 100644
index d260568..0000000
--- a/health/2.0/utils/libhealthservice/include/health2/service.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_HEALTH_V2_0_SERVICE_COMMON
-#define ANDROID_HARDWARE_HEALTH_V2_0_SERVICE_COMMON
-
-int health_service_main(const char* instance = "");
-
-#endif  // ANDROID_HARDWARE_HEALTH_V2_0_SERVICE_COMMON
diff --git a/health/2.0/utils/libhealthstoragedefault/Android.bp b/health/2.0/utils/libhealthstoragedefault/Android.bp
deleted file mode 100644
index 3de8789..0000000
--- a/health/2.0/utils/libhealthstoragedefault/Android.bp
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// Default implementation for (passthrough) clients that statically links to
-// android.hardware.health@2.0-impl but do no query for storage related
-// information.
-package {
-    // See: http://go/android-license-faq
-    // A large-scale-change added 'default_applicable_licenses' to import
-    // all of the 'license_kinds' from "hardware_interfaces_license"
-    // to get the below license kinds:
-    //   SPDX-license-identifier-Apache-2.0
-    default_applicable_licenses: ["hardware_interfaces_license"],
-}
-
-cc_library_static {
-    srcs: ["StorageHealthDefault.cpp"],
-    name: "libhealthstoragedefault",
-    vendor_available: true,
-    recovery_available: true,
-    cflags: ["-Werror"],
-    shared_libs: [
-        "android.hardware.health@2.0",
-    ],
-}
diff --git a/health/2.0/utils/libhealthstoragedefault/StorageHealthDefault.cpp b/health/2.0/utils/libhealthstoragedefault/StorageHealthDefault.cpp
deleted file mode 100644
index aba6cc3..0000000
--- a/health/2.0/utils/libhealthstoragedefault/StorageHealthDefault.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "include/StorageHealthDefault.h"
-
-void get_storage_info(std::vector<struct StorageInfo>&) {
-    // Use defaults.
-}
-
-void get_disk_stats(std::vector<struct DiskStats>&) {
-    // Use defaults
-}
diff --git a/health/2.0/utils/libhealthstoragedefault/include/StorageHealthDefault.h b/health/2.0/utils/libhealthstoragedefault/include/StorageHealthDefault.h
deleted file mode 100644
index 85eb210..0000000
--- a/health/2.0/utils/libhealthstoragedefault/include/StorageHealthDefault.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef ANDROID_HARDWARE_HEALTH_V2_0_STORAGE_HEALTH_H
-#define ANDROID_HARDWARE_HEALTH_V2_0_STORAGE_HEALTH_H
-
-#include <android/hardware/health/2.0/types.h>
-
-using android::hardware::health::V2_0::StorageInfo;
-using android::hardware::health::V2_0::DiskStats;
-
-/*
- * Get storage information.
- */
-void get_storage_info(std::vector<struct StorageInfo>& info);
-
-/*
- * Get disk statistics.
- */
-void get_disk_stats(std::vector<struct DiskStats>& stats);
-
-#endif  // ANDROID_HARDWARE_HEALTH_V2_0_STORAGE_HEALTH_H
diff --git a/health/2.0/vts/OWNERS b/health/2.0/vts/OWNERS
deleted file mode 100644
index 9f96f51..0000000
--- a/health/2.0/vts/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 30545
-elsk@google.com
-sspatil@google.com
diff --git a/health/2.1/vts/OWNERS b/health/2.1/vts/OWNERS
deleted file mode 100644
index a6803cd..0000000
--- a/health/2.1/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-elsk@google.com
-sspatil@google.com
diff --git a/health/2.1/vts/functional/OWNERS b/health/2.1/vts/functional/OWNERS
deleted file mode 100644
index cd06415..0000000
--- a/health/2.1/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 30545
-elsk@google.com
diff --git a/health/OWNERS b/health/OWNERS
new file mode 100644
index 0000000..e540d55
--- /dev/null
+++ b/health/OWNERS
@@ -0,0 +1,6 @@
+# Bug component: 30545
+
+apelosi@google.com
+dvander@google.com
+smoreland@google.com
+wjack@google.com
diff --git a/health/aidl/Android.bp b/health/aidl/Android.bp
index e288f17..4691dd6 100644
--- a/health/aidl/Android.bp
+++ b/health/aidl/Android.bp
@@ -48,7 +48,7 @@
         },
 
     ],
-    frozen: true,
+    frozen: false,
 
 }
 
@@ -80,7 +80,7 @@
     name: "android.hardware.health-translate-ndk",
     defaults: ["android.hardware.health-translate-ndk_defaults"],
     shared_libs: [
-        "android.hardware.health-V2-ndk",
+        "android.hardware.health-V3-ndk",
     ],
 }
 
@@ -97,7 +97,7 @@
     name: "android.hardware.health-translate-java",
     srcs: ["android/hardware/health/Translate.java"],
     libs: [
-        "android.hardware.health-V2-java",
+        "android.hardware.health-V3-java",
         "android.hardware.health-V2.0-java",
         "android.hardware.health-V2.1-java",
     ],
diff --git a/health/aidl/OWNERS b/health/aidl/OWNERS
deleted file mode 100644
index 0f1bee2..0000000
--- a/health/aidl/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-# Bug component: 30545
-elsk@google.com
-smoreland@google.com
-wjack@google.com
-apelosi@google.com
diff --git a/health/aidl/aidl_api/android.hardware.health/current/android/hardware/health/BatteryHealthData.aidl b/health/aidl/aidl_api/android.hardware.health/current/android/hardware/health/BatteryHealthData.aidl
index 2dd01b1..089c8ac 100644
--- a/health/aidl/aidl_api/android.hardware.health/current/android/hardware/health/BatteryHealthData.aidl
+++ b/health/aidl/aidl_api/android.hardware.health/current/android/hardware/health/BatteryHealthData.aidl
@@ -37,4 +37,6 @@
   long batteryManufacturingDateSeconds;
   long batteryFirstUsageSeconds;
   long batteryStateOfHealth;
+  @nullable String batterySerialNumber;
+  android.hardware.health.BatteryPartStatus batteryPartStatus = android.hardware.health.BatteryPartStatus.UNSUPPORTED;
 }
diff --git a/health/aidl/aidl_api/android.hardware.health/current/android/hardware/health/BatteryPartStatus.aidl b/health/aidl/aidl_api/android.hardware.health/current/android/hardware/health/BatteryPartStatus.aidl
new file mode 100644
index 0000000..e013e31
--- /dev/null
+++ b/health/aidl/aidl_api/android.hardware.health/current/android/hardware/health/BatteryPartStatus.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.health;
+@Backing(type="int") @VintfStability
+enum BatteryPartStatus {
+  UNSUPPORTED,
+  ORIGINAL,
+  REPLACED,
+}
diff --git a/health/aidl/android/hardware/health/BatteryHealthData.aidl b/health/aidl/android/hardware/health/BatteryHealthData.aidl
index 594bcce..7245298 100644
--- a/health/aidl/android/hardware/health/BatteryHealthData.aidl
+++ b/health/aidl/android/hardware/health/BatteryHealthData.aidl
@@ -16,6 +16,8 @@
 
 package android.hardware.health;
 
+import android.hardware.health.BatteryPartStatus;
+
 /*
  * Battery health data
  */
@@ -36,4 +38,14 @@
      * Otherwise, value must be in the range 0 to 100.
      */
     long batteryStateOfHealth;
+    /**
+     * Serial number of the battery. Null if not supported. If supported, a string of at least 6
+     * alphanumeric characters. Characters may either be upper or lower case, but for comparison
+     * and uniqueness purposes, must be treated as case-insensitive.
+     */
+    @nullable String batterySerialNumber;
+    /**
+     * Indicator for part originality of the battery.
+     */
+    BatteryPartStatus batteryPartStatus = BatteryPartStatus.UNSUPPORTED;
 }
diff --git a/health/aidl/android/hardware/health/BatteryPartStatus.aidl b/health/aidl/android/hardware/health/BatteryPartStatus.aidl
new file mode 100644
index 0000000..6c2060a
--- /dev/null
+++ b/health/aidl/android/hardware/health/BatteryPartStatus.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.health;
+
+/**
+ * Possible values for BatteryPartStatus.
+ * Note: These are currently in sync with BatteryManager and must not
+ * be extended / altered.
+ */
+@VintfStability
+@Backing(type="int")
+enum BatteryPartStatus {
+    /**
+     * Device cannot differentiate an original battery from a replaced battery.
+     */
+    UNSUPPORTED = 0,
+    /**
+     * Device has the original battery it was manufactured with.
+     */
+    ORIGINAL = 1,
+    /**
+     * Device has a replaced battery.
+     */
+    REPLACED = 2,
+}
diff --git a/health/aidl/default/Android.bp b/health/aidl/default/Android.bp
index b51e4f3..2071f08 100644
--- a/health/aidl/default/Android.bp
+++ b/health/aidl/default/Android.bp
@@ -29,7 +29,7 @@
         "libcutils",
         "liblog",
         "libutils",
-        "android.hardware.health-V2-ndk",
+        "android.hardware.health-V3-ndk",
 
         // TODO(b/177269435): remove when BatteryMonitor works with AIDL HealthInfo.
         "libhidlbase",
@@ -48,7 +48,7 @@
     name: "libhealth_aidl_charger_defaults",
     shared_libs: [
         // common
-        "android.hardware.health-V2-ndk",
+        "android.hardware.health-V3-ndk",
         "libbase",
         "libcutils",
         "liblog",
@@ -195,7 +195,7 @@
         "service_fuzzer_defaults",
     ],
     static_libs: [
-        "android.hardware.health-V2-ndk",
+        "android.hardware.health-V3-ndk",
         "libbase",
         "liblog",
         "fuzz_libhealth_aidl_impl",
diff --git a/health/aidl/default/Health.cpp b/health/aidl/default/Health.cpp
index f401643..8174bc8 100644
--- a/health/aidl/default/Health.cpp
+++ b/health/aidl/default/Health.cpp
@@ -62,6 +62,18 @@
 
 Health::~Health() {}
 
+static inline ndk::ScopedAStatus TranslateStatus(::android::status_t err) {
+    switch (err) {
+        case ::android::OK:
+            return ndk::ScopedAStatus::ok();
+        case ::android::NAME_NOT_FOUND:
+            return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+        default:
+            return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                    IHealth::STATUS_UNKNOWN, ::android::statusToString(err).c_str());
+    }
+}
+
 //
 // Getters.
 //
@@ -78,16 +90,7 @@
         LOG(DEBUG) << "getProperty(" << id << ")"
                    << " fails: (" << err << ") " << ::android::statusToString(err);
     }
-
-    switch (err) {
-        case ::android::OK:
-            return ndk::ScopedAStatus::ok();
-        case ::android::NAME_NOT_FOUND:
-            return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
-        default:
-            return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
-                    IHealth::STATUS_UNKNOWN, ::android::statusToString(err).c_str());
-    }
+    return TranslateStatus(err);
 }
 
 ndk::ScopedAStatus Health::getChargeCounterUah(int32_t* out) {
@@ -153,6 +156,21 @@
         !res.isOk()) {
         LOG(WARNING) << "Cannot get Battery_state_of_health: " << res.getDescription();
     }
+    if (auto res = battery_monitor_.getSerialNumber(&out->batterySerialNumber);
+        res != ::android::OK) {
+        LOG(WARNING) << "Cannot get Battery_serial_number: "
+                     << TranslateStatus(res).getDescription();
+    }
+
+    int64_t part_status = static_cast<int64_t>(BatteryPartStatus::UNSUPPORTED);
+    if (auto res = GetProperty<int64_t>(&battery_monitor_, ::android::BATTERY_PROP_PART_STATUS,
+                                        static_cast<int64_t>(BatteryPartStatus::UNSUPPORTED),
+                                        &part_status);
+        !res.isOk()) {
+        LOG(WARNING) << "Cannot get Battery_part_status: " << res.getDescription();
+    }
+    out->batteryPartStatus = static_cast<BatteryPartStatus>(part_status);
+
     return ndk::ScopedAStatus::ok();
 }
 
@@ -214,6 +232,7 @@
     } else {
         ::android::base::WriteStringToFd(res.getDescription(), fd);
     }
+    ::android::base::WriteStringToFd("\n", fd);
 
     fsync(fd);
     return STATUS_OK;
@@ -235,15 +254,6 @@
     return healthd_config_->screen_on(&props);
 }
 
-namespace {
-bool IsDeadObjectLogged(const ndk::ScopedAStatus& ret) {
-    if (ret.isOk()) return false;
-    if (ret.getStatus() == ::STATUS_DEAD_OBJECT) return true;
-    LOG(ERROR) << "Cannot call healthInfoChanged on callback: " << ret.getDescription();
-    return false;
-}
-}  // namespace
-
 //
 // Subclass helpers / overrides
 //
@@ -272,7 +282,11 @@
 
     {
         std::lock_guard<decltype(callbacks_lock_)> lock(callbacks_lock_);
-        callbacks_.emplace_back(LinkedCallback::Make(ref<Health>(), callback));
+        auto linked_callback_result = LinkedCallback::Make(ref<Health>(), callback);
+        if (!linked_callback_result.ok()) {
+            return ndk::ScopedAStatus::fromStatus(-linked_callback_result.error().code());
+        }
+        callbacks_.emplace_back(std::move(*linked_callback_result));
         // unlock
     }
 
@@ -283,8 +297,10 @@
         return ndk::ScopedAStatus::ok();
     }
 
-    if (auto res = callback->healthInfoChanged(health_info); IsDeadObjectLogged(res)) {
-        (void)unregisterCallback(callback);
+    auto res = callback->healthInfoChanged(health_info);
+    if (!res.isOk()) {
+        LOG(DEBUG) << "Cannot call healthInfoChanged:" << res.getDescription()
+                   << ". Do nothing here if callback is dead as it will be cleaned up later.";
     }
     return ndk::ScopedAStatus::ok();
 }
@@ -331,13 +347,13 @@
 void Health::OnHealthInfoChanged(const HealthInfo& health_info) {
     // Notify all callbacks
     std::unique_lock<decltype(callbacks_lock_)> lock(callbacks_lock_);
-    // is_dead notifies a callback and return true if it is dead.
-    auto is_dead = [&](const auto& linked) {
+    for (const auto& linked : callbacks_) {
         auto res = linked->callback()->healthInfoChanged(health_info);
-        return IsDeadObjectLogged(res);
-    };
-    auto it = std::remove_if(callbacks_.begin(), callbacks_.end(), is_dead);
-    callbacks_.erase(it, callbacks_.end());  // calls unlinkToDeath on deleted callbacks.
+        if (!res.isOk()) {
+            LOG(DEBUG) << "Cannot call healthInfoChanged:" << res.getDescription()
+                       << ". Do nothing here if callback is dead as it will be cleaned up later.";
+        }
+    }
     lock.unlock();
 
     // Let HalHealthLoop::OnHealthInfoChanged() adjusts uevent / wakealarm periods
diff --git a/health/aidl/default/LinkedCallback.cpp b/health/aidl/default/LinkedCallback.cpp
index 2985ffe..26e99f9 100644
--- a/health/aidl/default/LinkedCallback.cpp
+++ b/health/aidl/default/LinkedCallback.cpp
@@ -24,7 +24,7 @@
 
 namespace aidl::android::hardware::health {
 
-std::unique_ptr<LinkedCallback> LinkedCallback::Make(
+::android::base::Result<std::unique_ptr<LinkedCallback>> LinkedCallback::Make(
         std::shared_ptr<Health> service, std::shared_ptr<IHealthInfoCallback> callback) {
     std::unique_ptr<LinkedCallback> ret(new LinkedCallback());
     binder_status_t linkRet =
@@ -32,7 +32,7 @@
                                  reinterpret_cast<void*>(ret.get()));
     if (linkRet != ::STATUS_OK) {
         LOG(WARNING) << __func__ << "Cannot link to death: " << linkRet;
-        return nullptr;
+        return ::android::base::Error(-linkRet);
     }
     ret->service_ = service;
     ret->callback_ = std::move(callback);
diff --git a/health/aidl/default/LinkedCallback.h b/health/aidl/default/LinkedCallback.h
index 82490a7..da494c9 100644
--- a/health/aidl/default/LinkedCallback.h
+++ b/health/aidl/default/LinkedCallback.h
@@ -20,6 +20,7 @@
 
 #include <aidl/android/hardware/health/IHealthInfoCallback.h>
 #include <android-base/macros.h>
+#include <android-base/result.h>
 #include <android/binder_auto_utils.h>
 
 #include <health-impl/Health.h>
@@ -34,8 +35,8 @@
     // service->death_reciepient() should be from CreateDeathRecipient().
     // Not using a strong reference to |service| to avoid circular reference. The lifetime
     // of |service| must be longer than this LinkedCallback object.
-    static std::unique_ptr<LinkedCallback> Make(std::shared_ptr<Health> service,
-                                                std::shared_ptr<IHealthInfoCallback> callback);
+    static ::android::base::Result<std::unique_ptr<LinkedCallback>> Make(
+            std::shared_ptr<Health> service, std::shared_ptr<IHealthInfoCallback> callback);
 
     // Automatically unlinkToDeath upon destruction. So, it is always safe to reinterpret_cast
     // the cookie back to the LinkedCallback object.
diff --git a/health/aidl/default/android.hardware.health-service.example.xml b/health/aidl/default/android.hardware.health-service.example.xml
index 1fe9b8d..2acaaba 100644
--- a/health/aidl/default/android.hardware.health-service.example.xml
+++ b/health/aidl/default/android.hardware.health-service.example.xml
@@ -1,7 +1,7 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.health</name>
-        <version>2</version>
+        <version>3</version>
         <fqname>IHealth/default</fqname>
     </hal>
 </manifest>
diff --git a/health/aidl/vts/functional/Android.bp b/health/aidl/vts/functional/Android.bp
index b735a87..6d2b530 100644
--- a/health/aidl/vts/functional/Android.bp
+++ b/health/aidl/vts/functional/Android.bp
@@ -39,7 +39,7 @@
         "libbinder_ndk",
     ],
     static_libs: [
-        "android.hardware.health-V2-ndk",
+        "android.hardware.health-V3-ndk",
         "libgmock",
     ],
     header_libs: [
diff --git a/health/aidl/vts/functional/VtsHalHealthTargetTest.cpp b/health/aidl/vts/functional/VtsHalHealthTargetTest.cpp
index 783ce11..9360789 100644
--- a/health/aidl/vts/functional/VtsHalHealthTargetTest.cpp
+++ b/health/aidl/vts/functional/VtsHalHealthTargetTest.cpp
@@ -84,6 +84,21 @@
     return AnyOfArray(enum_range<T>().begin(), enum_range<T>().end());
 }
 
+MATCHER(IsValidSerialNumber, "") {
+    if (!arg) {
+        return true;
+    }
+    if (arg->size() < 6) {
+        return false;
+    }
+    for (const auto& c : *arg) {
+        if (!isalnum(c)) {
+            return false;
+        }
+    }
+    return true;
+}
+
 class HealthAidl : public testing::TestWithParam<std::string> {
   public:
     void SetUp() override {
@@ -270,7 +285,7 @@
     ASSERT_THAT(static_cast<int>(value), AnyOf(Eq(1), Eq(4)));
 }
 
-MATCHER(IsValidHealthData, "") {
+MATCHER_P(IsValidHealthData, version, "") {
     *result_listener << "value is " << arg.toString() << ".";
     if (!ExplainMatchResult(Ge(-1), arg.batteryManufacturingDateSeconds, result_listener)) {
         *result_listener << " for batteryManufacturingDateSeconds.";
@@ -284,6 +299,15 @@
         *result_listener << " for batteryStateOfHealth.";
         return false;
     }
+    if (!ExplainMatchResult(IsValidSerialNumber(), arg.batterySerialNumber, result_listener)) {
+        *result_listener << " for batterySerialNumber.";
+        return false;
+    }
+    if (!ExplainMatchResult(IsValidEnum<BatteryPartStatus>(), arg.batteryPartStatus,
+                            result_listener)) {
+        *result_listener << " for batteryPartStatus.";
+        return false;
+    }
 
     return true;
 }
@@ -303,7 +327,7 @@
     status = health->getBatteryHealthData(&value);
     ASSERT_THAT(status, AnyOf(IsOk(), ExceptionIs(EX_UNSUPPORTED_OPERATION)));
     if (!status.isOk()) return;
-    ASSERT_THAT(value, IsValidHealthData());
+    ASSERT_THAT(value, IsValidHealthData(version));
 }
 
 MATCHER(IsValidStorageInfo, "") {
diff --git a/health/storage/1.0/vts/functional/OWNERS b/health/storage/1.0/vts/functional/OWNERS
deleted file mode 100644
index 8f66979..0000000
--- a/health/storage/1.0/vts/functional/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 30545
-elsk@google.com
-jaegeuk@google.com
diff --git a/health/storage/OWNERS b/health/storage/OWNERS
new file mode 100644
index 0000000..7af8d99
--- /dev/null
+++ b/health/storage/OWNERS
@@ -0,0 +1,6 @@
+# Bug component: 30545
+
+set noparent
+
+jaegeuk@google.com
+elsk@google.com
diff --git a/health/utils/libhealthloop/include/health/HealthLoop.h b/health/utils/libhealthloop/include/health/HealthLoop.h
index 54b2740..fc3066e 100644
--- a/health/utils/libhealthloop/include/health/HealthLoop.h
+++ b/health/utils/libhealthloop/include/health/HealthLoop.h
@@ -15,6 +15,7 @@
  */
 #pragma once
 
+#include <functional>
 #include <memory>
 #include <mutex>
 #include <vector>
diff --git a/health/utils/libhealthshim/Android.bp b/health/utils/libhealthshim/Android.bp
index 14c32ae..b0ea743 100644
--- a/health/utils/libhealthshim/Android.bp
+++ b/health/utils/libhealthshim/Android.bp
@@ -34,7 +34,7 @@
         "-Werror",
     ],
     static_libs: [
-        "android.hardware.health-V2-ndk",
+        "android.hardware.health-V3-ndk",
         "android.hardware.health-translate-ndk",
         "android.hardware.health@1.0",
         "android.hardware.health@2.0",
diff --git a/health/utils/libhealthshim/shim.cpp b/health/utils/libhealthshim/shim.cpp
index 6a5f512..a5ba919 100644
--- a/health/utils/libhealthshim/shim.cpp
+++ b/health/utils/libhealthshim/shim.cpp
@@ -230,6 +230,7 @@
 ScopedAStatus HealthShim::getBatteryHealthData(BatteryHealthData* out) {
     out->batteryManufacturingDateSeconds = 0;
     out->batteryFirstUsageSeconds = 0;
+    out->batteryPartStatus = BatteryPartStatus::UNSUPPORTED;
     return ResultToStatus(Result::NOT_SUPPORTED);
 }
 
diff --git a/identity/support/Android.bp b/identity/support/Android.bp
index 3096fe5..d62d055 100644
--- a/identity/support/Android.bp
+++ b/identity/support/Android.bp
@@ -22,15 +22,8 @@
     default_applicable_licenses: ["hardware_interfaces_license"],
 }
 
-cc_library {
-    name: "android.hardware.identity-support-lib",
-    vendor_available: true,
-    srcs: [
-        "src/IdentityCredentialSupport.cpp",
-    ],
-    export_include_dirs: [
-        "include",
-    ],
+cc_defaults {
+    name: "android.hardware.identity-support-lib-deps",
     shared_libs: [
         "android.hardware.keymaster@4.0",
         "libcrypto",
@@ -47,19 +40,36 @@
     ],
 }
 
+cc_library {
+    name: "android.hardware.identity-support-lib",
+    vendor_available: true,
+    defaults: [
+        "android.hardware.identity-support-lib-deps",
+    ],
+    srcs: [
+        "src/IdentityCredentialSupport.cpp",
+    ],
+    export_include_dirs: [
+        "include",
+    ],
+}
+
 cc_test {
     name: "android.hardware.identity-support-lib-test",
     srcs: [
         "tests/IdentityCredentialSupportTest.cpp",
     ],
+    defaults: [
+        "android.hardware.identity-support-lib-deps",
+    ],
     shared_libs: [
-        "android.hardware.identity-support-lib",
         "libcrypto",
         "libbase",
         "libhidlbase",
         "libhardware",
     ],
     static_libs: [
+        "android.hardware.identity-support-lib",
         "libcppbor_external",
         "libgmock",
     ],
diff --git a/input/common/aidl/Android.bp b/input/common/aidl/Android.bp
index 95a14b2..f23f270 100644
--- a/input/common/aidl/Android.bp
+++ b/input/common/aidl/Android.bp
@@ -20,6 +20,9 @@
         java: {
             enabled: false,
         },
+        rust: {
+            enabled: true,
+        },
     },
     versions_with_info: [
         {
diff --git a/input/processor/aidl/default/Android.bp b/input/processor/aidl/default/Android.bp
index f485597..bdd27e2 100644
--- a/input/processor/aidl/default/Android.bp
+++ b/input/processor/aidl/default/Android.bp
@@ -28,27 +28,54 @@
     ],
 }
 
-filegroup {
+prebuilt_etc {
     name: "android.hardware.input.processor.xml",
-    srcs: ["android.hardware.input.processor.xml"],
+    src: "android.hardware.input.processor.xml",
+    sub_dir: "vintf",
+    installable: false,
+}
+
+prebuilt_etc {
+    name: "inputprocessor-default.rc",
+    src: "inputprocessor-default.rc",
+    installable: false,
 }
 
 cc_binary {
     name: "android.hardware.input.processor-service.example",
     relative_install_path: "hw",
-    init_rc: ["inputprocessor-default.rc"],
-    vintf_fragments: [":android.hardware.input.processor.xml"],
     vendor: true,
+    installable: false, // installed in APEX
+
+    stl: "c++_static",
     shared_libs: [
-        "libbase",
         "libbinder_ndk",
         "liblog",
-        "libutils",
-        "android.hardware.input.common-V1-ndk",
-        "android.hardware.input.processor-V1-ndk",
     ],
     static_libs: [
+        "android.hardware.input.common-V1-ndk",
+        "android.hardware.input.processor-V1-ndk",
+        "libbase",
         "libinputprocessorexampleimpl",
+        "libutils",
     ],
     srcs: ["main.cpp"],
 }
+
+apex {
+    name: "com.android.hardware.input.processor",
+    file_contexts: "apex_file_contexts",
+    manifest: "apex_manifest.json",
+    key: "com.android.hardware.key",
+    certificate: ":com.android.hardware.certificate",
+    updatable: false,
+    vendor: true,
+
+    binaries: [
+        "android.hardware.input.processor-service.example",
+    ],
+    prebuilts: [
+        "android.hardware.input.processor.xml",
+        "inputprocessor-default.rc",
+    ],
+}
diff --git a/input/processor/aidl/default/apex_file_contexts b/input/processor/aidl/default/apex_file_contexts
new file mode 100644
index 0000000..bd2945a
--- /dev/null
+++ b/input/processor/aidl/default/apex_file_contexts
@@ -0,0 +1,3 @@
+(/.*)?                                                          u:object_r:vendor_file:s0
+/etc(/.*)?                                                      u:object_r:vendor_configs_file:s0
+/bin/hw/android\.hardware\.input\.processor-service\.example    u:object_r:hal_input_processor_default_exec:s0
diff --git a/input/processor/aidl/default/apex_manifest.json b/input/processor/aidl/default/apex_manifest.json
new file mode 100644
index 0000000..2fe0a1d
--- /dev/null
+++ b/input/processor/aidl/default/apex_manifest.json
@@ -0,0 +1,4 @@
+{
+    "name": "com.android.hardware.input.processor",
+    "version": 1
+}
\ No newline at end of file
diff --git a/input/processor/aidl/default/inputprocessor-default.rc b/input/processor/aidl/default/inputprocessor-default.rc
index bcc6c02..ade0f11 100644
--- a/input/processor/aidl/default/inputprocessor-default.rc
+++ b/input/processor/aidl/default/inputprocessor-default.rc
@@ -1,4 +1,4 @@
-service vendor.inputprocessor-default /vendor/bin/hw/android.hardware.input.processor-service.example
+service vendor.inputprocessor-default /apex/com.android.hardware.input.processor/bin/hw/android.hardware.input.processor-service.example
     class hal
     user nobody
     group nobody
\ No newline at end of file
diff --git a/ir/aidl/default/Android.bp b/ir/aidl/default/Android.bp
index a8096c2..4006554 100644
--- a/ir/aidl/default/Android.bp
+++ b/ir/aidl/default/Android.bp
@@ -36,8 +36,58 @@
         "liblog",
         "libutils",
         "android.hardware.ir-V1-ndk",
-        "libhardware"
+        "libhardware",
     ],
 
     srcs: ["main.cpp"],
 }
+
+prebuilt_etc {
+    name: "android.hardware.ir-service.example.rc",
+    src: ":gen-android.hardware.ir-service.example.rc",
+    installable: false,
+}
+
+genrule {
+    name: "gen-android.hardware.ir-service.example.rc",
+    srcs: ["android.hardware.ir-service.example.rc"],
+    out: ["android.hardware.ir-service.example.apex.rc"],
+    cmd: "sed -e 's@/vendor/bin/@/apex/com.android.hardware.ir/bin/@' $(in) > $(out)",
+}
+
+prebuilt_etc {
+    name: "android.hardware.ir-service.example.xml",
+    src: "android.hardware.ir-service.example.xml",
+    sub_dir: "vintf",
+    installable: false,
+}
+
+filegroup {
+    name: "com.android.hardware.ir_file_contexts",
+    srcs: ["apex_file_contexts"],
+}
+
+filegroup {
+    name: "com.android.hardware.ir_apex_manifest.json",
+    srcs: ["apex_manifest.json"],
+}
+
+apex_defaults {
+    name: "com.android.hardware.ir",
+    // Reference to the filegroup instead of direct path since
+    // paths in defaults don't work in a different directory.
+    file_contexts: ":com.android.hardware.ir_file_contexts",
+    manifest: ":com.android.hardware.ir_apex_manifest.json",
+
+    updatable: false,
+    vendor: true,
+
+    binaries: [
+        "android.hardware.ir-service.example",
+    ],
+    prebuilts: [
+        "android.hardware.ir-service.example.rc",
+        "android.hardware.ir-service.example.xml",
+        "android.hardware.consumerir.prebuilt.xml", // feature
+    ],
+}
diff --git a/ir/aidl/default/apex_file_contexts b/ir/aidl/default/apex_file_contexts
new file mode 100644
index 0000000..3bbf131
--- /dev/null
+++ b/ir/aidl/default/apex_file_contexts
@@ -0,0 +1,3 @@
+(/.*)?                                          u:object_r:vendor_file:s0
+/etc(/.*)?                                      u:object_r:vendor_configs_file:s0
+/bin/hw/android\.hardware\.ir-service\.example  u:object_r:hal_ir_default_exec:s0
diff --git a/ir/aidl/default/apex_manifest.json b/ir/aidl/default/apex_manifest.json
new file mode 100644
index 0000000..d384375
--- /dev/null
+++ b/ir/aidl/default/apex_manifest.json
@@ -0,0 +1,4 @@
+{
+    "name": "com.android.hardware.ir",
+    "version": 1
+}
\ No newline at end of file
diff --git a/keymaster/3.0/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/3.0/vts/functional/keymaster_hidl_hal_test.cpp
index 554afe7..65b3dfa 100644
--- a/keymaster/3.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/3.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -2617,10 +2617,11 @@
     EVP_PKEY_Ptr pkey(d2i_PUBKEY(nullptr /* alloc new */, &p, exported.size()));
     RSA_Ptr rsa(EVP_PKEY_get1_RSA(pkey.get()));
 
-    size_t modulus_len = BN_num_bytes(rsa->n);
+    const BIGNUM* n = RSA_get0_n(rsa.get());
+    size_t modulus_len = BN_num_bytes(n);
     ASSERT_EQ(1024U / 8, modulus_len);
     std::unique_ptr<uint8_t[]> modulus_buf(new uint8_t[modulus_len]);
-    BN_bn2bin(rsa->n, modulus_buf.get());
+    BN_bn2bin(n, modulus_buf.get());
 
     // The modulus is too big to encrypt.
     string message(reinterpret_cast<const char*>(modulus_buf.get()), modulus_len);
@@ -2632,10 +2633,12 @@
     EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, Finish(message, &result));
 
     // One smaller than the modulus is okay.
-    BN_sub(rsa->n, rsa->n, BN_value_one());
-    modulus_len = BN_num_bytes(rsa->n);
+    BIGNUM_Ptr n_minus_1(BN_new());
+    ASSERT_TRUE(n_minus_1);
+    ASSERT_TRUE(BN_sub(n_minus_1.get(), n, BN_value_one()));
+    modulus_len = BN_num_bytes(n_minus_1.get());
     ASSERT_EQ(1024U / 8, modulus_len);
-    BN_bn2bin(rsa->n, modulus_buf.get());
+    BN_bn2bin(n_minus_1.get(), modulus_buf.get());
     message = string(reinterpret_cast<const char*>(modulus_buf.get()), modulus_len);
     EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
     EXPECT_EQ(ErrorCode::OK, Finish(message, &result));
diff --git a/keymaster/4.0/support/fuzzer/Android.bp b/keymaster/4.0/support/fuzzer/Android.bp
index 8bc681a..f61d10f 100644
--- a/keymaster/4.0/support/fuzzer/Android.bp
+++ b/keymaster/4.0/support/fuzzer/Android.bp
@@ -39,9 +39,17 @@
     ],
     fuzz_config: {
         cc: [
-            "android-media-fuzzing-reports@google.com",
+            "android-hardware-security@google.com",
         ],
-        componentid: 533764,
+        componentid: 1084733,
+        hotlists: [
+            "4593311",
+        ],
+        description: "The fuzzer targets the APIs of libkeymaster4support",
+        vector: "local_no_privileges_required",
+        service_privilege: "privileged",
+        users: "multi_user",
+        fuzzed_code_usage: "shipped",
     },
 }
 
diff --git a/keymaster/4.0/support/fuzzer/keymaster4_utils_fuzzer.cpp b/keymaster/4.0/support/fuzzer/keymaster4_utils_fuzzer.cpp
index bf074e8..55c2630 100644
--- a/keymaster/4.0/support/fuzzer/keymaster4_utils_fuzzer.cpp
+++ b/keymaster/4.0/support/fuzzer/keymaster4_utils_fuzzer.cpp
@@ -46,33 +46,42 @@
     support::getOsVersion();
     support::getOsPatchlevel();
 
-    VerificationToken token;
-    token.challenge = mFdp->ConsumeIntegral<uint64_t>();
-    token.timestamp = mFdp->ConsumeIntegral<uint64_t>();
-    token.securityLevel = mFdp->PickValueInArray(kSecurityLevel);
-    size_t vectorSize = mFdp->ConsumeIntegralInRange<size_t>(0, kMaxVectorSize);
-    token.mac.resize(vectorSize);
-    for (size_t n = 0; n < vectorSize; ++n) {
-        token.mac[n] = n;
+    while (mFdp->remaining_bytes() > 0) {
+        auto keymaster_function = mFdp->PickValueInArray<const std::function<void()>>({
+                [&]() {
+                    VerificationToken token;
+                    token.challenge = mFdp->ConsumeIntegral<uint64_t>();
+                    token.timestamp = mFdp->ConsumeIntegral<uint64_t>();
+                    token.securityLevel = mFdp->PickValueInArray(kSecurityLevel);
+                    size_t vectorSize = mFdp->ConsumeIntegralInRange<size_t>(0, kMaxVectorSize);
+                    token.mac.resize(vectorSize);
+                    for (size_t n = 0; n < vectorSize; ++n) {
+                        token.mac[n] = mFdp->ConsumeIntegral<uint8_t>();
+                    }
+                    std::optional<std::vector<uint8_t>> serialized =
+                            serializeVerificationToken(token);
+                    if (serialized.has_value()) {
+                        std::optional<VerificationToken> deserialized =
+                                deserializeVerificationToken(serialized.value());
+                    }
+                },
+                [&]() {
+                    std::vector<uint8_t> dataVector;
+                    size_t size = mFdp->ConsumeIntegralInRange<size_t>(0, sizeof(hw_auth_token_t));
+                    dataVector = mFdp->ConsumeBytes<uint8_t>(size);
+                    support::blob2hidlVec(dataVector.data(), dataVector.size());
+                    support::blob2hidlVec(dataVector);
+                    HardwareAuthToken authToken = support::hidlVec2AuthToken(dataVector);
+                    hidl_vec<uint8_t> volatile hidlVector = support::authToken2HidlVec(authToken);
+                },
+                [&]() {
+                    std::string str = mFdp->ConsumeRandomLengthString(kMaxCharacters);
+                    support::blob2hidlVec(str);
+                },
+        });
+        keymaster_function();
     }
-    std::optional<std::vector<uint8_t>> serialized = serializeVerificationToken(token);
-    if (serialized.has_value()) {
-        std::optional<VerificationToken> deserialized =
-                deserializeVerificationToken(serialized.value());
-    }
-
-    std::vector<uint8_t> dataVector;
-    size_t size = mFdp->ConsumeIntegralInRange<size_t>(0, sizeof(hw_auth_token_t));
-    dataVector = mFdp->ConsumeBytes<uint8_t>(size);
-    support::blob2hidlVec(dataVector.data(), dataVector.size());
-
-    support::blob2hidlVec(dataVector);
-
-    std::string str = mFdp->ConsumeRandomLengthString(kMaxCharacters);
-    support::blob2hidlVec(str);
-
-    HardwareAuthToken authToken = support::hidlVec2AuthToken(dataVector);
-    hidl_vec<uint8_t> volatile hidlVector = support::authToken2HidlVec(authToken);
+    return;
 }
 
 void KeyMaster4UtilsFuzzer::process(const uint8_t* data, size_t size) {
diff --git a/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp b/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp
index f57a668..1bff076 100644
--- a/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp
+++ b/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp
@@ -137,7 +137,7 @@
     auto nonces = copyNonces(params);
     EXPECT_EQ(allKeymasters().size(), nonces.size());
     std::sort(nonces.begin(), nonces.end());
-    std::unique(nonces.begin(), nonces.end());
+    nonces.erase(std::unique(nonces.begin(), nonces.end()), nonces.end());
     EXPECT_EQ(allKeymasters().size(), nonces.size());
 
     auto responses = computeSharedHmac(allKeymasters(), params);
diff --git a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
index b709904..96580c0 100644
--- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -2449,10 +2449,11 @@
     EVP_PKEY_Ptr pkey(d2i_PUBKEY(nullptr /* alloc new */, &p, exported.size()));
     RSA_Ptr rsa(EVP_PKEY_get1_RSA(pkey.get()));
 
-    size_t modulus_len = BN_num_bytes(rsa->n);
+    const BIGNUM* n = RSA_get0_n(rsa.get());
+    size_t modulus_len = BN_num_bytes(n);
     ASSERT_EQ(2048U / 8, modulus_len);
     std::unique_ptr<uint8_t[]> modulus_buf(new uint8_t[modulus_len]);
-    BN_bn2bin(rsa->n, modulus_buf.get());
+    BN_bn2bin(n, modulus_buf.get());
 
     // The modulus is too big to encrypt.
     string message(reinterpret_cast<const char*>(modulus_buf.get()), modulus_len);
@@ -2464,10 +2465,12 @@
     EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, Finish(message, &result));
 
     // One smaller than the modulus is okay.
-    BN_sub(rsa->n, rsa->n, BN_value_one());
-    modulus_len = BN_num_bytes(rsa->n);
+    BIGNUM_Ptr n_minus_1(BN_new());
+    ASSERT_TRUE(n_minus_1);
+    ASSERT_TRUE(BN_sub(n_minus_1.get(), n, BN_value_one()));
+    modulus_len = BN_num_bytes(n_minus_1.get());
     ASSERT_EQ(2048U / 8, modulus_len);
-    BN_bn2bin(rsa->n, modulus_buf.get());
+    BN_bn2bin(n_minus_1.get(), modulus_buf.get());
     message = string(reinterpret_cast<const char*>(modulus_buf.get()), modulus_len);
     EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
     EXPECT_EQ(ErrorCode::OK, Finish(message, &result));
diff --git a/keymaster/TEST_MAPPING b/keymaster/TEST_MAPPING
new file mode 100644
index 0000000..8cbf3e1
--- /dev/null
+++ b/keymaster/TEST_MAPPING
@@ -0,0 +1,13 @@
+{
+  "presubmit": [
+    {
+      "name": "VtsHalKeymasterV3_0TargetTest"
+    },
+    {
+      "name": "VtsHalKeymasterV4_0TargetTest"
+    },
+    {
+      "name": "VtsHalKeymasterV4_1TargetTest"
+    }
+  ]
+}
diff --git a/light/OWNERS b/light/OWNERS
new file mode 100644
index 0000000..d1da8a7
--- /dev/null
+++ b/light/OWNERS
@@ -0,0 +1,5 @@
+# Bug Component: 185877106
+
+michaelwr@google.com
+santoscordon@google.com
+philipjunker@google.com
diff --git a/light/aidl/Android.bp b/light/aidl/Android.bp
index c11934f..c9fba95 100644
--- a/light/aidl/Android.bp
+++ b/light/aidl/Android.bp
@@ -18,6 +18,9 @@
         java: {
             sdk_version: "module_current",
         },
+        rust: {
+            enabled: true,
+        },
     },
     versions_with_info: [
         {
diff --git a/light/aidl/default/Android.bp b/light/aidl/default/Android.bp
index 7920503..285329e 100644
--- a/light/aidl/default/Android.bp
+++ b/light/aidl/default/Android.bp
@@ -7,19 +7,17 @@
     default_applicable_licenses: ["hardware_interfaces_license"],
 }
 
-cc_binary {
+rust_binary {
     name: "android.hardware.lights-service.example",
     relative_install_path: "hw",
     init_rc: ["lights-default.rc"],
     vintf_fragments: ["lights-default.xml"],
     vendor: true,
-    shared_libs: [
-        "libbase",
-        "libbinder_ndk",
-        "android.hardware.light-V2-ndk",
+    rustlibs: [
+        "liblogger",
+        "liblog_rust",
+        "libbinder_rs",
+        "android.hardware.light-V2-rust",
     ],
-    srcs: [
-        "Lights.cpp",
-        "main.cpp",
-    ],
+    srcs: [ "main.rs" ],
 }
diff --git a/light/aidl/default/Lights.cpp b/light/aidl/default/Lights.cpp
deleted file mode 100644
index 9bf3b20..0000000
--- a/light/aidl/default/Lights.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "Lights.h"
-
-#include <android-base/logging.h>
-
-namespace aidl {
-namespace android {
-namespace hardware {
-namespace light {
-
-static constexpr int kNumDefaultLights = 3;
-
-ndk::ScopedAStatus Lights::setLightState(int id, const HwLightState& state) {
-    LOG(INFO) << "Lights setting state for id=" << id << " to color " << std::hex << state.color;
-    if (id <= 0 || id > kNumDefaultLights) {
-        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
-    } else {
-        return ndk::ScopedAStatus::ok();
-    }
-}
-
-ndk::ScopedAStatus Lights::getLights(std::vector<HwLight>* lights) {
-    for (int i = 1; i <= kNumDefaultLights; i++) {
-        lights->push_back({i, i});
-    }
-    LOG(INFO) << "Lights reporting supported lights";
-    return ndk::ScopedAStatus::ok();
-}
-
-}  // namespace light
-}  // namespace hardware
-}  // namespace android
-}  // namespace aidl
diff --git a/light/aidl/default/Lights.h b/light/aidl/default/Lights.h
deleted file mode 100644
index cba147f..0000000
--- a/light/aidl/default/Lights.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <aidl/android/hardware/light/BnLights.h>
-
-namespace aidl {
-namespace android {
-namespace hardware {
-namespace light {
-
-// Default implementation that reports a few placeholder lights.
-class Lights : public BnLights {
-    ndk::ScopedAStatus setLightState(int id, const HwLightState& state) override;
-    ndk::ScopedAStatus getLights(std::vector<HwLight>* lights) override;
-};
-
-}  // namespace light
-}  // namespace hardware
-}  // namespace android
-}  // namespace aidl
diff --git a/light/aidl/default/lights.rs b/light/aidl/default/lights.rs
new file mode 100644
index 0000000..6c8aa3f
--- /dev/null
+++ b/light/aidl/default/lights.rs
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+//! This module implements the ILights AIDL interface.
+
+use std::collections::HashMap;
+use std::sync::Mutex;
+
+use log::info;
+
+use android_hardware_light::aidl::android::hardware::light::{
+    HwLight::HwLight, HwLightState::HwLightState, ILights::ILights, LightType::LightType,
+};
+
+use binder::{ExceptionCode, Interface, Status};
+
+struct Light {
+    hw_light: HwLight,
+    state: HwLightState,
+}
+
+const NUM_DEFAULT_LIGHTS: i32 = 3;
+
+/// Defined so we can implement the ILights AIDL interface.
+pub struct LightsService {
+    lights: Mutex<HashMap<i32, Light>>,
+}
+
+impl Interface for LightsService {}
+
+impl LightsService {
+    fn new(hw_lights: impl IntoIterator<Item = HwLight>) -> Self {
+        let mut lights_map = HashMap::new();
+
+        for hw_light in hw_lights {
+            lights_map.insert(hw_light.id, Light { hw_light, state: Default::default() });
+        }
+
+        Self { lights: Mutex::new(lights_map) }
+    }
+}
+
+impl Default for LightsService {
+    fn default() -> Self {
+        let id_mapping_closure =
+            |light_id| HwLight { id: light_id, ordinal: light_id, r#type: LightType::BACKLIGHT };
+
+        Self::new((1..=NUM_DEFAULT_LIGHTS).map(id_mapping_closure))
+    }
+}
+
+impl ILights for LightsService {
+    fn setLightState(&self, id: i32, state: &HwLightState) -> binder::Result<()> {
+        info!("Lights setting state for id={} to color {:x}", id, state.color);
+
+        if let Some(light) = self.lights.lock().unwrap().get_mut(&id) {
+            light.state = *state;
+            Ok(())
+        } else {
+            Err(Status::new_exception(ExceptionCode::UNSUPPORTED_OPERATION, None))
+        }
+    }
+
+    fn getLights(&self) -> binder::Result<Vec<HwLight>> {
+        info!("Lights reporting supported lights");
+        Ok(self.lights.lock().unwrap().values().map(|light| light.hw_light).collect())
+    }
+}
diff --git a/light/aidl/default/main.cpp b/light/aidl/default/main.cpp
deleted file mode 100644
index 54e1316..0000000
--- a/light/aidl/default/main.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "Lights.h"
-
-#include <android-base/logging.h>
-#include <android/binder_manager.h>
-#include <android/binder_process.h>
-
-using ::aidl::android::hardware::light::Lights;
-
-int main() {
-    ABinderProcess_setThreadPoolMaxThreadCount(0);
-    std::shared_ptr<Lights> lights = ndk::SharedRefBase::make<Lights>();
-
-    const std::string instance = std::string() + Lights::descriptor + "/default";
-    binder_status_t status = AServiceManager_addService(lights->asBinder().get(), instance.c_str());
-    CHECK_EQ(status, STATUS_OK);
-
-    ABinderProcess_joinThreadPool();
-    return EXIT_FAILURE;  // should not reached
-}
diff --git a/light/aidl/default/main.rs b/light/aidl/default/main.rs
new file mode 100644
index 0000000..8f32470
--- /dev/null
+++ b/light/aidl/default/main.rs
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+//! This implements the Lights Example Service.
+
+use android_hardware_light::aidl::android::hardware::light::ILights::{BnLights, ILights};
+use binder::BinderFeatures;
+
+mod lights;
+use lights::LightsService;
+
+const LOG_TAG: &str = "lights_service_example_rust";
+
+use log::Level;
+
+fn main() {
+    let logger_success = logger::init(
+        logger::Config::default().with_tag_on_device(LOG_TAG).with_min_level(Level::Trace),
+    );
+    if !logger_success {
+        panic!("{LOG_TAG}: Failed to start logger.");
+    }
+
+    binder::ProcessState::set_thread_pool_max_thread_count(0);
+
+    let lights_service = LightsService::default();
+    let lights_service_binder = BnLights::new_binder(lights_service, BinderFeatures::default());
+
+    let service_name = format!("{}/default", LightsService::get_descriptor());
+    binder::add_service(&service_name, lights_service_binder.as_binder())
+        .expect("Failed to register service");
+
+    binder::ProcessState::join_thread_pool()
+}
diff --git a/macsec/OWNERS b/macsec/OWNERS
new file mode 100644
index 0000000..6934f86
--- /dev/null
+++ b/macsec/OWNERS
@@ -0,0 +1 @@
+keithmok@google.com
diff --git a/macsec/aidl/Android.bp b/macsec/aidl/Android.bp
new file mode 100644
index 0000000..5e47999
--- /dev/null
+++ b/macsec/aidl/Android.bp
@@ -0,0 +1,40 @@
+//
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES 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.macsec",
+    vendor_available: true,
+    srcs: ["android/hardware/macsec/*.aidl"],
+    stability: "vintf",
+    host_supported: true,
+    backend: {
+        java: {
+            enabled: false,
+        },
+        rust: {
+            enabled: false,
+        },
+    },
+}
diff --git a/macsec/aidl/aidl_api/android.hardware.macsec/current/android/hardware/macsec/IMacsecPskPlugin.aidl b/macsec/aidl/aidl_api/android.hardware.macsec/current/android/hardware/macsec/IMacsecPskPlugin.aidl
new file mode 100644
index 0000000..6a93919
--- /dev/null
+++ b/macsec/aidl/aidl_api/android.hardware.macsec/current/android/hardware/macsec/IMacsecPskPlugin.aidl
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.macsec;
+
+/**
+ * MACSEC (IEEE 802.1AE) pre-shared key plugin for wpa_supplicant
+ *
+ * The goal of this service is to provide function for using the MACSEC CAK
+ *
+ */
+@VintfStability
+interface IMacsecPskPlugin {
+    /**
+     * For xTS test only inject a key to verify implementation correctness, not called in production
+     *
+     * @param keyId is key id to add
+     * @param Connectivity Association Keys (CAK) to set
+     * @param Connectivity Association Key Name (CKN) to set
+     *
+     */
+    void addTestKey(in byte[] keyId, in byte[] CAK, in byte[] CKN);
+
+    /**
+     * Use ICV key do AES CMAC
+     * same as ieee802_1x_icv_aes_cmac in wpa_supplicant
+     *
+     * @param keyId is key id to be used for AES CMAC
+     * @param data, a data pointer to the buffer for calculate the ICV
+     *
+     * @return Integrity check value (ICV).
+     */
+    byte[] calcIcv(in byte[] keyId, in byte[] data);
+
+    /**
+     * KDF with CAK key to generate Secure Association Key (SAK)
+     * same as ieee802_1x_sak_aes_cmac in wpa_supplicant
+     *
+     * @param keyId is key id to be used for KDF
+     * @param data is key seed (random number)
+     * @param sakLength generated SAK length (16 or 32)
+     *
+     * @return Secure Association Key (SAK).
+     */
+    byte[] generateSak(in byte[] keyId, in byte[] data, in int sakLength);
+
+    /**
+     * Encrypt using KEK key, this is same as aes_wrap with kek.key in wpa_supplicant
+     * which used to wrap a SAK key
+     *
+     * @param keyId is key id to be used for encryption
+     * @param sak is the SAK key (16 or 32 bytes) to be wrapped.
+     *
+     * @return wrapped data using Key Encrypting Key (KEK).
+     */
+    byte[] wrapSak(in byte[] keyId, in byte[] sak);
+
+    /**
+     * Decrypt using KEK key, this is same as aes_unwrap with kek.key in wpa_supplicant
+     * which used to unwrap a SAK key
+     *
+     * @param keyId is key id to be used for decryption
+     * @param sak is wrapped SAK key.
+     *
+     * @return unwrapped data using KEK key.
+     */
+    byte[] unwrapSak(in byte[] keyId, in byte[] sak);
+}
diff --git a/macsec/aidl/android/hardware/macsec/IMacsecPskPlugin.aidl b/macsec/aidl/android/hardware/macsec/IMacsecPskPlugin.aidl
new file mode 100644
index 0000000..a98cfa6
--- /dev/null
+++ b/macsec/aidl/android/hardware/macsec/IMacsecPskPlugin.aidl
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.macsec;
+
+/**
+ * MACSEC (IEEE 802.1AE) pre-shared key plugin for wpa_supplicant
+ *
+ * The goal of this service is to provide function for using the MACSEC CAK
+ *
+ */
+@VintfStability
+interface IMacsecPskPlugin {
+    /**
+     * For xTS test only inject a key to verify implementation correctness, not called in production
+     *
+     * @param keyId is key id to add
+     * @param Connectivity Association Keys (CAK) to set
+     * @param Connectivity Association Key Name (CKN) to set
+     * @throws EX_ILLEGAL_ARGUMENT If CAK size is not 16 or 32 or keyID size not equals to CAK size
+     */
+    void addTestKey(in byte[] keyId, in byte[] CAK, in byte[] CKN);
+
+    /**
+     * Use ICV key do AES CMAC
+     * same as ieee802_1x_icv_aes_cmac in wpa_supplicant
+     *
+     * @param keyId is key id to be used for AES CMAC
+     * @param data, a data pointer to the buffer for calculate the ICV
+     *
+     * @return Integrity check value (ICV).
+     * @throws EX_ILLEGAL_ARGUMENT If keyId does not exist
+     */
+    byte[] calcIcv(in byte[] keyId, in byte[] data);
+
+    /**
+     * KDF with CAK key to generate Secure Association Key (SAK)
+     * same as ieee802_1x_sak_aes_cmac in wpa_supplicant
+     *
+     * @param keyId is key id to be used for KDF
+     * @param data is key seed (random number)
+     * @param sakLength generated SAK length (16 or 32)
+     *
+     * @return Secure Association Key (SAK).
+     * @throws EX_ILLEGAL_ARGUMENT In the following cases:
+     *                             - If keyId does not exist
+     *                             - sakLength != 16 or 32
+     *                             - data length < sakLength
+     */
+    byte[] generateSak(in byte[] keyId, in byte[] data, in int sakLength);
+
+    /**
+     * Encrypt using KEK key, this is same as aes_wrap with kek.key in wpa_supplicant
+     * which used to wrap a SAK key
+     *
+     * @param keyId is key id to be used for encryption
+     * @param sak is the SAK key (16 or 32 bytes) to be wrapped.
+     *
+     * @return wrapped data using Key Encrypting Key (KEK).
+     * @throws EX_ILLEGAL_ARGUMENT In the following cases:
+     *                             - If keyId does not exist
+     *                             - sak size eqauls to 0 or not multiples of 8
+     */
+    byte[] wrapSak(in byte[] keyId, in byte[] sak);
+
+    /**
+     * Decrypt using KEK key, this is same as aes_unwrap with kek.key in wpa_supplicant
+     * which used to unwrap a SAK key
+     *
+     * @param keyId is key id to be used for decryption
+     * @param sak is wrapped SAK key.
+     *
+     * @return unwrapped data using KEK key.
+     * @throws EX_ILLEGAL_ARGUMENT In the following cases:
+     *                             - If keyId does not exist
+     *                             - sak size <= 8 or not multiples of 8
+     */
+    byte[] unwrapSak(in byte[] keyId, in byte[] sak);
+}
diff --git a/macsec/aidl/default/Android.bp b/macsec/aidl/default/Android.bp
new file mode 100644
index 0000000..7c7346f
--- /dev/null
+++ b/macsec/aidl/default/Android.bp
@@ -0,0 +1,64 @@
+//
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES 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.macsec-service",
+    init_rc: ["android.hardware.macsec.rc"],
+    vendor: true,
+    relative_install_path: "hw",
+    srcs: [
+        "MacsecPskPlugin.cpp",
+        "service.cpp",
+    ],
+    shared_libs: [
+        "android.hardware.macsec-V1-ndk",
+        "libcrypto",
+        "libbase",
+        "libbinder_ndk",
+    ],
+    vintf_fragments: ["android.hardware.macsec.xml"],
+}
+
+cc_fuzz {
+    name: "android.hardware.macsec@V1-default-service.aidl_fuzzer",
+    vendor: true,
+    srcs: [
+        "MacsecPskPlugin.cpp",
+        "fuzzer/fuzzer.cpp",
+    ],
+    shared_libs: [
+        "android.hardware.macsec-V1-ndk",
+        "libcrypto",
+        "liblog",
+    ],
+    defaults: [
+        "service_fuzzer_defaults",
+    ],
+    fuzz_config: {
+        cc: [
+            "keithmok@google.com",
+        ],
+    },
+}
diff --git a/macsec/aidl/default/MacsecPskPlugin.cpp b/macsec/aidl/default/MacsecPskPlugin.cpp
new file mode 100644
index 0000000..82d2545
--- /dev/null
+++ b/macsec/aidl/default/MacsecPskPlugin.cpp
@@ -0,0 +1,308 @@
+/*
+ * Copyright 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "MacsecPskPlugin.h"
+#include <openssl/cipher.h>
+#include <openssl/mem.h>
+
+#include <android-base/format.h>
+#include <android-base/logging.h>
+
+namespace aidl::android::hardware::macsec {
+
+constexpr auto ok = &ndk::ScopedAStatus::ok;
+
+// vendor should hide the key in TEE/TA
+// CAK key can be either 16 / 32 bytes
+const std::vector<uint8_t> CAK_ID_1 = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
+const std::vector<uint8_t> CAK_KEY_1 = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
+                                        0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF};
+std::vector<uint8_t> CKN_1 = {0x31, 0x32, 0x33, 0x34};  // maximum 16 bytes
+
+const std::vector<uint8_t> CAK_ID_2 = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02};
+const std::vector<uint8_t> CAK_KEY_2 = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
+                                        0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
+                                        0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
+                                        0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF};
+std::vector<uint8_t> CKN_2 = {0x35, 0x36, 0x37, 0x38};  // maximum 16 bytes
+
+static ndk::ScopedAStatus resultToStatus(binder_exception_t res, const std::string& msg = "") {
+    if (msg.empty()) {
+        return ndk::ScopedAStatus::fromExceptionCode(res);
+    }
+    return ndk::ScopedAStatus::fromExceptionCodeWithMessage(res, msg.c_str());
+}
+
+static int omac1_aes(CMAC_CTX* ctx, const uint8_t* data, size_t data_len,
+                     uint8_t* mac /* 16 bytes */) {
+    size_t outlen;
+
+    // Just reuse same key in ctx
+    if (!CMAC_Reset(ctx)) {
+        return -1;
+    }
+
+    if (!CMAC_Update(ctx, data, data_len)) {
+        return -1;
+    }
+
+    if (!CMAC_Final(ctx, mac, &outlen) || outlen != 16) {
+        return -1;
+    }
+    return 0;
+}
+
+static void put_be16(uint8_t* addr, uint16_t value) {
+    *addr++ = value >> 8;
+    *addr = value & 0xff;
+}
+
+/* IEEE Std 802.1X-2010, 6.2.1 KDF */
+static int aes_kdf(CMAC_CTX* ctx, const char* label, const uint8_t* context, int ctx_bits,
+                   int ret_bits, uint8_t* ret) {
+    const int h = 128;
+    const int r = 8;
+    int i, n;
+    int lab_len, ctx_len, ret_len, buf_len;
+    uint8_t* buf;
+
+    lab_len = strlen(label);
+    ctx_len = (ctx_bits + 7) / 8;
+    ret_len = ((ret_bits & 0xffff) + 7) / 8;
+    buf_len = lab_len + ctx_len + 4;
+
+    memset(ret, 0, ret_len);
+
+    n = (ret_bits + h - 1) / h;
+    if (n > ((0x1 << r) - 1)) return -1;
+
+    buf = (uint8_t*)calloc(1, buf_len);
+    if (buf == NULL) return -1;
+
+    memcpy(buf + 1, label, lab_len);
+    memcpy(buf + lab_len + 2, context, ctx_len);
+    put_be16(&buf[buf_len - 2], ret_bits);
+
+    for (i = 0; i < n; i++) {
+        int res;
+
+        buf[0] = (uint8_t)(i + 1);
+        res = omac1_aes(ctx, buf, buf_len, ret);
+        if (res) {
+            free(buf);
+            return -1;
+        }
+        ret = ret + h / 8;
+    }
+    free(buf);
+    return 0;
+}
+
+MacsecPskPlugin::MacsecPskPlugin() {
+    // always make sure ckn is 16 bytes, zero padded
+    CKN_1.resize(16);
+    CKN_2.resize(16);
+
+    addTestKey(CAK_ID_1, CAK_KEY_1, CKN_1);
+    addTestKey(CAK_ID_2, CAK_KEY_2, CKN_2);
+}
+
+MacsecPskPlugin::~MacsecPskPlugin() {
+    for (auto s : mKeys) {
+        OPENSSL_cleanse(&s.kekEncCtx, sizeof(AES_KEY));
+        OPENSSL_cleanse(&s.kekDecCtx, sizeof(AES_KEY));
+        CMAC_CTX_free(s.ickCtx);
+        CMAC_CTX_free(s.cakCtx);
+    }
+}
+
+ndk::ScopedAStatus MacsecPskPlugin::addTestKey(const std::vector<uint8_t>& keyId,
+                                               const std::vector<uint8_t>& CAK,
+                                               const std::vector<uint8_t>& CKN) {
+    if (CAK.size() != 16 && CAK.size() != 32) {
+        return resultToStatus(EX_ILLEGAL_ARGUMENT, "CAK length must be 16 or 32 bytes");
+    }
+
+    if (keyId.size() != CAK.size()) {
+        return resultToStatus(EX_ILLEGAL_ARGUMENT, "Key ID must be same as CAK length");
+    }
+
+    std::vector<uint8_t> ckn;
+    ckn = CKN;
+    ckn.resize(16);  // make sure it is always zero padded with maximum length of
+                     // 16 bytes
+
+    AES_KEY kekEncCtx;
+    AES_KEY kekDecCtx;
+    CMAC_CTX* ickCtx;
+    CMAC_CTX* cakCtx;
+
+    // Create the CAK openssl context
+    cakCtx = CMAC_CTX_new();
+
+    CMAC_Init(cakCtx, CAK.data(), CAK.size(),
+              CAK.size() == 16 ? EVP_aes_128_cbc() : EVP_aes_256_cbc(), NULL);
+
+    // derive KEK from CAK (ieee802_1x_kek_aes_cmac)
+    std::vector<uint8_t> kek;
+    kek.resize(CAK.size());
+
+    aes_kdf(cakCtx, "IEEE8021 KEK", (const uint8_t*)ckn.data(), ckn.size() * 8, 8 * kek.size(),
+            kek.data());
+
+    AES_set_encrypt_key(kek.data(), kek.size() << 3, &kekEncCtx);
+    AES_set_decrypt_key(kek.data(), kek.size() << 3, &kekDecCtx);
+
+    // derive ICK from CAK (ieee802_1x_ick_aes_cmac)
+    std::vector<uint8_t> ick;
+    ick.resize(CAK.size());
+
+    aes_kdf(cakCtx, "IEEE8021 ICK", (const uint8_t*)CKN.data(), CKN.size() * 8, 8 * ick.size(),
+            ick.data());
+
+    ickCtx = CMAC_CTX_new();
+
+    CMAC_Init(ickCtx, ick.data(), ick.size(),
+              ick.size() == 16 ? EVP_aes_128_cbc() : EVP_aes_256_cbc(), NULL);
+
+    mKeys.push_back({keyId, kekEncCtx, kekDecCtx, ickCtx, cakCtx});
+
+    return ok();
+}
+
+ndk::ScopedAStatus MacsecPskPlugin::calcIcv(const std::vector<uint8_t>& keyId,
+                                            const std::vector<uint8_t>& data,
+                                            std::vector<uint8_t>* out) {
+    CMAC_CTX* ctx = NULL;
+
+    for (auto s : mKeys) {
+        if (s.keyId == keyId) {
+            ctx = s.ickCtx;
+            break;
+        }
+    }
+
+    if (ctx == NULL) {
+        return resultToStatus(EX_ILLEGAL_ARGUMENT, "Key not exist");
+    }
+
+    out->resize(16);
+    if (omac1_aes(ctx, data.data(), data.size(), out->data()) != 0) {
+        return resultToStatus(EX_SERVICE_SPECIFIC, "Internal error");
+    }
+
+    return ok();
+}
+
+ndk::ScopedAStatus MacsecPskPlugin::generateSak(const std::vector<uint8_t>& keyId,
+                                                const std::vector<uint8_t>& data,
+                                                const int sakLength, std::vector<uint8_t>* out) {
+    CMAC_CTX* ctx = NULL;
+
+    if ((sakLength != 16) && (sakLength != 32)) {
+        return resultToStatus(EX_ILLEGAL_ARGUMENT, "Invalid SAK length");
+    }
+
+    if (data.size() < sakLength) {
+        return resultToStatus(EX_ILLEGAL_ARGUMENT, "Invalid data length");
+    }
+
+    for (auto s : mKeys) {
+        if (s.keyId == keyId) {
+            ctx = s.cakCtx;
+            break;
+        }
+    }
+
+    if (ctx == NULL) {
+        return resultToStatus(EX_ILLEGAL_ARGUMENT, "Key not exist");
+    }
+
+    out->resize(sakLength);
+
+    if (aes_kdf(ctx, "IEEE8021 SAK", data.data(), data.size() * 8, out->size() * 8, out->data()) !=
+        0) {
+        return resultToStatus(EX_SERVICE_SPECIFIC, "Internal error");
+    }
+
+    return ok();
+}
+
+ndk::ScopedAStatus MacsecPskPlugin::wrapSak(const std::vector<uint8_t>& keyId,
+                                            const std::vector<uint8_t>& sak,
+                                            std::vector<uint8_t>* out) {
+    if (sak.size() == 0 || sak.size() % 8 != 0) {
+        return resultToStatus(EX_ILLEGAL_ARGUMENT,
+                              "SAK length not multiple of 8 or greater than 0");
+    }
+
+    AES_KEY* ctx = NULL;
+
+    for (auto s : mKeys) {
+        if (s.keyId == keyId) {
+            ctx = &s.kekEncCtx;
+            break;
+        }
+    }
+
+    if (ctx == NULL) {
+        return resultToStatus(EX_ILLEGAL_ARGUMENT, "Key not exist");
+    }
+
+    out->resize(sak.size() + 8);
+
+    if (AES_wrap_key(ctx, NULL, out->data(), sak.data(), sak.size()) > 0) {
+        return ok();
+    }
+
+    return resultToStatus(EX_SERVICE_SPECIFIC, "Internal error");
+}
+
+ndk::ScopedAStatus MacsecPskPlugin::unwrapSak(const std::vector<uint8_t>& keyId,
+                                              const std::vector<uint8_t>& sak,
+                                              std::vector<uint8_t>* out) {
+    if (sak.size() <= 8 || sak.size() % 8 != 0) {
+        return resultToStatus(EX_ILLEGAL_ARGUMENT,
+                              "SAK length not multiple of 8 or greater than 0");
+    }
+
+    AES_KEY* ctx = NULL;
+
+    for (auto s : mKeys) {
+        if (s.keyId == keyId) {
+            ctx = &s.kekDecCtx;
+            break;
+        }
+    }
+
+    if (ctx == NULL) {
+        return resultToStatus(EX_ILLEGAL_ARGUMENT, "Key not exist");
+    }
+
+    out->resize(sak.size() - 8);
+
+    if (AES_unwrap_key(ctx, NULL, out->data(), sak.data(), sak.size()) > 0) {
+        return ok();
+    }
+
+    return resultToStatus(EX_SERVICE_SPECIFIC, "Internal error");
+}
+
+}  // namespace aidl::android::hardware::macsec
diff --git a/macsec/aidl/default/MacsecPskPlugin.h b/macsec/aidl/default/MacsecPskPlugin.h
new file mode 100644
index 0000000..0b056e3
--- /dev/null
+++ b/macsec/aidl/default/MacsecPskPlugin.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/macsec/BnMacsecPskPlugin.h>
+
+#include <openssl/aes.h>
+#include <openssl/cmac.h>
+
+namespace aidl::android::hardware::macsec {
+
+struct keys {
+    std::vector<uint8_t> keyId;
+    AES_KEY kekEncCtx;
+    AES_KEY kekDecCtx;
+    CMAC_CTX* ickCtx;
+    CMAC_CTX* cakCtx;
+};
+
+class MacsecPskPlugin : public BnMacsecPskPlugin {
+  public:
+    MacsecPskPlugin();
+    ~MacsecPskPlugin();
+    ndk::ScopedAStatus addTestKey(const std::vector<uint8_t>& keyId,
+                                  const std::vector<uint8_t>& CAK,
+                                  const std::vector<uint8_t>& CKN) override;
+    ndk::ScopedAStatus calcIcv(const std::vector<uint8_t>& keyId, const std::vector<uint8_t>& data,
+                               std::vector<uint8_t>* out) override;
+
+    ndk::ScopedAStatus generateSak(const std::vector<uint8_t>& keyId,
+                                   const std::vector<uint8_t>& data, const int sakLength,
+                                   std::vector<uint8_t>* out);
+
+    ndk::ScopedAStatus wrapSak(const std::vector<uint8_t>& keyId, const std::vector<uint8_t>& sak,
+                               std::vector<uint8_t>* out) override;
+
+    ndk::ScopedAStatus unwrapSak(const std::vector<uint8_t>& keyId, const std::vector<uint8_t>& sak,
+                                 std::vector<uint8_t>* out) override;
+
+  private:
+    std::vector<struct keys> mKeys;
+};
+}  // namespace aidl::android::hardware::macsec
diff --git a/macsec/aidl/default/android.hardware.macsec.rc b/macsec/aidl/default/android.hardware.macsec.rc
new file mode 100644
index 0000000..0ff0e53
--- /dev/null
+++ b/macsec/aidl/default/android.hardware.macsec.rc
@@ -0,0 +1,3 @@
+service android.hardware.macsec /vendor/bin/hw/android.hardware.macsec-service
+    class early_hal
+    user nobody
diff --git a/macsec/aidl/default/android.hardware.macsec.xml b/macsec/aidl/default/android.hardware.macsec.xml
new file mode 100644
index 0000000..9cf9e5a
--- /dev/null
+++ b/macsec/aidl/default/android.hardware.macsec.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.macsec</name>
+        <version>1</version>
+        <interface>
+            <name>IMacsecPskPlugin</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/macsec/aidl/default/fuzzer/fuzzer.cpp b/macsec/aidl/default/fuzzer/fuzzer.cpp
new file mode 100644
index 0000000..d912a67
--- /dev/null
+++ b/macsec/aidl/default/fuzzer/fuzzer.cpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fuzzbinder/libbinder_ndk_driver.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include "MacsecPskPlugin.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    std::shared_ptr<aidl::android::hardware::macsec::MacsecPskPlugin> service =
+            ndk::SharedRefBase::make<aidl::android::hardware::macsec::MacsecPskPlugin>();
+    android::fuzzService(service->asBinder().get(), FuzzedDataProvider(data, size));
+
+    return 0;
+}
diff --git a/macsec/aidl/default/service.cpp b/macsec/aidl/default/service.cpp
new file mode 100644
index 0000000..faf3a09
--- /dev/null
+++ b/macsec/aidl/default/service.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "MacsecPskPlugin.h"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+namespace android::hardware::macsec {
+
+using namespace std::string_literals;
+using ::aidl::android::hardware::macsec::MacsecPskPlugin;
+
+extern "C" int main() {
+    base::SetDefaultTag("MacsecPskPlugin");
+    base::SetMinimumLogSeverity(base::VERBOSE);
+
+    LOG(VERBOSE) << "Starting up...";
+    auto service = ndk::SharedRefBase::make<MacsecPskPlugin>();
+    const auto instance = MacsecPskPlugin::descriptor + "/default"s;
+    const auto status = AServiceManager_addService(service->asBinder().get(), instance.c_str());
+    CHECK_EQ(status, STATUS_OK) << "Failed to add service " << instance;
+    LOG(VERBOSE) << "Started successfully!";
+
+    ABinderProcess_joinThreadPool();
+    LOG(FATAL) << "MacsecPskPlugin exited unexpectedly!";
+    return EXIT_FAILURE;
+}
+}  // namespace android::hardware::macsec
diff --git a/macsec/aidl/vts/functional/Android.bp b/macsec/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..0c8f43d
--- /dev/null
+++ b/macsec/aidl/vts/functional/Android.bp
@@ -0,0 +1,48 @@
+//
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES 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: "VtsHalMacsecPskPluginV1Test",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    cpp_std: "experimental",
+    srcs: [
+        "MacsecAidlTest.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+    ],
+    static_libs: [
+        "android.hardware.macsec-V1-ndk",
+        "libgmock",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
diff --git a/macsec/aidl/vts/functional/MacsecAidlTest.cpp b/macsec/aidl/vts/functional/MacsecAidlTest.cpp
new file mode 100644
index 0000000..e94c049
--- /dev/null
+++ b/macsec/aidl/vts/functional/MacsecAidlTest.cpp
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/macsec/IMacsecPskPlugin.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <gtest/gtest.h>
+
+#include <chrono>
+#include <thread>
+
+using aidl::android::hardware::macsec::IMacsecPskPlugin;
+using namespace std::chrono_literals;
+using namespace std::string_literals;
+
+const std::vector<uint8_t> CAK_ID_1 = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01};
+const std::vector<uint8_t> CAK_KEY_1 = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
+                                        0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF};
+const std::vector<uint8_t> CKN_1 = {0x31, 0x32, 0x33, 0x34};  // maximum 16 bytes
+const std::vector<uint8_t> SAK_DATA_1 = {0x31, 0x32, 0x33, 0x34, 0x11, 0x12, 0x12, 0x14,
+                                         0x31, 0x32, 0x33, 0x34, 0x11, 0x12, 0x12, 0x14};
+const std::vector<uint8_t> SAK_1 = {0x13, 0xD9, 0xEE, 0x5B, 0x26, 0x8B, 0x44, 0xFB,
+                                    0x37, 0x63, 0x3D, 0x41, 0xC8, 0xE7, 0x0D, 0x93};
+const std::vector<uint8_t> WRAPPED_SAK_1 = {0x3B, 0x39, 0xAB, 0x4C, 0xD8, 0xDA, 0x2E, 0xC5,
+                                            0xD1, 0x38, 0x6A, 0x13, 0x9D, 0xE3, 0x78, 0xD9,
+                                            0x93, 0xD2, 0xA0, 0x70, 0x88, 0xCB, 0xF5, 0xEC};
+const std::vector<uint8_t> DATA_1 = {0x31, 0x32, 0x33, 0x34, 0x31, 0x32, 0x34, 0x29,
+                                     0x51, 0x52, 0x53, 0x54, 0x51, 0x35, 0x54, 0x59};
+const std::vector<uint8_t> ICV_1 = {0xDF, 0x54, 0xFF, 0xCD, 0xE0, 0xA9, 0x78, 0x10,
+                                    0x6B, 0x7B, 0xD2, 0xBF, 0xEF, 0xD9, 0x0C, 0x81};
+
+const std::vector<uint8_t> CAK_ID_2 = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02};
+const std::vector<uint8_t> CAK_KEY_2 = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
+                                        0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
+                                        0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
+                                        0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF};
+const std::vector<uint8_t> CKN_2 = {0x35, 0x36, 0x37, 0x38};  // maximum 16 bytes
+const std::vector<uint8_t> SAK_DATA_2 = {0x31, 0x32, 0x33, 0x34, 0x31, 0x32, 0x33, 0x34,
+                                         0x31, 0x32, 0x33, 0x34, 0x31, 0x32, 0x33, 0x34,
+                                         0x31, 0x32, 0x33, 0x34, 0x31, 0x32, 0x33, 0x34,
+                                         0x31, 0x32, 0x33, 0x34, 0x31, 0x32, 0x33, 0x34};
+const std::vector<uint8_t> SAK_2 = {0x39, 0x09, 0x36, 0x60, 0x18, 0x07, 0x2B, 0x5D,
+                                    0xF0, 0x81, 0x81, 0x45, 0xCD, 0x71, 0xC6, 0xBA,
+                                    0x1D, 0x2B, 0x87, 0xC4, 0xEF, 0x79, 0x68, 0x82,
+                                    0x28, 0xD0, 0x25, 0x86, 0xD3, 0x63, 0xFF, 0x89};
+const std::vector<uint8_t> WRAPPED_SAK_2 = {
+        0x2f, 0x6a, 0x22, 0x29, 0x68, 0x0e, 0x6e, 0x35, 0x91, 0x64, 0x05, 0x4a, 0x31, 0x8d,
+        0x35, 0xea, 0x95, 0x85, 0x40, 0xc6, 0xea, 0x55, 0xe5, 0xc5, 0x68, 0x40, 0xae, 0x4d,
+        0x6f, 0xeb, 0x73, 0xcd, 0x4e, 0x2a, 0x43, 0xb1, 0xda, 0x49, 0x4f, 0x0a};
+const std::vector<uint8_t> DATA_2 = {0x71, 0x82, 0x13, 0x24, 0x31, 0x82, 0xA4, 0x2F,
+                                     0x51, 0x52, 0x53, 0x44, 0x21, 0x35, 0x54, 0x59};
+const std::vector<uint8_t> ICV_2 = {0x8D, 0xF1, 0x1D, 0x6E, 0xAC, 0x62, 0xC1, 0x2A,
+                                    0xE8, 0xF8, 0x4E, 0xB1, 0x00, 0x45, 0x9A, 0xAD};
+
+class MacsecAidlTest : public ::testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        android::base::SetDefaultTag("MACSEC_HAL_VTS");
+        android::base::SetMinimumLogSeverity(android::base::VERBOSE);
+        const auto instance = IMacsecPskPlugin::descriptor + "/default"s;
+        mMacsecPskPluginService = IMacsecPskPlugin::fromBinder(
+                ndk::SpAIBinder(AServiceManager_waitForService(instance.c_str())));
+
+        ASSERT_NE(mMacsecPskPluginService, nullptr);
+        auto aidlStatus = mMacsecPskPluginService->addTestKey(CAK_ID_1, CAK_KEY_1, CKN_1);
+        ASSERT_TRUE(aidlStatus.isOk());
+        aidlStatus = mMacsecPskPluginService->addTestKey(CAK_ID_2, CAK_KEY_2, CKN_2);
+        ASSERT_TRUE(aidlStatus.isOk());
+    }
+    virtual void TearDown() override {}
+
+    std::shared_ptr<IMacsecPskPlugin> mMacsecPskPluginService;
+};
+
+TEST_P(MacsecAidlTest, calcIcv) {
+    std::vector<uint8_t> out;
+    auto aidlStatus = mMacsecPskPluginService->calcIcv(CAK_ID_1, DATA_1, &out);
+    ASSERT_TRUE(aidlStatus.isOk()) << "calcIcv KEY 1 failed: " << aidlStatus.getMessage();
+    EXPECT_EQ(out, ICV_1);
+
+    aidlStatus = mMacsecPskPluginService->calcIcv(CAK_ID_2, DATA_2, &out);
+    ASSERT_TRUE(aidlStatus.isOk()) << "calcIcv KEY 2 failed: " << aidlStatus.getMessage();
+    EXPECT_EQ(out, ICV_2);
+}
+
+TEST_P(MacsecAidlTest, generateSak) {
+    std::vector<uint8_t> out;
+    auto aidlStatus = mMacsecPskPluginService->generateSak(CAK_ID_1, SAK_DATA_1, 16, &out);
+    ASSERT_TRUE(aidlStatus.isOk()) << "generateSak KEY 1 failed: " << aidlStatus.getMessage();
+    EXPECT_EQ(out, SAK_1);
+
+    aidlStatus = mMacsecPskPluginService->generateSak(CAK_ID_2, SAK_DATA_2, 32, &out);
+    ASSERT_TRUE(aidlStatus.isOk()) << "generateSak KEY 2 failed: " << aidlStatus.getMessage();
+    EXPECT_EQ(out, SAK_2);
+}
+
+TEST_P(MacsecAidlTest, wrapSak) {
+    std::vector<uint8_t> out;
+    auto aidlStatus = mMacsecPskPluginService->wrapSak(CAK_ID_1, SAK_1, &out);
+    ASSERT_TRUE(aidlStatus.isOk()) << "wrapSak KEY 1 failed: " << aidlStatus.getMessage();
+    EXPECT_EQ(out, WRAPPED_SAK_1);
+
+    aidlStatus = mMacsecPskPluginService->wrapSak(CAK_ID_2, SAK_2, &out);
+    ASSERT_TRUE(aidlStatus.isOk()) << "wrapSak KEY 2 failed: " << aidlStatus.getMessage();
+    EXPECT_EQ(out, WRAPPED_SAK_2);
+}
+
+TEST_P(MacsecAidlTest, unwrapSak) {
+    std::vector<uint8_t> out;
+    auto aidlStatus = mMacsecPskPluginService->unwrapSak(CAK_ID_1, WRAPPED_SAK_1, &out);
+    ASSERT_TRUE(aidlStatus.isOk()) << "unwrapSak KEY 1 failed: " << aidlStatus.getMessage();
+    EXPECT_EQ(out, SAK_1);
+
+    aidlStatus = mMacsecPskPluginService->unwrapSak(CAK_ID_2, WRAPPED_SAK_2, &out);
+    ASSERT_TRUE(aidlStatus.isOk()) << "unwrapSak KEY 2 failed: " << aidlStatus.getMessage();
+    EXPECT_EQ(out, SAK_2);
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MacsecAidlTest);
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, MacsecAidlTest,
+        testing::ValuesIn(android::getAidlHalInstanceNames(IMacsecPskPlugin::descriptor)),
+        android::PrintInstanceNameToString);
diff --git a/macsec/aidl/vts/functional/OWNERS b/macsec/aidl/vts/functional/OWNERS
new file mode 100644
index 0000000..5009a88
--- /dev/null
+++ b/macsec/aidl/vts/functional/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 533426
+keithmok@google.com
diff --git a/media/OWNERS b/media/OWNERS
index 71a53ef..01b440a 100644
--- a/media/OWNERS
+++ b/media/OWNERS
@@ -1,7 +1,6 @@
 # Bug component: 25690
 
 # Media team
-jgus@google.com
 lajos@google.com
 taklee@google.com
 wonsik@google.com
diff --git a/media/bufferpool/aidl/Android.bp b/media/bufferpool/aidl/Android.bp
index 8caf525..9dcc90e 100644
--- a/media/bufferpool/aidl/Android.bp
+++ b/media/bufferpool/aidl/Android.bp
@@ -26,6 +26,9 @@
     vendor_available: true,
     double_loadable: true,
     srcs: ["android/hardware/media/bufferpool2/*.aidl"],
+    headers: [
+        "HardwareBuffer_aidl",
+    ],
     imports: [
         "android.hardware.common-V2",
         "android.hardware.common.fmq-V1",
@@ -44,8 +47,14 @@
                 "//apex_available:platform",
                 "com.android.media.swcodec",
             ],
+            additional_shared_libraries: [
+                "libnativewindow",
+            ],
             min_sdk_version: "29",
         },
+        rust: {
+            enabled: false,
+        },
     },
     versions_with_info: [
         {
@@ -56,6 +65,6 @@
             ],
         },
     ],
-    frozen: true,
+    frozen: false,
 
 }
diff --git a/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/Buffer.aidl b/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/Buffer.aidl
index 4ea0bba..85a78ad 100644
--- a/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/Buffer.aidl
+++ b/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/Buffer.aidl
@@ -35,5 +35,6 @@
 @VintfStability
 parcelable Buffer {
   int id;
-  android.hardware.common.NativeHandle buffer;
+  @nullable android.hardware.common.NativeHandle buffer;
+  @nullable android.hardware.HardwareBuffer hwbBuffer;
 }
diff --git a/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/IClientManager.aidl b/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/IClientManager.aidl
index 5899a40..298cb13 100644
--- a/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/IClientManager.aidl
+++ b/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/IClientManager.aidl
@@ -35,6 +35,7 @@
 @VintfStability
 interface IClientManager {
   android.hardware.media.bufferpool2.IClientManager.Registration registerSender(in android.hardware.media.bufferpool2.IAccessor bufferPool);
+  android.hardware.media.bufferpool2.IClientManager.Registration registerPassiveSender(in android.hardware.media.bufferpool2.IAccessor bufferPool);
   @VintfStability
   parcelable Registration {
     long connectionId;
diff --git a/media/bufferpool/aidl/android/hardware/media/bufferpool2/Buffer.aidl b/media/bufferpool/aidl/android/hardware/media/bufferpool2/Buffer.aidl
index 976f674..79b3f23 100644
--- a/media/bufferpool/aidl/android/hardware/media/bufferpool2/Buffer.aidl
+++ b/media/bufferpool/aidl/android/hardware/media/bufferpool2/Buffer.aidl
@@ -17,6 +17,7 @@
 package android.hardware.media.bufferpool2;
 
 import android.hardware.common.NativeHandle;
+import android.hardware.HardwareBuffer;
 
 /**
  * Generic buffer for fast recycling for media/stagefright.
@@ -26,10 +27,14 @@
  * by a buffer pool, and are recycled to the buffer pool when they are
  * no longer referenced by the clients.
  *
+ * Initially all buffers in media HAL should be NativeHandle(actually native_handle_t).
+ * HardwareBuffer(actually AHardwareBuffer) for GraphicBuffer is added from V2.
+ *
  * E.g. ion or gralloc buffer
  */
 @VintfStability
 parcelable Buffer {
     int id;
-    NativeHandle buffer;
+    @nullable NativeHandle buffer;
+    @nullable HardwareBuffer hwbBuffer;
 }
diff --git a/media/bufferpool/aidl/android/hardware/media/bufferpool2/IClientManager.aidl b/media/bufferpool/aidl/android/hardware/media/bufferpool2/IClientManager.aidl
index a3054cb..2bc77bc 100644
--- a/media/bufferpool/aidl/android/hardware/media/bufferpool2/IClientManager.aidl
+++ b/media/bufferpool/aidl/android/hardware/media/bufferpool2/IClientManager.aidl
@@ -40,7 +40,8 @@
     /**
      * Sets up a buffer receiving communication node for the specified
      * buffer pool. A manager must create a IConnection to the buffer
-     * pool if it does not already have a connection.
+     * pool if it does not already have a connection. To transfer buffers
+     * using the interface, the sender must initiates transfer.
      *
      * @param bufferPool a buffer pool which is specified with the IAccessor.
      *     The specified buffer pool is the owner of received buffers.
@@ -52,4 +53,21 @@
      *     ResultStatus::CRITICAL_ERROR   - Other errors.
      */
     Registration registerSender(in IAccessor bufferPool);
+
+    /**
+     * Sets up a buffer receiving communication node for the specified
+     * buffer pool. A manager must create a IConnection to the buffer
+     * pool if it does not already have a connection. To transfer buffers
+     * using the interface, the receiver must initiates transfer(on demand).
+     *
+     * @param bufferPool a buffer pool which is specified with the IAccessor.
+     *     The specified buffer pool is the owner of received buffers.
+     * @return the Id of the communication node to the buffer pool.
+     *     This id is used in FMQ to notify IAccessor that a buffer has been
+     *     sent to that connection during transfers.
+     * @throws ServiceSpecificException with one of the following values:
+     *     ResultStatus::NO_MEMORY        - Memory allocation failure occurred.
+     *     ResultStatus::CRITICAL_ERROR   - Other errors.
+     */
+    Registration registerPassiveSender(in IAccessor bufferPool);
 }
diff --git a/media/bufferpool/aidl/default/Android.bp b/media/bufferpool/aidl/default/Android.bp
index 11a6163..4d12d63 100644
--- a/media/bufferpool/aidl/default/Android.bp
+++ b/media/bufferpool/aidl/default/Android.bp
@@ -33,15 +33,16 @@
         "libcutils",
         "libfmq",
         "liblog",
+        "libnativewindow",
         "libutils",
-        "android.hardware.media.bufferpool2-V1-ndk",
+        "android.hardware.media.bufferpool2-V2-ndk",
     ],
     static_libs: [
         "libaidlcommonsupport",
     ],
     export_shared_lib_headers: [
         "libfmq",
-        "android.hardware.media.bufferpool2-V1-ndk",
+        "android.hardware.media.bufferpool2-V2-ndk",
     ],
     double_loadable: true,
     cflags: [
diff --git a/media/bufferpool/aidl/default/BufferPoolClient.cpp b/media/bufferpool/aidl/default/BufferPoolClient.cpp
index e9777d8..ce4ad8e 100644
--- a/media/bufferpool/aidl/default/BufferPoolClient.cpp
+++ b/media/bufferpool/aidl/default/BufferPoolClient.cpp
@@ -297,7 +297,7 @@
       mLastEvictCacheMs(::android::elapsedRealtime()) {
     IAccessor::ConnectionInfo conInfo;
     bool valid = false;
-    if(accessor->connect(observer, &conInfo).isOk()) {
+    if (accessor && accessor->connect(observer, &conInfo).isOk()) {
         auto channel = std::make_unique<BufferStatusChannel>(conInfo.toFmqDesc);
         auto observer = std::make_unique<BufferInvalidationListener>(conInfo.fromFmqDesc);
 
@@ -757,7 +757,13 @@
         return svcSpecific ? svcSpecific : ResultStatus::CRITICAL_ERROR;
     }
     if (results[0].getTag() == FetchResult::buffer) {
-        *handle = ::android::dupFromAidl(results[0].get<FetchResult::buffer>().buffer);
+        if (results[0].get<FetchResult::buffer>().buffer.has_value()) {
+            *handle = ::android::dupFromAidl(results[0].get<FetchResult::buffer>().buffer.value());
+        } else {
+            // TODO: Support HardwareBuffer
+            ALOGW("handle nullptr");
+            *handle = nullptr;
+        }
         return ResultStatus::OK;
     }
     return results[0].get<FetchResult::failure>();
diff --git a/media/bufferpool/aidl/default/ClientManager.cpp b/media/bufferpool/aidl/default/ClientManager.cpp
index de1db50..138790d 100644
--- a/media/bufferpool/aidl/default/ClientManager.cpp
+++ b/media/bufferpool/aidl/default/ClientManager.cpp
@@ -422,6 +422,14 @@
     return ::ndk::ScopedAStatus::ok();
 }
 
+::ndk::ScopedAStatus ClientManager::registerPassiveSender(
+        const std::shared_ptr<IAccessor>& in_bufferPool, Registration* _aidl_return) {
+    // TODO
+    (void) in_bufferPool;
+    (void) _aidl_return;
+    return ::ndk::ScopedAStatus::fromServiceSpecificError(ResultStatus::NOT_FOUND);
+}
+
 // Methods for local use.
 std::shared_ptr<ClientManager> ClientManager::sInstance;
 std::mutex ClientManager::sInstanceLock;
diff --git a/media/bufferpool/aidl/default/include/bufferpool2/ClientManager.h b/media/bufferpool/aidl/default/include/bufferpool2/ClientManager.h
index bff75ba..4b0916f 100644
--- a/media/bufferpool/aidl/default/include/bufferpool2/ClientManager.h
+++ b/media/bufferpool/aidl/default/include/bufferpool2/ClientManager.h
@@ -34,6 +34,11 @@
         ::aidl::android::hardware::media::bufferpool2::IClientManager::Registration* _aidl_return)
         override;
 
+    ::ndk::ScopedAStatus registerPassiveSender(
+        const std::shared_ptr<IAccessor>& in_bufferPool,
+        ::aidl::android::hardware::media::bufferpool2::IClientManager::Registration* _aidl_return)
+        override;
+
     /** Gets an instance. */
     static std::shared_ptr<ClientManager> getInstance();
 
diff --git a/media/bufferpool/aidl/default/tests/Android.bp b/media/bufferpool/aidl/default/tests/Android.bp
index 549af57..487ed4c 100644
--- a/media/bufferpool/aidl/default/tests/Android.bp
+++ b/media/bufferpool/aidl/default/tests/Android.bp
@@ -36,8 +36,9 @@
         "libcutils",
         "libfmq",
         "liblog",
+        "libnativewindow",
         "libutils",
-        "android.hardware.media.bufferpool2-V1-ndk",
+        "android.hardware.media.bufferpool2-V2-ndk",
     ],
     static_libs: [
         "libaidlcommonsupport",
@@ -59,8 +60,9 @@
         "libcutils",
         "libfmq",
         "liblog",
+        "libnativewindow",
         "libutils",
-        "android.hardware.media.bufferpool2-V1-ndk",
+        "android.hardware.media.bufferpool2-V2-ndk",
     ],
     static_libs: [
         "libaidlcommonsupport",
@@ -82,8 +84,9 @@
         "libcutils",
         "libfmq",
         "liblog",
+        "libnativewindow",
         "libutils",
-        "android.hardware.media.bufferpool2-V1-ndk",
+        "android.hardware.media.bufferpool2-V2-ndk",
     ],
     static_libs: [
         "libaidlcommonsupport",
diff --git a/media/c2/aidl/Android.bp b/media/c2/aidl/Android.bp
new file mode 100644
index 0000000..2eaeb01
--- /dev/null
+++ b/media/c2/aidl/Android.bp
@@ -0,0 +1,52 @@
+// This is the expected build file, but it may not be right in all cases
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+    name: "android.hardware.media.c2",
+    min_sdk_version: "30",
+    vendor_available: true,
+    double_loadable: true,
+    srcs: ["android/hardware/media/c2/*.aidl"],
+    headers: [
+        "HardwareBuffer_aidl",
+    ],
+    imports: [
+        "android.hardware.common-V2",
+        "android.hardware.media.bufferpool2-V2",
+    ],
+    include_dirs: [
+        "frameworks/native/aidl/gui",
+    ],
+    stability: "vintf",
+    backend: {
+        cpp: {
+            enabled: false,
+        },
+        java: {
+            enabled: false,
+        },
+        ndk: {
+            enabled: true,
+            apex_available: [
+                "//apex_available:platform",
+                "com.android.media.swcodec",
+                "test_com.android.media.swcodec",
+            ],
+            additional_shared_libraries: [
+                "libnativewindow",
+            ],
+        },
+        rust: {
+            // No users, and no rust implementation of android.os.Surface yet
+            enabled: false,
+        },
+    },
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/BaseBlock.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/BaseBlock.aidl
new file mode 100644
index 0000000..069b2cf
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/BaseBlock.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.media.c2;
+@VintfStability
+union BaseBlock {
+  android.hardware.common.NativeHandle nativeBlock;
+  android.hardware.HardwareBuffer hwbBlock;
+  android.hardware.media.bufferpool2.BufferStatusMessage pooledBlock;
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/Block.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/Block.aidl
new file mode 100644
index 0000000..7b3005e
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/Block.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.media.c2;
+@VintfStability
+parcelable Block {
+  int index;
+  android.hardware.media.c2.Params meta;
+  android.hardware.common.NativeHandle fence;
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/Buffer.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/Buffer.aidl
new file mode 100644
index 0000000..b632932
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/Buffer.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.media.c2;
+@VintfStability
+parcelable Buffer {
+  android.hardware.media.c2.Params info;
+  android.hardware.media.c2.Block[] blocks;
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/FieldDescriptor.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/FieldDescriptor.aidl
new file mode 100644
index 0000000..909476c
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/FieldDescriptor.aidl
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.media.c2;
+@VintfStability
+parcelable FieldDescriptor {
+  android.hardware.media.c2.FieldId fieldId;
+  android.hardware.media.c2.FieldDescriptor.Type type;
+  int structIndex;
+  int extent;
+  String name;
+  android.hardware.media.c2.FieldDescriptor.NamedValue[] namedValues;
+  @Backing(type="int") @VintfStability
+  enum Type {
+    NO_INIT = 0,
+    INT32,
+    UINT32,
+    CNTR32,
+    INT64,
+    UINT64,
+    CNTR64,
+    FLOAT,
+    STRING = 0x100,
+    BLOB,
+    STRUCT = 0x20000,
+  }
+  @VintfStability
+  parcelable NamedValue {
+    String name;
+    long value;
+  }
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/FieldId.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/FieldId.aidl
new file mode 100644
index 0000000..935b85d
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/FieldId.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.media.c2;
+@VintfStability
+parcelable FieldId {
+  int offset;
+  int sizeBytes;
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/FieldSupportedValues.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/FieldSupportedValues.aidl
new file mode 100644
index 0000000..69060be
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/FieldSupportedValues.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.media.c2;
+@VintfStability
+union FieldSupportedValues {
+  boolean empty;
+  android.hardware.media.c2.ValueRange range;
+  long[] values;
+  long[] flags;
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/FieldSupportedValuesQuery.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/FieldSupportedValuesQuery.aidl
new file mode 100644
index 0000000..6a5fbe2
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/FieldSupportedValuesQuery.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.media.c2;
+@VintfStability
+parcelable FieldSupportedValuesQuery {
+  android.hardware.media.c2.ParamField field;
+  android.hardware.media.c2.FieldSupportedValuesQuery.Type type;
+  @Backing(type="int") @VintfStability
+  enum Type {
+    POSSIBLE = 0,
+    CURRENT,
+  }
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/FieldSupportedValuesQueryResult.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/FieldSupportedValuesQueryResult.aidl
new file mode 100644
index 0000000..187e3eb
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/FieldSupportedValuesQueryResult.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.media.c2;
+@VintfStability
+parcelable FieldSupportedValuesQueryResult {
+  android.hardware.media.c2.Status status;
+  android.hardware.media.c2.FieldSupportedValues values;
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/FrameData.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/FrameData.aidl
new file mode 100644
index 0000000..07bfb72
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/FrameData.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.media.c2;
+@VintfStability
+parcelable FrameData {
+  int flags;
+  android.hardware.media.c2.WorkOrdinal ordinal;
+  android.hardware.media.c2.Buffer[] buffers;
+  android.hardware.media.c2.Params configUpdate;
+  android.hardware.media.c2.InfoBuffer[] infoBuffers;
+  const int DROP_FRAME = (1 << 0) /* 1 */;
+  const int END_OF_STREAM = (1 << 1) /* 2 */;
+  const int DISCARD_FRAME = (1 << 2) /* 4 */;
+  const int FLAG_INCOMPLETE = (1 << 3) /* 8 */;
+  const int CODEC_CONFIG = (1 << 31) /* -2147483648 */;
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IComponent.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IComponent.aidl
new file mode 100644
index 0000000..0a7e3c4
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IComponent.aidl
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.media.c2;
+@VintfStability
+interface IComponent {
+  android.hardware.common.NativeHandle configureVideoTunnel(in int avSyncHwId);
+  android.hardware.media.c2.IComponent.BlockPool createBlockPool(in android.hardware.media.c2.IComponent.BlockPoolAllocator allocator);
+  void destroyBlockPool(in long blockPoolId);
+  void drain(in boolean withEos);
+  android.hardware.media.c2.WorkBundle flush();
+  android.hardware.media.c2.IComponentInterface getInterface();
+  void queue(in android.hardware.media.c2.WorkBundle workBundle);
+  void release();
+  void reset();
+  void start();
+  void stop();
+  android.hardware.media.c2.IInputSurfaceConnection connectToInputSurface(in android.hardware.media.c2.IInputSurface inputSurface);
+  android.hardware.media.c2.IInputSink asInputSink();
+  parcelable BlockPool {
+    long blockPoolId;
+    android.hardware.media.c2.IConfigurable configurable;
+  }
+  parcelable GbAllocator {
+    ParcelFileDescriptor waitableFd;
+    android.hardware.media.c2.IGraphicBufferAllocator igba;
+  }
+  parcelable PooledGbAllocator {
+    ParcelFileDescriptor waitableFd;
+    long receiverId;
+    android.hardware.media.c2.IPooledGraphicBufferAllocator ipgba;
+  }
+  parcelable BlockPoolAllocator {
+    int allocatorId;
+    @nullable android.hardware.media.c2.IComponent.GbAllocator gbAllocator;
+    @nullable android.hardware.media.c2.IComponent.PooledGbAllocator pooledGbAllocator;
+  }
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IComponentInterface.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IComponentInterface.aidl
new file mode 100644
index 0000000..2350dae
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IComponentInterface.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.media.c2;
+@VintfStability
+interface IComponentInterface {
+  android.hardware.media.c2.IConfigurable getConfigurable();
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IComponentListener.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IComponentListener.aidl
new file mode 100644
index 0000000..f6f2a63
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IComponentListener.aidl
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.media.c2;
+@VintfStability
+interface IComponentListener {
+  oneway void onError(in android.hardware.media.c2.Status status, in int errorCode);
+  oneway void onFramesRendered(in android.hardware.media.c2.IComponentListener.RenderedFrame[] renderedFrames);
+  oneway void onInputBuffersReleased(in android.hardware.media.c2.IComponentListener.InputBuffer[] inputBuffers);
+  oneway void onTripped(in android.hardware.media.c2.SettingResult[] settingResults);
+  oneway void onWorkDone(in android.hardware.media.c2.WorkBundle workBundle);
+  @VintfStability
+  parcelable InputBuffer {
+    long frameIndex;
+    int arrayIndex;
+  }
+  @VintfStability
+  parcelable RenderedFrame {
+    long bufferQueueId;
+    int slotId;
+    long timestampNs;
+  }
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IComponentStore.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IComponentStore.aidl
new file mode 100644
index 0000000..d7a4706
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IComponentStore.aidl
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.media.c2;
+@VintfStability
+interface IComponentStore {
+  void copyBuffer(in android.hardware.media.c2.Buffer src, in android.hardware.media.c2.Buffer dst);
+  android.hardware.media.c2.IComponent createComponent(in String name, in android.hardware.media.c2.IComponentListener listener, in android.hardware.media.bufferpool2.IClientManager pool);
+  android.hardware.media.c2.IComponentInterface createInterface(in String name);
+  android.hardware.media.c2.IConfigurable getConfigurable();
+  android.hardware.media.bufferpool2.IClientManager getPoolClientManager();
+  android.hardware.media.c2.StructDescriptor[] getStructDescriptors(in int[] indices);
+  android.hardware.media.c2.IComponentStore.ComponentTraits[] listComponents();
+  android.hardware.media.c2.IInputSurface createInputSurface();
+  @VintfStability
+  parcelable ComponentTraits {
+    String name;
+    android.hardware.media.c2.IComponentStore.ComponentTraits.Domain domain;
+    android.hardware.media.c2.IComponentStore.ComponentTraits.Kind kind;
+    int rank;
+    String mediaType;
+    String[] aliases;
+    @Backing(type="int") @VintfStability
+    enum Kind {
+      OTHER = 0,
+      DECODER,
+      ENCODER,
+    }
+    @Backing(type="int") @VintfStability
+    enum Domain {
+      OTHER = 0,
+      VIDEO,
+      AUDIO,
+      IMAGE,
+    }
+  }
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IConfigurable.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IConfigurable.aidl
new file mode 100644
index 0000000..04e776e
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IConfigurable.aidl
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.media.c2;
+@VintfStability
+interface IConfigurable {
+  android.hardware.media.c2.IConfigurable.ConfigResult config(in android.hardware.media.c2.Params inParams, in boolean mayBlock);
+  int getId();
+  String getName();
+  android.hardware.media.c2.IConfigurable.QueryResult query(in int[] indices, in boolean mayBlock);
+  android.hardware.media.c2.ParamDescriptor[] querySupportedParams(in int start, in int count);
+  android.hardware.media.c2.IConfigurable.QuerySupportedValuesResult querySupportedValues(in android.hardware.media.c2.FieldSupportedValuesQuery[] inFields, in boolean mayBlock);
+  @VintfStability
+  parcelable ConfigResult {
+    android.hardware.media.c2.Params params;
+    android.hardware.media.c2.SettingResult[] failures;
+    android.hardware.media.c2.Status status;
+  }
+  @VintfStability
+  parcelable QueryResult {
+    android.hardware.media.c2.Params params;
+    android.hardware.media.c2.Status status;
+  }
+  @VintfStability
+  parcelable QuerySupportedValuesResult {
+    android.hardware.media.c2.FieldSupportedValuesQueryResult[] values;
+    android.hardware.media.c2.Status status;
+  }
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IGraphicBufferAllocator.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IGraphicBufferAllocator.aidl
new file mode 100644
index 0000000..e13ba1f
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IGraphicBufferAllocator.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.media.c2;
+@VintfStability
+interface IGraphicBufferAllocator {
+  android.hardware.media.c2.IGraphicBufferAllocator.Allocation allocate(in android.hardware.media.c2.IGraphicBufferAllocator.Description desc);
+  boolean deallocate(in long id);
+  ParcelFileDescriptor getWaitableFd();
+  parcelable Allocation {
+    android.hardware.HardwareBuffer buffer;
+    @nullable ParcelFileDescriptor fence;
+  }
+  parcelable Description {
+    int width;
+    int height;
+    int format;
+    long usage;
+  }
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IInputSink.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IInputSink.aidl
new file mode 100644
index 0000000..e6ea4d5
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IInputSink.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.media.c2;
+@VintfStability
+interface IInputSink {
+  void queue(in android.hardware.media.c2.WorkBundle workBundle);
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IInputSurface.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IInputSurface.aidl
new file mode 100644
index 0000000..14455cb
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IInputSurface.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.media.c2;
+@VintfStability
+interface IInputSurface {
+  android.view.Surface getSurface();
+  android.hardware.media.c2.IConfigurable getConfigurable();
+  android.hardware.media.c2.IInputSurfaceConnection connect(in android.hardware.media.c2.IInputSink sink);
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IInputSurfaceConnection.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IInputSurfaceConnection.aidl
new file mode 100644
index 0000000..28fff65
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IInputSurfaceConnection.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.media.c2;
+@VintfStability
+interface IInputSurfaceConnection {
+  void disconnect();
+  void signalEndOfStream();
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IPooledGraphicBufferAllocator.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IPooledGraphicBufferAllocator.aidl
new file mode 100644
index 0000000..1a8c66d
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IPooledGraphicBufferAllocator.aidl
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.media.c2;
+@VintfStability
+interface IPooledGraphicBufferAllocator {
+  android.hardware.media.c2.IPooledGraphicBufferAllocator.Allocation allocate(in android.hardware.media.c2.IPooledGraphicBufferAllocator.Description desc);
+  boolean deallocate(in int id);
+  parcelable Allocation {
+    int bufferId;
+    @nullable ParcelFileDescriptor fence;
+  }
+  parcelable Description {
+    int widthPixels;
+    int heightPixels;
+    int format;
+    long usage;
+  }
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/InfoBuffer.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/InfoBuffer.aidl
new file mode 100644
index 0000000..94cd77d
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/InfoBuffer.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.media.c2;
+@VintfStability
+parcelable InfoBuffer {
+  int index;
+  android.hardware.media.c2.Buffer buffer;
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/ParamDescriptor.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/ParamDescriptor.aidl
new file mode 100644
index 0000000..6f0ac50
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/ParamDescriptor.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.media.c2;
+@VintfStability
+parcelable ParamDescriptor {
+  int index;
+  int attrib;
+  String name;
+  int[] dependencies;
+  const int ATTRIBUTE_REQUIRED = (1 << 0) /* 1 */;
+  const int ATTRIBUTE_PERSISTENT = (1 << 1) /* 2 */;
+  const int ATTRIBUTE_STRICT = (1 << 2) /* 4 */;
+  const int ATTRIBUTE_READ_ONLY = (1 << 3) /* 8 */;
+  const int ATTRIBUTE_HIDDEN = (1 << 4) /* 16 */;
+  const int ATTRIBUTE_INTERNAL = (1 << 5) /* 32 */;
+  const int ATTRIBUTE_CONST = (1 << 6) /* 64 */;
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/ParamField.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/ParamField.aidl
new file mode 100644
index 0000000..13d2522
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/ParamField.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.media.c2;
+@VintfStability
+parcelable ParamField {
+  int index;
+  android.hardware.media.c2.FieldId fieldId;
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/ParamFieldValues.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/ParamFieldValues.aidl
new file mode 100644
index 0000000..5a2821c
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/ParamFieldValues.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.media.c2;
+@VintfStability
+parcelable ParamFieldValues {
+  android.hardware.media.c2.ParamField paramOrField;
+  android.hardware.media.c2.FieldSupportedValues[] values;
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/Params.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/Params.aidl
new file mode 100644
index 0000000..7d363c0
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/Params.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.media.c2;
+@VintfStability
+parcelable Params {
+  byte[] params;
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/SettingResult.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/SettingResult.aidl
new file mode 100644
index 0000000..07fc1f3
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/SettingResult.aidl
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.media.c2;
+@VintfStability
+parcelable SettingResult {
+  android.hardware.media.c2.SettingResult.Failure failure;
+  android.hardware.media.c2.ParamFieldValues field;
+  android.hardware.media.c2.ParamFieldValues[] conflicts;
+  @Backing(type="int") @VintfStability
+  enum Failure {
+    BAD_TYPE,
+    BAD_PORT,
+    BAD_INDEX,
+    READ_ONLY,
+    MISMATCH,
+    BAD_VALUE,
+    CONFLICT,
+    UNSUPPORTED,
+    INFO_BAD_VALUE,
+    INFO_CONFLICT,
+  }
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/Status.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/Status.aidl
new file mode 100644
index 0000000..8b430d2
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/Status.aidl
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.media.c2;
+@VintfStability
+parcelable Status {
+  int status;
+  const int OK = 0;
+  const int BAD_VALUE = (-22) /* -22 */;
+  const int BAD_INDEX = (-75) /* -75 */;
+  const int CANNOT_DO = (-2147483646) /* -2147483646 */;
+  const int DUPLICATE = (-17) /* -17 */;
+  const int NOT_FOUND = (-2) /* -2 */;
+  const int BAD_STATE = (-38) /* -38 */;
+  const int BLOCKING = (-9930) /* -9930 */;
+  const int NO_MEMORY = (-12) /* -12 */;
+  const int REFUSED = (-1) /* -1 */;
+  const int TIMED_OUT = (-110) /* -110 */;
+  const int OMITTED = (-74) /* -74 */;
+  const int CORRUPTED = (-2147483648) /* -2147483648 */;
+  const int NO_INIT = (-19) /* -19 */;
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/StructDescriptor.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/StructDescriptor.aidl
new file mode 100644
index 0000000..58268e0
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/StructDescriptor.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.media.c2;
+@VintfStability
+parcelable StructDescriptor {
+  int type;
+  android.hardware.media.c2.FieldDescriptor[] fields;
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/ValueRange.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/ValueRange.aidl
new file mode 100644
index 0000000..db71ce0
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/ValueRange.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.media.c2;
+@VintfStability
+parcelable ValueRange {
+  long min;
+  long max;
+  long step;
+  long num;
+  long denom;
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/Work.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/Work.aidl
new file mode 100644
index 0000000..a534348
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/Work.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.media.c2;
+@VintfStability
+parcelable Work {
+  byte[] chainInfo;
+  android.hardware.media.c2.FrameData input;
+  android.hardware.media.c2.Worklet[] worklets;
+  int workletsProcessed;
+  android.hardware.media.c2.Status result;
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/WorkBundle.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/WorkBundle.aidl
new file mode 100644
index 0000000..84708a8
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/WorkBundle.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.media.c2;
+@VintfStability
+parcelable WorkBundle {
+  android.hardware.media.c2.Work[] works;
+  android.hardware.media.c2.BaseBlock[] baseBlocks;
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/WorkOrdinal.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/WorkOrdinal.aidl
new file mode 100644
index 0000000..2833df3
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/WorkOrdinal.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.media.c2;
+@VintfStability
+parcelable WorkOrdinal {
+  long timestampUs;
+  long frameIndex;
+  long customOrdinal;
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/Worklet.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/Worklet.aidl
new file mode 100644
index 0000000..a79abf2
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/Worklet.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.media.c2;
+@VintfStability
+parcelable Worklet {
+  int componentId;
+  byte[] tunings;
+  android.hardware.media.c2.SettingResult[] failures;
+  android.hardware.media.c2.FrameData output;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/BaseBlock.aidl b/media/c2/aidl/android/hardware/media/c2/BaseBlock.aidl
new file mode 100644
index 0000000..7cc041c
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/BaseBlock.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2;
+
+import android.hardware.HardwareBuffer;
+import android.hardware.common.NativeHandle;
+
+/**
+ * Storage type for `BaseBlock`.
+ *
+ * A `BaseBlock` is a representation of a codec memory block. Coded data,
+ * decoded data, codec-specific data, and other codec-related data are all sent
+ * in the form of BaseBlocks.
+ */
+@VintfStability
+union BaseBlock {
+    /**
+     * #nativeBlock is the opaque representation of a buffer.
+     */
+    NativeHandle nativeBlock;
+    /**
+     * #hwbBlock is the opaque representation of a GraphicBuffer
+     */
+    HardwareBuffer hwbBlock;
+    /**
+     * #pooledBlock is a reference to a buffer handled by a BufferPool.
+     */
+    android.hardware.media.bufferpool2.BufferStatusMessage pooledBlock;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/Block.aidl b/media/c2/aidl/android/hardware/media/c2/Block.aidl
new file mode 100644
index 0000000..34aa7b1
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/Block.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2;
+
+import android.hardware.common.NativeHandle;
+import android.hardware.media.c2.Params;
+
+/**
+ * Reference to a @ref BaseBlock within a @ref WorkBundle.
+ *
+ * `Block` contains additional attributes that `BaseBlock` does not. These
+ * attributes may differ among `Block` objects that refer to the same
+ * `BaseBlock` in the same `WorkBundle`.
+ */
+@VintfStability
+parcelable Block {
+    /**
+     * Identity of a `BaseBlock` within a `WorkBundle`. This is an index into
+     * #WorkBundle.baseBlocks.
+     */
+    int index;
+    /**
+     * Metadata associated with this `Block`.
+     */
+    Params meta;
+    /**
+     * Fence for synchronizing `Block` access.
+     */
+    NativeHandle fence;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/Buffer.aidl b/media/c2/aidl/android/hardware/media/c2/Buffer.aidl
new file mode 100644
index 0000000..d2dcf2d
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/Buffer.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2;
+
+import android.hardware.media.c2.Block;
+import android.hardware.media.c2.Params;
+
+/**
+ * A codec buffer, which is a collection of @ref Block objects and metadata.
+ *
+ * This is a part of @ref FrameData.
+ */
+@VintfStability
+parcelable Buffer {
+    /**
+     * Metadata associated with the buffer.
+     */
+    Params info;
+    /**
+     * Blocks contained in the buffer.
+     */
+    Block[] blocks;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/FieldDescriptor.aidl b/media/c2/aidl/android/hardware/media/c2/FieldDescriptor.aidl
new file mode 100644
index 0000000..a2774ec
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/FieldDescriptor.aidl
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2;
+
+import android.hardware.media.c2.FieldId;
+
+/**
+ * Description of a field inside a C2Param structure.
+ */
+@VintfStability
+parcelable FieldDescriptor {
+    /**
+     * Possible types of the field.
+     */
+    @VintfStability
+    @Backing(type="int")
+    enum Type {
+        NO_INIT = 0,
+        INT32,
+        UINT32,
+        CNTR32,
+        INT64,
+        UINT64,
+        CNTR64,
+        FLOAT,
+        /**
+         * Fixed-size string (POD).
+         */
+        STRING = 0x100,
+        /**
+         * A blob has no sub-elements and can be thought of as an array of
+         * bytes. However, bytes cannot be individually addressed by clients.
+         */
+        BLOB,
+        /**
+         * The field is a structure that may contain other fields.
+         */
+        STRUCT = 0x20000,
+    }
+    /**
+     * Named value type. This is used for defining an enum value for a numeric
+     * type.
+     */
+    @VintfStability
+    parcelable NamedValue {
+        /**
+         * Name of the enum value. This must be unique for each enum value in
+         * the same field.
+         */
+        String name;
+        /**
+         * Underlying value of the enum value. Multiple enum names may have the
+         * same underlying value.
+         */
+        long value;
+    }
+    /**
+     * Location of the field in the C2Param structure
+     */
+    FieldId fieldId;
+    /**
+     * Type of the field.
+     */
+    Type type;
+    /**
+     * If #type is #Type.STRUCT, #structIndex is the C2Param structure index;
+     * otherwise, #structIndex is not used.
+     */
+    int structIndex;
+    /**
+     * Extent of the field.
+     * - For a non-array field, #extent is 1.
+     * - For a fixed-length array field, #extent is the length. An array field
+     *   of length 1 is indistinguishable from a non-array field.
+     * - For a variable-length array field, #extent is 0. This can only occur as
+     *   the last member of a C2Param structure.
+     */
+    int extent;
+    /**
+     * Name of the field. This must be unique for each field in the same
+     * structure.
+     */
+    String name;
+    /**
+     * List of enum values. This is not used when #type is not one of the
+     * numeric types.
+     */
+    NamedValue[] namedValues;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/FieldId.aidl b/media/c2/aidl/android/hardware/media/c2/FieldId.aidl
new file mode 100644
index 0000000..68bf058
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/FieldId.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2;
+
+/**
+ * Identifying information of a field relative to a known C2Param structure.
+ *
+ * Within a given C2Param structure, each field is uniquely identified by @ref
+ * FieldId.
+ */
+@VintfStability
+parcelable FieldId {
+    /**
+     * Offset of the field in bytes.
+     */
+    int offset;
+    /**
+     * Size of the field in bytes.
+     */
+    int sizeBytes;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/FieldSupportedValues.aidl b/media/c2/aidl/android/hardware/media/c2/FieldSupportedValues.aidl
new file mode 100644
index 0000000..6c2033b
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/FieldSupportedValues.aidl
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2;
+
+import android.hardware.media.c2.ValueRange;
+
+/*
+ * Description of supported values for a field of C2Param.
+ *
+ * This can be a continuous range or a discrete set of values.
+ *
+ * The intended type of values must be made clear in the context where
+ * `FieldSupportedValues` is used.
+ */
+@VintfStability
+union FieldSupportedValues {
+    /**
+     * No supported values
+     */
+    boolean empty;
+    /**
+     * Numeric range, described in a #ValueRange structure
+     */
+    ValueRange range;
+    /**
+     * List of values
+     */
+    long[] values;
+    /**
+     * List of flags that can be OR-ed.
+     *
+     * The list contains { min-mask, flag1, flag2... }. Basically, the first
+     * value is the required set of flags to be set, and the rest of the values are flags that can
+     * be set independently. FLAGS is only supported for integral types. Supported flags should
+     * not overlap, as it can make validation non-deterministic. The standard validation method
+     * is that starting from the original value, if each flag is removed when fully present (the
+     * min-mask must be fully present), we shall arrive at 0.
+     */
+    long[] flags;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/FieldSupportedValuesQuery.aidl b/media/c2/aidl/android/hardware/media/c2/FieldSupportedValuesQuery.aidl
new file mode 100644
index 0000000..bdaaef6
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/FieldSupportedValuesQuery.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2;
+
+import android.hardware.media.c2.ParamField;
+
+/**
+ * Query information for supported values of a field. This is used as input to
+ * IConfigurable::querySupportedValues().
+ */
+@VintfStability
+parcelable FieldSupportedValuesQuery {
+    @VintfStability
+    @Backing(type="int")
+    enum Type {
+        /**
+         * Query all possible values regardless of other settings.
+         */
+        POSSIBLE = 0,
+        /**
+         * Query currently possible values given dependent settings.
+         */
+        CURRENT,
+    }
+    /**
+     * Identity of the field to query.
+     */
+    ParamField field;
+    /**
+     * Type of the query. See #Type for more information.
+     */
+    Type type;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/FieldSupportedValuesQueryResult.aidl b/media/c2/aidl/android/hardware/media/c2/FieldSupportedValuesQueryResult.aidl
new file mode 100644
index 0000000..b5c28c6
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/FieldSupportedValuesQueryResult.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2;
+
+import android.hardware.media.c2.FieldSupportedValues;
+import android.hardware.media.c2.Status;
+
+/**
+ * This structure is used to hold the result from
+ * IConfigurable::querySupportedValues().
+ */
+@VintfStability
+parcelable FieldSupportedValuesQueryResult {
+    /**
+     * Result of the query. Possible values are
+     * - `Status::OK`: The query was successful.
+     * - `Status::BAD_STATE`: The query was requested when the `IConfigurable` instance
+     *   was in a bad state.
+     * - `Status::BAD_INDEX`: The requested field was not recognized.
+     * - `Status::TIMED_OUT`: The query could not be completed in a timely manner.
+     * - `Status::BLOCKING`: The query must block, but the parameter `mayBlock` in the
+     *   call to `querySupportedValues()` was `false`.
+     * - `Status::CORRUPTED`: Some unknown error occurred.
+     */
+    Status status;
+    /**
+     * Supported values. This is meaningful only when #status is `OK`.
+     */
+    FieldSupportedValues values;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/FrameData.aidl b/media/c2/aidl/android/hardware/media/c2/FrameData.aidl
new file mode 100644
index 0000000..15c1b6d
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/FrameData.aidl
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2;
+
+import android.hardware.media.c2.Buffer;
+import android.hardware.media.c2.InfoBuffer;
+import android.hardware.media.c2.Params;
+import android.hardware.media.c2.WorkOrdinal;
+
+/**
+ * Data for an input frame or an output frame.
+ *
+ * This structure represents a @e frame with its metadata. A @e frame consists
+ * of an ordered set of buffers, configuration changes, and info buffers along
+ * with some non-configuration metadata.
+ *
+ * @note `FrameData` is the HIDL counterpart of `C2FrameData` in the Codec 2.0
+ * standard.
+ */
+@VintfStability
+parcelable FrameData {
+    /** List of frame flags */
+    /**
+     * For input frames: no output frame shall be generated when processing
+     * this frame, but metadata must still be processed.
+     *
+     * For output frames: this frame must be discarded but metadata is still
+     * valid.
+     */
+    const int DROP_FRAME = (1 << 0);
+    /**
+     * This frame is the last frame of the current stream. Further frames
+     * are part of a new stream.
+     */
+    const int END_OF_STREAM = (1 << 1);
+    /**
+     * This frame must be discarded with its metadata.
+     *
+     * This flag is only set by components, e.g. as a response to the flush
+     * command.
+     */
+    const int DISCARD_FRAME = (1 << 2);
+    /**
+     * This frame is not the last frame produced for the input.
+     *
+     * This flag is normally set by the component - e.g. when an input frame
+     * results in multiple output frames, this flag is set on all but the
+     * last output frame.
+     *
+     * Also, when components are chained, this flag should be propagated
+     * down the work chain. That is, if set on an earlier frame of a
+     * work-chain, it should be propagated to all later frames in that
+     * chain. Additionally, components down the chain could set this flag
+     * even if not set earlier, e.g. if multiple output frames are generated
+     * at that component for the input frame.
+     */
+    const int FLAG_INCOMPLETE = (1 << 3);
+    /**
+     * This frame contains only codec-specific configuration data, and no
+     * actual access unit.
+     */
+    const int CODEC_CONFIG = (1 << 31);
+    /**
+     * Frame flags, as described above.
+     */
+    int flags;
+    /**
+     * @ref WorkOrdinal of the frame.
+     */
+    WorkOrdinal ordinal;
+    /**
+     * List of frame buffers.
+     */
+    Buffer[] buffers;
+    /**
+     * List of configuration updates.
+     */
+    Params configUpdate;
+    /**
+     * List of info buffers.
+     */
+    InfoBuffer[] infoBuffers;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/IComponent.aidl b/media/c2/aidl/android/hardware/media/c2/IComponent.aidl
new file mode 100644
index 0000000..387d70a
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/IComponent.aidl
@@ -0,0 +1,359 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2;
+
+import android.hardware.common.NativeHandle;
+
+import android.hardware.media.c2.IComponentInterface;
+import android.hardware.media.c2.IConfigurable;
+import android.hardware.media.c2.IGraphicBufferAllocator;
+import android.hardware.media.c2.IInputSink;
+import android.hardware.media.c2.IInputSurface;
+import android.hardware.media.c2.IInputSurfaceConnection;
+import android.hardware.media.c2.IPooledGraphicBufferAllocator;
+import android.hardware.media.c2.WorkBundle;
+import android.os.ParcelFileDescriptor;
+
+
+/**
+ * Interface for an AIDL Codec2 component.
+ * Components have two states: stopped and running. The running state has three
+ * sub-states: executing, tripped and error.
+ *
+ * All methods in `IComponent` must not block. If a method call cannot be
+ * completed in a timely manner, it must throw `Status::TIMED_OUT`.
+ */
+@VintfStability
+interface IComponent {
+    /**
+     * The reference object from framwork to HAL C2BlockPool.
+     *
+     * The object will be returned when C2BlockPool is created by a framework
+     * request. The object also can be destroyed using blockPoolId.
+     * Using configurable framework can query/config the object in HAL(IComponent).
+     */
+    parcelable BlockPool {
+        long blockPoolId;
+        IConfigurable configurable;
+    }
+
+    /**
+     * C2AIDL allocator interface along with a waitable fd.
+     *
+     * The interface is used from a specific type of C2BlockPool to allocate
+     * graphic blocks. the waitable fd is used to create a specific type of
+     * C2Fence which can be used for waiting until to allocate is not blocked.
+     */
+    parcelable GbAllocator {
+        ParcelFileDescriptor waitableFd;
+        IGraphicBufferAllocator igba;
+    }
+
+    /**
+     * C2AIDL allocator interface based on media.bufferpool2 along with a waitable fd.
+     *
+     * The interface is used from a specific type of C2BlockPool to allocate
+     * graphic blocks. the waitable fd is used to create a specific type of
+     * C2Fence which can be used for waiting until to allocate is not blocked.
+     * receiverId is id of receiver IConnection of media.bufferpool2.
+     */
+    parcelable PooledGbAllocator {
+        ParcelFileDescriptor waitableFd;
+        long receiverId;
+        IPooledGraphicBufferAllocator ipgba;
+    }
+
+
+    /**
+     * Allocator for C2BlockPool.
+     *
+     * C2BlockPool will use a C2Allocator which is specified by an id.
+     * Based on allocator id, allocator is specified.
+     */
+    parcelable BlockPoolAllocator {
+        int allocatorId;
+        @nullable GbAllocator gbAllocator;
+        @nullable PooledGbAllocator pooledGbAllocator;
+    }
+
+    /**
+     * Configures a component for a tunneled playback mode.
+     *
+     * A successful call to this method puts the component in the *tunneled*
+     * mode. In this mode, the output `Worklet`s returned in
+     * IComponentListener::onWorkDone() may not contain any buffers. The output
+     * buffers are passed directly to the consumer end of a buffer queue whose
+     * producer side is configured with the returned @p sidebandStream passed
+     * to IGraphicBufferProducer::setSidebandStream().
+     *
+     * The component is initially in the non-tunneled mode by default. The
+     * tunneled mode can be toggled on only before the component starts
+     * processing. Once the component is put into the tunneled mode, it shall
+     * stay in the tunneled mode until and only until reset() is called.
+     *
+     * @param avSyncHwId A resource ID for hardware sync. The generator of sync
+     *     IDs must ensure that this number is unique among all services at any
+     *     given time. For example, if both the audio HAL and the tuner HAL
+     *     support this feature, sync IDs from the audio HAL must not clash
+     *     with sync IDs from the tuner HAL.
+     * @return Codec-allocated sideband stream NativeHandle. This can
+     *     be passed to IGraphicBufferProducer::setSidebandStream() to
+     *     establish a direct channel to the consumer.
+     * @throws ServiceSpecificException with one of the following values:
+     *   - `Status::OMITTED`   - The component does not support video tunneling.
+     *   - `Status::BAD_STATE` - The component is already running.
+     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `Status::CORRUPTED` - Some unknown error occurred.
+     */
+    NativeHandle configureVideoTunnel(in int avSyncHwId);
+
+    /**
+     * Creates a local `C2BlockPool` backed by the given allocator and returns
+     * its id.
+     *
+     * The returned @p blockPoolId is the only way the client can refer to a
+     * `C2BlockPool` object in the component. The id can be passed to
+     * setOutputSurface() or used in some C2Param objects later.
+     *
+     * The created `C2BlockPool` object can be destroyed by calling
+     * destroyBlockPool(), reset() or release(). reset() and release() must
+     * destroy all `C2BlockPool` objects that have been created.
+     *
+     * @param allocator AIDL allocator interface or C2Allocator specifier
+     *     for C2BlockPool
+     * @param out configurable Configuration interface for the created pool. This
+     *     must not be null.
+     * @return Created block pool information. This could be used to config/query and
+     * also be used in setOutputSurface() if the allocator
+     * @throws ServiceSpecificException with one of the following values:
+     *   - `Status::NO_MEMORY` - Not enough memory to create the pool.
+     *   - `Status::BAD_VALUE` - @p allocatorId is not recognized.
+     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `Status::CORRUPTED` - Some unknown error occurred.
+     */
+    BlockPool createBlockPool(in BlockPoolAllocator allocator);
+
+    /**
+     * Destroys a local block pool previously created by createBlockPool().
+     *
+     * @param blockPoolId Id of a `C2BlockPool` that was previously returned by
+     *      createBlockPool().
+     * @throws ServiceSpecificException with one of the following values:
+     *   - `Status::NOT_FOUND` - The supplied blockPoolId is not valid.
+     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `Status::CORRUPTED` - Some unknown error occurred.
+     */
+    void destroyBlockPool(in long blockPoolId);
+
+    /**
+     * Drains the component, and optionally downstream components. This is a
+     * signalling method; as such it does not wait for any work completion.
+     *
+     * The last `Work` item is marked as "drain-till-here", so the component is
+     * notified not to wait for further `Work` before it processes what is
+     * already queued. This method can also be used to set the end-of-stream
+     * flag after `Work` has been queued. Client can continue to queue further
+     * `Work` immediately after this method returns.
+     *
+     * This method must be supported in running (including tripped) states.
+     *
+     * `Work` that is completed must be returned via
+     * IComponentListener::onWorkDone().
+     *
+     * @param withEos Whether to drain the component with marking end-of-stream.
+     * @throws ServiceSpecificException with one of the following values:
+     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `Status::CORRUPTED` - Some unknown error occurred.
+     */
+    void drain(in boolean withEos);
+
+    /**
+     * Discards and abandons any pending `Work` items for the component.
+     *
+     * This method must be supported in running (including tripped) states.
+     *
+     * `Work` that could be immediately abandoned/discarded must be returned in
+     * @p flushedWorkBundle. The order in which queued `Work` items are
+     * discarded can be arbitrary.
+     *
+     * `Work` that could not be abandoned or discarded immediately must be
+     * marked to be discarded at the earliest opportunity, and must be returned
+     * via IComponentListener::onWorkDone(). This must be completed within
+     * 500ms.
+     *
+     * @return `WorkBundle` object containing flushed `Work` items.
+     * @throws ServiceSpecificException with one of the following values:
+     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `Status::CORRUPTED` - Some unknown error occurred.
+     */
+    WorkBundle flush();
+
+    /**
+     * Returns the @ref IComponentInterface instance associated to this
+     * component.
+     *
+     * An @ref IConfigurable instance for the component can be obtained by calling
+     * IComponentInterface::getConfigurable() on the returned @p intf.
+     *
+     * @return `IComponentInterface` instance. This must not be null.
+     */
+    IComponentInterface getInterface();
+
+    /**
+     * Queues up work for the component.
+     *
+     * This method must be supported in running (including tripped) states.
+     *
+     * It is acceptable for this method to return `OK` and return an error value
+     * using the IComponentListener::onWorkDone() callback.
+     *
+     * @param workBundle `WorkBundle` object containing a list of `Work` objects
+     *     to queue to the component.
+     * @throws ServiceSpecificException with one of the following values:
+     *   - `Status::BAD_INDEX` - Some component id in some `Worklet` is not valid.
+     *   - `Status::CANNOT_DO` - The components are not tunneled but some `Work` object
+     *                   contains tunneling information.
+     *   - `Status::NO_MEMORY` - Not enough memory to queue @p workBundle.
+     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `Status::CORRUPTED` - Some unknown error occurred.
+     */
+    void queue(in WorkBundle workBundle);
+
+    /**
+     * Releases the component.
+     *
+     * This method must be supported in stopped state.
+     *
+     * This method destroys the component. Upon return, if @p status is `OK` or
+     * `DUPLICATE`, all resources must have been released.
+     *
+     * @throws ServiceSpecificException with one of the following values:
+     *   - `Status::BAD_STATE` - The component is running.
+     *   - `Status::DUPLICATE` - The component is already released.
+     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `Status::CORRUPTED` - Some unknown error occurred.
+     */
+    void release();
+
+    /**
+     * Resets the component.
+     *
+     * This method must be supported in all (including tripped) states other
+     * than released.
+     *
+     * This method must be supported during any other blocking call.
+     *
+     * This method must return within 500ms.
+     *
+     * When this call returns, if @p status is `OK`, all `Work` items must
+     * have been abandoned, and all resources (including `C2BlockPool` objects
+     * previously created by createBlockPool()) must have been released.
+     *
+     * If the return value is `BAD_STATE` or `DUPLICATE`, no state change is
+     * expected as a response to this call. For all other return values, the
+     * component must be in the stopped state.
+     *
+     * This brings settings back to their default, "guaranteeing" no tripped
+     * state.
+     *
+     * @throws ServiceSpecificException with one of the following values:
+     *   - `Status::BAD_STATE` - Component is in released state.
+     *   - `Status::DUPLICATE` - When called during another reset call from another
+     *                   thread.
+     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `Status::CORRUPTED` - Some unknown error occurred.
+     */
+    void reset();
+
+    /**
+     * Starts the component.
+     *
+     * This method must be supported in stopped state as well as tripped state.
+     *
+     * If the return value is `OK`, the component must be in the running state.
+     * If the return value is `BAD_STATE` or `DUPLICATE`, no state change is
+     * expected as a response to this call. Otherwise, the component must be in
+     * the stopped state.
+     *
+     * If a component is in the tripped state and start() is called while the
+     * component configuration still results in a trip, start() must succeed and
+     * a new onTripped() callback must be used to communicate the configuration
+     * conflict that results in the new trip.
+     *
+     * @throws ServiceSpecificException with one of the following values:
+     *   - `Status::BAD_STATE` - Component is not in stopped or tripped state.
+     *   - `Status::DUPLICATE` - When called during another start call from another
+     *                   thread.
+     *   - `Status::NO_MEMORY` - Not enough memory to start the component.
+     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `Status::CORRUPTED` - Some unknown error occurred.
+     */
+    void start();
+
+    /**
+     * Stops the component.
+     *
+     * This method must be supported in running (including tripped) state.
+     *
+     * This method must return within 500ms.
+     *
+     * Upon this call, all pending `Work` must be abandoned.
+     *
+     * If the return value is `BAD_STATE` or `DUPLICATE`, no state change is
+     * expected as a response to this call. For all other return values, the
+     * component must be in the stopped state.
+     *
+     * This does not alter any settings and tunings that may have resulted in a
+     * tripped state.
+     *
+     * @throws ServiceSpecificException with one of the following values:
+     *   - `Status::BAD_STATE` - Component is not in running state.
+     *   - `Status::DUPLICATE` - When called during another stop call from another
+     *                   thread.
+     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `Status::CORRUPTED` - Some unknown error occurred.
+     */
+    void stop();
+
+    /**
+     * Starts using an input surface.
+     *
+     * The component must be in running state.
+     *
+     * @param inputSurface Input surface to connect to.
+     * @return connection `IInputSurfaceConnection` object, which can be used to
+     *     query and configure properties of the connection. This cannot be
+     *     null.
+     * @throws ServiceSpecificException with one of the following values:
+     *   - `Status::CANNOT_DO` - The component does not support an input surface.
+     *   - `Status::BAD_STATE` - The component is not in running state.
+     *   - `Status::DUPLICATE` - The component is already connected to an input surface.
+     *   - `Status::REFUSED`   - The input surface is already in use.
+     *   - `Status::NO_MEMORY` - Not enough memory to start the component.
+     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `Status::CORRUPTED` - Some unknown error occurred.
+     */
+    IInputSurfaceConnection connectToInputSurface(in IInputSurface inputSurface);
+
+    /**
+     * Returns an @ref IInputSink instance that has the component as the
+     * underlying implementation.
+     *
+     * @return sink `IInputSink` instance.
+     */
+    IInputSink asInputSink();
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/IComponentInterface.aidl b/media/c2/aidl/android/hardware/media/c2/IComponentInterface.aidl
new file mode 100644
index 0000000..9db81e6
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/IComponentInterface.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2;
+
+import android.hardware.media.c2.IConfigurable;
+
+/**
+ * Component interface object. This object contains all of the configurations of
+ * a potential or actual component. It can be created and used independently of
+ * an actual Codec2 component to query supported parameters for various
+ * component settings, and configurations for a potential component.
+ *
+ * An actual component exposes this interface via IComponent::getInterface().
+ */
+@VintfStability
+interface IComponentInterface {
+    /**
+     * Returns the @ref IConfigurable instance associated to this component
+     * interface.
+     *
+     * @return `IConfigurable` instance. This must not be null.
+     */
+    IConfigurable getConfigurable();
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/IComponentListener.aidl b/media/c2/aidl/android/hardware/media/c2/IComponentListener.aidl
new file mode 100644
index 0000000..75500b7
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/IComponentListener.aidl
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2;
+
+import android.hardware.media.c2.SettingResult;
+import android.hardware.media.c2.Status;
+import android.hardware.media.c2.WorkBundle;
+
+/**
+ * Callback interface for handling notifications from @ref IComponent.
+ */
+@VintfStability
+oneway interface IComponentListener {
+    /**
+     * Identifying information for an input buffer previously queued to the
+     * component via IComponent::queue().
+     */
+    @VintfStability
+    parcelable InputBuffer {
+        /**
+         * This value comes from `Work::input.ordinal.frameIndex` in a `Work`
+         * object that was previously queued.
+         */
+        long frameIndex;
+        /**
+         * This value is an index into `Work::input.buffers` (which is an array)
+         * in a `Work` object that was previously queued.
+         */
+        int arrayIndex;
+    }
+    /**
+     * Information about rendering of a frame to a `Surface`.
+     */
+    @VintfStability
+    parcelable RenderedFrame {
+        /**
+         * Id of the `BufferQueue` containing the rendered buffer.
+         *
+         * This value must have been obtained by an earlier call to
+         * IGraphicBufferProducer::getUniqueId().
+         */
+        long bufferQueueId;
+        /**
+         * Id of the slot of the rendered buffer.
+         *
+         * This value must have been obtained by an earlier call to
+         * IGraphicBufferProducer::dequeueBuffer() or
+         * IGraphicBufferProducer::attachBuffer().
+         */
+        int slotId;
+        /**
+         * Timestamp the rendering happened.
+         *
+         * The reference point for the timestamp is determined by the
+         * `BufferQueue` that performed the rendering.
+         */
+        long timestampNs;
+    }
+    /**
+     * Notify the listener of an error.
+     *
+     * @param status Error type. @p status may be `OK`, which means that an
+     *     error has occurred, but the error type does not fit into the type
+     *     `Status`. In this case, additional information is provided by
+     *     @p errorCode.
+     * @param errorCode Additional error information. The framework may not
+     *     recognize the meaning of this value.
+     */
+    void onError(in Status status, in int errorCode);
+
+    /**
+     * Notify the listener that frames have been rendered.
+     *
+     * @param renderedFrames List of @ref RenderedFrame objects.
+     */
+    void onFramesRendered(in RenderedFrame[] renderedFrames);
+
+    /**
+     * Notify the listener that some input buffers are no longer needed by the
+     * component, and hence can be released or reused by the client.
+     *
+     * Input buffers that are contained in a `Work` object returned by an
+     * earlier onWorkDone() call are assumed released, so they must not appear
+     * in any onInputBuffersReleased() calls. That means
+     * onInputBuffersReleased() must only report input buffers that are released
+     * before the output in the same `Work` item is produced. However, it is
+     * possible for an input buffer to be returned by onWorkDone() after it has
+     * been reported by onInputBuffersReleased().
+     *
+     * @note onWorkDone() and onInputBuffersReleased() both notify the client
+     * that input buffers are no longer needed. However, in order to minimize
+     * IPC calls, onInputBuffersReleased() should be called only when
+     * onWorkDone() cannot be called, e.g., the component needs more input
+     * before an output can be produced.
+     *
+     * @param inputBuffers List of `InputBuffer` objects, identifying input
+     * buffers that are no longer needed by the component.
+     */
+    void onInputBuffersReleased(in InputBuffer[] inputBuffers);
+
+    /**
+     * Notify the listener that the component is tripped.
+     *
+     * @param settingResults List of failures.
+     */
+    void onTripped(in SettingResult[] settingResults);
+
+    /**
+     * Notify the listener that some `Work` items have been completed.
+     *
+     * All the input buffers in the returned `Work` objects must not be used by
+     * the component after onWorkDone() is called.
+     *
+     * @param workBundle List of completed `Work` objects.
+     */
+    void onWorkDone(in WorkBundle workBundle);
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/IComponentStore.aidl b/media/c2/aidl/android/hardware/media/c2/IComponentStore.aidl
new file mode 100644
index 0000000..019405d
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/IComponentStore.aidl
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2;
+
+import android.hardware.media.c2.Buffer;
+import android.hardware.media.c2.IComponent;
+import android.hardware.media.c2.IComponentInterface;
+import android.hardware.media.c2.IComponentListener;
+import android.hardware.media.c2.IConfigurable;
+import android.hardware.media.c2.IInputSurface;
+import android.hardware.media.c2.StructDescriptor;
+
+/**
+ * Entry point for Codec2 HAL.
+ *
+ * All methods in `IComponentStore` must not block. If a method call cannot be
+ * completed in a timely manner, it must throw `Status::TIMED_OUT`. The only
+ * exceptions are getPoolClientManager() and getConfigurable(),  which must
+ * always return immediately.
+ *
+ * @note This is an extension of version 1.1 of `IComponentStore`. The purpose
+ * of the extension is to add support for blocking output buffer allocator.
+ */
+@VintfStability
+interface IComponentStore {
+    /**
+     * Component traits.
+     */
+    @VintfStability
+    parcelable ComponentTraits {
+        @VintfStability
+        @Backing(type="int")
+        enum Kind {
+            OTHER = 0,
+            DECODER,
+            ENCODER,
+        }
+        @VintfStability
+        @Backing(type="int")
+        enum Domain {
+            OTHER = 0,
+            VIDEO,
+            AUDIO,
+            IMAGE,
+        }
+        /**
+         * Name of the component. This must be unique for each component.
+         *
+         * This name is use to identify the component to create in
+         * createComponent() and createComponentInterface().
+         */
+        String name;
+        /**
+         * Component domain.
+         */
+        Domain domain;
+        /**
+         * Component kind.
+         */
+        Kind kind;
+        /**
+         * Rank used by `MediaCodecList` to determine component ordering. Lower
+         * value means higher priority.
+         */
+        int rank;
+        /**
+         * MIME type.
+         */
+        String mediaType;
+        /**
+         * Aliases for component name for backward compatibility.
+         *
+         * Multiple components can have the same alias (but not the same
+         * component name) as long as their media types differ.
+         */
+        String[] aliases;
+    }
+
+    /**
+     * Copies the contents of @p src into @p dst without changing the format of
+     * @p dst.
+     *
+     * @param src Source buffer.
+     * @param dst Destination buffer.
+     * @throws ServiceSpecificException with one of the following values:
+     *   - `Status::CANNOT_DO` - @p src and @p dst are not compatible.
+     *   - `Status::REFUSED`   - No permission to copy.
+     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `Status::CORRUPTED` - Some unknown error occurred.
+     */
+    void copyBuffer(in Buffer src, in Buffer dst);
+
+    /**
+     * Creates a component by name.
+     *
+     * @param name Name of the component to create. This must match one of the
+     *     names returned by listComponents().
+     * @param listener Callback receiver.
+     * @param pool `IClientManager` object of the BufferPool in the client
+     *     process. This may be null if the client does not own a BufferPool.
+     * @return The created component.
+     * @throws ServiceSpecificException with one of the following values:
+     *   - `Status::NOT_FOUND` - There is no component with the given name.
+     *   - `Status::NO_MEMORY` - Not enough memory to create the component.
+     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `Status::CORRUPTED` - Some unknown error occurred.
+     *
+     * @sa IComponentListener.
+     */
+    IComponent createComponent(in String name, in IComponentListener listener,
+        in android.hardware.media.bufferpool2.IClientManager pool);
+
+    /**
+     * Creates a component interface by name.
+     *
+     * @param name Name of the component interface to create. This should match
+     *     one of the names returned by listComponents().
+     * @return The created component interface.
+     * @throws ServiceSpecificException with one of the following values:
+     *   - `Status::NOT_FOUND` - There is no component interface with the given name.
+     *   - `Status::NO_MEMORY` - Not enough memory to create the component interface.
+     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `Status::CORRUPTED` - Some unknown error occurred.
+     */
+    IComponentInterface createInterface(in String name);
+
+    /**
+     * Returns the @ref IConfigurable instance associated to this component
+     * store.
+     *
+     * @return `IConfigurable` instance. This must not be null.
+     */
+    IConfigurable getConfigurable();
+
+    /**
+     * Returns the `IClientManager` object for the component's BufferPool.
+     *
+     * @return If the component store supports receiving buffers via
+     *     BufferPool API, @p pool must be a valid `IClientManager` instance.
+     *     Otherwise, @p pool must be null.
+     */
+    android.hardware.media.bufferpool2.IClientManager getPoolClientManager();
+
+    /**
+     * Returns a list of `StructDescriptor` objects for a set of requested
+     * C2Param structure indices that this store is aware of.
+     *
+     * This operation must be performed at best effort, e.g. the component
+     * store must simply ignore all struct indices that it is not aware of.
+     *
+     * @param indices Indices of C2Param structures to describe.
+     * @return List of `StructDescriptor` objects.
+     * @throws ServiceSpecificException with one of the following values:
+     *   - `Status::NOT_FOUND` - Some indices were not known.
+     *   - `Status::NO_MEMORY` - Not enough memory to complete this method.
+     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `Status::CORRUPTED` - Some unknown error occurred.
+     */
+    StructDescriptor[] getStructDescriptors(in int[] indices);
+
+    /**
+     * Returns the list of components supported by this component store.
+     *
+     * @return traits List of component traits for all components supported by
+     *     this store (in no particular order).
+     * @throws ServiceSpecificException with one of the following values:
+     *   - `Status::NO_MEMORY` - Not enough memory to complete this method.
+     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `Status::CORRUPTED` - Some unknown error occurred.
+     */
+    ComponentTraits[] listComponents();
+
+    /**
+     * Creates a persistent input surface that can be used as an input surface
+     * for any IComponent instance
+     *
+     * @return IInputSurface A persistent input surface.
+     * @throws ServiceSpecificException with one of following values:
+     *   - `Status::NO_MEMORY` - Not enough memory to complete this method.
+     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `Status::CORRUPTED` - Some unknown error occurred.
+     */
+    IInputSurface createInputSurface();
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/IConfigurable.aidl b/media/c2/aidl/android/hardware/media/c2/IConfigurable.aidl
new file mode 100644
index 0000000..1481c15
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/IConfigurable.aidl
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2;
+
+import android.hardware.media.c2.FieldSupportedValuesQuery;
+import android.hardware.media.c2.FieldSupportedValuesQueryResult;
+import android.hardware.media.c2.ParamDescriptor;
+import android.hardware.media.c2.Params;
+import android.hardware.media.c2.SettingResult;
+import android.hardware.media.c2.Status;
+
+/**
+ * Generic configuration interface presented by all configurable Codec2 objects.
+ *
+ * This interface must be supported in all states of the owning object, and must
+ * not change the state of the owning object.
+ */
+@VintfStability
+interface IConfigurable {
+    /**
+     * Return parcelable for config() interface.
+     *
+     * This includes the successful config settings along with the failure reasons of
+     * the specified setting. @p status is for the compatibility with HIDL interface.
+     * (The value is defined in Status.aidl, and possible values are enumerated
+     * in config() interface definition)
+     */
+    @VintfStability
+    parcelable ConfigResult {
+        Params params;
+        SettingResult[] failures;
+        Status status;
+    }
+
+    /**
+     * Return parcelable for query() interface.
+     *
+     * @p params is the parameter descripion for queried configuration indices.
+     * @p status is for the compatibility with HIDL interface. (The value is defined in
+     * Status.aidl, and possible values are enumerated in query() interface definition)
+     */
+    @VintfStability
+    parcelable QueryResult {
+        Params params;
+        Status status;
+    }
+
+    /**
+     * Return parcelable for querySupportedValues() interface.
+     *
+     * @p values is the value descripion for queried configuration fields.
+     * @p status is for the compatibility with HIDL interface. (The value is defined in
+     * Status.aidl, and possible values are enumerated in querySupportedValues()
+     * interface definition)
+     */
+    @VintfStability
+    parcelable QuerySupportedValuesResult {
+        FieldSupportedValuesQueryResult[] values;
+        Status status;
+    }
+
+    /**
+     * Sets a set of parameters for the object.
+     *
+     * Tuning is performed at best effort: the object must update all supported
+     * configurations at best effort and skip unsupported parameters. Any errors
+     * are communicated in the return value along with the failures.
+     *
+     * A non-strict parameter update with an unsupported value shall cause an
+     * update to the closest supported value. A strict parameter update with an
+     * unsupported value shall be skipped and a failure shall be returned.
+     *
+     * If @p mayBlock is false, this method must not block. An update that
+     * requires blocking shall be skipped and a failure shall be returned.
+     *
+     * If @p mayBlock is true, an update may block, but the whole method call
+     * has to complete in a timely manner, or `Status::TIMED_OUT` is thrown.
+     *
+     * The final values for all parameters set are propagated back to the caller
+     * in @p params.
+     *
+     * \par For IComponent
+     *
+     * When the object type is @ref IComponent, this method must be supported in
+     * any state except released.
+     *
+     * The blocking behavior of this method differs among states:
+     *   - In the stopped state, this must be non-blocking. @p mayBlock is
+     *     ignored. (The method operates as if @p mayBlock was false.)
+     *   - In any of the running states, this method may block momentarily if
+     *     @p mayBlock is true. However, if the call cannot be completed in a
+     *     timely manner, `Status::TIMED_OUT` is thrown.
+     *
+     * @note Parameter tuning @e does depend on the order of the tuning
+     * parameters, e.g., some parameter update may enable some subsequent
+     * parameter update.
+     *
+     * @param inParams Requested parameter updates.
+     * @param mayBlock Whether this call may block or not.
+     * @return result of config. Params in the result should be in same order
+     *     with @p inParams.
+     *
+     *     Returned @p status will be one of the following.
+     *   - `Status::NO_MEMORY` - Some supported parameters could not be updated
+     *                   successfully because they contained unsupported values.
+     *                   These are returned in @p failures.
+     *   - `Status::BLOCKING`  - Setting some parameters requires blocking, but
+     *                   @p mayBlock is false.
+     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `Status::CORRUPTED` - Some unknown error occurred.
+     */
+    ConfigResult config(in Params inParams, in boolean mayBlock);
+
+    /**
+     * Returns the id of the object. This must be unique among all objects of
+     * the same type hosted by the same store.
+     *
+     * @return Id of the object.
+     */
+    int getId();
+
+    /**
+     * Returns the name of the object.
+     *
+     * This must match the name that was supplied during the creation of the
+     * object.
+     *
+     * @return Name of the object.
+     */
+    String getName();
+
+    /**
+     * Queries a set of parameters from the object.
+     *
+     * Querying is performed at best effort: the object must query all supported
+     * parameters and skip unsupported ones (which may include parameters that
+     * could not be allocated).
+     *
+     * If @p mayBlock is true, a query may block, but the whole method call
+     * has to complete in a timely manner, or `Status::TIMED_OUT` is thrown.
+     *
+     * If @p mayBlock is false, this method must not block(All parameter queries
+     * that require blocking must be skipped). Otherwise, this
+     * method is allowed to block for a certain period of time before completing
+     * the operation. If the operation is not completed in a timely manner,
+     * `Status::TIMED_OUT` is thrown.
+     *
+     * @note Since unsupported parameters will be skipped, the returned results
+     *     does not have every settings from @p indices, but the result will preserve
+     *     the original order from @p indices though unsupported settings are skipped.
+     *
+     * \par For IComponent
+     *
+     * When the object type is @ref IComponent, this method must be supported in
+     * any state except released. This call must not change the state nor the
+     * internal configuration of the component.
+     *
+     * The blocking behavior of this method differs among states:
+     *   - In the stopped state, this must be non-blocking. @p mayBlock is
+     *     ignored. (The method operates as if @p mayBlock was false.)
+     *   - In any of the running states, this method may block momentarily if
+     *     @p mayBlock is true. However, if the call cannot be completed in a
+     *     timely manner, `Status::status` is thrown.
+     *
+     * @param indices List of C2Param structure indices to query.
+     * @param mayBlock Whether this call may block or not.
+     * @return @p params is the flattened representation of std::vector<C2Param> object.
+     *     Technically unsupported settings can be either skipped or invalidated.
+     *     (Invalidated params will be skipped during unflattening to make these identical.)
+     *     In the future we will want these to be invalidated to make it easier
+     *     for the framework code.
+     *
+     *     The order in @p indices still be preserved except skipped settings.
+     *
+     *     Returned @p status will be one of the following.
+     *   - `Status::NO_MEMORY` - Could not allocate memory for a supported parameter.
+     *   - `Status::BLOCKING`  - Querying some parameters requires blocking, but
+     *                   @p mayBlock is false.
+     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `Status::CORRUPTED` - Some unknown error occurred.
+     */
+    QueryResult query(in int[] indices, in boolean mayBlock);
+
+    /**
+     * Returns a list of supported parameters within a selected range of C2Param
+     * structure indices.
+     *
+     * @param start The first index of the selected range.
+     * @param count The length of the selected range.
+     * @return List of supported parameters in the selected range. This
+     *     list may have fewer than @p count elements if some indices in the
+     *     range are not supported.
+     * @throws ServiceSpecificException with one of the following values:
+     *   - `Status::NO_MEMORY` - Not enough memory to complete this method.
+     *
+     */
+    ParamDescriptor[] querySupportedParams(in int start, in int count);
+
+    /**
+     * Retrieves the supported values for the queried fields.
+     *
+     * The object must process all fields queried even if some queries fail.
+     *
+     * If @p mayBlock is false, this method must not block. Otherwise, this
+     * method is allowed to block for a certain period of time before completing
+     * the operation. If the operation cannot be completed in a timely manner,
+     * `Status::TIMED_OUT` is thrown.
+     *
+     * \par For IComponent
+     *
+     * When the object type is @ref IComponent, this method must be supported in
+     * any state except released.
+     *
+     * The blocking behavior of this method differs among states:
+     *   - In the stopped state, this must be non-blocking. @p mayBlock is
+     *     ignored. (The method operates as if @p mayBlock was false.)
+     *   - In any of the running states, this method may block momentarily if
+     *     @p mayBlock is true. However, if the call cannot be completed in a
+     *     timely manner, `Status::TIMED_OUT` is thrown.
+     *
+     * @param inFields List of field queries.
+     * @param mayBlock Whether this call may block or not.
+     * @return @p values is the list of supported values and results for the
+     *     supplied queries.
+     *
+     *     Returned @p status will be one of the following.
+     *   - `Status::BLOCKING`  - Querying some parameters requires blocking, but
+     *                   @p mayBlock is false.
+     *   - `Status::NO_MEMORY` - Not enough memory to complete this method.
+     *   - `Status::BLOCKING`  - Querying some fields requires blocking, but @p mayblock
+     *                   is false.
+     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `Status::CORRUPTED` - Some unknown error occurred.
+     */
+    QuerySupportedValuesResult querySupportedValues(
+            in FieldSupportedValuesQuery[] inFields, in boolean mayBlock);
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/IGraphicBufferAllocator.aidl b/media/c2/aidl/android/hardware/media/c2/IGraphicBufferAllocator.aidl
new file mode 100644
index 0000000..1710242
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/IGraphicBufferAllocator.aidl
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2;
+
+import android.hardware.HardwareBuffer;
+import android.os.ParcelFileDescriptor;
+
+/**
+ * Interface for decoder output buffer allocator for HAL process
+ *
+ * A graphic buffer for decoder output is allocated by the interface.
+ */
+@VintfStability
+interface IGraphicBufferAllocator {
+    /**
+     * A graphic buffer allocation.
+     *
+     * buffer is in android.hardware.HardwareBuffer.
+     * fence is provided in order to signal readiness of the buffer I/O inside
+     * underlying Graphics subsystem. This is called a sync fence throughout Android framework.
+     */
+    parcelable Allocation {
+        HardwareBuffer buffer;
+        @nullable ParcelFileDescriptor fence;
+    }
+
+    /**
+     * Parameters for a graphic buffer allocation.
+     *
+     * Refer to AHardwareBuffer_Desc(libnativewindow) for details.
+     */
+    parcelable Description {
+        int width;
+        int height;
+        int format;
+        long usage;
+    }
+
+    /**
+     * Allocate a graphic buffer.
+     *
+     * @param desc Allocation parameters.
+     * @return an android.hardware.HardwareBuffer which is basically same to
+     *     AHardwareBuffer. If underlying grpahics system is blocked, c2::Status::Blocked
+     *     will be returned. In this case getWaitableFds() will return file descriptors which
+     *     can be used to construct a waitable object. The waitable object will be notified
+     *     when underlying graphics system is unblocked
+     * @throws ServiceSpecificException with one of the following values:
+     *   - `c2::Status::BAD_STATE` - The client is not in running states.
+     *   - `c2::Status::BLOCKED`   - Underlying graphics system is blocked.
+     *   - `c2::Status::CORRUPTED` - Some unknown error occurred.
+     */
+    Allocation allocate(in Description desc);
+
+    /**
+     * De-allocate a graphic buffer by graphic buffer's unique id.
+     *
+     * @param id graphic buffer's unique id. See also AHardwareBuffer_getId().
+     * @return {@code true} when de-allocate happened, {@code false} otherwise.
+     */
+    boolean deallocate(in long id);
+
+    /**
+     * Gets a waitable file descriptor.
+     *
+     * Use this method once and cache it in order not to create unnecessary duplicated fds.
+     *
+     * Two file descriptors are created by pipe2(), and the reading end will be returned
+     * and shared by this method. Whenever a dequeuable buffer is ready a byte will be
+     * written to the writing end. Whenever a buffer is allocated(or dequeued) a byte will
+     * be read from the reading end.
+     *
+     * The returned file descriptor(the reading end) can be polled whether the read is ready
+     * via ::poll(). If no more allocate() can be fulfilled(by status change or etc.), the
+     * writing end will be closed. In the case, POLLHUP event can be retrieved via ::poll().
+     *
+     * C2Fence object should be implemented based on this Fd. Thus, C2Fence can return
+     * either by allocation being ready or allocation being infeasible by the client status
+     * change.
+     *
+     * If many waitable objects based on the same fd are competing, all watiable objects will be
+     * notified. After being notified, they should invoke allocate(). At least one of them can
+     * successfully allocate. Others not having an Allocation will have c2::Status::BLOCKED
+     * as return value. They should wait again via waitable objects based on the fds which are
+     * already returned from this interface.
+     *
+     * @return an fd array which will be wrapped to C2Fence and will be waited for
+     *     until allocating is unblocked.
+     */
+    ParcelFileDescriptor getWaitableFd();
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/IInputSink.aidl b/media/c2/aidl/android/hardware/media/c2/IInputSink.aidl
new file mode 100644
index 0000000..eb8ad3d
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/IInputSink.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2;
+
+import android.hardware.media.c2.WorkBundle;
+
+/**
+ * An `IInputSink` is a receiver of work items.
+ *
+ * An @ref IComponent instance can present itself as an `IInputSink` via a thin
+ * wrapper.
+ *
+ * @sa IInputSurface, IComponent.
+ */
+@VintfStability
+interface IInputSink {
+    /**
+     * Feeds work to the sink.
+     *
+     * @param workBundle `WorkBundle` object containing a list of `Work` objects
+     *     to queue to the component.
+     * @throws ServiceSpecificException with one of the following values:
+     *   - `Status::BAD_INDEX` - Some component id in some `Worklet` is not valid.
+     *   - `Status::CANNOT_DO` - Tunneling has not been set up for this sink, but some
+     *                   `Work` object contains tunneling information.
+     *   - `Status::NO_MEMORY` - Not enough memory to queue @p workBundle.
+     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `Status::CORRUPTED` - Some unknown error occurred.
+     */
+    void queue(in WorkBundle workBundle);
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/IInputSurface.aidl b/media/c2/aidl/android/hardware/media/c2/IInputSurface.aidl
new file mode 100644
index 0000000..77cb1fd
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/IInputSurface.aidl
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2;
+
+import android.hardware.media.c2.IConfigurable;
+import android.hardware.media.c2.IInputSink;
+import android.hardware.media.c2.IInputSurfaceConnection;
+import android.view.Surface;
+
+/**
+ * Input surface for a Codec2 component.
+ *
+ * An <em>input surface</em> is an instance of `IInputSurface`, which may be
+ * created by calling IComponentStore::createInputSurface(). Once created, the
+ * client may
+ *   1. write data to it via the `NativeWindow` interface; and
+ *   2. use it as input to a Codec2 encoder.
+ *
+ * @sa IInputSurfaceConnection, IComponentStore::createInputSurface(),
+ *     IComponent::connectToInputSurface().
+ */
+@VintfStability
+interface IInputSurface {
+    /**
+     * Returns the producer interface into the internal buffer queue.
+     *
+     * @return producer `Surface` instance(actually ANativeWindow). This must not
+     * be null.
+     */
+    Surface getSurface();
+
+    /**
+     * Returns the @ref IConfigurable instance associated to this input surface.
+     *
+     * @return configurable `IConfigurable` instance. This must not be null.
+     */
+    IConfigurable getConfigurable();
+
+    /**
+     * Connects the input surface to an input sink.
+     *
+     * This function is generally called from inside the implementation of
+     * IComponent::connectToInputSurface(), where @p sink is a thin wrapper of
+     * the component that consumes buffers from this surface.
+     *
+     * @param sink Input sink. See `IInputSink` for more information.
+     * @return connection `IInputSurfaceConnection` object. This must not be
+     *     null if @p status is `OK`.
+     * @throws ServiceSpecificException with one of following values:
+     *   - `Status::BAD_VALUE` - @p sink is invalid.
+     *   - `Status::CORRUPTED` - Some unknown error occurred.
+     */
+    IInputSurfaceConnection connect(in IInputSink sink);
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/IInputSurfaceConnection.aidl b/media/c2/aidl/android/hardware/media/c2/IInputSurfaceConnection.aidl
new file mode 100644
index 0000000..36524eb
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/IInputSurfaceConnection.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2;
+
+/**
+ * Connection between an IInputSink and an IInpuSurface.
+ */
+@VintfStability
+interface IInputSurfaceConnection {
+    /**
+     * Destroys the connection between an input surface and a component.
+     *
+     * @throws ServiceSpecificException with one of following values:
+     *   - `Status::BAD_STATE` - The component is not in running state.
+     *   - `Status::NOT_FOUND` - The surface is not connected to a component.
+     *   - `Status::CORRUPTED` - Some unknown error occurred.
+     */
+    void disconnect();
+
+    /**
+     * Signal the end of stream.
+
+     * @throws ServiceSpecificException with one of following values:
+     *   - `Status::BAD_STATE` - The component is not in running state.
+     */
+    void signalEndOfStream();
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/IPooledGraphicBufferAllocator.aidl b/media/c2/aidl/android/hardware/media/c2/IPooledGraphicBufferAllocator.aidl
new file mode 100644
index 0000000..b599d52
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/IPooledGraphicBufferAllocator.aidl
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2;
+
+import android.os.ParcelFileDescriptor;
+
+/**
+ * Interface for decoder output buffer allocator for HAL process
+ *
+ * A graphic buffer for decoder output is allocated by the interface.
+ */
+@VintfStability
+interface IPooledGraphicBufferAllocator {
+    /**
+     * A graphic buffer allocation.
+     *
+     * bufferId is id of buffer from a media.bufferpool2. The buffer is
+     * android.hardware.HardwareBuffer.
+     * fence is provided in order to signal readiness of the buffer I/O inside
+     * underlying Graphics subsystem. This is called a sync fence throughout Android framework.
+     */
+    parcelable Allocation {
+        int bufferId;
+        @nullable ParcelFileDescriptor fence;
+    }
+
+    /**
+     * Parameters for a graphic buffer allocation.
+     *
+     * Refer to AHardwareBuffer_Desc(libnativewindow) for details.
+     */
+    parcelable Description {
+        int widthPixels;
+        int heightPixels;
+        int format; // AHardwareBuffer_Format
+        long usage; // AHardwareBuffer_UsageFlags
+    }
+
+    /**
+     * Allocate a graphic buffer.
+     * deallocate() must be called after the allocated buffer is no longer needed.
+     *
+     * @param desc Allocation parameters.
+     * @return an id of a buffer, the id is created from media.bufferpool2 in order for
+     *     caching and recycling,
+     *     If underlying allocator is blocked, c2::Status::Blocked will be returned.
+     *     Waitable fd must be obtained using the ndk object locally. The waitable fd must
+     *     be passed to the receiver during BlockPool creation request via AIDL.
+     * @throws ServiceSpecificException with one of the following values:
+     *   - `c2::Status::BAD_STATE` - The client is not in running states.
+     *   - `c2::Status::BLOCKED`   - Underlying graphics system is blocked.
+     *   - `c2::Status::CORRUPTED` - Some unknown error occurred.
+     */
+    Allocation allocate(in Description desc);
+
+    /**
+     * De-allocate a graphic buffer by graphic buffer's unique id.
+     *
+     * @param id buffer id.
+     * @return {@code true} when de-allocate happened, {@code false} otherwise.
+     */
+    boolean deallocate(in int id);
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/InfoBuffer.aidl b/media/c2/aidl/android/hardware/media/c2/InfoBuffer.aidl
new file mode 100644
index 0000000..207c4d0
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/InfoBuffer.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2;
+
+import android.hardware.media.c2.Buffer;
+
+/**
+ * An extension of @ref Buffer that also contains a C2Param structure index.
+ *
+ * This is a part of @ref FrameData.
+ */
+@VintfStability
+parcelable InfoBuffer {
+    /**
+     * A C2Param structure index.
+     */
+    int index;
+    /**
+     * Associated @ref Buffer object.
+     */
+    Buffer buffer;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/ParamDescriptor.aidl b/media/c2/aidl/android/hardware/media/c2/ParamDescriptor.aidl
new file mode 100644
index 0000000..84c6acc
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/ParamDescriptor.aidl
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2;
+
+/**
+ * Usage description of a C2Param structure.
+ *
+ * @ref ParamDescriptor is returned by IConfigurable::querySupportedParams().
+ */
+@VintfStability
+parcelable ParamDescriptor {
+    /** The list of bit flags for attrib */
+    /**
+     * The parameter is required to be specified.
+     */
+    const int ATTRIBUTE_REQUIRED = 1 << 0;
+    /**
+     * The parameter retains its value.
+     */
+    const int ATTRIBUTE_PERSISTENT = 1 << 1;
+    /**
+     * The parameter is strict.
+     */
+    const int ATTRIBUTE_STRICT = 1 << 2;
+    /**
+     * The parameter is publicly read-only.
+     */
+    const int ATTRIBUTE_READ_ONLY = 1 << 3;
+    /**
+     * The parameter must not be visible to clients.
+     */
+    const int ATTRIBUTE_HIDDEN = 1 << 4;
+    /**
+     * The parameter must not be used by framework (other than testing).
+     */
+    const int ATTRIBUTE_INTERNAL = 1 << 5;
+    /**
+     * The parameter is publicly constant (hence read-only).
+     */
+    const int ATTRIBUTE_CONST = 1 << 6;
+
+    /**
+     * Index of the C2Param structure being described.
+     */
+    int index;
+    /**
+     * bit flag for attribute defined in the above.
+     */
+    int attrib;
+    /**
+     * Name of the structure. This must be unique for each structure.
+     */
+    String name;
+    /**
+     * Indices of other C2Param structures that this C2Param structure depends
+     * on.
+     */
+    int[] dependencies;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/ParamField.aidl b/media/c2/aidl/android/hardware/media/c2/ParamField.aidl
new file mode 100644
index 0000000..64a46bb
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/ParamField.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2;
+
+import android.hardware.media.c2.FieldId;
+
+/**
+ * Reference to a field in a C2Param structure.
+ */
+@VintfStability
+parcelable ParamField {
+    /**
+     * Index of the C2Param structure.
+     */
+    int index;
+    /**
+     * Identifier of the field inside the C2Param structure.
+     */
+    FieldId fieldId;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/ParamFieldValues.aidl b/media/c2/aidl/android/hardware/media/c2/ParamFieldValues.aidl
new file mode 100644
index 0000000..7b74c0e
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/ParamFieldValues.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2;
+
+import android.hardware.media.c2.FieldSupportedValues;
+import android.hardware.media.c2.ParamField;
+
+/**
+ * Supported values for a field.
+ *
+ * This is a pair of the field specifier together with an optional supported
+ * values object. This structure is used when reporting parameter configuration
+ * failures and conflicts.
+ */
+@VintfStability
+parcelable ParamFieldValues {
+    /**
+     * Reference to a field or a C2Param structure.
+     */
+    ParamField paramOrField;
+    /**
+     * Optional supported values for the field if #paramOrField specifies an
+     * actual field that is numeric (non struct, blob or string). Supported
+     * values for arrays (including string and blobs) describe the supported
+     * values for each element (character for string, and bytes for blobs). It
+     * is optional for read-only strings and blobs.
+     */
+    FieldSupportedValues[] values;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/Params.aidl b/media/c2/aidl/android/hardware/media/c2/Params.aidl
new file mode 100644
index 0000000..53b512c
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/Params.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2;
+
+/**
+ * Flattened representation of std::vector<C2Param> object.
+ *
+ * The `Params` type is an array of bytes made up by concatenating a list of
+ * C2Param objects. The start index (offset into @ref Params) of each C2Param
+ * object in the list is divisible by 8. Up to 7 padding bytes may be added
+ * after each C2Param object to achieve this 64-bit alignment.
+ *
+ * Each C2Param object has the following layout:
+ * - 4 bytes: C2Param structure index (of type @ref ParamIndex) identifying the
+ *   type of the C2Param object.
+ * - 4 bytes: size of the C2Param object (unsigned 4-byte integer).
+ * - (size - 8) bytes: data of the C2Param object.
+ */
+@VintfStability
+parcelable Params {
+    byte[] params;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/SettingResult.aidl b/media/c2/aidl/android/hardware/media/c2/SettingResult.aidl
new file mode 100644
index 0000000..c2b9574
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/SettingResult.aidl
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2;
+
+import android.hardware.media.c2.ParamFieldValues;
+
+/**
+ * Information describing the reason the parameter settings may fail, or may be
+ * overridden.
+ */
+@VintfStability
+parcelable SettingResult {
+    /**
+     * Failure code
+     */
+    @VintfStability
+    @Backing(type="int")
+    enum Failure {
+        /**
+         * Parameter is not supported.
+         */
+        BAD_TYPE,
+        /**
+         * Parameter is not supported on the specific port.
+         */
+        BAD_PORT,
+        /**
+         * Parameter is not supported on the specific stream.
+         */
+        BAD_INDEX,
+        /**
+         * Parameter is read-only and cannot be set.
+         */
+        READ_ONLY,
+        /**
+         * Parameter mismatches input data.
+         */
+        MISMATCH,
+        /**
+         * Strict parameter does not accept value for the field at all.
+         */
+        BAD_VALUE,
+        /**
+         * Strict parameter field value is in conflict with an/other
+         * setting(s).
+         */
+        CONFLICT,
+        /**
+         * Parameter field is out of range due to other settings. (This failure
+         * mode can only be used for strict calculated parameters.)
+         */
+        UNSUPPORTED,
+        /**
+         * Field does not access the requested parameter value at all. It has
+         * been corrected to the closest supported value. This failure mode is
+         * provided to give guidance as to what are the currently supported
+         * values for this field (which may be a subset of the at-all-potential
+         * values).
+         */
+        INFO_BAD_VALUE,
+        /**
+         * Requested parameter value is in conflict with an/other setting(s)
+         * and has been corrected to the closest supported value. This failure
+         * mode is given to provide guidance as to what are the currently
+         * supported values as well as to optionally provide suggestion to the
+         * client as to how to enable the requested parameter value.
+         */
+        INFO_CONFLICT,
+    }
+    Failure failure;
+    /**
+     * Failing (or corrected) field or parameter and optionally, currently
+     * supported values for the field. Values must only be set for field
+     * failures other than `BAD_VALUE`, and only if they are different from the
+     * globally supported values (e.g. due to restrictions by another parameter
+     * or input data).
+     */
+    ParamFieldValues field;
+    /**
+     * Conflicting parameters or fields with (optional) suggested values for any
+     * conflicting fields to avoid the conflict. Values must only be set for
+     * `CONFLICT`, `UNSUPPORTED` or `INFO_CONFLICT` failure code.
+     */
+    ParamFieldValues[] conflicts;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/Status.aidl b/media/c2/aidl/android/hardware/media/c2/Status.aidl
new file mode 100644
index 0000000..58a2404
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/Status.aidl
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2;
+
+/**
+ * Common return values for Codec2 operations.
+ */
+@VintfStability
+parcelable Status {
+    /**
+     * Operation completed successfully.
+     */
+    const int OK = 0;
+    /**
+     * Argument has invalid value (user error).
+     */
+    const int BAD_VALUE = -22;
+    /**
+     * Argument uses invalid index (user error).
+     */
+    const int BAD_INDEX = -75;
+    /**
+     * Argument/Index is valid but not possible.
+     */
+    const int CANNOT_DO = -2147483646;
+    /**
+     * Object already exists.
+     */
+    const int DUPLICATE = -17;
+    /**
+     * Object not found.
+     */
+    const int NOT_FOUND = -2;
+    /**
+     * Operation is not permitted in the current state.
+     */
+    const int BAD_STATE = -38;
+    /**
+     * Operation would block but blocking is not permitted.
+     */
+    const int BLOCKING = -9930;
+    /**
+     * Not enough memory to complete operation.
+     */
+    const int NO_MEMORY = -12;
+    /**
+     * Missing permission to complete operation.
+     */
+    const int REFUSED = -1;
+    /**
+     * Operation did not complete within timeout.
+     */
+    const int TIMED_OUT = -110;
+    /**
+     * Operation is not implemented/supported (optional only).
+     */
+    const int OMITTED = -74;
+    /**
+     * Some unexpected error prevented the operation.
+     */
+    const int CORRUPTED = -2147483648;
+    /**
+     * Status has not been initialized.
+     */
+    const int NO_INIT = -19;
+
+    int status;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/StructDescriptor.aidl b/media/c2/aidl/android/hardware/media/c2/StructDescriptor.aidl
new file mode 100644
index 0000000..00359041
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/StructDescriptor.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2;
+
+import android.hardware.media.c2.FieldDescriptor;
+
+/**
+ * Description of a C2Param structure. It consists of an index and a list of
+ * `FieldDescriptor`s.
+ */
+@VintfStability
+parcelable StructDescriptor {
+    /**
+     * Index of the structure.
+     *
+     * Actually C2Param::CoreIndex
+     * Core index is the underlying parameter type for a parameter. It is used to describe the
+     * layout of the parameter structure regardless of the component or parameter kind/scope.
+     *
+     * It is used to identify and distinguish global parameters, and also parameters on a given
+     * port or stream. They must be unique for the set of global parameters, as well as for the
+     * set of parameters on each port or each stream, but the same core index can be used for
+     * parameters on different streams or ports, as well as for global parameters and port/stream
+     * parameters.
+     */
+    int type;
+    /**
+     * List of fields in the structure.
+     *
+     * Fields are ordered by their offsets. A field that is a structure is
+     * ordered before its members.
+     */
+    FieldDescriptor[] fields;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/ValueRange.aidl b/media/c2/aidl/android/hardware/media/c2/ValueRange.aidl
new file mode 100644
index 0000000..9abcb7d
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/ValueRange.aidl
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2;
+
+/**
+ * Description of a set of values.
+ *
+ * If the `step` member is 0, and `num` and `denom` are both 1, the `Range`
+ * structure represents a closed interval bounded by `min` and `max`.
+ *
+ * Otherwise, the #ValueRange structure represents a finite sequence of numbers
+ * produced from the following recurrence relation:
+ *
+ * @code
+ * v[0] = min
+ * v[i] = v[i - 1] * num / denom + step ; i >= 1
+ * @endcode
+ *
+ * Both the ratio `num / denom` and the value `step` must be positive. The
+ * last number in the sequence described by this #Range structure is the
+ * largest number in the sequence that is smaller than or equal to `max`.
+ *
+ * @note
+ * The division in the formula may truncate the result if the data type of
+ * these values is an integral type.
+ */
+@VintfStability
+parcelable ValueRange {
+    /**
+     * Lower end of the range (inclusive).
+     */
+    long min;
+    /**
+     * Upper end of the range (inclusive).
+     */
+    long max;
+    /**
+     * The non-homogeneous term in the recurrence relation.
+     */
+    long step;
+    /**
+     * The numerator of the scale coefficient in the recurrence relation.
+     */
+    long num;
+    /**
+     * The denominator of the scale coefficient in the recurrence relation.
+     */
+    long denom;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/Work.aidl b/media/c2/aidl/android/hardware/media/c2/Work.aidl
new file mode 100644
index 0000000..4b8d696
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/Work.aidl
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2;
+
+import android.hardware.media.c2.FrameData;
+import android.hardware.media.c2.Status;
+import android.hardware.media.c2.Worklet;
+
+/**
+ * A collection of input data to and output data from the component.
+ *
+ * A `Work` object holds information about a single work item. It is created by
+ * the client and passed to the component via IComponent::queue(). The component
+ * has two ways of returning a `Work` object to the client:
+ *   1. If the queued `Work` object has been successfully processed,
+ *      IComponentListener::onWorkDone() shall be called to notify the listener,
+ *      and the output shall be included in the returned `Work` object.
+ *   2. If the client calls IComponent::flush(), a `Work` object that has not
+ *      been processed shall be returned.
+ *
+ * `Work` is a part of @ref WorkBundle.
+ */
+@VintfStability
+parcelable Work {
+    /**
+     * Additional work chain info not part of this work.
+     */
+    byte[] chainInfo;
+    /**
+     * @ref FrameData for the input.
+     */
+    FrameData input;
+    /**
+     * The chain of `Worklet`s.
+     *
+     * The length of #worklets is 1 when tunneling is not enabled.
+     *
+     * If #worklets has more than a single element, the tunnels between
+     * successive components of the work chain must have been successfully
+     * pre-registered at the time that the `Work` is submitted. Allocating the
+     * output buffers in the `Worklet`s is the responsibility of each component
+     * in the chain.
+     *
+     * Upon `Work` submission, #worklets must be an appropriately sized vector
+     * containing `Worklet`s with @ref Worklet.hasOutput set to `false`. After a
+     * successful processing, all but the final `Worklet` in the returned
+     * #worklets must have @ref Worklet.hasOutput set to `false`.
+     */
+    Worklet[] worklets;
+    /**
+     * The number of `Worklet`s successfully processed in this chain.
+     *
+     * This must be initialized to 0 by the client when the `Work` is submitted,
+     * and it must contain the number of `Worklet`s that were successfully
+     * processed when the `Work` is returned to the client.
+     *
+     * #workletsProcessed cannot exceed the length of #worklets. If
+     * #workletsProcessed is smaller than the length of #worklets, #result
+     * cannot be `OK`.
+     */
+    int workletsProcessed;
+    /**
+     * The final outcome of the `Work` (corresponding to #workletsProcessed).
+     *
+     * The value of @ref Status.OK implies that all `Worklet`s have been
+     * successfully processed.
+     */
+    Status result;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/WorkBundle.aidl b/media/c2/aidl/android/hardware/media/c2/WorkBundle.aidl
new file mode 100644
index 0000000..2125fda
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/WorkBundle.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2;
+
+import android.hardware.media.c2.BaseBlock;
+import android.hardware.media.c2.Work;
+
+/**
+ * List of `Work` objects.
+ *
+ * `WorkBundle` is used in IComponent::queue(), IComponent::flush() and
+ * IComponentListener::onWorkDone(). A `WorkBundle` object consists of a list of
+ * `Work` objects and a list of `BaseBlock` objects. Bundling multiple `Work`
+ * objects together provides two benefits:
+ *   1. Batching of `Work` objects can reduce the number of IPC calls.
+ *   2. If multiple `Work` objects contain `Block`s that refer to the same
+ *      `BaseBlock`, the number of `BaseBlock`s that is sent between processes
+ *      is also reduced.
+ *
+ * @note `WorkBundle` is the AIDL counterpart of the vector of `C2Work` in the
+ * Codec 2.0 standard. The presence of #baseBlocks helps with minimizing the
+ * data transferred over an IPC.
+ */
+@VintfStability
+parcelable WorkBundle {
+    /**
+     * A list of Work items.
+     */
+    Work[] works;
+    /**
+     * A list of blocks indexed by elements of #works.
+     */
+    BaseBlock[] baseBlocks;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/WorkOrdinal.aidl b/media/c2/aidl/android/hardware/media/c2/WorkOrdinal.aidl
new file mode 100644
index 0000000..5708a90
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/WorkOrdinal.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2;
+
+/**
+ * Ordering information of @ref FrameData objects. Each member is used for
+ * comparing urgency: a smaller difference from a reference value indicates that
+ * the associated Work object is more urgent. The reference value for each
+ * member is initialized the first time it is communicated between the client
+ * and the codec, and it may be updated to later values that are communicated.
+ *
+ * Each member of `WorkOrdinal` is stored as an unsigned integer, but the actual
+ * order it represents is derived by subtracting the reference value, then
+ * interpreting the result as a signed number with the same storage size (using
+ * two's complement).
+ *
+ * @note `WorkOrdinal` is the HIDL counterpart of `C2WorkOrdinalStruct` in the
+ * Codec 2.0 standard.
+ */
+@VintfStability
+parcelable WorkOrdinal {
+    /**
+     * Timestamp in microseconds.
+     */
+    long timestampUs;
+    /**
+     * Frame index.
+     */
+    long frameIndex;
+    /**
+     * Component specific frame ordinal.
+     */
+    long customOrdinal;
+}
diff --git a/media/c2/aidl/android/hardware/media/c2/Worklet.aidl b/media/c2/aidl/android/hardware/media/c2/Worklet.aidl
new file mode 100644
index 0000000..6b3ceac
--- /dev/null
+++ b/media/c2/aidl/android/hardware/media/c2/Worklet.aidl
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2;
+
+import android.hardware.media.c2.FrameData;
+import android.hardware.media.c2.SettingResult;
+
+/**
+ * In/out structure containing some instructions for and results from output
+ * processing.
+ *
+ * This is a part of @ref Work. One `Worklet` corresponds to one output
+ * @ref FrameData. The client must construct an original `Worklet` object inside
+ * a @ref Work object for each expected output before calling
+ * IComponent::queue().
+ */
+@VintfStability
+parcelable Worklet {
+    /**
+     * Component id. (Input)
+     *
+     * This is used only when tunneling is enabled.
+     *
+     * When used, this must match the return value from IConfigurable::getId().
+     */
+    int componentId;
+    /**
+     * List of C2Param objects describing tunings to be applied before
+     * processing this `Worklet`. (Input)
+     */
+    byte[] tunings;
+    /**
+     * List of failures. (Output)
+     */
+    SettingResult[] failures;
+    /**
+     * Output frame data. (Output)
+     */
+    FrameData output;
+}
diff --git a/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoEncTest.cpp b/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoEncTest.cpp
index f24c6d1..9a75e6e 100644
--- a/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoEncTest.cpp
+++ b/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoEncTest.cpp
@@ -630,10 +630,7 @@
         if (error != android::NO_ERROR) return 1;
     } else {
         void* data;
-        int32_t outBytesPerPixel;
-        int32_t outBytesPerStride;
-        error = gbmapper.lock(buff, buffer->omxBuffer.attr.anwBuffer.usage, rect, &data,
-                              &outBytesPerPixel, &outBytesPerStride);
+        error = gbmapper.lock(buff, buffer->omxBuffer.attr.anwBuffer.usage, rect, &data);
         EXPECT_EQ(error, android::NO_ERROR);
         if (error != android::NO_ERROR) return 1;
 
diff --git a/memtrack/aidl/default/Android.bp b/memtrack/aidl/default/Android.bp
index 6c77177..cf95bbb 100644
--- a/memtrack/aidl/default/Android.bp
+++ b/memtrack/aidl/default/Android.bp
@@ -37,3 +37,56 @@
         "Memtrack.cpp",
     ],
 }
+
+cc_binary {
+    name: "android.hardware.memtrack-service.apex",
+    stem: "android.hardware.memtrack-service.example",
+    relative_install_path: "hw",
+    vendor: true,
+
+    stl: "c++_static",
+    static_libs: [
+        "libbase",
+        "android.hardware.memtrack-V1-ndk",
+    ],
+    shared_libs: [
+        "libbinder_ndk",
+        "liblog",
+    ],
+    srcs: [
+        "main.cpp",
+        "Memtrack.cpp",
+    ],
+    installable: false, // installed in APEX
+}
+
+prebuilt_etc {
+    name: "memtrack-default-apex.rc",
+    src: "memtrack-default-apex.rc",
+    installable: false,
+}
+
+prebuilt_etc {
+    name: "memtrack-default.xml",
+    src: "memtrack-default.xml",
+    sub_dir: "vintf",
+    installable: false,
+}
+
+apex {
+    name: "com.android.hardware.memtrack",
+    file_contexts: "apex_file_contexts",
+    manifest: "apex_manifest.json",
+    key: "com.android.hardware.key",
+    certificate: ":com.android.hardware.certificate",
+    updatable: false,
+    vendor: true,
+
+    binaries: [
+        "android.hardware.memtrack-service.apex",
+    ],
+    prebuilts: [
+        "memtrack-default-apex.rc",
+        "memtrack-default.xml",
+    ],
+}
diff --git a/memtrack/aidl/default/apex_file_contexts b/memtrack/aidl/default/apex_file_contexts
new file mode 100644
index 0000000..40c0af4
--- /dev/null
+++ b/memtrack/aidl/default/apex_file_contexts
@@ -0,0 +1,3 @@
+(/.*)?                                                      u:object_r:vendor_file:s0
+/etc(/.*)?                                                  u:object_r:vendor_configs_file:s0
+/bin/hw/android\.hardware\.memtrack-service\.example        u:object_r:hal_memtrack_default_exec:s0
diff --git a/memtrack/aidl/default/apex_manifest.json b/memtrack/aidl/default/apex_manifest.json
new file mode 100644
index 0000000..16d195e
--- /dev/null
+++ b/memtrack/aidl/default/apex_manifest.json
@@ -0,0 +1,4 @@
+{
+    "name": "com.android.hardware.memtrack",
+    "version": 1
+}
\ No newline at end of file
diff --git a/memtrack/aidl/default/memtrack-default-apex.rc b/memtrack/aidl/default/memtrack-default-apex.rc
new file mode 100644
index 0000000..53e712a
--- /dev/null
+++ b/memtrack/aidl/default/memtrack-default-apex.rc
@@ -0,0 +1,4 @@
+service vendor.memtrack-default /apex/com.android.hardware.memtrack/bin/hw/android.hardware.memtrack-service.example
+    class hal
+    user nobody
+    group system
diff --git a/neuralnetworks/1.0/Android.bp b/neuralnetworks/1.0/Android.bp
index 7bc65ff..8b7af11 100644
--- a/neuralnetworks/1.0/Android.bp
+++ b/neuralnetworks/1.0/Android.bp
@@ -23,4 +23,8 @@
         "android.hidl.base@1.0",
     ],
     gen_java: false,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.neuralnetworks",
+    ],
 }
diff --git a/neuralnetworks/1.1/Android.bp b/neuralnetworks/1.1/Android.bp
index 772e5e6..b93c80c 100644
--- a/neuralnetworks/1.1/Android.bp
+++ b/neuralnetworks/1.1/Android.bp
@@ -21,4 +21,8 @@
         "android.hidl.base@1.0",
     ],
     gen_java: false,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.neuralnetworks",
+    ],
 }
diff --git a/neuralnetworks/1.2/Android.bp b/neuralnetworks/1.2/Android.bp
index 2b83d39..63e0f61 100644
--- a/neuralnetworks/1.2/Android.bp
+++ b/neuralnetworks/1.2/Android.bp
@@ -28,4 +28,8 @@
         "android.hidl.safe_union@1.0",
     ],
     gen_java: false,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.neuralnetworks",
+    ],
 }
diff --git a/neuralnetworks/1.3/Android.bp b/neuralnetworks/1.3/Android.bp
index aa8fc39..c343802 100644
--- a/neuralnetworks/1.3/Android.bp
+++ b/neuralnetworks/1.3/Android.bp
@@ -29,4 +29,8 @@
         "android.hidl.safe_union@1.0",
     ],
     gen_java: false,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.neuralnetworks",
+    ],
 }
diff --git a/neuralnetworks/aidl/Android.bp b/neuralnetworks/aidl/Android.bp
index be86879..145604c 100644
--- a/neuralnetworks/aidl/Android.bp
+++ b/neuralnetworks/aidl/Android.bp
@@ -17,7 +17,7 @@
     stability: "vintf",
     imports: [
         "android.hardware.common-V2",
-        "android.hardware.graphics.common-V4",
+        "android.hardware.graphics.common-V5",
     ],
     backend: {
         java: {
@@ -40,28 +40,28 @@
             version: "1",
             imports: [
                 "android.hardware.common-V2",
-                "android.hardware.graphics.common-V4",
+                "android.hardware.graphics.common-V5",
             ],
         },
         {
             version: "2",
             imports: [
                 "android.hardware.common-V2",
-                "android.hardware.graphics.common-V4",
+                "android.hardware.graphics.common-V5",
             ],
         },
         {
             version: "3",
             imports: [
                 "android.hardware.common-V2",
-                "android.hardware.graphics.common-V4",
+                "android.hardware.graphics.common-V5",
             ],
         },
         {
             version: "4",
             imports: [
                 "android.hardware.common-V2",
-                "android.hardware.graphics.common-V4",
+                "android.hardware.graphics.common-V5",
             ],
         },
 
diff --git a/nfc/1.0/Android.bp b/nfc/1.0/Android.bp
index 55c8639..ef12c7c 100644
--- a/nfc/1.0/Android.bp
+++ b/nfc/1.0/Android.bp
@@ -22,4 +22,8 @@
     ],
     gen_java: true,
     gen_java_constants: true,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.nfcservices",
+    ],
 }
diff --git a/nfc/1.1/Android.bp b/nfc/1.1/Android.bp
index a8463cf..65da2a0 100644
--- a/nfc/1.1/Android.bp
+++ b/nfc/1.1/Android.bp
@@ -22,4 +22,8 @@
         "android.hidl.base@1.0",
     ],
     gen_java: true,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.nfcservices",
+    ],
 }
diff --git a/nfc/1.2/Android.bp b/nfc/1.2/Android.bp
index 4831ab9..8ad93f9 100644
--- a/nfc/1.2/Android.bp
+++ b/nfc/1.2/Android.bp
@@ -22,4 +22,8 @@
         "android.hidl.base@1.0",
     ],
     gen_java: true,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.nfcservices",
+    ],
 }
diff --git a/nfc/aidl/Android.bp b/nfc/aidl/Android.bp
index 09a45d1..dae9f29 100644
--- a/nfc/aidl/Android.bp
+++ b/nfc/aidl/Android.bp
@@ -34,6 +34,16 @@
             sdk_version: "module_current",
             enabled: false,
         },
+	ndk: {
+            enabled: true,
+            apex_available: [
+                "//apex_available:platform",
+                "com.android.nfcservices",
+            ],
+        },
+        rust: {
+            enabled: true,
+        },
     },
     versions_with_info: [
         {
diff --git a/oemlock/1.0/vts/functional/OWNERS b/oemlock/1.0/vts/functional/OWNERS
deleted file mode 100644
index ec8c304..0000000
--- a/oemlock/1.0/vts/functional/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 186411
-chengyouho@google.com
-frankwoo@google.com
diff --git a/oemlock/OWNERS b/oemlock/OWNERS
new file mode 100644
index 0000000..5a5d074
--- /dev/null
+++ b/oemlock/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 186411
+
+chengyouho@google.com
+frankwoo@google.com
diff --git a/oemlock/aidl/vts/OWNERS b/oemlock/aidl/vts/OWNERS
deleted file mode 100644
index 40d95e4..0000000
--- a/oemlock/aidl/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-chengyouho@google.com
-frankwoo@google.com
diff --git a/power/aidl/Android.bp b/power/aidl/Android.bp
index 082572d..8900fb8 100644
--- a/power/aidl/Android.bp
+++ b/power/aidl/Android.bp
@@ -28,11 +28,20 @@
         "android/hardware/power/*.aidl",
     ],
     stability: "vintf",
+    imports: [
+        "android.hardware.common.fmq-V1",
+        "android.hardware.common-V2",
+    ],
     backend: {
         cpp: {
+            enabled: false,
+        },
+        ndk: {
             enabled: true,
         },
         java: {
+            sdk_version: "module_current",
+            enabled: true,
             platform_apis: true,
         },
     },
@@ -55,6 +64,44 @@
         },
 
     ],
-    frozen: true,
+    frozen: false,
 
 }
+
+cc_defaults {
+    name: "android.hardware.power-ndk_shared",
+    shared_libs: [
+        "android.hardware.power-V5-ndk",
+    ],
+}
+
+cc_defaults {
+    name: "android.hardware.power-ndk_export_shared",
+    shared_libs: [
+        "android.hardware.power-V5-ndk",
+    ],
+    export_shared_lib_headers: [
+        "android.hardware.power-V5-ndk",
+    ],
+}
+
+cc_defaults {
+    name: "android.hardware.power-ndk_static",
+    static_libs: [
+        "android.hardware.power-V5-ndk",
+    ],
+}
+
+java_defaults {
+    name: "android.hardware.power-java_shared",
+    libs: [
+        "android.hardware.power-V5-java",
+    ],
+}
+
+java_defaults {
+    name: "android.hardware.power-java_static",
+    static_libs: [
+        "android.hardware.power-V5-java",
+    ],
+}
diff --git a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/Boost.aidl b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/Boost.aidl
index c792d4e..8ee15ef 100644
--- a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/Boost.aidl
+++ b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/Boost.aidl
@@ -34,10 +34,10 @@
 package android.hardware.power;
 @Backing(type="int") @VintfStability
 enum Boost {
-  INTERACTION = 0,
-  DISPLAY_UPDATE_IMMINENT = 1,
-  ML_ACC = 2,
-  AUDIO_LAUNCH = 3,
-  CAMERA_LAUNCH = 4,
-  CAMERA_SHOT = 5,
+  INTERACTION,
+  DISPLAY_UPDATE_IMMINENT,
+  ML_ACC,
+  AUDIO_LAUNCH,
+  CAMERA_LAUNCH,
+  CAMERA_SHOT,
 }
diff --git a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/ChannelConfig.aidl b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/ChannelConfig.aidl
new file mode 100644
index 0000000..d3caca4
--- /dev/null
+++ b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/ChannelConfig.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.power;
+@VintfStability
+parcelable ChannelConfig {
+  android.hardware.common.fmq.MQDescriptor<android.hardware.power.ChannelMessage,android.hardware.common.fmq.SynchronizedReadWrite> channelDescriptor;
+  @nullable android.hardware.common.fmq.MQDescriptor<byte,android.hardware.common.fmq.SynchronizedReadWrite> eventFlagDescriptor;
+  int readFlagBitmask;
+  int writeFlagBitmask;
+}
diff --git a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/ChannelMessage.aidl b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/ChannelMessage.aidl
new file mode 100644
index 0000000..25f01c0
--- /dev/null
+++ b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/ChannelMessage.aidl
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.power;
+@FixedSize @VintfStability
+parcelable ChannelMessage {
+  int sessionID;
+  android.hardware.power.ChannelMessage.ChannelMessageContents data;
+  @FixedSize @VintfStability
+  union ChannelMessageContents {
+    int[20] tids = {(-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */, (-1) /* -1 */};
+    long targetDuration;
+    android.hardware.power.SessionHint hint;
+    android.hardware.power.ChannelMessage.ChannelMessageContents.SessionModeSetter mode;
+    android.hardware.power.WorkDurationFixedV1 workDuration;
+    @FixedSize @VintfStability
+    parcelable SessionModeSetter {
+      android.hardware.power.SessionMode modeInt;
+      boolean enabled;
+    }
+  }
+}
diff --git a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPower.aidl b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPower.aidl
index ae03313..8acdaf2 100644
--- a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPower.aidl
+++ b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPower.aidl
@@ -40,4 +40,7 @@
   boolean isBoostSupported(in android.hardware.power.Boost type);
   android.hardware.power.IPowerHintSession createHintSession(in int tgid, in int uid, in int[] threadIds, in long durationNanos);
   long getHintSessionPreferredRate();
+  android.hardware.power.IPowerHintSession createHintSessionWithConfig(in int tgid, in int uid, in int[] threadIds, in long durationNanos, in android.hardware.power.SessionTag tag, out android.hardware.power.SessionConfig config);
+  android.hardware.power.ChannelConfig getSessionChannel(in int tgid, in int uid);
+  oneway void closeSessionChannel(in int tgid, in int uid);
 }
diff --git a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPowerHintSession.aidl b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPowerHintSession.aidl
index e6809da..010f815 100644
--- a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPowerHintSession.aidl
+++ b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPowerHintSession.aidl
@@ -41,4 +41,6 @@
   oneway void close();
   oneway void sendHint(android.hardware.power.SessionHint hint);
   void setThreads(in int[] threadIds);
+  oneway void setMode(android.hardware.power.SessionMode type, boolean enabled);
+  android.hardware.power.SessionConfig getSessionConfig();
 }
diff --git a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/Mode.aidl b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/Mode.aidl
index f38426b..46eca69 100644
--- a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/Mode.aidl
+++ b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/Mode.aidl
@@ -34,21 +34,23 @@
 package android.hardware.power;
 @Backing(type="int") @VintfStability
 enum Mode {
-  DOUBLE_TAP_TO_WAKE = 0,
-  LOW_POWER = 1,
-  SUSTAINED_PERFORMANCE = 2,
-  FIXED_PERFORMANCE = 3,
-  VR = 4,
-  LAUNCH = 5,
-  EXPENSIVE_RENDERING = 6,
-  INTERACTIVE = 7,
-  DEVICE_IDLE = 8,
-  DISPLAY_INACTIVE = 9,
-  AUDIO_STREAMING_LOW_LATENCY = 10,
-  CAMERA_STREAMING_SECURE = 11,
-  CAMERA_STREAMING_LOW = 12,
-  CAMERA_STREAMING_MID = 13,
-  CAMERA_STREAMING_HIGH = 14,
-  GAME = 15,
-  GAME_LOADING = 16,
+  DOUBLE_TAP_TO_WAKE,
+  LOW_POWER,
+  SUSTAINED_PERFORMANCE,
+  FIXED_PERFORMANCE,
+  VR,
+  LAUNCH,
+  EXPENSIVE_RENDERING,
+  INTERACTIVE,
+  DEVICE_IDLE,
+  DISPLAY_INACTIVE,
+  AUDIO_STREAMING_LOW_LATENCY,
+  CAMERA_STREAMING_SECURE,
+  CAMERA_STREAMING_LOW,
+  CAMERA_STREAMING_MID,
+  CAMERA_STREAMING_HIGH,
+  GAME,
+  GAME_LOADING,
+  DISPLAY_CHANGE,
+  AUTOMOTIVE_PROJECTION,
 }
diff --git a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/SessionConfig.aidl b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/SessionConfig.aidl
new file mode 100644
index 0000000..b03cfb2
--- /dev/null
+++ b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/SessionConfig.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.power;
+@VintfStability
+parcelable SessionConfig {
+  long id;
+}
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 9c1f381..df31618 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
@@ -39,4 +39,7 @@
   CPU_LOAD_RESET = 2,
   CPU_LOAD_RESUME = 3,
   POWER_EFFICIENCY = 4,
+  GPU_LOAD_UP = 5,
+  GPU_LOAD_DOWN = 6,
+  GPU_LOAD_RESET = 7,
 }
diff --git a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/SessionMode.aidl b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/SessionMode.aidl
new file mode 100644
index 0000000..d0ae0ba
--- /dev/null
+++ b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/SessionMode.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.power;
+@Backing(type="int") @VintfStability
+enum SessionMode {
+  POWER_EFFICIENCY,
+}
diff --git a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/SessionTag.aidl b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/SessionTag.aidl
new file mode 100644
index 0000000..862fbc5
--- /dev/null
+++ b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/SessionTag.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.power;
+@Backing(type="int") @VintfStability
+enum SessionTag {
+  OTHER,
+  SURFACEFLINGER,
+  HWUI,
+  GAME,
+  APP,
+}
diff --git a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/WorkDuration.aidl b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/WorkDuration.aidl
index e86cd40..45013dd 100644
--- a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/WorkDuration.aidl
+++ b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/WorkDuration.aidl
@@ -36,4 +36,7 @@
 parcelable WorkDuration {
   long timeStampNanos;
   long durationNanos;
+  long workPeriodStartTimestampNanos;
+  long cpuDurationNanos;
+  long gpuDurationNanos;
 }
diff --git a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/WorkDurationFixedV1.aidl b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/WorkDurationFixedV1.aidl
new file mode 100644
index 0000000..8cd246d
--- /dev/null
+++ b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/WorkDurationFixedV1.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.power;
+@FixedSize @VintfStability
+parcelable WorkDurationFixedV1 {
+  long timeStampNanos;
+  long durationNanos;
+  long workPeriodStartTimestampNanos;
+  long cpuDurationNanos;
+  long gpuDurationNanos;
+}
diff --git a/power/aidl/android/hardware/power/ChannelConfig.aidl b/power/aidl/android/hardware/power/ChannelConfig.aidl
new file mode 100644
index 0000000..4da292e
--- /dev/null
+++ b/power/aidl/android/hardware/power/ChannelConfig.aidl
@@ -0,0 +1,52 @@
+
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.power;
+
+import android.hardware.common.fmq.MQDescriptor;
+import android.hardware.common.fmq.SynchronizedReadWrite;
+import android.hardware.power.ChannelMessage;
+
+@VintfStability
+parcelable ChannelConfig {
+    /**
+     * The message queue descriptor that provides the information necessary for
+     * a client to write to this channel.
+     */
+    MQDescriptor<ChannelMessage, SynchronizedReadWrite> channelDescriptor;
+
+    /**
+     * A message queue descriptor used to pass an optional event flag to clients,
+     * used to synchronize multiple message queues using the same flag. If not
+     * defined, the flag from the channelDescriptor should be used.
+     */
+    @nullable MQDescriptor<byte, SynchronizedReadWrite> eventFlagDescriptor;
+
+    /**
+     * The read flag bitmask to be used with the event flag, specifying the
+     * bits used by this channel to mark that the buffer has been read from.
+     * If set to 0, the default bitmask will be used.
+     */
+    int readFlagBitmask;
+
+    /**
+     * The write flag bitmask to be used with the event flag, specifying the
+     * bits used by this channel to mark that the buffer has been written to.
+     * If set to 0, the default bitmask will be used.
+     */
+    int writeFlagBitmask;
+}
diff --git a/power/aidl/android/hardware/power/ChannelMessage.aidl b/power/aidl/android/hardware/power/ChannelMessage.aidl
new file mode 100644
index 0000000..4747d90
--- /dev/null
+++ b/power/aidl/android/hardware/power/ChannelMessage.aidl
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.power;
+
+import android.hardware.power.SessionHint;
+import android.hardware.power.SessionMode;
+import android.hardware.power.WorkDurationFixedV1;
+
+/**
+ * Data sent through the FMQ must follow this structure. It's important to note
+ * that such data may come from the app itself, so the HAL must validate all
+ * data received through this interface, and reject any calls not guaranteed to be
+ * valid. Each of the types defined in the inner union maps to an equivalent call
+ * on IPowerHintSession, and is merely being used to expedite the use of that API
+ * in cases where it is safe to bypass the HintManagerService.
+ */
+@FixedSize
+@VintfStability
+parcelable ChannelMessage {
+    /**
+     * The ID of the specific session sending the hint, used to enable a single
+     * channel to be multiplexed across all sessions in a single process.
+     */
+    int sessionID;
+
+    /**
+     * A union defining the different messages that can be passed through the
+     * channel. Each type corresponds to a different call in IPowerHintSession.
+     */
+    ChannelMessageContents data;
+
+    @FixedSize
+    @VintfStability
+    union ChannelMessageContents {
+        /**
+         * List of TIDs for this session to change to. Can be used in cases
+         * where HintManagerService is not needed to validate the TIDs, such as
+         * when all TIDs directly belong to the process that owns the session.
+         */
+        int[20] tids = {
+                -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
+
+        /**
+         * Setting this field will update the session’s target duration, equivalent
+         * to calling updateTargetWorkDuration(targetDuration).
+         */
+        long targetDuration;
+
+        /**
+         * Setting this field will send a hint to the session, equivalent to
+         * calling sendHint(hint).
+         */
+        SessionHint hint;
+
+        /**
+         * Setting this field will send a hint to the session, equivalent to
+         * calling setMode(mode.modeInt, mode.enabled).
+         */
+        SessionModeSetter mode;
+
+        /**
+         * Setting this field will update the session’s actual duration, equivalent
+         * to calling reportActualWorkDuration([workDuration]). Only one duration
+         * can be passed at a time; this API expects durations to be reported
+         * immediately each frame, since the overhead of this call is much lower.
+         */
+        WorkDurationFixedV1 workDuration;
+
+        /**
+         * This structure is used to fit both the mode and the state within one
+         * entry in the union.
+         */
+        @FixedSize
+        @VintfStability
+        parcelable SessionModeSetter {
+            SessionMode modeInt;
+            boolean enabled;
+        }
+    }
+}
diff --git a/power/aidl/android/hardware/power/IPower.aidl b/power/aidl/android/hardware/power/IPower.aidl
index ee8e5a3..e25714f 100644
--- a/power/aidl/android/hardware/power/IPower.aidl
+++ b/power/aidl/android/hardware/power/IPower.aidl
@@ -17,8 +17,11 @@
 package android.hardware.power;
 
 import android.hardware.power.Boost;
+import android.hardware.power.ChannelConfig;
 import android.hardware.power.IPowerHintSession;
 import android.hardware.power.Mode;
+import android.hardware.power.SessionConfig;
+import android.hardware.power.SessionTag;
 
 @VintfStability
 interface IPower {
@@ -103,4 +106,42 @@
      *         EX_UNSUPPORTED_OPERATION if hint session is not supported.
      */
     long getHintSessionPreferredRate();
+
+    /**
+     * A version of createHintSession that returns an additional bundle of session
+     * data, useful to help the session immediately communicate via an FMQ channel
+     * for more efficient updates.
+     *
+     * @return  the new session if it is supported on this device, otherwise return
+     *          with EX_UNSUPPORTED_OPERATION error if hint session is not
+     *          supported on this device.
+     * @param   tgid The TGID to be associated with this session.
+     * @param   uid The UID to be associated with this session.
+     * @param   threadIds The list of threads to be associated with this session.
+     * @param   durationNanos The desired duration in nanoseconds for this session.
+     * @param   config Extra session metadata to be returned to the caller.
+     */
+    IPowerHintSession createHintSessionWithConfig(in int tgid, in int uid, in int[] threadIds,
+            in long durationNanos, in SessionTag tag, out SessionConfig config);
+
+    /**
+     * Used to get an FMQ channel, per-process. The channel should be unique to
+     * that process, and should return the same ChannelConfig if called multiple
+     * times from that same process.
+     *
+     * @return  the channel config if hint sessions are supported on this device,
+     *          otherwise return with EX_UNSUPPORTED_OPERATION.
+     * @param   tgid The TGID to be associated with this channel.
+     * @param   uid The UID to be associated with this channel.
+     */
+    ChannelConfig getSessionChannel(in int tgid, in int uid);
+
+    /**
+     * Used to close a channel once it is no longer needed by a process, or that
+     * process dies.
+     *
+     * @param   tgid The TGID to be associated with this channel.
+     * @param   uid The UID to be associated with this channel.
+     */
+    oneway void closeSessionChannel(in int tgid, in int uid);
 }
diff --git a/power/aidl/android/hardware/power/IPowerHintSession.aidl b/power/aidl/android/hardware/power/IPowerHintSession.aidl
index 7db0ea1..9dd251f 100644
--- a/power/aidl/android/hardware/power/IPowerHintSession.aidl
+++ b/power/aidl/android/hardware/power/IPowerHintSession.aidl
@@ -16,7 +16,9 @@
 
 package android.hardware.power;
 
+import android.hardware.power.SessionConfig;
 import android.hardware.power.SessionHint;
+import android.hardware.power.SessionMode;
 import android.hardware.power.WorkDuration;
 
 @VintfStability
@@ -81,4 +83,20 @@
      *    must be thrown.
      */
     void setThreads(in int[] threadIds);
+
+    /**
+     * Called to enable or disable special modes for the hint session, which may
+     * adjust the power or performance of the session.
+     *
+     * @param type The mode being set
+     * @param enabled True to enable the mode, false to disable it
+     */
+    oneway void setMode(SessionMode type, boolean enabled);
+
+    /**
+     * This method provides direct access to a session's config data.
+     *
+     * @return  the config data for this session
+     */
+    SessionConfig getSessionConfig();
 }
diff --git a/power/aidl/android/hardware/power/Mode.aidl b/power/aidl/android/hardware/power/Mode.aidl
index cc4b130..a8fba72 100644
--- a/power/aidl/android/hardware/power/Mode.aidl
+++ b/power/aidl/android/hardware/power/Mode.aidl
@@ -134,11 +134,6 @@
     DISPLAY_INACTIVE,
 
     /**
-     * Below hints are currently not sent in Android framework but OEM might choose to
-     * implement for power/perf optimizations.
-     */
-
-    /**
      * This mode indicates that low latency audio is active.
      */
     AUDIO_STREAMING_LOW_LATENCY,
@@ -172,4 +167,16 @@
      * This mode indicates that the user is waiting for loading in a game.
      */
     GAME_LOADING,
+
+    /**
+     * This mode indicates that the display layout is changing due to rotation
+     * or switching between inner and outer panels.
+     */
+    DISPLAY_CHANGE,
+
+    /**
+     * This mode indicates that the device is rendering to a remote display in
+     * a vehicle (such as Android Auto projection screen).
+     */
+    AUTOMOTIVE_PROJECTION,
 }
diff --git a/power/aidl/android/hardware/power/SessionConfig.aidl b/power/aidl/android/hardware/power/SessionConfig.aidl
new file mode 100644
index 0000000..93dc9a2
--- /dev/null
+++ b/power/aidl/android/hardware/power/SessionConfig.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.power;
+
+/**
+ * Additional session to be passed to the hint session during creation, or acquired
+ * after creation from the session directly.
+ */
+@VintfStability
+parcelable SessionConfig {
+    /**
+     * The session's unique ID, used to identify the session for debugging and
+     * for multiplexing on the per-process FMQ channel.
+     */
+    long id;
+}
diff --git a/power/aidl/android/hardware/power/SessionHint.aidl b/power/aidl/android/hardware/power/SessionHint.aidl
index a172e12..1a8c505 100644
--- a/power/aidl/android/hardware/power/SessionHint.aidl
+++ b/power/aidl/android/hardware/power/SessionHint.aidl
@@ -52,4 +52,24 @@
      * power hint session is noncritical despite its CPU intensity.
      */
     POWER_EFFICIENCY = 4,
+
+    /**
+     * This hint indicates an increase in GPU workload intensity. It means that
+     * this hint session needs extra GPU resources to meet the target duration.
+     * This hint must be sent before reporting the actual duration to the session.
+     */
+    GPU_LOAD_UP = 5,
+
+    /**
+     * This hint indicates a decrease in GPU workload intensity. It means that
+     * this hint session can reduce GPU resources and still meet the target duration.
+     */
+    GPU_LOAD_DOWN = 6,
+
+    /**
+     * This hint indicates an upcoming GPU workload that is completely changed and
+     * unknown. It means that the hint session should reset GPU resources to a known
+     * baseline to prepare for an arbitrary load, and must wake up if inactive.
+     */
+    GPU_LOAD_RESET = 7,
 }
diff --git a/power/aidl/android/hardware/power/SessionMode.aidl b/power/aidl/android/hardware/power/SessionMode.aidl
new file mode 100644
index 0000000..f1ee64e
--- /dev/null
+++ b/power/aidl/android/hardware/power/SessionMode.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.power;
+
+@VintfStability
+@Backing(type="int")
+enum SessionMode {
+    /**
+     * This mode indicates that the work of this hint session is not
+     * critical to perceived performance, despite its CPU intensity,
+     * and can be safely scheduled to prefer power efficiency.
+     */
+    POWER_EFFICIENCY,
+}
diff --git a/power/aidl/android/hardware/power/SessionTag.aidl b/power/aidl/android/hardware/power/SessionTag.aidl
new file mode 100644
index 0000000..27bf3e3
--- /dev/null
+++ b/power/aidl/android/hardware/power/SessionTag.aidl
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.power;
+
+@VintfStability
+@Backing(type="int")
+enum SessionTag {
+    /**
+     * This tag is used to mark uncategorized hint sessions.
+     */
+    OTHER,
+
+    /**
+     * This tag is used to mark the SurfaceFlinger hint session.
+     */
+    SURFACEFLINGER,
+
+    /**
+     * This tag is used to mark hint sessions created by HWUI.
+     */
+    HWUI,
+
+    /**
+     * This tag is used to mark hint sessions created by applications that are
+     * categorized as games.
+     */
+    GAME,
+
+    /**
+     * This tag is used to mark the hint session is created by the application.
+     * If an applications is categorized as game, then GAME should be used
+     * instead.
+     */
+    APP,
+}
diff --git a/power/aidl/android/hardware/power/WorkDuration.aidl b/power/aidl/android/hardware/power/WorkDuration.aidl
index a06a058..fcd638b 100644
--- a/power/aidl/android/hardware/power/WorkDuration.aidl
+++ b/power/aidl/android/hardware/power/WorkDuration.aidl
@@ -23,8 +23,30 @@
      * sample was measured.
      */
     long timeStampNanos;
+
     /**
-     * Work duration in nanoseconds.
+     * Total work duration in nanoseconds.
      */
     long durationNanos;
+
+    /**
+     * Timestamp in nanoseconds based on CLOCK_MONOTONIC when the work starts.
+     * The work period start timestamp could be zero if the call is from
+     * the legacy SDK/NDK reportActualWorkDuration API.
+     */
+    long workPeriodStartTimestampNanos;
+
+    /**
+     * CPU work duration in nanoseconds.
+     * The CPU work duration could be the same as the total work duration if
+     * the call is from the legacy SDK/NDK reportActualWorkDuration API.
+     */
+    long cpuDurationNanos;
+
+    /**
+     * GPU work duration in nanoseconds.
+     * The GPU work duration could be zero if the call is from the legacy
+     * SDK/NDK reportActualWorkDuration API.
+     */
+    long gpuDurationNanos;
 }
diff --git a/power/aidl/android/hardware/power/WorkDurationFixedV1.aidl b/power/aidl/android/hardware/power/WorkDurationFixedV1.aidl
new file mode 100644
index 0000000..2d202ff
--- /dev/null
+++ b/power/aidl/android/hardware/power/WorkDurationFixedV1.aidl
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.power;
+
+@FixedSize
+@VintfStability
+parcelable WorkDurationFixedV1 {
+    /**
+     * Timestamp in nanoseconds based on CLOCK_MONOTONIC when the duration
+     * sample was measured.
+     */
+    long timeStampNanos;
+
+    /**
+     * Total work duration in nanoseconds.
+     */
+    long durationNanos;
+
+    /**
+     * Timestamp in nanoseconds based on CLOCK_MONOTONIC when the work starts.
+     * The work period start timestamp could be zero if the call is from
+     * the legacy SDK/NDK reportActualWorkDuration API.
+     */
+    long workPeriodStartTimestampNanos;
+
+    /**
+     * CPU work duration in nanoseconds.
+     * The CPU work duration could be the same as the total work duration if
+     * the call is from the legacy SDK/NDK reportActualWorkDuration API.
+     */
+    long cpuDurationNanos;
+
+    /**
+     * GPU work duration in nanoseconds.
+     * The GPU work duration could be zero if the call is from the legacy
+     * SDK/NDK reportActualWorkDuration API.
+     */
+    long gpuDurationNanos;
+}
diff --git a/power/aidl/default/Android.bp b/power/aidl/default/Android.bp
index da91ee6..b4ccc7d 100644
--- a/power/aidl/default/Android.bp
+++ b/power/aidl/default/Android.bp
@@ -23,14 +23,18 @@
 
 cc_binary {
     name: "android.hardware.power-service.example",
+    defaults: ["android.hardware.power-ndk_shared"],
     relative_install_path: "hw",
     init_rc: [":android.hardware.power.rc"],
     vintf_fragments: [":android.hardware.power.xml"],
     vendor: true,
     shared_libs: [
+        "android.hardware.common-V2-ndk",
+        "android.hardware.common.fmq-V1-ndk",
         "libbase",
         "libbinder_ndk",
-        "android.hardware.power-V4-ndk",
+        "libcutils",
+        "libfmq",
     ],
     srcs: [
         "main.cpp",
@@ -39,9 +43,11 @@
     ],
 }
 
-filegroup {
+prebuilt_etc {
     name: "android.hardware.power.xml",
-    srcs: ["power-default.xml"],
+    src: "power-default.xml",
+    sub_dir: "vintf",
+    installable: false,
 }
 
 filegroup {
diff --git a/power/aidl/default/Power.cpp b/power/aidl/default/Power.cpp
index 8fe370c..8f15663 100644
--- a/power/aidl/default/Power.cpp
+++ b/power/aidl/default/Power.cpp
@@ -18,6 +18,8 @@
 #include "PowerHintSession.h"
 
 #include <android-base/logging.h>
+#include <fmq/AidlMessageQueue.h>
+#include <fmq/EventFlag.h>
 
 namespace aidl {
 namespace android {
@@ -27,6 +29,10 @@
 namespace example {
 
 using namespace std::chrono_literals;
+using ::aidl::android::hardware::common::fmq::MQDescriptor;
+using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using ::aidl::android::hardware::power::ChannelMessage;
+using ::android::AidlMessageQueue;
 
 using ndk::ScopedAStatus;
 
@@ -70,6 +76,27 @@
     return ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus Power::createHintSessionWithConfig(
+        int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, int64_t durationNanos,
+        SessionTag, SessionConfig* config, std::shared_ptr<IPowerHintSession>* _aidl_return) {
+    auto out = createHintSession(tgid, uid, threadIds, durationNanos, _aidl_return);
+    static_cast<PowerHintSession*>(_aidl_return->get())->getSessionConfig(config);
+    return out;
+}
+
+ndk::ScopedAStatus Power::getSessionChannel(int32_t, int32_t, ChannelConfig* _aidl_return) {
+    static AidlMessageQueue<ChannelMessage, SynchronizedReadWrite> stubQueue{1, true};
+    _aidl_return->channelDescriptor = stubQueue.dupeDesc();
+    _aidl_return->readFlagBitmask = 0;
+    _aidl_return->writeFlagBitmask = 0;
+    _aidl_return->eventFlagDescriptor = std::nullopt;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Power::closeSessionChannel(int32_t, int32_t) {
+    return ndk::ScopedAStatus::ok();
+}
+
 ScopedAStatus Power::getHintSessionPreferredRate(int64_t* outNanoseconds) {
     *outNanoseconds = std::chrono::nanoseconds(1ms).count();
     return ScopedAStatus::ok();
diff --git a/power/aidl/default/Power.h b/power/aidl/default/Power.h
index 7f8405e..baabaa7 100644
--- a/power/aidl/default/Power.h
+++ b/power/aidl/default/Power.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <aidl/android/hardware/power/BnPower.h>
+#include "aidl/android/hardware/power/SessionTag.h"
 
 namespace aidl {
 namespace android {
@@ -35,7 +36,14 @@
                                          const std::vector<int32_t>& threadIds,
                                          int64_t durationNanos,
                                          std::shared_ptr<IPowerHintSession>* _aidl_return) override;
+    ndk::ScopedAStatus createHintSessionWithConfig(
+            int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, int64_t durationNanos,
+            SessionTag tag, SessionConfig* config,
+            std::shared_ptr<IPowerHintSession>* _aidl_return) override;
     ndk::ScopedAStatus getHintSessionPreferredRate(int64_t* outNanoseconds) override;
+    ndk::ScopedAStatus getSessionChannel(int32_t tgid, int32_t uid,
+                                         ChannelConfig* _aidl_return) override;
+    ndk::ScopedAStatus closeSessionChannel(int32_t tgid, int32_t uid) override;
 
   private:
     std::vector<std::shared_ptr<IPowerHintSession>> mPowerHintSessions;
diff --git a/power/aidl/default/PowerHintSession.cpp b/power/aidl/default/PowerHintSession.cpp
index f395800..847a42e 100644
--- a/power/aidl/default/PowerHintSession.cpp
+++ b/power/aidl/default/PowerHintSession.cpp
@@ -17,6 +17,7 @@
 #include "PowerHintSession.h"
 
 #include <android-base/logging.h>
+#include "android/binder_auto_utils.h"
 
 namespace aidl::android::hardware::power::impl::example {
 
@@ -59,4 +60,13 @@
     return ScopedAStatus::ok();
 }
 
+ScopedAStatus PowerHintSession::setMode(SessionMode /* mode */, bool /* enabled */) {
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus PowerHintSession::getSessionConfig(SessionConfig* _aidl_return) {
+    _aidl_return->id = 1;
+    return ScopedAStatus::ok();
+}
+
 }  // namespace aidl::android::hardware::power::impl::example
diff --git a/power/aidl/default/PowerHintSession.h b/power/aidl/default/PowerHintSession.h
index 1d74716..2ed5588 100644
--- a/power/aidl/default/PowerHintSession.h
+++ b/power/aidl/default/PowerHintSession.h
@@ -18,6 +18,7 @@
 
 #include <aidl/android/hardware/power/BnPowerHintSession.h>
 #include <aidl/android/hardware/power/SessionHint.h>
+#include <aidl/android/hardware/power/SessionMode.h>
 #include <aidl/android/hardware/power/WorkDuration.h>
 
 namespace aidl::android::hardware::power::impl::example {
@@ -33,6 +34,8 @@
     ndk::ScopedAStatus close() override;
     ndk::ScopedAStatus sendHint(SessionHint hint) override;
     ndk::ScopedAStatus setThreads(const std::vector<int32_t>& threadIds) override;
+    ndk::ScopedAStatus setMode(SessionMode mode, bool enabled) override;
+    ndk::ScopedAStatus getSessionConfig(SessionConfig* _aidl_return) override;
 };
 
 }  // namespace aidl::android::hardware::power::impl::example
diff --git a/power/aidl/default/apex/Android.bp b/power/aidl/default/apex/Android.bp
index eb04087..a21901f 100644
--- a/power/aidl/default/apex/Android.bp
+++ b/power/aidl/default/apex/Android.bp
@@ -16,17 +16,6 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-apex_key {
-    name: "com.android.hardware.power.key",
-    public_key: "com.android.hardware.power.avbpubkey",
-    private_key: "com.android.hardware.power.pem",
-}
-
-android_app_certificate {
-    name: "com.android.hardware.power.certificate",
-    certificate: "com.android.hardware.power",
-}
-
 genrule {
     name: "com.android.hardware.power.rc-srcs",
     srcs: [
@@ -34,7 +23,7 @@
         ":android.hardware.power.stats.rc",
     ],
     out: ["com.android.hardware.power.rc"],
-    cmd: "sed -E 's/\\/vendor/\\/apex\\/com.android.hardware.power/' $(in) > $(out)",
+    cmd: "sed -E 's@/vendor/bin/@/apex/com.android.hardware.power/bin/@' $(in) > $(out)",
 }
 
 prebuilt_etc {
@@ -46,13 +35,12 @@
 apex {
     name: "com.android.hardware.power",
     manifest: "apex_manifest.json",
-    key: "com.android.hardware.power.key",
-    certificate: ":com.android.hardware.power.certificate",
+    key: "com.android.hardware.key",
+    certificate: ":com.android.hardware.certificate",
     file_contexts: "file_contexts",
-    use_vndk_as_stable: true,
     updatable: false,
-    // Install the apex in /vendor/apex
-    soc_specific: true,
+    vendor: true,
+
     // Bundle the Power and PowerStats HALs into this one APEX.
     binaries: [
         "android.hardware.power-service.example",
@@ -60,10 +48,8 @@
     ],
     prebuilts: [
         "com.android.hardware.power.rc",
-    ],
-    vintf_fragments: [
-        ":android.hardware.power.xml",
-        ":android.hardware.power.stats.xml",
+        "android.hardware.power.xml",
+        "android.hardware.power.stats.xml",
     ],
     overrides: [
         // Shared lib installed by default but unused by the AIDL implementation.
diff --git a/power/aidl/default/apex/com.android.hardware.power.avbpubkey b/power/aidl/default/apex/com.android.hardware.power.avbpubkey
deleted file mode 100644
index 3b6411d..0000000
--- a/power/aidl/default/apex/com.android.hardware.power.avbpubkey
+++ /dev/null
Binary files differ
diff --git a/power/aidl/default/apex/com.android.hardware.power.pem b/power/aidl/default/apex/com.android.hardware.power.pem
deleted file mode 100644
index d18ae98..0000000
--- a/power/aidl/default/apex/com.android.hardware.power.pem
+++ /dev/null
@@ -1,51 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIIJKQIBAAKCAgEAsUdFjtLq05tWKdQd4aj8V7tmV4KXw41pKGT5Q1CPzrdHF3yJ
-B/8VWdMpjZ+eQO1q8SijPgfvWExeWQVMfxKmwTmj26xWXhIOgo5G02Zva7zOptig
-KGnl/RdFlOiIGC36XeWDhzdIOhlGv+er9Sykf6Ot84OvktTBUTZNJrXQsyYTBRUX
-6B+wloPdBVxVf1HgzjeHUyCy5dTz0xZSWWELoW24tHIvV5FtJVKSY8ZDfuXWLLfT
-he7E93TepjT027U/J/iW4ITJzw4Qq87ick1D/jZDUbTrkqUMFEgPdgCouZ9zt5xG
-pcHAZ/Fcz9DZfEdX9Xy0R5/XbfrJdvDPguJlwK1pZnr/Pe13xxmE+TEohMmaQDqX
-jQNX3UlcfOYUAjnFMGucHDM10KjTMbP8ytCys88aNLiv7FOgVGrQ/djZN8rkMyVP
-ccoksUBMQmjYaQQZ2yZuJMiLD3P6aYkgU5tMEMoMTrBzfcx05GfElal+ZqOFKAzj
-eUxoZTR27wJb684FRbeE45D+y4jpFfrTEXry+aI7GrfDsVDnUqmyObCUttRtaT04
-6kuUmC44wFEg1EBfcWZc1szI192GBjMuZjFcYvJ4vMdCuennqvLNPBDY1PtqzCOf
-D8vpOE3T9rjS23xxFmmSmorwKKQOGChKqO/SaY0axkXgt+FbSsvTBQtZTSsCAwEA
-AQKCAgEArEu3t+MYJcdwS8EDtcF2V5IkGmMrOvziOkdA14Kh8efBKXt49xOc3atU
-VHfQ6AuXh4DWf0BZB7lZbS2wNkSbW2q47ZSmcFEeVxcOkQGawtxDAHfD2ONrirqm
-ft4s/0sYbU/WsIEzKnxMfdEdGHFmA0PCmczfxFYQ+OxMuZW1m5ginirtDEZYa0EH
-e+FMmyypz+K6HDnIhYWd4Aduy718/0zTWlUr2/DUYpTJAD2+dcPNj7Kt2xq/xj2I
-84K+hBa4phF+GgIU3a8u1ryA61RbA+QbM3siBWlxvvh2RlrHoXjuj4JMS2dup9c2
-PCggaCAyxb2IvaAFUbePPJE5LVz6RFT4HnLEydd5Yt+CEAm+iZKfCzyUgFRtb5y0
-HHTME1eVAt/rf/yIXUYA7q8nQ/PtSzIol5KLX4FUjX1MVKNmIWMa+836kxbuYDFB
-K1M1IKc1k0t9Q9F3TRCMhP/6qH/vJfubCGQhSRUMq7JyjivK9GjYST8R07Dpgu9Z
-4i9TRI8d+UVERsg8niCXONVkmNa3U49u2duUvqV3KmKgQ/Hgyy3keDjz6x56ie5w
-e0EusHAsot60W1BvHrdwlmGZjW3JmZEyazUPh9nBUAaQve1rIOpn80kGXx4EAE2o
-HcrcInJx/zVBk1Wk3UQDwmhUNpa64q9+nd9VMaR9SQNK3ah4NDECggEBAOeput2F
-CgRrvzka69i7FbgY4VmpNMIICPIB6gxvwpir/g4/GgYknuBB6ep1ksf/IZfsMp5A
-JTH1KdXqqQm8nV9v+ETYQAO+VnmWKSBKHsNJqONxsKkQ+xIJcusmKBTYLfL88XQg
-YWH3VMXgqPP8DnJYCeVRIKj1WqfEFFHiaLJJB8FgKhtZBwBnibkVG1K0XCkTdUfY
-mME2GRKW/C7DMvuFOpcFVj7Obwn68R2k3zsOhWA5NQGZF5mqhg5KYLVDg3IbMJQQ
-D+DymQxnc2s2ar0q24isy1Y/FOXrA057j1vAN951+pk6F/PCJM/mtAiRjhP0Aru1
-P6bbR11p+wnpU7MCggEBAMPm8Jmwu3F0xsyFC+1sWPAzPiwaMa7/30wANNKKqHVO
-7lUv1WYFbFMyAOzYPp3Y5HxdxNa43reULGk0R20kSu6W6FkApSvAws0rLKRlS5UI
-oZqhLGHUH2M7q07m2RgQY2TJkU2Zq6AH1kjcbSr127ISXKanKpqonwSHy38BTcGt
-Dl2fVioPzK/vwmiNo2njhh95TV4kqlbUfl7xtDt56tbg8oFBwOsK7UGajXYOxTGB
-o1DtO5E+oiOmlclXuo3m4qpSSMv+wM91aRFhHZVIx0vmO8y5lrfU2kM/5DDhJBxV
-FM4TaA+c5tFOTuCLejHc7nM99wVx7O4QZ0wBwETUxKkCggEAH0tBT+1J1iEL+tXV
-KDjVjUHnJyqBUvis5Kw3hqiOO/t33UrO5CeMQrUEuURaqKOhURl6GQCHRcFdfmUt
-ooAVLjA89GfV9et/WPtc4NzCXRUVOGxCNgRyNhSKrpM/9NjjFCDxKQO6w/YaQITB
-rfvNo8qaw5x68ff64BDPweP4yqSs5IVuCrWzCW3zH8pnH3v3uyDCxgrPT8JUDrvQ
-oyyBNZLgwEfbR66xN0Lr0VpVQXALulzf+TBKDNsJMuL/P104Y3Ci1k15J6T94bwT
-zlbSgm1IrKTS7vqkgw6FKtPsILPNmEKNsKc1VxtRx7fdeA7Zh3595Adu6sZSVJ8d
-Z1BamwKCAQAnbu0vgqu4gtEhigaEnDKq5yW0qvElUMwZ+FCpsM+IDYNcEmzaRG0x
-sfcNtdmk3GvhvN5KepwaR/FInAVkqtGKhUXv5Hla/Uo5El/CF8HHFh2xio/sgU5w
-IyqwjzdT6LiZKRnejPhHFkzEDdrLswGuLpQH185zo02fE9aakiCcw8EIh3JItTV2
-lMSFVz11qx7sZvZz5N2E7PEjG3Q0JK5o4o7uBdZXebOYaQvgn8iB1p6RQ6+h5QGu
-O3IbPVWICtnFfxq4NWeKWw/zN6FE04mKdaXD5/e2uVnV/55nWGp0aYvuj2l6+xJb
-P3ARMwI910MIX4jBx9TxdsvUOOYC9PFBAoIBAQDWswLnaNth4pgutngVWbMenSpv
-eK1RA1ldw2NoTZrGlqPB+LvjEMSH/7ioby8YtOyJRIWs3si8HpVF12qneu8qi7b7
-QlUtqyJOTnGalvhrlq5zPhdW+kk2DXvtTylUnz3vSxxi2I7cLhQRryLC/1kAwy67
-wEr0+u59bOvaqe8L1zgtYJpLQZeskUMzdSMIRVDdFShEFrMJU7adUvGpA7OZ6Ogf
-ux2jWr2vv/eKq6fU6kDPi/66MQjPbZPf2Uq6+XedkNkAeELpN4o3hw0/l/rfiK/r
-YUMJBwtjQw/hehtvC4GlgsH1tMZWzCZULo0tcW4qbzyi9PBrWFPteb33OjBc
------END RSA PRIVATE KEY-----
diff --git a/power/aidl/default/apex/com.android.hardware.power.pk8 b/power/aidl/default/apex/com.android.hardware.power.pk8
deleted file mode 100644
index e45435d..0000000
--- a/power/aidl/default/apex/com.android.hardware.power.pk8
+++ /dev/null
Binary files differ
diff --git a/power/aidl/default/apex/com.android.hardware.power.x509.pem b/power/aidl/default/apex/com.android.hardware.power.x509.pem
deleted file mode 100644
index 9f0c5f0..0000000
--- a/power/aidl/default/apex/com.android.hardware.power.x509.pem
+++ /dev/null
@@ -1,34 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIF2TCCA8ECFDFsXbm5CdS/UtQZgTiF8Umr8LrLMA0GCSqGSIb3DQEBCwUAMIGn
-MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91
-bnRhaW4gVmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UECwwHQW5kcm9pZDEi
-MCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTEjMCEGA1UEAwwaY29t
-LmFuZHJvaWQuaGFyZHdhcmUucG93ZXIwIBcNMjExMDIwMTcwNTA0WhgPNDc1OTA5
-MTYxNzA1MDRaMIGnMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEW
-MBQGA1UEBwwNTW91bnRhaW4gVmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UE
-CwwHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTEj
-MCEGA1UEAwwaY29tLmFuZHJvaWQuaGFyZHdhcmUucG93ZXIwggIiMA0GCSqGSIb3
-DQEBAQUAA4ICDwAwggIKAoICAQC/37fhOkOfgM2e+M7bMJ1baLFif8dKGwRa6mkJ
-9HWmuOgRcTKllzuEHtrJ0jzur3cDy6/0oZSfA/E1ck3DdRHMQadW26JSNSg6fCU9
-h1kDzkakZgyr3DsJnKGoSHCJ2V2kVbCnd6GuOaOU1ZZISw1I+BWJDc3t1mZPs80D
-ar7/hoIZnsWRoE/eWgJDcWWscRsquSi+q6hyqlCbRvwRznPaDGwmb4geHNugCXkz
-EtCswfc5jiT8DjMDkgVsGO/WcYj2GWT0K0H+Zf1CmEO9fAoXTLfVBjdumtGILgii
-d/TJe2tOBSWyZz6sVzfac2PvUH5Lm8TNUXuLV5IEdcpySge0vqYQwAyd2EgsTH1e
-mRNSk9NerpmfCFEySRRP3BWMGRhbST1d8M3v9Bq0QFhrxoAF12r6GXBUpp9XcOL5
-pBTcAkA9XI++mfz4pDzyGRGOy4WX+8XtsaVZ/14JklupSLr0Tt7oaNocUhoXB03g
-4B0jUTX0hNnVzCxzJypw6YJ60Zc8z+z8pEF34FWarHec1QbkFuyWxbaTPQ4d2NLH
-8zDxQpMILErWdAgKsRL0d8RFG5fBcleEoBM2kKHMAgnP+1qyDqBgt8zloWbmmblw
-JXMuoePFOgeVcgPrZ3EGJSx+s4+dQGQc6r/GwKLKSWpUvHxTIGug76IX9xmptB+I
-F3xb2QIDAQABMA0GCSqGSIb3DQEBCwUAA4ICAQANISf3Vi2eueOlzzfnEGGa+CXz
-nvlgUXKv8Gv0/Pbg5uC1BaHTAUgRu5rvrfP9p3Mdj86I/HbE/F4Vkuzqb8/JTWGA
-mG636zAsJRJr0fnkbPma9wVEPSK8MF1QqM6PmKXboixX82TqV1R1sRYG+9hh9W3u
-isDzYDb2ODE0X9M8/3hLS28zdCdtl4zCRK6KB86aGxvkVEj4qDA5l+AbVYevS/SU
-hz1+K/aM0Fi6MZovo5kd/Mof5l05e1TEgCoL1FtFX79r+PYGHJ8/LjtEMkFgwqvG
-CLx2sOV09EHZU27EbVvSs1JYMMXgeAvKaHsVZ51QlSzW4esg/E6z4pw654p8qyK/
-WLXIZ7BMILl1sHYmGqXitnu19puvNks2/+hyqVr0seM5GyQDuwBE8nx6xZzTRxdj
-4TZyN9LuMc9/cKJFvOPqD152bkA2frCLEzYCQreDWwxsWcUHzYrQT+v2SqzP6Ue2
-Xn06HDLx9wBL7Dz6no05SlNS0u1KdvKas6FKZHO+QaKKsBlDmXbMrBTcuUI6OXv2
-6NpVbeyDd0+A23hDiNSgI6zTY6jMidesNExB7rW/bCE4ltPyxFAB+sffyXounODc
-groB5CaS2bv+H1IXJzMMe4LkgQPl1C7G+I3KvJmnrYwmIhLIDuxP82arClIDzccS
-ExRR7ugEg91XCc87Zg==
------END CERTIFICATE-----
diff --git a/power/aidl/default/apex/file_contexts b/power/aidl/default/apex/file_contexts
index 3433851..3b7526a 100644
--- a/power/aidl/default/apex/file_contexts
+++ b/power/aidl/default/apex/file_contexts
@@ -1,3 +1,4 @@
 (/.*)?                                                      u:object_r:vendor_file:s0
+/etc(/.*)?                                                  u:object_r:vendor_configs_file:s0
 /bin/hw/android\.hardware\.power-service\.example           u:object_r:hal_power_default_exec:s0
 /bin/hw/android\.hardware\.power\.stats-service\.example    u:object_r:hal_power_stats_default_exec:s0
diff --git a/power/aidl/default/power-default.xml b/power/aidl/default/power-default.xml
index f5dd6b9..418fb83 100644
--- a/power/aidl/default/power-default.xml
+++ b/power/aidl/default/power-default.xml
@@ -1,7 +1,7 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.power</name>
-        <version>4</version>
+        <version>5</version>
         <fqname>IPower/default</fqname>
     </hal>
 </manifest>
diff --git a/power/aidl/vts/Android.bp b/power/aidl/vts/Android.bp
index 56c98bd..c9285f4 100644
--- a/power/aidl/vts/Android.bp
+++ b/power/aidl/vts/Android.bp
@@ -26,13 +26,16 @@
     defaults: [
         "VtsHalTargetTestDefaults",
         "use_libaidlvintf_gtest_helper_static",
+        "android.hardware.power-ndk_static",
     ],
     srcs: ["VtsHalPowerTargetTest.cpp"],
     shared_libs: [
         "libbinder_ndk",
+        "libfmq",
     ],
     static_libs: [
-        "android.hardware.power-V4-ndk",
+        "android.hardware.common.fmq-V1-ndk",
+        "android.hardware.common-V2-ndk",
     ],
     test_suites: [
         "general-tests",
diff --git a/power/aidl/vts/VtsHalPowerTargetTest.cpp b/power/aidl/vts/VtsHalPowerTargetTest.cpp
index c2216f8..d8e73bf 100644
--- a/power/aidl/vts/VtsHalPowerTargetTest.cpp
+++ b/power/aidl/vts/VtsHalPowerTargetTest.cpp
@@ -24,19 +24,31 @@
 #include <android/binder_process.h>
 #include <android/binder_status.h>
 
+#include <fmq/AidlMessageQueue.h>
+#include <fmq/EventFlag.h>
+
 #include <unistd.h>
+#include <cstdint>
+#include "aidl/android/hardware/common/fmq/SynchronizedReadWrite.h"
+#include "fmq/EventFlag.h"
 
 namespace aidl::android::hardware::power {
 namespace {
 
-using ::android::base::GetUintProperty;
+using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using ::android::AidlMessageQueue;
 using android::hardware::power::Boost;
+using android::hardware::power::ChannelConfig;
+using android::hardware::power::ChannelMessage;
 using android::hardware::power::IPower;
 using android::hardware::power::IPowerHintSession;
 using android::hardware::power::Mode;
 using android::hardware::power::SessionHint;
+using android::hardware::power::SessionMode;
 using android::hardware::power::WorkDuration;
 
+using SessionMessageQueue = AidlMessageQueue<ChannelMessage, SynchronizedReadWrite>;
+
 const std::vector<Boost> kBoosts{ndk::enum_range<Boost>().begin(), ndk::enum_range<Boost>().end()};
 
 const std::vector<Mode> kModes{ndk::enum_range<Mode>().begin(), ndk::enum_range<Mode>().end()};
@@ -44,6 +56,9 @@
 const std::vector<SessionHint> kSessionHints{ndk::enum_range<SessionHint>().begin(),
                                              ndk::enum_range<SessionHint>().end()};
 
+const std::vector<SessionMode> kSessionModes{ndk::enum_range<SessionMode>().begin(),
+                                             ndk::enum_range<SessionMode>().end()};
+
 const std::vector<Boost> kInvalidBoosts = {
         static_cast<Boost>(static_cast<int32_t>(kBoosts.front()) - 1),
         static_cast<Boost>(static_cast<int32_t>(kBoosts.back()) + 1),
@@ -59,6 +74,11 @@
         static_cast<SessionHint>(static_cast<int32_t>(kSessionHints.back()) + 1),
 };
 
+const std::vector<SessionMode> kInvalidSessionModes = {
+        static_cast<SessionMode>(static_cast<int32_t>(kSessionModes.front()) - 1),
+        static_cast<SessionMode>(static_cast<int32_t>(kSessionModes.back()) + 1),
+};
+
 class DurationWrapper : public WorkDuration {
   public:
     DurationWrapper(int64_t dur, int64_t time) {
@@ -73,8 +93,6 @@
 
 const std::vector<int32_t> kEmptyTids = {};
 
-const std::vector<WorkDuration> kNoDurations = {};
-
 const std::vector<WorkDuration> kDurationsWithZero = {
         DurationWrapper(1000L, 1L),
         DurationWrapper(0L, 2L),
@@ -92,36 +110,33 @@
         DurationWrapper(1000000000L, 4L),
 };
 
-// DEVICEs launching with Android 11 MUST meet the requirements for the
-// target-level=5 compatibility_matrix file.
-const uint64_t kCompatibilityMatrix5ApiLevel = 30;
-
-// DEVICEs launching with Android 13 MUST meet the requirements for the
-// target-level=7 compatibility_matrix file.
-const uint64_t kCompatibilityMatrix7ApiLevel = 33;
-
-// DEVICEs launching with Android 14 MUST meet the requirements for the
-// target-level=8 compatibility_matrix file.
-const uint64_t kCompatibilityMatrix8ApiLevel = 34;
-
-inline bool isUnknownOrUnsupported(const ndk::ScopedAStatus& status) {
-    return status.getStatus() == STATUS_UNKNOWN_TRANSACTION ||
-           status.getExceptionCode() == EX_UNSUPPORTED_OPERATION;
-}
-
 class PowerAidl : public testing::TestWithParam<std::string> {
   public:
     virtual void SetUp() override {
         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);
+        auto status = power->getInterfaceVersion(&mServiceVersion);
+        ASSERT_TRUE(status.isOk());
     }
 
     std::shared_ptr<IPower> power;
-    uint64_t mApiLevel;
+    int32_t mServiceVersion;
+};
+
+class HintSessionAidl : public PowerAidl {
+  public:
+    virtual void SetUp() override {
+        PowerAidl::SetUp();
+        if (mServiceVersion < 2) {
+            GTEST_SKIP() << "DEVICE not launching with Power V2 and beyond.";
+        }
+
+        auto status = power->createHintSession(getpid(), getuid(), kSelfTids, 16666666L, &mSession);
+        ASSERT_TRUE(status.isOk());
+        ASSERT_NE(nullptr, mSession);
+    }
+    std::shared_ptr<IPowerHintSession> mSession;
 };
 
 TEST_P(PowerAidl, setMode) {
@@ -175,113 +190,128 @@
 }
 
 TEST_P(PowerAidl, getHintSessionPreferredRate) {
-    int64_t rate = -1;
-    auto status = power->getHintSessionPreferredRate(&rate);
-    if (mApiLevel < kCompatibilityMatrix7ApiLevel && !status.isOk()) {
-        EXPECT_TRUE(isUnknownOrUnsupported(status));
-        GTEST_SKIP() << "DEVICE not launching with Android 13 and beyond.";
+    if (mServiceVersion < 2) {
+        GTEST_SKIP() << "DEVICE not launching with Power V2 and beyond.";
     }
-    ASSERT_TRUE(status.isOk());
+
+    int64_t rate = -1;
+    ASSERT_TRUE(power->getHintSessionPreferredRate(&rate).isOk());
     // At least 1ms rate limit from HAL
     ASSERT_GE(rate, 1000000);
 }
 
-TEST_P(PowerAidl, createAndCloseHintSession) {
-    std::shared_ptr<IPowerHintSession> session;
-    auto status = power->createHintSession(getpid(), getuid(), kSelfTids, 16666666L, &session);
-    if (mApiLevel < kCompatibilityMatrix7ApiLevel && !status.isOk()) {
-        EXPECT_TRUE(isUnknownOrUnsupported(status));
-        GTEST_SKIP() << "DEVICE not launching with Android 13 and beyond.";
+TEST_P(PowerAidl, createHintSessionWithConfig) {
+    if (mServiceVersion < 5) {
+        GTEST_SKIP() << "DEVICE not launching with Power V5 and beyond.";
     }
+    std::shared_ptr<IPowerHintSession> session;
+    SessionConfig config;
+
+    auto status = power->createHintSessionWithConfig(getpid(), getuid(), kSelfTids, 16666666L,
+                                                     SessionTag::OTHER, &config, &session);
     ASSERT_TRUE(status.isOk());
     ASSERT_NE(nullptr, session);
-    ASSERT_TRUE(session->pause().isOk());
-    ASSERT_TRUE(session->resume().isOk());
-    // Test normal destroy operation
-    ASSERT_TRUE(session->close().isOk());
-    session.reset();
 }
 
-TEST_P(PowerAidl, createHintSessionFailed) {
+TEST_P(PowerAidl, getAndCloseSessionChannel) {
+    if (mServiceVersion < 5) {
+        GTEST_SKIP() << "DEVICE not launching with Power V5 and beyond.";
+    }
+    ChannelConfig config;
+    auto status = power->getSessionChannel(getpid(), getuid(), &config);
+    ASSERT_TRUE(status.isOk());
+    auto messageQueue = std::make_shared<SessionMessageQueue>(config.channelDescriptor, true);
+    ASSERT_TRUE(messageQueue->isValid());
+    ASSERT_TRUE(power->closeSessionChannel(getpid(), getuid()).isOk());
+}
+
+TEST_P(HintSessionAidl, createAndCloseHintSession) {
+    ASSERT_TRUE(mSession->pause().isOk());
+    ASSERT_TRUE(mSession->resume().isOk());
+    // Test normal destroy operation
+    ASSERT_TRUE(mSession->close().isOk());
+    mSession.reset();
+}
+
+TEST_P(HintSessionAidl, 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 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());
 }
 
-TEST_P(PowerAidl, updateAndReportDurations) {
-    std::shared_ptr<IPowerHintSession> session;
-    auto status = power->createHintSession(getpid(), getuid(), kSelfTids, 16666666L, &session);
-    if (mApiLevel < kCompatibilityMatrix7ApiLevel && !status.isOk()) {
-        EXPECT_TRUE(isUnknownOrUnsupported(status));
-        GTEST_SKIP() << "DEVICE not launching with Android 13 and beyond.";
-    }
-    ASSERT_TRUE(status.isOk());
-    ASSERT_NE(nullptr, session);
-
-    ASSERT_TRUE(session->updateTargetWorkDuration(16666667LL).isOk());
-    ASSERT_TRUE(session->reportActualWorkDuration(kDurations).isOk());
+TEST_P(HintSessionAidl, updateAndReportDurations) {
+    ASSERT_TRUE(mSession->updateTargetWorkDuration(16666667LL).isOk());
+    ASSERT_TRUE(mSession->reportActualWorkDuration(kDurations).isOk());
 }
 
-TEST_P(PowerAidl, sendSessionHint) {
-    std::shared_ptr<IPowerHintSession> session;
-    auto status = power->createHintSession(getpid(), getuid(), kSelfTids, 16666666L, &session);
-    if (!status.isOk()) {
-        EXPECT_TRUE(isUnknownOrUnsupported(status));
-        return;
+TEST_P(HintSessionAidl, sendSessionHint) {
+    if (mServiceVersion < 4) {
+        GTEST_SKIP() << "DEVICE not launching with Power V4 and beyond.";
     }
+
     for (const auto& sessionHint : kSessionHints) {
-        ASSERT_TRUE(session->sendHint(sessionHint).isOk());
+        ASSERT_TRUE(mSession->sendHint(sessionHint).isOk());
     }
     for (const auto& sessionHint : kInvalidSessionHints) {
-        ASSERT_TRUE(session->sendHint(sessionHint).isOk());
+        ASSERT_TRUE(mSession->sendHint(sessionHint).isOk());
     }
 }
 
-TEST_P(PowerAidl, setThreads) {
-    std::shared_ptr<IPowerHintSession> session;
-    auto status = power->createHintSession(getpid(), getuid(), kSelfTids, 16666666L, &session);
-    if (mApiLevel < kCompatibilityMatrix7ApiLevel && !status.isOk()) {
-        EXPECT_TRUE(isUnknownOrUnsupported(status));
-        GTEST_SKIP() << "DEVICE not launching with Android 13 and beyond.";
+TEST_P(HintSessionAidl, setThreads) {
+    if (mServiceVersion < 4) {
+        GTEST_SKIP() << "DEVICE not launching with Power V4 and beyond.";
     }
-    ASSERT_TRUE(status.isOk());
 
-    status = session->setThreads(kEmptyTids);
-    if (mApiLevel < kCompatibilityMatrix8ApiLevel && isUnknownOrUnsupported(status)) {
-        GTEST_SKIP() << "DEVICE not launching with Android 14 and beyond.";
-    }
+    auto status = mSession->setThreads(kEmptyTids);
     ASSERT_FALSE(status.isOk());
     ASSERT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
 
-    status = session->setThreads(kSelfTids);
-    ASSERT_TRUE(status.isOk());
+    ASSERT_TRUE(mSession->setThreads(kSelfTids).isOk());
+}
+
+TEST_P(HintSessionAidl, setSessionMode) {
+    if (mServiceVersion < 5) {
+        GTEST_SKIP() << "DEVICE not launching with Power V5 and beyond.";
+    }
+
+    for (const auto& sessionMode : kSessionModes) {
+        ASSERT_TRUE(mSession->setMode(sessionMode, true).isOk());
+        ASSERT_TRUE(mSession->setMode(sessionMode, false).isOk());
+    }
+    for (const auto& sessionMode : kInvalidSessionModes) {
+        ASSERT_TRUE(mSession->setMode(sessionMode, true).isOk());
+        ASSERT_TRUE(mSession->setMode(sessionMode, false).isOk());
+    }
+}
+
+TEST_P(HintSessionAidl, getSessionConfig) {
+    if (mServiceVersion < 5) {
+        GTEST_SKIP() << "DEVICE not launching with Power V5 and beyond.";
+    }
+    SessionConfig config;
+    ASSERT_TRUE(mSession->getSessionConfig(&config).isOk());
 }
 
 // FIXED_PERFORMANCE mode is required for all devices which ship on Android 11
 // or later
 TEST_P(PowerAidl, hasFixedPerformance) {
-    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);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(HintSessionAidl);
+
 INSTANTIATE_TEST_SUITE_P(Power, PowerAidl,
                          testing::ValuesIn(::android::getAidlHalInstanceNames(IPower::descriptor)),
                          ::android::PrintInstanceNameToString);
+INSTANTIATE_TEST_SUITE_P(Power, HintSessionAidl,
+                         testing::ValuesIn(::android::getAidlHalInstanceNames(IPower::descriptor)),
+                         ::android::PrintInstanceNameToString);
 
 }  // namespace
 }  // namespace aidl::android::hardware::power
diff --git a/power/stats/aidl/default/Android.bp b/power/stats/aidl/default/Android.bp
index d3ab29b..cc0fbf6 100644
--- a/power/stats/aidl/default/Android.bp
+++ b/power/stats/aidl/default/Android.bp
@@ -38,9 +38,11 @@
     ],
 }
 
-filegroup {
+prebuilt_etc {
     name: "android.hardware.power.stats.xml",
-    srcs: ["power.stats-default.xml"],
+    src: "power.stats-default.xml",
+    sub_dir: "vintf",
+    installable: false,
 }
 
 filegroup {
diff --git a/radio/1.0/vts/OWNERS b/radio/1.0/vts/OWNERS
deleted file mode 100644
index 117692a..0000000
--- a/radio/1.0/vts/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-# Bug component: 20868
-jminjie@google.com
-sarahchin@google.com
-shuoq@google.com
-jackyu@google.com
diff --git a/radio/1.0/vts/functional/OWNERS b/radio/1.0/vts/functional/OWNERS
deleted file mode 100644
index 1b6d937..0000000
--- a/radio/1.0/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 20868
-shuoq@google.com
diff --git a/radio/1.1/vts/OWNERS b/radio/1.1/vts/OWNERS
deleted file mode 100644
index 4d199ca..0000000
--- a/radio/1.1/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 20868
-include ../../1.0/vts/OWNERS
diff --git a/radio/1.2/vts/OWNERS b/radio/1.2/vts/OWNERS
deleted file mode 100644
index 4d199ca..0000000
--- a/radio/1.2/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 20868
-include ../../1.0/vts/OWNERS
diff --git a/radio/1.3/vts/OWNERS b/radio/1.3/vts/OWNERS
deleted file mode 100644
index 4d199ca..0000000
--- a/radio/1.3/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 20868
-include ../../1.0/vts/OWNERS
diff --git a/radio/1.4/vts/OWNERS b/radio/1.4/vts/OWNERS
deleted file mode 100644
index 4d199ca..0000000
--- a/radio/1.4/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 20868
-include ../../1.0/vts/OWNERS
diff --git a/radio/1.5/vts/OWNERS b/radio/1.5/vts/OWNERS
deleted file mode 100644
index 4d199ca..0000000
--- a/radio/1.5/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 20868
-include ../../1.0/vts/OWNERS
diff --git a/radio/1.6/vts/OWNERS b/radio/1.6/vts/OWNERS
deleted file mode 100644
index a07c917..0000000
--- a/radio/1.6/vts/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-include ../../1.0/vts/OWNERS
diff --git a/radio/OWNERS b/radio/OWNERS
new file mode 100644
index 0000000..8107287
--- /dev/null
+++ b/radio/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 20868
+
+jackyu@google.com
+sarahchin@google.com
+jayachandranc@google.com
\ No newline at end of file
diff --git a/radio/aidl/Android.bp b/radio/aidl/Android.bp
index 09f845b..1971832 100644
--- a/radio/aidl/Android.bp
+++ b/radio/aidl/Android.bp
@@ -12,7 +12,6 @@
     vendor_available: true,
     host_supported: true,
     srcs: ["android/hardware/radio/*.aidl"],
-    frozen: true,
     stability: "vintf",
     backend: {
         cpp: {
@@ -41,9 +40,8 @@
     vendor_available: true,
     host_supported: true,
     srcs: ["android/hardware/radio/config/*.aidl"],
-    frozen: true,
     stability: "vintf",
-    imports: ["android.hardware.radio-V2"],
+    imports: ["android.hardware.radio-V3"],
     backend: {
         cpp: {
             enabled: true,
@@ -72,7 +70,7 @@
     host_supported: true,
     srcs: ["android/hardware/radio/data/*.aidl"],
     stability: "vintf",
-    imports: ["android.hardware.radio-V2"],
+    imports: ["android.hardware.radio-V3"],
     backend: {
         cpp: {
             enabled: true,
@@ -92,8 +90,6 @@
         },
 
     ],
-    frozen: true,
-
 }
 
 aidl_interface {
@@ -102,7 +98,7 @@
     host_supported: true,
     srcs: ["android/hardware/radio/messaging/*.aidl"],
     stability: "vintf",
-    imports: ["android.hardware.radio-V2"],
+    imports: ["android.hardware.radio-V3"],
     backend: {
         cpp: {
             enabled: true,
@@ -122,8 +118,6 @@
         },
 
     ],
-    frozen: true,
-
 }
 
 aidl_interface {
@@ -132,7 +126,7 @@
     host_supported: true,
     srcs: ["android/hardware/radio/modem/*.aidl"],
     stability: "vintf",
-    imports: ["android.hardware.radio-V2"],
+    imports: ["android.hardware.radio-V3"],
     backend: {
         cpp: {
             enabled: true,
@@ -152,8 +146,6 @@
         },
 
     ],
-    frozen: true,
-
 }
 
 aidl_interface {
@@ -162,7 +154,7 @@
     host_supported: true,
     srcs: ["android/hardware/radio/network/*.aidl"],
     stability: "vintf",
-    imports: ["android.hardware.radio-V2"],
+    imports: ["android.hardware.radio-V3"],
     backend: {
         cpp: {
             enabled: true,
@@ -182,8 +174,6 @@
         },
 
     ],
-    frozen: true,
-
 }
 
 aidl_interface {
@@ -212,7 +202,6 @@
         },
     ],
     frozen: true,
-
 }
 
 aidl_interface {
@@ -222,8 +211,8 @@
     srcs: ["android/hardware/radio/sim/*.aidl"],
     stability: "vintf",
     imports: [
-        "android.hardware.radio-V2",
-        "android.hardware.radio.config-V2",
+        "android.hardware.radio-V3",
+        "android.hardware.radio.config-V3",
     ],
     backend: {
         cpp: {
@@ -250,8 +239,6 @@
         },
 
     ],
-    frozen: true,
-
 }
 
 aidl_interface {
@@ -260,7 +247,7 @@
     host_supported: true,
     srcs: ["android/hardware/radio/voice/*.aidl"],
     stability: "vintf",
-    imports: ["android.hardware.radio-V2"],
+    imports: ["android.hardware.radio-V3"],
     backend: {
         cpp: {
             enabled: true,
@@ -280,8 +267,6 @@
         },
 
     ],
-    frozen: true,
-
 }
 
 aidl_interface {
@@ -290,8 +275,8 @@
     srcs: ["android/hardware/radio/ims/media/*.aidl"],
     stability: "vintf",
     imports: [
-        "android.hardware.radio-V2",
-        "android.hardware.radio.data-V2",
+        "android.hardware.radio-V3",
+        "android.hardware.radio.data-V3",
     ],
     backend: {
         cpp: {
@@ -310,8 +295,6 @@
             ],
         },
     ],
-    frozen: true,
-
 }
 
 aidl_interface {
@@ -319,7 +302,7 @@
     vendor_available: true,
     srcs: ["android/hardware/radio/ims/*.aidl"],
     stability: "vintf",
-    imports: ["android.hardware.radio-V2"],
+    imports: ["android.hardware.radio-V3"],
     backend: {
         cpp: {
             enabled: false,
@@ -334,6 +317,4 @@
             imports: ["android.hardware.radio-V2"],
         },
     ],
-    frozen: true,
-
 }
diff --git a/radio/aidl/OWNERS b/radio/aidl/OWNERS
deleted file mode 100644
index 7b01aad..0000000
--- a/radio/aidl/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 20868
-include ../1.0/vts/OWNERS
-
diff --git a/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/IRadioConfig.aidl b/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/IRadioConfig.aidl
index a48a89b..bc1c292 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/IRadioConfig.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/IRadioConfig.aidl
@@ -40,6 +40,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.config;
+/* @hide */
 @VintfStability
 interface IRadioConfig {
   oneway void getHalDeviceCapabilities(in int serial);
@@ -50,4 +51,5 @@
   oneway void setPreferredDataModem(in int serial, in byte modemId);
   oneway void setResponseFunctions(in android.hardware.radio.config.IRadioConfigResponse radioConfigResponse, in android.hardware.radio.config.IRadioConfigIndication radioConfigIndication);
   oneway void setSimSlotsMapping(in int serial, in android.hardware.radio.config.SlotPortMapping[] slotMap);
+  oneway void getSimultaneousCallingSupport(in int serial);
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/IRadioConfigIndication.aidl b/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/IRadioConfigIndication.aidl
index 994e337..f786373 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/IRadioConfigIndication.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/IRadioConfigIndication.aidl
@@ -32,7 +32,9 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.config;
+/* @hide */
 @VintfStability
 interface IRadioConfigIndication {
   oneway void simSlotsStatusChanged(in android.hardware.radio.RadioIndicationType type, in android.hardware.radio.config.SimSlotStatus[] slotStatus);
+  oneway void onSimultaneousCallingSupportChanged(in int[] enabledLogicalSlots);
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/IRadioConfigResponse.aidl b/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/IRadioConfigResponse.aidl
index 038b0ae..6ff7bd0 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/IRadioConfigResponse.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/IRadioConfigResponse.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.config;
+/* @hide */
 @VintfStability
 interface IRadioConfigResponse {
   oneway void getHalDeviceCapabilitiesResponse(in android.hardware.radio.RadioResponseInfo info, in boolean modemReducedFeatureSet1);
@@ -41,4 +42,5 @@
   oneway void setNumOfLiveModemsResponse(in android.hardware.radio.RadioResponseInfo info);
   oneway void setPreferredDataModemResponse(in android.hardware.radio.RadioResponseInfo info);
   oneway void setSimSlotsMappingResponse(in android.hardware.radio.RadioResponseInfo info);
+  oneway void getSimultaneousCallingSupportResponse(in android.hardware.radio.RadioResponseInfo info, in int[] enabledLogicalSlots);
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/MultipleEnabledProfilesMode.aidl b/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/MultipleEnabledProfilesMode.aidl
index 74017e4..41c4201 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/MultipleEnabledProfilesMode.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/MultipleEnabledProfilesMode.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.config;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum MultipleEnabledProfilesMode {
   NONE,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/PhoneCapability.aidl b/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/PhoneCapability.aidl
index db3a4c6..2c66abd 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/PhoneCapability.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/PhoneCapability.aidl
@@ -32,10 +32,13 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.config;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable PhoneCapability {
   byte maxActiveData;
   byte maxActiveInternetData;
   boolean isInternetLingeringSupported;
   byte[] logicalModemIds;
+  byte maxActiveVoice = UNKNOWN /* -1 */;
+  const byte UNKNOWN = (-1) /* -1 */;
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/SimPortInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/SimPortInfo.aidl
index b5d31ad..ede3189 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/SimPortInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/SimPortInfo.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.config;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable SimPortInfo {
   String iccId;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/SimSlotStatus.aidl b/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/SimSlotStatus.aidl
index c264dfd..e84e7d4 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/SimSlotStatus.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/SimSlotStatus.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.config;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable SimSlotStatus {
   int cardState;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/SlotPortMapping.aidl b/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/SlotPortMapping.aidl
index 31271ee..5278e79 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/SlotPortMapping.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/SlotPortMapping.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.config;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable SlotPortMapping {
   int physicalSlotId;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/ApnAuthType.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/ApnAuthType.aidl
index a33ad6e..eed8170 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/ApnAuthType.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/ApnAuthType.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum ApnAuthType {
   NO_PAP_NO_CHAP,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/ApnTypes.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/ApnTypes.aidl
index 45d22c8..782dbbf 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/ApnTypes.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/ApnTypes.aidl
@@ -32,22 +32,24 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum ApnTypes {
   NONE = 0,
-  DEFAULT = (1 << 0),
-  MMS = (1 << 1),
-  SUPL = (1 << 2),
-  DUN = (1 << 3),
-  HIPRI = (1 << 4),
-  FOTA = (1 << 5),
-  IMS = (1 << 6),
-  CBS = (1 << 7),
-  IA = (1 << 8),
-  EMERGENCY = (1 << 9),
-  MCX = (1 << 10),
-  XCAP = (1 << 11),
-  VSIM = (1 << 12),
-  BIP = (1 << 13),
-  ENTERPRISE = (1 << 14),
+  DEFAULT = (1 << 0) /* 1 */,
+  MMS = (1 << 1) /* 2 */,
+  SUPL = (1 << 2) /* 4 */,
+  DUN = (1 << 3) /* 8 */,
+  HIPRI = (1 << 4) /* 16 */,
+  FOTA = (1 << 5) /* 32 */,
+  IMS = (1 << 6) /* 64 */,
+  CBS = (1 << 7) /* 128 */,
+  IA = (1 << 8) /* 256 */,
+  EMERGENCY = (1 << 9) /* 512 */,
+  MCX = (1 << 10) /* 1024 */,
+  XCAP = (1 << 11) /* 2048 */,
+  VSIM = (1 << 12) /* 4096 */,
+  BIP = (1 << 13) /* 8192 */,
+  ENTERPRISE = (1 << 14) /* 16384 */,
+  RCS = (1 << 15) /* 32768 */,
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/DataCallFailCause.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/DataCallFailCause.aidl
index 8a3fd4f..009b428 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/DataCallFailCause.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/DataCallFailCause.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum DataCallFailCause {
   NONE = 0,
@@ -101,12 +102,12 @@
   OEM_DCFAILCAUSE_13 = 0x100D,
   OEM_DCFAILCAUSE_14 = 0x100E,
   OEM_DCFAILCAUSE_15 = 0x100F,
-  VOICE_REGISTRATION_FAIL = (-1),
-  DATA_REGISTRATION_FAIL = (-2),
-  SIGNAL_LOST = (-3),
-  PREF_RADIO_TECH_CHANGED = (-4),
-  RADIO_POWER_OFF = (-5),
-  TETHERED_CALL_ACTIVE = (-6),
+  VOICE_REGISTRATION_FAIL = (-1) /* -1 */,
+  DATA_REGISTRATION_FAIL = (-2) /* -2 */,
+  SIGNAL_LOST = (-3) /* -3 */,
+  PREF_RADIO_TECH_CHANGED = (-4) /* -4 */,
+  RADIO_POWER_OFF = (-5) /* -5 */,
+  TETHERED_CALL_ACTIVE = (-6) /* -6 */,
   ERROR_UNSPECIFIED = 0xffff,
   LLC_SNDCP = 0x19,
   ACTIVATION_REJECTED_BCM_VIOLATION = 0x30,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/DataProfileInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/DataProfileInfo.aidl
index 0136fa4..7f3fdc7 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/DataProfileInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/DataProfileInfo.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable DataProfileInfo {
   int profileId;
@@ -54,6 +55,7 @@
   boolean persistent;
   boolean alwaysOn;
   android.hardware.radio.data.TrafficDescriptor trafficDescriptor;
+  int infrastructureBitmap = INFRASTRUCTURE_UNKNOWN /* 0 */;
   const int ID_DEFAULT = 0;
   const int ID_TETHERED = 1;
   const int ID_IMS = 2;
@@ -64,4 +66,7 @@
   const int TYPE_COMMON = 0;
   const int TYPE_3GPP = 1;
   const int TYPE_3GPP2 = 2;
+  const int INFRASTRUCTURE_UNKNOWN = 0;
+  const int INFRASTRUCTURE_CELLULAR = (1 << 0) /* 1 */;
+  const int INFRASTRUCTURE_SATELLITE = (1 << 1) /* 2 */;
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/DataRequestReason.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/DataRequestReason.aidl
index 0ddaff1..98ae53a 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/DataRequestReason.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/DataRequestReason.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum DataRequestReason {
   NORMAL = 1,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/DataThrottlingAction.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/DataThrottlingAction.aidl
index e80a764..e1fedb8 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/DataThrottlingAction.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/DataThrottlingAction.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
+/* @hide */
 @Backing(type="byte") @JavaDerive(toString=true) @VintfStability
 enum DataThrottlingAction {
   NO_DATA_THROTTLING,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/EpsQos.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/EpsQos.aidl
index 5b9aaa0..3a3f41d 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/EpsQos.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/EpsQos.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable EpsQos {
   int qci;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/IRadioData.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/IRadioData.aidl
index 7b572f1..3888c62 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/IRadioData.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/IRadioData.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
+/* @hide */
 @VintfStability
 interface IRadioData {
   oneway void allocatePduSessionId(in int serial);
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/IRadioDataIndication.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/IRadioDataIndication.aidl
index 0ffa1f7..6057d6a 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/IRadioDataIndication.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/IRadioDataIndication.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
+/* @hide */
 @VintfStability
 interface IRadioDataIndication {
   oneway void dataCallListChanged(in android.hardware.radio.RadioIndicationType type, in android.hardware.radio.data.SetupDataCallResult[] dcList);
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/IRadioDataResponse.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/IRadioDataResponse.aidl
index 4edc17d..dc44454 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/IRadioDataResponse.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/IRadioDataResponse.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
+/* @hide */
 @VintfStability
 interface IRadioDataResponse {
   oneway void acknowledgeRequest(in int serial);
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/KeepaliveRequest.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/KeepaliveRequest.aidl
index 592a54a..789ee86 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/KeepaliveRequest.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/KeepaliveRequest.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable KeepaliveRequest {
   int type;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/KeepaliveStatus.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/KeepaliveStatus.aidl
index 82b0fc8..404b44a 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/KeepaliveStatus.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/KeepaliveStatus.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable KeepaliveStatus {
   int sessionHandle;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/LinkAddress.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/LinkAddress.aidl
index 77d637b..bef4c73 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/LinkAddress.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/LinkAddress.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable LinkAddress {
   String address;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/NrQos.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/NrQos.aidl
index be859b7..22bbe42 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/NrQos.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/NrQos.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable NrQos {
   int fiveQi;
@@ -42,8 +43,8 @@
    * @deprecated use averagingWindowMillis;
    */
   char averagingWindowMs;
-  int averagingWindowMillis = AVERAGING_WINDOW_UNKNOWN;
+  int averagingWindowMillis = AVERAGING_WINDOW_UNKNOWN /* -1 */;
   const byte FLOW_ID_RANGE_MIN = 1;
   const byte FLOW_ID_RANGE_MAX = 63;
-  const int AVERAGING_WINDOW_UNKNOWN = (-1);
+  const int AVERAGING_WINDOW_UNKNOWN = (-1) /* -1 */;
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/OsAppId.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/OsAppId.aidl
index 8595d52..e4bbf79 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/OsAppId.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/OsAppId.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable OsAppId {
   byte[] osAppId;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/PcoDataInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/PcoDataInfo.aidl
index 033b12f..ea7529c 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/PcoDataInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/PcoDataInfo.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable PcoDataInfo {
   int cid;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/PdpProtocolType.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/PdpProtocolType.aidl
index d1c4a62..3a7f82d 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/PdpProtocolType.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/PdpProtocolType.aidl
@@ -32,9 +32,10 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum PdpProtocolType {
-  UNKNOWN = (-1),
+  UNKNOWN = (-1) /* -1 */,
   IP = 0,
   IPV6 = 1,
   IPV4V6 = 2,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/PortRange.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/PortRange.aidl
index 470a9c1..45e2dc9 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/PortRange.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/PortRange.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable PortRange {
   int start;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/Qos.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/Qos.aidl
index ca06e41..4dac56c 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/Qos.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/Qos.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 union Qos {
   boolean noinit;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/QosBandwidth.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/QosBandwidth.aidl
index 6d4b7a9..b59dee0 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/QosBandwidth.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/QosBandwidth.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable QosBandwidth {
   int maxBitrateKbps;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/QosFilter.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/QosFilter.aidl
index de45cc5..a3208d9 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/QosFilter.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/QosFilter.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable QosFilter {
   String[] localAddresses;
@@ -47,7 +48,7 @@
   const byte DIRECTION_DOWNLINK = 0;
   const byte DIRECTION_UPLINK = 1;
   const byte DIRECTION_BIDIRECTIONAL = 2;
-  const byte PROTOCOL_UNSPECIFIED = (-1);
+  const byte PROTOCOL_UNSPECIFIED = (-1) /* -1 */;
   const byte PROTOCOL_TCP = 6;
   const byte PROTOCOL_UDP = 17;
   const byte PROTOCOL_ESP = 50;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/QosFilterIpsecSpi.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/QosFilterIpsecSpi.aidl
index 4b75340..50b52a4 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/QosFilterIpsecSpi.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/QosFilterIpsecSpi.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 union QosFilterIpsecSpi {
   boolean noinit;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/QosFilterIpv6FlowLabel.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/QosFilterIpv6FlowLabel.aidl
index 3fb34ea..4913dcf 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/QosFilterIpv6FlowLabel.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/QosFilterIpv6FlowLabel.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 union QosFilterIpv6FlowLabel {
   boolean noinit;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/QosFilterTypeOfService.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/QosFilterTypeOfService.aidl
index fa85b5a..4f0d260 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/QosFilterTypeOfService.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/QosFilterTypeOfService.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 union QosFilterTypeOfService {
   boolean noinit;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/QosSession.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/QosSession.aidl
index bbfdd2d..89010a9 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/QosSession.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/QosSession.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable QosSession {
   int qosSessionId;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/RouteSelectionDescriptor.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/RouteSelectionDescriptor.aidl
index d83df81..8864c24 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/RouteSelectionDescriptor.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/RouteSelectionDescriptor.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable RouteSelectionDescriptor {
   byte precedence;
@@ -39,7 +40,7 @@
   byte sscMode;
   android.hardware.radio.data.SliceInfo[] sliceInfo;
   String[] dnn;
-  const byte SSC_MODE_UNKNOWN = (-1);
+  const byte SSC_MODE_UNKNOWN = (-1) /* -1 */;
   const byte SSC_MODE_1 = 1;
   const byte SSC_MODE_2 = 2;
   const byte SSC_MODE_3 = 3;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/SetupDataCallResult.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/SetupDataCallResult.aidl
index 83f9db6..6ae626e 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/SetupDataCallResult.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/SetupDataCallResult.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable SetupDataCallResult {
   android.hardware.radio.data.DataCallFailCause cause;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/SliceInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/SliceInfo.aidl
index efe4816..60df402 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/SliceInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/SliceInfo.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable SliceInfo {
   byte sliceServiceType;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/SlicingConfig.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/SlicingConfig.aidl
index b00febe..4d28737 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/SlicingConfig.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/SlicingConfig.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable SlicingConfig {
   android.hardware.radio.data.UrspRule[] urspRules;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/TrafficDescriptor.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/TrafficDescriptor.aidl
index d7b0654..dc474a2 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/TrafficDescriptor.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/TrafficDescriptor.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable TrafficDescriptor {
   @nullable String dnn;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/UrspRule.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/UrspRule.aidl
index 7002fd1..6850f6a 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/UrspRule.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/UrspRule.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable UrspRule {
   int precedence;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/AmrMode.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/AmrMode.aidl
index 37e3b25..36a538c 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/AmrMode.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/AmrMode.aidl
@@ -32,7 +32,8 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.ims.media;
-@Backing(type="int") @VintfStability
+/* @hide */
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum AmrMode {
   AMR_MODE_0 = (1 << 0) /* 1 */,
   AMR_MODE_1 = (1 << 1) /* 2 */,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/AmrParams.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/AmrParams.aidl
index 36edb7f..dcf0dd1 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/AmrParams.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/AmrParams.aidl
@@ -32,7 +32,8 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.ims.media;
-@VintfStability
+/* @hide */
+@JavaDerive(toString=true) @VintfStability
 parcelable AmrParams {
   android.hardware.radio.ims.media.AmrMode amrMode;
   boolean octetAligned;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/AnbrMode.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/AnbrMode.aidl
index c108c07..eca7b93 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/AnbrMode.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/AnbrMode.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.ims.media;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable AnbrMode {
   android.hardware.radio.ims.media.CodecMode anbrUplinkMode;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/CallQuality.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/CallQuality.aidl
index fff6e1c..594a39f 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/CallQuality.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/CallQuality.aidl
@@ -32,7 +32,8 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.ims.media;
-@VintfStability
+/* @hide */
+@JavaDerive(toString=true) @VintfStability
 parcelable CallQuality {
   int downlinkCallQualityLevel;
   int uplinkCallQualityLevel;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/CodecMode.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/CodecMode.aidl
index 0e9140f..644321c 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/CodecMode.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/CodecMode.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.ims.media;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 union CodecMode {
   boolean noinit;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/CodecParams.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/CodecParams.aidl
index 3da2dbd..6eefb34 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/CodecParams.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/CodecParams.aidl
@@ -32,7 +32,8 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.ims.media;
-@VintfStability
+/* @hide */
+@JavaDerive(toString=true) @VintfStability
 parcelable CodecParams {
   android.hardware.radio.ims.media.CodecType codecType;
   byte rxPayloadTypeNumber;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/CodecSpecificParams.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/CodecSpecificParams.aidl
index 08e3f0f..7e5722f 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/CodecSpecificParams.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/CodecSpecificParams.aidl
@@ -32,7 +32,8 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.ims.media;
-@VintfStability
+/* @hide */
+@JavaDerive(toString=true) @VintfStability
 union CodecSpecificParams {
   android.hardware.radio.ims.media.AmrParams amr;
   android.hardware.radio.ims.media.EvsParams evs;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/CodecType.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/CodecType.aidl
index e4193cd..98463b1 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/CodecType.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/CodecType.aidl
@@ -32,7 +32,8 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.ims.media;
-@Backing(type="int") @VintfStability
+/* @hide */
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum CodecType {
   AMR = (1 << 0) /* 1 */,
   AMR_WB = (1 << 1) /* 2 */,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/DtmfParams.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/DtmfParams.aidl
index 5523fd8..f420fa7 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/DtmfParams.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/DtmfParams.aidl
@@ -32,7 +32,8 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.ims.media;
-@VintfStability
+/* @hide */
+@JavaDerive(toString=true) @VintfStability
 parcelable DtmfParams {
   byte rxPayloadTypeNumber;
   byte txPayloadTypeNumber;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/EvsBandwidth.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/EvsBandwidth.aidl
index db3eb29..d8c77bd 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/EvsBandwidth.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/EvsBandwidth.aidl
@@ -32,7 +32,8 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.ims.media;
-@Backing(type="int") @VintfStability
+/* @hide */
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum EvsBandwidth {
   NONE = 0,
   NARROW_BAND = (1 << 0) /* 1 */,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/EvsMode.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/EvsMode.aidl
index fb1f14d..1a59389 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/EvsMode.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/EvsMode.aidl
@@ -32,7 +32,8 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.ims.media;
-@Backing(type="int") @VintfStability
+/* @hide */
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum EvsMode {
   EVS_MODE_0 = (1 << 0) /* 1 */,
   EVS_MODE_1 = (1 << 1) /* 2 */,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/EvsParams.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/EvsParams.aidl
index 735eb08..deb53af 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/EvsParams.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/EvsParams.aidl
@@ -32,7 +32,8 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.ims.media;
-@VintfStability
+/* @hide */
+@JavaDerive(toString=true) @VintfStability
 parcelable EvsParams {
   android.hardware.radio.ims.media.EvsBandwidth bandwidth;
   android.hardware.radio.ims.media.EvsMode evsMode;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/IImsMedia.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/IImsMedia.aidl
index 30793e5..190d25b 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/IImsMedia.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/IImsMedia.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.ims.media;
+/* @hide */
 @VintfStability
 interface IImsMedia {
   oneway void setListener(in android.hardware.radio.ims.media.IImsMediaListener mediaListener);
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/IImsMediaListener.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/IImsMediaListener.aidl
index 40f7107..9b7a392 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/IImsMediaListener.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/IImsMediaListener.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.ims.media;
+/* @hide */
 @VintfStability
 interface IImsMediaListener {
   oneway void onOpenSessionSuccess(int sessionId, android.hardware.radio.ims.media.IImsMediaSession session);
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/IImsMediaSession.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/IImsMediaSession.aidl
index ea9f3a4..2150fbe 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/IImsMediaSession.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/IImsMediaSession.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.ims.media;
+/* @hide */
 @VintfStability
 interface IImsMediaSession {
   oneway void setListener(in android.hardware.radio.ims.media.IImsMediaSessionListener sessionListener);
@@ -41,4 +42,6 @@
   oneway void stopDtmf();
   oneway void sendHeaderExtension(in List<android.hardware.radio.ims.media.RtpHeaderExtension> extensions);
   oneway void setMediaQualityThreshold(in android.hardware.radio.ims.media.MediaQualityThreshold threshold);
+  oneway void requestRtpReceptionStats(in int intervalMs);
+  oneway void adjustDelay(in int delayMs);
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/IImsMediaSessionListener.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/IImsMediaSessionListener.aidl
index cb221df..87474ef 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/IImsMediaSessionListener.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/IImsMediaSessionListener.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.ims.media;
+/* @hide */
 @VintfStability
 interface IImsMediaSessionListener {
   oneway void onModifySessionResponse(in android.hardware.radio.ims.media.RtpConfig config, android.hardware.radio.ims.media.RtpError error);
@@ -41,4 +42,5 @@
   oneway void triggerAnbrQuery(in android.hardware.radio.ims.media.RtpConfig config);
   oneway void onDtmfReceived(char dtmfDigit, int durationMs);
   oneway void onCallQualityChanged(in android.hardware.radio.ims.media.CallQuality callQuality);
+  oneway void notifyRtpReceptionStats(in android.hardware.radio.ims.media.RtpReceptionStats stats);
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/LocalEndPoint.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/LocalEndPoint.aidl
index 6ec5156..1095f01 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/LocalEndPoint.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/LocalEndPoint.aidl
@@ -32,7 +32,8 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.ims.media;
-@VintfStability
+/* @hide */
+@JavaDerive(toString=true) @VintfStability
 parcelable LocalEndPoint {
   ParcelFileDescriptor rtpFd;
   ParcelFileDescriptor rtcpFd;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/MediaDirection.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/MediaDirection.aidl
index 0e9eaee..5410f2a 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/MediaDirection.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/MediaDirection.aidl
@@ -32,7 +32,8 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.ims.media;
-@Backing(type="int") @VintfStability
+/* @hide */
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum MediaDirection {
   NO_FLOW = 0,
   RTP_TX = (1 << 0) /* 1 */,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/MediaQualityStatus.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/MediaQualityStatus.aidl
index 4accf53..da6e751 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/MediaQualityStatus.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/MediaQualityStatus.aidl
@@ -32,7 +32,8 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.ims.media;
-@VintfStability
+/* @hide */
+@JavaDerive(toString=true) @VintfStability
 parcelable MediaQualityStatus {
   int rtpInactivityTimeMillis;
   int rtcpInactivityTimeMillis;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/MediaQualityThreshold.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/MediaQualityThreshold.aidl
index 31cf373..ecc379c 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/MediaQualityThreshold.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/MediaQualityThreshold.aidl
@@ -32,7 +32,8 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.ims.media;
-@VintfStability
+/* @hide */
+@JavaDerive(toString=true) @VintfStability
 parcelable MediaQualityThreshold {
   int[] rtpInactivityTimerMillis;
   int rtcpInactivityTimerMillis;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtcpConfig.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtcpConfig.aidl
index 6a76d85..0bc4154 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtcpConfig.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtcpConfig.aidl
@@ -32,7 +32,8 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.ims.media;
-@VintfStability
+/* @hide */
+@JavaDerive(toString=true) @VintfStability
 parcelable RtcpConfig {
   String canonicalName;
   int transmitPort;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtcpXrReportBlockType.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtcpXrReportBlockType.aidl
index 289c810..714442c 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtcpXrReportBlockType.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtcpXrReportBlockType.aidl
@@ -32,7 +32,8 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.ims.media;
-@Backing(type="int") @VintfStability
+/* @hide */
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum RtcpXrReportBlockType {
   RTCPXR_NONE = 0,
   RTCPXR_LOSS_RLE_REPORT_BLOCK = (1 << 0) /* 1 */,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtpAddress.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtpAddress.aidl
index 35357d1..dd7f466 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtpAddress.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtpAddress.aidl
@@ -32,7 +32,8 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.ims.media;
-@VintfStability
+/* @hide */
+@JavaDerive(toString=true) @VintfStability
 parcelable RtpAddress {
   String ipAddress;
   int portNumber;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtpConfig.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtpConfig.aidl
index 8a826f6..472ec35 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtpConfig.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtpConfig.aidl
@@ -32,7 +32,8 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.ims.media;
-@VintfStability
+/* @hide */
+@JavaDerive(toString=true) @VintfStability
 parcelable RtpConfig {
   int direction;
   android.hardware.radio.AccessNetwork accessNetwork;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtpError.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtpError.aidl
index 41b0aeb..97dacf1 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtpError.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtpError.aidl
@@ -32,7 +32,8 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.ims.media;
-@Backing(type="int") @VintfStability
+/* @hide */
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum RtpError {
   NONE = 0,
   INVALID_PARAM = 1,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtpHeaderExtension.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtpHeaderExtension.aidl
index 83b8a31..06207ee 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtpHeaderExtension.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtpHeaderExtension.aidl
@@ -32,7 +32,8 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.ims.media;
-@VintfStability
+/* @hide */
+@JavaDerive(toString=true) @VintfStability
 parcelable RtpHeaderExtension {
   int localId;
   byte[] data;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtpReceptionStats.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtpReceptionStats.aidl
new file mode 100644
index 0000000..82b798b
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtpReceptionStats.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.radio.ims.media;
+@VintfStability
+parcelable RtpReceptionStats {
+  int rtpTimestamp;
+  int rtpSequenceNumber;
+  int timeDurationMs;
+  int jitterBufferMs;
+  int roundTripTimeMs;
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtpSessionParams.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtpSessionParams.aidl
index 13a7487..4107432 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtpSessionParams.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims.media/current/android/hardware/radio/ims/media/RtpSessionParams.aidl
@@ -32,7 +32,8 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.ims.media;
-@VintfStability
+/* @hide */
+@JavaDerive(toString=true) @VintfStability
 parcelable RtpSessionParams {
   byte pTimeMillis;
   int maxPtimeMillis;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ConnectionFailureInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ConnectionFailureInfo.aidl
index 90e75f9..421f752 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ConnectionFailureInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ConnectionFailureInfo.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.ims;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable ConnectionFailureInfo {
   android.hardware.radio.ims.ConnectionFailureInfo.ConnectionFailureReason failureReason;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/EpsFallbackReason.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/EpsFallbackReason.aidl
index ebea903..75099e7 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/EpsFallbackReason.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/EpsFallbackReason.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.ims;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum EpsFallbackReason {
   NO_NETWORK_TRIGGER = 1,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/IRadioIms.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/IRadioIms.aidl
index 4df8709..6018a4b 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/IRadioIms.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/IRadioIms.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.ims;
+/* @hide */
 @VintfStability
 interface IRadioIms {
   oneway void setSrvccCallInfo(int serial, in android.hardware.radio.ims.SrvccCall[] srvccCalls);
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/IRadioImsIndication.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/IRadioImsIndication.aidl
index ef6b4cc..c754af3 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/IRadioImsIndication.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/IRadioImsIndication.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.ims;
+/* @hide */
 @VintfStability
 interface IRadioImsIndication {
   oneway void onConnectionSetupFailure(in android.hardware.radio.RadioIndicationType type, int token, in android.hardware.radio.ims.ConnectionFailureInfo info);
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/IRadioImsResponse.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/IRadioImsResponse.aidl
index 053ba46..fbb1bfc 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/IRadioImsResponse.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/IRadioImsResponse.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.ims;
+/* @hide */
 @VintfStability
 interface IRadioImsResponse {
   oneway void setSrvccCallInfoResponse(in android.hardware.radio.RadioResponseInfo info);
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsCall.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsCall.aidl
index 6e14830..3895d75 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsCall.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsCall.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.ims;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable ImsCall {
   int index;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsDeregistrationReason.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsDeregistrationReason.aidl
index b04e559..5b5bd40 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsDeregistrationReason.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsDeregistrationReason.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.ims;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum ImsDeregistrationReason {
   REASON_SIM_REMOVED = 1,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsRegistration.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsRegistration.aidl
index be5e004..66d8165 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsRegistration.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsRegistration.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.ims;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable ImsRegistration {
   android.hardware.radio.ims.ImsRegistrationState regState;
@@ -39,8 +40,8 @@
   android.hardware.radio.ims.SuggestedAction suggestedAction;
   int capabilities;
   const int IMS_MMTEL_CAPABILITY_NONE = 0;
-  const int IMS_MMTEL_CAPABILITY_VOICE = (1 << 0);
-  const int IMS_MMTEL_CAPABILITY_VIDEO = (1 << 1);
-  const int IMS_MMTEL_CAPABILITY_SMS = (1 << 2);
-  const int IMS_RCS_CAPABILITIES = (1 << 3);
+  const int IMS_MMTEL_CAPABILITY_VOICE = (1 << 0) /* 1 */;
+  const int IMS_MMTEL_CAPABILITY_VIDEO = (1 << 1) /* 2 */;
+  const int IMS_MMTEL_CAPABILITY_SMS = (1 << 2) /* 4 */;
+  const int IMS_RCS_CAPABILITIES = (1 << 3) /* 8 */;
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsRegistrationState.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsRegistrationState.aidl
index 6302b47..01ae565 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsRegistrationState.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsRegistrationState.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.ims;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum ImsRegistrationState {
   NOT_REGISTERED,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsStreamDirection.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsStreamDirection.aidl
index cf2e4f1..efc3551 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsStreamDirection.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsStreamDirection.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.ims;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum ImsStreamDirection {
   UPLINK = 1,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsStreamType.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsStreamType.aidl
index 10c477f..853f4b5 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsStreamType.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsStreamType.aidl
@@ -32,7 +32,8 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.ims;
-@Backing(type="int") @VintfStability
+/* @hide */
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum ImsStreamType {
   AUDIO = 1,
   VIDEO = 2,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsTrafficType.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsTrafficType.aidl
index b1a0b77..4eeda9d 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsTrafficType.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/ImsTrafficType.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.ims;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum ImsTrafficType {
   EMERGENCY,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/SrvccCall.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/SrvccCall.aidl
index 5119b0f..21645da 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/SrvccCall.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/SrvccCall.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.ims;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable SrvccCall {
   int index;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/SuggestedAction.aidl b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/SuggestedAction.aidl
index bbe170e..9846006 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/SuggestedAction.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.ims/current/android/hardware/radio/ims/SuggestedAction.aidl
@@ -32,9 +32,12 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.ims;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum SuggestedAction {
   NONE,
   TRIGGER_PLMN_BLOCK,
   TRIGGER_PLMN_BLOCK_WITH_TIMEOUT,
+  TRIGGER_RAT_BLOCK,
+  TRIGGER_CLEAR_RAT_BLOCKS,
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/CdmaBroadcastSmsConfigInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/CdmaBroadcastSmsConfigInfo.aidl
index 39e2be2..abfb308 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/CdmaBroadcastSmsConfigInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/CdmaBroadcastSmsConfigInfo.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.messaging;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable CdmaBroadcastSmsConfigInfo {
   int serviceCategory;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/CdmaSmsAck.aidl b/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/CdmaSmsAck.aidl
index befdbde..ee8371c 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/CdmaSmsAck.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/CdmaSmsAck.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.messaging;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable CdmaSmsAck {
   boolean errorClass;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/CdmaSmsAddress.aidl b/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/CdmaSmsAddress.aidl
index ab29c77..7382b1f 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/CdmaSmsAddress.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/CdmaSmsAddress.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.messaging;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable CdmaSmsAddress {
   int digitMode;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/CdmaSmsMessage.aidl b/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/CdmaSmsMessage.aidl
index 867596c..0e98f4b 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/CdmaSmsMessage.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/CdmaSmsMessage.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.messaging;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable CdmaSmsMessage {
   int teleserviceId;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/CdmaSmsSubaddress.aidl b/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/CdmaSmsSubaddress.aidl
index d67fe8c..a0e3991 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/CdmaSmsSubaddress.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/CdmaSmsSubaddress.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.messaging;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable CdmaSmsSubaddress {
   int subaddressType;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/CdmaSmsWriteArgs.aidl b/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/CdmaSmsWriteArgs.aidl
index b0a7f98..d6292e7 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/CdmaSmsWriteArgs.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/CdmaSmsWriteArgs.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.messaging;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable CdmaSmsWriteArgs {
   int status;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/GsmBroadcastSmsConfigInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/GsmBroadcastSmsConfigInfo.aidl
index 46604ca..1ccba86 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/GsmBroadcastSmsConfigInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/GsmBroadcastSmsConfigInfo.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.messaging;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable GsmBroadcastSmsConfigInfo {
   int fromServiceId;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/GsmSmsMessage.aidl b/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/GsmSmsMessage.aidl
index 4df7fd2..bdd7d0c 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/GsmSmsMessage.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/GsmSmsMessage.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.messaging;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable GsmSmsMessage {
   String smscPdu;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/IRadioMessaging.aidl b/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/IRadioMessaging.aidl
index dfec59a..bf5fde5 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/IRadioMessaging.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/IRadioMessaging.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.messaging;
+/* @hide */
 @VintfStability
 interface IRadioMessaging {
   oneway void acknowledgeIncomingGsmSmsWithPdu(in int serial, in boolean success, in String ackPdu);
diff --git a/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/IRadioMessagingIndication.aidl b/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/IRadioMessagingIndication.aidl
index 8f7824f..389fb26 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/IRadioMessagingIndication.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/IRadioMessagingIndication.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.messaging;
+/* @hide */
 @VintfStability
 interface IRadioMessagingIndication {
   oneway void cdmaNewSms(in android.hardware.radio.RadioIndicationType type, in android.hardware.radio.messaging.CdmaSmsMessage msg);
diff --git a/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/IRadioMessagingResponse.aidl b/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/IRadioMessagingResponse.aidl
index c3af7a6..9b10464 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/IRadioMessagingResponse.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/IRadioMessagingResponse.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.messaging;
+/* @hide */
 @VintfStability
 interface IRadioMessagingResponse {
   oneway void acknowledgeIncomingGsmSmsWithPduResponse(in android.hardware.radio.RadioResponseInfo info);
diff --git a/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/ImsSmsMessage.aidl b/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/ImsSmsMessage.aidl
index 85f62b7..40b9ddb 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/ImsSmsMessage.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/ImsSmsMessage.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.messaging;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable ImsSmsMessage {
   android.hardware.radio.RadioTechnologyFamily tech;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/SendSmsResult.aidl b/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/SendSmsResult.aidl
index 32f7a5c..3f1d120 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/SendSmsResult.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/SendSmsResult.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.messaging;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable SendSmsResult {
   int messageRef;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/SmsAcknowledgeFailCause.aidl b/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/SmsAcknowledgeFailCause.aidl
index d061c9e..6aeda3e 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/SmsAcknowledgeFailCause.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/SmsAcknowledgeFailCause.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.messaging;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum SmsAcknowledgeFailCause {
   MEMORY_CAPACITY_EXCEEDED = 0xD3,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/SmsWriteArgs.aidl b/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/SmsWriteArgs.aidl
index 489cc07..a294b47 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/SmsWriteArgs.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.messaging/current/android/hardware/radio/messaging/SmsWriteArgs.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.messaging;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable SmsWriteArgs {
   int status;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/ActivityStatsInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/ActivityStatsInfo.aidl
index 7e22ee0..c834342 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/ActivityStatsInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/ActivityStatsInfo.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.modem;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable ActivityStatsInfo {
   int sleepModeTimeMs;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/ActivityStatsTechSpecificInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/ActivityStatsTechSpecificInfo.aidl
index 08ed9a5..b44ab71 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/ActivityStatsTechSpecificInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/ActivityStatsTechSpecificInfo.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.modem;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable ActivityStatsTechSpecificInfo {
   android.hardware.radio.AccessNetwork rat;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/DeviceStateType.aidl b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/DeviceStateType.aidl
index acc0b22..1159f93 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/DeviceStateType.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/DeviceStateType.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.modem;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum DeviceStateType {
   POWER_SAVE_MODE,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/HardwareConfig.aidl b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/HardwareConfig.aidl
index 3a0ec25..2d814ef 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/HardwareConfig.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/HardwareConfig.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.modem;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable HardwareConfig {
   int type;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/HardwareConfigModem.aidl b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/HardwareConfigModem.aidl
index 62bb160..d453cb0 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/HardwareConfigModem.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/HardwareConfigModem.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.modem;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable HardwareConfigModem {
   int rilModel;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/HardwareConfigSim.aidl b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/HardwareConfigSim.aidl
index 5810982..4c2e31b 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/HardwareConfigSim.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/HardwareConfigSim.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.modem;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable HardwareConfigSim {
   String modemUuid;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/IRadioModem.aidl b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/IRadioModem.aidl
index 8546be7..bd8ba47 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/IRadioModem.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/IRadioModem.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.modem;
+/* @hide */
 @VintfStability
 interface IRadioModem {
   oneway void enableModem(in int serial, in boolean on);
diff --git a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/IRadioModemIndication.aidl b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/IRadioModemIndication.aidl
index 514ff9a..3c06877 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/IRadioModemIndication.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/IRadioModemIndication.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.modem;
+/* @hide */
 @VintfStability
 interface IRadioModemIndication {
   oneway void hardwareConfigChanged(in android.hardware.radio.RadioIndicationType type, in android.hardware.radio.modem.HardwareConfig[] configs);
@@ -39,4 +40,5 @@
   oneway void radioCapabilityIndication(in android.hardware.radio.RadioIndicationType type, in android.hardware.radio.modem.RadioCapability rc);
   oneway void radioStateChanged(in android.hardware.radio.RadioIndicationType type, in android.hardware.radio.modem.RadioState radioState);
   oneway void rilConnected(in android.hardware.radio.RadioIndicationType type);
+  oneway void onImeiMappingChanged(in android.hardware.radio.RadioIndicationType type, in android.hardware.radio.modem.ImeiInfo imeiInfo);
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/IRadioModemResponse.aidl b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/IRadioModemResponse.aidl
index 5955439..b9ef51b 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/IRadioModemResponse.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/IRadioModemResponse.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.modem;
+/* @hide */
 @VintfStability
 interface IRadioModemResponse {
   oneway void acknowledgeRequest(in int serial);
diff --git a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/ImeiInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/ImeiInfo.aidl
index f8776ec..a2df30d 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/ImeiInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/ImeiInfo.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.modem;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable ImeiInfo {
   android.hardware.radio.modem.ImeiInfo.ImeiType type;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/NvItem.aidl b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/NvItem.aidl
index b80d7ac..f97b9a2 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/NvItem.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/NvItem.aidl
@@ -33,6 +33,7 @@
 
 package android.hardware.radio.modem;
 /**
+ * @hide
  * @deprecated NV APIs are deprecated starting from Android U.
  */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
diff --git a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/NvWriteItem.aidl b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/NvWriteItem.aidl
index 6a786bc..c38ceb7 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/NvWriteItem.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/NvWriteItem.aidl
@@ -33,6 +33,7 @@
 
 package android.hardware.radio.modem;
 /**
+ * @hide
  * @deprecated NV APIs are deprecated starting from Android U.
  */
 @JavaDerive(toString=true) @VintfStability
diff --git a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/RadioCapability.aidl b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/RadioCapability.aidl
index f2e2858..bc3cfcc 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/RadioCapability.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/RadioCapability.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.modem;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable RadioCapability {
   int session;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/RadioState.aidl b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/RadioState.aidl
index 57f2941..3383fa4 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/RadioState.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/RadioState.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.modem;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum RadioState {
   OFF = 0,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/ResetNvType.aidl b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/ResetNvType.aidl
index 37622b1..b4208b7 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/ResetNvType.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/ResetNvType.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.modem;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum ResetNvType {
   RELOAD,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/AccessTechnologySpecificInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/AccessTechnologySpecificInfo.aidl
index 28d8862..667a8a7 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/AccessTechnologySpecificInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/AccessTechnologySpecificInfo.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 union AccessTechnologySpecificInfo {
   boolean noinit;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/BarringInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/BarringInfo.aidl
index e105b39..67c9349 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/BarringInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/BarringInfo.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable BarringInfo {
   int serviceType;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/BarringTypeSpecificInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/BarringTypeSpecificInfo.aidl
index a813633..03369b9 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/BarringTypeSpecificInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/BarringTypeSpecificInfo.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable BarringTypeSpecificInfo {
   int factor;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/Cdma2000RegistrationInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/Cdma2000RegistrationInfo.aidl
index 927f9ac..bc9c0ba 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/Cdma2000RegistrationInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/Cdma2000RegistrationInfo.aidl
@@ -32,13 +32,14 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable Cdma2000RegistrationInfo {
   boolean cssSupported;
   int roamingIndicator;
   int systemIsInPrl;
   int defaultRoamingIndicator;
-  const int PRL_INDICATOR_NOT_REGISTERED = (-1);
+  const int PRL_INDICATOR_NOT_REGISTERED = (-1) /* -1 */;
   const int PRL_INDICATOR_NOT_IN_PRL = 0;
   const int PRL_INDICATOR_IN_PRL = 1;
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CdmaRoamingType.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CdmaRoamingType.aidl
index 2a4db70..84532e3 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CdmaRoamingType.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CdmaRoamingType.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum CdmaRoamingType {
   HOME_NETWORK,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CdmaSignalStrength.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CdmaSignalStrength.aidl
index e2f97bf..94430a8 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CdmaSignalStrength.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CdmaSignalStrength.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable CdmaSignalStrength {
   int dbm;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellConnectionStatus.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellConnectionStatus.aidl
index 5ce3b3e..3775a40 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellConnectionStatus.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellConnectionStatus.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum CellConnectionStatus {
   NONE,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellIdentity.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellIdentity.aidl
index 2ee92de..ba27b39 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellIdentity.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellIdentity.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 union CellIdentity {
   boolean noinit;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellIdentityCdma.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellIdentityCdma.aidl
index d659a28..63571bb 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellIdentityCdma.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellIdentityCdma.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable CellIdentityCdma {
   int networkId;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellIdentityGsm.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellIdentityGsm.aidl
index d3193be..5040f20 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellIdentityGsm.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellIdentityGsm.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable CellIdentityGsm {
   String mcc;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellIdentityLte.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellIdentityLte.aidl
index 2ae7b43..be7821d 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellIdentityLte.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellIdentityLte.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable CellIdentityLte {
   String mcc;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellIdentityNr.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellIdentityNr.aidl
index b30af50..6f4f9a0 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellIdentityNr.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellIdentityNr.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable CellIdentityNr {
   String mcc;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellIdentityTdscdma.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellIdentityTdscdma.aidl
index e99d147..864a886 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellIdentityTdscdma.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellIdentityTdscdma.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable CellIdentityTdscdma {
   String mcc;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellIdentityWcdma.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellIdentityWcdma.aidl
index 12001fc..4e76277 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellIdentityWcdma.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellIdentityWcdma.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable CellIdentityWcdma {
   String mcc;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellInfo.aidl
index 467c6b7..6bb31b0 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellInfo.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable CellInfo {
   boolean registered;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellInfoCdma.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellInfoCdma.aidl
index e3bf46b..6d76a26 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellInfoCdma.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellInfoCdma.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable CellInfoCdma {
   android.hardware.radio.network.CellIdentityCdma cellIdentityCdma;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellInfoGsm.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellInfoGsm.aidl
index 84dcd07..2074c2f 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellInfoGsm.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellInfoGsm.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable CellInfoGsm {
   android.hardware.radio.network.CellIdentityGsm cellIdentityGsm;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellInfoLte.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellInfoLte.aidl
index 221340b..aa3b310 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellInfoLte.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellInfoLte.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable CellInfoLte {
   android.hardware.radio.network.CellIdentityLte cellIdentityLte;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellInfoNr.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellInfoNr.aidl
index b392c1d..a8f49af 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellInfoNr.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellInfoNr.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable CellInfoNr {
   android.hardware.radio.network.CellIdentityNr cellIdentityNr;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellInfoRatSpecificInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellInfoRatSpecificInfo.aidl
index 4ab0640..fd3239d 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellInfoRatSpecificInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellInfoRatSpecificInfo.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 union CellInfoRatSpecificInfo {
   android.hardware.radio.network.CellInfoGsm gsm;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellInfoTdscdma.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellInfoTdscdma.aidl
index 138b35c..1a03f34 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellInfoTdscdma.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellInfoTdscdma.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable CellInfoTdscdma {
   android.hardware.radio.network.CellIdentityTdscdma cellIdentityTdscdma;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellInfoWcdma.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellInfoWcdma.aidl
index cf7b135..d02824d 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellInfoWcdma.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellInfoWcdma.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable CellInfoWcdma {
   android.hardware.radio.network.CellIdentityWcdma cellIdentityWcdma;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellularIdentifier.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellularIdentifier.aidl
new file mode 100644
index 0000000..d38494f
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellularIdentifier.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.radio.network;
+/* @hide */
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
+enum CellularIdentifier {
+  UNKNOWN = 0,
+  IMSI = 1,
+  IMEI = 2,
+  SUCI = 3,
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellularIdentifierDisclosure.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellularIdentifierDisclosure.aidl
new file mode 100644
index 0000000..cb542e8
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/CellularIdentifierDisclosure.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.radio.network;
+/* @hide */
+@JavaDerive(toString=true) @VintfStability
+parcelable CellularIdentifierDisclosure {
+  String plmn;
+  android.hardware.radio.network.CellularIdentifier identifier;
+  android.hardware.radio.network.NasProtocolMessage protocolMessage;
+  boolean isEmergency;
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/ClosedSubscriberGroupInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/ClosedSubscriberGroupInfo.aidl
index fe734c8..b9e6f82 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/ClosedSubscriberGroupInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/ClosedSubscriberGroupInfo.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable ClosedSubscriberGroupInfo {
   boolean csgIndication;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/ConnectionEvent.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/ConnectionEvent.aidl
new file mode 100644
index 0000000..1529512
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/ConnectionEvent.aidl
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.radio.network;
+/* @hide */
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
+enum ConnectionEvent {
+  CS_SIGNALLING_GSM = 0,
+  PS_SIGNALLING_GPRS = 1,
+  CS_SIGNALLING_3G = 2,
+  PS_SIGNALLING_3G = 3,
+  NAS_SIGNALLING_LTE = 4,
+  AS_SIGNALLING_LTE = 5,
+  VOLTE_SIP = 6,
+  VOLTE_SIP_SOS = 7,
+  VOLTE_RTP = 8,
+  VOLTE_RTP_SOS = 9,
+  NAS_SIGNALLING_5G = 10,
+  AS_SIGNALLING_5G = 11,
+  VONR_SIP = 12,
+  VONR_SIP_SOS = 13,
+  VONR_RTP = 14,
+  VONR_RTP_SOS = 15,
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/Domain.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/Domain.aidl
index 6b022b6..0de7e20 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/Domain.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/Domain.aidl
@@ -32,8 +32,9 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum Domain {
-  CS = (1 << 0),
-  PS = (1 << 1),
+  CS = (1 << 0) /* 1 */,
+  PS = (1 << 1) /* 2 */,
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EmergencyMode.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EmergencyMode.aidl
index 071e6b5..c5b067e 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EmergencyMode.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EmergencyMode.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum EmergencyMode {
   EMERGENCY_WWAN = 1,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EmergencyNetworkScanTrigger.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EmergencyNetworkScanTrigger.aidl
index 2797aff..471c7a0 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EmergencyNetworkScanTrigger.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EmergencyNetworkScanTrigger.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable EmergencyNetworkScanTrigger {
   android.hardware.radio.AccessNetwork[] accessNetwork;
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 7d99a53..3b8083d 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
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable EmergencyRegResult {
   android.hardware.radio.AccessNetwork accessNetwork;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EmergencyScanType.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EmergencyScanType.aidl
index 5e86c76..0681a73 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EmergencyScanType.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EmergencyScanType.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum EmergencyScanType {
   NO_PREFERENCE = 0,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EutranBands.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EutranBands.aidl
index 57fac3f..82257ec 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EutranBands.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EutranBands.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum EutranBands {
   BAND_1 = 1,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EutranRegistrationInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EutranRegistrationInfo.aidl
index 90e342a..bb34fe1 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EutranRegistrationInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EutranRegistrationInfo.aidl
@@ -32,14 +32,15 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable EutranRegistrationInfo {
   android.hardware.radio.network.LteVopsInfo lteVopsInfo;
   android.hardware.radio.network.NrIndicators nrIndicators;
   android.hardware.radio.network.EutranRegistrationInfo.AttachResultType lteAttachResultType;
   int extraInfo;
-  const int EXTRA_CSFB_NOT_PREFERRED = (1 << 0);
-  const int EXTRA_SMS_ONLY = (1 << 1);
+  const int EXTRA_CSFB_NOT_PREFERRED = (1 << 0) /* 1 */;
+  const int EXTRA_SMS_ONLY = (1 << 1) /* 2 */;
   enum AttachResultType {
     NONE,
     EPS_ONLY,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EvdoSignalStrength.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EvdoSignalStrength.aidl
index 7c56711..e97e17d 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EvdoSignalStrength.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EvdoSignalStrength.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable EvdoSignalStrength {
   int dbm;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/GeranBands.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/GeranBands.aidl
index 135935f..ee0d419 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/GeranBands.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/GeranBands.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum GeranBands {
   BAND_T380 = 1,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/GsmSignalStrength.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/GsmSignalStrength.aidl
index 2b53b39..65847ef 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/GsmSignalStrength.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/GsmSignalStrength.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable GsmSignalStrength {
   int signalStrength;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetwork.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetwork.aidl
index 382ddd8..8af617f 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetwork.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetwork.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @VintfStability
 interface IRadioNetwork {
   oneway void getAllowedNetworkTypesBitmap(in int serial);
@@ -81,4 +82,8 @@
   oneway void isNullCipherAndIntegrityEnabled(in int serial);
   oneway void isN1ModeEnabled(in int serial);
   oneway void setN1ModeEnabled(in int serial, boolean enable);
+  oneway void isCellularIdentifierTransparencyEnabled(in int serial);
+  oneway void setCellularIdentifierTransparencyEnabled(in int serial, in boolean enabled);
+  oneway void setSecurityAlgorithmsUpdatedEnabled(in int serial, boolean enable);
+  oneway void isSecurityAlgorithmsUpdatedEnabled(in int serial);
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkIndication.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkIndication.aidl
index 0f017ea..8eea14f 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkIndication.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkIndication.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @VintfStability
 interface IRadioNetworkIndication {
   oneway void barringInfoChanged(in android.hardware.radio.RadioIndicationType type, in android.hardware.radio.network.CellIdentity cellIdentity, in android.hardware.radio.network.BarringInfo[] barringInfos);
@@ -49,4 +50,6 @@
   oneway void suppSvcNotify(in android.hardware.radio.RadioIndicationType type, in android.hardware.radio.network.SuppSvcNotification suppSvc);
   oneway void voiceRadioTechChanged(in android.hardware.radio.RadioIndicationType type, in android.hardware.radio.RadioTechnology rat);
   oneway void emergencyNetworkScanResult(in android.hardware.radio.RadioIndicationType type, in android.hardware.radio.network.EmergencyRegResult result);
+  oneway void cellularIdentifierDisclosed(in android.hardware.radio.RadioIndicationType type, in android.hardware.radio.network.CellularIdentifierDisclosure disclosure);
+  oneway void securityAlgorithmsUpdated(in android.hardware.radio.RadioIndicationType type, in android.hardware.radio.network.SecurityAlgorithmUpdate securityAlgorithmUpdate);
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkResponse.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkResponse.aidl
index bfe8fa3..e7f2918 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkResponse.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkResponse.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @VintfStability
 interface IRadioNetworkResponse {
   oneway void acknowledgeRequest(in int serial);
@@ -80,4 +81,8 @@
   oneway void isNullCipherAndIntegrityEnabledResponse(in android.hardware.radio.RadioResponseInfo info, in boolean isEnabled);
   oneway void isN1ModeEnabledResponse(in android.hardware.radio.RadioResponseInfo info, boolean isEnabled);
   oneway void setN1ModeEnabledResponse(in android.hardware.radio.RadioResponseInfo info);
+  oneway void isCellularIdentifierTransparencyEnabledResponse(in android.hardware.radio.RadioResponseInfo info, boolean isEnabled);
+  oneway void setCellularIdentifierTransparencyEnabledResponse(in android.hardware.radio.RadioResponseInfo info);
+  oneway void setSecurityAlgorithmsUpdatedEnabledResponse(in android.hardware.radio.RadioResponseInfo info);
+  oneway void isSecurityAlgorithmsUpdatedEnabledResponse(in android.hardware.radio.RadioResponseInfo info, in boolean isEnabled);
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IndicationFilter.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IndicationFilter.aidl
index 00ba346..7847fbe 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IndicationFilter.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IndicationFilter.aidl
@@ -32,15 +32,16 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum IndicationFilter {
   NONE = 0,
-  ALL = (~0),
-  SIGNAL_STRENGTH = (1 << 0),
-  FULL_NETWORK_STATE = (1 << 1),
-  DATA_CALL_DORMANCY_CHANGED = (1 << 2),
-  LINK_CAPACITY_ESTIMATE = (1 << 3),
-  PHYSICAL_CHANNEL_CONFIG = (1 << 4),
-  REGISTRATION_FAILURE = (1 << 5),
-  BARRING_INFO = (1 << 6),
+  ALL = (~0) /* -1 */,
+  SIGNAL_STRENGTH = (1 << 0) /* 1 */,
+  FULL_NETWORK_STATE = (1 << 1) /* 2 */,
+  DATA_CALL_DORMANCY_CHANGED = (1 << 2) /* 4 */,
+  LINK_CAPACITY_ESTIMATE = (1 << 3) /* 8 */,
+  PHYSICAL_CHANNEL_CONFIG = (1 << 4) /* 16 */,
+  REGISTRATION_FAILURE = (1 << 5) /* 32 */,
+  BARRING_INFO = (1 << 6) /* 64 */,
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LceDataInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LceDataInfo.aidl
index 27b16c1..6dc6d3e 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LceDataInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LceDataInfo.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable LceDataInfo {
   int lastHopCapacityKbps;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LinkCapacityEstimate.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LinkCapacityEstimate.aidl
index 5707b8e..3fc4b5c 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LinkCapacityEstimate.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LinkCapacityEstimate.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable LinkCapacityEstimate {
   int downlinkCapacityKbps;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LteSignalStrength.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LteSignalStrength.aidl
index b5b8579..eb2ca28 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LteSignalStrength.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LteSignalStrength.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable LteSignalStrength {
   int signalStrength;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LteVopsInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LteVopsInfo.aidl
index 6d8dd4e..f8d3aa1 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LteVopsInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LteVopsInfo.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable LteVopsInfo {
   boolean isVopsSupported;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/NasProtocolMessage.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/NasProtocolMessage.aidl
new file mode 100644
index 0000000..4fbc802
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/NasProtocolMessage.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.radio.network;
+/* @hide */
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
+enum NasProtocolMessage {
+  UNKNOWN = 0,
+  ATTACH_REQUEST = 1,
+  IDENTITY_RESPONSE = 2,
+  DETACH_REQUEST = 3,
+  TRACKING_AREA_UPDATE_REQUEST = 4,
+  LOCATION_UPDATE_REQUEST = 5,
+  AUTHENTICATION_AND_CIPHERING_RESPONSE = 6,
+  REGISTRATION_REQUEST = 7,
+  DEREGISTRATION_REQUEST = 8,
+  CM_REESTABLISHMENT_REQUEST = 9,
+  CM_SERVICE_REQUEST = 10,
+  IMSI_DETACH_INDICATION = 11,
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/NetworkScanRequest.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/NetworkScanRequest.aidl
index 6039740..60eaf77 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/NetworkScanRequest.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/NetworkScanRequest.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable NetworkScanRequest {
   int type;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/NetworkScanResult.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/NetworkScanResult.aidl
index 4e392d0..695a194 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/NetworkScanResult.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/NetworkScanResult.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable NetworkScanResult {
   int status;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/NgranBands.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/NgranBands.aidl
index 5904690..fb939df 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/NgranBands.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/NgranBands.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum NgranBands {
   BAND_1 = 1,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/NrDualConnectivityState.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/NrDualConnectivityState.aidl
index 62c2a56..7af15a7 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/NrDualConnectivityState.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/NrDualConnectivityState.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @Backing(type="byte") @JavaDerive(toString=true) @VintfStability
 enum NrDualConnectivityState {
   ENABLE = 1,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/NrIndicators.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/NrIndicators.aidl
index 88429f6..efcd6d3 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/NrIndicators.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/NrIndicators.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable NrIndicators {
   boolean isEndcAvailable;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/NrSignalStrength.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/NrSignalStrength.aidl
index 7d6ab82..11e7356 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/NrSignalStrength.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/NrSignalStrength.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable NrSignalStrength {
   int ssRsrp;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/NrVopsInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/NrVopsInfo.aidl
index e5a0a70..61146aa 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/NrVopsInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/NrVopsInfo.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable NrVopsInfo {
   byte vopsSupported;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/OperatorInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/OperatorInfo.aidl
index 034150e..abe2bea 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/OperatorInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/OperatorInfo.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable OperatorInfo {
   String alphaLong;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/PhoneRestrictedState.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/PhoneRestrictedState.aidl
index 4e3e39e..44cab0e 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/PhoneRestrictedState.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/PhoneRestrictedState.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum PhoneRestrictedState {
   NONE = 0x00,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/PhysicalChannelConfig.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/PhysicalChannelConfig.aidl
index 928c6b7..7d64f7e 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/PhysicalChannelConfig.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/PhysicalChannelConfig.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable PhysicalChannelConfig {
   android.hardware.radio.network.CellConnectionStatus status;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/PhysicalChannelConfigBand.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/PhysicalChannelConfigBand.aidl
index efc64a6..2e50e67 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/PhysicalChannelConfigBand.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/PhysicalChannelConfigBand.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 union PhysicalChannelConfigBand {
   boolean noinit;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/RadioAccessSpecifier.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/RadioAccessSpecifier.aidl
index 1566bb5..8229207 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/RadioAccessSpecifier.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/RadioAccessSpecifier.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable RadioAccessSpecifier {
   android.hardware.radio.AccessNetwork accessNetwork;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/RadioAccessSpecifierBands.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/RadioAccessSpecifierBands.aidl
index a6ac12a..9ba420e 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/RadioAccessSpecifierBands.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/RadioAccessSpecifierBands.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 union RadioAccessSpecifierBands {
   boolean noinit;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/RadioBandMode.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/RadioBandMode.aidl
index 74696fb..6058e30 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/RadioBandMode.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/RadioBandMode.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum RadioBandMode {
   BAND_MODE_UNSPECIFIED,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/RegState.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/RegState.aidl
index 711c9ac..f11b911 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/RegState.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/RegState.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum RegState {
   NOT_REG_MT_NOT_SEARCHING_OP = 0,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/RegStateResult.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/RegStateResult.aidl
index f0a03ae..625d970 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/RegStateResult.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/RegStateResult.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable RegStateResult {
   android.hardware.radio.network.RegState regState;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/RegistrationFailCause.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/RegistrationFailCause.aidl
index 8acf8ab..fcc079e 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/RegistrationFailCause.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/RegistrationFailCause.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum RegistrationFailCause {
   NONE = 0,
@@ -49,7 +50,11 @@
   ROAMING_NOT_ALLOWED = 13,
   GPRS_SERVICES_NOT_ALLOWED_IN_PLMN = 14,
   NO_SUITABLE_CELLS = 15,
+  /**
+   * @deprecated MSC_TEMPORARILY_NOT_REACHABLE value is wrong and should not be used. Use MSC_TEMP_NOT_REACHABLE instead.
+   */
   MSC_TEMPORARILY_NOT_REACHABLE = 15,
+  MSC_TEMP_NOT_REACHABLE = 16,
   NETWORK_FAILURE = 17,
   MAC_FAILURE = 20,
   SYNC_FAILURE = 21,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/SecurityAlgorithm.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/SecurityAlgorithm.aidl
new file mode 100644
index 0000000..c3333bf
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/SecurityAlgorithm.aidl
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.radio.network;
+/* @hide */
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
+enum SecurityAlgorithm {
+  A50 = 0,
+  A51 = 1,
+  A52 = 2,
+  A53 = 3,
+  A54 = 4,
+  GEA0 = 14,
+  GEA1 = 15,
+  GEA2 = 16,
+  GEA3 = 17,
+  GEA4 = 18,
+  GEA5 = 19,
+  UEA0 = 29,
+  UEA1 = 30,
+  UEA2 = 31,
+  EEA0 = 41,
+  EEA1 = 42,
+  EEA2 = 43,
+  EEA3 = 44,
+  NEA0 = 55,
+  NEA1 = 56,
+  NEA2 = 57,
+  NEA3 = 58,
+  SIP_NO_IPSEC_CONFIG = 66,
+  IMS_NULL = 67,
+  SIP_NULL = 68,
+  AES_GCM = 69,
+  AES_GMAC = 70,
+  AES_CBC = 71,
+  DES_EDE3_CBC = 72,
+  AES_EDE3_CBC = 73,
+  HMAC_SHA1_96 = 74,
+  HMAC_MD5_96 = 75,
+  RTP = 85,
+  SRTP_NULL = 86,
+  SRTP_AES_COUNTER = 87,
+  SRTP_AES_F8 = 88,
+  SRTP_HMAC_SHA1 = 89,
+  ENCR_AES_GCM_16 = 99,
+  ENCR_AES_CBC = 100,
+  AUTH_HMAC_SHA2_256_128 = 101,
+  UNKNOWN = 113,
+  OTHER = 114,
+  ORYX = 124,
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/SecurityAlgorithmUpdate.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/SecurityAlgorithmUpdate.aidl
new file mode 100644
index 0000000..73ad180
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/SecurityAlgorithmUpdate.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.radio.network;
+/* @hide */
+@JavaDerive(toString=true) @VintfStability
+parcelable SecurityAlgorithmUpdate {
+  android.hardware.radio.network.ConnectionEvent connectionEvent;
+  android.hardware.radio.network.SecurityAlgorithm encryption;
+  android.hardware.radio.network.SecurityAlgorithm integrity;
+  boolean isUnprotectedEmergency;
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/SignalStrength.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/SignalStrength.aidl
index 1c50190..da7db9a 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/SignalStrength.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/SignalStrength.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable SignalStrength {
   android.hardware.radio.network.GsmSignalStrength gsm;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/SignalThresholdInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/SignalThresholdInfo.aidl
index 744eed7..77b4831 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/SignalThresholdInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/SignalThresholdInfo.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable SignalThresholdInfo {
   int signalMeasurement;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/SuppSvcNotification.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/SuppSvcNotification.aidl
index b62c71b..5192eae 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/SuppSvcNotification.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/SuppSvcNotification.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable SuppSvcNotification {
   boolean isMT;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/TdscdmaSignalStrength.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/TdscdmaSignalStrength.aidl
index d74c950..fe209e5 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/TdscdmaSignalStrength.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/TdscdmaSignalStrength.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable TdscdmaSignalStrength {
   int signalStrength;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/UsageSetting.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/UsageSetting.aidl
index 3ca16b5..a6f4d13 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/UsageSetting.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/UsageSetting.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum UsageSetting {
   VOICE_CENTRIC = 1,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/UtranBands.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/UtranBands.aidl
index 8be3da2..977afe3 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/UtranBands.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/UtranBands.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum UtranBands {
   BAND_1 = 1,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/WcdmaSignalStrength.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/WcdmaSignalStrength.aidl
index 9112527..b765ab6 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/WcdmaSignalStrength.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/WcdmaSignalStrength.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable WcdmaSignalStrength {
   int signalStrength;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/AppStatus.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/AppStatus.aidl
index 8a41fb9..898b616 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/AppStatus.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/AppStatus.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.sim;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable AppStatus {
   int appType;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/CardPowerState.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/CardPowerState.aidl
index 6bc3919..066777a 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/CardPowerState.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/CardPowerState.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.sim;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum CardPowerState {
   POWER_DOWN,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/CardStatus.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/CardStatus.aidl
index 46cb7be..1a9d621 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/CardStatus.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/CardStatus.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.sim;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable CardStatus {
   int cardState;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/Carrier.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/Carrier.aidl
index cc56888..24fff2e 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/Carrier.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/Carrier.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.sim;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable Carrier {
   String mcc;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/CarrierInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/CarrierInfo.aidl
new file mode 100644
index 0000000..7d4a54b
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/CarrierInfo.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.radio.sim;
+/* @hide */
+@JavaDerive(toString=true) @VintfStability
+parcelable CarrierInfo {
+  String mcc;
+  String mnc;
+  @nullable String spn;
+  @nullable String gid1;
+  @nullable String gid2;
+  @nullable String imsiPrefix;
+  @nullable List<android.hardware.radio.sim.Plmn> ehplmn;
+  @nullable String iccid;
+  @nullable String impi;
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/CarrierRestrictions.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/CarrierRestrictions.aidl
index 3700de3..a5b8dc9 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/CarrierRestrictions.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/CarrierRestrictions.aidl
@@ -32,12 +32,21 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.sim;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable CarrierRestrictions {
+  /**
+   * @deprecated use @List<CarrierInfo> allowedCarrierInfoList
+   */
   android.hardware.radio.sim.Carrier[] allowedCarriers;
+  /**
+   * @deprecated use @List<CarrierInfo> excludedCarrierInfoList
+   */
   android.hardware.radio.sim.Carrier[] excludedCarriers;
   boolean allowedCarriersPrioritized;
   android.hardware.radio.sim.CarrierRestrictions.CarrierRestrictionStatus status;
+  android.hardware.radio.sim.CarrierInfo[] allowedCarrierInfoList = {};
+  android.hardware.radio.sim.CarrierInfo[] excludedCarrierInfoList = {};
   @Backing(type="int") @VintfStability
   enum CarrierRestrictionStatus {
     UNKNOWN = 0,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/CdmaSubscriptionSource.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/CdmaSubscriptionSource.aidl
index 080aa5e..13b06e7 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/CdmaSubscriptionSource.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/CdmaSubscriptionSource.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.sim;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum CdmaSubscriptionSource {
   RUIM_SIM,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/IRadioSim.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/IRadioSim.aidl
index 901b251..1728e41 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/IRadioSim.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/IRadioSim.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.sim;
+/* @hide */
 @VintfStability
 interface IRadioSim {
   oneway void areUiccApplicationsEnabled(in int serial);
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/IRadioSimIndication.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/IRadioSimIndication.aidl
index d4371b8..a74b65a 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/IRadioSimIndication.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/IRadioSimIndication.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.sim;
+/* @hide */
 @VintfStability
 interface IRadioSimIndication {
   oneway void carrierInfoForImsiEncryption(in android.hardware.radio.RadioIndicationType info);
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/IRadioSimResponse.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/IRadioSimResponse.aidl
index d7c2100..c653847 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/IRadioSimResponse.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/IRadioSimResponse.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.sim;
+/* @hide */
 @VintfStability
 interface IRadioSimResponse {
   oneway void acknowledgeRequest(in int serial);
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/IccIo.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/IccIo.aidl
index 5a312dc..661518d 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/IccIo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/IccIo.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.sim;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable IccIo {
   int command;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/IccIoResult.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/IccIoResult.aidl
index 6c6bde2..1e418cd 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/IccIoResult.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/IccIoResult.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.sim;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable IccIoResult {
   int sw1;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/ImsiEncryptionInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/ImsiEncryptionInfo.aidl
index 05e71cd..40722e5 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/ImsiEncryptionInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/ImsiEncryptionInfo.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.sim;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable ImsiEncryptionInfo {
   String mcc;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/PbReceivedStatus.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/PbReceivedStatus.aidl
index 5e96fc6..aaf9f3e 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/PbReceivedStatus.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/PbReceivedStatus.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.sim;
+/* @hide */
 @Backing(type="byte") @JavaDerive(toString=true) @VintfStability
 enum PbReceivedStatus {
   PB_RECEIVED_OK = 1,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/PersoSubstate.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/PersoSubstate.aidl
index dc1d960..7952308 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/PersoSubstate.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/PersoSubstate.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.sim;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum PersoSubstate {
   UNKNOWN,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/PhonebookCapacity.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/PhonebookCapacity.aidl
index 7531c96..b020687 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/PhonebookCapacity.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/PhonebookCapacity.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.sim;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable PhonebookCapacity {
   int maxAdnRecords;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/PhonebookRecordInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/PhonebookRecordInfo.aidl
index 2e96a4b..1a6943b 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/PhonebookRecordInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/PhonebookRecordInfo.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.sim;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable PhonebookRecordInfo {
   int recordId;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/PinState.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/PinState.aidl
index 663ea73..924929b 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/PinState.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/PinState.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.sim;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum PinState {
   UNKNOWN,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/Plmn.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/Plmn.aidl
new file mode 100644
index 0000000..b29a4a7
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/Plmn.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.radio.sim;
+/* @hide */
+@JavaDerive(toString=true) @VintfStability
+parcelable Plmn {
+  String mcc;
+  String mnc;
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/SelectUiccSub.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/SelectUiccSub.aidl
index 02121e6..57ca2a5 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/SelectUiccSub.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/SelectUiccSub.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.sim;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable SelectUiccSub {
   int slot;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/SessionInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/SessionInfo.aidl
index 1329141..5c81e3d 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/SessionInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/SessionInfo.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.sim;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable SessionInfo {
   int sessionId;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/SimApdu.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/SimApdu.aidl
index c391e5a..45f6e48 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/SimApdu.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/SimApdu.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.sim;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable SimApdu {
   int sessionId;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/SimLockMultiSimPolicy.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/SimLockMultiSimPolicy.aidl
index d59fcab..8cfe417 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/SimLockMultiSimPolicy.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/SimLockMultiSimPolicy.aidl
@@ -32,8 +32,16 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.sim;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum SimLockMultiSimPolicy {
   NO_MULTISIM_POLICY,
   ONE_VALID_SIM_MUST_BE_PRESENT,
+  APPLY_TO_ALL_SLOTS,
+  APPLY_TO_ONLY_SLOT_1,
+  VALID_SIM_MUST_PRESENT_ON_SLOT_1,
+  ACTIVE_SERVICE_ON_SLOT_1_TO_UNBLOCK_OTHER_SLOTS,
+  ACTIVE_SERVICE_ON_ANY_SLOT_TO_UNBLOCK_OTHER_SLOTS,
+  ALL_SIMS_MUST_BE_VALID,
+  SLOT_POLICY_OTHER,
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/SimRefreshResult.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/SimRefreshResult.aidl
index 69bf476..81ba510 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/SimRefreshResult.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/SimRefreshResult.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.sim;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable SimRefreshResult {
   int type;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/AudioQuality.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/AudioQuality.aidl
index 1ab2902..8725c7f 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/AudioQuality.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/AudioQuality.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum AudioQuality {
   UNSPECIFIED,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/Call.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/Call.aidl
index 10d2ee7..b45a45b 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/Call.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/Call.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable Call {
   int state;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CallForwardInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CallForwardInfo.aidl
index 8e7aaab..51c8758 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CallForwardInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CallForwardInfo.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable CallForwardInfo {
   int status;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CdmaCallWaiting.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CdmaCallWaiting.aidl
index 310f9a0..0b36be4 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CdmaCallWaiting.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CdmaCallWaiting.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable CdmaCallWaiting {
   String number;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CdmaDisplayInfoRecord.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CdmaDisplayInfoRecord.aidl
index b6b562c..300b03f 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CdmaDisplayInfoRecord.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CdmaDisplayInfoRecord.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable CdmaDisplayInfoRecord {
   String alphaBuf;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CdmaInformationRecord.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CdmaInformationRecord.aidl
index 24ae775..2f7f5f0 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CdmaInformationRecord.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CdmaInformationRecord.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable CdmaInformationRecord {
   int name;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CdmaLineControlInfoRecord.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CdmaLineControlInfoRecord.aidl
index e34b393..4e4a7ee 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CdmaLineControlInfoRecord.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CdmaLineControlInfoRecord.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable CdmaLineControlInfoRecord {
   byte lineCtrlPolarityIncluded;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CdmaNumberInfoRecord.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CdmaNumberInfoRecord.aidl
index aeb0347..c3b0d5a 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CdmaNumberInfoRecord.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CdmaNumberInfoRecord.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable CdmaNumberInfoRecord {
   String number;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CdmaOtaProvisionStatus.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CdmaOtaProvisionStatus.aidl
index fad3841..ae35fba 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CdmaOtaProvisionStatus.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CdmaOtaProvisionStatus.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum CdmaOtaProvisionStatus {
   SPL_UNLOCKED,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CdmaRedirectingNumberInfoRecord.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CdmaRedirectingNumberInfoRecord.aidl
index b61b91b..93c7c6b 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CdmaRedirectingNumberInfoRecord.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CdmaRedirectingNumberInfoRecord.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable CdmaRedirectingNumberInfoRecord {
   android.hardware.radio.voice.CdmaNumberInfoRecord redirectingNumber;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CdmaSignalInfoRecord.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CdmaSignalInfoRecord.aidl
index 6c7b264..69447b4 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CdmaSignalInfoRecord.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CdmaSignalInfoRecord.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable CdmaSignalInfoRecord {
   boolean isPresent;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CdmaT53AudioControlInfoRecord.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CdmaT53AudioControlInfoRecord.aidl
index 438231c..69d79aa 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CdmaT53AudioControlInfoRecord.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CdmaT53AudioControlInfoRecord.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable CdmaT53AudioControlInfoRecord {
   byte upLink;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CdmaT53ClirInfoRecord.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CdmaT53ClirInfoRecord.aidl
index 1b254f5..83b6fb9 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CdmaT53ClirInfoRecord.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CdmaT53ClirInfoRecord.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable CdmaT53ClirInfoRecord {
   byte cause;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CfData.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CfData.aidl
index 7e799c7..fc811f2 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CfData.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/CfData.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable CfData {
   android.hardware.radio.voice.CallForwardInfo[] cfInfo;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/ClipStatus.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/ClipStatus.aidl
index a34149a..c38c801 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/ClipStatus.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/ClipStatus.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum ClipStatus {
   CLIP_PROVISIONED,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/Dial.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/Dial.aidl
index 2b2e759..26041f0 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/Dial.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/Dial.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable Dial {
   String address;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/EmergencyCallRouting.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/EmergencyCallRouting.aidl
index 4e1dfc0..3099a20 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/EmergencyCallRouting.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/EmergencyCallRouting.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum EmergencyCallRouting {
   UNKNOWN,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/EmergencyNumber.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/EmergencyNumber.aidl
index ac3867e..2129f39 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/EmergencyNumber.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/EmergencyNumber.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable EmergencyNumber {
   String number;
@@ -40,8 +41,8 @@
   int categories;
   String[] urns;
   int sources;
-  const int SOURCE_NETWORK_SIGNALING = (1 << 0);
-  const int SOURCE_SIM = (1 << 1);
-  const int SOURCE_MODEM_CONFIG = (1 << 2);
-  const int SOURCE_DEFAULT = (1 << 3);
+  const int SOURCE_NETWORK_SIGNALING = (1 << 0) /* 1 */;
+  const int SOURCE_SIM = (1 << 1) /* 2 */;
+  const int SOURCE_MODEM_CONFIG = (1 << 2) /* 4 */;
+  const int SOURCE_DEFAULT = (1 << 3) /* 8 */;
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/EmergencyServiceCategory.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/EmergencyServiceCategory.aidl
index 0a70d2d..819baf8 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/EmergencyServiceCategory.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/EmergencyServiceCategory.aidl
@@ -32,14 +32,15 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum EmergencyServiceCategory {
   UNSPECIFIED = 0,
-  POLICE = (1 << 0),
-  AMBULANCE = (1 << 1),
-  FIRE_BRIGADE = (1 << 2),
-  MARINE_GUARD = (1 << 3),
-  MOUNTAIN_RESCUE = (1 << 4),
-  MIEC = (1 << 5),
-  AIEC = (1 << 6),
+  POLICE = (1 << 0) /* 1 */,
+  AMBULANCE = (1 << 1) /* 2 */,
+  FIRE_BRIGADE = (1 << 2) /* 4 */,
+  MARINE_GUARD = (1 << 3) /* 8 */,
+  MOUNTAIN_RESCUE = (1 << 4) /* 16 */,
+  MIEC = (1 << 5) /* 32 */,
+  AIEC = (1 << 6) /* 64 */,
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/IRadioVoice.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/IRadioVoice.aidl
index 603b1d6..d0a9451 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/IRadioVoice.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/IRadioVoice.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
+/* @hide */
 @VintfStability
 interface IRadioVoice {
   oneway void acceptCall(in int serial);
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/IRadioVoiceIndication.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/IRadioVoiceIndication.aidl
index 189ed43..4614ee1 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/IRadioVoiceIndication.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/IRadioVoiceIndication.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
+/* @hide */
 @VintfStability
 interface IRadioVoiceIndication {
   oneway void callRing(in android.hardware.radio.RadioIndicationType type, in boolean isGsm, in android.hardware.radio.voice.CdmaSignalInfoRecord record);
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/IRadioVoiceResponse.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/IRadioVoiceResponse.aidl
index 7acc044..46927c2 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/IRadioVoiceResponse.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/IRadioVoiceResponse.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
+/* @hide */
 @VintfStability
 interface IRadioVoiceResponse {
   oneway void acceptCallResponse(in android.hardware.radio.RadioResponseInfo info);
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/LastCallFailCause.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/LastCallFailCause.aidl
index 7d54623..0cac135 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/LastCallFailCause.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/LastCallFailCause.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum LastCallFailCause {
   UNOBTAINABLE_NUMBER = 1,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/LastCallFailCauseInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/LastCallFailCauseInfo.aidl
index 221acf7..151adf2 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/LastCallFailCauseInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/LastCallFailCauseInfo.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable LastCallFailCauseInfo {
   android.hardware.radio.voice.LastCallFailCause causeCode;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/SrvccState.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/SrvccState.aidl
index 4b5c216..981ba02 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/SrvccState.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/SrvccState.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum SrvccState {
   HANDOVER_STARTED,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/SsInfoData.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/SsInfoData.aidl
index f18b404..24365dc 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/SsInfoData.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/SsInfoData.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable SsInfoData {
   int[] ssInfo;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/StkCcUnsolSsResult.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/StkCcUnsolSsResult.aidl
index 75f3de5..999f47c 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/StkCcUnsolSsResult.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/StkCcUnsolSsResult.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable StkCcUnsolSsResult {
   int serviceType;
@@ -72,13 +73,13 @@
   const int TELESERVICE_TYPE_SMS_SERVICES = 4;
   const int TELESERVICE_TYPE_ALL_TELESERVICES_EXCEPT_SMS = 5;
   const int SUPP_SERVICE_CLASS_NONE = 0;
-  const int SUPP_SERVICE_CLASS_VOICE = (1 << 0);
-  const int SUPP_SERVICE_CLASS_DATA = (1 << 1);
-  const int SUPP_SERVICE_CLASS_FAX = (1 << 2);
-  const int SUPP_SERVICE_CLASS_SMS = (1 << 3);
-  const int SUPP_SERVICE_CLASS_DATA_SYNC = (1 << 4);
-  const int SUPP_SERVICE_CLASS_DATA_ASYNC = (1 << 5);
-  const int SUPP_SERVICE_CLASS_PACKET = (1 << 6);
-  const int SUPP_SERVICE_CLASS_PAD = (1 << 7);
-  const int SUPP_SERVICE_CLASS_MAX = (1 << 7);
+  const int SUPP_SERVICE_CLASS_VOICE = (1 << 0) /* 1 */;
+  const int SUPP_SERVICE_CLASS_DATA = (1 << 1) /* 2 */;
+  const int SUPP_SERVICE_CLASS_FAX = (1 << 2) /* 4 */;
+  const int SUPP_SERVICE_CLASS_SMS = (1 << 3) /* 8 */;
+  const int SUPP_SERVICE_CLASS_DATA_SYNC = (1 << 4) /* 16 */;
+  const int SUPP_SERVICE_CLASS_DATA_ASYNC = (1 << 5) /* 32 */;
+  const int SUPP_SERVICE_CLASS_PACKET = (1 << 6) /* 64 */;
+  const int SUPP_SERVICE_CLASS_PAD = (1 << 7) /* 128 */;
+  const int SUPP_SERVICE_CLASS_MAX = (1 << 7) /* 128 */;
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/TtyMode.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/TtyMode.aidl
index e432e65..41ff6b8 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/TtyMode.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/TtyMode.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum TtyMode {
   OFF,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/UssdModeType.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/UssdModeType.aidl
index 424e73f..9e80f03 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/UssdModeType.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/UssdModeType.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum UssdModeType {
   NOTIFY,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/UusInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/UusInfo.aidl
index 9313760..3c84c8d 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/UusInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/current/android/hardware/radio/voice/UusInfo.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable UusInfo {
   int uusType;
diff --git a/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/AccessNetwork.aidl b/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/AccessNetwork.aidl
index 9641651..73a267b 100644
--- a/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/AccessNetwork.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/AccessNetwork.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum AccessNetwork {
   UNKNOWN,
diff --git a/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioAccessFamily.aidl b/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioAccessFamily.aidl
index b7b074b..1298ab0 100644
--- a/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioAccessFamily.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioAccessFamily.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum RadioAccessFamily {
   UNKNOWN = (1 << android.hardware.radio.RadioTechnology.UNKNOWN) /* 1 */,
diff --git a/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioConst.aidl b/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioConst.aidl
index 9785825..970cd1e 100644
--- a/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioConst.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioConst.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable RadioConst {
   const int MAX_RILDS = 3;
diff --git a/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioError.aidl b/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioError.aidl
index 98606e5..02c5370 100644
--- a/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioError.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioError.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum RadioError {
   NONE = 0,
diff --git a/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioIndicationType.aidl b/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioIndicationType.aidl
index 58b35a5..316f92f 100644
--- a/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioIndicationType.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioIndicationType.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum RadioIndicationType {
   UNSOLICITED,
diff --git a/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioResponseInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioResponseInfo.aidl
index b2a7a06..f03a73b 100644
--- a/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioResponseInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioResponseInfo.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable RadioResponseInfo {
   android.hardware.radio.RadioResponseType type;
diff --git a/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioResponseInfoModem.aidl b/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioResponseInfoModem.aidl
index 37ed7bb..2e0c315 100644
--- a/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioResponseInfoModem.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioResponseInfoModem.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio;
+/* @hide */
 @JavaDerive(toString=true) @VintfStability
 parcelable RadioResponseInfoModem {
   android.hardware.radio.RadioResponseType type;
diff --git a/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioResponseType.aidl b/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioResponseType.aidl
index 1ee62bd..8bdb45b 100644
--- a/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioResponseType.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioResponseType.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum RadioResponseType {
   SOLICITED,
diff --git a/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioTechnology.aidl b/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioTechnology.aidl
index b6af5aa..7c6a657 100644
--- a/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioTechnology.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioTechnology.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum RadioTechnology {
   UNKNOWN,
diff --git a/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioTechnologyFamily.aidl b/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioTechnologyFamily.aidl
index 2af7e53..85e9850 100644
--- a/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioTechnologyFamily.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioTechnologyFamily.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio;
+/* @hide */
 @Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum RadioTechnologyFamily {
   THREE_GPP,
diff --git a/radio/aidl/android/hardware/radio/AccessNetwork.aidl b/radio/aidl/android/hardware/radio/AccessNetwork.aidl
index 2885642..4099f83 100644
--- a/radio/aidl/android/hardware/radio/AccessNetwork.aidl
+++ b/radio/aidl/android/hardware/radio/AccessNetwork.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio;
 
+/** @hide */
 @VintfStability
 @Backing(type="int")
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/RadioAccessFamily.aidl b/radio/aidl/android/hardware/radio/RadioAccessFamily.aidl
index edf33ba..9ab4583 100644
--- a/radio/aidl/android/hardware/radio/RadioAccessFamily.aidl
+++ b/radio/aidl/android/hardware/radio/RadioAccessFamily.aidl
@@ -18,6 +18,7 @@
 
 import android.hardware.radio.RadioTechnology;
 
+/** @hide */
 @VintfStability
 @Backing(type="int")
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/RadioConst.aidl b/radio/aidl/android/hardware/radio/RadioConst.aidl
index 6591ef1..7b923b9 100644
--- a/radio/aidl/android/hardware/radio/RadioConst.aidl
+++ b/radio/aidl/android/hardware/radio/RadioConst.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable RadioConst {
diff --git a/radio/aidl/android/hardware/radio/RadioError.aidl b/radio/aidl/android/hardware/radio/RadioError.aidl
index 2031399..9c39bc4 100644
--- a/radio/aidl/android/hardware/radio/RadioError.aidl
+++ b/radio/aidl/android/hardware/radio/RadioError.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio;
 
+/** @hide */
 @VintfStability
 @Backing(type="int")
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/RadioIndicationType.aidl b/radio/aidl/android/hardware/radio/RadioIndicationType.aidl
index 2dcc492..594b147 100644
--- a/radio/aidl/android/hardware/radio/RadioIndicationType.aidl
+++ b/radio/aidl/android/hardware/radio/RadioIndicationType.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio;
 
+/** @hide */
 @VintfStability
 @Backing(type="int")
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/RadioResponseInfo.aidl b/radio/aidl/android/hardware/radio/RadioResponseInfo.aidl
index f70a3fe..25195aa 100644
--- a/radio/aidl/android/hardware/radio/RadioResponseInfo.aidl
+++ b/radio/aidl/android/hardware/radio/RadioResponseInfo.aidl
@@ -19,6 +19,7 @@
 import android.hardware.radio.RadioError;
 import android.hardware.radio.RadioResponseType;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable RadioResponseInfo {
diff --git a/radio/aidl/android/hardware/radio/RadioResponseInfoModem.aidl b/radio/aidl/android/hardware/radio/RadioResponseInfoModem.aidl
index 13abfb9..286f397 100644
--- a/radio/aidl/android/hardware/radio/RadioResponseInfoModem.aidl
+++ b/radio/aidl/android/hardware/radio/RadioResponseInfoModem.aidl
@@ -19,6 +19,7 @@
 import android.hardware.radio.RadioError;
 import android.hardware.radio.RadioResponseType;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable RadioResponseInfoModem {
diff --git a/radio/aidl/android/hardware/radio/RadioResponseType.aidl b/radio/aidl/android/hardware/radio/RadioResponseType.aidl
index cd4a305..000f478 100644
--- a/radio/aidl/android/hardware/radio/RadioResponseType.aidl
+++ b/radio/aidl/android/hardware/radio/RadioResponseType.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio;
 
+/** @hide */
 @VintfStability
 @Backing(type="int")
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/RadioTechnology.aidl b/radio/aidl/android/hardware/radio/RadioTechnology.aidl
index 4b51152..7ae428b 100644
--- a/radio/aidl/android/hardware/radio/RadioTechnology.aidl
+++ b/radio/aidl/android/hardware/radio/RadioTechnology.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio;
 
+/** @hide */
 @VintfStability
 @Backing(type="int")
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/RadioTechnologyFamily.aidl b/radio/aidl/android/hardware/radio/RadioTechnologyFamily.aidl
index a2b989d..4b5498c 100644
--- a/radio/aidl/android/hardware/radio/RadioTechnologyFamily.aidl
+++ b/radio/aidl/android/hardware/radio/RadioTechnologyFamily.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio;
 
+/** @hide */
 @VintfStability
 @Backing(type="int")
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/config/IRadioConfig.aidl b/radio/aidl/android/hardware/radio/config/IRadioConfig.aidl
index 85c2cee..8f4dff4 100644
--- a/radio/aidl/android/hardware/radio/config/IRadioConfig.aidl
+++ b/radio/aidl/android/hardware/radio/config/IRadioConfig.aidl
@@ -28,6 +28,7 @@
 import android.hardware.radio.config.IRadioConfigResponse;
 import android.hardware.radio.config.SlotPortMapping;
 
+/** @hide */
 @VintfStability
 oneway interface IRadioConfig {
     /**
@@ -39,6 +40,8 @@
      *
      * Response callback is
      * IRadioConfigResponse.getHalDeviceCapabilitiesResponse()
+     *
+     * This is available when android.hardware.telephony is defined.
      */
     void getHalDeviceCapabilities(in int serial);
 
@@ -53,6 +56,8 @@
      *
      * Response callback is IRadioConfigResponse.getNumOfLiveModemsResponse() which
      * will return <byte>.
+     *
+     * This is available when android.hardware.telephony is defined.
      */
     void getNumOfLiveModems(in int serial);
 
@@ -63,6 +68,8 @@
      *
      * Response callback is IRadioResponse.getPhoneCapabilityResponse() which
      * will return <PhoneCapability>.
+     *
+     * This is available when android.hardware.telephony is defined.
      */
     void getPhoneCapability(in int serial);
 
@@ -75,6 +82,8 @@
      * @param serial Serial number of request.
      *
      * Response callback is IRadioConfigResponse.getSimSlotsStatusResponse()
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void getSimSlotsStatus(in int serial);
 
@@ -92,6 +101,8 @@
      * @param modemsConfig byte object including the number of live modems
      *
      * Response callback is IRadioResponse.setNumOfLiveModemsResponse()
+     *
+     * This is available when android.hardware.telephony is defined.
      */
     void setNumOfLiveModems(in int serial, in byte numOfLiveModems);
 
@@ -106,6 +117,8 @@
      * from getPhoneCapability().
      *
      * Response callback is IRadioConfigResponse.setPreferredDataModemResponse()
+     *
+     * This is available when android.hardware.telephony.data is defined.
      */
     void setPreferredDataModem(in int serial, in byte modemId);
 
@@ -114,6 +127,8 @@
      *
      * @param radioConfigResponse Object containing radio config response functions
      * @param radioConfigIndication Object containing radio config indications
+     *
+     * This is available when android.hardware.telephony is defined.
      */
     void setResponseFunctions(in IRadioConfigResponse radioConfigResponse,
             in IRadioConfigIndication radioConfigIndication);
@@ -172,6 +187,24 @@
      *        getSimSlotsStatusResponse
      *
      * Response callback is IRadioConfigResponse.setSimSlotsMappingResponse()
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void setSimSlotsMapping(in int serial, in SlotPortMapping[] slotMap);
+
+    /**
+     * Get the set of logical slots where simultaneous cellular calling is currently possible. This
+     * does not include simultaneous calling availability over other non-cellular transports, such
+     * as IWLAN.
+     *
+     * Get the set of slots that currently support simultaneous cellular calling. When a new
+     * cellular call is placed/received, if another slot is active and handing a call, both the
+     * active slot and proposed slot must be in this list in order to support simultaneous cellular
+     * calling for both of those slots.
+     *
+     * @param serial Serial number of request
+     *
+     * This is available when android.hardware.telephony is defined.
+     */
+    void getSimultaneousCallingSupport(in int serial);
 }
diff --git a/radio/aidl/android/hardware/radio/config/IRadioConfigIndication.aidl b/radio/aidl/android/hardware/radio/config/IRadioConfigIndication.aidl
index abf55f1..9eacb8e 100644
--- a/radio/aidl/android/hardware/radio/config/IRadioConfigIndication.aidl
+++ b/radio/aidl/android/hardware/radio/config/IRadioConfigIndication.aidl
@@ -20,6 +20,7 @@
 
 /**
  * Interface declaring unsolicited radio config indications.
+ * @hide
  */
 @VintfStability
 oneway interface IRadioConfigIndication {
@@ -36,4 +37,15 @@
      */
     void simSlotsStatusChanged(
             in android.hardware.radio.RadioIndicationType type, in SimSlotStatus[] slotStatus);
+
+    /**
+     * The logical slots supporting simultaneous cellular calling has changed.
+     *
+     * @param enabledLogicalSlots The slots that have simultaneous cellular calling enabled. If
+     * there is a call active on logical slot X, then a simultaneous cellular call is only possible
+     * on logical slot Y if BOTH slot X and slot Y are in enabledLogicalSlots. If simultaneous
+     * cellular calling is not currently supported, the expected value of enabledLogicalSLots is an
+     * empty int array. Sending only one radio slot is not acceptable in any case.
+     */
+    void onSimultaneousCallingSupportChanged(in int[] enabledLogicalSlots);
 }
diff --git a/radio/aidl/android/hardware/radio/config/IRadioConfigResponse.aidl b/radio/aidl/android/hardware/radio/config/IRadioConfigResponse.aidl
index 0d36bbd..33b0ff0 100644
--- a/radio/aidl/android/hardware/radio/config/IRadioConfigResponse.aidl
+++ b/radio/aidl/android/hardware/radio/config/IRadioConfigResponse.aidl
@@ -21,6 +21,7 @@
 
 /**
  * Interface declaring response functions to solicited radio config requests.
+ * @hide
  */
 @VintfStability
 oneway interface IRadioConfigResponse {
@@ -39,6 +40,7 @@
      *          IRadioIndication.currentPhysicalChannelConfigs_1_6()
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
@@ -52,6 +54,7 @@
      *        are enabled and actively working as part of a working connectivity stack
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      */
@@ -64,6 +67,7 @@
      *        how many logical modems it has, how many data connections it supports.
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
@@ -77,6 +81,8 @@
      *        equal to the number of physical slots on the device
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.subscription is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:NO_MEMORY
@@ -90,6 +96,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_ARGUMENTS
@@ -100,6 +107,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.data is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
@@ -111,6 +119,8 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.subscription is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:NO_MEMORY
@@ -119,4 +129,27 @@
      *   RadioError:INVALID_ARGUMENTS
      */
     void setSimSlotsMappingResponse(in android.hardware.radio.RadioResponseInfo info);
+
+    /**
+     * Response to the asynchronous
+     * {@link IRadioConfig#getSimultaneousCallingSupport} request.
+     *
+     * @param info Response info struct containing response type, serial no. and error
+     * @param enabledLogicalSlots The slots that have simultaneous cellular calling enabled. If
+     * there is a call active on logical slot X, then a simultaneous cellular call is only possible
+     * on logical slot Y if BOTH slot X and slot Y are in enabledLogicalSlots. If simultaneous
+     * cellular calling is not currently supported, the expected value of enabledLogicalSLots is an
+     * empty int array. Sending only one radio slot is not acceptable in any case.
+     *
+     * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony is not defined
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:INTERNAL_ERR
+     *   RadioError:MODEM_ERR
+     *
+     * @see IRadioConfig#getSimultaneousCallingSupport for more information.
+     */
+    void getSimultaneousCallingSupportResponse(
+            in android.hardware.radio.RadioResponseInfo info, in int[] enabledLogicalSlots);
 }
diff --git a/radio/aidl/android/hardware/radio/config/MultipleEnabledProfilesMode.aidl b/radio/aidl/android/hardware/radio/config/MultipleEnabledProfilesMode.aidl
index b18ea0e..1d9b66e 100644
--- a/radio/aidl/android/hardware/radio/config/MultipleEnabledProfilesMode.aidl
+++ b/radio/aidl/android/hardware/radio/config/MultipleEnabledProfilesMode.aidl
@@ -20,6 +20,7 @@
  * Multiple Enabled Profiles(MEP) mode is the jointly supported MEP mode. As per section 3.4.1.1 of
  * GSMA spec SGP.22 v3.0,there are 3 supported MEP modes: MEP-A1, MEP-A2 and MEP-B.
  * If there is no jointly supported MEP mode, supported MEP mode is set to NONE.
+ * @hide
  */
 @VintfStability
 @Backing(type="int")
diff --git a/radio/aidl/android/hardware/radio/config/PhoneCapability.aidl b/radio/aidl/android/hardware/radio/config/PhoneCapability.aidl
index 8e4f338..7936eb6 100644
--- a/radio/aidl/android/hardware/radio/config/PhoneCapability.aidl
+++ b/radio/aidl/android/hardware/radio/config/PhoneCapability.aidl
@@ -20,10 +20,12 @@
  * Phone capability which describes the data connection capability of modem.
  * It's used to evaluate possible phone config change, for example from single
  * SIM device to multi-SIM device.
+ * @hide
  */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable PhoneCapability {
+    const byte UNKNOWN = -1;
     /**
      * maxActiveData defines how many logical modems can have
      * PS attached simultaneously. For example, for L+L modem it
@@ -46,4 +48,10 @@
      * List of logical modem IDs.
      */
     byte[] logicalModemIds;
+    /**
+     * maxActiveVoice defines how many logical modems can have
+     * cellular voice calls simultaneously. For example, for cellular DSDA
+     * with simultaneous calling support, it should be 2.
+     */
+    byte maxActiveVoice = UNKNOWN;
 }
diff --git a/radio/aidl/android/hardware/radio/config/SimPortInfo.aidl b/radio/aidl/android/hardware/radio/config/SimPortInfo.aidl
index db24719..f579639 100644
--- a/radio/aidl/android/hardware/radio/config/SimPortInfo.aidl
+++ b/radio/aidl/android/hardware/radio/config/SimPortInfo.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.config;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable SimPortInfo {
diff --git a/radio/aidl/android/hardware/radio/config/SimSlotStatus.aidl b/radio/aidl/android/hardware/radio/config/SimSlotStatus.aidl
index 6a36d5e..34f98c5 100644
--- a/radio/aidl/android/hardware/radio/config/SimSlotStatus.aidl
+++ b/radio/aidl/android/hardware/radio/config/SimSlotStatus.aidl
@@ -19,6 +19,7 @@
 import android.hardware.radio.config.MultipleEnabledProfilesMode;
 import android.hardware.radio.config.SimPortInfo;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable SimSlotStatus {
diff --git a/radio/aidl/android/hardware/radio/config/SlotPortMapping.aidl b/radio/aidl/android/hardware/radio/config/SlotPortMapping.aidl
index c78afcb..30cca50 100644
--- a/radio/aidl/android/hardware/radio/config/SlotPortMapping.aidl
+++ b/radio/aidl/android/hardware/radio/config/SlotPortMapping.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.config;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable SlotPortMapping {
diff --git a/radio/aidl/android/hardware/radio/data/ApnAuthType.aidl b/radio/aidl/android/hardware/radio/data/ApnAuthType.aidl
index a4116db..1d1d851 100644
--- a/radio/aidl/android/hardware/radio/data/ApnAuthType.aidl
+++ b/radio/aidl/android/hardware/radio/data/ApnAuthType.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.data;
 
+/** @hide */
 @VintfStability
 @Backing(type="int")
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/data/ApnTypes.aidl b/radio/aidl/android/hardware/radio/data/ApnTypes.aidl
index ed1256d..f44c636 100644
--- a/radio/aidl/android/hardware/radio/data/ApnTypes.aidl
+++ b/radio/aidl/android/hardware/radio/data/ApnTypes.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.data;
 
+/** @hide */
 @VintfStability
 @Backing(type="int")
 @JavaDerive(toString=true)
@@ -85,5 +86,9 @@
     /**
      * APN type for ENTERPRISE
      */
-    ENTERPRISE = 1 << 14
+    ENTERPRISE = 1 << 14,
+    /**
+     * APN type for RCS (Rich Communication Services)
+     */
+    RCS = 1 << 15
 }
diff --git a/radio/aidl/android/hardware/radio/data/DataCallFailCause.aidl b/radio/aidl/android/hardware/radio/data/DataCallFailCause.aidl
index 071ce55..e015e8e 100644
--- a/radio/aidl/android/hardware/radio/data/DataCallFailCause.aidl
+++ b/radio/aidl/android/hardware/radio/data/DataCallFailCause.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.data;
 
+/** @hide */
 @VintfStability
 @Backing(type="int")
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/data/DataProfileInfo.aidl b/radio/aidl/android/hardware/radio/data/DataProfileInfo.aidl
index ea4e751..d01f8ff 100644
--- a/radio/aidl/android/hardware/radio/data/DataProfileInfo.aidl
+++ b/radio/aidl/android/hardware/radio/data/DataProfileInfo.aidl
@@ -20,6 +20,7 @@
 import android.hardware.radio.data.PdpProtocolType;
 import android.hardware.radio.data.TrafficDescriptor;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable DataProfileInfo {
@@ -39,6 +40,21 @@
     const int TYPE_3GPP2 = 2;
 
     /**
+     * Innfrastructure type unknown. This is only for initializing.
+     */
+    const int INFRASTRUCTURE_UNKNOWN = 0;
+
+    /**
+     * Indicating this APN can be used when the device is using terrestrial cellular networks.
+     */
+    const int INFRASTRUCTURE_CELLULAR = 1 << 0;
+
+    /**
+     * Indicating this APN can be used when the device is attached to satellite.
+     */
+    const int INFRASTRUCTURE_SATELLITE = 1 << 1;
+
+    /**
      * ID of the data profile.
      * Values are ID_
      */
@@ -130,4 +146,10 @@
      * apn; apn must be used as the end point if one is not specified through URSP rules.
      */
     TrafficDescriptor trafficDescriptor;
+    /**
+     * The infrastructure bitmap which the APN can be used on. For example, some APNs can only
+     * be used when the device is using cellular network, using satellite network, or can be used
+     * in either cases.
+     */
+    int infrastructureBitmap = INFRASTRUCTURE_UNKNOWN;
 }
diff --git a/radio/aidl/android/hardware/radio/data/DataRequestReason.aidl b/radio/aidl/android/hardware/radio/data/DataRequestReason.aidl
index 44b47f8..b16081d 100644
--- a/radio/aidl/android/hardware/radio/data/DataRequestReason.aidl
+++ b/radio/aidl/android/hardware/radio/data/DataRequestReason.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.data;
 
+/** @hide */
 @VintfStability
 @Backing(type="int")
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/data/DataThrottlingAction.aidl b/radio/aidl/android/hardware/radio/data/DataThrottlingAction.aidl
index e4ee444..a762e34 100644
--- a/radio/aidl/android/hardware/radio/data/DataThrottlingAction.aidl
+++ b/radio/aidl/android/hardware/radio/data/DataThrottlingAction.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.data;
 
+/** @hide */
 @VintfStability
 @Backing(type="byte")
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/data/EpsQos.aidl b/radio/aidl/android/hardware/radio/data/EpsQos.aidl
index 8965d6e..42eee32 100644
--- a/radio/aidl/android/hardware/radio/data/EpsQos.aidl
+++ b/radio/aidl/android/hardware/radio/data/EpsQos.aidl
@@ -20,6 +20,7 @@
 
 /**
  * LTE/EPS Quality of Service parameters as per 3gpp spec 24.301 sec 9.9.4.3.
+ * @hide
  */
 @VintfStability
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/data/IRadioData.aidl b/radio/aidl/android/hardware/radio/data/IRadioData.aidl
index 0171d39..a73616a 100644
--- a/radio/aidl/android/hardware/radio/data/IRadioData.aidl
+++ b/radio/aidl/android/hardware/radio/data/IRadioData.aidl
@@ -34,6 +34,7 @@
  * duration of a method call. If clients provide colliding serials (including passing the same
  * serial to different methods), multiple responses (one for each method call) must still be served.
  * setResponseFunctions must work with IRadioDataResponse and IRadioDataIndication.
+ * @hide
  */
 @VintfStability
 oneway interface IRadioData {
@@ -47,6 +48,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioDataResponse.allocatePduSessionIdResponse()
+     *
+     * This is available when android.hardware.telephony.data is defined.
      */
     void allocatePduSessionId(in int serial);
 
@@ -59,6 +62,8 @@
      * @param id callId The identifier of the data call which is provided in SetupDataCallResult
      *
      * Response function is IRadioDataResponse.cancelHandoverResponse()
+     *
+     * This is available when android.hardware.telephony.ims is defined.
      */
     void cancelHandover(in int serial, in int callId);
 
@@ -72,6 +77,8 @@
      * @param reason The request reason. Must be normal, handover, or shutdown.
      *
      * Response function is IRadioDataResponse.deactivateDataCallResponse()
+     *
+     * This is available when android.hardware.telephony.data is defined.
      */
     void deactivateDataCall(in int serial, in int cid, in DataRequestReason reason);
 
@@ -82,6 +89,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioDataResponse.getDataCallListResponse()
+     *
+     * This is available when android.hardware.telephony.data is defined.
      */
     void getDataCallList(in int serial);
 
@@ -95,6 +104,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioDataResponse.getSlicingConfigResponse()
+     *
+     * This is available when android.hardware.telephony.data is defined.
      */
     void getSlicingConfig(in int serial);
 
@@ -106,6 +117,8 @@
      * @param id Pdu session id to release.
      *
      * Response function is IRadioDataResponse.releasePduSessionIdResponse()
+     *
+     * This is available when android.hardware.telephony.ims is defined.
      */
     void releasePduSessionId(in int serial, in int id);
 
@@ -113,6 +126,8 @@
      * When response type received from a radio indication or radio response is
      * RadioIndicationType:UNSOLICITED_ACK_EXP or RadioResponseType:SOLICITED_ACK_EXP respectively,
      * acknowledge the receipt of those messages by sending responseAcknowledgement().
+     *
+     * This is available when android.hardware.telephony.data is defined.
      */
     void responseAcknowledgement();
 
@@ -123,6 +138,8 @@
      * @param allow true to allow data calls, false to disallow data calls
      *
      * Response function is IRadioDataResponse.setDataAllowedResponse()
+     *
+     * This is available when android.hardware.telephony.data is defined.
      */
     void setDataAllowed(in int serial, in boolean allow);
 
@@ -133,6 +150,8 @@
      * @param profiles Array of DataProfileInfo to set.
      *
      * Response function is IRadioDataResponse.setDataProfileResponse()
+     *
+     * This is available when android.hardware.telephony.data is defined.
      */
     void setDataProfile(in int serial, in DataProfileInfo[] profiles);
 
@@ -154,6 +173,8 @@
      *        DataThrottlingAction:HOLD.
      *
      * Response function is IRadioDataResponse.setDataThrottlingResponse()
+     *
+     * This is available when android.hardware.telephony.data is defined.
      */
     void setDataThrottling(in int serial, in DataThrottlingAction dataThrottlingAction,
             in long completionDurationMillis);
@@ -166,6 +187,8 @@
      *        initial attach APN.
      *
      * Response function is IRadioDataResponse.setInitialAttachApnResponse()
+     *
+     * This is available when android.hardware.telephony.data is defined.
      */
     void setInitialAttachApn(in int serial, in @nullable DataProfileInfo dataProfileInfo);
 
@@ -174,6 +197,8 @@
      *
      * @param radioDataResponse Object containing response functions
      * @param radioDataIndication Object containing radio indications
+     *
+     * This is available when android.hardware.telephony.data is defined.
      */
     void setResponseFunctions(
             in IRadioDataResponse radioDataResponse, in IRadioDataIndication radioDataIndication);
@@ -228,6 +253,8 @@
      *        example, a zero-rating slice.
      *
      * Response function is IRadioDataResponse.setupDataCallResponse()
+     *
+     * This is available when android.hardware.telephony.data is defined.
      */
     void setupDataCall(in int serial, in AccessNetwork accessNetwork,
             in DataProfileInfo dataProfileInfo, in boolean roamingAllowed,
@@ -249,6 +276,8 @@
      * @param id callId The identifier of the data call which is provided in SetupDataCallResult
      *
      * Response function is IRadioDataResponse.startHandoverResponse()
+     *
+     * This is available when android.hardware.telephony.ims is defined.
      */
     void startHandover(in int serial, in int callId);
 
@@ -259,6 +288,8 @@
      * @param keepalive A request structure containing all necessary info to describe a keepalive
      *
      * Response function is IRadioDataResponse.startKeepaliveResponse()
+     *
+     * This is available when android.hardware.telephony.data is defined.
      */
     void startKeepalive(in int serial, in KeepaliveRequest keepalive);
 
@@ -270,6 +301,8 @@
      *        IRadioDataResponse.startKeepaliveResponse
      *
      * Response function is IRadioDataResponse.stopKeepaliveResponse()
+     *
+     * This is available when android.hardware.telephony.data is defined.
      */
     void stopKeepalive(in int serial, in int sessionHandle);
 }
diff --git a/radio/aidl/android/hardware/radio/data/IRadioDataIndication.aidl b/radio/aidl/android/hardware/radio/data/IRadioDataIndication.aidl
index 938c695..c3fdcaa 100644
--- a/radio/aidl/android/hardware/radio/data/IRadioDataIndication.aidl
+++ b/radio/aidl/android/hardware/radio/data/IRadioDataIndication.aidl
@@ -25,6 +25,7 @@
 
 /**
  * Interface declaring unsolicited radio indications for data APIs.
+ * @hide
  */
 @VintfStability
 oneway interface IRadioDataIndication {
diff --git a/radio/aidl/android/hardware/radio/data/IRadioDataResponse.aidl b/radio/aidl/android/hardware/radio/data/IRadioDataResponse.aidl
index 06c83c1..538b90a 100644
--- a/radio/aidl/android/hardware/radio/data/IRadioDataResponse.aidl
+++ b/radio/aidl/android/hardware/radio/data/IRadioDataResponse.aidl
@@ -23,6 +23,7 @@
 
 /**
  * Interface declaring response functions to solicited radio requests for data APIs.
+ * @hide
  */
 @VintfStability
 oneway interface IRadioDataResponse {
@@ -40,6 +41,7 @@
      * @param id The allocated id. On an error, this is set to 0.
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.data is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
@@ -52,6 +54,7 @@
      * @param dcResponse Attributes of data call
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.ims is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
@@ -64,6 +67,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.data is not defined
      *   RadioError:NONE indicates success. Any other error will remove the network from the list.
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_CALL_ID
@@ -82,6 +86,7 @@
      * @param dcResponse List of SetupDataCallResult
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.data is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
@@ -94,6 +99,7 @@
      * @param slicingConfig Current slicing configuration
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.data is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
@@ -105,6 +111,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.ims is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
@@ -116,6 +123,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.data is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:NO_MEMORY
@@ -134,6 +142,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.data is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:SUBSCRIPTION_NOT_AVAILABLE
@@ -149,6 +158,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      *  Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.data is not defined
      *  RadioError:NONE
      *  RadioError:RADIO_NOT_AVAILABLE
      *  RadioError:MODEM_ERR
@@ -160,6 +170,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.data is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:SUBSCRIPTION_NOT_AVAILABLE
@@ -179,6 +190,7 @@
      * @param dcResponse SetupDataCallResult
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.data is not defined
      *   RadioError:NONE must be returned on both success and failure of setup with the
      *              DataCallResponse.status containing the actual status
      *              For all other errors the DataCallResponse is ignored.
@@ -196,6 +208,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.ims is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
@@ -211,6 +224,7 @@
      *        request.
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.data is not defined
      *   RadioError:NONE
      *   RadioError:NO_RESOURCES
      *   RadioError:INVALID_ARGUMENTS
@@ -221,6 +235,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.data is not defined
      *   RadioError:NONE
      *   RadioError:INVALID_ARGUMENTS
      */
diff --git a/radio/aidl/android/hardware/radio/data/KeepaliveRequest.aidl b/radio/aidl/android/hardware/radio/data/KeepaliveRequest.aidl
index c720de0..1838f2e 100644
--- a/radio/aidl/android/hardware/radio/data/KeepaliveRequest.aidl
+++ b/radio/aidl/android/hardware/radio/data/KeepaliveRequest.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.data;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable KeepaliveRequest {
diff --git a/radio/aidl/android/hardware/radio/data/KeepaliveStatus.aidl b/radio/aidl/android/hardware/radio/data/KeepaliveStatus.aidl
index 0b829c4..162fc37 100644
--- a/radio/aidl/android/hardware/radio/data/KeepaliveStatus.aidl
+++ b/radio/aidl/android/hardware/radio/data/KeepaliveStatus.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.data;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable KeepaliveStatus {
diff --git a/radio/aidl/android/hardware/radio/data/LinkAddress.aidl b/radio/aidl/android/hardware/radio/data/LinkAddress.aidl
index 12a7637..957973d 100644
--- a/radio/aidl/android/hardware/radio/data/LinkAddress.aidl
+++ b/radio/aidl/android/hardware/radio/data/LinkAddress.aidl
@@ -18,6 +18,7 @@
 
 /**
  * Describes a data link address for mobile data connection.
+ * @hide
  */
 @VintfStability
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/data/NrQos.aidl b/radio/aidl/android/hardware/radio/data/NrQos.aidl
index 4078fdc..f636e6b 100644
--- a/radio/aidl/android/hardware/radio/data/NrQos.aidl
+++ b/radio/aidl/android/hardware/radio/data/NrQos.aidl
@@ -20,6 +20,7 @@
 
 /**
  * 5G Quality of Service parameters as per 3gpp spec 24.501 sec 9.11.4.12
+ * @hide
  */
 @VintfStability
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/data/OsAppId.aidl b/radio/aidl/android/hardware/radio/data/OsAppId.aidl
index 88e7832..ae38cf3 100644
--- a/radio/aidl/android/hardware/radio/data/OsAppId.aidl
+++ b/radio/aidl/android/hardware/radio/data/OsAppId.aidl
@@ -18,6 +18,7 @@
 
 /**
  * This struct represents the OsId + OsAppId as defined in TS 24.526 Section 5.2
+ * @hide
  */
 @VintfStability
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/data/PcoDataInfo.aidl b/radio/aidl/android/hardware/radio/data/PcoDataInfo.aidl
index 38a821f..a487bb3 100644
--- a/radio/aidl/android/hardware/radio/data/PcoDataInfo.aidl
+++ b/radio/aidl/android/hardware/radio/data/PcoDataInfo.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.data;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable PcoDataInfo {
diff --git a/radio/aidl/android/hardware/radio/data/PdpProtocolType.aidl b/radio/aidl/android/hardware/radio/data/PdpProtocolType.aidl
index 792a503..27e541d 100644
--- a/radio/aidl/android/hardware/radio/data/PdpProtocolType.aidl
+++ b/radio/aidl/android/hardware/radio/data/PdpProtocolType.aidl
@@ -18,6 +18,7 @@
 
 /**
  * Specifies the type of packet data protocol which is defined in TS 27.007 section 10.1.1.
+ * @hide
  */
 @VintfStability
 @Backing(type="int")
diff --git a/radio/aidl/android/hardware/radio/data/PortRange.aidl b/radio/aidl/android/hardware/radio/data/PortRange.aidl
index 5c83ca4..7326966 100644
--- a/radio/aidl/android/hardware/radio/data/PortRange.aidl
+++ b/radio/aidl/android/hardware/radio/data/PortRange.aidl
@@ -20,6 +20,7 @@
  * Defines range of ports. start and end are the first and last port numbers (inclusive) in the
  * range. Both start and end are in PORT_RANGE_MIN to PORT_RANGE_MAX range. A single port shall
  * be represented by the same start and end value.
+ * @hide
  */
 @VintfStability
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/data/Qos.aidl b/radio/aidl/android/hardware/radio/data/Qos.aidl
index d9ab9e7..e98d030 100644
--- a/radio/aidl/android/hardware/radio/data/Qos.aidl
+++ b/radio/aidl/android/hardware/radio/data/Qos.aidl
@@ -21,6 +21,7 @@
 
 /**
  * EPS or NR QOS parameters
+ * @hide
  */
 @VintfStability
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/data/QosBandwidth.aidl b/radio/aidl/android/hardware/radio/data/QosBandwidth.aidl
index e841548..f2eca41 100644
--- a/radio/aidl/android/hardware/radio/data/QosBandwidth.aidl
+++ b/radio/aidl/android/hardware/radio/data/QosBandwidth.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.data;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable QosBandwidth {
diff --git a/radio/aidl/android/hardware/radio/data/QosFilter.aidl b/radio/aidl/android/hardware/radio/data/QosFilter.aidl
index f5dc7ec..4a2b61d 100644
--- a/radio/aidl/android/hardware/radio/data/QosFilter.aidl
+++ b/radio/aidl/android/hardware/radio/data/QosFilter.aidl
@@ -23,6 +23,7 @@
 
 /**
  * See 3gpp 24.008 10.5.6.12 and 3gpp 24.501 9.11.4.13
+ * @hide
  */
 @VintfStability
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/data/QosFilterIpsecSpi.aidl b/radio/aidl/android/hardware/radio/data/QosFilterIpsecSpi.aidl
index 5059c28..83c4fe1 100644
--- a/radio/aidl/android/hardware/radio/data/QosFilterIpsecSpi.aidl
+++ b/radio/aidl/android/hardware/radio/data/QosFilterIpsecSpi.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.data;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 union QosFilterIpsecSpi {
diff --git a/radio/aidl/android/hardware/radio/data/QosFilterIpv6FlowLabel.aidl b/radio/aidl/android/hardware/radio/data/QosFilterIpv6FlowLabel.aidl
index 6f14934..4591174 100644
--- a/radio/aidl/android/hardware/radio/data/QosFilterIpv6FlowLabel.aidl
+++ b/radio/aidl/android/hardware/radio/data/QosFilterIpv6FlowLabel.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.data;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 union QosFilterIpv6FlowLabel {
diff --git a/radio/aidl/android/hardware/radio/data/QosFilterTypeOfService.aidl b/radio/aidl/android/hardware/radio/data/QosFilterTypeOfService.aidl
index f5770a4..8d27399 100644
--- a/radio/aidl/android/hardware/radio/data/QosFilterTypeOfService.aidl
+++ b/radio/aidl/android/hardware/radio/data/QosFilterTypeOfService.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.data;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 union QosFilterTypeOfService {
diff --git a/radio/aidl/android/hardware/radio/data/QosSession.aidl b/radio/aidl/android/hardware/radio/data/QosSession.aidl
index 770b124..1a8eb2c 100644
--- a/radio/aidl/android/hardware/radio/data/QosSession.aidl
+++ b/radio/aidl/android/hardware/radio/data/QosSession.aidl
@@ -21,6 +21,7 @@
 
 /**
  * QOS session associated with a dedicated bearer
+ * @hide
  */
 @VintfStability
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/data/RouteSelectionDescriptor.aidl b/radio/aidl/android/hardware/radio/data/RouteSelectionDescriptor.aidl
index 14b0ffc..4e9e954 100644
--- a/radio/aidl/android/hardware/radio/data/RouteSelectionDescriptor.aidl
+++ b/radio/aidl/android/hardware/radio/data/RouteSelectionDescriptor.aidl
@@ -21,6 +21,7 @@
 
 /**
  * This struct represents a single route selection descriptor as defined in 3GPP TS 24.526.
+ * @hide
  */
 @VintfStability
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/data/SetupDataCallResult.aidl b/radio/aidl/android/hardware/radio/data/SetupDataCallResult.aidl
index fee54ac..b8f01c0 100644
--- a/radio/aidl/android/hardware/radio/data/SetupDataCallResult.aidl
+++ b/radio/aidl/android/hardware/radio/data/SetupDataCallResult.aidl
@@ -24,6 +24,7 @@
 import android.hardware.radio.data.SliceInfo;
 import android.hardware.radio.data.TrafficDescriptor;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable SetupDataCallResult {
diff --git a/radio/aidl/android/hardware/radio/data/SliceInfo.aidl b/radio/aidl/android/hardware/radio/data/SliceInfo.aidl
index 7ad7fc3..809b8e0 100644
--- a/radio/aidl/android/hardware/radio/data/SliceInfo.aidl
+++ b/radio/aidl/android/hardware/radio/data/SliceInfo.aidl
@@ -18,6 +18,7 @@
 
 /**
  * This struct represents a S-NSSAI as defined in 3GPP TS 24.501.
+ * @hide
  */
 @VintfStability
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/data/SlicingConfig.aidl b/radio/aidl/android/hardware/radio/data/SlicingConfig.aidl
index e94b58c..47ac41e 100644
--- a/radio/aidl/android/hardware/radio/data/SlicingConfig.aidl
+++ b/radio/aidl/android/hardware/radio/data/SlicingConfig.aidl
@@ -21,6 +21,7 @@
 
 /**
  * This struct represents the current slicing configuration.
+ * @hide
  */
 @VintfStability
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/data/TrafficDescriptor.aidl b/radio/aidl/android/hardware/radio/data/TrafficDescriptor.aidl
index 2c117a5..098c77a 100644
--- a/radio/aidl/android/hardware/radio/data/TrafficDescriptor.aidl
+++ b/radio/aidl/android/hardware/radio/data/TrafficDescriptor.aidl
@@ -22,6 +22,7 @@
  * This struct represents a traffic descriptor. A valid struct must have at least one of the
  * optional values present. This is based on the definition of traffic descriptor in
  * TS 24.526 Section 5.2.
+ * @hide
  */
 @VintfStability
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/data/UrspRule.aidl b/radio/aidl/android/hardware/radio/data/UrspRule.aidl
index 0499edd..f2028b4 100644
--- a/radio/aidl/android/hardware/radio/data/UrspRule.aidl
+++ b/radio/aidl/android/hardware/radio/data/UrspRule.aidl
@@ -21,6 +21,7 @@
 
 /**
  * This struct represents a single URSP rule as defined in 3GPP TS 24.526.
+ * @hide
  */
 @VintfStability
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/ims/ConnectionFailureInfo.aidl b/radio/aidl/android/hardware/radio/ims/ConnectionFailureInfo.aidl
index 70faa1e..c96f59f 100644
--- a/radio/aidl/android/hardware/radio/ims/ConnectionFailureInfo.aidl
+++ b/radio/aidl/android/hardware/radio/ims/ConnectionFailureInfo.aidl
@@ -16,10 +16,10 @@
 
 package android.hardware.radio.ims;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable ConnectionFailureInfo {
-
     @VintfStability
     @Backing(type="int")
     enum ConnectionFailureReason {
diff --git a/radio/aidl/android/hardware/radio/ims/EpsFallbackReason.aidl b/radio/aidl/android/hardware/radio/ims/EpsFallbackReason.aidl
index 670638b..5300fbe 100644
--- a/radio/aidl/android/hardware/radio/ims/EpsFallbackReason.aidl
+++ b/radio/aidl/android/hardware/radio/ims/EpsFallbackReason.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.ims;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 @Backing(type="int")
diff --git a/radio/aidl/android/hardware/radio/ims/IRadioIms.aidl b/radio/aidl/android/hardware/radio/ims/IRadioIms.aidl
index bd661a7..90792f7 100644
--- a/radio/aidl/android/hardware/radio/ims/IRadioIms.aidl
+++ b/radio/aidl/android/hardware/radio/ims/IRadioIms.aidl
@@ -34,6 +34,7 @@
  * duration of a method call. If clients provide colliding serials (including passing the same
  * serial to different methods), multiple responses (one for each method call) must still be served.
  * setResponseFunctions must work with IRadioImsResponse and IRadioImsIndication.
+ * @hide
  */
 @VintfStability
 oneway interface IRadioIms {
@@ -44,6 +45,8 @@
      * @param srvccCalls the list of calls
      *
      * Response function is IRadioImsResponse.setSrvccCallInfoResponse()
+     *
+     * This is available when android.hardware.telephony.ims is defined.
      */
     void setSrvccCallInfo(int serial, in SrvccCall[] srvccCalls);
 
@@ -59,6 +62,8 @@
      * @param imsRegistration IMS registration information
      *
      * Response function is IRadioImsResponse.updateImsRegistrationInfoResponse()
+     *
+     * This is available when android.hardware.telephony.ims is defined.
      */
     void updateImsRegistrationInfo(int serial, in ImsRegistration imsRegistration);
 
@@ -89,10 +94,11 @@
      *        mobile terminated use case eg. MO/MT call/SMS etc
      *
      * Response function is IRadioImsResponse.startImsTrafficResponse()
+     *
+     * This is available when android.hardware.telephony.ims is defined.
      */
-    void startImsTraffic(int serial, int token,
-            ImsTrafficType imsTrafficType, AccessNetwork accessNetworkType,
-            ImsCall.Direction trafficDirection);
+    void startImsTraffic(int serial, int token, ImsTrafficType imsTrafficType,
+            AccessNetwork accessNetworkType, ImsCall.Direction trafficDirection);
 
     /**
      * Indicates IMS traffic has been stopped.
@@ -103,6 +109,8 @@
      * @param token The token assigned by startImsTraffic()
      *
      * Response function is IRadioImsResponse.stopImsTrafficResponse()
+     *
+     * This is available when android.hardware.telephony.ims is defined.
      */
     void stopImsTraffic(int serial, int token);
 
@@ -114,6 +122,8 @@
      * @param reason Specifies the reason that causes EPS fallback
      *
      * Response function is IRadioImsResponse.triggerEpsFallbackResponse()
+     *
+     * This is available when android.hardware.telephony.ims is defined.
      */
     void triggerEpsFallback(int serial, in EpsFallbackReason reason);
 
@@ -122,9 +132,11 @@
      *
      * @param radioImsResponse Object containing response functions
      * @param radioImsIndication Object containing radio indications
+     *
+     * This is available when android.hardware.telephony.ims is defined.
      */
-    void setResponseFunctions(in IRadioImsResponse radioImsResponse,
-            in IRadioImsIndication radioImsIndication);
+    void setResponseFunctions(
+            in IRadioImsResponse radioImsResponse, in IRadioImsIndication radioImsIndication);
 
     /**
      * Access Network Bitrate Recommendation Query (ANBRQ), see 3GPP TS 26.114.
@@ -137,8 +149,11 @@
      * @param bitsPerSecond The bit rate requested by the opponent UE
      *
      * Response function is IRadioImsResponse.sendAnbrQueryResponse()
+     *
+     * This is available when android.hardware.telephony.ims is defined.
      */
-    void sendAnbrQuery(int serial, ImsStreamType mediaType, ImsStreamDirection direction, int bitsPerSecond);
+    void sendAnbrQuery(
+            int serial, ImsStreamType mediaType, ImsStreamDirection direction, int bitsPerSecond);
 
     /**
      * Provides a list of IMS call information to radio.
@@ -147,6 +162,8 @@
      * @param imsCalls The list of IMS calls
      *
      * Response function is IRadioImsResponse.updateImsCallStatusResponse()
+     *
+     * This is available when android.hardware.telephony.ims is defined.
      */
     void updateImsCallStatus(int serial, in ImsCall[] imsCalls);
 }
diff --git a/radio/aidl/android/hardware/radio/ims/IRadioImsIndication.aidl b/radio/aidl/android/hardware/radio/ims/IRadioImsIndication.aidl
index d123d07..58e30ce 100644
--- a/radio/aidl/android/hardware/radio/ims/IRadioImsIndication.aidl
+++ b/radio/aidl/android/hardware/radio/ims/IRadioImsIndication.aidl
@@ -24,6 +24,7 @@
 
 /**
  * Interface declaring unsolicited radio indications for ims APIs.
+ * @hide
  */
 @VintfStability
 oneway interface IRadioImsIndication {
diff --git a/radio/aidl/android/hardware/radio/ims/IRadioImsResponse.aidl b/radio/aidl/android/hardware/radio/ims/IRadioImsResponse.aidl
index ff516cc..ca33d07 100644
--- a/radio/aidl/android/hardware/radio/ims/IRadioImsResponse.aidl
+++ b/radio/aidl/android/hardware/radio/ims/IRadioImsResponse.aidl
@@ -21,14 +21,15 @@
 
 /**
  * Interface declaring response functions to solicited radio requests for ims APIs.
+ * @hide
  */
 @VintfStability
 oneway interface IRadioImsResponse {
-
     /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.ims is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_STATE
@@ -45,6 +46,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.ims is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_STATE
@@ -63,6 +65,7 @@
      *        it should be {@code null}.
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.ims is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_STATE
@@ -73,13 +76,14 @@
      *   RadioError:INVALID_ARGUMENTS
      *   RadioError:NO_RESOURCES
      */
-    void startImsTrafficResponse(in RadioResponseInfo info,
-            in @nullable ConnectionFailureInfo failureInfo);
+    void startImsTrafficResponse(
+            in RadioResponseInfo info, in @nullable ConnectionFailureInfo failureInfo);
 
     /**
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.ims is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_STATE
@@ -96,6 +100,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.ims is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_STATE
@@ -112,6 +117,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.ims is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_STATE
@@ -128,6 +134,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.ims is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_STATE
diff --git a/radio/aidl/android/hardware/radio/ims/ImsCall.aidl b/radio/aidl/android/hardware/radio/ims/ImsCall.aidl
index b71682f..427c1f5 100644
--- a/radio/aidl/android/hardware/radio/ims/ImsCall.aidl
+++ b/radio/aidl/android/hardware/radio/ims/ImsCall.aidl
@@ -18,10 +18,10 @@
 
 import android.hardware.radio.AccessNetwork;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable ImsCall {
-
     @Backing(type="int")
     enum CallType {
         NORMAL,
diff --git a/radio/aidl/android/hardware/radio/ims/ImsDeregistrationReason.aidl b/radio/aidl/android/hardware/radio/ims/ImsDeregistrationReason.aidl
index eac8db4..acfe51c 100644
--- a/radio/aidl/android/hardware/radio/ims/ImsDeregistrationReason.aidl
+++ b/radio/aidl/android/hardware/radio/ims/ImsDeregistrationReason.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.ims;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 @Backing(type="int")
diff --git a/radio/aidl/android/hardware/radio/ims/ImsRegistration.aidl b/radio/aidl/android/hardware/radio/ims/ImsRegistration.aidl
index 662f9e9..5158386 100644
--- a/radio/aidl/android/hardware/radio/ims/ImsRegistration.aidl
+++ b/radio/aidl/android/hardware/radio/ims/ImsRegistration.aidl
@@ -20,6 +20,7 @@
 import android.hardware.radio.ims.ImsRegistrationState;
 import android.hardware.radio.ims.SuggestedAction;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable ImsRegistration {
diff --git a/radio/aidl/android/hardware/radio/ims/ImsRegistrationState.aidl b/radio/aidl/android/hardware/radio/ims/ImsRegistrationState.aidl
index fd5c0fa..187cb38 100644
--- a/radio/aidl/android/hardware/radio/ims/ImsRegistrationState.aidl
+++ b/radio/aidl/android/hardware/radio/ims/ImsRegistrationState.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.ims;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 @Backing(type="int")
@@ -25,4 +26,4 @@
 
     /** IMS is successfully registered */
     REGISTERED,
-}
\ No newline at end of file
+}
diff --git a/radio/aidl/android/hardware/radio/ims/ImsStreamDirection.aidl b/radio/aidl/android/hardware/radio/ims/ImsStreamDirection.aidl
index c0cea32..42ce1bd 100644
--- a/radio/aidl/android/hardware/radio/ims/ImsStreamDirection.aidl
+++ b/radio/aidl/android/hardware/radio/ims/ImsStreamDirection.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.ims;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 @Backing(type="int")
diff --git a/radio/aidl/android/hardware/radio/ims/ImsStreamType.aidl b/radio/aidl/android/hardware/radio/ims/ImsStreamType.aidl
index c12a0c1..b88dc60 100644
--- a/radio/aidl/android/hardware/radio/ims/ImsStreamType.aidl
+++ b/radio/aidl/android/hardware/radio/ims/ImsStreamType.aidl
@@ -16,8 +16,10 @@
 
 package android.hardware.radio.ims;
 
+/** @hide */
 @VintfStability
 @Backing(type="int")
+@JavaDerive(toString=true)
 enum ImsStreamType {
     /** Media Stream Type - Audio **/
     AUDIO = 1,
diff --git a/radio/aidl/android/hardware/radio/ims/ImsTrafficType.aidl b/radio/aidl/android/hardware/radio/ims/ImsTrafficType.aidl
index 5a824c0..5af43f9 100644
--- a/radio/aidl/android/hardware/radio/ims/ImsTrafficType.aidl
+++ b/radio/aidl/android/hardware/radio/ims/ImsTrafficType.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.ims;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 @Backing(type="int")
@@ -40,4 +41,4 @@
 
     /** Ut/XCAP (XML Configuration Access Protocol) */
     UT_XCAP
-}
\ No newline at end of file
+}
diff --git a/radio/aidl/android/hardware/radio/ims/SrvccCall.aidl b/radio/aidl/android/hardware/radio/ims/SrvccCall.aidl
index 38e6cdb..16858f9 100644
--- a/radio/aidl/android/hardware/radio/ims/SrvccCall.aidl
+++ b/radio/aidl/android/hardware/radio/ims/SrvccCall.aidl
@@ -16,10 +16,10 @@
 
 package android.hardware.radio.ims;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable SrvccCall {
-
     @VintfStability
     @Backing(type="int")
     enum CallType {
diff --git a/radio/aidl/android/hardware/radio/ims/SuggestedAction.aidl b/radio/aidl/android/hardware/radio/ims/SuggestedAction.aidl
index 2d12ed6..73c57fa 100644
--- a/radio/aidl/android/hardware/radio/ims/SuggestedAction.aidl
+++ b/radio/aidl/android/hardware/radio/ims/SuggestedAction.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.ims;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 @Backing(type="int")
@@ -34,4 +35,19 @@
      * management timer value as per the carrier requirements.
      */
     TRIGGER_PLMN_BLOCK_WITH_TIMEOUT,
+    /**
+     * Indicates that the IMS registration on current RAT failed multiple times.
+     * The radio shall block the {@link AccessNetwork} included with this and
+     * search for other available RATs in the background.
+     * If no other RAT is available that meets the carrier requirements, the
+     * radio may remain on the blocked RAT for internet service. The radio clears all
+     * RATs marked as unavailable if {@link IRadioIms#updateImsRegistrationInfo()} API
+     * with REGISTERED state is invoked.
+     */
+    TRIGGER_RAT_BLOCK,
+    /**
+     * Indicates that the radio clears all RATs marked as unavailable and tries to find
+     * an available RAT that meets the carrier requirements.
+     */
+    TRIGGER_CLEAR_RAT_BLOCKS,
 }
diff --git a/radio/aidl/android/hardware/radio/ims/media/AmrMode.aidl b/radio/aidl/android/hardware/radio/ims/media/AmrMode.aidl
index 66d8ef0..dc2a162 100644
--- a/radio/aidl/android/hardware/radio/ims/media/AmrMode.aidl
+++ b/radio/aidl/android/hardware/radio/ims/media/AmrMode.aidl
@@ -16,9 +16,13 @@
 
 package android.hardware.radio.ims.media;
 
-/** AMR codec mode to represent the bit rate. See 3ggp Specs 26.976 & 26.071 */
+/**
+ * AMR codec mode to represent the bit rate. See 3ggp Specs 26.976 & 26.071
+ * @hide
+ */
 @VintfStability
 @Backing(type="int")
+@JavaDerive(toString=true)
 enum AmrMode {
     /** 4.75 kbps for AMR / 6.6 kbps for AMR-WB */
     AMR_MODE_0 = 1 << 0,
diff --git a/radio/aidl/android/hardware/radio/ims/media/AmrParams.aidl b/radio/aidl/android/hardware/radio/ims/media/AmrParams.aidl
index 4ed3a24..9d7ab05 100644
--- a/radio/aidl/android/hardware/radio/ims/media/AmrParams.aidl
+++ b/radio/aidl/android/hardware/radio/ims/media/AmrParams.aidl
@@ -18,7 +18,9 @@
 
 import android.hardware.radio.ims.media.AmrMode;
 
+/** @hide */
 @VintfStability
+@JavaDerive(toString=true)
 parcelable AmrParams {
     /** mode-set: AMR codec mode to represent the bit rate */
     AmrMode amrMode;
diff --git a/radio/aidl/android/hardware/radio/ims/media/AnbrMode.aidl b/radio/aidl/android/hardware/radio/ims/media/AnbrMode.aidl
index f758cd4..af6f92f 100644
--- a/radio/aidl/android/hardware/radio/ims/media/AnbrMode.aidl
+++ b/radio/aidl/android/hardware/radio/ims/media/AnbrMode.aidl
@@ -18,6 +18,7 @@
 
 import android.hardware.radio.ims.media.CodecMode;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable AnbrMode {
diff --git a/radio/aidl/android/hardware/radio/ims/media/CallQuality.aidl b/radio/aidl/android/hardware/radio/ims/media/CallQuality.aidl
index a8f7b16..dcf9623 100644
--- a/radio/aidl/android/hardware/radio/ims/media/CallQuality.aidl
+++ b/radio/aidl/android/hardware/radio/ims/media/CallQuality.aidl
@@ -16,7 +16,9 @@
 
 package android.hardware.radio.ims.media;
 
+/** @hide */
 @VintfStability
+@JavaDerive(toString=true)
 parcelable CallQuality {
     /**
      * downlink CallQualityLevel for a given ongoing call
diff --git a/radio/aidl/android/hardware/radio/ims/media/CodecMode.aidl b/radio/aidl/android/hardware/radio/ims/media/CodecMode.aidl
index aa1b3a4..6858ef4 100644
--- a/radio/aidl/android/hardware/radio/ims/media/CodecMode.aidl
+++ b/radio/aidl/android/hardware/radio/ims/media/CodecMode.aidl
@@ -19,6 +19,7 @@
 import android.hardware.radio.ims.media.AmrMode;
 import android.hardware.radio.ims.media.EvsMode;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 union CodecMode {
diff --git a/radio/aidl/android/hardware/radio/ims/media/CodecParams.aidl b/radio/aidl/android/hardware/radio/ims/media/CodecParams.aidl
index 0aa5505..74de6ec 100644
--- a/radio/aidl/android/hardware/radio/ims/media/CodecParams.aidl
+++ b/radio/aidl/android/hardware/radio/ims/media/CodecParams.aidl
@@ -19,7 +19,9 @@
 import android.hardware.radio.ims.media.CodecSpecificParams;
 import android.hardware.radio.ims.media.CodecType;
 
+/** @hide */
 @VintfStability
+@JavaDerive(toString=true)
 parcelable CodecParams {
     /** Negotiated codec type */
     CodecType codecType;
diff --git a/radio/aidl/android/hardware/radio/ims/media/CodecSpecificParams.aidl b/radio/aidl/android/hardware/radio/ims/media/CodecSpecificParams.aidl
index 4410c81..86dcea0 100644
--- a/radio/aidl/android/hardware/radio/ims/media/CodecSpecificParams.aidl
+++ b/radio/aidl/android/hardware/radio/ims/media/CodecSpecificParams.aidl
@@ -19,7 +19,9 @@
 import android.hardware.radio.ims.media.AmrParams;
 import android.hardware.radio.ims.media.EvsParams;
 
+/** @hide */
 @VintfStability
+@JavaDerive(toString=true)
 union CodecSpecificParams {
     AmrParams amr;
     EvsParams evs;
diff --git a/radio/aidl/android/hardware/radio/ims/media/CodecType.aidl b/radio/aidl/android/hardware/radio/ims/media/CodecType.aidl
index 31218e3..99fbac4 100644
--- a/radio/aidl/android/hardware/radio/ims/media/CodecType.aidl
+++ b/radio/aidl/android/hardware/radio/ims/media/CodecType.aidl
@@ -16,8 +16,10 @@
 
 package android.hardware.radio.ims.media;
 
+/** @hide */
 @VintfStability
 @Backing(type="int")
+@JavaDerive(toString=true)
 enum CodecType {
     /** Adaptive Multi-Rate */
     AMR = 1 << 0,
diff --git a/radio/aidl/android/hardware/radio/ims/media/DtmfParams.aidl b/radio/aidl/android/hardware/radio/ims/media/DtmfParams.aidl
index a7dcb0d..d2926f0 100644
--- a/radio/aidl/android/hardware/radio/ims/media/DtmfParams.aidl
+++ b/radio/aidl/android/hardware/radio/ims/media/DtmfParams.aidl
@@ -16,7 +16,9 @@
 
 package android.hardware.radio.ims.media;
 
+/** @hide */
 @VintfStability
+@JavaDerive(toString=true)
 parcelable DtmfParams {
     /**
      * Dynamic payload type number to be used for DTMF RTP packets received.
diff --git a/radio/aidl/android/hardware/radio/ims/media/EvsBandwidth.aidl b/radio/aidl/android/hardware/radio/ims/media/EvsBandwidth.aidl
index 8278514..279c489 100644
--- a/radio/aidl/android/hardware/radio/ims/media/EvsBandwidth.aidl
+++ b/radio/aidl/android/hardware/radio/ims/media/EvsBandwidth.aidl
@@ -15,9 +15,14 @@
  */
 
 package android.hardware.radio.ims.media;
-/** EVS Speech codec bandwidths, See 3gpp spec 26.441 Table 1 */
+
+/**
+ * EVS Speech codec bandwidths, See 3gpp spec 26.441 Table 1
+ * @hide
+ */
 @VintfStability
 @Backing(type="int")
+@JavaDerive(toString=true)
 enum EvsBandwidth {
     NONE = 0,
     NARROW_BAND = 1 << 0,
diff --git a/radio/aidl/android/hardware/radio/ims/media/EvsMode.aidl b/radio/aidl/android/hardware/radio/ims/media/EvsMode.aidl
index 95bd6c7..12d981b 100644
--- a/radio/aidl/android/hardware/radio/ims/media/EvsMode.aidl
+++ b/radio/aidl/android/hardware/radio/ims/media/EvsMode.aidl
@@ -16,9 +16,13 @@
 
 package android.hardware.radio.ims.media;
 
-/** EVS codec mode to represent the bit rate. See 3ggp Spec 26.952 Table 5.1 */
+/**
+ * EVS codec mode to represent the bit rate. See 3ggp Spec 26.952 Table 5.1
+ * @hide
+ */
 @VintfStability
 @Backing(type="int")
+@JavaDerive(toString=true)
 enum EvsMode {
     /** 6.6 kbps for EVS AMR-WB IO */
     EVS_MODE_0 = 1 << 0,
diff --git a/radio/aidl/android/hardware/radio/ims/media/EvsParams.aidl b/radio/aidl/android/hardware/radio/ims/media/EvsParams.aidl
index d138c83..52c3bf9 100644
--- a/radio/aidl/android/hardware/radio/ims/media/EvsParams.aidl
+++ b/radio/aidl/android/hardware/radio/ims/media/EvsParams.aidl
@@ -19,7 +19,9 @@
 import android.hardware.radio.ims.media.EvsBandwidth;
 import android.hardware.radio.ims.media.EvsMode;
 
+/** @hide */
 @VintfStability
+@JavaDerive(toString=true)
 parcelable EvsParams {
     /** EVS codec bandwidth */
     EvsBandwidth bandwidth;
diff --git a/radio/aidl/android/hardware/radio/ims/media/IImsMedia.aidl b/radio/aidl/android/hardware/radio/ims/media/IImsMedia.aidl
index ecf1370..14fe68b 100644
--- a/radio/aidl/android/hardware/radio/ims/media/IImsMedia.aidl
+++ b/radio/aidl/android/hardware/radio/ims/media/IImsMedia.aidl
@@ -23,14 +23,16 @@
 
 /**
  * This interface is used by IMS media framework to talk to RTP stack located in another processor.
+ * @hide
  */
 @VintfStability
 oneway interface IImsMedia {
-
     /**
      * Set the listener functions for receiving notifications from the RTP stack.
      *
      * @param mediaListener Object containing listener methods
+     *
+     * This is available when android.hardware.telephony.ims is defined.
      */
     void setListener(in IImsMediaListener mediaListener);
 
@@ -46,6 +48,8 @@
      * @param localEndPoint provides IP address, port and logical modem id for local RTP endpoint
      * @param config provides remote end point info and codec details. This could be null initially
      *        and the application may update this later using modifySession() API.
+     *
+     * This is available when android.hardware.telephony.ims is defined.
      */
     void openSession(int sessionId, in LocalEndPoint localEndPoint, in RtpConfig config);
 
@@ -54,6 +58,8 @@
      * This shall also close the session specific binder connection opened as part of openSession().
      *
      * @param sessionId identifier for the rtp session that needs to be closed
+     *
+     * This is available when android.hardware.telephony.ims is defined.
      */
     void closeSession(int sessionId);
 }
diff --git a/radio/aidl/android/hardware/radio/ims/media/IImsMediaListener.aidl b/radio/aidl/android/hardware/radio/ims/media/IImsMediaListener.aidl
index 228acb7..371edd2 100644
--- a/radio/aidl/android/hardware/radio/ims/media/IImsMediaListener.aidl
+++ b/radio/aidl/android/hardware/radio/ims/media/IImsMediaListener.aidl
@@ -21,6 +21,7 @@
 
 /**
  * Interface declaring listener functions for unsolicited IMS media notifications.
+ * @hide
  */
 @VintfStability
 oneway interface IImsMediaListener {
diff --git a/radio/aidl/android/hardware/radio/ims/media/IImsMediaSession.aidl b/radio/aidl/android/hardware/radio/ims/media/IImsMediaSession.aidl
index ec2fa2b..0fe6740 100644
--- a/radio/aidl/android/hardware/radio/ims/media/IImsMediaSession.aidl
+++ b/radio/aidl/android/hardware/radio/ims/media/IImsMediaSession.aidl
@@ -24,6 +24,7 @@
 
 /**
  * Session specific interface used by IMS media framework to talk to the vendor RTP stack.
+ * @hide
  */
 @VintfStability
 oneway interface IImsMediaSession {
@@ -31,6 +32,8 @@
      * Set the listener functions to receive IMS media session specific notifications.
      *
      * @param sessionListener Object containing notification methods
+     *
+     * This is available when android.hardware.telephony.ims is defined.
      */
     void setListener(in IImsMediaSessionListener sessionListener);
 
@@ -39,6 +42,8 @@
      * the media stream by changing the value of the MediaDirection.
      *
      * @param config provides remote end point info and codec details
+     *
+     * This is available when android.hardware.telephony.ims is defined.
      */
     void modifySession(in RtpConfig config);
 
@@ -47,6 +52,8 @@
      *
      * @param dtmfDigit single char having one of 12 values: 0-9, *, #
      * @param duration of the key press in milliseconds.
+     *
+     * This is available when android.hardware.telephony.ims is defined.
      */
     void sendDtmf(char dtmfDigit, int duration);
 
@@ -56,12 +63,16 @@
      * stopDtmf() is not received yet, then that digit must be stopped first
      *
      * @param dtmfDigit single char having one of 12 values: 0-9, *, #
+     *
+     * This is available when android.hardware.telephony.ims is defined.
      */
     void startDtmf(char dtmfDigit);
 
     /**
      * Stop sending the last DTMF digit started by startDtmf().
      * stopDtmf() without preceding startDtmf() must be ignored.
+     *
+     * This is available when android.hardware.telephony.ims is defined.
      */
     void stopDtmf();
 
@@ -69,6 +80,8 @@
      * Send RTP header extension to the other party in the next RTP packet.
      *
      * @param extensions data to be transmitted via RTP header extension
+     *
+     * This is available when android.hardware.telephony.ims is defined.
      */
     void sendHeaderExtension(in List<RtpHeaderExtension> extensions);
 
@@ -77,6 +90,30 @@
      * media quality notifications.
      *
      * @param threshold media quality thresholds for various quality parameters
+     *
+     * This is available when android.hardware.telephony.ims is defined.
      */
     void setMediaQualityThreshold(in MediaQualityThreshold threshold);
+
+    /**
+     * Queries the current RTP reception statistics of the RTP stream. It will trigger the
+       IImsMediaSessionListener#notifyRtpReceptionStats(RtpReceptionStats).
+     *
+     * @param intervalMs The interval of the time in milliseconds of the RTP reception
+     * notification. When it is zero, the report is disabled.
+     *
+     * This is available when android.hardware.telephony.ims is defined.
+     */
+    void requestRtpReceptionStats(in int intervalMs);
+
+    /**
+     * Adjust the delay in the jitter buffer to synchronize the audio with the time of video
+     * frames
+     *
+     * @param delayMs The delay to apply to the jitter buffer. If it is positive, the jitter
+     * buffer increases the delay, if it is negative, the jitter buffer decreases the delay.
+     *
+     * This is available when android.hardware.telephony.ims is defined.
+     */
+    void adjustDelay(in int delayMs);
 }
diff --git a/radio/aidl/android/hardware/radio/ims/media/IImsMediaSessionListener.aidl b/radio/aidl/android/hardware/radio/ims/media/IImsMediaSessionListener.aidl
index 8341da2..d3d0b26 100644
--- a/radio/aidl/android/hardware/radio/ims/media/IImsMediaSessionListener.aidl
+++ b/radio/aidl/android/hardware/radio/ims/media/IImsMediaSessionListener.aidl
@@ -21,9 +21,11 @@
 import android.hardware.radio.ims.media.RtpConfig;
 import android.hardware.radio.ims.media.RtpError;
 import android.hardware.radio.ims.media.RtpHeaderExtension;
+import android.hardware.radio.ims.media.RtpReceptionStats;
 
 /**
  * Interface declaring listener functions for unsolicited IMS media notifications per session.
+ * @hide
  */
 @VintfStability
 oneway interface IImsMediaSessionListener {
@@ -36,6 +38,8 @@
      *   RtpError :INTERNAL_ERR
      *   RtpError :NO_MEMORY
      *   RtpError :NO_RESOURCES
+     *
+     * This is available when android.hardware.telephony.ims is defined.
      */
     void onModifySessionResponse(in RtpConfig config, RtpError error);
 
@@ -48,6 +52,8 @@
      * packets from the most recently added config.
      *
      * @param config The remote config where the media is received
+     *
+     * This is available when android.hardware.telephony.ims is defined.
      */
     void onFirstMediaPacketReceived(in RtpConfig config);
 
@@ -55,6 +61,8 @@
      * RTP header extension received from the other party
      *
      * @param extensions content of the received RTP header extension
+     *
+     * This is available when android.hardware.telephony.ims is defined.
      */
     void onHeaderExtensionReceived(in List<RtpHeaderExtension> extensions);
 
@@ -63,6 +71,8 @@
      * {@link MediaQualityThreshold} set by {@link IImsMediaSession#setMediaQualityThreshold()}.
      *
      * @param quality The object of MediaQualityStatus with the rtp and the rtcp statistics.
+     *
+     * This is available when android.hardware.telephony.ims is defined.
      */
     void notifyMediaQualityStatus(in MediaQualityStatus quality);
 
@@ -72,6 +82,8 @@
      * See 3GPP TS 26.114.
      *
      * @param config containing desired bitrate and direction
+     *
+     * This is available when android.hardware.telephony.ims is defined.
      */
     void triggerAnbrQuery(in RtpConfig config);
 
@@ -80,6 +92,8 @@
      *
      * @param dtmfDigit single char having one of 12 values: 0-9, *, #
      * @param durationMs The duration to play the tone in milliseconds unit
+     *
+     * This is available when android.hardware.telephony.ims is defined.
      */
     void onDtmfReceived(char dtmfDigit, int durationMs);
 
@@ -87,6 +101,18 @@
      * Notifies when a change to call quality has occurred
      *
      * @param CallQuality The call quality statistics of ongoing call since last report
+     *
+     * This is available when android.hardware.telephony.ims is defined.
      */
     void onCallQualityChanged(in CallQuality callQuality);
+
+    /**
+     * Notifies the RTP reception statistics periodically after
+     * IImsMediaSession#requestRtpReceptionStats(intervalMs) is invoked.
+     *
+     * @param stats The RTP reception statistics
+     *
+     * This is available when android.hardware.telephony.ims is defined.
+     */
+    void notifyRtpReceptionStats(in RtpReceptionStats stats);
 }
diff --git a/radio/aidl/android/hardware/radio/ims/media/LocalEndPoint.aidl b/radio/aidl/android/hardware/radio/ims/media/LocalEndPoint.aidl
index 2bd48c6..29f25bb 100644
--- a/radio/aidl/android/hardware/radio/ims/media/LocalEndPoint.aidl
+++ b/radio/aidl/android/hardware/radio/ims/media/LocalEndPoint.aidl
@@ -18,7 +18,9 @@
 
 import android.os.ParcelFileDescriptor;
 
+/** @hide */
 @VintfStability
+@JavaDerive(toString=true)
 parcelable LocalEndPoint {
     /** Socket file descriptor for RTP traffic */
     ParcelFileDescriptor rtpFd;
diff --git a/radio/aidl/android/hardware/radio/ims/media/MediaDirection.aidl b/radio/aidl/android/hardware/radio/ims/media/MediaDirection.aidl
index e5c34c7..4ae36df 100644
--- a/radio/aidl/android/hardware/radio/ims/media/MediaDirection.aidl
+++ b/radio/aidl/android/hardware/radio/ims/media/MediaDirection.aidl
@@ -26,9 +26,11 @@
  *     Receive-Only : RTP_RX | RTCP_TX | RTCP_RX - eg. Remote Hold.
  *     Send-Receive : RTP_TX | RTP_RX | RTCP_TX | RTCP_RX - eg. Active call.
  *     Send-Only    : RTP_TX | RTCP_TX | RTCP_RX - eg. Simplex call, voice mail, etc
+ * @hide
  */
 @VintfStability
 @Backing(type="int")
+@JavaDerive(toString=true)
 enum MediaDirection {
     /**
      * No RTP/RTCP flow in either direction. The implementation
diff --git a/radio/aidl/android/hardware/radio/ims/media/MediaQualityStatus.aidl b/radio/aidl/android/hardware/radio/ims/media/MediaQualityStatus.aidl
index b99e501..b617f91 100644
--- a/radio/aidl/android/hardware/radio/ims/media/MediaQualityStatus.aidl
+++ b/radio/aidl/android/hardware/radio/ims/media/MediaQualityStatus.aidl
@@ -16,7 +16,9 @@
 
 package android.hardware.radio.ims.media;
 
+/** @hide */
 @VintfStability
+@JavaDerive(toString=true)
 parcelable MediaQualityStatus {
     /**
      * Rtp inactivity observed as per threshold set by
diff --git a/radio/aidl/android/hardware/radio/ims/media/MediaQualityThreshold.aidl b/radio/aidl/android/hardware/radio/ims/media/MediaQualityThreshold.aidl
index bf98928..25473d0 100644
--- a/radio/aidl/android/hardware/radio/ims/media/MediaQualityThreshold.aidl
+++ b/radio/aidl/android/hardware/radio/ims/media/MediaQualityThreshold.aidl
@@ -16,7 +16,9 @@
 
 package android.hardware.radio.ims.media;
 
+/** @hide */
 @VintfStability
+@JavaDerive(toString=true)
 parcelable MediaQualityThreshold {
     /** Array including threshold values in milliseconds for monitoring RTP inactivity */
     int[] rtpInactivityTimerMillis;
diff --git a/radio/aidl/android/hardware/radio/ims/media/RtcpConfig.aidl b/radio/aidl/android/hardware/radio/ims/media/RtcpConfig.aidl
index 98bbfc6..9cb3c0e 100644
--- a/radio/aidl/android/hardware/radio/ims/media/RtcpConfig.aidl
+++ b/radio/aidl/android/hardware/radio/ims/media/RtcpConfig.aidl
@@ -16,7 +16,9 @@
 
 package android.hardware.radio.ims.media;
 
+/** @hide */
 @VintfStability
+@JavaDerive(toString=true)
 parcelable RtcpConfig {
     /** Canonical name that will be sent to all session participants */
     String canonicalName;
diff --git a/radio/aidl/android/hardware/radio/ims/media/RtcpXrReportBlockType.aidl b/radio/aidl/android/hardware/radio/ims/media/RtcpXrReportBlockType.aidl
index 7f6839a..88180d7 100644
--- a/radio/aidl/android/hardware/radio/ims/media/RtcpXrReportBlockType.aidl
+++ b/radio/aidl/android/hardware/radio/ims/media/RtcpXrReportBlockType.aidl
@@ -16,25 +16,28 @@
 
 package android.hardware.radio.ims.media;
 
-/** RTP Control Protocol Extended Reports (RTCP XR) Blocks, See RFC 3611 section 4 */
-
+/**
+ * RTP Control Protocol Extended Reports (RTCP XR) Blocks, See RFC 3611 section 4
+ * @hide
+ */
 @VintfStability
 @Backing(type="int")
+@JavaDerive(toString=true)
 enum RtcpXrReportBlockType {
     /** Disable RTCP XR */
     RTCPXR_NONE = 0,
     /** Loss RLE Report Block */
-    RTCPXR_LOSS_RLE_REPORT_BLOCK                  = 1 << 0,
+    RTCPXR_LOSS_RLE_REPORT_BLOCK = 1 << 0,
     /** Duplicate RLE Report Block */
-    RTCPXR_DUPLICATE_RLE_REPORT_BLOCK             = 1 << 1,
+    RTCPXR_DUPLICATE_RLE_REPORT_BLOCK = 1 << 1,
     /** Packet Receipt Times Report Block */
-    RTCPXR_PACKET_RECEIPT_TIMES_REPORT_BLOCK      = 1 << 2,
+    RTCPXR_PACKET_RECEIPT_TIMES_REPORT_BLOCK = 1 << 2,
     /** Receiver Reference Time Report Block */
-    RTCPXR_RECEIVER_REFERENCE_TIME_REPORT_BLOCK   = 1 << 3,
+    RTCPXR_RECEIVER_REFERENCE_TIME_REPORT_BLOCK = 1 << 3,
     /** DLRR Report Block */
-    RTCPXR_DLRR_REPORT_BLOCK                      = 1 << 4,
+    RTCPXR_DLRR_REPORT_BLOCK = 1 << 4,
     /** Statistics Summary Report Block */
-    RTCPXR_STATISTICS_SUMMARY_REPORT_BLOCK        = 1 << 5,
+    RTCPXR_STATISTICS_SUMMARY_REPORT_BLOCK = 1 << 5,
     /** VoIP Metrics Report Block */
-    RTCPXR_VOIP_METRICS_REPORT_BLOCK              = 1 << 6,
+    RTCPXR_VOIP_METRICS_REPORT_BLOCK = 1 << 6,
 }
diff --git a/radio/aidl/android/hardware/radio/ims/media/RtpAddress.aidl b/radio/aidl/android/hardware/radio/ims/media/RtpAddress.aidl
index 2db73a3..c17e4b2 100644
--- a/radio/aidl/android/hardware/radio/ims/media/RtpAddress.aidl
+++ b/radio/aidl/android/hardware/radio/ims/media/RtpAddress.aidl
@@ -16,7 +16,9 @@
 
 package android.hardware.radio.ims.media;
 
+/** @hide */
 @VintfStability
+@JavaDerive(toString=true)
 parcelable RtpAddress {
     /** Point to point IP address */
     String ipAddress;
diff --git a/radio/aidl/android/hardware/radio/ims/media/RtpConfig.aidl b/radio/aidl/android/hardware/radio/ims/media/RtpConfig.aidl
index f93b112..3c5c4dd 100644
--- a/radio/aidl/android/hardware/radio/ims/media/RtpConfig.aidl
+++ b/radio/aidl/android/hardware/radio/ims/media/RtpConfig.aidl
@@ -22,7 +22,9 @@
 import android.hardware.radio.ims.media.RtpAddress;
 import android.hardware.radio.ims.media.RtpSessionParams;
 
+/** @hide */
 @VintfStability
+@JavaDerive(toString=true)
 parcelable RtpConfig {
     /** Media flow direction. The bitfield of MediaDirection(s) */
     int direction;
diff --git a/radio/aidl/android/hardware/radio/ims/media/RtpError.aidl b/radio/aidl/android/hardware/radio/ims/media/RtpError.aidl
index 11a3468..84f972f 100644
--- a/radio/aidl/android/hardware/radio/ims/media/RtpError.aidl
+++ b/radio/aidl/android/hardware/radio/ims/media/RtpError.aidl
@@ -16,8 +16,10 @@
 
 package android.hardware.radio.ims.media;
 
+/** @hide */
 @VintfStability
 @Backing(type="int")
+@JavaDerive(toString=true)
 enum RtpError {
     /** Success */
     NONE = 0,
diff --git a/radio/aidl/android/hardware/radio/ims/media/RtpHeaderExtension.aidl b/radio/aidl/android/hardware/radio/ims/media/RtpHeaderExtension.aidl
index 76b13dc..19e855a 100644
--- a/radio/aidl/android/hardware/radio/ims/media/RtpHeaderExtension.aidl
+++ b/radio/aidl/android/hardware/radio/ims/media/RtpHeaderExtension.aidl
@@ -16,8 +16,12 @@
 
 package android.hardware.radio.ims.media;
 
-/** RTP Header Extensions, see RFC 8285 */
+/**
+ * RTP Header Extensions, see RFC 8285
+ * @hide
+ */
 @VintfStability
+@JavaDerive(toString=true)
 parcelable RtpHeaderExtension {
     /** Local identifier */
     int localId;
diff --git a/radio/aidl/android/hardware/radio/ims/media/RtpReceptionStats.aidl b/radio/aidl/android/hardware/radio/ims/media/RtpReceptionStats.aidl
new file mode 100644
index 0000000..1239d13
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/ims/media/RtpReceptionStats.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio.ims.media;
+
+@VintfStability
+parcelable RtpReceptionStats {
+    /** The timestamp of the latest RTP packet received */
+    int rtpTimestamp;
+    /** The sequence number of latest RTP packet received */
+    int rtpSequenceNumber;
+    /** The system clock time in millisecond of latest RTP packet received */
+    int timeDurationMs;
+    /** The jitter buffer size in millisecond when latest RTP packet received */
+    int jitterBufferMs;
+    /** The round trip time delay in millisecond when latest RTP packet received */
+    int roundTripTimeMs;
+}
diff --git a/radio/aidl/android/hardware/radio/ims/media/RtpSessionParams.aidl b/radio/aidl/android/hardware/radio/ims/media/RtpSessionParams.aidl
index f93c52c..ae5c7e6 100644
--- a/radio/aidl/android/hardware/radio/ims/media/RtpSessionParams.aidl
+++ b/radio/aidl/android/hardware/radio/ims/media/RtpSessionParams.aidl
@@ -19,7 +19,9 @@
 import android.hardware.radio.ims.media.CodecParams;
 import android.hardware.radio.ims.media.DtmfParams;
 
+/** @hide */
 @VintfStability
+@JavaDerive(toString=true)
 parcelable RtpSessionParams {
     /**
      * ptime: Recommended length of time in milliseconds represented by the media
diff --git a/radio/aidl/android/hardware/radio/messaging/CdmaBroadcastSmsConfigInfo.aidl b/radio/aidl/android/hardware/radio/messaging/CdmaBroadcastSmsConfigInfo.aidl
index 4173f15..35a6a8d 100644
--- a/radio/aidl/android/hardware/radio/messaging/CdmaBroadcastSmsConfigInfo.aidl
+++ b/radio/aidl/android/hardware/radio/messaging/CdmaBroadcastSmsConfigInfo.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.messaging;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable CdmaBroadcastSmsConfigInfo {
diff --git a/radio/aidl/android/hardware/radio/messaging/CdmaSmsAck.aidl b/radio/aidl/android/hardware/radio/messaging/CdmaSmsAck.aidl
index 85ef692..2544ab5 100644
--- a/radio/aidl/android/hardware/radio/messaging/CdmaSmsAck.aidl
+++ b/radio/aidl/android/hardware/radio/messaging/CdmaSmsAck.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.messaging;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable CdmaSmsAck {
diff --git a/radio/aidl/android/hardware/radio/messaging/CdmaSmsAddress.aidl b/radio/aidl/android/hardware/radio/messaging/CdmaSmsAddress.aidl
index 8e521df..a7ad233 100644
--- a/radio/aidl/android/hardware/radio/messaging/CdmaSmsAddress.aidl
+++ b/radio/aidl/android/hardware/radio/messaging/CdmaSmsAddress.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.messaging;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable CdmaSmsAddress {
diff --git a/radio/aidl/android/hardware/radio/messaging/CdmaSmsMessage.aidl b/radio/aidl/android/hardware/radio/messaging/CdmaSmsMessage.aidl
index d4fb26f..51388b6 100644
--- a/radio/aidl/android/hardware/radio/messaging/CdmaSmsMessage.aidl
+++ b/radio/aidl/android/hardware/radio/messaging/CdmaSmsMessage.aidl
@@ -19,6 +19,7 @@
 import android.hardware.radio.messaging.CdmaSmsAddress;
 import android.hardware.radio.messaging.CdmaSmsSubaddress;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable CdmaSmsMessage {
diff --git a/radio/aidl/android/hardware/radio/messaging/CdmaSmsSubaddress.aidl b/radio/aidl/android/hardware/radio/messaging/CdmaSmsSubaddress.aidl
index 18e5837..19d84ff 100644
--- a/radio/aidl/android/hardware/radio/messaging/CdmaSmsSubaddress.aidl
+++ b/radio/aidl/android/hardware/radio/messaging/CdmaSmsSubaddress.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.messaging;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable CdmaSmsSubaddress {
diff --git a/radio/aidl/android/hardware/radio/messaging/CdmaSmsWriteArgs.aidl b/radio/aidl/android/hardware/radio/messaging/CdmaSmsWriteArgs.aidl
index 4191985..897ec80 100644
--- a/radio/aidl/android/hardware/radio/messaging/CdmaSmsWriteArgs.aidl
+++ b/radio/aidl/android/hardware/radio/messaging/CdmaSmsWriteArgs.aidl
@@ -18,6 +18,7 @@
 
 import android.hardware.radio.messaging.CdmaSmsMessage;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable CdmaSmsWriteArgs {
diff --git a/radio/aidl/android/hardware/radio/messaging/GsmBroadcastSmsConfigInfo.aidl b/radio/aidl/android/hardware/radio/messaging/GsmBroadcastSmsConfigInfo.aidl
index 5138c3c..b4ab518 100644
--- a/radio/aidl/android/hardware/radio/messaging/GsmBroadcastSmsConfigInfo.aidl
+++ b/radio/aidl/android/hardware/radio/messaging/GsmBroadcastSmsConfigInfo.aidl
@@ -18,6 +18,7 @@
 
 /**
  * Which types of Cell Broadcast Message (CBM) are to be received by the ME
+ * @hide
  */
 @VintfStability
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/messaging/GsmSmsMessage.aidl b/radio/aidl/android/hardware/radio/messaging/GsmSmsMessage.aidl
index b256c9a..9a1a7b9 100644
--- a/radio/aidl/android/hardware/radio/messaging/GsmSmsMessage.aidl
+++ b/radio/aidl/android/hardware/radio/messaging/GsmSmsMessage.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.messaging;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable GsmSmsMessage {
diff --git a/radio/aidl/android/hardware/radio/messaging/IRadioMessaging.aidl b/radio/aidl/android/hardware/radio/messaging/IRadioMessaging.aidl
index 8bd84a3..945453c 100644
--- a/radio/aidl/android/hardware/radio/messaging/IRadioMessaging.aidl
+++ b/radio/aidl/android/hardware/radio/messaging/IRadioMessaging.aidl
@@ -35,6 +35,7 @@
  * duration of a method call. If clients provide colliding serials (including passing the same
  * serial to different methods), multiple responses (one for each method call) must still be served.
  * setResponseFunctions must work with IRadioMessagingResponse and IRadioMessagingIndication.
+ * @hide
  */
 @VintfStability
 oneway interface IRadioMessaging {
@@ -49,6 +50,8 @@
      * @param ackPdu acknowledgement TPDU in hexadecimal format
      *
      * Response function is IRadioMessagingResponse.acknowledgeIncomingGsmSmsWithPduResponse()
+     *
+     * This is available when android.hardware.telephony.messaging is defined.
      */
     void acknowledgeIncomingGsmSmsWithPdu(in int serial, in boolean success, in String ackPdu);
 
@@ -60,6 +63,8 @@
      * @param smsAck Cdma Sms ack to be sent described by CdmaSmsAck
      *
      * Response function is IRadioMessagingResponse.acknowledgeLastIncomingCdmaSmsResponse()
+     *
+     * This is available when android.hardware.telephony.cdma is defined.
      */
     void acknowledgeLastIncomingCdmaSms(in int serial, in CdmaSmsAck smsAck);
 
@@ -74,6 +79,8 @@
      *        in TS 23.040, 9.2.3.22.
      *
      * Response function is IRadioMessagingResponse.acknowledgeLastIncomingGsmSmsResponse()
+     *
+     * This is available when android.hardware.telephony.messaging is defined.
      */
     void acknowledgeLastIncomingGsmSms(
             in int serial, in boolean success, in SmsAcknowledgeFailCause cause);
@@ -85,6 +92,8 @@
      * @param index record index of the message to delete
      *
      * Response function is IRadioMessagingResponse.deleteSmsOnRuimResponse()
+     *
+     * This is available when android.hardware.telephony.cdma is defined.
      */
     void deleteSmsOnRuim(in int serial, in int index);
 
@@ -95,6 +104,8 @@
      * @param index Record index of the message to delete.
      *
      * Response function is IRadioMessagingResponse.deleteSmsOnSimResponse()
+     *
+     * This is available when android.hardware.telephony.messaging is defined.
      */
     void deleteSmsOnSim(in int serial, in int index);
 
@@ -104,6 +115,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioMessagingResponse.getCdmaBroadcastConfigResponse()
+     *
+     * This is available when android.hardware.telephony.cdma is defined.
      */
     void getCdmaBroadcastConfig(in int serial);
 
@@ -113,6 +126,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioMessagingResponse.getGsmBroadcastConfigResponse()
+     *
+     * This is available when android.hardware.telephony.messaging is defined.
      */
     void getGsmBroadcastConfig(in int serial);
 
@@ -122,6 +137,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioMessagingResponse.getSmscAddressResponse()
+     *
+     * This is available when android.hardware.telephony.messaging is defined.
      */
     void getSmscAddress(in int serial);
 
@@ -133,6 +150,8 @@
      *        false if memory capacity is exceeded
      *
      * Response function is IRadioMessagingResponse.reportSmsMemoryStatusResponse()
+     *
+     * This is available when android.hardware.telephony.messaging is defined.
      */
     void reportSmsMemoryStatus(in int serial, in boolean available);
 
@@ -140,6 +159,8 @@
      * When response type received from a radio indication or radio response is
      * RadioIndicationType:UNSOLICITED_ACK_EXP or RadioResponseType:SOLICITED_ACK_EXP respectively,
      * acknowledge the receipt of those messages by sending responseAcknowledgement().
+     *
+     * This is available when android.hardware.telephony.messaging is defined.
      */
     void responseAcknowledgement();
 
@@ -150,6 +171,8 @@
      * @param sms CdmaSmsMessage to be sent
      *
      * Response function is IRadioMessagingResponse.sendCdmaSmsResponse()
+     *
+     * This is available when android.hardware.telephony.cdma is defined.
      */
     void sendCdmaSms(in int serial, in CdmaSmsMessage sms);
 
@@ -161,6 +184,8 @@
      * @param sms CdmaSmsMessage to be sent
      *
      * Response function is IRadioMessagingResponse.sendCdmaSmsExpectMoreResponse()
+     *
+     * This is available when android.hardware.telephony.cdma is defined.
      */
     void sendCdmaSmsExpectMore(in int serial, in CdmaSmsMessage sms);
 
@@ -173,6 +198,8 @@
      * @param message ImsSmsMessage to be sent
      *
      * Response function is IRadioMessagingResponse.sendImsSmsResponse()
+     *
+     * This is available when android.hardware.telephony.ims is defined.
      */
     void sendImsSms(in int serial, in ImsSmsMessage message);
 
@@ -185,6 +212,8 @@
      * @param message GsmSmsMessage to be sent
      *
      * Response function is IRadioMessagingResponse.sendSmsResponse()
+     *
+     * This is available when android.hardware.telephony.messaging is defined.
      */
     void sendSms(in int serial, in GsmSmsMessage message);
 
@@ -199,6 +228,8 @@
      * @param message GsmSmsMessage to be sent
      *
      * Response function is IRadioMessagingResponse.sendSmsExpectMoreResponse()
+     *
+     * This is available when android.hardware.telephony.messaging is defined.
      */
     void sendSmsExpectMore(in int serial, in GsmSmsMessage message);
 
@@ -210,6 +241,8 @@
      *        true = activate, false = turn off
      *
      * Response function is IRadioMessagingResponse.setCdmaBroadcastActivationResponse()
+     *
+     * This is available when android.hardware.telephony.cdma is defined.
      */
     void setCdmaBroadcastActivation(in int serial, in boolean activate);
 
@@ -220,6 +253,8 @@
      * @param configInfo CDMA Broadcast SMS config to be set.
      *
      * Response function is IRadioMessagingResponse.setCdmaBroadcastConfigResponse()
+     *
+     * This is available when android.hardware.telephony.cdma is defined.
      */
     void setCdmaBroadcastConfig(in int serial, in CdmaBroadcastSmsConfigInfo[] configInfo);
 
@@ -231,6 +266,8 @@
      *        Cell Broadcast SMS. true = activate, false = turn off
      *
      * Response function is IRadioMessagingResponse.setGsmBroadcastActivationResponse()
+     *
+     * This is available when android.hardware.telephony.messaging is defined.
      */
     void setGsmBroadcastActivation(in int serial, in boolean activate);
 
@@ -241,6 +278,8 @@
      * @param configInfo Setting of GSM/WCDMA Cell broadcast config
      *
      * Response function is IRadioMessagingResponse.setGsmBroadcastConfigResponse()
+     *
+     * This is available when android.hardware.telephony.messaging is defined.
      */
     void setGsmBroadcastConfig(in int serial, in GsmBroadcastSmsConfigInfo[] configInfo);
 
@@ -249,6 +288,8 @@
      *
      * @param radioMessagingResponse Object containing response functions
      * @param radioMessagingIndication Object containing radio indications
+     *
+     * This is available when android.hardware.telephony.messaging is defined.
      */
     void setResponseFunctions(in IRadioMessagingResponse radioMessagingResponse,
             in IRadioMessagingIndication radioMessagingIndication);
@@ -260,6 +301,8 @@
      * @param smsc Short Message Service Center address to set
      *
      * Response function is IRadioMessagingResponse.setSmscAddressResponse()
+     *
+     * This is available when android.hardware.telephony.messaging is defined.
      */
     void setSmscAddress(in int serial, in String smsc);
 
@@ -270,6 +313,8 @@
      * @param cdmaSms CdmaSmsWriteArgs
      *
      * Response function is IRadioMessagingResponse.writeSmsToRuimResponse()
+     *
+     * This is available when android.hardware.telephony.cdma is defined.
      */
     void writeSmsToRuim(in int serial, in CdmaSmsWriteArgs cdmaSms);
 
@@ -280,6 +325,8 @@
      * @param smsWriteArgs SmsWriteArgs
      *
      * Response function is IRadioMessagingResponse.writeSmsToSimResponse()
+     *
+     * This is available when android.hardware.telephony.messaging is defined.
      */
     void writeSmsToSim(in int serial, in SmsWriteArgs smsWriteArgs);
 }
diff --git a/radio/aidl/android/hardware/radio/messaging/IRadioMessagingIndication.aidl b/radio/aidl/android/hardware/radio/messaging/IRadioMessagingIndication.aidl
index 8834cd9..a177c2c 100644
--- a/radio/aidl/android/hardware/radio/messaging/IRadioMessagingIndication.aidl
+++ b/radio/aidl/android/hardware/radio/messaging/IRadioMessagingIndication.aidl
@@ -21,6 +21,7 @@
 
 /**
  * Interface declaring unsolicited radio indications for messaging APIs.
+ * @hide
  */
 @VintfStability
 oneway interface IRadioMessagingIndication {
diff --git a/radio/aidl/android/hardware/radio/messaging/IRadioMessagingResponse.aidl b/radio/aidl/android/hardware/radio/messaging/IRadioMessagingResponse.aidl
index 8cbc869..f0d7999 100644
--- a/radio/aidl/android/hardware/radio/messaging/IRadioMessagingResponse.aidl
+++ b/radio/aidl/android/hardware/radio/messaging/IRadioMessagingResponse.aidl
@@ -23,6 +23,7 @@
 
 /**
  * Interface declaring response functions to solicited radio requests for messaging APIs.
+ * @hide
  */
 @VintfStability
 oneway interface IRadioMessagingResponse {
@@ -30,6 +31,8 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.messaging is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
@@ -43,6 +46,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.cdma is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_ARGUMENTS
@@ -65,6 +69,8 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.messaging is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
@@ -87,6 +93,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.cdma is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_ARGUMENTS
@@ -108,6 +115,8 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.messaging is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:SIM_FULL
@@ -130,6 +139,7 @@
      * @param configs Vector of CDMA Broadcast SMS configs.
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.cdma is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_ARGUMENTS
@@ -152,6 +162,8 @@
      * @param configs Vector of GSM/WCDMA Cell broadcast configs
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.messaging is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_ARGUMENTS
@@ -174,6 +186,8 @@
      * @param smsc Short Message Service Center address on the device
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.messaging is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_ARGUMENTS
@@ -195,6 +209,8 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.messaging is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_ARGUMENTS
@@ -215,6 +231,7 @@
      * @param sms Response to sms sent as defined by SendSmsResult
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.cdma is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:SMS_SEND_FAIL_RETRY
@@ -248,6 +265,7 @@
      * @param sms Sms result struct as defined by SendSmsResult
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.cdma is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_ARGUMENTS
@@ -281,6 +299,7 @@
      * @param sms Response to sms sent as defined by SendSmsResult
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.ims is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:SMS_SEND_FAIL_RETRY
@@ -308,6 +327,8 @@
      * @param sms Response to sms sent as defined by SendSmsResult
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.messaging is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:SMS_SEND_FAIL_RETRY
@@ -340,6 +361,8 @@
      * @param sms Response to sms sent as defined by SendSmsResult
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.messaging is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:SMS_SEND_FAIL_RETRY
@@ -370,6 +393,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.cdma is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_ARGUMENTS
@@ -390,6 +414,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.cdma is not
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_ARGUMENTS
@@ -409,6 +434,8 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.messaging is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_ARGUMENTS
@@ -429,6 +456,8 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.messaging is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_ARGUMENTS
@@ -448,6 +477,8 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.messaging is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_ARGUMENTS
@@ -470,6 +501,7 @@
      * @param index record index where the cmda sms message is stored
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.cdma is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_ARGUMENTS
@@ -496,6 +528,8 @@
      * @param index record index where the message is stored
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.messaging is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:SIM_FULL
diff --git a/radio/aidl/android/hardware/radio/messaging/ImsSmsMessage.aidl b/radio/aidl/android/hardware/radio/messaging/ImsSmsMessage.aidl
index d4be044..5f9f82b 100644
--- a/radio/aidl/android/hardware/radio/messaging/ImsSmsMessage.aidl
+++ b/radio/aidl/android/hardware/radio/messaging/ImsSmsMessage.aidl
@@ -20,6 +20,7 @@
 import android.hardware.radio.messaging.CdmaSmsMessage;
 import android.hardware.radio.messaging.GsmSmsMessage;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable ImsSmsMessage {
diff --git a/radio/aidl/android/hardware/radio/messaging/SendSmsResult.aidl b/radio/aidl/android/hardware/radio/messaging/SendSmsResult.aidl
index 80e059c..ea93727 100644
--- a/radio/aidl/android/hardware/radio/messaging/SendSmsResult.aidl
+++ b/radio/aidl/android/hardware/radio/messaging/SendSmsResult.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.messaging;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable SendSmsResult {
diff --git a/radio/aidl/android/hardware/radio/messaging/SmsAcknowledgeFailCause.aidl b/radio/aidl/android/hardware/radio/messaging/SmsAcknowledgeFailCause.aidl
index eb15bf1..6f529eb 100644
--- a/radio/aidl/android/hardware/radio/messaging/SmsAcknowledgeFailCause.aidl
+++ b/radio/aidl/android/hardware/radio/messaging/SmsAcknowledgeFailCause.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.messaging;
 
+/** @hide */
 @VintfStability
 @Backing(type="int")
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/messaging/SmsWriteArgs.aidl b/radio/aidl/android/hardware/radio/messaging/SmsWriteArgs.aidl
index 6eef941..64ce606 100644
--- a/radio/aidl/android/hardware/radio/messaging/SmsWriteArgs.aidl
+++ b/radio/aidl/android/hardware/radio/messaging/SmsWriteArgs.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.messaging;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable SmsWriteArgs {
diff --git a/radio/aidl/android/hardware/radio/modem/ActivityStatsInfo.aidl b/radio/aidl/android/hardware/radio/modem/ActivityStatsInfo.aidl
index b2a56d4..db77c51 100644
--- a/radio/aidl/android/hardware/radio/modem/ActivityStatsInfo.aidl
+++ b/radio/aidl/android/hardware/radio/modem/ActivityStatsInfo.aidl
@@ -18,6 +18,7 @@
 
 import android.hardware.radio.modem.ActivityStatsTechSpecificInfo;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable ActivityStatsInfo {
diff --git a/radio/aidl/android/hardware/radio/modem/ActivityStatsTechSpecificInfo.aidl b/radio/aidl/android/hardware/radio/modem/ActivityStatsTechSpecificInfo.aidl
index fcc2df2..7ca4021 100644
--- a/radio/aidl/android/hardware/radio/modem/ActivityStatsTechSpecificInfo.aidl
+++ b/radio/aidl/android/hardware/radio/modem/ActivityStatsTechSpecificInfo.aidl
@@ -18,6 +18,7 @@
 
 import android.hardware.radio.AccessNetwork;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable ActivityStatsTechSpecificInfo {
diff --git a/radio/aidl/android/hardware/radio/modem/DeviceStateType.aidl b/radio/aidl/android/hardware/radio/modem/DeviceStateType.aidl
index ad0d59c..c1f4cd6 100644
--- a/radio/aidl/android/hardware/radio/modem/DeviceStateType.aidl
+++ b/radio/aidl/android/hardware/radio/modem/DeviceStateType.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.modem;
 
+/** @hide */
 @VintfStability
 @Backing(type="int")
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/modem/HardwareConfig.aidl b/radio/aidl/android/hardware/radio/modem/HardwareConfig.aidl
index 8eb1f2d..323e5c9 100644
--- a/radio/aidl/android/hardware/radio/modem/HardwareConfig.aidl
+++ b/radio/aidl/android/hardware/radio/modem/HardwareConfig.aidl
@@ -19,6 +19,7 @@
 import android.hardware.radio.modem.HardwareConfigModem;
 import android.hardware.radio.modem.HardwareConfigSim;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable HardwareConfig {
diff --git a/radio/aidl/android/hardware/radio/modem/HardwareConfigModem.aidl b/radio/aidl/android/hardware/radio/modem/HardwareConfigModem.aidl
index f5e2c27..1ba3562 100644
--- a/radio/aidl/android/hardware/radio/modem/HardwareConfigModem.aidl
+++ b/radio/aidl/android/hardware/radio/modem/HardwareConfigModem.aidl
@@ -18,6 +18,7 @@
 
 import android.hardware.radio.RadioTechnology;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable HardwareConfigModem {
diff --git a/radio/aidl/android/hardware/radio/modem/HardwareConfigSim.aidl b/radio/aidl/android/hardware/radio/modem/HardwareConfigSim.aidl
index c82bc6e..a5747c1 100644
--- a/radio/aidl/android/hardware/radio/modem/HardwareConfigSim.aidl
+++ b/radio/aidl/android/hardware/radio/modem/HardwareConfigSim.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.modem;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable HardwareConfigSim {
diff --git a/radio/aidl/android/hardware/radio/modem/IRadioModem.aidl b/radio/aidl/android/hardware/radio/modem/IRadioModem.aidl
index 2011c53..bfca5a9 100644
--- a/radio/aidl/android/hardware/radio/modem/IRadioModem.aidl
+++ b/radio/aidl/android/hardware/radio/modem/IRadioModem.aidl
@@ -31,6 +31,7 @@
  * duration of a method call. If clients provide colliding serials (including passing the same
  * serial to different methods), multiple responses (one for each method call) must still be served.
  * setResponseFunctions must work with IRadioModemResponse and IRadioModemIndication.
+ * @hide
  */
 @VintfStability
 oneway interface IRadioModem {
@@ -47,6 +48,8 @@
      * @param on True to turn on the logical modem, otherwise turn it off.
      *
      * Response function is IRadioModemResponse.enableModemResponse()
+     *
+     * This is available when android.hardware.telephony is defined.
      */
     void enableModem(in int serial, in boolean on);
 
@@ -56,6 +59,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioModemResponse.getBasebandVersionResponse()
+     *
+     * This is available when android.hardware.telephony is defined.
      */
     void getBasebandVersion(in int serial);
 
@@ -67,6 +72,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioModemResponse.getDeviceIdentityResponse()
+     *
+     * This is available when android.hardware.telephony is defined.
      * @deprecated use getImei(int serial)
      */
     void getDeviceIdentity(in int serial);
@@ -77,6 +84,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioModemResponse.getHardwareConfigResponse()
+     *
+     * This is available when android.hardware.telephony is defined.
      */
     void getHardwareConfig(in int serial);
 
@@ -88,6 +97,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioModemResponse.getModemActivityInfoResponse()
+     *
+     * This is available when android.hardware.telephony.radio.access is defined.
      */
     void getModemActivityInfo(in int serial);
 
@@ -98,6 +109,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioModemResponse.getModemStackStatusResponse()
+     *
+     * This is available when android.hardware.telephony is defined.
      */
     void getModemStackStatus(in int serial);
 
@@ -107,6 +120,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioModemResponse.getRadioCapabilityResponse()
+     *
+     * This is available when android.hardware.telephony.radio.access is defined.
      */
     void getRadioCapability(in int serial);
 
@@ -145,6 +160,8 @@
      *
      * Response function is IRadioModemResponse.nvWriteCdmaPrlResponse()
      *
+     * This is available when android.hardware.telephony.cdma is defined.
+     *
      * @deprecated NV APIs are deprecated starting from Android U.
      */
     void nvWriteCdmaPrl(in int serial, in byte[] prl);
@@ -169,6 +186,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioModemResponse.requestShutdownResponse()
+     *
+     * This is available when android.hardware.telephony.radio.access is defined.
      */
     void requestShutdown(in int serial);
 
@@ -176,6 +195,8 @@
      * When response type received from a radio indication or radio response is
      * RadioIndicationType:UNSOLICITED_ACK_EXP or RadioResponseType:SOLICITED_ACK_EXP respectively,
      * acknowledge the receipt of those messages by sending responseAcknowledgement().
+     *
+     * This is available when android.hardware.telephony is defined.
      */
     void responseAcknowledgement();
 
@@ -188,6 +209,8 @@
      * @param state The updated state. See the definition of state at DeviceStateType.
      *
      * Response function is IRadioModemResponse.sendDeviceStateResponse()
+     *
+     * This is available when android.hardware.telephony is defined.
      */
     void sendDeviceState(in int serial, in DeviceStateType deviceStateType, in boolean state);
 
@@ -200,6 +223,8 @@
      * @param rc RadioCapability structure to be set
      *
      * Response function is IRadioModemResponse.setRadioCapabilityResponse()
+     *
+     * This is available when android.hardware.telephony.radio.access is defined.
      */
     void setRadioCapability(in int serial, in RadioCapability rc);
 
@@ -224,6 +249,8 @@
      *        on this modem or not. No effect if forEmergencyCall is false, or powerOn is false.
      *
      * Response function is IRadioConfigResponse.setRadioPowerResponse()
+     *
+     * This is available when android.hardware.telephony.radio.access is defined.
      */
     void setRadioPower(in int serial, in boolean powerOn, in boolean forEmergencyCall,
             in boolean preferredForEmergencyCall);
@@ -233,6 +260,8 @@
      *
      * @param radioModemResponse Object containing response functions
      * @param radioModemIndication Object containing radio indications
+     *
+     * This is available when android.hardware.telephony is defined.
      */
     void setResponseFunctions(in IRadioModemResponse radioModemResponse,
             in IRadioModemIndication radioModemIndication);
@@ -243,6 +272,8 @@
      * @param serial : Serial number of request.
      *
      * Response function is IRadioModemResponse.getImeiResponse()
+     *
+     * This is available when android.hardware.telephony.gsm is defined.
      */
-     void getImei(in int serial);
+    void getImei(in int serial);
 }
diff --git a/radio/aidl/android/hardware/radio/modem/IRadioModemIndication.aidl b/radio/aidl/android/hardware/radio/modem/IRadioModemIndication.aidl
index c61de99..ba3c510 100644
--- a/radio/aidl/android/hardware/radio/modem/IRadioModemIndication.aidl
+++ b/radio/aidl/android/hardware/radio/modem/IRadioModemIndication.aidl
@@ -20,9 +20,11 @@
 import android.hardware.radio.modem.HardwareConfig;
 import android.hardware.radio.modem.RadioCapability;
 import android.hardware.radio.modem.RadioState;
+import android.hardware.radio.modem.ImeiInfo;
 
 /**
  * Interface declaring unsolicited radio indications for modem APIs.
+ * @hide
  */
 @VintfStability
 oneway interface IRadioModemIndication {
@@ -75,4 +77,12 @@
      * @param type Type of radio indication
      */
     void rilConnected(in RadioIndicationType type);
+
+    /**
+     * Indicates when there is a change in the IMEI mapping.
+     *
+     * @param type Type of radio indication
+     * @param imeiInfo IMEI information
+     */
+     void onImeiMappingChanged(in RadioIndicationType type, in ImeiInfo imeiInfo);
 }
diff --git a/radio/aidl/android/hardware/radio/modem/IRadioModemResponse.aidl b/radio/aidl/android/hardware/radio/modem/IRadioModemResponse.aidl
index fd4bffb..6d2504c 100644
--- a/radio/aidl/android/hardware/radio/modem/IRadioModemResponse.aidl
+++ b/radio/aidl/android/hardware/radio/modem/IRadioModemResponse.aidl
@@ -19,11 +19,12 @@
 import android.hardware.radio.RadioResponseInfo;
 import android.hardware.radio.modem.ActivityStatsInfo;
 import android.hardware.radio.modem.HardwareConfig;
-import android.hardware.radio.modem.RadioCapability;
 import android.hardware.radio.modem.ImeiInfo;
+import android.hardware.radio.modem.RadioCapability;
 
 /**
  * Interface declaring response functions to solicited radio requests for modem APIs.
+ * @hide
  */
 @VintfStability
 oneway interface IRadioModemResponse {
@@ -40,6 +41,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:MODEM_ERR
@@ -54,6 +56,7 @@
      * @param version string containing version string for log reporting
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:EMPTY_RECORD
@@ -78,6 +81,7 @@
      * accessing the device.
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:NO_MEMORY
@@ -99,6 +103,7 @@
      * @param config Array of HardwareConfig of the radio.
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      */
@@ -109,6 +114,8 @@
      * @param activityInfo modem activity information
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:NO_MEMORY
@@ -125,6 +132,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:MODEM_ERR
@@ -136,6 +144,8 @@
      * @param rc Radio capability as defined by RadioCapability in types.hal
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:OPERATION_NOT_ALLOWED
@@ -174,6 +184,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.cdma is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *
@@ -196,6 +207,8 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:OPERATION_NOT_ALLOWED
@@ -211,6 +224,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:NO_MEMORY
@@ -228,6 +242,8 @@
      *        feedback return status
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
      *   RadioError:NONE means a unsol radioCapability() will be sent within 30 seconds.
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:OPERATION_NOT_ALLOWED
@@ -246,6 +262,8 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:INTERNAL_ERR
      *   RadioError:INVALID_ARGUMENTS
@@ -264,6 +282,7 @@
      * @param imeiInfo IMEI information
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.gsm is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:MODEM_ERR
diff --git a/radio/aidl/android/hardware/radio/modem/ImeiInfo.aidl b/radio/aidl/android/hardware/radio/modem/ImeiInfo.aidl
index 2d25bb7..6d33505 100644
--- a/radio/aidl/android/hardware/radio/modem/ImeiInfo.aidl
+++ b/radio/aidl/android/hardware/radio/modem/ImeiInfo.aidl
@@ -18,26 +18,25 @@
 
 /**
  * ImeiInfo to encapsulate the IMEI information from modem
+ * @hide
  */
-
 @VintfStability
 @JavaDerive(toString=true)
 parcelable ImeiInfo {
-
     @VintfStability
     @Backing(type="int")
     /**
      * ImeiType enum is used identify the IMEI as primary or secondary as mentioned in GSMA TS.37
      */
     enum ImeiType {
-       /**
-        * This is the primary IMEI of the device as mentioned in the GSMA TS.37. In a multi-SIM
-        * device the modem must set one IMEI with this type as mentioned in GSMA TS37_2.2_REQ_8.
-        * A single SIM with one IMEI must by default set that IMEI with this type.
-        */
-       PRIMARY = 1,
-       /** This is not the primary IMEI of the device */
-       SECONDARY = 2,
+        /**
+         * This is the primary IMEI of the device as mentioned in the GSMA TS.37. In a multi-SIM
+         * device the modem must set one IMEI with this type as mentioned in GSMA TS37_2.2_REQ_8.
+         * A single SIM with one IMEI must by default set that IMEI with this type.
+         */
+        PRIMARY = 1,
+        /** This is not the primary IMEI of the device */
+        SECONDARY = 2,
     }
 
     /** Primary or secondary IMEI as mentioned in GSMA spec TS.37 */
@@ -48,8 +47,8 @@
      * SIM activations or swaps.
      */
     String imei;
-   /**
+    /**
      * IMEI software version, see 3gpp spec 23.003 section 6.
      */
     String svn;
-}
\ No newline at end of file
+}
diff --git a/radio/aidl/android/hardware/radio/modem/NvItem.aidl b/radio/aidl/android/hardware/radio/modem/NvItem.aidl
index 310b1ad..b405137 100644
--- a/radio/aidl/android/hardware/radio/modem/NvItem.aidl
+++ b/radio/aidl/android/hardware/radio/modem/NvItem.aidl
@@ -16,7 +16,10 @@
 
 package android.hardware.radio.modem;
 
-/** @deprecated NV APIs are deprecated starting from Android U. */
+/**
+ * @deprecated NV APIs are deprecated starting from Android U.
+ * @hide
+ */
 @VintfStability
 @Backing(type="int")
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/modem/NvWriteItem.aidl b/radio/aidl/android/hardware/radio/modem/NvWriteItem.aidl
index 6472f23..c57253b 100644
--- a/radio/aidl/android/hardware/radio/modem/NvWriteItem.aidl
+++ b/radio/aidl/android/hardware/radio/modem/NvWriteItem.aidl
@@ -18,7 +18,10 @@
 
 import android.hardware.radio.modem.NvItem;
 
-/** @deprecated NV APIs are deprecated starting from Android U. */
+/**
+ * @deprecated NV APIs are deprecated starting from Android U.
+ * @hide
+ */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable NvWriteItem {
diff --git a/radio/aidl/android/hardware/radio/modem/RadioCapability.aidl b/radio/aidl/android/hardware/radio/modem/RadioCapability.aidl
index 16cba09..9781595 100644
--- a/radio/aidl/android/hardware/radio/modem/RadioCapability.aidl
+++ b/radio/aidl/android/hardware/radio/modem/RadioCapability.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.modem;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable RadioCapability {
diff --git a/radio/aidl/android/hardware/radio/modem/RadioState.aidl b/radio/aidl/android/hardware/radio/modem/RadioState.aidl
index dedad25..c36dbe0 100644
--- a/radio/aidl/android/hardware/radio/modem/RadioState.aidl
+++ b/radio/aidl/android/hardware/radio/modem/RadioState.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.modem;
 
+/** @hide */
 @VintfStability
 @Backing(type="int")
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/modem/ResetNvType.aidl b/radio/aidl/android/hardware/radio/modem/ResetNvType.aidl
index 6476fe8..e290a52 100644
--- a/radio/aidl/android/hardware/radio/modem/ResetNvType.aidl
+++ b/radio/aidl/android/hardware/radio/modem/ResetNvType.aidl
@@ -16,7 +16,10 @@
 
 package android.hardware.radio.modem;
 
-/** Note: This will be deprecated along with nvResetConfig in Android U. */
+/**
+ * Note: This will be deprecated along with nvResetConfig in Android U.
+ * @hide
+ */
 @VintfStability
 @Backing(type="int")
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/network/AccessTechnologySpecificInfo.aidl b/radio/aidl/android/hardware/radio/network/AccessTechnologySpecificInfo.aidl
index 8b95ced..9c48a8d 100644
--- a/radio/aidl/android/hardware/radio/network/AccessTechnologySpecificInfo.aidl
+++ b/radio/aidl/android/hardware/radio/network/AccessTechnologySpecificInfo.aidl
@@ -20,6 +20,7 @@
 import android.hardware.radio.network.EutranRegistrationInfo;
 import android.hardware.radio.network.NrVopsInfo;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 union AccessTechnologySpecificInfo {
diff --git a/radio/aidl/android/hardware/radio/network/BarringInfo.aidl b/radio/aidl/android/hardware/radio/network/BarringInfo.aidl
index 2759406..f12e35c 100644
--- a/radio/aidl/android/hardware/radio/network/BarringInfo.aidl
+++ b/radio/aidl/android/hardware/radio/network/BarringInfo.aidl
@@ -18,6 +18,7 @@
 
 import android.hardware.radio.network.BarringTypeSpecificInfo;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable BarringInfo {
diff --git a/radio/aidl/android/hardware/radio/network/BarringTypeSpecificInfo.aidl b/radio/aidl/android/hardware/radio/network/BarringTypeSpecificInfo.aidl
index 3db3bf3..b4a3bdf 100644
--- a/radio/aidl/android/hardware/radio/network/BarringTypeSpecificInfo.aidl
+++ b/radio/aidl/android/hardware/radio/network/BarringTypeSpecificInfo.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.network;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable BarringTypeSpecificInfo {
diff --git a/radio/aidl/android/hardware/radio/network/Cdma2000RegistrationInfo.aidl b/radio/aidl/android/hardware/radio/network/Cdma2000RegistrationInfo.aidl
index b06fabb..91b8500 100644
--- a/radio/aidl/android/hardware/radio/network/Cdma2000RegistrationInfo.aidl
+++ b/radio/aidl/android/hardware/radio/network/Cdma2000RegistrationInfo.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.network;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable Cdma2000RegistrationInfo {
diff --git a/radio/aidl/android/hardware/radio/network/CdmaRoamingType.aidl b/radio/aidl/android/hardware/radio/network/CdmaRoamingType.aidl
index 2fea519..0bb7c04 100644
--- a/radio/aidl/android/hardware/radio/network/CdmaRoamingType.aidl
+++ b/radio/aidl/android/hardware/radio/network/CdmaRoamingType.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.network;
 
+/** @hide */
 @VintfStability
 @Backing(type="int")
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/network/CdmaSignalStrength.aidl b/radio/aidl/android/hardware/radio/network/CdmaSignalStrength.aidl
index 1286f67..ae7aa93 100644
--- a/radio/aidl/android/hardware/radio/network/CdmaSignalStrength.aidl
+++ b/radio/aidl/android/hardware/radio/network/CdmaSignalStrength.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.network;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable CdmaSignalStrength {
diff --git a/radio/aidl/android/hardware/radio/network/CellConnectionStatus.aidl b/radio/aidl/android/hardware/radio/network/CellConnectionStatus.aidl
index da36ff0..3bc19e1 100644
--- a/radio/aidl/android/hardware/radio/network/CellConnectionStatus.aidl
+++ b/radio/aidl/android/hardware/radio/network/CellConnectionStatus.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.network;
 
+/** @hide */
 @VintfStability
 @Backing(type="int")
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/network/CellIdentity.aidl b/radio/aidl/android/hardware/radio/network/CellIdentity.aidl
index e34866b..6142087 100644
--- a/radio/aidl/android/hardware/radio/network/CellIdentity.aidl
+++ b/radio/aidl/android/hardware/radio/network/CellIdentity.aidl
@@ -25,6 +25,7 @@
 
 /**
  * A union representing the CellIdentity of a single cell.
+ * @hide
  */
 @VintfStability
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/network/CellIdentityCdma.aidl b/radio/aidl/android/hardware/radio/network/CellIdentityCdma.aidl
index 5bb26c1..b93988f 100644
--- a/radio/aidl/android/hardware/radio/network/CellIdentityCdma.aidl
+++ b/radio/aidl/android/hardware/radio/network/CellIdentityCdma.aidl
@@ -18,6 +18,7 @@
 
 import android.hardware.radio.network.OperatorInfo;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable CellIdentityCdma {
diff --git a/radio/aidl/android/hardware/radio/network/CellIdentityGsm.aidl b/radio/aidl/android/hardware/radio/network/CellIdentityGsm.aidl
index 60f42b6..bc02adc 100644
--- a/radio/aidl/android/hardware/radio/network/CellIdentityGsm.aidl
+++ b/radio/aidl/android/hardware/radio/network/CellIdentityGsm.aidl
@@ -18,6 +18,7 @@
 
 import android.hardware.radio.network.OperatorInfo;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable CellIdentityGsm {
diff --git a/radio/aidl/android/hardware/radio/network/CellIdentityLte.aidl b/radio/aidl/android/hardware/radio/network/CellIdentityLte.aidl
index bfa58ac..27c2580 100644
--- a/radio/aidl/android/hardware/radio/network/CellIdentityLte.aidl
+++ b/radio/aidl/android/hardware/radio/network/CellIdentityLte.aidl
@@ -20,6 +20,7 @@
 import android.hardware.radio.network.EutranBands;
 import android.hardware.radio.network.OperatorInfo;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable CellIdentityLte {
diff --git a/radio/aidl/android/hardware/radio/network/CellIdentityNr.aidl b/radio/aidl/android/hardware/radio/network/CellIdentityNr.aidl
index d51a18e..4192845 100644
--- a/radio/aidl/android/hardware/radio/network/CellIdentityNr.aidl
+++ b/radio/aidl/android/hardware/radio/network/CellIdentityNr.aidl
@@ -22,6 +22,7 @@
 /**
  * The CellIdentity structure should be reported once for each element of the PLMN-IdentityInfoList
  * broadcast in SIB1 CellAccessRelatedInfo as per 3GPP TS 38.331 Section 6.3.2.
+ * @hide
  */
 @VintfStability
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/network/CellIdentityTdscdma.aidl b/radio/aidl/android/hardware/radio/network/CellIdentityTdscdma.aidl
index f6e790f..33ffc6f 100644
--- a/radio/aidl/android/hardware/radio/network/CellIdentityTdscdma.aidl
+++ b/radio/aidl/android/hardware/radio/network/CellIdentityTdscdma.aidl
@@ -19,6 +19,7 @@
 import android.hardware.radio.network.ClosedSubscriberGroupInfo;
 import android.hardware.radio.network.OperatorInfo;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable CellIdentityTdscdma {
diff --git a/radio/aidl/android/hardware/radio/network/CellIdentityWcdma.aidl b/radio/aidl/android/hardware/radio/network/CellIdentityWcdma.aidl
index a76509b..b6e328a 100644
--- a/radio/aidl/android/hardware/radio/network/CellIdentityWcdma.aidl
+++ b/radio/aidl/android/hardware/radio/network/CellIdentityWcdma.aidl
@@ -19,6 +19,7 @@
 import android.hardware.radio.network.ClosedSubscriberGroupInfo;
 import android.hardware.radio.network.OperatorInfo;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable CellIdentityWcdma {
diff --git a/radio/aidl/android/hardware/radio/network/CellInfo.aidl b/radio/aidl/android/hardware/radio/network/CellInfo.aidl
index 161ac71..4895326 100644
--- a/radio/aidl/android/hardware/radio/network/CellInfo.aidl
+++ b/radio/aidl/android/hardware/radio/network/CellInfo.aidl
@@ -19,6 +19,7 @@
 import android.hardware.radio.network.CellConnectionStatus;
 import android.hardware.radio.network.CellInfoRatSpecificInfo;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable CellInfo {
diff --git a/radio/aidl/android/hardware/radio/network/CellInfoCdma.aidl b/radio/aidl/android/hardware/radio/network/CellInfoCdma.aidl
index 5408104..0a2bc54 100644
--- a/radio/aidl/android/hardware/radio/network/CellInfoCdma.aidl
+++ b/radio/aidl/android/hardware/radio/network/CellInfoCdma.aidl
@@ -20,6 +20,7 @@
 import android.hardware.radio.network.CellIdentityCdma;
 import android.hardware.radio.network.EvdoSignalStrength;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable CellInfoCdma {
diff --git a/radio/aidl/android/hardware/radio/network/CellInfoGsm.aidl b/radio/aidl/android/hardware/radio/network/CellInfoGsm.aidl
index cadcd91..db84510 100644
--- a/radio/aidl/android/hardware/radio/network/CellInfoGsm.aidl
+++ b/radio/aidl/android/hardware/radio/network/CellInfoGsm.aidl
@@ -19,6 +19,7 @@
 import android.hardware.radio.network.CellIdentityGsm;
 import android.hardware.radio.network.GsmSignalStrength;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable CellInfoGsm {
diff --git a/radio/aidl/android/hardware/radio/network/CellInfoLte.aidl b/radio/aidl/android/hardware/radio/network/CellInfoLte.aidl
index 443a668..3d9b2f3 100644
--- a/radio/aidl/android/hardware/radio/network/CellInfoLte.aidl
+++ b/radio/aidl/android/hardware/radio/network/CellInfoLte.aidl
@@ -19,6 +19,7 @@
 import android.hardware.radio.network.CellIdentityLte;
 import android.hardware.radio.network.LteSignalStrength;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable CellInfoLte {
diff --git a/radio/aidl/android/hardware/radio/network/CellInfoNr.aidl b/radio/aidl/android/hardware/radio/network/CellInfoNr.aidl
index 6b3d4f4..61591a9 100644
--- a/radio/aidl/android/hardware/radio/network/CellInfoNr.aidl
+++ b/radio/aidl/android/hardware/radio/network/CellInfoNr.aidl
@@ -19,6 +19,7 @@
 import android.hardware.radio.network.CellIdentityNr;
 import android.hardware.radio.network.NrSignalStrength;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable CellInfoNr {
diff --git a/radio/aidl/android/hardware/radio/network/CellInfoRatSpecificInfo.aidl b/radio/aidl/android/hardware/radio/network/CellInfoRatSpecificInfo.aidl
index 76e92a4..10a4a5f 100644
--- a/radio/aidl/android/hardware/radio/network/CellInfoRatSpecificInfo.aidl
+++ b/radio/aidl/android/hardware/radio/network/CellInfoRatSpecificInfo.aidl
@@ -23,6 +23,7 @@
 import android.hardware.radio.network.CellInfoTdscdma;
 import android.hardware.radio.network.CellInfoWcdma;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 union CellInfoRatSpecificInfo {
diff --git a/radio/aidl/android/hardware/radio/network/CellInfoTdscdma.aidl b/radio/aidl/android/hardware/radio/network/CellInfoTdscdma.aidl
index fb9c984..ff0fff3 100644
--- a/radio/aidl/android/hardware/radio/network/CellInfoTdscdma.aidl
+++ b/radio/aidl/android/hardware/radio/network/CellInfoTdscdma.aidl
@@ -19,6 +19,7 @@
 import android.hardware.radio.network.CellIdentityTdscdma;
 import android.hardware.radio.network.TdscdmaSignalStrength;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable CellInfoTdscdma {
diff --git a/radio/aidl/android/hardware/radio/network/CellInfoWcdma.aidl b/radio/aidl/android/hardware/radio/network/CellInfoWcdma.aidl
index 2d6a2e5..c38e306 100644
--- a/radio/aidl/android/hardware/radio/network/CellInfoWcdma.aidl
+++ b/radio/aidl/android/hardware/radio/network/CellInfoWcdma.aidl
@@ -19,6 +19,7 @@
 import android.hardware.radio.network.CellIdentityWcdma;
 import android.hardware.radio.network.WcdmaSignalStrength;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable CellInfoWcdma {
diff --git a/radio/aidl/android/hardware/radio/network/CellularIdentifier.aidl b/radio/aidl/android/hardware/radio/network/CellularIdentifier.aidl
new file mode 100644
index 0000000..6d43920
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/network/CellularIdentifier.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio.network;
+
+/** @hide **/
+@VintfStability
+@Backing(type="int")
+@JavaDerive(toString=true)
+enum CellularIdentifier {
+    UNKNOWN = 0,
+    IMSI = 1,
+    IMEI = 2,
+    SUCI = 3,
+}
diff --git a/radio/aidl/android/hardware/radio/network/CellularIdentifierDisclosure.aidl b/radio/aidl/android/hardware/radio/network/CellularIdentifierDisclosure.aidl
new file mode 100644
index 0000000..52b4116
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/network/CellularIdentifierDisclosure.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio.network;
+
+import android.hardware.radio.network.CellularIdentifier;
+import android.hardware.radio.network.NasProtocolMessage;
+
+/**
+ * A single occurrence of a cellular identifier being sent in the clear pre-authentication. See
+ * IRadioNetwork.setCellularIdentifierTransparencyEnabled for more details.
+ *
+ * @hide
+ */
+@JavaDerive(toString=true)
+@VintfStability
+parcelable CellularIdentifierDisclosure {
+    // The PLMN-ID to which the UE transmitted the cellular identifier
+    String plmn;
+    // The type of cellular identifier that was disclosed
+    CellularIdentifier identifier;
+    // The NAS protocol message within which the cellular identifier was transmitted.
+    NasProtocolMessage protocolMessage;
+    // Whether or not this cellular identifier disclosure is in service of an emergency call.
+    boolean isEmergency;
+}
diff --git a/radio/aidl/android/hardware/radio/network/ClosedSubscriberGroupInfo.aidl b/radio/aidl/android/hardware/radio/network/ClosedSubscriberGroupInfo.aidl
index a2d82d7..d61c1dc 100644
--- a/radio/aidl/android/hardware/radio/network/ClosedSubscriberGroupInfo.aidl
+++ b/radio/aidl/android/hardware/radio/network/ClosedSubscriberGroupInfo.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.network;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable ClosedSubscriberGroupInfo {
diff --git a/radio/aidl/android/hardware/radio/network/ConnectionEvent.aidl b/radio/aidl/android/hardware/radio/network/ConnectionEvent.aidl
new file mode 100644
index 0000000..d5f367f
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/network/ConnectionEvent.aidl
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio.network;
+
+/**
+ * See IRadioNetwork.securityAlgorithmsUpdated for more details.
+ *
+ * @hide
+ */
+@VintfStability
+@Backing(type="int")
+@JavaDerive(toString=true)
+enum ConnectionEvent {
+    // 2G GSM circuit switched
+    CS_SIGNALLING_GSM = 0,
+
+    // 2G GPRS packet services
+    PS_SIGNALLING_GPRS = 1,
+
+    // 3G circuit switched
+    CS_SIGNALLING_3G = 2,
+
+    // 3G packet switched
+    PS_SIGNALLING_3G = 3,
+
+    // 4G LTE packet services
+    NAS_SIGNALLING_LTE = 4,
+    AS_SIGNALLING_LTE = 5,
+
+    // VoLTE
+    // Note: emergency calls could use either normal or SOS (emergency) PDN in practice
+    VOLTE_SIP = 6,
+    VOLTE_SIP_SOS = 7,
+    VOLTE_RTP = 8,
+    VOLTE_RTP_SOS = 9,
+
+    // 5G packet services
+    NAS_SIGNALLING_5G = 10,
+    AS_SIGNALLING_5G = 11,
+
+    // VoNR
+    // Note: emergency calls could use either normal or SOS (emergency) PDN in practice
+    VONR_SIP = 12,
+    VONR_SIP_SOS = 13,
+    VONR_RTP = 14,
+    VONR_RTP_SOS = 15
+}
diff --git a/radio/aidl/android/hardware/radio/network/Domain.aidl b/radio/aidl/android/hardware/radio/network/Domain.aidl
index be5f320..bb169bd 100644
--- a/radio/aidl/android/hardware/radio/network/Domain.aidl
+++ b/radio/aidl/android/hardware/radio/network/Domain.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.network;
 
+/** @hide */
 @VintfStability
 @Backing(type="int")
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/network/EmergencyMode.aidl b/radio/aidl/android/hardware/radio/network/EmergencyMode.aidl
index 25031a9..7a2ed9c 100644
--- a/radio/aidl/android/hardware/radio/network/EmergencyMode.aidl
+++ b/radio/aidl/android/hardware/radio/network/EmergencyMode.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.network;
 
+/** @hide */
 @VintfStability
 @Backing(type="int")
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/network/EmergencyNetworkScanTrigger.aidl b/radio/aidl/android/hardware/radio/network/EmergencyNetworkScanTrigger.aidl
index 0a22e4c..ea4bfeb 100644
--- a/radio/aidl/android/hardware/radio/network/EmergencyNetworkScanTrigger.aidl
+++ b/radio/aidl/android/hardware/radio/network/EmergencyNetworkScanTrigger.aidl
@@ -18,9 +18,10 @@
 import android.hardware.radio.AccessNetwork;
 import android.hardware.radio.network.EmergencyScanType;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
-parcelable EmergencyNetworkScanTrigger{
+parcelable EmergencyNetworkScanTrigger {
     /**
      * Access network to be prioritized during emergency scan. The 1st entry has the highest
      * priority.
diff --git a/radio/aidl/android/hardware/radio/network/EmergencyRegResult.aidl b/radio/aidl/android/hardware/radio/network/EmergencyRegResult.aidl
index 2215149..af2750e 100644
--- a/radio/aidl/android/hardware/radio/network/EmergencyRegResult.aidl
+++ b/radio/aidl/android/hardware/radio/network/EmergencyRegResult.aidl
@@ -19,6 +19,7 @@
 import android.hardware.radio.network.Domain;
 import android.hardware.radio.network.RegState;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable EmergencyRegResult {
diff --git a/radio/aidl/android/hardware/radio/network/EmergencyScanType.aidl b/radio/aidl/android/hardware/radio/network/EmergencyScanType.aidl
index 72c5490..efa6c02 100644
--- a/radio/aidl/android/hardware/radio/network/EmergencyScanType.aidl
+++ b/radio/aidl/android/hardware/radio/network/EmergencyScanType.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.network;
 
+/** @hide */
 @VintfStability
 @Backing(type="int")
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/network/EutranBands.aidl b/radio/aidl/android/hardware/radio/network/EutranBands.aidl
index 72e76e3..969a1b7 100644
--- a/radio/aidl/android/hardware/radio/network/EutranBands.aidl
+++ b/radio/aidl/android/hardware/radio/network/EutranBands.aidl
@@ -18,6 +18,7 @@
 
 /**
  * EUTRAN bands up to V16.4.0
+ * @hide
  */
 @VintfStability
 @Backing(type="int")
diff --git a/radio/aidl/android/hardware/radio/network/EutranRegistrationInfo.aidl b/radio/aidl/android/hardware/radio/network/EutranRegistrationInfo.aidl
index b986944..fb319c1 100644
--- a/radio/aidl/android/hardware/radio/network/EutranRegistrationInfo.aidl
+++ b/radio/aidl/android/hardware/radio/network/EutranRegistrationInfo.aidl
@@ -19,6 +19,7 @@
 import android.hardware.radio.network.LteVopsInfo;
 import android.hardware.radio.network.NrIndicators;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable EutranRegistrationInfo {
diff --git a/radio/aidl/android/hardware/radio/network/EvdoSignalStrength.aidl b/radio/aidl/android/hardware/radio/network/EvdoSignalStrength.aidl
index c3b3898..fc7cc1b 100644
--- a/radio/aidl/android/hardware/radio/network/EvdoSignalStrength.aidl
+++ b/radio/aidl/android/hardware/radio/network/EvdoSignalStrength.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.network;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable EvdoSignalStrength {
diff --git a/radio/aidl/android/hardware/radio/network/GeranBands.aidl b/radio/aidl/android/hardware/radio/network/GeranBands.aidl
index 0e5b7b2..29d829f 100644
--- a/radio/aidl/android/hardware/radio/network/GeranBands.aidl
+++ b/radio/aidl/android/hardware/radio/network/GeranBands.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.network;
 
+/** @hide */
 @VintfStability
 @Backing(type="int")
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/network/GsmSignalStrength.aidl b/radio/aidl/android/hardware/radio/network/GsmSignalStrength.aidl
index 796f80f..d569cf7 100644
--- a/radio/aidl/android/hardware/radio/network/GsmSignalStrength.aidl
+++ b/radio/aidl/android/hardware/radio/network/GsmSignalStrength.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.network;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable GsmSignalStrength {
diff --git a/radio/aidl/android/hardware/radio/network/IRadioNetwork.aidl b/radio/aidl/android/hardware/radio/network/IRadioNetwork.aidl
index f22cdb0..5f26195 100644
--- a/radio/aidl/android/hardware/radio/network/IRadioNetwork.aidl
+++ b/radio/aidl/android/hardware/radio/network/IRadioNetwork.aidl
@@ -32,11 +32,13 @@
 
 /**
  * This interface is used by telephony and telecom to talk to cellular radio for network APIs.
+ * All functions apply to both terrestrial and extraterrestrial (satellite) based cellular networks.
  * All the functions have minimum one parameter:
  * serial: which corresponds to serial no. of request. Serial numbers must only be memorized for the
  * duration of a method call. If clients provide colliding serials (including passing the same
  * serial to different methods), multiple responses (one for each method call) must still be served.
  * setResponseFunctions must work with IRadioNetworkResponse and IRadioNetworkIndication.
+ * @hide
  */
 @VintfStability
 oneway interface IRadioNetwork {
@@ -46,6 +48,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioNetworkResponse.getAllowedNetworkTypesBitmapResponse()
+     *
+     * This is available when android.hardware.telephony.radio.access is defined.
      */
     void getAllowedNetworkTypesBitmap(in int serial);
 
@@ -55,6 +59,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioNetworkResponse.getAvailableBandModesResponse()
+     *
+     * This is available when android.hardware.telephony.radio.access is defined.
      */
     void getAvailableBandModes(in int serial);
 
@@ -64,6 +70,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioNetworkResponse.getAvailableNetworksResponse()
+     *
+     * This is available when android.hardware.telephony.radio.access is defined.
      */
     void getAvailableNetworks(in int serial);
 
@@ -73,6 +81,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioNetworkResponse.getBarringInfoResponse()
+     *
+     * This is available when android.hardware.telephony.radio.access is defined.
      */
     void getBarringInfo(in int serial);
 
@@ -82,6 +92,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioNetworkResponse.getCdmaRoamingPreferenceResponse()
+     *
+     * This is available when android.hardware.telephony.cdma is defined.
      */
     void getCdmaRoamingPreference(in int serial);
 
@@ -94,6 +106,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioNetworkResponse.getCellInfoListResponse()
+     *
+     * This is available when android.hardware.telephony.radio.access is defined.
      */
     void getCellInfoList(in int serial);
 
@@ -103,6 +117,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioNetworkResponse.getDataRegistrationStateResponse()
+     *
+     * This is available when android.hardware.telephony.radio.access is defined.
      */
     void getDataRegistrationState(in int serial);
 
@@ -113,6 +129,8 @@
      *
      * Response function is IRadioNetworkResponse.getImsRegistrationStateResponse()
      *
+     * This is available when android.hardware.telephony.ims is defined.
+     *
      * @deprecated Deprecated starting from Android U.
      */
     void getImsRegistrationState(in int serial);
@@ -123,6 +141,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioNetworkResponse.getNetworkSelectionModeResponse()
+     *
+     * This is available when android.hardware.telephony.radio.access is defined.
      */
     void getNetworkSelectionMode(in int serial);
 
@@ -132,6 +152,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioNetworkResponse.getOperatorResponse()
+     *
+     * This is available when android.hardware.telephony.radio.access is defined.
      */
     void getOperator(in int serial);
 
@@ -141,6 +163,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioNetworkResponse.getSignalStrengthResponse()
+     *
+     * This is available when android.hardware.telephony.radio.access is defined.
      */
     void getSignalStrength(in int serial);
 
@@ -150,6 +174,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioNetworkResponse.getSystemSelectionChannelsResponse()
+     *
+     * This is available when android.hardware.telephony.radio.access is defined.
      */
     void getSystemSelectionChannels(in int serial);
 
@@ -160,6 +186,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioNetworkResponse.getVoiceRadioTechnologyResponse()
+     *
+     * This is available when android.hardware.telephony.radio.access is defined.
      */
     void getVoiceRadioTechnology(in int serial);
 
@@ -169,6 +197,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioNetworkResponse.getVoiceRegistrationStateResponse()
+     *
+     * This is available when android.hardware.telephony.radio.access is defined.
      */
     void getVoiceRegistrationState(in int serial);
 
@@ -178,6 +208,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioNetworkResponse.isNrDualConnectivityEnabledResponse()
+     *
+     * This is available when android.hardware.telephony.radio.access is defined.
      */
     void isNrDualConnectivityEnabled(in int serial);
 
@@ -185,6 +217,8 @@
      * When response type received from a radio indication or radio response is
      * RadioIndicationType:UNSOLICITED_ACK_EXP or RadioResponseType:SOLICITED_ACK_EXP respectively,
      * acknowledge the receipt of those messages by sending responseAcknowledgement().
+     *
+     * This is available when android.hardware.telephony.radio.access is defined.
      */
     void responseAcknowledgement();
 
@@ -197,6 +231,8 @@
      * @param networkTypeBitmap a 32-bit bearer bitmap of RadioAccessFamily
      *
      * Response function is IRadioNetworkResponse.setAllowedNetworkTypesBitmapResponse()
+     *
+     * This is available when android.hardware.telephony.radio.access is defined.
      */
     void setAllowedNetworkTypesBitmap(in int serial, in int networkTypeBitmap);
 
@@ -207,6 +243,8 @@
      * @param mode RadioBandMode
      *
      * Response function is IRadioNetworkResponse.setBandModeResponse()
+     *
+     * This is available when android.hardware.telephony.radio.access is defined.
      */
     void setBandMode(in int serial, in RadioBandMode mode);
 
@@ -219,6 +257,8 @@
      * @param newPassword new password
      *
      * Response function is IRadioNetworkResponse.setBarringPasswordResponse()
+     *
+     * This is available when android.hardware.telephony.radio.access is defined.
      */
     void setBarringPassword(
             in int serial, in String facility, in String oldPassword, in String newPassword);
@@ -230,6 +270,8 @@
      * @param type CdmaRoamingType defined in types.hal
      *
      * Response function is IRadioNetworkResponse.setCdmaRoamingPreferenceResponse()
+     *
+     * This is available when android.hardware.telephony.cdma is defined.
      */
     void setCdmaRoamingPreference(in int serial, in CdmaRoamingType type);
 
@@ -242,6 +284,8 @@
      * @param rate minimum time in milliseconds to indicate time between unsolicited cellInfoList()
      *
      * Response function is IRadioNetworkResponse.setCellInfoListRateResponse()
+     *
+     * This is available when android.hardware.telephony.radio.access is defined.
      */
     void setCellInfoListRate(in int serial, in int rate);
 
@@ -255,6 +299,8 @@
      *        indications are enabled. See IndicationFilter for the definition of each bit.
      *
      * Response function is IRadioNetworkResponse.setIndicationFilterResponse()
+     *
+     * This is available when android.hardware.telephony.radio.access is defined.
      */
     void setIndicationFilter(in int serial, in int indicationFilter);
 
@@ -279,6 +325,8 @@
      * @param accessNetwork The type of network for which to apply these thresholds.
      *
      * Response function is IRadioNetworkResponse.setLinkCapacityReportingCriteriaResponse().
+     *
+     * This is available when android.hardware.telephony.radio.access is defined.
      */
     void setLinkCapacityReportingCriteria(in int serial, in int hysteresisMs,
             in int hysteresisDlKbps, in int hysteresisUlKbps, in int[] thresholdsDownlinkKbps,
@@ -294,6 +342,8 @@
      * @param enable true=updates enabled (+CREG=2), false=updates disabled (+CREG=1)
      *
      * Response function is IRadioNetworkResponse.setLocationUpdatesResponse()
+     *
+     * This is available when android.hardware.telephony.radio.access is defined.
      */
     void setLocationUpdates(in int serial, in boolean enable);
 
@@ -304,6 +354,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioNetworkResponse.setNetworkSelectionModeAutomaticResponse()
+     *
+     * This is available when android.hardware.telephony.radio.access is defined.
      */
     void setNetworkSelectionModeAutomatic(in int serial);
 
@@ -320,6 +372,8 @@
      *        the next best RAN for network registration.
      *
      * Response function is IRadioNetworkResponse.setNetworkSelectionModeManualResponse()
+     *
+     * This is available when android.hardware.telephony.radio.access is defined.
      */
     void setNetworkSelectionModeManual(
             in int serial, in String operatorNumeric, in AccessNetwork ran);
@@ -336,6 +390,8 @@
      *           {NrDualConnectivityState:DISABLE_IMMEDIATE}
      *
      * Response function is IRadioNetworkResponse.setNrDualConnectivityStateResponse()
+     *
+     * This is available when android.hardware.telephony.radio.access is defined.
      */
     void setNrDualConnectivityState(
             in int serial, in NrDualConnectivityState nrDualConnectivityState);
@@ -345,6 +401,8 @@
      *
      * @param radioNetworkResponse Object containing response functions
      * @param radioNetworkIndication Object containing radio indications
+     *
+     * This is available when android.hardware.telephony.radio.access is defined.
      */
     void setResponseFunctions(in IRadioNetworkResponse radioNetworkResponse,
             in IRadioNetworkIndication radioNetworkIndication);
@@ -363,6 +421,8 @@
      *        criteria. See SignalThresholdInfo for details.
      *
      * Response function is IRadioNetworkResponse.setSignalStrengthReportingCriteriaResponse()
+     *
+     * This is available when android.hardware.telephony.radio.access is defined.
      */
     void setSignalStrengthReportingCriteria(
             in int serial, in SignalThresholdInfo[] signalThresholdInfos);
@@ -375,6 +435,8 @@
      * @param enable true = notifications enabled, false = notifications disabled.
      *
      * Response function is IRadioNetworkResponse.setSuppServiceNotificationsResponse()
+     *
+     * This is available when android.hardware.telephony.calling is defined.
      */
     void setSuppServiceNotifications(in int serial, in boolean enable);
 
@@ -388,6 +450,8 @@
      * @param specifiers which bands to scan. Only used if specifyChannels is true.
      *
      * Response function is IRadioNetworkResponse.setSystemSelectionChannelsResponse()
+     *
+     * This is available when android.hardware.telephony.radio.access is defined.
      */
     void setSystemSelectionChannels(
             in int serial, in boolean specifyChannels, in RadioAccessSpecifier[] specifiers);
@@ -399,6 +463,8 @@
      * @param request Defines the radio networks/bands/channels which need to be scanned.
      *
      * Response function is IRadioNetworkResponse.startNetworkScanResponse()
+     *
+     * This is available when android.hardware.telephony.radio.access is defined.
      */
     void startNetworkScan(in int serial, in NetworkScanRequest request);
 
@@ -408,6 +474,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioNetworkResponse.stopNetworkScanResponse()
+     *
+     * This is available when android.hardware.telephony.radio.access is defined.
      */
     void stopNetworkScan(in int serial);
 
@@ -418,6 +486,8 @@
      * @param netPin Network depersonlization code
      *
      * Response function is IRadioNetworkResponse.supplyNetworkDepersonalizationResponse()
+     *
+     * This is available when android.hardware.telephony.radio.access is defined.
      */
     void supplyNetworkDepersonalization(in int serial, in String netPin);
 
@@ -430,6 +500,8 @@
      *
      * @param serial Serial number of request.
      * @param usageSetting the usage setting for the current SIM.
+     *
+     * This is available when android.hardware.telephony is defined.
      */
     oneway void setUsageSetting(in int serial, in UsageSetting usageSetting);
 
@@ -439,6 +511,8 @@
      * <p>Gets the usage setting in accordance with 3gpp 24.301 sec 4.3 and 3gpp 24.501 sec 4.3.
      *
      * @param serial Serial number of request.
+     *
+     * This is available when android.hardware.telephony is defined.
      */
     oneway void getUsageSetting(in int serial);
 
@@ -450,6 +524,8 @@
      * type of service to be scanned.
      *
      * Response function is IRadioEmergencyResponse.setEmergencyModeResponse()
+     *
+     * This is available when android.hardware.telephony.radio.access is defined.
      */
     void setEmergencyMode(int serial, in EmergencyMode emcModeType);
 
@@ -461,6 +537,8 @@
      *                See {@link EmergencyNetworkScanTrigger}.
      *
      * Response function is IRadioEmergencyResponse.triggerEmergencyNetworkScanResponse()
+     *
+     * This is available when android.hardware.telephony.radio.access is defined.
      */
     void triggerEmergencyNetworkScan(int serial, in EmergencyNetworkScanTrigger request);
 
@@ -473,6 +551,8 @@
      *        otherwise the modem shall resume from the last search.
      *
      * Response function is IRadioEmergencyResponse.cancelEmergencyNetworkScan()
+     *
+     * This is available when android.hardware.telephony.radio.access is defined.
      */
     void cancelEmergencyNetworkScan(int serial, boolean resetScan);
 
@@ -482,6 +562,8 @@
      * @param serial Serial number of the request.
      *
      * Response function is IRadioEmergencyResponse.exitEmergencyModeResponse()
+     *
+     * This is available when android.hardware.telephony.radio.access is defined.
      */
     void exitEmergencyMode(in int serial);
 
@@ -512,6 +594,8 @@
      *                Otherwise, false.
      *
      * Response callback is IRadioResponse.setNullCipherAndIntegrityEnabledResponse()
+     *
+     * This is available when android.hardware.telephony.radio.access is defined.
      */
     void setNullCipherAndIntegrityEnabled(in int serial, in boolean enabled);
 
@@ -527,6 +611,8 @@
      * @param serial Serial number of the request.
      *
      * Response callback is IRadioNetworkResponse.isNullCipherAndIntegrityEnabledResponse()
+     *
+     * This is available when android.hardware.telephony.radio.access is defined.
      */
     void isNullCipherAndIntegrityEnabled(in int serial);
 
@@ -536,6 +622,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioNetworkResponse.isN1ModeEnabledResponse()
+     *
+     * This is available when android.hardware.telephony.radio.access is defined.
      */
     void isN1ModeEnabled(in int serial);
 
@@ -553,6 +641,76 @@
      * @param enable {@code true} to enable N1 mode, {@code false} to disable N1 mode.
      *
      * Response function is IRadioNetworkResponse.setN1ModeEnabledResponse()
+     *
+     * This is available when android.hardware.telephony.radio.access is defined.
      */
     void setN1ModeEnabled(in int serial, boolean enable);
+
+    /**
+     * Get whether pre-auth cellular identifier in-the-clear transparency is enabled. If
+     * IRadioNetworkInterface.setCellularIdentifierTransparencyEnabled has been called, this should
+     * return the value of the `enabled` parameter of the last successful call and false if
+     * IRadioNetworkInterface.setCellularIdentifierTransparencyEnabled has not been called yet.
+     *
+     * @param serial Serial number of request
+     *
+     * Response callback is IRadioNetworkResponse.isCellularIdentifierTransparencyEnabledResponse
+     *
+     * This is available when android.hardware.telephony.access is defined.
+     */
+    void isCellularIdentifierTransparencyEnabled(in int serial);
+
+    /**
+     * Enable or disable transparency for in-the-clear cellular identifiers. If the value of enabled
+     * is true, the modem must call IRadioNetworkIndication.cellularIdentifierDisclosed when an
+     * IMSI, IMEI, or unciphered SUCI (in 5G SA) appears in one of the following UE-initiated NAS
+     * messages before a security context is established.
+     *
+     * Note: Cellular identifiers disclosed in uplink messages covered under a NAS Security Context
+     * as well as identifiers disclosed in downlink messages are out of scope.
+     *
+     * This feature applies to 2g, 3g, 4g, and 5g (SA and NSA) messages sent before a security
+     * context is established. In scope message definitions and their associated spec references can
+     * be found in NasProtocolMessage.
+     *
+     * If the value of enabled is false, the modem must not call
+     * IRadioNetworkIndication.sentCellularIdentifierDisclosure again until a subsequent call
+     * re-enables this functionality. The modem may choose to stop tracking cellular identifiers in
+     * the clear during this time.
+     *
+     * @param serial Serial number of request
+     * @param enabled Whether or not to enable sending indications for cellular identifiers in the
+     *         clear
+     *
+     * Response function is IRadioNetworkResponse.setCellularIdentifierTransparencyEnabledResponse
+     *
+     * This is available when android.hardware.telephony.access is defined.
+     */
+    void setCellularIdentifierTransparencyEnabled(in int serial, in boolean enabled);
+
+    /**
+     * Enables or disables security algorithm update reports via indication API
+     * {@link IRadioNetworkIndication.securityAlgorithmsUpdated()}.
+     *
+     * @param serial Serial number of request.
+     * @param enable {@code true} to enable security algorithm update reports, {@code false} to
+     *         disable.
+     *
+     * Response function is IRadioNetworkResponse.setSecurityAlgorithmsUpdatedEnabledResponse()
+     *
+     * This is available when android.hardware.telephony.access is defined.
+     */
+    void setSecurityAlgorithmsUpdatedEnabled(in int serial, boolean enable);
+
+    /**
+     * Checks whether security algorithm update reports are enabled via indication API
+     * {@link IRadioNetworkIndication.securityAlgorithmsUpdated()}.
+     *
+     * @param serial Serial number of request.
+     *
+     * Response function is IRadioNetworkResponse.isSecurityAlgorithmsUpdatedEnabledResponse()
+     *
+     * This is available when android.hardware.telephony.access is defined.
+     */
+    void isSecurityAlgorithmsUpdatedEnabled(in int serial);
 }
diff --git a/radio/aidl/android/hardware/radio/network/IRadioNetworkIndication.aidl b/radio/aidl/android/hardware/radio/network/IRadioNetworkIndication.aidl
index 47d932d..da82b78 100644
--- a/radio/aidl/android/hardware/radio/network/IRadioNetworkIndication.aidl
+++ b/radio/aidl/android/hardware/radio/network/IRadioNetworkIndication.aidl
@@ -21,16 +21,19 @@
 import android.hardware.radio.network.BarringInfo;
 import android.hardware.radio.network.CellIdentity;
 import android.hardware.radio.network.CellInfo;
+import android.hardware.radio.network.CellularIdentifierDisclosure;
+import android.hardware.radio.network.EmergencyRegResult;
 import android.hardware.radio.network.LinkCapacityEstimate;
 import android.hardware.radio.network.NetworkScanResult;
 import android.hardware.radio.network.PhoneRestrictedState;
 import android.hardware.radio.network.PhysicalChannelConfig;
+import android.hardware.radio.network.SecurityAlgorithmUpdate;
 import android.hardware.radio.network.SignalStrength;
 import android.hardware.radio.network.SuppSvcNotification;
-import android.hardware.radio.network.EmergencyRegResult;
 
 /**
  * Interface declaring unsolicited radio indications for network APIs.
+ * @hide
  */
 @VintfStability
 oneway interface IRadioNetworkIndication {
@@ -199,4 +202,58 @@
      * @param result the result of the Emergency Network Scan
      */
     void emergencyNetworkScanResult(in RadioIndicationType type, in EmergencyRegResult result);
+
+    /**
+     * Report a cellular identifier disclosure event. See
+     * IRadioNetwork.setCellularIdnetifierTransparencyEnabled for more details.
+     *
+     * A non-exhaustive list of when this method should be called follows:
+     *
+     * - If a device attempts an IMSI attach to the network.
+     * - If a device includes an IMSI in the IDENTITY_RESPONSE message on the NAS and a security
+     * context has not yet been established.
+     * - If a device includes an IMSI in a DETACH_REQUEST message sent on the NAS and the message is
+     * sent before a security context has been established.
+     * - If a device includes an IMSI in a TRACKING_AREA_UPDATE message sent on the NAS and the
+     * message is sent before a security context has been established.
+     * - If a device uses a 2G network to send a LOCATION_UPDATE_REQUEST message on the NAS that
+     * includes an IMSI or IMEI.
+     * - If a device uses a 2G network to send a AUTHENTICATION_AND_CIPHERING_RESPONSE message on
+     * the NAS and the message includes an IMEISV.
+     *
+     * @param type Type of radio indication
+     * @param disclosure A CellularIdentifierDisclosure as specified by
+     *         IRadioNetwork.setCellularIdentifierTransparencyEnabled.
+     *
+     */
+    void cellularIdentifierDisclosed(
+            in RadioIndicationType type, in CellularIdentifierDisclosure disclosure);
+
+    /*
+     * Indicates that a new ciphering or integrity algorithm was used for a particular voice,
+     * signaling, or data connection for a given PLMN and/or access network. Due to power
+     * concerns, once a connection type has been reported on, follow-up reports about that
+     * connection type are only generated if there is any change to the most-recently reported
+     * encryption or integrity, or if the value of SecurityAlgorithmUpdate#isUnprotectedEmergency
+     * changes. A change only in cell ID should not trigger an update, as the design is intended
+     * to be agnostic to dual connectivity ("secondary serving cells").
+     *
+     * Sample scenario to further clarify "most-recently reported":
+     *
+     * 1. Modem reports user is connected to a null-ciphered 3G network.
+     * 2. User then moves and connects to a well-ciphered 5G network, and modem reports this.
+     * 3. User returns to original location and reconnects to the null-ciphered 3G network. Modem
+     *    should report this as it's different than the most-recently reported data from step (2).
+     *
+     * State is reset when (1) RadioState is transitioned to ON from any other state (e.g. radio
+     * is turned on during device boot, or modem boot), and (2) when CardState is transitioned
+     * to PRESENT from any other state (e.g. when SIM is inserted), or (3) if there is a change in
+     * access network (PLMN).
+     *
+     * @param type Type of radio indication
+     * @param securityAlgorithmUpdate SecurityAlgorithmUpdate encapsulates details of security
+     *         algorithm updates
+     */
+    void securityAlgorithmsUpdated(
+            in RadioIndicationType type, in SecurityAlgorithmUpdate securityAlgorithmUpdate);
 }
diff --git a/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl b/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl
index 457b5b9..d9eea03 100644
--- a/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl
+++ b/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl
@@ -33,6 +33,7 @@
 
 /**
  * Interface declaring response functions to solicited radio requests for network APIs.
+ * @hide
  */
 @VintfStability
 oneway interface IRadioNetworkResponse {
@@ -50,6 +51,8 @@
      * @param networkTypeBitmap a 32-bit bitmap of RadioAccessFamily.
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:OPERATION_NOT_ALLOWED
@@ -66,6 +69,8 @@
      * @param bandModes List of RadioBandMode listing supported modes
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_ARGUMENTS
@@ -83,6 +88,8 @@
      * @param networkInfos List of network operator information as OperatorInfos
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:OPERATION_NOT_ALLOWED
@@ -103,6 +110,8 @@
      * @param barringInfos a vector of barring info for all barring service types
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
@@ -116,6 +125,7 @@
      * @param type CdmaRoamingType
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.cdma is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_ARGUMENTS
@@ -134,6 +144,8 @@
      * @param cellInfo List of current cell information known to radio
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
@@ -145,6 +157,8 @@
      * @param dataRegResponse Current data registration response as defined by RegStateResult
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
@@ -159,6 +173,7 @@
      * @param ratFamily RadioTechnologyFamily. This value is valid only if isRegistered is true.
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.ims is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
@@ -177,6 +192,8 @@
      * @param selection false for automatic selection, true for manual selection
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:NO_MEMORY
@@ -196,6 +213,8 @@
      * @param numeric is 5 or 6 digit numeric code (MCC + MNC) or empty string if unregistered
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:NO_MEMORY
@@ -212,6 +231,8 @@
      * @param signalStrength Current signal strength
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
@@ -223,6 +244,8 @@
      * @param specifiers List of RadioAccessSpecifiers that are scanned.
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
@@ -236,6 +259,8 @@
      * @param rat Current voice RAT
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
@@ -250,6 +275,8 @@
      * @param voiceRegResponse Current Voice registration response as defined by RegStateResult
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
@@ -263,6 +290,8 @@
      *        else false.
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
@@ -273,6 +302,8 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:OPERATION_NOT_ALLOWED
@@ -288,6 +319,8 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:OPERATION_NOT_ALLOWED
@@ -305,6 +338,8 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:SS_MODIFIED_TO_DIAL
@@ -325,6 +360,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.cdma is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:NO_MEMORY
@@ -343,6 +379,8 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:NO_MEMORY
@@ -358,6 +396,8 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:INVALID_ARGUMENTS
      *   RadioError:RADIO_NOT_AVAILABLE
@@ -370,6 +410,8 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:INVALID_ARGUMENTS
      *   RadioError:RADIO_NOT_AVAILABLE
@@ -381,6 +423,8 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:NO_MEMORY
@@ -398,6 +442,8 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:ILLEGAL_SIM_OR_ME
@@ -419,6 +465,8 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:ILLEGAL_SIM_OR_ME
@@ -441,6 +489,8 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
@@ -452,6 +502,8 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:INVALID_ARGUMENTS
      *   RadioError:RADIO_NOT_AVAILABLE
@@ -462,6 +514,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.calling is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_ARGUMENTS
@@ -480,6 +533,8 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
@@ -491,6 +546,8 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:DEVICE_IN_USE
@@ -504,6 +561,8 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:INTERNAL_ERR
      *   RadioError:MODEM_ERR
@@ -515,6 +574,8 @@
      * @param remainingRetries Number of retries remaining, must be equal to -1 if unknown.
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:PASSWORD_INCORRECT (code is invalid)
@@ -534,6 +595,7 @@
      * @param info Response info struct containing response type, serial no. and error.
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_STATE
@@ -548,6 +610,7 @@
      * @param usageSetting the usage setting for the current SIM.
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_STATE
@@ -564,6 +627,8 @@
      * @param regState the current registration state of the modem.
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:RADIO_NOT_AVAILABLE
@@ -579,6 +644,8 @@
      * @param info Response info struct containing response type, serial no. and error.
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:RADIO_NOT_AVAILABLE
@@ -594,6 +661,8 @@
      * @param info Response info struct containing response type, serial no. and error.
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:RADIO_NOT_AVAILABLE
@@ -608,6 +677,8 @@
      * @param info Response info struct containing response type, serial no. and error.
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:REQUEST_NOT_SUPPORTED
      *   RadioError:RADIO_NOT_AVAILABLE
@@ -619,10 +690,11 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:MODEM_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      */
     void setNullCipherAndIntegrityEnabledResponse(in RadioResponseInfo info);
 
@@ -631,10 +703,11 @@
      * @param enabled the last known state of null ciphering and integrity algorithms
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:MODEM_ERR
-     *   RadioError:REQUEST_NOT_SUPPORTED
      */
     void isNullCipherAndIntegrityEnabledResponse(in RadioResponseInfo info, in boolean isEnabled);
 
@@ -646,6 +719,8 @@
      * @param isEnabled Indicates whether N1 mode is enabled or not.
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
@@ -660,6 +735,8 @@
      * @param info Response info struct containing response type, serial no. and error.
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
@@ -667,4 +744,66 @@
      *   RadioError:INVALID_STATE
      */
     void setN1ModeEnabledResponse(in RadioResponseInfo info);
+
+    /**
+     * Response of isCellularIdentifierTransparencyEnabled.
+     *
+     * @param info Response info struct containing response type, serial no. and error.
+     * @param isEnabled Indicates whether cellular identifier transparency is enabled or not.
+     *
+     * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:INTERNAL_ERR
+     */
+    void isCellularIdentifierTransparencyEnabledResponse(
+            in RadioResponseInfo info, boolean isEnabled);
+
+    /**
+     * Response of setCellularIdentifierTransparencyEnabled.
+     *
+     * @param info Response info struct containing response type, serial no. and error.
+     *
+     * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:INTERNAL_ERR
+     *   RadioError:INVALID_STATE
+     */
+    void setCellularIdentifierTransparencyEnabledResponse(in RadioResponseInfo info);
+
+    /**
+     * Response of setSecurityAlgorithmsUpdatedEnabled.
+     *
+     * @param info Response info struct containing response type, serial no. and error.
+     *
+     * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:INTERNAL_ERR
+     *   RadioError:INVALID_STATE
+     */
+    void setSecurityAlgorithmsUpdatedEnabledResponse(in RadioResponseInfo info);
+
+    /**
+     * Response of isSecurityAlgorithmsUpdatedEnabled.
+     *
+     * @param info Response info struct containing response type, serial no. and error.
+     * @param isEnabled Indicates whether cellular ciphering transparency is enabled or not.
+     *
+     * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.radio.access is not
+     *                                    defined
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:INTERNAL_ERR
+     */
+    void isSecurityAlgorithmsUpdatedEnabledResponse(
+            in RadioResponseInfo info, in boolean isEnabled);
 }
diff --git a/radio/aidl/android/hardware/radio/network/IndicationFilter.aidl b/radio/aidl/android/hardware/radio/network/IndicationFilter.aidl
index 9cab28d..7b95273 100644
--- a/radio/aidl/android/hardware/radio/network/IndicationFilter.aidl
+++ b/radio/aidl/android/hardware/radio/network/IndicationFilter.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.network;
 
+/** @hide */
 @VintfStability
 @Backing(type="int")
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/network/LceDataInfo.aidl b/radio/aidl/android/hardware/radio/network/LceDataInfo.aidl
index fdbdc2b..c855b18 100644
--- a/radio/aidl/android/hardware/radio/network/LceDataInfo.aidl
+++ b/radio/aidl/android/hardware/radio/network/LceDataInfo.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.network;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable LceDataInfo {
diff --git a/radio/aidl/android/hardware/radio/network/LinkCapacityEstimate.aidl b/radio/aidl/android/hardware/radio/network/LinkCapacityEstimate.aidl
index 6461719..0aea27c 100644
--- a/radio/aidl/android/hardware/radio/network/LinkCapacityEstimate.aidl
+++ b/radio/aidl/android/hardware/radio/network/LinkCapacityEstimate.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.network;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable LinkCapacityEstimate {
diff --git a/radio/aidl/android/hardware/radio/network/LteSignalStrength.aidl b/radio/aidl/android/hardware/radio/network/LteSignalStrength.aidl
index 2d97c45..21d3ec7 100644
--- a/radio/aidl/android/hardware/radio/network/LteSignalStrength.aidl
+++ b/radio/aidl/android/hardware/radio/network/LteSignalStrength.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.network;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable LteSignalStrength {
diff --git a/radio/aidl/android/hardware/radio/network/LteVopsInfo.aidl b/radio/aidl/android/hardware/radio/network/LteVopsInfo.aidl
index fb3b986..a320acb 100644
--- a/radio/aidl/android/hardware/radio/network/LteVopsInfo.aidl
+++ b/radio/aidl/android/hardware/radio/network/LteVopsInfo.aidl
@@ -19,6 +19,7 @@
 /**
  * Type to define the LTE specific network capabilities for voice over PS including emergency and
  * normal voice calls.
+ * @hide
  */
 @VintfStability
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/network/NasProtocolMessage.aidl b/radio/aidl/android/hardware/radio/network/NasProtocolMessage.aidl
new file mode 100644
index 0000000..5a23661
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/network/NasProtocolMessage.aidl
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio.network;
+
+/**
+ * Each enum value represents a message type on the Non-Access Stratum (NAS). The relevant cellular
+ * generation is noted for each message type. Sample spec references are provided, but generally
+ * only reference one network generation's spec.
+ *
+ * @hide
+ */
+@VintfStability
+@Backing(type="int")
+@JavaDerive(toString=true)
+enum NasProtocolMessage {
+    UNKNOWN = 0,
+    // Sample Reference: 3GPP TS 24.301 8.2.4
+    // Applies to 2g, 3g, and 4g networks
+    ATTACH_REQUEST = 1,
+    // Sample Reference: 3GPP TS 24.301 8.2.19
+    // Applies to 2g, 3g, 4g, and 5g networks
+    IDENTITY_RESPONSE = 2,
+    // Sample Reference: 3GPP TS 24.301 8.2.11
+    // Applies to 2g, 3g, and 4g networks
+    DETACH_REQUEST = 3,
+    // Sample Reference: 3GPP TS 24.301 8.2.29
+    // Note: that per the spec, only temporary IDs should be sent
+    // in the TAU Request, but since the EPS Mobile Identity field
+    // supports IMSIs, this is included as an extra safety measure
+    // to combat implementation bugs.
+    // Applies to 4g and 5g networks
+    TRACKING_AREA_UPDATE_REQUEST = 4,
+    // Sample Reference: 3GPP TS 24.008 4.4.3
+    // Applies to 2g and 3g networks
+    LOCATION_UPDATE_REQUEST = 5,
+    // Reference: 3GPP TS 24.008 4.7.7.1
+    // Applies to 2g and 3g networks
+    AUTHENTICATION_AND_CIPHERING_RESPONSE = 6,
+    // Reference: 3GPP TS 24.501 8.2.6
+    // Applies to 5g networks
+    REGISTRATION_REQUEST = 7,
+    // Reference: 3GPP TS 24.501 8.2.12
+    // Applies to 5g networks
+    DEREGISTRATION_REQUEST = 8,
+    // Reference: 3GPP TS 24.008 9.2.4
+    // Applies to 2g and 3g networks
+    CM_REESTABLISHMENT_REQUEST = 9,
+    // Reference: 3GPP TS 24.008 9.2.9
+    // Applies to 2g and 3g networks
+    CM_SERVICE_REQUEST = 10,
+    // Reference: 3GPP TS 24.008 9.2.14
+    // Applies to 2g and 3g networks. Used for circuit-switched detach.
+    IMSI_DETACH_INDICATION = 11
+}
diff --git a/radio/aidl/android/hardware/radio/network/NetworkScanRequest.aidl b/radio/aidl/android/hardware/radio/network/NetworkScanRequest.aidl
index ae173c7..37f2cf1 100644
--- a/radio/aidl/android/hardware/radio/network/NetworkScanRequest.aidl
+++ b/radio/aidl/android/hardware/radio/network/NetworkScanRequest.aidl
@@ -18,6 +18,7 @@
 
 import android.hardware.radio.network.RadioAccessSpecifier;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable NetworkScanRequest {
diff --git a/radio/aidl/android/hardware/radio/network/NetworkScanResult.aidl b/radio/aidl/android/hardware/radio/network/NetworkScanResult.aidl
index 6d83f74..4465046 100644
--- a/radio/aidl/android/hardware/radio/network/NetworkScanResult.aidl
+++ b/radio/aidl/android/hardware/radio/network/NetworkScanResult.aidl
@@ -19,6 +19,7 @@
 import android.hardware.radio.RadioError;
 import android.hardware.radio.network.CellInfo;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable NetworkScanResult {
diff --git a/radio/aidl/android/hardware/radio/network/NgranBands.aidl b/radio/aidl/android/hardware/radio/network/NgranBands.aidl
index 53c7a3d..a87a0d1 100644
--- a/radio/aidl/android/hardware/radio/network/NgranBands.aidl
+++ b/radio/aidl/android/hardware/radio/network/NgranBands.aidl
@@ -18,6 +18,7 @@
 
 /**
  * NGRAN bands up to V16.5.0
+ * @hide
  */
 @VintfStability
 @Backing(type="int")
diff --git a/radio/aidl/android/hardware/radio/network/NrDualConnectivityState.aidl b/radio/aidl/android/hardware/radio/network/NrDualConnectivityState.aidl
index e293dff..00e19fe 100644
--- a/radio/aidl/android/hardware/radio/network/NrDualConnectivityState.aidl
+++ b/radio/aidl/android/hardware/radio/network/NrDualConnectivityState.aidl
@@ -18,6 +18,7 @@
 
 /**
  * NR Dual connectivity state
+ * @hide
  */
 @VintfStability
 @Backing(type="byte")
diff --git a/radio/aidl/android/hardware/radio/network/NrIndicators.aidl b/radio/aidl/android/hardware/radio/network/NrIndicators.aidl
index 32cc964..214272c 100644
--- a/radio/aidl/android/hardware/radio/network/NrIndicators.aidl
+++ b/radio/aidl/android/hardware/radio/network/NrIndicators.aidl
@@ -18,6 +18,7 @@
 
 /**
  * The parameters of NR 5G Non-Standalone.
+ * @hide
  */
 @VintfStability
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/network/NrSignalStrength.aidl b/radio/aidl/android/hardware/radio/network/NrSignalStrength.aidl
index 30ae067..65daf36 100644
--- a/radio/aidl/android/hardware/radio/network/NrSignalStrength.aidl
+++ b/radio/aidl/android/hardware/radio/network/NrSignalStrength.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.network;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable NrSignalStrength {
diff --git a/radio/aidl/android/hardware/radio/network/NrVopsInfo.aidl b/radio/aidl/android/hardware/radio/network/NrVopsInfo.aidl
index 197f401..71961a3 100644
--- a/radio/aidl/android/hardware/radio/network/NrVopsInfo.aidl
+++ b/radio/aidl/android/hardware/radio/network/NrVopsInfo.aidl
@@ -19,6 +19,7 @@
 /**
  * Type to define the NR specific network capabilities for voice over PS including emergency and
  * normal voice calls.
+ * @hide
  */
 @VintfStability
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/network/OperatorInfo.aidl b/radio/aidl/android/hardware/radio/network/OperatorInfo.aidl
index 56f4dca..36dbadf 100644
--- a/radio/aidl/android/hardware/radio/network/OperatorInfo.aidl
+++ b/radio/aidl/android/hardware/radio/network/OperatorInfo.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.network;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable OperatorInfo {
diff --git a/radio/aidl/android/hardware/radio/network/PhoneRestrictedState.aidl b/radio/aidl/android/hardware/radio/network/PhoneRestrictedState.aidl
index 23ae3b1..de3527c 100644
--- a/radio/aidl/android/hardware/radio/network/PhoneRestrictedState.aidl
+++ b/radio/aidl/android/hardware/radio/network/PhoneRestrictedState.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.network;
 
+/** @hide */
 @VintfStability
 @Backing(type="int")
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/network/PhysicalChannelConfig.aidl b/radio/aidl/android/hardware/radio/network/PhysicalChannelConfig.aidl
index 9996953..ecb9463 100644
--- a/radio/aidl/android/hardware/radio/network/PhysicalChannelConfig.aidl
+++ b/radio/aidl/android/hardware/radio/network/PhysicalChannelConfig.aidl
@@ -20,6 +20,7 @@
 import android.hardware.radio.network.CellConnectionStatus;
 import android.hardware.radio.network.PhysicalChannelConfigBand;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable PhysicalChannelConfig {
diff --git a/radio/aidl/android/hardware/radio/network/PhysicalChannelConfigBand.aidl b/radio/aidl/android/hardware/radio/network/PhysicalChannelConfigBand.aidl
index 707a032..aa0e9b2 100644
--- a/radio/aidl/android/hardware/radio/network/PhysicalChannelConfigBand.aidl
+++ b/radio/aidl/android/hardware/radio/network/PhysicalChannelConfigBand.aidl
@@ -21,6 +21,7 @@
 import android.hardware.radio.network.NgranBands;
 import android.hardware.radio.network.UtranBands;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 union PhysicalChannelConfigBand {
diff --git a/radio/aidl/android/hardware/radio/network/RadioAccessSpecifier.aidl b/radio/aidl/android/hardware/radio/network/RadioAccessSpecifier.aidl
index 8504248..b3cee47 100644
--- a/radio/aidl/android/hardware/radio/network/RadioAccessSpecifier.aidl
+++ b/radio/aidl/android/hardware/radio/network/RadioAccessSpecifier.aidl
@@ -19,6 +19,7 @@
 import android.hardware.radio.AccessNetwork;
 import android.hardware.radio.network.RadioAccessSpecifierBands;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable RadioAccessSpecifier {
diff --git a/radio/aidl/android/hardware/radio/network/RadioAccessSpecifierBands.aidl b/radio/aidl/android/hardware/radio/network/RadioAccessSpecifierBands.aidl
index 38afee5..4bf694a 100644
--- a/radio/aidl/android/hardware/radio/network/RadioAccessSpecifierBands.aidl
+++ b/radio/aidl/android/hardware/radio/network/RadioAccessSpecifierBands.aidl
@@ -21,6 +21,7 @@
 import android.hardware.radio.network.NgranBands;
 import android.hardware.radio.network.UtranBands;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 union RadioAccessSpecifierBands {
diff --git a/radio/aidl/android/hardware/radio/network/RadioBandMode.aidl b/radio/aidl/android/hardware/radio/network/RadioBandMode.aidl
index 45c4a51..364a562 100644
--- a/radio/aidl/android/hardware/radio/network/RadioBandMode.aidl
+++ b/radio/aidl/android/hardware/radio/network/RadioBandMode.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.network;
 
+/** @hide */
 @VintfStability
 @Backing(type="int")
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/network/RegState.aidl b/radio/aidl/android/hardware/radio/network/RegState.aidl
index bdba4c4..de2d5f6 100644
--- a/radio/aidl/android/hardware/radio/network/RegState.aidl
+++ b/radio/aidl/android/hardware/radio/network/RegState.aidl
@@ -20,6 +20,7 @@
  * Please note that registration state UNKNOWN is treated as "out of service" in Android telephony.
  * Registration state REG_DENIED must be returned if Location Update Reject (with cause 17 - Network
  * Failure) is received repeatedly from the network, to facilitate "managed roaming".
+ * @hide
  */
 @VintfStability
 @Backing(type="int")
diff --git a/radio/aidl/android/hardware/radio/network/RegStateResult.aidl b/radio/aidl/android/hardware/radio/network/RegStateResult.aidl
index f1d2972..57a73c0 100644
--- a/radio/aidl/android/hardware/radio/network/RegStateResult.aidl
+++ b/radio/aidl/android/hardware/radio/network/RegStateResult.aidl
@@ -22,6 +22,7 @@
 import android.hardware.radio.network.RegState;
 import android.hardware.radio.network.RegistrationFailCause;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable RegStateResult {
diff --git a/radio/aidl/android/hardware/radio/network/RegistrationFailCause.aidl b/radio/aidl/android/hardware/radio/network/RegistrationFailCause.aidl
index 9549f2e..11fd8c5 100644
--- a/radio/aidl/android/hardware/radio/network/RegistrationFailCause.aidl
+++ b/radio/aidl/android/hardware/radio/network/RegistrationFailCause.aidl
@@ -19,6 +19,7 @@
 /**
  * Call fail causes for Circuit-switched service enumerated in 3GPP TS 24.008, 10.5.3.6 and
  * 10.5.147. Additional detail is available in 3GPP TS 24.008 Annex G.
+ * @hide
  */
 @VintfStability
 @Backing(type="int")
@@ -85,10 +86,15 @@
      */
     NO_SUITABLE_CELLS = 15,
     /**
-     * 16 - MSC temporarily not reachable
+     * @deprecated MSC_TEMPORARILY_NOT_REACHABLE value is wrong and should not be used.
+     * Use MSC_TEMP_NOT_REACHABLE instead.
      */
     MSC_TEMPORARILY_NOT_REACHABLE = 15,
     /**
+     * 16 - MSC temporarily not reachable
+     */
+    MSC_TEMP_NOT_REACHABLE = 16,
+    /**
      * 17 - Network Failure
      */
     NETWORK_FAILURE = 17,
diff --git a/radio/aidl/android/hardware/radio/network/SecurityAlgorithm.aidl b/radio/aidl/android/hardware/radio/network/SecurityAlgorithm.aidl
new file mode 100644
index 0000000..01f7327
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/network/SecurityAlgorithm.aidl
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio.network;
+
+/**
+ * See IRadioNetwork.securityAlgorithmsUpdated for more details.
+ *
+ * @hide
+ */
+@VintfStability
+@Backing(type="int")
+@JavaDerive(toString=true)
+enum SecurityAlgorithm {
+    // GSM CS services (3GPP TS 43.020)
+    A50 = 0,
+    A51 = 1,
+    A52 = 2,
+    A53 = 3,
+    A54 = 4,
+
+    // GPRS PS services (3GPP TS 43.020)
+    // These also refer to the respective integrity counterparts.
+    // E.g. GEA1 = GIA1
+    GEA0 = 14,
+    GEA1 = 15,
+    GEA2 = 16,
+    GEA3 = 17,
+    GEA4 = 18,
+    GEA5 = 19,
+
+    // 3G PS/CS services (3GPP TS 33.102)
+    UEA0 = 29,
+    UEA1 = 30,
+    UEA2 = 31,
+
+    // 4G PS services & 5G NSA (3GPP TS 33.401)
+    EEA0 = 41,
+    EEA1 = 42,
+    EEA2 = 43,
+    EEA3 = 44,
+
+    // 5G PS services (3GPP TS 33.401 for 5G NSA and 3GPP TS 33.501 for 5G SA)
+    NEA0 = 55,
+    NEA1 = 56,
+    NEA2 = 57,
+    NEA3 = 58,
+
+    // IMS and SIP layer security (See 3GPP TS 33.203)
+    // No IPsec config
+    SIP_NO_IPSEC_CONFIG = 66,
+    IMS_NULL = 67,
+
+    // Has IPsec config
+    SIP_NULL = 68,
+    AES_GCM = 69,
+    AES_GMAC = 70,
+    AES_CBC = 71,
+    DES_EDE3_CBC = 72,
+    AES_EDE3_CBC = 73,
+    HMAC_SHA1_96 = 74,
+    HMAC_MD5_96 = 75,
+
+    // RTP and SRTP (see 3GPP TS 33.328)
+    // When SRTP is not being used
+    RTP = 85,
+    // When SRTP is available and used
+    SRTP_NULL = 86,
+    SRTP_AES_COUNTER = 87,
+    SRTP_AES_F8 = 88,
+    SRTP_HMAC_SHA1 = 89,
+
+    // ePDG (3GPP TS 33.402) (reserved for future use)
+    ENCR_AES_GCM_16 = 99,
+    ENCR_AES_CBC = 100,
+    AUTH_HMAC_SHA2_256_128 = 101,
+
+    /** Unknown */
+    UNKNOWN = 113,
+    OTHER = 114,
+
+    /** For proprietary algorithms */
+    ORYX = 124,
+}
diff --git a/radio/aidl/android/hardware/radio/network/SecurityAlgorithmUpdate.aidl b/radio/aidl/android/hardware/radio/network/SecurityAlgorithmUpdate.aidl
new file mode 100644
index 0000000..e945d3b
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/network/SecurityAlgorithmUpdate.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio.network;
+
+import android.hardware.radio.network.ConnectionEvent;
+import android.hardware.radio.network.SecurityAlgorithm;
+
+/**
+ * A single occurrence capturing a notable change to previously reported
+ * cryptography algorithms for a given network and network event.
+ *
+ * @hide
+ */
+@JavaDerive(toString=true)
+@VintfStability
+parcelable SecurityAlgorithmUpdate {
+    /**
+     * Type of connection event which is being reported on
+     */
+    ConnectionEvent connectionEvent;
+    /**
+     * Encryption algorithm which was used
+     */
+    SecurityAlgorithm encryption;
+    /**
+     * Integrity algorithm which was used
+     */
+    SecurityAlgorithm integrity;
+    /**
+     * Whether or not this connection event is associated with an
+     * unauthenticated / unencrypted emergency session
+     */
+    boolean isUnprotectedEmergency;
+}
diff --git a/radio/aidl/android/hardware/radio/network/SignalStrength.aidl b/radio/aidl/android/hardware/radio/network/SignalStrength.aidl
index ddb4582..5fed522 100644
--- a/radio/aidl/android/hardware/radio/network/SignalStrength.aidl
+++ b/radio/aidl/android/hardware/radio/network/SignalStrength.aidl
@@ -24,6 +24,7 @@
 import android.hardware.radio.network.TdscdmaSignalStrength;
 import android.hardware.radio.network.WcdmaSignalStrength;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable SignalStrength {
diff --git a/radio/aidl/android/hardware/radio/network/SignalThresholdInfo.aidl b/radio/aidl/android/hardware/radio/network/SignalThresholdInfo.aidl
index 0a8e9ce..e440a64 100644
--- a/radio/aidl/android/hardware/radio/network/SignalThresholdInfo.aidl
+++ b/radio/aidl/android/hardware/radio/network/SignalThresholdInfo.aidl
@@ -20,6 +20,7 @@
 
 /**
  * Contains the threshold values of each signal measurement type.
+ * @hide
  */
 @VintfStability
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/network/SuppSvcNotification.aidl b/radio/aidl/android/hardware/radio/network/SuppSvcNotification.aidl
index d4229e1..3b8c8b2 100644
--- a/radio/aidl/android/hardware/radio/network/SuppSvcNotification.aidl
+++ b/radio/aidl/android/hardware/radio/network/SuppSvcNotification.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.network;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable SuppSvcNotification {
diff --git a/radio/aidl/android/hardware/radio/network/TdscdmaSignalStrength.aidl b/radio/aidl/android/hardware/radio/network/TdscdmaSignalStrength.aidl
index ec9ca6b..4afdd0f 100644
--- a/radio/aidl/android/hardware/radio/network/TdscdmaSignalStrength.aidl
+++ b/radio/aidl/android/hardware/radio/network/TdscdmaSignalStrength.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.network;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable TdscdmaSignalStrength {
diff --git a/radio/aidl/android/hardware/radio/network/UsageSetting.aidl b/radio/aidl/android/hardware/radio/network/UsageSetting.aidl
index 5a714a4..0b6cfdd 100644
--- a/radio/aidl/android/hardware/radio/network/UsageSetting.aidl
+++ b/radio/aidl/android/hardware/radio/network/UsageSetting.aidl
@@ -21,6 +21,7 @@
  *
  * <p>Also refer to "UE's usage setting" as defined in 3gpp 24.301 section 3.1 and 3gpp 23.221
  * Annex A.
+ * @hide
  */
 @VintfStability
 @Backing(type="int")
diff --git a/radio/aidl/android/hardware/radio/network/UtranBands.aidl b/radio/aidl/android/hardware/radio/network/UtranBands.aidl
index a0fd427..8478b66 100644
--- a/radio/aidl/android/hardware/radio/network/UtranBands.aidl
+++ b/radio/aidl/android/hardware/radio/network/UtranBands.aidl
@@ -18,6 +18,7 @@
 
 /**
  * UTRAN bands up to V15.0.0
+ * @hide
  */
 @VintfStability
 @Backing(type="int")
diff --git a/radio/aidl/android/hardware/radio/network/WcdmaSignalStrength.aidl b/radio/aidl/android/hardware/radio/network/WcdmaSignalStrength.aidl
index 7595c05..ace89ed 100644
--- a/radio/aidl/android/hardware/radio/network/WcdmaSignalStrength.aidl
+++ b/radio/aidl/android/hardware/radio/network/WcdmaSignalStrength.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.network;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable WcdmaSignalStrength {
diff --git a/radio/aidl/android/hardware/radio/sap/ISap.aidl b/radio/aidl/android/hardware/radio/sap/ISap.aidl
index 552e602..04eee43 100644
--- a/radio/aidl/android/hardware/radio/sap/ISap.aidl
+++ b/radio/aidl/android/hardware/radio/sap/ISap.aidl
@@ -28,6 +28,8 @@
      * @param serial Id to match req-resp. Resp must include same serial.
      * @param type APDU command type
      * @param command CommandAPDU/CommandAPDU7816 parameter depending on type
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void apduReq(in int serial, in SapApduType type, in byte[] command);
 
@@ -36,6 +38,8 @@
      *
      * @param serial Id to match req-resp. Resp must include same serial.
      * @param maxMsgSizeBytes MaxMsgSize to be used for SIM Access Profile connection
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void connectReq(in int serial, in int maxMsgSizeBytes);
 
@@ -43,6 +47,8 @@
      * DISCONNECT_REQ from SAP 1.1 spec 5.1.3
      *
      * @param serial Id to match req-resp. Resp must include same serial.
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void disconnectReq(in int serial);
 
@@ -51,6 +57,8 @@
      *
      * @param serial Id to match req-resp. Resp must include same serial.
      * @param powerOn true for on, false for off
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void powerReq(in int serial, in boolean powerOn);
 
@@ -58,6 +66,8 @@
      * RESET_SIM_REQ from SAP 1.1 spec 5.1.14
      *
      * @param serial Id to match req-resp. Resp must include same serial.
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void resetSimReq(in int serial);
 
@@ -65,6 +75,8 @@
      * Set callback that has response and unsolicited indication functions
      *
      * @param sapCallback Object containing response and unosolicited indication callbacks
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void setCallback(in ISapCallback sapCallback);
 
@@ -73,6 +85,8 @@
      *
      * @param serial Id to match req-resp. Resp must include same serial.
      * @param transferProtocol Transport Protocol
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void setTransferProtocolReq(in int serial, in SapTransferProtocol transferProtocol);
 
@@ -80,6 +94,8 @@
      * TRANSFER_ATR_REQ from SAP 1.1 spec 5.1.8
      *
      * @param serial Id to match req-resp. Resp must include same serial.
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void transferAtrReq(in int serial);
 
@@ -87,6 +103,8 @@
      * TRANSFER_CARD_READER_STATUS_REQ from SAP 1.1 spec 5.1.17
      *
      * @param serial Id to match req-resp. Resp must include same serial.
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void transferCardReaderStatusReq(in int serial);
 }
diff --git a/radio/aidl/android/hardware/radio/sap/ISapCallback.aidl b/radio/aidl/android/hardware/radio/sap/ISapCallback.aidl
index 34111eb..37a94b8 100644
--- a/radio/aidl/android/hardware/radio/sap/ISapCallback.aidl
+++ b/radio/aidl/android/hardware/radio/sap/ISapCallback.aidl
@@ -29,6 +29,8 @@
      * @param serial Id to match req-resp. Value must match the one in req.
      * @param resultCode ResultCode to indicate if command was processed correctly
      *        Possible values:
+     *        SapResultCode:NOT_SUPPORTED  when android.hardware.telephony.subscription is not
+     *                                     defined
      *        SapResultCode:SUCCESS,
      *        SapResultCode:GENERIC_FAILURE,
      *        SapResultCode:CARD_NOT_ACCESSSIBLE,
@@ -77,6 +79,8 @@
      * @param serial Id to match req-resp. Value must match the one in req.
      * @param resultCode ResultCode to indicate if command was processed correctly
      *        Possible values:
+     *        SapResultCode:NOT_SUPPORTED  when android.hardware.telephony.subscription is not
+     *                                     defined
      *        SapResultCode:SUCCESS,
      *        SapResultCode:GENERIC_FAILURE,
      *        SapResultCode:CARD_NOT_ACCESSSIBLE, (possible only for power on req)
@@ -92,6 +96,8 @@
      * @param serial Id to match req-resp. Value must match the one in req.
      * @param resultCode ResultCode to indicate if command was processed correctly
      *        Possible values:
+     *        SapResultCode:NOT_SUPPORTED  when android.hardware.telephony.subscription is not
+     *                                     defined
      *        SapResultCode:SUCCESS,
      *        SapResultCode:GENERIC_FAILURE,
      *        SapResultCode:CARD_NOT_ACCESSSIBLE,
@@ -114,6 +120,8 @@
      * @param serial Id to match req-resp. Value must match the one in req.
      * @param resultCode ResultCode to indicate if command was processed correctly
      *        Possible values:
+     *        SapResultCode:NOT_SUPPORTED  when android.hardware.telephony.subscription is not
+     *                                     defined
      *        SapResultCode:SUCCESS,
      *        SapResultCode:GENERIC_FAILURE,
      *        SapResultCode:CARD_ALREADY_POWERED_OFF,
@@ -130,6 +138,8 @@
      * @param serial Id to match req-resp. Value must match the one in req.
      * @param resultCode ResultCode to indicate if command was processed correctly
      *        Possible values:
+     *        SapResultCode:NOT_SUPPORTED  when android.hardware.telephony.subscription is not
+     *                                     defined
      *        SapResultCode:SUCCESS,
      *        SapResultCode:GENERIC_FAILURE
      *        SapResultCode:DATA_NOT_AVAILABLE
@@ -145,6 +155,8 @@
      * @param serial Id to match req-resp. Value must match the one in req.
      * @param resultCode ResultCode to indicate if command was processed correctly
      *        Possible values:
+     *        SapResultCode:NOT_SUPPORTED  when android.hardware.telephony.subscription is not
+     *                                     defined
      *        SapResultCode:SUCCESS
      *        SapResultCode:NOT_SUPPORTED
      */
diff --git a/radio/aidl/android/hardware/radio/sim/AppStatus.aidl b/radio/aidl/android/hardware/radio/sim/AppStatus.aidl
index c072f6a..7fe8e40 100644
--- a/radio/aidl/android/hardware/radio/sim/AppStatus.aidl
+++ b/radio/aidl/android/hardware/radio/sim/AppStatus.aidl
@@ -19,6 +19,7 @@
 import android.hardware.radio.sim.PersoSubstate;
 import android.hardware.radio.sim.PinState;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable AppStatus {
diff --git a/radio/aidl/android/hardware/radio/sim/CardPowerState.aidl b/radio/aidl/android/hardware/radio/sim/CardPowerState.aidl
index f8b5922..2598dcb 100644
--- a/radio/aidl/android/hardware/radio/sim/CardPowerState.aidl
+++ b/radio/aidl/android/hardware/radio/sim/CardPowerState.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.sim;
 
+/** @hide */
 @VintfStability
 @Backing(type="int")
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/sim/CardStatus.aidl b/radio/aidl/android/hardware/radio/sim/CardStatus.aidl
index 1419c51..043bfa4 100644
--- a/radio/aidl/android/hardware/radio/sim/CardStatus.aidl
+++ b/radio/aidl/android/hardware/radio/sim/CardStatus.aidl
@@ -21,6 +21,7 @@
 import android.hardware.radio.sim.AppStatus;
 import android.hardware.radio.sim.PinState;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable CardStatus {
diff --git a/radio/aidl/android/hardware/radio/sim/Carrier.aidl b/radio/aidl/android/hardware/radio/sim/Carrier.aidl
index d25214f..8b27088 100644
--- a/radio/aidl/android/hardware/radio/sim/Carrier.aidl
+++ b/radio/aidl/android/hardware/radio/sim/Carrier.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.sim;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable Carrier {
diff --git a/radio/aidl/android/hardware/radio/sim/CarrierInfo.aidl b/radio/aidl/android/hardware/radio/sim/CarrierInfo.aidl
new file mode 100644
index 0000000..74fe31b
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/sim/CarrierInfo.aidl
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio.sim;
+
+import android.hardware.radio.sim.Plmn;
+
+/** @hide */
+@VintfStability
+@JavaDerive(toString=true)
+parcelable CarrierInfo {
+    /**
+     * MCC (Mobile Country Code) of Carrier. Wild char is either '*' or '?'.
+     */
+    String mcc;
+
+    /**
+     * MNC (Mobile Network Code) of the Carrier. Wild char is either '*' or '?'.
+     */
+    String mnc;
+    /**
+     * Service Provider Name(SPN) of the SIM card of the Carrier.
+     */
+    @nullable
+    String spn;
+    /**
+     * GID1 value of the SIM card of the Carrier.
+     */
+    @nullable
+    String gid1;
+    /**
+     * GID2 value of the SIM card of the Carrier.
+     */
+    @nullable
+    String gid2;
+
+    /**
+     * IMSI (International Mobile Subscriber Identity) prefix. Wild char is '*'.
+     */
+    @nullable
+    String imsiPrefix;
+    /**
+     * Equivalent HPLMN of the SIM card of the Carrier.
+     */
+    @nullable
+    List<Plmn> ehplmn;
+    /**
+     * ICCID (Integrated Circuit Card Identification) of the SIM card.
+     */
+    @nullable
+    String iccid;
+    /**
+     * IMPI (IMS Private Identity) of the SIM card of the Carrier.
+     */
+    @nullable
+    String impi;
+}
\ No newline at end of file
diff --git a/radio/aidl/android/hardware/radio/sim/CarrierRestrictions.aidl b/radio/aidl/android/hardware/radio/sim/CarrierRestrictions.aidl
index edbec2c..0002d5a 100644
--- a/radio/aidl/android/hardware/radio/sim/CarrierRestrictions.aidl
+++ b/radio/aidl/android/hardware/radio/sim/CarrierRestrictions.aidl
@@ -17,7 +17,9 @@
 package android.hardware.radio.sim;
 
 import android.hardware.radio.sim.Carrier;
+import android.hardware.radio.sim.CarrierInfo;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable CarrierRestrictions {
@@ -25,12 +27,12 @@
     @Backing(type="int")
     /** This enum defines the carrier restriction status values */
     enum CarrierRestrictionStatus {
-       /**
-        * Carrier restriction status value is unknown, used in cases where modem is dependent on
-        * external module to know about the lock status and the module hasn’t yet provided the lock
-        * status. For example, when the lock status is maintained on a cloud server and device has
-        * just booted after out of box and not yet connected to the internet.
-        */
+        /**
+         * Carrier restriction status value is unknown, used in cases where modem is dependent on
+         * external module to know about the lock status and the module hasn’t yet provided the lock
+         * status. For example, when the lock status is maintained on a cloud server and device has
+         * just booted after out of box and not yet connected to the internet.
+         */
         UNKNOWN = 0,
         /** There is no carrier restriction on the device */
         NOT_RESTRICTED = 1,
@@ -39,12 +41,14 @@
     }
     /**
      * Allowed carriers
+     * @deprecated use @List<CarrierInfo> allowedCarrierInfoList
      */
     Carrier[] allowedCarriers;
     /**
      * Explicitly excluded carriers which match allowed_carriers. Eg. allowedCarriers match mcc/mnc,
      * excludedCarriers has same mcc/mnc and gid1 is ABCD. It means except the carrier whose gid1
      * is ABCD, all carriers with the same mcc/mnc are allowed.
+     * @deprecated use @List<CarrierInfo> excludedCarrierInfoList
      */
     Carrier[] excludedCarriers;
     /**
@@ -58,4 +62,14 @@
     boolean allowedCarriersPrioritized;
     /** Current restriction status as defined in CarrierRestrictionStatus enum */
     CarrierRestrictionStatus status;
-}
+
+    /**  Allowed carriers. */
+    CarrierInfo[] allowedCarrierInfoList = {};
+
+    /**
+     * Explicitly excluded carriers which match allowed_carriers. Eg. allowedCarriers match mcc/mnc,
+     * excludedCarriers has same mcc/mnc and gid1 is ABCD. It means except the carrier whose gid1
+     * is ABCD, all carriers with the same mcc/mnc are allowed.
+     */
+    CarrierInfo[]  excludedCarrierInfoList = {};
+}
\ No newline at end of file
diff --git a/radio/aidl/android/hardware/radio/sim/CdmaSubscriptionSource.aidl b/radio/aidl/android/hardware/radio/sim/CdmaSubscriptionSource.aidl
index 6aa6926..4c6c1ef 100644
--- a/radio/aidl/android/hardware/radio/sim/CdmaSubscriptionSource.aidl
+++ b/radio/aidl/android/hardware/radio/sim/CdmaSubscriptionSource.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.sim;
 
+/** @hide */
 @VintfStability
 @Backing(type="int")
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/sim/IRadioSim.aidl b/radio/aidl/android/hardware/radio/sim/IRadioSim.aidl
index 3823a71..7870a74 100644
--- a/radio/aidl/android/hardware/radio/sim/IRadioSim.aidl
+++ b/radio/aidl/android/hardware/radio/sim/IRadioSim.aidl
@@ -37,6 +37,7 @@
  * duration of a method call. If clients provide colliding serials (including passing the same
  * serial to different methods), multiple responses (one for each method call) must still be served.
  * setResponseFunctions must work with IRadioSimResponse and IRadioSimIndication.
+ * @hide
  */
 @VintfStability
 oneway interface IRadioSim {
@@ -48,6 +49,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioSimResponse.areUiccApplicationsEnabledResponse()
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void areUiccApplicationsEnabled(in int serial);
 
@@ -60,6 +63,8 @@
      * @param aid AID value, See ETSI 102.221 8.1 and 101.220 4, empty string if no value.
      *
      * Response function is IRadioSimResponse.changeIccPin2ForAppResponse()
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void changeIccPin2ForApp(in int serial, in String oldPin2, in String newPin2, in String aid);
 
@@ -72,6 +77,8 @@
      * @param aid AID value, See ETSI 102.221 8.1 and 101.220 4, empty string if no value.
      *
      * Response function is IRadioSimResponse.changeIccPinForAppResponse()
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void changeIccPinForApp(in int serial, in String oldPin, in String newPin, in String aid);
 
@@ -90,6 +97,8 @@
      * @param enable true if to enable uiccApplications, false to disable.
      *
      * Response function is IRadioSimResponse.enableUiccApplicationsResponse()
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void enableUiccApplications(in int serial, in boolean enable);
 
@@ -99,6 +108,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioSimResponse.getAllowedCarriersResponse()
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void getAllowedCarriers(in int serial);
 
@@ -110,6 +121,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioSimResponse.getCdmaSubscriptionResponse()
+     *
+     * This is available when android.hardware.telephony.cdma is defined.
      */
     void getCdmaSubscription(in int serial);
 
@@ -119,6 +132,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioSimResponse.getCdmaSubscriptionSourceResponse()
+     *
+     * This is available when android.hardware.telephony.cdma is defined.
      */
     void getCdmaSubscriptionSource(in int serial);
 
@@ -134,6 +149,8 @@
      *        This is only applicable in the case of Fixed Dialing Numbers (FDN) requests.
      *
      * Response function is IRadioSimResponse.getFacilityLockForAppResponse()
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void getFacilityLockForApp(in int serial, in String facility, in String password,
             in int serviceClass, in String appId);
@@ -144,6 +161,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioSimResponse.getIccCardStatusResponse()
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void getIccCardStatus(in int serial);
 
@@ -154,6 +173,8 @@
      * @param aid AID value, See ETSI 102.221 8.1 and 101.220 4, empty string if no value.
      *
      * Response function is IRadioSimResponse.getImsiForAppResponse()
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void getImsiForApp(in int serial, in String aid);
 
@@ -163,6 +184,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioSimResponse.getSimPhonebookCapacityResponse()
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void getSimPhonebookCapacity(in int serial);
 
@@ -174,6 +197,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioSimResponse.getSimPhonebookRecordsResponse()
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void getSimPhonebookRecords(in int serial);
 
@@ -186,6 +211,8 @@
      *
      * Response function is IRadioSimResponse.iccCloseLogicalChannelResponse()
      *
+     * This is available when android.hardware.telephony.subscription is defined.
+     *
      * @deprecated use iccCloseLogicalChannelWithSessionInfo instead.
      */
     void iccCloseLogicalChannel(in int serial, in int channelId);
@@ -201,6 +228,8 @@
      * @param iccIo IccIo
      *
      * Response function is IRadioSimResponse.iccIoForAppResponse()
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void iccIoForApp(in int serial, in IccIo iccIo);
 
@@ -219,6 +248,8 @@
      * @param p2 P2 value, described in ISO 7816-4. Ignore if equal to RadioConst:P2_CONSTANT_NO_P2
      *
      * Response function is IRadioSimResponse.iccOpenLogicalChannelResponse()
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void iccOpenLogicalChannel(in int serial, in String aid, in int p2);
 
@@ -232,6 +263,8 @@
      * @param message SimApdu to be sent
      *
      * Response function is IRadioSimResponse.iccTransmitApduBasicChannelResponse()
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void iccTransmitApduBasicChannel(in int serial, in SimApdu message);
 
@@ -244,6 +277,8 @@
      * @param message SimApdu to be sent
      *
      * Response function is IRadioSimResponse.iccTransmitApduLogicalChannelResponse()
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void iccTransmitApduLogicalChannel(in int serial, in SimApdu message);
 
@@ -253,6 +288,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioSimResponse.reportStkServiceIsRunningResponse()
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void reportStkServiceIsRunning(in int serial);
 
@@ -266,6 +303,8 @@
      * @param aid AID value, See ETSI 102.221 8.1 and 101.220 4, empty string if no value
      *
      * Response function is IRadioSimResponse.requestIccSimAuthenticationResponse()
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void requestIccSimAuthentication(
             in int serial, in int authContext, in String authData, in String aid);
@@ -274,6 +313,8 @@
      * When response type received from a radio indication or radio response is
      * RadioIndicationType:UNSOLICITED_ACK_EXP or RadioResponseType:SOLICITED_ACK_EXP respectively,
      * acknowledge the receipt of those messages by sending responseAcknowledgement().
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void responseAcknowledgement();
 
@@ -285,6 +326,8 @@
      * @param contents SAT/USAT command in hexadecimal format string starting with command tag
      *
      * Response function is IRadioSimResponse.sendEnvelopeResponse()
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void sendEnvelope(in int serial, in String contents);
 
@@ -300,6 +343,8 @@
      * @param contents SAT/USAT command in hexadecimal format starting with command tag
      *
      * Response function is IRadioSimResponse.sendEnvelopeWithStatusResponse()
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void sendEnvelopeWithStatus(in int serial, in String contents);
 
@@ -311,6 +356,8 @@
      *        first byte of response data
      *
      * Response function is IRadioSimResponse.sendTerminalResponseResponseToSim()
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void sendTerminalResponseToSim(in int serial, in String contents);
 
@@ -330,6 +377,8 @@
      * @param multiSimPolicy Policy to be used for devices with multiple SIMs.
      *
      * Response function is IRadioSimResponse.setAllowedCarriersResponse()
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void setAllowedCarriers(in int serial, in CarrierRestrictions carriers,
             in SimLockMultiSimPolicy multiSimPolicy);
@@ -343,6 +392,8 @@
      * @param imsiEncryptionInfo ImsiEncryptionInfo
      *
      * Response function is IRadioSimResponse.setCarrierInfoForImsiEncryptionResponse()
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void setCarrierInfoForImsiEncryption(in int serial, in ImsiEncryptionInfo imsiEncryptionInfo);
 
@@ -353,6 +404,8 @@
      * @param cdmaSub CdmaSubscriptionSource
      *
      * Response function is IRadioSimResponse.setCdmaSubscriptionSourceResponse()
+     *
+     * This is available when android.hardware.telephony.cdma is defined.
      */
     void setCdmaSubscriptionSource(in int serial, in CdmaSubscriptionSource cdmaSub);
 
@@ -369,6 +422,8 @@
      *        This is only applicable in the case of Fixed Dialing Numbers (FDN) requests.
      *
      * Response function is IRadioSimResponse.setFacilityLockForAppResponse()
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void setFacilityLockForApp(in int serial, in String facility, in boolean lockState,
             in String password, in int serviceClass, in String appId);
@@ -378,6 +433,8 @@
      *
      * @param radioSimResponse Object containing response functions
      * @param radioSimIndication Object containing radio indications
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void setResponseFunctions(
             in IRadioSimResponse radioSimResponse, in IRadioSimIndication radioSimIndication);
@@ -408,6 +465,8 @@
      *                POWER_UP_PASS_THROUGH if powering up the SIM card in pass through mode
      *
      * Response function is IRadioSimResponse.setSimCardPowerResponse()
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void setSimCardPower(in int serial, in CardPowerState powerUp);
 
@@ -418,6 +477,8 @@
      * @param uiccSub SelectUiccSub
      *
      * Response function is IRadioSimResponse.setUiccSubscriptionResponse()
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void setUiccSubscription(in int serial, in SelectUiccSub uiccSub);
 
@@ -430,6 +491,8 @@
      * @param aid AID value, See ETSI 102.221 8.1 and 101.220 4, empty string if no value.
      *
      * Response function is IRadioSimResponse.supplyIccPin2ForAppResponse()
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void supplyIccPin2ForApp(in int serial, in String pin2, in String aid);
 
@@ -441,6 +504,8 @@
      * @param aid AID value, See ETSI 102.221 8.1 and 101.220 4, empty string if no value.
      *
      * Response function is IRadioSimResponse.supplyIccPinForAppResponse()
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void supplyIccPinForApp(in int serial, in String pin, in String aid);
 
@@ -453,6 +518,8 @@
      * @param aid AID value, See ETSI 102.221 8.1 and 101.220 4, empty string if no value.
      *
      * Response function is IRadioSimResponse.supplyIccPuk2ForAppResponse()
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void supplyIccPuk2ForApp(in int serial, in String puk2, in String pin2, in String aid);
 
@@ -465,6 +532,8 @@
      * @param aid AID value, See ETSI 102.221 8.1 and 101.220 4, empty string if no value.
      *
      * Response function is IRadioSimResponse.supplyIccPukForAppResponse()
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void supplyIccPukForApp(in int serial, in String puk, in String pin, in String aid);
 
@@ -480,6 +549,8 @@
      * @param controlKey the unlock code for removing persoType personalization from this device
      *
      * Response function is IRadioSimResponse.supplySimDepersonalizationResponse()
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void supplySimDepersonalization(
             in int serial, in PersoSubstate persoType, in String controlKey);
@@ -495,6 +566,8 @@
      * @param recordInfo Details of the record to insert, delete or update.
      *
      * Response function is IRadioSimResponse.updateSimPhonebookRecordsResponse()
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void updateSimPhonebookRecords(in int serial, in PhonebookRecordInfo recordInfo);
 
@@ -510,6 +583,8 @@
      * @param sessionInfo Details of the opened logical channel info like sessionId and isEs10.
      *
      * Response function is IRadioSimResponse.iccCloseLogicalChannelWithSessionInfoResponse()
+     *
+     * This is available when android.hardware.telephony.subscription is defined.
      */
     void iccCloseLogicalChannelWithSessionInfo(in int serial, in SessionInfo sessionInfo);
 }
diff --git a/radio/aidl/android/hardware/radio/sim/IRadioSimIndication.aidl b/radio/aidl/android/hardware/radio/sim/IRadioSimIndication.aidl
index a139040..fc6355d 100644
--- a/radio/aidl/android/hardware/radio/sim/IRadioSimIndication.aidl
+++ b/radio/aidl/android/hardware/radio/sim/IRadioSimIndication.aidl
@@ -24,6 +24,7 @@
 
 /**
  * Interface declaring unsolicited radio indications for SIM APIs.
+ * @hide
  */
 @VintfStability
 oneway interface IRadioSimIndication {
diff --git a/radio/aidl/android/hardware/radio/sim/IRadioSimResponse.aidl b/radio/aidl/android/hardware/radio/sim/IRadioSimResponse.aidl
index 90f172f..91b5729 100644
--- a/radio/aidl/android/hardware/radio/sim/IRadioSimResponse.aidl
+++ b/radio/aidl/android/hardware/radio/sim/IRadioSimResponse.aidl
@@ -27,6 +27,7 @@
 
 /**
  * Interface declaring response functions to solicited radio requests for SIM APIs.
+ * @hide
  */
 @VintfStability
 oneway interface IRadioSimResponse {
@@ -44,6 +45,8 @@
      * @param enabled whether Uicc applications are enabled.
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.subscription is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:SIM_ABSENT
      *   RadioError:RADIO_NOT_AVAILABLE
@@ -56,6 +59,8 @@
      * @param remainingRetries Number of retries remaining, must be equal to -1 if unknown.
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.subscription is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE (radio resetting)
      *   RadioError:PASSWORD_INCORRECT (old PIN2 is invalid)
@@ -74,6 +79,8 @@
      * @param remainingRetries Number of retries remaining, must be equal to -1 if unknown.
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.subscription is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE (radio resetting)
      *   RadioError:PASSWORD_INCORRECT
@@ -90,6 +97,8 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.subscription is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:SIM_ABSENT
      *   RadioError:RADIO_NOT_AVAILABLE
@@ -104,6 +113,8 @@
      * @param multiSimPolicy Policy used for devices with multiple SIM cards.
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.subscription is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      */
@@ -121,6 +132,7 @@
      * @param prl PRL version if CDMA subscription is available
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.cdma is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:SUBSCRIPTION_NOT_AVAILABLE
@@ -142,6 +154,7 @@
      * @param source CDMA subscription source
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.cdma is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:SUBSCRIPTION_NOT_AVAILABLE
@@ -160,6 +173,8 @@
      *        specified barring facility is active. "0" means "disabled for all"
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.subscription is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:SS_MODIFIED_TO_DIAL
@@ -181,6 +196,8 @@
      * @param cardStatus ICC card status as defined by CardStatus
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.subscription is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
@@ -193,6 +210,8 @@
      * @param imsi String containing the IMSI
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.subscription is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE (radio resetting)
      *   RadioError:INTERNAL_ERR
@@ -209,6 +228,8 @@
      * @param capacity Response capacity enum indicating response processing status
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.subscription is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_ARGUMENTS
@@ -222,6 +243,8 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.subscription is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_ARGUMENTS
@@ -235,6 +258,8 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.subscription is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
@@ -251,6 +276,8 @@
      * @param iccIo ICC IO operation response
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.subscription is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:SIM_PIN2
@@ -271,6 +298,8 @@
      *        byte per integer
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.subscription is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:MISSING_RESOURCE
@@ -291,6 +320,8 @@
      * @param result IccIoResult
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.subscription is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
@@ -305,6 +336,8 @@
      * @param result IccIoResult
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.subscription is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
@@ -318,6 +351,8 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.subscription is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
@@ -332,6 +367,8 @@
      * @param result IccIoResult
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.subscription is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
@@ -350,6 +387,8 @@
      *        byte of response
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.subscription is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:SIM_BUSY
@@ -369,6 +408,8 @@
      * @param iccIo IccIoResult corresponding to ICC IO response
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.subscription is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:SIM_BUSY
@@ -385,6 +426,8 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.subscription is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_ARGUMENTS
@@ -402,6 +445,8 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.subscription is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_ARGUMENTS
@@ -412,6 +457,8 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.subscription is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:SIM_ABSENT
@@ -424,6 +471,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.cdma is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:SIM_ABSENT
@@ -440,6 +488,8 @@
      * @param retry 0 is the number of retries remaining, or -1 if unknown
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.subscription is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:SS_MODIFIED_TO_DIAL
@@ -462,6 +512,8 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.subscription is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_ARGUMENTS
@@ -473,6 +525,8 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.subscription is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:SUBSCRIPTION_NOT_SUPPORTED
@@ -491,6 +545,8 @@
      * @param remainingRetries Number of retries remaining, must be equal to -1 if unknown.
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.subscription is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE (radio resetting)
      *   RadioError:PASSWORD_INCORRECT
@@ -509,6 +565,8 @@
      * @param remainingRetries Number of retries remaining, must be equal to -1 if unknown.
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.subscription is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE (radio resetting)
      *   RadioError:PASSWORD_INCORRECT
@@ -526,6 +584,8 @@
      * @param remainingRetries Number of retries remaining, must be equal to -1 if unknown.
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.subscription is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE (radio resetting)
      *   RadioError:PASSWORD_INCORRECT (PUK is invalid)
@@ -543,6 +603,8 @@
      * @param remainingRetries Number of retries remaining, must be equal to -1 if unknown.
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.subscription is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE (radio resetting)
      *   RadioError:PASSWORD_INCORRECT (PUK is invalid)
@@ -562,6 +624,8 @@
      *        to -1 if number of retries is infinite.
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.subscription is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:PASSWORD_INCORRECT (code is invalid)
@@ -582,6 +646,8 @@
      *        the minimum value is 1
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.subscription is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_ARGUMENTS
@@ -598,6 +664,8 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.subscription is not
+     *                                    defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
diff --git a/radio/aidl/android/hardware/radio/sim/IccIo.aidl b/radio/aidl/android/hardware/radio/sim/IccIo.aidl
index f173c8e..0877b7a 100644
--- a/radio/aidl/android/hardware/radio/sim/IccIo.aidl
+++ b/radio/aidl/android/hardware/radio/sim/IccIo.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.sim;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable IccIo {
diff --git a/radio/aidl/android/hardware/radio/sim/IccIoResult.aidl b/radio/aidl/android/hardware/radio/sim/IccIoResult.aidl
index efcbbda..ac89698 100644
--- a/radio/aidl/android/hardware/radio/sim/IccIoResult.aidl
+++ b/radio/aidl/android/hardware/radio/sim/IccIoResult.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.sim;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable IccIoResult {
diff --git a/radio/aidl/android/hardware/radio/sim/ImsiEncryptionInfo.aidl b/radio/aidl/android/hardware/radio/sim/ImsiEncryptionInfo.aidl
index ba1dda5..b31b081 100644
--- a/radio/aidl/android/hardware/radio/sim/ImsiEncryptionInfo.aidl
+++ b/radio/aidl/android/hardware/radio/sim/ImsiEncryptionInfo.aidl
@@ -18,6 +18,7 @@
 
 /**
  * Carrier specific Information sent by the carrier, which will be used to encrypt IMSI and IMPI.
+ * @hide
  */
 @VintfStability
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/sim/PbReceivedStatus.aidl b/radio/aidl/android/hardware/radio/sim/PbReceivedStatus.aidl
index b1385a4..f9414a8 100644
--- a/radio/aidl/android/hardware/radio/sim/PbReceivedStatus.aidl
+++ b/radio/aidl/android/hardware/radio/sim/PbReceivedStatus.aidl
@@ -18,6 +18,7 @@
 
 /**
  * Enum representing the status of the received PB indication.
+ * @hide
  */
 @VintfStability
 @Backing(type="byte")
diff --git a/radio/aidl/android/hardware/radio/sim/PersoSubstate.aidl b/radio/aidl/android/hardware/radio/sim/PersoSubstate.aidl
index f85c84b..4da86c5 100644
--- a/radio/aidl/android/hardware/radio/sim/PersoSubstate.aidl
+++ b/radio/aidl/android/hardware/radio/sim/PersoSubstate.aidl
@@ -19,6 +19,7 @@
 /**
  * Additional personalization categories in addition to those specified in 3GPP TS 22.022 and
  * 3GPP2 C.S0068-0.
+ * @hide
  */
 @VintfStability
 @Backing(type="int")
diff --git a/radio/aidl/android/hardware/radio/sim/PhonebookCapacity.aidl b/radio/aidl/android/hardware/radio/sim/PhonebookCapacity.aidl
index 97c3dba..2212fda 100644
--- a/radio/aidl/android/hardware/radio/sim/PhonebookCapacity.aidl
+++ b/radio/aidl/android/hardware/radio/sim/PhonebookCapacity.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.sim;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable PhonebookCapacity {
diff --git a/radio/aidl/android/hardware/radio/sim/PhonebookRecordInfo.aidl b/radio/aidl/android/hardware/radio/sim/PhonebookRecordInfo.aidl
index c4db0e6..1653c31 100644
--- a/radio/aidl/android/hardware/radio/sim/PhonebookRecordInfo.aidl
+++ b/radio/aidl/android/hardware/radio/sim/PhonebookRecordInfo.aidl
@@ -19,6 +19,7 @@
 /**
  * Phonebook-record-information specified by EF_ADN (Abbreviated dialing numbers) record of SIM
  * as per 3GPP spec 31.102 v15 Section-4.4.2.3.
+ * @hide
  */
 @VintfStability
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/sim/PinState.aidl b/radio/aidl/android/hardware/radio/sim/PinState.aidl
index 85048bb..f5f3108 100644
--- a/radio/aidl/android/hardware/radio/sim/PinState.aidl
+++ b/radio/aidl/android/hardware/radio/sim/PinState.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.sim;
 
+/** @hide */
 @VintfStability
 @Backing(type="int")
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/sim/Plmn.aidl b/radio/aidl/android/hardware/radio/sim/Plmn.aidl
new file mode 100644
index 0000000..fd82692
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/sim/Plmn.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio.sim;
+
+/** @hide */
+@VintfStability
+@JavaDerive(toString=true)
+parcelable Plmn {
+    /**
+     * MCC (Mobile Country Code) of the PLMN
+     */
+    String mcc;
+    /**
+     * MNC (Mobile Network Code) of the PLMN
+     */
+    String mnc;
+}
\ No newline at end of file
diff --git a/radio/aidl/android/hardware/radio/sim/SelectUiccSub.aidl b/radio/aidl/android/hardware/radio/sim/SelectUiccSub.aidl
index 553404b..70a2191 100644
--- a/radio/aidl/android/hardware/radio/sim/SelectUiccSub.aidl
+++ b/radio/aidl/android/hardware/radio/sim/SelectUiccSub.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.sim;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable SelectUiccSub {
diff --git a/radio/aidl/android/hardware/radio/sim/SessionInfo.aidl b/radio/aidl/android/hardware/radio/sim/SessionInfo.aidl
index 9e3e8ed..585118a 100644
--- a/radio/aidl/android/hardware/radio/sim/SessionInfo.aidl
+++ b/radio/aidl/android/hardware/radio/sim/SessionInfo.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.sim;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable SessionInfo {
diff --git a/radio/aidl/android/hardware/radio/sim/SimApdu.aidl b/radio/aidl/android/hardware/radio/sim/SimApdu.aidl
index 9799f2b..d0e3c39 100644
--- a/radio/aidl/android/hardware/radio/sim/SimApdu.aidl
+++ b/radio/aidl/android/hardware/radio/sim/SimApdu.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.sim;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable SimApdu {
diff --git a/radio/aidl/android/hardware/radio/sim/SimLockMultiSimPolicy.aidl b/radio/aidl/android/hardware/radio/sim/SimLockMultiSimPolicy.aidl
index 6490d51..89d85a9 100644
--- a/radio/aidl/android/hardware/radio/sim/SimLockMultiSimPolicy.aidl
+++ b/radio/aidl/android/hardware/radio/sim/SimLockMultiSimPolicy.aidl
@@ -16,18 +16,61 @@
 
 package android.hardware.radio.sim;
 
+/** @hide */
 @VintfStability
 @Backing(type="int")
 @JavaDerive(toString=true)
 enum SimLockMultiSimPolicy {
+
     /**
      * Indicates that configuration applies to each slot independently.
      */
     NO_MULTISIM_POLICY,
+
     /**
      * Indicates that any SIM card can be used as far as one valid card is present in the device.
      * For the modem, a SIM card is valid when its content (i.e. MCC, MNC, GID, SPN) matches the
      * carrier restriction configuration.
      */
     ONE_VALID_SIM_MUST_BE_PRESENT,
+
+    /**
+     * Indicates that the SIM lock policy applies uniformly to all sim slots.
+     */
+    APPLY_TO_ALL_SLOTS,
+
+    /**
+     * The SIM lock configuration applies exclusively to sim slot 1, leaving
+     * all other sim slots unlocked irrespective of the SIM card in slot 1
+     */
+    APPLY_TO_ONLY_SLOT_1,
+
+    /**
+     * Valid sim cards must be present on sim slot1 in order
+     * to use other sim slots.
+     */
+    VALID_SIM_MUST_PRESENT_ON_SLOT_1,
+
+    /**
+     * Valid sim card must be present on slot1 and it must be in full service
+     * in order to use other sim slots.
+     */
+    ACTIVE_SERVICE_ON_SLOT_1_TO_UNBLOCK_OTHER_SLOTS,
+
+    /**
+     * Valid sim card be present on any slot and it must be in full service
+     * in order to use other sim slots.
+     */
+    ACTIVE_SERVICE_ON_ANY_SLOT_TO_UNBLOCK_OTHER_SLOTS,
+
+    /**
+     * Valid sim cards must be present on all slots. If any SIM cards become
+     * invalid then device would set other SIM cards as invalid as well.
+     */
+    ALL_SIMS_MUST_BE_VALID,
+
+    /**
+     * In case there is no match policy listed above.
+     */
+    SLOT_POLICY_OTHER
 }
diff --git a/radio/aidl/android/hardware/radio/sim/SimRefreshResult.aidl b/radio/aidl/android/hardware/radio/sim/SimRefreshResult.aidl
index 69aff66..943f1d2 100644
--- a/radio/aidl/android/hardware/radio/sim/SimRefreshResult.aidl
+++ b/radio/aidl/android/hardware/radio/sim/SimRefreshResult.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.sim;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable SimRefreshResult {
diff --git a/radio/aidl/android/hardware/radio/voice/AudioQuality.aidl b/radio/aidl/android/hardware/radio/voice/AudioQuality.aidl
index dc47172..334ae3d 100644
--- a/radio/aidl/android/hardware/radio/voice/AudioQuality.aidl
+++ b/radio/aidl/android/hardware/radio/voice/AudioQuality.aidl
@@ -19,6 +19,7 @@
 /**
  * Audio codec which is used on GSM, UMTS, and CDMA. These values must be opaque to the Android
  * framework. Only for display.
+ * @hide
  */
 @VintfStability
 @Backing(type="int")
diff --git a/radio/aidl/android/hardware/radio/voice/Call.aidl b/radio/aidl/android/hardware/radio/voice/Call.aidl
index b09d7a0..ee0b025 100644
--- a/radio/aidl/android/hardware/radio/voice/Call.aidl
+++ b/radio/aidl/android/hardware/radio/voice/Call.aidl
@@ -19,6 +19,7 @@
 import android.hardware.radio.voice.AudioQuality;
 import android.hardware.radio.voice.UusInfo;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable Call {
diff --git a/radio/aidl/android/hardware/radio/voice/CallForwardInfo.aidl b/radio/aidl/android/hardware/radio/voice/CallForwardInfo.aidl
index c4143b9..9b4ecd9 100644
--- a/radio/aidl/android/hardware/radio/voice/CallForwardInfo.aidl
+++ b/radio/aidl/android/hardware/radio/voice/CallForwardInfo.aidl
@@ -18,6 +18,7 @@
 
 /**
  * See also com.android.internal.telephony.gsm.CallForwardInfo
+ * @hide
  */
 @VintfStability
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/voice/CdmaCallWaiting.aidl b/radio/aidl/android/hardware/radio/voice/CdmaCallWaiting.aidl
index 4d447d7..d97b319 100644
--- a/radio/aidl/android/hardware/radio/voice/CdmaCallWaiting.aidl
+++ b/radio/aidl/android/hardware/radio/voice/CdmaCallWaiting.aidl
@@ -18,6 +18,7 @@
 
 import android.hardware.radio.voice.CdmaSignalInfoRecord;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable CdmaCallWaiting {
diff --git a/radio/aidl/android/hardware/radio/voice/CdmaDisplayInfoRecord.aidl b/radio/aidl/android/hardware/radio/voice/CdmaDisplayInfoRecord.aidl
index 522f7ae..7e5a68d 100644
--- a/radio/aidl/android/hardware/radio/voice/CdmaDisplayInfoRecord.aidl
+++ b/radio/aidl/android/hardware/radio/voice/CdmaDisplayInfoRecord.aidl
@@ -22,6 +22,7 @@
  * the form: display_tag, display_len, and display_len occurrences of the char field if the
  * display_tag is not 10000000 or 10000001. To save space, the records are stored consecutively in
  * a byte buffer. The display_tag, display_len and chari fields are all 1 byte.
+ * @hide
  */
 @VintfStability
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/voice/CdmaInformationRecord.aidl b/radio/aidl/android/hardware/radio/voice/CdmaInformationRecord.aidl
index 1a4f1b3..f5c656b 100644
--- a/radio/aidl/android/hardware/radio/voice/CdmaInformationRecord.aidl
+++ b/radio/aidl/android/hardware/radio/voice/CdmaInformationRecord.aidl
@@ -24,10 +24,11 @@
 import android.hardware.radio.voice.CdmaT53AudioControlInfoRecord;
 import android.hardware.radio.voice.CdmaT53ClirInfoRecord;
 
-@VintfStability
 /**
  * Max length of CdmaInformationRecords[] is CDMA_MAX_NUMBER_OF_INFO_RECS
+ * @hide
  */
+@VintfStability
 @JavaDerive(toString=true)
 parcelable CdmaInformationRecord {
     const int CDMA_MAX_NUMBER_OF_INFO_RECS = 10;
diff --git a/radio/aidl/android/hardware/radio/voice/CdmaLineControlInfoRecord.aidl b/radio/aidl/android/hardware/radio/voice/CdmaLineControlInfoRecord.aidl
index 8bfc5f7..15c22a0 100644
--- a/radio/aidl/android/hardware/radio/voice/CdmaLineControlInfoRecord.aidl
+++ b/radio/aidl/android/hardware/radio/voice/CdmaLineControlInfoRecord.aidl
@@ -18,6 +18,7 @@
 
 /**
  * Line Control Information Record as defined in C.S0005 section 3.7.5.15
+ * @hide
  */
 @VintfStability
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/voice/CdmaNumberInfoRecord.aidl b/radio/aidl/android/hardware/radio/voice/CdmaNumberInfoRecord.aidl
index 9084b25..b04e273 100644
--- a/radio/aidl/android/hardware/radio/voice/CdmaNumberInfoRecord.aidl
+++ b/radio/aidl/android/hardware/radio/voice/CdmaNumberInfoRecord.aidl
@@ -20,6 +20,7 @@
  * Called Party Number Info Rec as defined in C.S0005 section 3.7.5.2
  * Calling Party Number Info Rec as defined in C.S0005 section 3.7.5.3
  * Connected Number Info Rec as defined in C.S0005 section 3.7.5.4
+ * @hide
  */
 @VintfStability
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/voice/CdmaOtaProvisionStatus.aidl b/radio/aidl/android/hardware/radio/voice/CdmaOtaProvisionStatus.aidl
index 81fb003..b6444ab 100644
--- a/radio/aidl/android/hardware/radio/voice/CdmaOtaProvisionStatus.aidl
+++ b/radio/aidl/android/hardware/radio/voice/CdmaOtaProvisionStatus.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.voice;
 
+/** @hide */
 @VintfStability
 @Backing(type="int")
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/voice/CdmaRedirectingNumberInfoRecord.aidl b/radio/aidl/android/hardware/radio/voice/CdmaRedirectingNumberInfoRecord.aidl
index 5c9e2f2..691712e 100644
--- a/radio/aidl/android/hardware/radio/voice/CdmaRedirectingNumberInfoRecord.aidl
+++ b/radio/aidl/android/hardware/radio/voice/CdmaRedirectingNumberInfoRecord.aidl
@@ -18,6 +18,7 @@
 
 import android.hardware.radio.voice.CdmaNumberInfoRecord;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable CdmaRedirectingNumberInfoRecord {
diff --git a/radio/aidl/android/hardware/radio/voice/CdmaSignalInfoRecord.aidl b/radio/aidl/android/hardware/radio/voice/CdmaSignalInfoRecord.aidl
index 3334475..4302ba4 100644
--- a/radio/aidl/android/hardware/radio/voice/CdmaSignalInfoRecord.aidl
+++ b/radio/aidl/android/hardware/radio/voice/CdmaSignalInfoRecord.aidl
@@ -18,6 +18,7 @@
 
 /**
  * CDMA Signal Information Record as defined in C.S0005 section 3.7.5.5
+ * @hide
  */
 @VintfStability
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/voice/CdmaT53AudioControlInfoRecord.aidl b/radio/aidl/android/hardware/radio/voice/CdmaT53AudioControlInfoRecord.aidl
index 9795cf0..44ac2b4 100644
--- a/radio/aidl/android/hardware/radio/voice/CdmaT53AudioControlInfoRecord.aidl
+++ b/radio/aidl/android/hardware/radio/voice/CdmaT53AudioControlInfoRecord.aidl
@@ -18,6 +18,7 @@
 
 /**
  * T53 Audio Control Information Record
+ * @hide
  */
 @VintfStability
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/voice/CdmaT53ClirInfoRecord.aidl b/radio/aidl/android/hardware/radio/voice/CdmaT53ClirInfoRecord.aidl
index 5ccd251..564d761 100644
--- a/radio/aidl/android/hardware/radio/voice/CdmaT53ClirInfoRecord.aidl
+++ b/radio/aidl/android/hardware/radio/voice/CdmaT53ClirInfoRecord.aidl
@@ -18,6 +18,7 @@
 
 /**
  * T53 CLIR Information Record
+ * @hide
  */
 @VintfStability
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/voice/CfData.aidl b/radio/aidl/android/hardware/radio/voice/CfData.aidl
index 8f4c227..84304f4 100644
--- a/radio/aidl/android/hardware/radio/voice/CfData.aidl
+++ b/radio/aidl/android/hardware/radio/voice/CfData.aidl
@@ -18,6 +18,7 @@
 
 import android.hardware.radio.voice.CallForwardInfo;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable CfData {
diff --git a/radio/aidl/android/hardware/radio/voice/ClipStatus.aidl b/radio/aidl/android/hardware/radio/voice/ClipStatus.aidl
index 4021471..0a2ea2c 100644
--- a/radio/aidl/android/hardware/radio/voice/ClipStatus.aidl
+++ b/radio/aidl/android/hardware/radio/voice/ClipStatus.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.voice;
 
+/** @hide */
 @VintfStability
 @Backing(type="int")
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/voice/Dial.aidl b/radio/aidl/android/hardware/radio/voice/Dial.aidl
index ca028ad..a874181 100644
--- a/radio/aidl/android/hardware/radio/voice/Dial.aidl
+++ b/radio/aidl/android/hardware/radio/voice/Dial.aidl
@@ -18,6 +18,7 @@
 
 import android.hardware.radio.voice.UusInfo;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable Dial {
diff --git a/radio/aidl/android/hardware/radio/voice/EmergencyCallRouting.aidl b/radio/aidl/android/hardware/radio/voice/EmergencyCallRouting.aidl
index d623346..9f8993d 100644
--- a/radio/aidl/android/hardware/radio/voice/EmergencyCallRouting.aidl
+++ b/radio/aidl/android/hardware/radio/voice/EmergencyCallRouting.aidl
@@ -18,6 +18,7 @@
 
 /**
  * Indicates how the implementation should handle the emergency call if it is required by Android.
+ * @hide
  */
 @VintfStability
 @Backing(type="int")
diff --git a/radio/aidl/android/hardware/radio/voice/EmergencyNumber.aidl b/radio/aidl/android/hardware/radio/voice/EmergencyNumber.aidl
index e380ce8..30f29a9 100644
--- a/radio/aidl/android/hardware/radio/voice/EmergencyNumber.aidl
+++ b/radio/aidl/android/hardware/radio/voice/EmergencyNumber.aidl
@@ -37,6 +37,7 @@
  *            3gpp 23.167, Section 6 - Functional description;
  *            3gpp 24.503, Section 5.1.6.8.1 - General;
  *            RFC 5031
+ * @hide
  */
 @VintfStability
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/voice/EmergencyServiceCategory.aidl b/radio/aidl/android/hardware/radio/voice/EmergencyServiceCategory.aidl
index a4ac7aa..80f873a 100644
--- a/radio/aidl/android/hardware/radio/voice/EmergencyServiceCategory.aidl
+++ b/radio/aidl/android/hardware/radio/voice/EmergencyServiceCategory.aidl
@@ -31,6 +31,7 @@
  * services are associated with this emergency number.
  *
  * Reference: 3gpp 22.101, Section 10 - Emergency Calls
+ * @hide
  */
 @VintfStability
 @Backing(type="int")
diff --git a/radio/aidl/android/hardware/radio/voice/IRadioVoice.aidl b/radio/aidl/android/hardware/radio/voice/IRadioVoice.aidl
index c05d237..0c2b51d 100644
--- a/radio/aidl/android/hardware/radio/voice/IRadioVoice.aidl
+++ b/radio/aidl/android/hardware/radio/voice/IRadioVoice.aidl
@@ -30,6 +30,7 @@
  * duration of a method call. If clients provide colliding serials (including passing the same
  * serial to different methods), multiple responses (one for each method call) must still be served.
  * setResponseFunctions must work with IRadioVoiceResponse and IRadioVoiceIndication.
+ * @hide
  */
 @VintfStability
 oneway interface IRadioVoice {
@@ -40,6 +41,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioVoiceResponse.acceptCallResponse()
+     *
+     * This is available when android.hardware.telephony.calling is defined.
      */
     void acceptCall(in int serial);
 
@@ -49,6 +52,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioVoiceResponse.cancelPendingUssdResponse()
+     *
+     * This is available when android.hardware.telephony.calling is defined.
      */
     void cancelPendingUssd(in int serial);
 
@@ -58,6 +63,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioVoiceResponse.conferenceResponse()
+     *
+     * This is available when android.hardware.telephony.calling is defined.
      */
     void conference(in int serial);
 
@@ -68,6 +75,8 @@
      * @param dialInfo Dial struct
      *
      * Response function is IRadioVoiceResponse.dialResponse()
+     *
+     * This is available when android.hardware.telephony.calling is defined.
      */
     void dial(in int serial, in Dial dialInfo);
 
@@ -124,6 +133,8 @@
      * @param isTesting Flag indicating if this request is for testing purpose.
      *
      * Response function is IRadioVoiceResponse.emergencyDialResponse()
+     *
+     * This is available when android.hardware.telephony.calling is defined.
      */
     void emergencyDial(in int serial, in Dial dialInfo, in int categories, in String[] urns,
             in EmergencyCallRouting routing, in boolean hasKnownUserIntentEmergency,
@@ -136,6 +147,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioVoiceResponse.exitEmergencyCallbackModeResponse()
+     *
+     * This is available when android.hardware.telephony.calling is defined.
      */
     void exitEmergencyCallbackMode(in int serial);
 
@@ -145,6 +158,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioVoiceResponse.explicitCallTransferResponse()
+     *
+     * This is available when android.hardware.telephony.calling is defined.
      */
     void explicitCallTransfer(in int serial);
 
@@ -155,6 +170,8 @@
      * @param callInfo CallForwardInfo
      *
      * Response function is IRadioVoiceResponse.getCallForwardStatusResponse()
+     *
+     * This is available when android.hardware.telephony.calling is defined.
      */
     void getCallForwardStatus(in int serial, in CallForwardInfo callInfo);
 
@@ -165,6 +182,8 @@
      * @param serviceClass Service class is the TS 27.007 service class to query
      *
      * Response function is IRadioVoiceResponse.getCallWaitingResponse()
+     *
+     * This is available when android.hardware.telephony.calling is defined.
      */
     void getCallWaiting(in int serial, in int serviceClass);
 
@@ -174,6 +193,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioVoiceResponse.getClipResponse()
+     *
+     * This is available when android.hardware.telephony.calling is defined.
      */
     void getClip(in int serial);
 
@@ -183,6 +204,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioVoiceResponse.getClirResponse()
+     *
+     * This is available when android.hardware.telephony.calling is defined.
      */
     void getClir(in int serial);
 
@@ -192,6 +215,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioVoiceResponse.getCurrentCallsResponse()
+     *
+     * This is available when android.hardware.telephony.calling is defined.
      */
     void getCurrentCalls(in int serial);
 
@@ -201,6 +226,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioVoiceResponse.getLastCallFailCauseResponse()
+     *
+     * This is available when android.hardware.telephony.calling is defined.
      */
     void getLastCallFailCause(in int serial);
 
@@ -210,6 +237,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioVoiceResponse.getMuteResponse()
+     *
+     * This is available when android.hardware.telephony.calling is defined.
      */
     void getMute(in int serial);
 
@@ -219,6 +248,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioVoiceResponse.getPreferredVoicePrivacyResponse()
+     *
+     * This is available when android.hardware.telephony.calling is defined.
      */
     void getPreferredVoicePrivacy(in int serial);
 
@@ -228,6 +259,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioVoiceResponse.getTtyModeResponse()
+     *
+     * This is available when android.hardware.telephony.calling is defined.
      */
     void getTtyMode(in int serial);
 
@@ -240,6 +273,8 @@
      * @param accept true = accept the call setup, false = reject the call setup
      *
      * Response function is IRadioVoiceResponse.handleStkCallSetupRequestFromSimResponse()
+     *
+     * This is available when android.hardware.telephony.calling is defined.
      */
     void handleStkCallSetupRequestFromSim(in int serial, in boolean accept);
 
@@ -251,6 +286,8 @@
      * @param gsmIndex Connection index (value of 'x' in CHLD above)
      *
      * Response function is IRadioVoiceResponse.hangupResponse()
+     *
+     * This is available when android.hardware.telephony.calling is defined.
      */
     void hangup(in int serial, in int gsmIndex);
 
@@ -261,6 +298,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioVoiceResponse.hangupForegroundResumeBackgroundResponse()
+     *
+     * This is available when android.hardware.telephony.calling is defined.
      */
     void hangupForegroundResumeBackground(in int serial);
 
@@ -271,6 +310,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioVoiceResponse.hangupWaitingOrBackgroundResponse()
+     *
+     * This is available when android.hardware.telephony.calling is defined.
      */
     void hangupWaitingOrBackground(in int serial);
 
@@ -280,6 +321,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioVoiceResponse.isVoNrEnabledResponse()
+     *
+     * This is available when android.hardware.telephony.ims is defined.
      */
     void isVoNrEnabled(in int serial);
 
@@ -289,6 +332,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioVoiceResponse.rejectCallResponse()
+     *
+     * This is available when android.hardware.telephony.calling is defined.
      */
     void rejectCall(in int serial);
 
@@ -296,6 +341,8 @@
      * When response type received from a radio indication or radio response is
      * RadioIndicationType:UNSOLICITED_ACK_EXP or RadioResponseType:SOLICITED_ACK_EXP respectively,
      * acknowledge the receipt of those messages by sending responseAcknowledgement().
+     *
+     * This is available when android.hardware.telephony.calling is defined.
      */
     void responseAcknowledgement();
 
@@ -308,6 +355,8 @@
      * @param off is the DTMF OFF length in milliseconds, or 0 to use default
      *
      * Response function is IRadioVoiceResponse.sendBurstDtmfResponse()
+     *
+     * This is available when android.hardware.telephony.calling is defined.
      */
     void sendBurstDtmf(in int serial, in String dtmf, in int on, in int off);
 
@@ -318,6 +367,8 @@
      * @param featureCode String associated with Flash command
      *
      * Response function is IRadioVoiceResponse.sendCdmaFeatureCodeResponse()
+     *
+     * This is available when android.hardware.telephony.cdma is defined.
      */
     void sendCdmaFeatureCode(in int serial, in String featureCode);
 
@@ -329,6 +380,8 @@
      * @param s string with single char having one of 12 values: 0-9, *, #
      *
      * Response function is IRadioVoiceResponse.sendDtmfResponse()
+     *
+     * This is available when android.hardware.telephony.calling is defined.
      */
     void sendDtmf(in int serial, in String s);
 
@@ -346,6 +399,8 @@
      * @param ussd string containing the USSD request in UTF-8 format
      *
      * Response function is IRadioVoiceResponse.sendUssdResponse()
+     *
+     * This is available when android.hardware.telephony.calling is defined.
      */
     void sendUssd(in int serial, in String ussd);
 
@@ -362,6 +417,8 @@
      * @param gsmIndex contains Connection index (value of 'x' in CHLD above)
      *
      * Response function is IRadioVoiceResponse.separateConnectionResponse()
+     *
+     * This is available when android.hardware.telephony.calling is defined.
      */
     void separateConnection(in int serial, in int gsmIndex);
 
@@ -372,6 +429,8 @@
      * @param callInfo CallForwardInfo
      *
      * Response function is IRadioVoiceResponse.setCallForwardResponse()
+     *
+     * This is available when android.hardware.telephony.calling is defined.
      */
     void setCallForward(in int serial, in CallForwardInfo callInfo);
 
@@ -383,6 +442,8 @@
      * @param serviceClass is the TS 27.007 service class bit vector of services to modify
      *
      * Response function is IRadioVoiceResponse.setCallWaitingResponse()
+     *
+     * This is available when android.hardware.telephony.calling is defined.
      */
     void setCallWaiting(in int serial, in boolean enable, in int serviceClass);
 
@@ -393,6 +454,8 @@
      * @param status "n" parameter from TS 27.007 7.7
      *
      * Response function is IRadioVoiceResponse.setClirResponse()
+     *
+     * This is available when android.hardware.telephony.calling is defined.
      */
     void setClir(in int serial, in int status);
 
@@ -404,6 +467,8 @@
      * @param enable true for "enable mute" and false for "disable mute"
      *
      * Response function is IRadioVoiceResponse.setMuteResponse()
+     *
+     * This is available when android.hardware.telephony.calling is defined.
      */
     void setMute(in int serial, in boolean enable);
 
@@ -415,6 +480,8 @@
      *        true for Enhanced Privacy Mode (Private Long Code Mask)
      *
      * Response function is IRadioVoiceResponse.setPreferredVoicePrivacyResponse()
+     *
+     * This is available when android.hardware.telephony.calling is defined.
      */
     void setPreferredVoicePrivacy(in int serial, in boolean enable);
 
@@ -423,6 +490,8 @@
      *
      * @param radioVoiceResponse Object containing response functions
      * @param radioVoiceIndication Object containing radio indications
+     *
+     * This is available when android.hardware.telephony.calling is defined.
      */
     void setResponseFunctions(in IRadioVoiceResponse radioVoiceResponse,
             in IRadioVoiceIndication radioVoiceIndication);
@@ -434,6 +503,8 @@
      * @param mode TtyMode
      *
      * Response function is IRadioVoiceResponse.setTtyModeResponse()
+     *
+     * This is available when android.hardware.telephony.calling is defined.
      */
     void setTtyMode(in int serial, in TtyMode mode);
 
@@ -444,6 +515,8 @@
      * @param enable true for "enable vonr" and false for "disable vonr"
      *
      * Response function is IRadioVoiceResponse.setVoNrEnabledResponse()
+     *
+     * This is available when android.hardware.telephony.ims is defined.
      */
     void setVoNrEnabled(in int serial, in boolean enable);
 
@@ -456,6 +529,8 @@
      * @param s string having a single character with one of 12 values: 0-9,*,#
      *
      * Response function is IRadioVoiceResponse.startDtmfResponse()
+     *
+     * This is available when android.hardware.telephony.calling is defined.
      */
     void startDtmf(in int serial, in String s);
 
@@ -465,6 +540,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioVoiceResponse.stopDtmfResponse()
+     *
+     * This is available when android.hardware.telephony.calling is defined.
      */
     void stopDtmf(in int serial);
 
@@ -482,6 +559,8 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioVoiceResponse.switchWaitingOrHoldingAndActiveResponse()
+     *
+     * This is available when android.hardware.telephony.calling is defined.
      */
     void switchWaitingOrHoldingAndActive(in int serial);
 }
diff --git a/radio/aidl/android/hardware/radio/voice/IRadioVoiceIndication.aidl b/radio/aidl/android/hardware/radio/voice/IRadioVoiceIndication.aidl
index 437fef6..9de6364 100644
--- a/radio/aidl/android/hardware/radio/voice/IRadioVoiceIndication.aidl
+++ b/radio/aidl/android/hardware/radio/voice/IRadioVoiceIndication.aidl
@@ -28,6 +28,7 @@
 
 /**
  * Interface declaring unsolicited radio indications for voice APIs.
+ * @hide
  */
 @VintfStability
 oneway interface IRadioVoiceIndication {
diff --git a/radio/aidl/android/hardware/radio/voice/IRadioVoiceResponse.aidl b/radio/aidl/android/hardware/radio/voice/IRadioVoiceResponse.aidl
index 39e3ace..a904eaa 100644
--- a/radio/aidl/android/hardware/radio/voice/IRadioVoiceResponse.aidl
+++ b/radio/aidl/android/hardware/radio/voice/IRadioVoiceResponse.aidl
@@ -25,6 +25,7 @@
 
 /**
  * Interface declaring response functions to solicited radio requests for voice APIs.
+ * @hide
  */
 @VintfStability
 oneway interface IRadioVoiceResponse {
@@ -32,6 +33,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.calling is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_STATE
@@ -60,6 +62,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.calling is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:SIM_BUSY
@@ -80,6 +83,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.calling is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE (radio resetting)
      *   RadioError:NO_MEMORY
@@ -100,6 +104,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.calling is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE (radio resetting)
      *   RadioError:DIAL_MODIFIED_TO_USSD
@@ -128,6 +133,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.calling is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE (radio resetting)
      *   RadioError:DIAL_MODIFIED_TO_USSD
@@ -151,6 +157,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.calling is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:OPERATION_NO_ALLOWED
@@ -169,6 +176,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.calling is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_ARGUMENTS
@@ -195,6 +203,7 @@
      *        CallForwardInfo must be returned with the service class set to "data + voice = 3".
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.calling is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:SS_MODIFIED_TO_DIAL
@@ -222,6 +231,7 @@
      *        for data and voice and disabled for everything else.
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.calling is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:SS_MODIFIED_TO_DIAL
@@ -244,6 +254,7 @@
      * @param status indicates CLIP status
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.calling is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_ARGUMENTS
@@ -263,6 +274,7 @@
      * @param m is "m" parameter from TS 27.007 7.7
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.calling is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:SS_MODIFIED_TO_DIAL
@@ -284,6 +296,7 @@
      * @param calls Current call list
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.calling is not defined
      *   RadioError:NO_MEMORY
      *   RadioError:INTERNAL_ERR
      *   RadioError:SYSTEM_ERR
@@ -326,6 +339,7 @@
      * for tone generation or error notification.
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.calling is not defined
      *   RadioError:NONE
      *   RadioError:NO_MEMORY
      *   RadioError:RADIO_NOT_AVAILABLE
@@ -345,6 +359,7 @@
      * @param enable true for "mute enabled" and false for "mute disabled"
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.calling is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:SS_MODIFIED_TO_DIAL
@@ -366,6 +381,7 @@
      *        true for Enhanced Privacy Mode (Private Long Code Mask)
      *
      * Valid errors:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.calling is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_ARGUMENTS
@@ -383,6 +399,7 @@
      * @param mode TtyMode
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.calling is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_ARGUMENTS
@@ -399,6 +416,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.calling is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:NO_MEMORY
@@ -416,6 +434,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.calling is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE (radio resetting)
      *   RadioError:INVALID_ARGUMENTS
@@ -433,6 +452,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.calling is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE (radio resetting)
      *   RadioError:INVALID_STATE
@@ -453,6 +473,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.calling is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE (radio resetting)
      *   RadioError:INVALID_STATE
@@ -473,6 +494,7 @@
      * @param enable true for "vonr enabled" and false for "vonr disabled"
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.ims is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:MODEM_ERR
@@ -485,6 +507,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.calling is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE (radio resetting)
      *   RadioError:INVALID_STATE
@@ -506,6 +529,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.calling is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_ARGUMENTS
@@ -526,6 +550,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.cdma is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_ARGUMENTS
@@ -546,6 +571,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.calling is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_ARGUMENTS
@@ -564,6 +590,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.calling is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:FDN_CHECK_FAILURE
@@ -589,6 +616,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.calling is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_ARGUMENTS
@@ -609,6 +637,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.calling is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:SS_MODIFIED_TO_DIAL
@@ -631,6 +660,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.calling is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:SS_MODIFIED_TO_DIAL
@@ -653,6 +683,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.calling is not defined
      *   RadioError:NONE
      *   RadioError:INVALID_ARGUMENTS
      *   RadioError:RADIO_NOT_AVAILABLE
@@ -671,6 +702,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.calling is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_ARGUMENTS
@@ -687,6 +719,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.calling is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_ARGUMENTS
@@ -704,6 +737,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.calling is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_ARGUMENTS
@@ -720,6 +754,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.calling is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_ARGUMENTS
@@ -733,6 +768,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.calling is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_ARGUMENTS
@@ -752,6 +788,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.calling is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_ARGUMENTS
@@ -771,6 +808,7 @@
      * @param info Response info struct containing response type, serial no. and error
      *
      * Valid errors returned:
+     *   RadioError:REQUEST_NOT_SUPPORTED when android.hardware.telephony.calling is not defined
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE (radio resetting)
      *   RadioError:INVALID_STATE
diff --git a/radio/aidl/android/hardware/radio/voice/LastCallFailCause.aidl b/radio/aidl/android/hardware/radio/voice/LastCallFailCause.aidl
index 5c8c819..9a38197 100644
--- a/radio/aidl/android/hardware/radio/voice/LastCallFailCause.aidl
+++ b/radio/aidl/android/hardware/radio/voice/LastCallFailCause.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.voice;
 
+/** @hide */
 @VintfStability
 @Backing(type="int")
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/voice/LastCallFailCauseInfo.aidl b/radio/aidl/android/hardware/radio/voice/LastCallFailCauseInfo.aidl
index 078722a..4ed17d2 100644
--- a/radio/aidl/android/hardware/radio/voice/LastCallFailCauseInfo.aidl
+++ b/radio/aidl/android/hardware/radio/voice/LastCallFailCauseInfo.aidl
@@ -18,6 +18,7 @@
 
 import android.hardware.radio.voice.LastCallFailCause;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable LastCallFailCauseInfo {
diff --git a/radio/aidl/android/hardware/radio/voice/SrvccState.aidl b/radio/aidl/android/hardware/radio/voice/SrvccState.aidl
index 08eb877..923518d 100644
--- a/radio/aidl/android/hardware/radio/voice/SrvccState.aidl
+++ b/radio/aidl/android/hardware/radio/voice/SrvccState.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.voice;
 
+/** @hide */
 @VintfStability
 @Backing(type="int")
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/voice/SsInfoData.aidl b/radio/aidl/android/hardware/radio/voice/SsInfoData.aidl
index b944bf4..c965a7d 100644
--- a/radio/aidl/android/hardware/radio/voice/SsInfoData.aidl
+++ b/radio/aidl/android/hardware/radio/voice/SsInfoData.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.voice;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable SsInfoData {
diff --git a/radio/aidl/android/hardware/radio/voice/StkCcUnsolSsResult.aidl b/radio/aidl/android/hardware/radio/voice/StkCcUnsolSsResult.aidl
index 7982275..9fe4024 100644
--- a/radio/aidl/android/hardware/radio/voice/StkCcUnsolSsResult.aidl
+++ b/radio/aidl/android/hardware/radio/voice/StkCcUnsolSsResult.aidl
@@ -20,6 +20,7 @@
 import android.hardware.radio.voice.CfData;
 import android.hardware.radio.voice.SsInfoData;
 
+/** @hide */
 @VintfStability
 @JavaDerive(toString=true)
 parcelable StkCcUnsolSsResult {
diff --git a/radio/aidl/android/hardware/radio/voice/TtyMode.aidl b/radio/aidl/android/hardware/radio/voice/TtyMode.aidl
index e8dd723..b9203e1 100644
--- a/radio/aidl/android/hardware/radio/voice/TtyMode.aidl
+++ b/radio/aidl/android/hardware/radio/voice/TtyMode.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.voice;
 
+/** @hide */
 @VintfStability
 @Backing(type="int")
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/voice/UssdModeType.aidl b/radio/aidl/android/hardware/radio/voice/UssdModeType.aidl
index cece4bd..d43462e 100644
--- a/radio/aidl/android/hardware/radio/voice/UssdModeType.aidl
+++ b/radio/aidl/android/hardware/radio/voice/UssdModeType.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.voice;
 
+/** @hide */
 @VintfStability
 @Backing(type="int")
 @JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/voice/UusInfo.aidl b/radio/aidl/android/hardware/radio/voice/UusInfo.aidl
index 220a8fc..5d499ca 100644
--- a/radio/aidl/android/hardware/radio/voice/UusInfo.aidl
+++ b/radio/aidl/android/hardware/radio/voice/UusInfo.aidl
@@ -18,6 +18,7 @@
 
 /**
  * User-to-User Signaling Information defined in 3GPP 23.087 v8.0
+ * @hide
  */
 @VintfStability
 @JavaDerive(toString=true)
diff --git a/radio/aidl/compat/OWNERS b/radio/aidl/compat/OWNERS
index 471d806..3a7a009 100644
--- a/radio/aidl/compat/OWNERS
+++ b/radio/aidl/compat/OWNERS
@@ -1,3 +1,3 @@
 # Bug component: 20868
-include ../../1.0/vts/OWNERS
+
 twasilczyk@google.com
diff --git a/radio/aidl/compat/libradiocompat/Android.bp b/radio/aidl/compat/libradiocompat/Android.bp
index 5cf1378..66970db 100644
--- a/radio/aidl/compat/libradiocompat/Android.bp
+++ b/radio/aidl/compat/libradiocompat/Android.bp
@@ -31,20 +31,20 @@
         "-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION",
     ],
     shared_libs: [
-        "android.hardware.radio.config-V2-ndk",
+        "android.hardware.radio.config-V3-ndk",
         "android.hardware.radio.config@1.0",
         "android.hardware.radio.config@1.1",
         "android.hardware.radio.config@1.2",
         "android.hardware.radio.config@1.3",
-        "android.hardware.radio.data-V2-ndk",
-        "android.hardware.radio.ims-V1-ndk",
-        "android.hardware.radio.ims.media-V1-ndk",
-        "android.hardware.radio.messaging-V2-ndk",
-        "android.hardware.radio.modem-V2-ndk",
-        "android.hardware.radio.network-V2-ndk",
+        "android.hardware.radio.data-V3-ndk",
+        "android.hardware.radio.ims-V2-ndk",
+        "android.hardware.radio.ims.media-V2-ndk",
+        "android.hardware.radio.messaging-V3-ndk",
+        "android.hardware.radio.modem-V3-ndk",
+        "android.hardware.radio.network-V3-ndk",
         "android.hardware.radio.sap-V1-ndk",
-        "android.hardware.radio.sim-V2-ndk",
-        "android.hardware.radio.voice-V2-ndk",
+        "android.hardware.radio.sim-V3-ndk",
+        "android.hardware.radio.voice-V3-ndk",
         "android.hardware.radio@1.0",
         "android.hardware.radio@1.1",
         "android.hardware.radio@1.2",
diff --git a/radio/aidl/compat/libradiocompat/CallbackManager.cpp b/radio/aidl/compat/libradiocompat/CallbackManager.cpp
index c2eaed1..96aaebc 100644
--- a/radio/aidl/compat/libradiocompat/CallbackManager.cpp
+++ b/radio/aidl/compat/libradiocompat/CallbackManager.cpp
@@ -53,6 +53,10 @@
     return *mRadioResponse;
 }
 
+RadioIndication& CallbackManager::indication() const {
+    return *mRadioIndication;
+}
+
 void CallbackManager::setResponseFunctionsDelayed() {
     std::unique_lock<std::mutex> lock(mDelayedSetterGuard);
     mDelayedSetterDeadline = std::chrono::steady_clock::now() + kDelayedSetterDelay;
diff --git a/radio/aidl/compat/libradiocompat/config/RadioConfig.cpp b/radio/aidl/compat/libradiocompat/config/RadioConfig.cpp
index b450418..837c626 100644
--- a/radio/aidl/compat/libradiocompat/config/RadioConfig.cpp
+++ b/radio/aidl/compat/libradiocompat/config/RadioConfig.cpp
@@ -62,6 +62,13 @@
     return ok();
 }
 
+ScopedAStatus RadioConfig::getSimultaneousCallingSupport(int32_t serial) {
+    LOG_CALL << serial;
+    LOG(ERROR) << " getSimultaneousCallingSupport is unsupported by HIDL HALs";
+    respond()->getSimultaneousCallingSupportResponse(notSupported(serial), {});
+    return ok();
+}
+
 ScopedAStatus RadioConfig::getSimSlotsStatus(int32_t serial) {
     LOG_CALL << serial;
     mHal1_1->getSimSlotsStatus(serial);
diff --git a/radio/aidl/compat/libradiocompat/ims/media/RadioImsMediaSession.cpp b/radio/aidl/compat/libradiocompat/ims/media/RadioImsMediaSession.cpp
index ae86914..d509300 100644
--- a/radio/aidl/compat/libradiocompat/ims/media/RadioImsMediaSession.cpp
+++ b/radio/aidl/compat/libradiocompat/ims/media/RadioImsMediaSession.cpp
@@ -60,5 +60,12 @@
     LOG(ERROR) << " setMediaQualityThreshold is unsupported by HIDL HALs";
     return ok();
 }
-
+ScopedAStatus RadioImsMediaSession::requestRtpReceptionStats(int32_t /*in_intervalMs*/) {
+    LOG(ERROR) << " requestRtpReceptionStats is unsupported by HIDL HALs";
+    return ok();
+}
+ScopedAStatus RadioImsMediaSession::adjustDelay(int32_t /*in_delayMs*/) {
+    LOG(ERROR) << " adjustDelay is unsupported by HIDL HALs";
+    return ok();
+}
 }  // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/include/libradiocompat/CallbackManager.h b/radio/aidl/compat/libradiocompat/include/libradiocompat/CallbackManager.h
index f1a7b49..34ab5d7 100644
--- a/radio/aidl/compat/libradiocompat/include/libradiocompat/CallbackManager.h
+++ b/radio/aidl/compat/libradiocompat/include/libradiocompat/CallbackManager.h
@@ -46,6 +46,7 @@
     ~CallbackManager();
 
     RadioResponse& response() const;
+    RadioIndication& indication() const;
 
     template <typename ResponseType, typename IndicationType>
     void setResponseFunctions(const std::shared_ptr<ResponseType>& response,
diff --git a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioConfig.h b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioConfig.h
index 89ddea0..17d5985 100644
--- a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioConfig.h
+++ b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioConfig.h
@@ -42,6 +42,7 @@
     ::ndk::ScopedAStatus getHalDeviceCapabilities(int32_t serial) override;
     ::ndk::ScopedAStatus getNumOfLiveModems(int32_t serial) override;
     ::ndk::ScopedAStatus getPhoneCapability(int32_t serial) override;
+    ::ndk::ScopedAStatus getSimultaneousCallingSupport(int32_t serial) override;
     ::ndk::ScopedAStatus getSimSlotsStatus(int32_t serial) override;
     ::ndk::ScopedAStatus setNumOfLiveModems(int32_t serial, int8_t numOfLiveModems) override;
     ::ndk::ScopedAStatus setPreferredDataModem(int32_t serial, int8_t modemId) override;
diff --git a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioImsMediaSession.h b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioImsMediaSession.h
index 00f21fc..715fc77 100644
--- a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioImsMediaSession.h
+++ b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioImsMediaSession.h
@@ -38,6 +38,8 @@
     ::ndk::ScopedAStatus setMediaQualityThreshold(
             const ::aidl::android::hardware::radio::ims::media::MediaQualityThreshold& in_threshold)
             override;
+    ::ndk::ScopedAStatus requestRtpReceptionStats(int32_t in_intervalMs) override;
+    ::ndk::ScopedAStatus adjustDelay(int32_t in_delayMs) override;
 
   protected:
   public:
diff --git a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioIndication.h b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioIndication.h
index f042456..e6f2516 100644
--- a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioIndication.h
+++ b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioIndication.h
@@ -26,6 +26,7 @@
 #include <aidl/android/hardware/radio/sim/IRadioSimIndication.h>
 #include <aidl/android/hardware/radio/voice/IRadioVoiceIndication.h>
 #include <android/hardware/radio/1.6/IRadioIndication.h>
+#include <aidl/android/hardware/radio/modem/ImeiInfo.h>
 
 namespace android::hardware::radio::compat {
 
@@ -208,7 +209,8 @@
     Return<void> simPhonebookRecordsReceived(
             V1_0::RadioIndicationType type, V1_6::PbReceivedStatus status,
             const hidl_vec<V1_6::PhonebookRecordInfo>& records) override;
-
+    Return<void> onImeiMappingChanged(V1_0::RadioIndicationType type,
+                                      ::aidl::android::hardware::radio::modem::ImeiInfo config);
   public:
     RadioIndication(std::shared_ptr<DriverContext> context);
 
diff --git a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioNetwork.h b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioNetwork.h
index d57c83d..56724ae 100644
--- a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioNetwork.h
+++ b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioNetwork.h
@@ -107,6 +107,12 @@
 
     ::ndk::ScopedAStatus setNullCipherAndIntegrityEnabled(int32_t serial, bool enabled) override;
     ::ndk::ScopedAStatus isNullCipherAndIntegrityEnabled(int32_t serial) override;
+    ::ndk::ScopedAStatus isCellularIdentifierTransparencyEnabled(int32_t serial) override;
+    ::ndk::ScopedAStatus setCellularIdentifierTransparencyEnabled(int32_t serial,
+                                                                  bool enabled) override;
+
+    ::ndk::ScopedAStatus setSecurityAlgorithmsUpdatedEnabled(int32_t serial, bool enabled) override;
+    ::ndk::ScopedAStatus isSecurityAlgorithmsUpdatedEnabled(int32_t serial) override;
 
   protected:
     std::shared_ptr<::aidl::android::hardware::radio::network::IRadioNetworkResponse> respond();
diff --git a/radio/aidl/compat/libradiocompat/modem/RadioIndication-modem.cpp b/radio/aidl/compat/libradiocompat/modem/RadioIndication-modem.cpp
index 851c93b..990ccff 100644
--- a/radio/aidl/compat/libradiocompat/modem/RadioIndication-modem.cpp
+++ b/radio/aidl/compat/libradiocompat/modem/RadioIndication-modem.cpp
@@ -68,4 +68,11 @@
     return {};
 }
 
+Return<void> RadioIndication::onImeiMappingChanged(V1_0::RadioIndicationType type,
+                                    ::aidl::android::hardware::radio::modem::ImeiInfo imeiInfo) {
+    LOG_CALL << type;
+    modemCb()->onImeiMappingChanged(toAidl(type), imeiInfo);
+    return {};
+}
+
 }  // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp b/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp
index a379eec..1e43789 100644
--- a/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp
+++ b/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp
@@ -372,4 +372,34 @@
     respond()->setN1ModeEnabledResponse(notSupported(serial));
     return ok();
 }
+
+ScopedAStatus RadioNetwork::isCellularIdentifierTransparencyEnabled(int32_t serial) {
+    LOG_CALL << serial;
+    LOG(ERROR) << " isCellularIdentifierTransparencyEnabled is unsupported by HIDL HALs";
+    respond()->isCellularIdentifierTransparencyEnabledResponse(notSupported(serial), false);
+    return ok();
+}
+
+ScopedAStatus RadioNetwork::setCellularIdentifierTransparencyEnabled(int32_t serial,
+                                                                     bool /*enabled*/) {
+    LOG_CALL << serial;
+    LOG(ERROR) << " setCellularIdentifierTransparencyEnabled is unsupported by HIDL HALs";
+    respond()->setCellularIdentifierTransparencyEnabledResponse(notSupported(serial));
+    return ok();
+}
+
+ScopedAStatus RadioNetwork::isSecurityAlgorithmsUpdatedEnabled(int32_t serial) {
+    LOG_CALL << serial;
+    LOG(ERROR) << " isSecurityAlgorithmsUpdatedEnabled is unsupported by HIDL HALs";
+    respond()->isSecurityAlgorithmsUpdatedEnabledResponse(notSupported(serial), false);
+    return ok();
+}
+
+ScopedAStatus RadioNetwork::setSecurityAlgorithmsUpdatedEnabled(int32_t serial, bool /*enable*/) {
+    LOG_CALL << serial;
+    LOG(ERROR) << " setSecurityAlgorithmsUpdatedEnabled is unsupported by HIDL HALs";
+    respond()->setSecurityAlgorithmsUpdatedEnabledResponse(notSupported(serial));
+    return ok();
+}
+
 }  // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/service/Android.bp b/radio/aidl/compat/service/Android.bp
index dff0182..62c99fe 100644
--- a/radio/aidl/compat/service/Android.bp
+++ b/radio/aidl/compat/service/Android.bp
@@ -34,20 +34,20 @@
     ],
     shared_libs: [
         "android.hardware.radio-library.compat",
-        "android.hardware.radio.config-V2-ndk",
+        "android.hardware.radio.config-V3-ndk",
         "android.hardware.radio.config@1.0",
         "android.hardware.radio.config@1.1",
         "android.hardware.radio.config@1.2",
         "android.hardware.radio.config@1.3",
-        "android.hardware.radio.data-V2-ndk",
-        "android.hardware.radio.ims-V1-ndk",
-        "android.hardware.radio.ims.media-V1-ndk",
-        "android.hardware.radio.messaging-V2-ndk",
-        "android.hardware.radio.modem-V2-ndk",
-        "android.hardware.radio.network-V2-ndk",
+        "android.hardware.radio.data-V3-ndk",
+        "android.hardware.radio.ims-V2-ndk",
+        "android.hardware.radio.ims.media-V2-ndk",
+        "android.hardware.radio.messaging-V3-ndk",
+        "android.hardware.radio.modem-V3-ndk",
+        "android.hardware.radio.network-V3-ndk",
         "android.hardware.radio.sap-V1-ndk",
-        "android.hardware.radio.sim-V2-ndk",
-        "android.hardware.radio.voice-V2-ndk",
+        "android.hardware.radio.sim-V3-ndk",
+        "android.hardware.radio.voice-V3-ndk",
         "android.hardware.radio@1.0",
         "android.hardware.radio@1.1",
         "android.hardware.radio@1.2",
diff --git a/radio/aidl/vts/Android.bp b/radio/aidl/vts/Android.bp
index e79d3c0..d985686 100644
--- a/radio/aidl/vts/Android.bp
+++ b/radio/aidl/vts/Android.bp
@@ -66,22 +66,27 @@
         "radio_voice_test.cpp",
         "VtsHalRadioTargetTest.cpp",
     ],
+    header_libs: [
+        "jni_headers",
+    ],
     shared_libs: [
         "libbinder_ndk",
         "libvintf",
+        "server_configurable_flags",
     ],
     static_libs: [
-        "android.hardware.radio-V2-ndk",
-        "android.hardware.radio.config-V2-ndk",
-        "android.hardware.radio.data-V2-ndk",
-        "android.hardware.radio.ims-V1-ndk",
-        "android.hardware.radio.ims.media-V1-ndk",
-        "android.hardware.radio.messaging-V2-ndk",
-        "android.hardware.radio.modem-V2-ndk",
-        "android.hardware.radio.network-V2-ndk",
+        "android.hardware.radio-V3-ndk",
+        "android.hardware.radio.config-V3-ndk",
+        "android.hardware.radio.data-V3-ndk",
+        "android.hardware.radio.ims-V2-ndk",
+        "android.hardware.radio.ims.media-V2-ndk",
+        "android.hardware.radio.messaging-V3-ndk",
+        "android.hardware.radio.modem-V3-ndk",
+        "android.hardware.radio.network-V3-ndk",
         "android.hardware.radio.sap-V1-ndk",
-        "android.hardware.radio.sim-V2-ndk",
-        "android.hardware.radio.voice-V2-ndk",
+        "android.hardware.radio.sim-V3-ndk",
+        "android.hardware.radio.voice-V3-ndk",
+        "telephony_flags_c_lib",
     ],
     test_suites: [
         "general-tests",
diff --git a/radio/aidl/vts/radio_aidl_hal_utils.h b/radio/aidl/vts/radio_aidl_hal_utils.h
index d8aa024..aea5cee 100644
--- a/radio/aidl/vts/radio_aidl_hal_utils.h
+++ b/radio/aidl/vts/radio_aidl_hal_utils.h
@@ -24,6 +24,7 @@
 #include <aidl/android/hardware/radio/network/RegState.h>
 #include <aidl/android/hardware/radio/sim/CardStatus.h>
 #include <aidl/android/hardware/radio/sim/IRadioSim.h>
+#include <com_android_internal_telephony_flags.h>
 #include <utils/Log.h>
 
 using namespace aidl::android::hardware::radio;
@@ -31,6 +32,8 @@
 using aidl::android::hardware::radio::network::RegState;
 using aidl::android::hardware::radio::sim::CardStatus;
 
+namespace telephony_flags = com::android::internal::telephony::flags;
+
 extern CardStatus cardStatus;
 extern SimSlotStatus slotStatus;
 extern int serial;
@@ -68,6 +71,18 @@
 
 static constexpr const char* FEATURE_TELEPHONY_IMS = "android.hardware.telephony.ims";
 
+static constexpr const char* FEATURE_TELEPHONY_CALLING = "android.hardware.telephony.calling";
+
+static constexpr const char* FEATURE_TELEPHONY_DATA = "android.hardware.telephony.data";
+
+static constexpr const char* FEATURE_TELEPHONY_MESSAGING = "android.hardware.telephony.messaging";
+
+static constexpr const char* FEATURE_TELEPHONY_SUBSCRIPTION =
+        "android.hardware.telephony.subscription";
+
+static constexpr const char* FEATURE_TELEPHONY_RADIO_ACCESS =
+        "android.hardware.telephony.radio.access";
+
 #define MODEM_EMERGENCY_CALL_ESTABLISH_TIME 3
 #define MODEM_EMERGENCY_CALL_DISCONNECT_TIME 3
 #define MODEM_SET_SIM_POWER_DELAY_IN_SECONDS 2
diff --git a/radio/aidl/vts/radio_config_indication.cpp b/radio/aidl/vts/radio_config_indication.cpp
index a84c20b..c707663 100644
--- a/radio/aidl/vts/radio_config_indication.cpp
+++ b/radio/aidl/vts/radio_config_indication.cpp
@@ -22,3 +22,8 @@
         RadioIndicationType /*type*/, const std::vector<SimSlotStatus>& /*slotStatus*/) {
     return ndk::ScopedAStatus::ok();
 }
+
+ndk::ScopedAStatus RadioConfigIndication::onSimultaneousCallingSupportChanged(
+        const std::vector<int32_t>& /*enabledLogicalSlots*/) {
+    return ndk::ScopedAStatus::ok();
+}
diff --git a/radio/aidl/vts/radio_config_response.cpp b/radio/aidl/vts/radio_config_response.cpp
index 7384f87..c532440 100644
--- a/radio/aidl/vts/radio_config_response.cpp
+++ b/radio/aidl/vts/radio_config_response.cpp
@@ -40,6 +40,14 @@
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus RadioConfigResponse::getSimultaneousCallingSupportResponse(
+        const RadioResponseInfo& info, const std::vector<int32_t>& enabledLogicalSlots) {
+    rspInfo = info;
+    currentEnabledLogicalSlots = enabledLogicalSlots;
+    parent_config.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
 ndk::ScopedAStatus RadioConfigResponse::setPreferredDataModemResponse(
         const RadioResponseInfo& info) {
     rspInfo = info;
diff --git a/radio/aidl/vts/radio_config_test.cpp b/radio/aidl/vts/radio_config_test.cpp
index aed3b05..6f18d18 100644
--- a/radio/aidl/vts/radio_config_test.cpp
+++ b/radio/aidl/vts/radio_config_test.cpp
@@ -54,6 +54,13 @@
  * Test IRadioConfig.getHalDeviceCapabilities() for the response returned.
  */
 TEST_P(RadioConfigTest, getHalDeviceCapabilities) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY)) {
+            GTEST_SKIP() << "Skipping getHalDeviceCapabilities "
+                            "due to undefined FEATURE_TELEPHONY";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     ndk::ScopedAStatus res = radio_config->getHalDeviceCapabilities(serial);
     ASSERT_OK(res);
@@ -66,6 +73,13 @@
  * Test IRadioConfig.getSimSlotsStatus() for the response returned.
  */
 TEST_P(RadioConfigTest, getSimSlotsStatus) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
+            GTEST_SKIP() << "Skipping getSimSlotsStatus "
+                            "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     ndk::ScopedAStatus res = radio_config->getSimSlotsStatus(serial);
     ASSERT_OK(res);
@@ -78,6 +92,13 @@
  * Test IRadioConfig.getPhoneCapability() for the response returned.
  */
 TEST_P(RadioConfigTest, getPhoneCapability) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY)) {
+            GTEST_SKIP() << "Skipping getPhoneCapability "
+                            "due to undefined FEATURE_TELEPHONY";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     ndk::ScopedAStatus res = radio_config->getPhoneCapability(serial);
     ASSERT_OK(res);
@@ -101,9 +122,58 @@
 }
 
 /*
+ * Test IRadioConfig.getSimultaneousCallingSupport() for the response returned.
+ */
+TEST_P(RadioConfigTest, getSimultaneousCallingSupport) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY)) {
+            GTEST_SKIP() << "Skipping getSimultaneousCallingSupport "
+                            "due to undefined FEATURE_TELEPHONY";
+        }
+    }
+
+    int32_t aidl_version;
+    ndk::ScopedAStatus aidl_status = radio_config->getInterfaceVersion(&aidl_version);
+    ASSERT_OK(aidl_status);
+    if (aidl_version < 3) {
+        ALOGI("Skipped the test since"
+                " getSimultaneousCallingSupport is not supported on version < 3.");
+        GTEST_SKIP();
+    }
+
+    serial = GetRandomSerialNumber();
+    ndk::ScopedAStatus res = radio_config->getSimultaneousCallingSupport(serial);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_config->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_config->rspInfo.serial);
+    ALOGI("getSimultaneousCallingSupport, rspInfo.error = %s\n",
+          toString(radioRsp_config->rspInfo.error).c_str());
+
+    // REQUEST_NOT_SUPPORTED is omitted here because users of the V3 HAL should implement this
+    // method and return at least an empty array
+    ASSERT_TRUE(CheckAnyOfErrors(
+            radioRsp_config->rspInfo.error,
+            {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::INTERNAL_ERR,
+            RadioError::MODEM_ERR}));
+
+    if (radioRsp_config->rspInfo.error == RadioError ::NONE) {
+        // The size of enabledLogicalSLots should be 0 or a positive number:
+        EXPECT_GE(radioRsp_config->currentEnabledLogicalSlots.size(), 0);
+    }
+}
+
+/*
  * Test IRadioConfig.setPreferredDataModem() for the response returned.
  */
 TEST_P(RadioConfigTest, setPreferredDataModem) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_DATA)) {
+            GTEST_SKIP() << "Skipping setPreferredDataModem "
+                            "due to undefined FEATURE_TELEPHONY_DATA";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     ndk::ScopedAStatus res = radio_config->getPhoneCapability(serial);
     ASSERT_OK(res);
@@ -146,6 +216,13 @@
  * Test IRadioConfig.setPreferredDataModem() with invalid arguments.
  */
 TEST_P(RadioConfigTest, setPreferredDataModem_invalidArgument) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_DATA)) {
+            GTEST_SKIP() << "Skipping setPreferredDataModem_invalidArgument "
+                            "due to undefined FEATURE_TELEPHONY_DATA";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     uint8_t modemId = -1;
     ndk::ScopedAStatus res = radio_config->setPreferredDataModem(serial, modemId);
@@ -166,6 +243,13 @@
  * Test IRadioConfig.setSimSlotsMapping() for the response returned.
  */
 TEST_P(RadioConfigTest, setSimSlotsMapping) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
+            GTEST_SKIP() << "Skipping setSimSlotsMapping "
+                            "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
+        }
+    }
+
     // get slot status and set SIM slots mapping based on the result.
     updateSimSlotStatus();
     if (radioRsp_config->rspInfo.error == RadioError::NONE) {
@@ -227,6 +311,13 @@
  */
 
 TEST_P(RadioConfigTest, checkPortInfoExistsAndPortActive) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
+            GTEST_SKIP() << "Skipping checkPortInfoExistsAndPortActive "
+                            "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     ndk::ScopedAStatus res = radio_config->getSimSlotsStatus(serial);
     ASSERT_OK(res);
diff --git a/radio/aidl/vts/radio_config_utils.h b/radio/aidl/vts/radio_config_utils.h
index f79aedb..84c74fc 100644
--- a/radio/aidl/vts/radio_config_utils.h
+++ b/radio/aidl/vts/radio_config_utils.h
@@ -39,6 +39,7 @@
     PhoneCapability phoneCap;
     bool modemReducedFeatureSet1;
     std::vector<SimSlotStatus> simSlotStatus;
+    std::vector<int32_t> currentEnabledLogicalSlots;
 
     virtual ndk::ScopedAStatus getSimSlotsStatusResponse(
             const RadioResponseInfo& info, const std::vector<SimSlotStatus>& slotStatus) override;
@@ -48,6 +49,9 @@
     virtual ndk::ScopedAStatus getPhoneCapabilityResponse(
             const RadioResponseInfo& info, const PhoneCapability& phoneCapability) override;
 
+    virtual ndk::ScopedAStatus getSimultaneousCallingSupportResponse(
+            const RadioResponseInfo& info, const std::vector<int32_t>& enabledLogicalSlots) override;
+
     virtual ndk::ScopedAStatus setPreferredDataModemResponse(
             const RadioResponseInfo& info) override;
 
@@ -71,6 +75,9 @@
 
     virtual ndk::ScopedAStatus simSlotsStatusChanged(
             RadioIndicationType type, const std::vector<SimSlotStatus>& slotStatus) override;
+
+    virtual ndk::ScopedAStatus onSimultaneousCallingSupportChanged(
+            const std::vector<int32_t>& /*enabledLogicalSlots*/) override;
 };
 
 // The main test class for Radio AIDL Config.
diff --git a/radio/aidl/vts/radio_data_test.cpp b/radio/aidl/vts/radio_data_test.cpp
index f31c254..2aa5508 100644
--- a/radio/aidl/vts/radio_data_test.cpp
+++ b/radio/aidl/vts/radio_data_test.cpp
@@ -68,6 +68,12 @@
  * Test IRadioData.setupDataCall() for the response returned.
  */
 TEST_P(RadioDataTest, setupDataCall) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_DATA)) {
+            GTEST_SKIP() << "setupDataCall : required FEATURE_TELEPHONY_DATA";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     AccessNetwork accessNetwork = AccessNetwork::EUTRAN;
@@ -135,6 +141,13 @@
  * Test IRadioData.setupDataCall() with osAppId for the response returned.
  */
 TEST_P(RadioDataTest, setupDataCall_osAppId) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_DATA)) {
+            GTEST_SKIP() << "Skipping setupDataCall_osAppId "
+                            "due to undefined FEATURE_TELEPHONY_DATA";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     AccessNetwork accessNetwork = AccessNetwork::EUTRAN;
@@ -227,6 +240,13 @@
  * Test IRadioData.getSlicingConfig() for the response returned.
  */
 TEST_P(RadioDataTest, getSlicingConfig) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_DATA)) {
+            GTEST_SKIP() << "Skipping getSlicingConfig "
+                            "due to undefined FEATURE_TELEPHONY_DATA";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     radio_data->getSlicingConfig(serial);
     EXPECT_EQ(std::cv_status::no_timeout, wait());
@@ -242,6 +262,13 @@
  * Test IRadioData.setDataThrottling() for the response returned.
  */
 TEST_P(RadioDataTest, setDataThrottling) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_DATA)) {
+            GTEST_SKIP() << "Skipping setDataThrottling "
+                            "due to undefined FEATURE_TELEPHONY_DATA";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     ndk::ScopedAStatus res = radio_data->setDataThrottling(
@@ -320,6 +347,13 @@
  * Test IRadioData.setInitialAttachApn() for the response returned.
  */
 TEST_P(RadioDataTest, setInitialAttachApn) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_DATA)) {
+            GTEST_SKIP() << "Skipping setInitialAttachApn "
+                            "due to undefined FEATURE_TELEPHONY_DATA";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     // Create a dataProfileInfo
@@ -363,6 +397,13 @@
  * Test IRadioData.setDataProfile() for the response returned.
  */
 TEST_P(RadioDataTest, setDataProfile) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_DATA)) {
+            GTEST_SKIP() << "Skipping setDataProfile "
+                            "due to undefined FEATURE_TELEPHONY_DATA";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     // Create a dataProfileInfo
@@ -409,6 +450,13 @@
  * Test IRadioData.deactivateDataCall() for the response returned.
  */
 TEST_P(RadioDataTest, deactivateDataCall) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_DATA)) {
+            GTEST_SKIP() << "Skipping deactivateDataCall "
+                            "due to undefined FEATURE_TELEPHONY_DATA";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     int cid = 1;
     DataRequestReason reason = DataRequestReason::NORMAL;
@@ -440,6 +488,13 @@
  * Test IRadioData.startKeepalive() for the response returned.
  */
 TEST_P(RadioDataTest, startKeepalive) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_DATA)) {
+            GTEST_SKIP() << "Skipping startKeepalive "
+                            "due to undefined FEATURE_TELEPHONY_DATA";
+        }
+    }
+
     std::vector<KeepaliveRequest> requests = {
             {
                     // Invalid IPv4 source address
@@ -538,6 +593,13 @@
  * Test IRadioData.stopKeepalive() for the response returned.
  */
 TEST_P(RadioDataTest, stopKeepalive) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_DATA)) {
+            GTEST_SKIP() << "Skipping stopKeepalive "
+                            "due to undefined FEATURE_TELEPHONY_DATA";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_data->stopKeepalive(serial, 0xBAD);
@@ -554,6 +616,13 @@
  * Test IRadioData.getDataCallList() for the response returned.
  */
 TEST_P(RadioDataTest, getDataCallList) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_DATA)) {
+            GTEST_SKIP() << "Skipping getDataCallList "
+                            "due to undefined FEATURE_TELEPHONY_DATA";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_data->getDataCallList(serial);
@@ -573,6 +642,13 @@
  * Test IRadioData.setDataAllowed() for the response returned.
  */
 TEST_P(RadioDataTest, setDataAllowed) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_DATA)) {
+            GTEST_SKIP() << "Skipping setDataAllowed "
+                            "due to undefined FEATURE_TELEPHONY_DATA";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     bool allow = true;
 
diff --git a/radio/aidl/vts/radio_imsmedia_session_listener.cpp b/radio/aidl/vts/radio_imsmedia_session_listener.cpp
index 986cab2..638a0e4 100644
--- a/radio/aidl/vts/radio_imsmedia_session_listener.cpp
+++ b/radio/aidl/vts/radio_imsmedia_session_listener.cpp
@@ -49,3 +49,7 @@
         const CallQuality& /*in_callQuality*/) {
     return ndk::ScopedAStatus::ok();
 }
+ndk::ScopedAStatus ImsMediaSessionListener::notifyRtpReceptionStats(
+        const RtpReceptionStats& /*in_stats*/) {
+    return ndk::ScopedAStatus::ok();
+}
diff --git a/radio/aidl/vts/radio_imsmedia_test.cpp b/radio/aidl/vts/radio_imsmedia_test.cpp
index 425f6b4..e479e64 100644
--- a/radio/aidl/vts/radio_imsmedia_test.cpp
+++ b/radio/aidl/vts/radio_imsmedia_test.cpp
@@ -260,6 +260,59 @@
     return result;
 }
 
+TEST_P(RadioImsMediaTest, testAvSyncOperation) {
+    int32_t sessionId = 1;
+    RtpConfig modifyRtpConfig;
+    int32_t receptionInterval = 1000;
+    int32_t delay = 200;
+
+    modifyRtpConfig.direction = static_cast<int32_t>(MediaDirection::RTP_TX) |
+                                static_cast<int32_t>(MediaDirection::RTP_RX) |
+                                static_cast<int32_t>(MediaDirection::RTCP_TX) |
+                                static_cast<int32_t>(MediaDirection::RTCP_RX);
+    modifyRtpConfig.remoteAddress.ipAddress = "122.22.22.33";
+    modifyRtpConfig.remoteAddress.portNumber = 1234;
+
+    if (!deviceSupportsFeature(FEATURE_TELEPHONY_IMS)) {
+        ALOGI("Skipping setListener because ims is not supported in device");
+        return;
+    } else {
+        ALOGI("Running setListener because ims is supported in device");
+    }
+
+    ndk::ScopedAStatus res = radio_imsmedia->setListener(radio_imsmedialistener);
+    ASSERT_OK(res);
+
+    serial = SERIAL_OPEN_SESSION;
+    res = triggerOpenSession(sessionId);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(sessionId, radio_imsmedialistener->mSessionId);
+    ASSERT_NE(nullptr, radio_imsmedialistener->mSession);
+
+    radio_imsmediasession = radio_imsmedialistener->mSession;
+    radio_imsmediasession->setListener(radio_imsmediasessionlistener);
+    ASSERT_OK(res);
+
+    serial = SERIAL_MODIFY_SESSION;
+    res = radio_imsmediasession->modifySession(modifyRtpConfig);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(modifyRtpConfig, radio_imsmediasessionlistener->mConfig);
+    verifyError(radio_imsmediasessionlistener->mError);
+
+    res = radio_imsmediasession->requestRtpReceptionStats(receptionInterval);
+    ASSERT_OK(res);
+
+    res = radio_imsmediasession->adjustDelay(delay);
+    ASSERT_OK(res);
+
+    serial = SERIAL_CLOSE_SESSION;
+    res = radio_imsmedia->closeSession(sessionId);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+}
+
 void RadioImsMediaTest::verifyError(RtpError error) {
     switch (error) {
         case RtpError::NONE:
diff --git a/radio/aidl/vts/radio_imsmedia_utils.h b/radio/aidl/vts/radio_imsmedia_utils.h
index 87f1b00..407ba95 100644
--- a/radio/aidl/vts/radio_imsmedia_utils.h
+++ b/radio/aidl/vts/radio_imsmedia_utils.h
@@ -76,6 +76,7 @@
     virtual ndk::ScopedAStatus onDtmfReceived(char16_t in_dtmfDigit,
                                               int32_t in_durationMs) override;
     virtual ndk::ScopedAStatus onCallQualityChanged(const CallQuality& in_callQuality) override;
+    virtual ndk::ScopedAStatus notifyRtpReceptionStats(const RtpReceptionStats& in_stats) override;
 };
 
 /* The main test class for Radio AIDL ImsMedia. */
diff --git a/radio/aidl/vts/radio_messaging_test.cpp b/radio/aidl/vts/radio_messaging_test.cpp
index 4ab88d2..95e2617 100644
--- a/radio/aidl/vts/radio_messaging_test.cpp
+++ b/radio/aidl/vts/radio_messaging_test.cpp
@@ -59,6 +59,13 @@
  * Test IRadioMessaging.sendSms() for the response returned.
  */
 TEST_P(RadioMessagingTest, sendSms) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_MESSAGING)) {
+            GTEST_SKIP() << "Skipping sendSms "
+                            "due to undefined FEATURE_TELEPHONY_MESSAGING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     GsmSmsMessage msg;
     msg.smscPdu = "";
@@ -83,6 +90,13 @@
  * Test IRadioMessaging.sendSmsExpectMore() for the response returned.
  */
 TEST_P(RadioMessagingTest, sendSmsExpectMore) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_MESSAGING)) {
+            GTEST_SKIP() << "Skipping sendSmsExpectMore "
+                            "due to undefined FEATURE_TELEPHONY_MESSAGING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     GsmSmsMessage msg;
     msg.smscPdu = "";
@@ -106,6 +120,13 @@
  * Test IRadioMessaging.sendCdmaSms() for the response returned.
  */
 TEST_P(RadioMessagingTest, sendCdmaSms) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
+            GTEST_SKIP() << "Skipping sendCdmaSms "
+                            "due to undefined FEATURE_TELEPHONY_CDMA";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     // Create a CdmaSmsAddress
@@ -150,6 +171,13 @@
  * Test IRadioMessaging.sendCdmaSmsExpectMore() for the response returned.
  */
 TEST_P(RadioMessagingTest, sendCdmaSmsExpectMore) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
+            GTEST_SKIP() << "Skipping sendCdmaSmsExpectMore "
+                            "due to undefined FEATURE_TELEPHONY_CDMA";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     // Create a CdmaSmsAddress
@@ -194,6 +222,13 @@
  * Test IRadioMessaging.setGsmBroadcastConfig() for the response returned.
  */
 TEST_P(RadioMessagingTest, setGsmBroadcastConfig) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_MESSAGING)) {
+            GTEST_SKIP() << "Skipping setGsmBroadcastConfig "
+                            "due to undefined FEATURE_TELEPHONY_MESSAGING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     // Create GsmBroadcastSmsConfigInfo #1
@@ -257,6 +292,13 @@
  * Test IRadioMessaging.getGsmBroadcastConfig() for the response returned.
  */
 TEST_P(RadioMessagingTest, getGsmBroadcastConfig) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_MESSAGING)) {
+            GTEST_SKIP() << "Skipping getGsmBroadcastConfig "
+                            "due to undefined FEATURE_TELEPHONY_MESSAGING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_messaging->getGsmBroadcastConfig(serial);
@@ -277,6 +319,13 @@
  * Test IRadioMessaging.setCdmaBroadcastConfig() for the response returned.
  */
 TEST_P(RadioMessagingTest, setCdmaBroadcastConfig) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
+            GTEST_SKIP() << "Skipping setCdmaBroadcastConfig "
+                            "due to undefined FEATURE_TELEPHONY_CDMA";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     CdmaBroadcastSmsConfigInfo cbSmsConfig;
@@ -303,6 +352,13 @@
  * Test IRadioMessaging.getCdmaBroadcastConfig() for the response returned.
  */
 TEST_P(RadioMessagingTest, getCdmaBroadcastConfig) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
+            GTEST_SKIP() << "Skipping getCdmaBroadcastConfig "
+                            "due to undefined FEATURE_TELEPHONY_CDMA";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_messaging->getCdmaBroadcastConfig(serial);
@@ -321,6 +377,13 @@
  * Test IRadioMessaging.setCdmaBroadcastActivation() for the response returned.
  */
 TEST_P(RadioMessagingTest, setCdmaBroadcastActivation) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
+            GTEST_SKIP() << "Skipping setCdmaBroadcastActivation "
+                            "due to undefined FEATURE_TELEPHONY_CDMA";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     bool activate = false;
 
@@ -341,6 +404,13 @@
  * Test IRadioMessaging.setGsmBroadcastActivation() for the response returned.
  */
 TEST_P(RadioMessagingTest, setGsmBroadcastActivation) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_MESSAGING)) {
+            GTEST_SKIP() << "Skipping setGsmBroadcastActivation "
+                            "due to undefined FEATURE_TELEPHONY_MESSAGING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     bool activate = false;
 
@@ -363,6 +433,13 @@
  * Test IRadioMessaging.acknowledgeLastIncomingGsmSms() for the response returned.
  */
 TEST_P(RadioMessagingTest, acknowledgeLastIncomingGsmSms) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_MESSAGING)) {
+            GTEST_SKIP() << "Skipping acknowledgeLastIncomingGsmSms "
+                            "due to undefined FEATURE_TELEPHONY_MESSAGING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     bool success = true;
 
@@ -384,6 +461,13 @@
  * Test IRadioMessaging.acknowledgeIncomingGsmSmsWithPdu() for the response returned.
  */
 TEST_P(RadioMessagingTest, acknowledgeIncomingGsmSmsWithPdu) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_MESSAGING)) {
+            GTEST_SKIP() << "Skipping acknowledgeIncomingGsmSmsWithPdu "
+                            "due to undefined FEATURE_TELEPHONY_MESSAGING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     bool success = true;
     std::string ackPdu = "";
@@ -405,6 +489,13 @@
  * Test IRadioMessaging.acknowledgeLastIncomingCdmaSms() for the response returned.
  */
 TEST_P(RadioMessagingTest, acknowledgeLastIncomingCdmaSms) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
+            GTEST_SKIP() << "Skipping acknowledgeIncomingGsmSmsWithPdu "
+                            "due to undefined FEATURE_TELEPHONY_CDMA";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     // Create a CdmaSmsAck
@@ -429,6 +520,13 @@
  * Test IRadioMessaging.sendImsSms() for the response returned.
  */
 TEST_P(RadioMessagingTest, sendImsSms) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_IMS)) {
+            GTEST_SKIP() << "Skipping acknowledgeIncomingGsmSmsWithPdu "
+                            "due to undefined FEATURE_TELEPHONY_IMS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     // Create a CdmaSmsAddress
@@ -479,6 +577,13 @@
  * Test IRadioMessaging.getSmscAddress() for the response returned.
  */
 TEST_P(RadioMessagingTest, getSmscAddress) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_MESSAGING)) {
+            GTEST_SKIP() << "Skipping getSmscAddress "
+                            "due to undefined FEATURE_TELEPHONY_MESSAGING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_messaging->getSmscAddress(serial);
@@ -499,6 +604,13 @@
  * Test IRadioMessaging.setSmscAddress() for the response returned.
  */
 TEST_P(RadioMessagingTest, setSmscAddress) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_MESSAGING)) {
+            GTEST_SKIP() << "Skipping setSmscAddress "
+                            "due to undefined FEATURE_TELEPHONY_MESSAGING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     std::string address = std::string("smscAddress");
 
@@ -520,6 +632,13 @@
  * Test IRadioMessaging.writeSmsToSim() for the response returned.
  */
 TEST_P(RadioMessagingTest, writeSmsToSim) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_MESSAGING)) {
+            GTEST_SKIP() << "Skipping writeSmsToSim "
+                            "due to undefined FEATURE_TELEPHONY_MESSAGING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     SmsWriteArgs smsWriteArgs;
     smsWriteArgs.status = SmsWriteArgs::STATUS_REC_UNREAD;
@@ -546,6 +665,13 @@
  * Test IRadioMessaging.deleteSmsOnSim() for the response returned.
  */
 TEST_P(RadioMessagingTest, deleteSmsOnSim) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_MESSAGING)) {
+            GTEST_SKIP() << "Skipping deleteSmsOnSim "
+                            "due to undefined FEATURE_TELEPHONY_MESSAGING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     int index = 1;
 
@@ -569,6 +695,13 @@
  * Test IRadioMessaging.writeSmsToRuim() for the response returned.
  */
 TEST_P(RadioMessagingTest, writeSmsToRuim) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
+            GTEST_SKIP() << "Skipping writeSmsToRuim "
+                            "due to undefined FEATURE_TELEPHONY_CDMA";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     // Create a CdmaSmsAddress
@@ -620,6 +753,13 @@
  * Test IRadioMessaging.deleteSmsOnRuim() for the response returned.
  */
 TEST_P(RadioMessagingTest, deleteSmsOnRuim) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
+            GTEST_SKIP() << "Skipping deleteSmsOnRuim "
+                            "due to undefined FEATURE_TELEPHONY_CDMA";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     int index = 1;
 
@@ -671,6 +811,13 @@
  * Test IRadioMessaging.reportSmsMemoryStatus() for the response returned.
  */
 TEST_P(RadioMessagingTest, reportSmsMemoryStatus) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_MESSAGING)) {
+            GTEST_SKIP() << "Skipping reportSmsMemoryStatus "
+                            "due to undefined FEATURE_TELEPHONY_MESSAGING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     bool available = true;
 
diff --git a/radio/aidl/vts/radio_modem_indication.cpp b/radio/aidl/vts/radio_modem_indication.cpp
index 0bfcd66..9f63cb0 100644
--- a/radio/aidl/vts/radio_modem_indication.cpp
+++ b/radio/aidl/vts/radio_modem_indication.cpp
@@ -41,3 +41,8 @@
 ndk::ScopedAStatus RadioModemIndication::rilConnected(RadioIndicationType /*type*/) {
     return ndk::ScopedAStatus::ok();
 }
+
+ndk::ScopedAStatus RadioModemIndication::onImeiMappingChanged(RadioIndicationType /*type*/,
+     const ::aidl::android::hardware::radio::modem::ImeiInfo& /*imeiInfo*/) {
+    return ndk::ScopedAStatus::ok();
+}
diff --git a/radio/aidl/vts/radio_modem_test.cpp b/radio/aidl/vts/radio_modem_test.cpp
index c48a461..6a9996b 100644
--- a/radio/aidl/vts/radio_modem_test.cpp
+++ b/radio/aidl/vts/radio_modem_test.cpp
@@ -59,6 +59,13 @@
  * Test IRadioModem.setRadioPower() for the response returned.
  */
 TEST_P(RadioModemTest, setRadioPower_emergencyCall_cancelled) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping setRadioPower_emergencyCall_cancelled "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     // Set radio power to off.
     serial = GetRandomSerialNumber();
     radio_modem->setRadioPower(serial, false, false, false);
@@ -90,6 +97,13 @@
  * Test IRadioModem.enableModem() for the response returned.
  */
 TEST_P(RadioModemTest, enableModem) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY)) {
+            GTEST_SKIP() << "Skipping enableModem "
+                            "due to undefined FEATURE_TELEPHONY";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     if (isSsSsEnabled()) {
@@ -134,6 +148,13 @@
  * Test IRadioModem.getModemStackStatus() for the response returned.
  */
 TEST_P(RadioModemTest, getModemStackStatus) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY)) {
+            GTEST_SKIP() << "Skipping getModemStackStatus "
+                            "due to undefined FEATURE_TELEPHONY";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     ndk::ScopedAStatus res = radio_modem->getModemStackStatus(serial);
@@ -152,6 +173,13 @@
  * Test IRadioModem.getBasebandVersion() for the response returned.
  */
 TEST_P(RadioModemTest, getBasebandVersion) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY)) {
+            GTEST_SKIP() << "Skipping getBasebandVersion "
+                            "due to undefined FEATURE_TELEPHONY";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_modem->getBasebandVersion(serial);
@@ -168,6 +196,13 @@
  * Test IRadioModem.getDeviceIdentity() for the response returned.
  */
 TEST_P(RadioModemTest, getDeviceIdentity) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY)) {
+            GTEST_SKIP() << "Skipping getDeviceIdentity "
+                            "due to undefined FEATURE_TELEPHONY";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_modem->getDeviceIdentity(serial);
@@ -185,6 +220,13 @@
  * Test IRadioModem.getImei() for the response returned.
  */
 TEST_P(RadioModemTest, getImei) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_GSM)) {
+            GTEST_SKIP() << "Skipping getImei "
+                            "due to undefined FEATURE_TELEPHONY_GSM";
+        }
+    }
+
     int32_t aidl_version;
     ndk::ScopedAStatus aidl_status = radio_modem->getInterfaceVersion(&aidl_version);
     ASSERT_OK(aidl_status);
@@ -246,6 +288,13 @@
  * Test IRadioModem.nvWriteCdmaPrl() for the response returned.
  */
 TEST_P(RadioModemTest, nvWriteCdmaPrl) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
+            GTEST_SKIP() << "Skipping nvWriteCdmaPrl "
+                            "due to undefined FEATURE_TELEPHONY_CDMA";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     std::vector<uint8_t> prl = {1, 2, 3, 4, 5};
 
@@ -283,6 +332,13 @@
  * Test IRadioModem.getHardwareConfig() for the response returned.
  */
 TEST_P(RadioModemTest, getHardwareConfig) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY)) {
+            GTEST_SKIP() << "Skipping getHardwareConfig "
+                            "due to undefined FEATURE_TELEPHONY";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_modem->getHardwareConfig(serial);
@@ -302,6 +358,13 @@
  * Test IRadioModem.requestShutdown() for the response returned.
  */
 TEST_P(RadioModemTest, DISABLED_requestShutdown) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping DISABLED_requestShutdown "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_modem->requestShutdown(serial);
@@ -319,6 +382,13 @@
  * Test IRadioModem.getRadioCapability() for the response returned.
  */
 TEST_P(RadioModemTest, getRadioCapability) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping getRadioCapability "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_modem->getRadioCapability(serial);
@@ -335,6 +405,13 @@
  * Test IRadioModem.setRadioCapability() for the response returned.
  */
 TEST_P(RadioModemTest, setRadioCapability) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping setRadioCapability "
+                            "due to undefined FEATURE_TELEPHONY";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     RadioCapability rc;
     memset(&rc, 0, sizeof(rc));
@@ -356,6 +433,13 @@
  * Test IRadioModem.getModemActivityInfo() for the response returned.
  */
 TEST_P(RadioModemTest, getModemActivityInfo) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping getModemActivityInfo "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_modem->getModemActivityInfo(serial);
@@ -373,6 +457,13 @@
  * Test IRadioModem.sendDeviceState() for the response returned.
  */
 TEST_P(RadioModemTest, sendDeviceState) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY)) {
+            GTEST_SKIP() << "Skipping sendDeviceState "
+                            "due to undefined FEATURE_TELEPHONY";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_modem->sendDeviceState(serial, DeviceStateType::POWER_SAVE_MODE, true);
diff --git a/radio/aidl/vts/radio_modem_utils.h b/radio/aidl/vts/radio_modem_utils.h
index d47bdeb..aa99ea3 100644
--- a/radio/aidl/vts/radio_modem_utils.h
+++ b/radio/aidl/vts/radio_modem_utils.h
@@ -109,6 +109,9 @@
                                                  RadioState radioState) override;
 
     virtual ndk::ScopedAStatus rilConnected(RadioIndicationType type) override;
+
+    virtual ndk::ScopedAStatus onImeiMappingChanged(RadioIndicationType type,
+            const ::aidl::android::hardware::radio::modem::ImeiInfo& imeiInfo) override;
 };
 
 // The main test class for Radio AIDL Modem.
diff --git a/radio/aidl/vts/radio_network_indication.cpp b/radio/aidl/vts/radio_network_indication.cpp
index ae3bd4b..9614783 100644
--- a/radio/aidl/vts/radio_network_indication.cpp
+++ b/radio/aidl/vts/radio_network_indication.cpp
@@ -97,3 +97,14 @@
         RadioIndicationType /*type*/, const EmergencyRegResult& /*result*/) {
     return ndk::ScopedAStatus::ok();
 }
+
+ndk::ScopedAStatus RadioNetworkIndication::cellularIdentifierDisclosed(
+        RadioIndicationType /*type*/,
+        const CellularIdentifierDisclosure& /*disclosures*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkIndication::securityAlgorithmsUpdated(
+        RadioIndicationType /*type*/, const SecurityAlgorithmUpdate& /*securityAlgorithmUpdate*/) {
+    return ndk::ScopedAStatus::ok();
+}
diff --git a/radio/aidl/vts/radio_network_response.cpp b/radio/aidl/vts/radio_network_response.cpp
index 25d45a5..4d452d0 100644
--- a/radio/aidl/vts/radio_network_response.cpp
+++ b/radio/aidl/vts/radio_network_response.cpp
@@ -320,3 +320,33 @@
     parent_network.notify(info.serial);
     return ndk::ScopedAStatus::ok();
 }
+
+ndk::ScopedAStatus RadioNetworkResponse::setCellularIdentifierTransparencyEnabledResponse(
+        const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_network.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkResponse::isCellularIdentifierTransparencyEnabledResponse(
+        const RadioResponseInfo& info, bool enabled) {
+    rspInfo = info;
+    this->isCellularIdentifierTransparencyEnabled = enabled;
+    parent_network.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkResponse::setSecurityAlgorithmsUpdatedEnabledResponse(
+        const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_network.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkResponse::isSecurityAlgorithmsUpdatedEnabledResponse(
+        const RadioResponseInfo& info, bool enabled) {
+    rspInfo = info;
+    this->isSecurityAlgorithmsUpdatedEnabled = enabled;
+    parent_network.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
diff --git a/radio/aidl/vts/radio_network_test.cpp b/radio/aidl/vts/radio_network_test.cpp
index f316a34..867be04 100644
--- a/radio/aidl/vts/radio_network_test.cpp
+++ b/radio/aidl/vts/radio_network_test.cpp
@@ -81,8 +81,20 @@
  * for the response returned.
  */
 TEST_P(RadioNetworkTest, setGetAllowedNetworkTypesBitmap) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping setGetAllowedNetworkTypesBitmap "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
+    // get aidl version
+    int32_t aidl_version;
+    ndk::ScopedAStatus aidl_status = radio_network->getInterfaceVersion(&aidl_version);
+    ASSERT_OK(aidl_status);
+
     // save current value
     radio_network->getAllowedNetworkTypesBitmap(serial);
     EXPECT_EQ(std::cv_status::no_timeout, wait());
@@ -118,6 +130,11 @@
                  RadioError::INVALID_ARGUMENTS, RadioError::MODEM_ERR,
                  RadioError::REQUEST_NOT_SUPPORTED, RadioError::NO_RESOURCES}));
         if (radioRsp_network->rspInfo.error == RadioError::NONE) {
+            if (aidl_version < 2) {
+                radioRsp_network->networkTypeBitmapResponse
+                    &= ~static_cast<int32_t>(RadioAccessFamily::LTE_CA);
+            }
+
             // verify we get the value we set
             EXPECT_EQ(radioRsp_network->networkTypeBitmapResponse, allowedNetworkTypesBitmap);
         }
@@ -133,6 +150,13 @@
  * Test IRadioNetwork.setNrDualConnectivityState() for the response returned.
  */
 TEST_P(RadioNetworkTest, setNrDualConnectivityState) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping setNrDualConnectivityState "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     ndk::ScopedAStatus res =
@@ -157,6 +181,13 @@
  * Test IRadioNetwork.isNrDualConnectivityEnabled() for the response returned.
  */
 TEST_P(RadioNetworkTest, isNrDualConnectivityEnabled) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping isNrDualConnectivityEnabled "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     ndk::ScopedAStatus res = radio_network->isNrDualConnectivityEnabled(serial);
@@ -195,6 +226,13 @@
  * Verify that the usage setting can be retrieved.
  */
 TEST_P(RadioNetworkTest, getUsageSetting) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY)) {
+            GTEST_SKIP() << "Skipping getUsageSetting "
+                            "due to undefined FEATURE_TELEPHONY";
+        }
+    }
+
     invokeAndExpectResponse([&](int serial) { return radio_network->getUsageSetting(serial); },
                             {RadioError::RADIO_NOT_AVAILABLE, RadioError::INVALID_STATE,
                              RadioError::SIM_ABSENT, RadioError::INTERNAL_ERR, RadioError::NONE});
@@ -232,6 +270,13 @@
  * -That the usage setting cannot be set to invalid values.
  */
 TEST_P(RadioNetworkTest, setUsageSetting) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY)) {
+            GTEST_SKIP() << "Skipping setUsageSetting "
+                            "due to undefined FEATURE_TELEPHONY";
+        }
+    }
+
     invokeAndExpectResponse([&](int serial) { return radio_network->getUsageSetting(serial); },
                             {RadioError::RADIO_NOT_AVAILABLE, RadioError::INVALID_STATE,
                              RadioError::SIM_ABSENT, RadioError::INTERNAL_ERR, RadioError::NONE});
@@ -294,6 +339,13 @@
  * Test IRadioNetwork.setSignalStrengthReportingCriteria() with invalid hysteresisDb
  */
 TEST_P(RadioNetworkTest, setSignalStrengthReportingCriteria_invalidHysteresisDb) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping setSignalStrengthReportingCriteria_invalidHysteresisDb "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     SignalThresholdInfo signalThresholdInfo;
@@ -320,6 +372,13 @@
  * Test IRadioNetwork.setSignalStrengthReportingCriteria() with empty thresholds
  */
 TEST_P(RadioNetworkTest, setSignalStrengthReportingCriteria_EmptyThresholds) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping setSignalStrengthReportingCriteria_EmptyThresholds "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     SignalThresholdInfo signalThresholdInfo;
@@ -345,6 +404,13 @@
  * Test IRadioNetwork.setSignalStrengthReportingCriteria() for GERAN
  */
 TEST_P(RadioNetworkTest, setSignalStrengthReportingCriteria_Geran) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping setSignalStrengthReportingCriteria_Geran "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     SignalThresholdInfo signalThresholdInfo;
@@ -372,6 +438,13 @@
  * Test IRadioNetwork.setSignalStrengthReportingCriteria() for UTRAN
  */
 TEST_P(RadioNetworkTest, setSignalStrengthReportingCriteria_Utran_Rscp) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping setSignalStrengthReportingCriteria_Utran_Rscp "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     SignalThresholdInfo signalThresholdInfo;
@@ -398,6 +471,13 @@
  * Test IRadioNetwork.setSignalStrengthReportingCriteria() for UTRAN
  */
 TEST_P(RadioNetworkTest, setSignalStrengthReportingCriteria_Utran_Ecno) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping setSignalStrengthReportingCriteria_Utran_Ecno "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     SignalThresholdInfo signalThresholdInfo;
@@ -425,6 +505,13 @@
  * Test IRadioNetwork.setSignalStrengthReportingCriteria() for EUTRAN
  */
 TEST_P(RadioNetworkTest, setSignalStrengthReportingCriteria_Eutran_RSRP) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping setSignalStrengthReportingCriteria_Eutran_RSRP "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     SignalThresholdInfo signalThresholdInfo;
@@ -451,6 +538,13 @@
  * Test IRadioNetwork.setSignalStrengthReportingCriteria() for EUTRAN
  */
 TEST_P(RadioNetworkTest, setSignalStrengthReportingCriteria_Eutran_RSRQ) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping setSignalStrengthReportingCriteria_Eutran_RSRQ "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     SignalThresholdInfo signalThresholdInfo;
@@ -477,6 +571,13 @@
  * Test IRadioNetwork.setSignalStrengthReportingCriteria() for EUTRAN
  */
 TEST_P(RadioNetworkTest, setSignalStrengthReportingCriteria_Eutran_RSSNR) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping setSignalStrengthReportingCriteria_Eutran_RSSNR "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     SignalThresholdInfo signalThresholdInfo;
@@ -499,6 +600,13 @@
  * Test IRadioNetwork.setSignalStrengthReportingCriteria() for CDMA2000
  */
 TEST_P(RadioNetworkTest, setSignalStrengthReportingCriteria_Cdma2000) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping setSignalStrengthReportingCriteria_Cdma2000 "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     SignalThresholdInfo signalThresholdInfo;
@@ -525,6 +633,13 @@
  * Test IRadioNetwork.setSignalStrengthReportingCriteria() for NGRAN_SSRSRP
  */
 TEST_P(RadioNetworkTest, setSignalStrengthReportingCriteria_NGRAN_SSRSRP) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping setSignalStrengthReportingCriteria_NGRAN_SSRSRP "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     SignalThresholdInfo signalThresholdInfo;
@@ -555,6 +670,13 @@
  * Test IRadioNetwork.setSignalStrengthReportingCriteria() for NGRAN_SSRSRQ
  */
 TEST_P(RadioNetworkTest, setSignalStrengthReportingCriteria_NGRAN_SSRSRQ) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping setSignalStrengthReportingCriteria_NGRAN_SSRSRQ "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     SignalThresholdInfo signalThresholdInfo;
@@ -585,6 +707,13 @@
  * Test IRadioNetwork.setSignalStrengthReportingCriteria() for EUTRAN
  */
 TEST_P(RadioNetworkTest, setSignalStrengthReportingCriteria_Disable_RSSNR) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping setSignalStrengthReportingCriteria_Disable_RSSNR "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     SignalThresholdInfo signalThresholdInfo;
@@ -607,6 +736,13 @@
  * Test IRadioNetwork.setSignalStrengthReportingCriteria() for NGRAN_SSSINR
  */
 TEST_P(RadioNetworkTest, setSignalStrengthReportingCriteria_NGRAN_SSSINR) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping setSignalStrengthReportingCriteria_NGRAN_SSSINR "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     SignalThresholdInfo signalThresholdInfo;
@@ -637,6 +773,13 @@
  * Test IRadioNetwork.setSignalStrengthReportingCriteria() for multi-RANs per request
  */
 TEST_P(RadioNetworkTest, setSignalStrengthReportingCriteria_multiRansPerRequest) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping setSignalStrengthReportingCriteria_multiRansPerRequest "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     SignalThresholdInfo signalThresholdInfoGeran;
     signalThresholdInfoGeran.signalMeasurement = SignalThresholdInfo::SIGNAL_MEASUREMENT_TYPE_RSSI;
     signalThresholdInfoGeran.hysteresisMs = 5000;
@@ -720,6 +863,13 @@
  * Test IRadioNetwork.setLinkCapacityReportingCriteria() invalid hysteresisDlKbps
  */
 TEST_P(RadioNetworkTest, setLinkCapacityReportingCriteria_invalidHysteresisDlKbps) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping setLinkCapacityReportingCriteria_invalidHysteresisDlKbps "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     ndk::ScopedAStatus res = radio_network->setLinkCapacityReportingCriteria(
@@ -740,6 +890,13 @@
  * Test IRadioNetwork.setLinkCapacityReportingCriteria() invalid hysteresisUlKbps
  */
 TEST_P(RadioNetworkTest, setLinkCapacityReportingCriteria_invalidHysteresisUlKbps) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping setLinkCapacityReportingCriteria_invalidHysteresisUlKbps "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     ndk::ScopedAStatus res = radio_network->setLinkCapacityReportingCriteria(
@@ -759,6 +916,13 @@
  * Test IRadioNetwork.setLinkCapacityReportingCriteria() empty params
  */
 TEST_P(RadioNetworkTest, setLinkCapacityReportingCriteria_emptyParams) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping setLinkCapacityReportingCriteria_emptyParams "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     ndk::ScopedAStatus res = radio_network->setLinkCapacityReportingCriteria(
@@ -777,6 +941,13 @@
  * Test IRadioNetwork.setLinkCapacityReportingCriteria() for GERAN
  */
 TEST_P(RadioNetworkTest, setLinkCapacityReportingCriteria_Geran) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping setLinkCapacityReportingCriteria_Geran "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     ndk::ScopedAStatus res = radio_network->setLinkCapacityReportingCriteria(
@@ -799,6 +970,13 @@
  * Test IRadioNetwork.setSystemSelectionChannels() for the response returned.
  */
 TEST_P(RadioNetworkTest, setSystemSelectionChannels) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping setSystemSelectionChannels "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     ndk::ScopedAStatus res = radio_network->getSystemSelectionChannels(serial);
     EXPECT_EQ(std::cv_status::no_timeout, wait());
@@ -848,6 +1026,13 @@
  * Test IRadioNetwork.startNetworkScan() for the response returned.
  */
 TEST_P(RadioNetworkTest, startNetworkScan) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping startNetworkScan "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_ONE_SHOT,
@@ -890,6 +1075,13 @@
  * Test IRadioNetwork.startNetworkScan() with invalid specifier.
  */
 TEST_P(RadioNetworkTest, startNetworkScan_InvalidArgument) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping startNetworkScan_InvalidArgument "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_ONE_SHOT, .interval = 60};
@@ -915,6 +1107,13 @@
  * Test IRadioNetwork.startNetworkScan() with invalid interval (lower boundary).
  */
 TEST_P(RadioNetworkTest, startNetworkScan_InvalidInterval1) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping startNetworkScan_InvalidInterval1 "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_PERIODIC,
@@ -944,6 +1143,13 @@
  * Test IRadioNetwork.startNetworkScan() with invalid interval (upper boundary).
  */
 TEST_P(RadioNetworkTest, startNetworkScan_InvalidInterval2) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping startNetworkScan_InvalidInterval2 "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_PERIODIC,
@@ -973,6 +1179,13 @@
  * Test IRadioNetwork.startNetworkScan() with invalid max search time (lower boundary).
  */
 TEST_P(RadioNetworkTest, startNetworkScan_InvalidMaxSearchTime1) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping startNetworkScan_InvalidMaxSearchTime1 "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_ONE_SHOT,
@@ -1002,6 +1215,13 @@
  * Test IRadioNetwork.startNetworkScan() with invalid max search time (upper boundary).
  */
 TEST_P(RadioNetworkTest, startNetworkScan_InvalidMaxSearchTime2) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping startNetworkScan_InvalidMaxSearchTime2 "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_ONE_SHOT,
@@ -1031,6 +1251,13 @@
  * Test IRadioNetwork.startNetworkScan() with invalid periodicity (lower boundary).
  */
 TEST_P(RadioNetworkTest, startNetworkScan_InvalidPeriodicity1) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping startNetworkScan_InvalidPeriodicity1 "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_ONE_SHOT,
@@ -1060,6 +1287,13 @@
  * Test IRadioNetwork.startNetworkScan() with invalid periodicity (upper boundary).
  */
 TEST_P(RadioNetworkTest, startNetworkScan_InvalidPeriodicity2) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping startNetworkScan_InvalidPeriodicity2 "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_ONE_SHOT,
@@ -1089,6 +1323,13 @@
  * Test IRadioNetwork.startNetworkScan() with valid periodicity
  */
 TEST_P(RadioNetworkTest, startNetworkScan_GoodRequest1) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping startNetworkScan_GoodRequest1 "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_ONE_SHOT,
@@ -1123,6 +1364,13 @@
  * Test IRadioNetwork.startNetworkScan() with valid periodicity and plmns
  */
 TEST_P(RadioNetworkTest, startNetworkScan_GoodRequest2) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping startNetworkScan_GoodRequest2 "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_ONE_SHOT,
@@ -1158,6 +1406,13 @@
  * Test IRadioNetwork.setNetworkSelectionModeManual() for the response returned.
  */
 TEST_P(RadioNetworkTest, setNetworkSelectionModeManual) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping setNetworkSelectionModeManual "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     // can't camp on nonexistent MCCMNC, so we expect this to fail.
@@ -1167,25 +1422,25 @@
     EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
     EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
 
-    if (cardStatus.cardState == CardStatus::STATE_ABSENT) {
-        ASSERT_TRUE(CheckAnyOfErrors(
-                radioRsp_network->rspInfo.error,
-                {RadioError::NONE, RadioError::ILLEGAL_SIM_OR_ME, RadioError::INVALID_ARGUMENTS,
-                 RadioError::INVALID_STATE, RadioError::RADIO_NOT_AVAILABLE, RadioError::NO_MEMORY,
-                 RadioError::INTERNAL_ERR, RadioError::SYSTEM_ERR, RadioError::CANCELLED}));
-    } else if (cardStatus.cardState == CardStatus::STATE_PRESENT) {
-        ASSERT_TRUE(CheckAnyOfErrors(
-                radioRsp_network->rspInfo.error,
-                {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::INVALID_ARGUMENTS,
-                 RadioError::INVALID_STATE, RadioError::NO_MEMORY, RadioError::INTERNAL_ERR,
-                 RadioError::SYSTEM_ERR, RadioError::CANCELLED}));
-    }
+    ASSERT_TRUE(CheckAnyOfErrors(
+            radioRsp_network->rspInfo.error,
+            {RadioError::NONE, RadioError::ILLEGAL_SIM_OR_ME, RadioError::RADIO_NOT_AVAILABLE,
+             RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE, RadioError::NO_MEMORY,
+             RadioError::INTERNAL_ERR, RadioError::SYSTEM_ERR, RadioError::CANCELLED,
+             RadioError::MODEM_ERR, RadioError::OPERATION_NOT_ALLOWED, RadioError::NO_RESOURCES}));
 }
 
 /*
  * Test IRadioNetwork.getBarringInfo() for the response returned.
  */
 TEST_P(RadioNetworkTest, getBarringInfo) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping getBarringInfo "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     ndk::ScopedAStatus res = radio_network->getBarringInfo(serial);
     EXPECT_EQ(std::cv_status::no_timeout, wait());
@@ -1290,6 +1545,13 @@
  * Test IRadioNetwork.getSignalStrength() for the response returned.
  */
 TEST_P(RadioNetworkTest, getSignalStrength) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping getSignalStrength "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_network->getSignalStrength(serial);
@@ -1309,6 +1571,13 @@
  * Test IRadioNetwork.getCellInfoList() for the response returned.
  */
 TEST_P(RadioNetworkTest, getCellInfoList) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping getCellInfoList "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     ndk::ScopedAStatus res = radio_network->getCellInfoList(serial);
@@ -1327,6 +1596,13 @@
  * Test IRadioNetwork.getVoiceRegistrationState() for the response returned.
  */
 TEST_P(RadioNetworkTest, getVoiceRegistrationState) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping getVoiceRegistrationState "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     ndk::ScopedAStatus res = radio_network->getVoiceRegistrationState(serial);
@@ -1345,6 +1621,13 @@
  * Test IRadioNetwork.getDataRegistrationState() for the response returned.
  */
 TEST_P(RadioNetworkTest, getDataRegistrationState) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping getDataRegistrationState "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     ndk::ScopedAStatus res = radio_network->getDataRegistrationState(serial);
@@ -1440,6 +1723,13 @@
  * Test IRadioNetwork.getAvailableBandModes() for the response returned.
  */
 TEST_P(RadioNetworkTest, getAvailableBandModes) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping getAvailableBandModes "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     ndk::ScopedAStatus res = radio_network->getAvailableBandModes(serial);
@@ -1469,6 +1759,13 @@
  * Test IRadioNetwork.setIndicationFilter()
  */
 TEST_P(RadioNetworkTest, setIndicationFilter) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping setIndicationFilter "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     ndk::ScopedAStatus res =
@@ -1487,6 +1784,13 @@
  * Test IRadioNetwork.setBarringPassword() for the response returned.
  */
 TEST_P(RadioNetworkTest, setBarringPassword) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping setBarringPassword "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     std::string facility = "";
     std::string oldPassword = "";
@@ -1510,6 +1814,13 @@
  * Test IRadioNetwork.setSuppServiceNotifications() for the response returned.
  */
 TEST_P(RadioNetworkTest, setSuppServiceNotifications) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CALLING)) {
+            GTEST_SKIP() << "Skipping setSuppServiceNotifications "
+                            "due to undefined FEATURE_TELEPHONY_CALLING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     bool enable = false;
 
@@ -1529,6 +1840,13 @@
  * Test IRadioNetwork.getImsRegistrationState() for the response returned.
  */
 TEST_P(RadioNetworkTest, getImsRegistrationState) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_IMS)) {
+            GTEST_SKIP() << "Skipping getImsRegistrationState "
+                            "due to undefined FEATURE_TELEPHONY_IMS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_network->getImsRegistrationState(serial);
@@ -1549,6 +1867,13 @@
  * Test IRadioNetwork.getOperator() for the response returned.
  */
 TEST_P(RadioNetworkTest, getOperator) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping getOperator "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_network->getOperator(serial);
@@ -1565,6 +1890,13 @@
  * Test IRadioNetwork.getNetworkSelectionMode() for the response returned.
  */
 TEST_P(RadioNetworkTest, getNetworkSelectionMode) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping getNetworkSelectionMode "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_network->getNetworkSelectionMode(serial);
@@ -1581,6 +1913,13 @@
  * Test IRadioNetwork.setNetworkSelectionModeAutomatic() for the response returned.
  */
 TEST_P(RadioNetworkTest, setNetworkSelectionModeAutomatic) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping setNetworkSelectionModeAutomatic "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_network->setNetworkSelectionModeAutomatic(serial);
@@ -1600,6 +1939,13 @@
  * Test IRadioNetwork.getAvailableNetworks() for the response returned.
  */
 TEST_P(RadioNetworkTest, getAvailableNetworks) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping getAvailableNetworks "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_network->getAvailableNetworks(serial);
@@ -1621,6 +1967,13 @@
  * Test IRadioNetwork.setBandMode() for the response returned.
  */
 TEST_P(RadioNetworkTest, setBandMode) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping setBandMode "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_network->setBandMode(serial, RadioBandMode::BAND_MODE_USA);
@@ -1638,6 +1991,13 @@
  * Test IRadioNetwork.setLocationUpdates() for the response returned.
  */
 TEST_P(RadioNetworkTest, setLocationUpdates) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping setLocationUpdates "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_network->setLocationUpdates(serial, true);
@@ -1655,6 +2015,13 @@
  * Test IRadioNetwork.setCdmaRoamingPreference() for the response returned.
  */
 TEST_P(RadioNetworkTest, setCdmaRoamingPreference) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
+            GTEST_SKIP() << "Skipping setCdmaRoamingPreference "
+                            "due to undefined FEATURE_TELEPHONY_CDMA";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_network->setCdmaRoamingPreference(serial, CdmaRoamingType::HOME_NETWORK);
@@ -1673,6 +2040,13 @@
  * Test IRadioNetwork.getCdmaRoamingPreference() for the response returned.
  */
 TEST_P(RadioNetworkTest, getCdmaRoamingPreference) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
+            GTEST_SKIP() << "Skipping getCdmaRoamingPreference "
+                            "due to undefined FEATURE_TELEPHONY_CDMA";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_network->getCdmaRoamingPreference(serial);
@@ -1692,6 +2066,13 @@
  * Test IRadioNetwork.getVoiceRadioTechnology() for the response returned.
  */
 TEST_P(RadioNetworkTest, getVoiceRadioTechnology) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping getVoiceRadioTechnology "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_network->getVoiceRadioTechnology(serial);
@@ -1708,6 +2089,13 @@
  * Test IRadioNetwork.setCellInfoListRate() for the response returned.
  */
 TEST_P(RadioNetworkTest, setCellInfoListRate) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping setCellInfoListRate "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_network->setCellInfoListRate(serial, 10);
@@ -1725,6 +2113,13 @@
  * Test IRadioNetwork.supplyNetworkDepersonalization() for the response returned.
  */
 TEST_P(RadioNetworkTest, supplyNetworkDepersonalization) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping supplyNetworkDepersonalization "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_network->supplyNetworkDepersonalization(serial, std::string("test"));
@@ -1745,6 +2140,13 @@
  * Test IRadioNetwork.setEmergencyMode() for the response returned.
  */
 TEST_P(RadioNetworkTest, setEmergencyMode) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping setEmergencyMode "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     int32_t aidl_version;
     ndk::ScopedAStatus aidl_status = radio_network->getInterfaceVersion(&aidl_version);
     ASSERT_OK(aidl_status);
@@ -1774,6 +2176,13 @@
  * Test IRadioNetwork.triggerEmergencyNetworkScan() for the response returned.
  */
 TEST_P(RadioNetworkTest, triggerEmergencyNetworkScan) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping triggerEmergencyNetworkScan "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     int32_t aidl_version;
     ndk::ScopedAStatus aidl_status = radio_network->getInterfaceVersion(&aidl_version);
     ASSERT_OK(aidl_status);
@@ -1804,6 +2213,13 @@
  * Test IRadioNetwork.cancelEmergencyNetworkScan() for the response returned.
  */
 TEST_P(RadioNetworkTest, cancelEmergencyNetworkScan) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping cancelEmergencyNetworkScan "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     int32_t aidl_version;
     ndk::ScopedAStatus aidl_status = radio_network->getInterfaceVersion(&aidl_version);
     ASSERT_OK(aidl_status);
@@ -1828,6 +2244,13 @@
  * Test IRadioNetwork.exitEmergencyMode() for the response returned.
  */
 TEST_P(RadioNetworkTest, exitEmergencyMode) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping exitEmergencyMode "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     int32_t aidl_version;
     ndk::ScopedAStatus aidl_status = radio_network->getInterfaceVersion(&aidl_version);
     ASSERT_OK(aidl_status);
@@ -1852,6 +2275,13 @@
  * Test IRadioNetwork.setN1ModeEnabled() for the response returned.
  */
 TEST_P(RadioNetworkTest, setN1ModeEnabled) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping setN1ModeEnabled "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     int32_t aidl_version;
     ndk::ScopedAStatus aidl_status = radio_network->getInterfaceVersion(&aidl_version);
     ASSERT_OK(aidl_status);
@@ -1884,6 +2314,13 @@
  * Test IRadioNetwork.isN1ModeEnabled() for the response returned.
  */
 TEST_P(RadioNetworkTest, isN1ModeEnabled) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping isN1ModeEnabled "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     int32_t aidl_version;
     ndk::ScopedAStatus aidl_status = radio_network->getInterfaceVersion(&aidl_version);
     ASSERT_OK(aidl_status);
@@ -1915,6 +2352,13 @@
  * Test IRadioNetwork.setNullCipherAndIntegrityEnabled() for the response returned.
  */
 TEST_P(RadioNetworkTest, setNullCipherAndIntegrityEnabled) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping setNullCipherAndIntegrityEnabled "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     int32_t aidl_version;
     ndk::ScopedAStatus aidl_status = radio_network->getInterfaceVersion(&aidl_version);
     ASSERT_OK(aidl_status);
@@ -1931,15 +2375,29 @@
     EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
     EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
 
-    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
-                                 {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED,
-                                  RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR}));
+    if (aidl_version >= 3 && deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+        ASSERT_TRUE(CheckAnyOfErrors(
+                radioRsp_network->rspInfo.error,
+                {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR}));
+    } else {
+        // For aidl_version 2, API is optional
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
+                                     {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
+                                      RadioError::MODEM_ERR, RadioError::REQUEST_NOT_SUPPORTED}));
+    }
 }
 
 /**
  * Test IRadioNetwork.isNullCipherAndIntegrityEnabled() for the response returned.
  */
 TEST_P(RadioNetworkTest, isNullCipherAndIntegrityEnabled) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+            GTEST_SKIP() << "Skipping isNullCipherAndIntegrityEnabled "
+                            "due to undefined FEATURE_TELEPHONY_RADIO_ACCESS";
+        }
+    }
+
     int32_t aidl_version;
     ndk::ScopedAStatus aidl_status = radio_network->getInterfaceVersion(&aidl_version);
     ASSERT_OK(aidl_status);
@@ -1958,7 +2416,168 @@
     EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
     EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
 
-    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
-                                 {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
-                                  RadioError::MODEM_ERR, RadioError::REQUEST_NOT_SUPPORTED}));
+    if (aidl_version >= 3 && deviceSupportsFeature(FEATURE_TELEPHONY_RADIO_ACCESS)) {
+        ASSERT_TRUE(CheckAnyOfErrors(
+                radioRsp_network->rspInfo.error,
+                {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR}));
+    } else {
+        // For aidl_version 2, API is optional
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
+                                     {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
+                                      RadioError::MODEM_ERR, RadioError::REQUEST_NOT_SUPPORTED}));
+    }
+}
+
+TEST_P(RadioNetworkTest, isCellularIdentifierTransparencyEnabled) {
+    int32_t aidl_version;
+    ndk::ScopedAStatus aidl_status = radio_network->getInterfaceVersion(&aidl_version);
+    ASSERT_OK(aidl_status);
+    if (aidl_version < 3) {
+        ALOGI("Skipped the test since"
+                " isCellularIdentifierTransparencyEnabled is not supported on version < 3.");
+        GTEST_SKIP();
+    }
+
+    serial = GetRandomSerialNumber();
+
+    ndk::ScopedAStatus res = radio_network->isCellularIdentifierTransparencyEnabled(serial);
+    ASSERT_OK(res);
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
+
+    ASSERT_TRUE(CheckAnyOfErrors(
+            radioRsp_network->rspInfo.error,
+            {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR}));
+}
+
+TEST_P(RadioNetworkTest, setCellularIdentifierTransparencyEnabled) {
+    int32_t aidl_version;
+    ndk::ScopedAStatus aidl_status = radio_network->getInterfaceVersion(&aidl_version);
+    ASSERT_OK(aidl_status);
+    if (aidl_version < 3) {
+        ALOGI("Skipped the test since"
+                " setCellularIdentifierTransparencyEnabled is not supported on version < 3.");
+        GTEST_SKIP();
+    }
+
+    // Get current value
+    serial = GetRandomSerialNumber();
+    radio_network->isCellularIdentifierTransparencyEnabled(serial);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    bool originalTransparencySetting = radioRsp_network->isCellularIdentifierTransparencyEnabled;
+
+    // We want to test flipping the value, so we are going to set it to the opposite of what
+    // the existing setting is. The test for isCellularIdentifierTransparencyEnabled should check
+    // for the right default value.
+    bool valueToSet = !originalTransparencySetting;
+    serial = GetRandomSerialNumber();
+    radio_network->setCellularIdentifierTransparencyEnabled(serial, valueToSet);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
+
+    ASSERT_TRUE(CheckAnyOfErrors(
+            radioRsp_network->rspInfo.error,
+            {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR}));
+
+    // Assert the value has changed
+    serial = GetRandomSerialNumber();
+    ndk::ScopedAStatus res = radio_network->isCellularIdentifierTransparencyEnabled(serial);
+
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
+    ASSERT_TRUE(CheckAnyOfErrors(
+            radioRsp_network->rspInfo.error,
+            {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR}));
+    EXPECT_EQ(valueToSet, radioRsp_network->isCellularIdentifierTransparencyEnabled);
+
+    // Reset original state
+    radio_network->setCellularIdentifierTransparencyEnabled(serial, originalTransparencySetting);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
+}
+
+/*
+ * Test IRadioNetwork.setSecurityAlgorithmsUpdatedEnabled for the response returned.
+ */
+TEST_P(RadioNetworkTest, setSecurityAlgorithmsUpdatedEnabled) {
+    int32_t aidl_version;
+    ndk::ScopedAStatus aidl_status = radio_network->getInterfaceVersion(&aidl_version);
+    ASSERT_OK(aidl_status);
+    if (aidl_version < 3) {
+        ALOGI("Skipped the test since"
+              " setSecurityAlgorithmsUpdatedEnabled is not supported on version < 3");
+        GTEST_SKIP();
+    }
+
+    // Get current value
+    serial = GetRandomSerialNumber();
+    radio_network->isSecurityAlgorithmsUpdatedEnabled(serial);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    bool originalSecuritySetting = radioRsp_network->isSecurityAlgorithmsUpdatedEnabled;
+
+    // We want to test flipping the value, so we are going to set it to the opposite of what
+    // the existing setting is. The test for isSecurityAlgorithmsUpdatedEnabled should check
+    // for the right default value.
+    bool valueToSet = !originalSecuritySetting;
+    serial = GetRandomSerialNumber();
+    radio_network->setSecurityAlgorithmsUpdatedEnabled(serial, valueToSet);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
+
+    ASSERT_TRUE(CheckAnyOfErrors(
+            radioRsp_network->rspInfo.error,
+            {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR}));
+
+    // Assert the value has changed
+    serial = GetRandomSerialNumber();
+    ndk::ScopedAStatus res = radio_network->isSecurityAlgorithmsUpdatedEnabled(serial);
+
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
+    ASSERT_TRUE(CheckAnyOfErrors(
+            radioRsp_network->rspInfo.error,
+            {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR}));
+    EXPECT_EQ(valueToSet, radioRsp_network->isSecurityAlgorithmsUpdatedEnabled);
+
+    // Reset original state
+    radio_network->setSecurityAlgorithmsUpdatedEnabled(serial, originalSecuritySetting);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
+}
+
+/**
+ * Test IRadioNetwork.isSecurityAlgorithmsUpdatedEnabled for the response returned.
+ */
+TEST_P(RadioNetworkTest, isSecurityAlgorithmsUpdatedEnabled) {
+    int32_t aidl_version;
+    ndk::ScopedAStatus aidl_status = radio_network->getInterfaceVersion(&aidl_version);
+    ASSERT_OK(aidl_status);
+    if (aidl_version < 3) {
+        ALOGI("Skipped the test since"
+              " isSecurityAlgorithmsUpdatedEnabled is not supported on version < 3");
+        GTEST_SKIP();
+    }
+
+    serial = GetRandomSerialNumber();
+
+    ndk::ScopedAStatus res = radio_network->isSecurityAlgorithmsUpdatedEnabled(serial);
+    ASSERT_OK(res);
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
+
+    ASSERT_TRUE(CheckAnyOfErrors(
+            radioRsp_network->rspInfo.error,
+            {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR}));
 }
diff --git a/radio/aidl/vts/radio_network_utils.h b/radio/aidl/vts/radio_network_utils.h
index 8f8f6b0..ad530eb 100644
--- a/radio/aidl/vts/radio_network_utils.h
+++ b/radio/aidl/vts/radio_network_utils.h
@@ -38,14 +38,16 @@
     RadioResponseInfo rspInfo;
     std::vector<RadioBandMode> radioBandModes;
     std::vector<OperatorInfo> networkInfos;
-    bool isNrDualConnectivityEnabled;
-    int networkTypeBitmapResponse;
+    bool isNrDualConnectivityEnabled = false;
+    int networkTypeBitmapResponse = 0;
     RegStateResult voiceRegResp;
     RegStateResult dataRegResp;
     CellIdentity barringCellIdentity;
     std::vector<BarringInfo> barringInfoList;
     UsageSetting usageSetting;
     std::vector<RadioAccessSpecifier> specifiers;
+    bool isCellularIdentifierTransparencyEnabled = false;
+    bool isSecurityAlgorithmsUpdatedEnabled = false;
 
     virtual ndk::ScopedAStatus acknowledgeRequest(int32_t serial) override;
 
@@ -169,6 +171,18 @@
             const RadioResponseInfo& info, bool isEnabled) override;
 
     virtual ndk::ScopedAStatus setN1ModeEnabledResponse(const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus setCellularIdentifierTransparencyEnabledResponse(
+            const RadioResponseInfo& info) override;
+
+    virtual ndk::ScopedAStatus isCellularIdentifierTransparencyEnabledResponse(
+            const RadioResponseInfo& info, bool /*enabled*/) override;
+
+    virtual ndk::ScopedAStatus isSecurityAlgorithmsUpdatedEnabledResponse(
+            const RadioResponseInfo& info, bool isEnabled) override;
+
+    virtual ndk::ScopedAStatus setSecurityAlgorithmsUpdatedEnabledResponse(
+            const RadioResponseInfo& info) override;
 };
 
 /* Callback class for radio network indication */
@@ -226,6 +240,13 @@
 
     virtual ndk::ScopedAStatus emergencyNetworkScanResult(
             RadioIndicationType type, const EmergencyRegResult& result) override;
+
+    virtual ndk::ScopedAStatus cellularIdentifierDisclosed(
+            RadioIndicationType type, const CellularIdentifierDisclosure& disclosures) override;
+
+    virtual ndk::ScopedAStatus securityAlgorithmsUpdated(
+            RadioIndicationType type,
+            const SecurityAlgorithmUpdate& securityAlgorithmUpdate) override;
 };
 
 // The main test class for Radio AIDL Network.
diff --git a/radio/aidl/vts/radio_sap_test.cpp b/radio/aidl/vts/radio_sap_test.cpp
index 9a1c145..6d283e9 100644
--- a/radio/aidl/vts/radio_sap_test.cpp
+++ b/radio/aidl/vts/radio_sap_test.cpp
@@ -85,6 +85,13 @@
  * Test ISap.connectReq() for the response returned.
  */
 TEST_P(SapTest, connectReq) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
+            GTEST_SKIP() << "Skipping connectReq "
+                            "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     int32_t maxMsgSize = 100;
 
@@ -103,6 +110,13 @@
  * Test ISap.disconnectReq() for the response returned
  */
 TEST_P(SapTest, disconnectReq) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
+            GTEST_SKIP() << "Skipping disconnectReq "
+                            "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     ndk::ScopedAStatus res = sap->disconnectReq(serial);
@@ -116,6 +130,13 @@
  * Test ISap.apduReq() for the response returned.
  */
 TEST_P(SapTest, apduReq) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
+            GTEST_SKIP() << "Skipping apduReq "
+                            "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     SapApduType sapApduType = SapApduType::APDU;
     std::vector<uint8_t> command = {};
@@ -137,6 +158,13 @@
  * Test ISap.transferAtrReq() for the response returned.
  */
 TEST_P(SapTest, transferAtrReq) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
+            GTEST_SKIP() << "Skipping transferAtrReq "
+                            "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     ndk::ScopedAStatus res = sap->transferAtrReq(serial);
@@ -155,6 +183,13 @@
  * Test ISap.powerReq() for the response returned.
  */
 TEST_P(SapTest, powerReq) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
+            GTEST_SKIP() << "Skipping powerReq "
+                            "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     bool state = true;
 
@@ -175,6 +210,13 @@
  * Test ISap.resetSimReq() for the response returned.
  */
 TEST_P(SapTest, resetSimReq) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
+            GTEST_SKIP() << "Skipping resetSimReq "
+                            "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     ndk::ScopedAStatus res = sap->resetSimReq(serial);
@@ -194,6 +236,13 @@
  * Test ISap.transferCardReaderStatusReq() for the response returned.
  */
 TEST_P(SapTest, transferCardReaderStatusReq) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
+            GTEST_SKIP() << "Skipping transferCardReaderStatusReq "
+                            "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     ndk::ScopedAStatus res = sap->transferCardReaderStatusReq(serial);
@@ -211,6 +260,13 @@
  * Test ISap.setTransferProtocolReq() for the response returned.
  */
 TEST_P(SapTest, setTransferProtocolReq) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
+            GTEST_SKIP() << "Skipping setTransferProtocolReq "
+                            "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     SapTransferProtocol sapTransferProtocol = SapTransferProtocol::T0;
 
diff --git a/radio/aidl/vts/radio_sim_test.cpp b/radio/aidl/vts/radio_sim_test.cpp
index d906588..06654c2 100644
--- a/radio/aidl/vts/radio_sim_test.cpp
+++ b/radio/aidl/vts/radio_sim_test.cpp
@@ -65,6 +65,13 @@
  * Test IRadioSim.setSimCardPower() for the response returned.
  */
 TEST_P(RadioSimTest, setSimCardPower) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
+            GTEST_SKIP() << "Skipping setSimCardPower "
+                            "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
+        }
+    }
+
     /* Test setSimCardPower power down */
     serial = GetRandomSerialNumber();
     radio_sim->setSimCardPower(serial, CardPowerState::POWER_DOWN);
@@ -120,6 +127,13 @@
  * Test IRadioSim.setCarrierInfoForImsiEncryption() for the response returned.
  */
 TEST_P(RadioSimTest, setCarrierInfoForImsiEncryption) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
+            GTEST_SKIP() << "Skipping setCarrierInfoForImsiEncryption "
+                            "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     ImsiEncryptionInfo imsiInfo;
     imsiInfo.mcc = "310";
@@ -144,6 +158,13 @@
  * Test IRadioSim.getSimPhonebookRecords() for the response returned.
  */
 TEST_P(RadioSimTest, getSimPhonebookRecords) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
+            GTEST_SKIP() << "Skipping getSimPhonebookRecords "
+                            "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     radio_sim->getSimPhonebookRecords(serial);
     EXPECT_EQ(std::cv_status::no_timeout, wait());
@@ -167,6 +188,13 @@
  * Test IRadioSim.getSimPhonebookCapacity for the response returned.
  */
 TEST_P(RadioSimTest, getSimPhonebookCapacity) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
+            GTEST_SKIP() << "Skipping getSimPhonebookCapacity "
+                            "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     radio_sim->getSimPhonebookCapacity(serial);
     EXPECT_EQ(std::cv_status::no_timeout, wait());
@@ -207,6 +235,13 @@
  * Test IRadioSim.updateSimPhonebookRecords() for the response returned.
  */
 TEST_P(RadioSimTest, updateSimPhonebookRecords) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
+            GTEST_SKIP() << "Skipping updateSimPhonebookRecords "
+                            "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     radio_sim->getSimPhonebookCapacity(serial);
     EXPECT_EQ(std::cv_status::no_timeout, wait());
@@ -271,6 +306,13 @@
  * For SIM ABSENT case.
  */
 TEST_P(RadioSimTest, togglingUiccApplicationsSimAbsent) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
+            GTEST_SKIP() << "Skipping togglingUiccApplicationsSimAbsent "
+                            "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
+        }
+    }
+
     // This test case only test SIM ABSENT case.
     if (cardStatus.cardState != CardStatus::STATE_ABSENT) return;
 
@@ -298,6 +340,13 @@
  * For SIM PRESENT case.
  */
 TEST_P(RadioSimTest, togglingUiccApplicationsSimPresent) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
+            GTEST_SKIP() << "Skipping togglingUiccApplicationsSimPresent "
+                            "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
+        }
+    }
+
     // This test case only test SIM ABSENT case.
     if (cardStatus.cardState != CardStatus::STATE_PRESENT) return;
     if (cardStatus.applications.size() == 0) return;
@@ -345,6 +394,13 @@
  * Test IRadioSim.areUiccApplicationsEnabled() for the response returned.
  */
 TEST_P(RadioSimTest, areUiccApplicationsEnabled) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
+            GTEST_SKIP() << "Skipping areUiccApplicationsEnabled "
+                            "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
+        }
+    }
+
     // Disable Uicc applications.
     serial = GetRandomSerialNumber();
     radio_sim->areUiccApplicationsEnabled(serial);
@@ -365,6 +421,13 @@
  * Test IRadioSim.getAllowedCarriers() for the response returned.
  */
 TEST_P(RadioSimTest, getAllowedCarriers) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
+            GTEST_SKIP() << "Skipping getAllowedCarriers "
+                            "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_sim->getAllowedCarriers(serial);
@@ -380,6 +443,13 @@
  * Test IRadioSim.setAllowedCarriers() for the response returned.
  */
 TEST_P(RadioSimTest, setAllowedCarriers) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
+            GTEST_SKIP() << "Skipping setAllowedCarriers "
+                            "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     CarrierRestrictions carrierRestrictions;
     memset(&carrierRestrictions, 0, sizeof(carrierRestrictions));
@@ -479,6 +549,13 @@
  * Test IRadioSim.getIccCardStatus() for the response returned.
  */
 TEST_P(RadioSimTest, getIccCardStatus) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
+            GTEST_SKIP() << "Skipping getIccCardStatus "
+                            "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
+        }
+    }
+
     EXPECT_LE(cardStatus.applications.size(), RadioConst::CARD_MAX_APPS);
     EXPECT_LT(cardStatus.gsmUmtsSubscriptionAppIndex, RadioConst::CARD_MAX_APPS);
     EXPECT_LT(cardStatus.cdmaSubscriptionAppIndex, RadioConst::CARD_MAX_APPS);
@@ -489,6 +566,13 @@
  * Test IRadioSim.supplyIccPinForApp() for the response returned
  */
 TEST_P(RadioSimTest, supplyIccPinForApp) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
+            GTEST_SKIP() << "Skipping supplyIccPinForApp "
+                            "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     // Pass wrong password and check PASSWORD_INCORRECT returned for 3GPP and
@@ -514,6 +598,13 @@
  * Test IRadioSim.supplyIccPukForApp() for the response returned.
  */
 TEST_P(RadioSimTest, supplyIccPukForApp) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
+            GTEST_SKIP() << "Skipping supplyIccPukForApp "
+                            "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     // Pass wrong password and check PASSWORD_INCORRECT returned for 3GPP and
@@ -539,6 +630,13 @@
  * Test IRadioSim.supplyIccPin2ForApp() for the response returned.
  */
 TEST_P(RadioSimTest, supplyIccPin2ForApp) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
+            GTEST_SKIP() << "Skipping supplyIccPin2ForApp "
+                            "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     // Pass wrong password and check PASSWORD_INCORRECT returned for 3GPP and
@@ -565,6 +663,13 @@
  * Test IRadioSim.supplyIccPuk2ForApp() for the response returned.
  */
 TEST_P(RadioSimTest, supplyIccPuk2ForApp) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
+            GTEST_SKIP() << "Skipping supplyIccPuk2ForApp "
+                            "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     // Pass wrong password and check PASSWORD_INCORRECT returned for 3GPP and
@@ -590,6 +695,13 @@
  * Test IRadioSim.changeIccPinForApp() for the response returned.
  */
 TEST_P(RadioSimTest, changeIccPinForApp) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
+            GTEST_SKIP() << "Skipping changeIccPinForApp "
+                            "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     // Pass wrong password and check PASSWORD_INCORRECT returned for 3GPP and
@@ -615,6 +727,13 @@
  * Test IRadioSim.changeIccPin2ForApp() for the response returned.
  */
 TEST_P(RadioSimTest, changeIccPin2ForApp) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
+            GTEST_SKIP() << "Skipping changeIccPin2ForApp "
+                            "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     // Pass wrong password and check PASSWORD_INCORRECT returned for 3GPP and
@@ -641,6 +760,13 @@
  * Test IRadioSim.getImsiForApp() for the response returned.
  */
 TEST_P(RadioSimTest, getImsiForApp) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
+            GTEST_SKIP() << "Skipping getImsiForApp "
+                            "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     // Check success returned while getting imsi for 3GPP and 3GPP2 apps only
@@ -670,6 +796,13 @@
  * Test IRadioSim.iccIoForApp() for the response returned.
  */
 TEST_P(RadioSimTest, iccIoForApp) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
+            GTEST_SKIP() << "Skipping iccIoForApp "
+                            "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     for (int i = 0; i < (int)cardStatus.applications.size(); i++) {
@@ -695,6 +828,13 @@
  * Test IRadioSim.iccTransmitApduBasicChannel() for the response returned.
  */
 TEST_P(RadioSimTest, iccTransmitApduBasicChannel) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
+            GTEST_SKIP() << "Skipping iccTransmitApduBasicChannel "
+                            "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     SimApdu msg;
     memset(&msg, 0, sizeof(msg));
@@ -710,6 +850,13 @@
  * Test IRadioSim.iccOpenLogicalChannel() for the response returned.
  */
 TEST_P(RadioSimTest, iccOpenLogicalChannel) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
+            GTEST_SKIP() << "Skipping iccOpenLogicalChannel "
+                            "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     int p2 = 0x04;
     // Specified in ISO 7816-4 clause 7.1.1 0x04 means that FCP template is requested.
@@ -725,6 +872,13 @@
  * Test IRadioSim.iccCloseLogicalChannel() for the response returned.
  */
 TEST_P(RadioSimTest, iccCloseLogicalChannel) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
+            GTEST_SKIP() << "Skipping iccCloseLogicalChannel "
+                            "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     // Try closing invalid channel and check INVALID_ARGUMENTS returned as error
     radio_sim->iccCloseLogicalChannel(serial, 0);
@@ -739,6 +893,13 @@
  * Test IRadioSim.iccCloseLogicalChannelWithSessionInfo() for the response returned.
  */
 TEST_P(RadioSimTest, iccCloseLogicalChannelWithSessionInfo) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
+            GTEST_SKIP() << "Skipping iccCloseLogicalChannelWithSessionInfo "
+                            "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
+        }
+    }
+
     int32_t aidl_version;
     ndk::ScopedAStatus aidl_status = radio_sim->getInterfaceVersion(&aidl_version);
     ASSERT_OK(aidl_status);
@@ -766,6 +927,13 @@
  * Test IRadioSim.iccTransmitApduLogicalChannel() for the response returned.
  */
 TEST_P(RadioSimTest, iccTransmitApduLogicalChannel) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
+            GTEST_SKIP() << "Skipping iccTransmitApduLogicalChannel "
+                            "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     SimApdu msg;
     memset(&msg, 0, sizeof(msg));
@@ -781,6 +949,13 @@
  * Test IRadioSim.requestIccSimAuthentication() for the response returned.
  */
 TEST_P(RadioSimTest, requestIccSimAuthentication) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
+            GTEST_SKIP() << "Skipping requestIccSimAuthentication "
+                            "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     // Pass wrong challenge string and check RadioError::INVALID_ARGUMENTS
@@ -801,6 +976,13 @@
  * Test IRadioSim.getFacilityLockForApp() for the response returned.
  */
 TEST_P(RadioSimTest, getFacilityLockForApp) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
+            GTEST_SKIP() << "Skipping getFacilityLockForApp "
+                            "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     std::string facility = "";
     std::string password = "";
@@ -824,6 +1006,13 @@
  * Test IRadioSim.setFacilityLockForApp() for the response returned.
  */
 TEST_P(RadioSimTest, setFacilityLockForApp) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
+            GTEST_SKIP() << "Skipping setFacilityLockForApp "
+                            "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     std::string facility = "";
     bool lockState = false;
@@ -848,6 +1037,13 @@
  * Test IRadioSim.getCdmaSubscription() for the response returned.
  */
 TEST_P(RadioSimTest, getCdmaSubscription) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
+            GTEST_SKIP() << "Skipping getCdmaSubscription "
+                            "due to undefined FEATURE_TELEPHONY_CDMA";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_sim->getCdmaSubscription(serial);
@@ -866,6 +1062,13 @@
  * Test IRadioSim.getCdmaSubscriptionSource() for the response returned.
  */
 TEST_P(RadioSimTest, getCdmaSubscriptionSource) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
+            GTEST_SKIP() << "Skipping getCdmaSubscriptionSource "
+                            "due to undefined FEATURE_TELEPHONY_CDMA";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_sim->getCdmaSubscriptionSource(serial);
@@ -884,6 +1087,13 @@
  * Test IRadioSim.setCdmaSubscriptionSource() for the response returned.
  */
 TEST_P(RadioSimTest, setCdmaSubscriptionSource) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
+            GTEST_SKIP() << "Skipping setCdmaSubscriptionSource "
+                            "due to undefined FEATURE_TELEPHONY_CDMA";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_sim->setCdmaSubscriptionSource(serial, CdmaSubscriptionSource::RUIM_SIM);
@@ -903,6 +1113,13 @@
  * Test IRadioSim.setUiccSubscription() for the response returned.
  */
 TEST_P(RadioSimTest, setUiccSubscription) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
+            GTEST_SKIP() << "Skipping setUiccSubscription "
+                            "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     SelectUiccSub item;
     memset(&item, 0, sizeof(item));
@@ -925,6 +1142,13 @@
  * Test IRadioSim.sendEnvelope() for the response returned.
  */
 TEST_P(RadioSimTest, sendEnvelope) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
+            GTEST_SKIP() << "Skipping sendEnvelope "
+                            "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     // Test with sending empty string
@@ -948,6 +1172,13 @@
  * Test IRadioSim.sendTerminalResponseToSim() for the response returned.
  */
 TEST_P(RadioSimTest, sendTerminalResponseToSim) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
+            GTEST_SKIP() << "Skipping sendTerminalResponseToSim "
+                            "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     // Test with sending empty string
@@ -971,6 +1202,13 @@
  * Test IRadioSim.reportStkServiceIsRunning() for the response returned.
  */
 TEST_P(RadioSimTest, reportStkServiceIsRunning) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
+            GTEST_SKIP() << "Skipping reportStkServiceIsRunning "
+                            "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_sim->reportStkServiceIsRunning(serial);
@@ -990,6 +1228,13 @@
  * string.
  */
 TEST_P(RadioSimTest, sendEnvelopeWithStatus) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
+            GTEST_SKIP() << "Skipping sendEnvelopeWithStatus "
+                            "due to undefined FEATURE_TELEPHONY_SUBSCRIPTION";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     // Test with sending empty string
diff --git a/radio/aidl/vts/radio_voice_test.cpp b/radio/aidl/vts/radio_voice_test.cpp
index 397c417..6c68fd5 100644
--- a/radio/aidl/vts/radio_voice_test.cpp
+++ b/radio/aidl/vts/radio_voice_test.cpp
@@ -93,15 +93,22 @@
  * Test IRadioVoice.emergencyDial() for the response returned.
  */
 TEST_P(RadioVoiceTest, emergencyDial) {
-    if (!deviceSupportsFeature(FEATURE_VOICE_CALL)) {
-        ALOGI("Skipping emergencyDial because voice call is not supported in device");
-        return;
-    } else if (!deviceSupportsFeature(FEATURE_TELEPHONY_GSM) &&
-               !deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
-        ALOGI("Skipping emergencyDial because gsm/cdma radio is not supported in device");
-        return;
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CALLING)) {
+            GTEST_SKIP() << "Skipping emergencyDial "
+                            "due to undefined FEATURE_TELEPHONY_CALLING";
+        }
     } else {
-        ALOGI("Running emergencyDial because voice call is supported in device");
+        if (!deviceSupportsFeature(FEATURE_VOICE_CALL)) {
+            ALOGI("Skipping emergencyDial because voice call is not supported in device");
+            return;
+        } else if (!deviceSupportsFeature(FEATURE_TELEPHONY_GSM) &&
+                   !deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
+            ALOGI("Skipping emergencyDial because gsm/cdma radio is not supported in device");
+            return;
+        } else {
+            ALOGI("Running emergencyDial because voice call is supported in device");
+        }
     }
 
     serial = GetRandomSerialNumber();
@@ -147,15 +154,22 @@
  * Test IRadioVoice.emergencyDial() with specified service and its response returned.
  */
 TEST_P(RadioVoiceTest, emergencyDial_withServices) {
-    if (!deviceSupportsFeature(FEATURE_VOICE_CALL)) {
-        ALOGI("Skipping emergencyDial because voice call is not supported in device");
-        return;
-    } else if (!deviceSupportsFeature(FEATURE_TELEPHONY_GSM) &&
-               !deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
-        ALOGI("Skipping emergencyDial because gsm/cdma radio is not supported in device");
-        return;
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CALLING)) {
+            GTEST_SKIP() << "Skipping emergencyDial_withServices "
+                            "due to undefined FEATURE_TELEPHONY_CALLING";
+        }
     } else {
-        ALOGI("Running emergencyDial because voice call is supported in device");
+        if (!deviceSupportsFeature(FEATURE_VOICE_CALL)) {
+            ALOGI("Skipping emergencyDial because voice call is not supported in device");
+            return;
+        } else if (!deviceSupportsFeature(FEATURE_TELEPHONY_GSM) &&
+                   !deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
+            ALOGI("Skipping emergencyDial because gsm/cdma radio is not supported in device");
+            return;
+        } else {
+            ALOGI("Running emergencyDial because voice call is supported in device");
+        }
     }
 
     serial = GetRandomSerialNumber();
@@ -201,15 +215,22 @@
  * Test IRadioVoice.emergencyDial() with known emergency call routing and its response returned.
  */
 TEST_P(RadioVoiceTest, emergencyDial_withEmergencyRouting) {
-    if (!deviceSupportsFeature(FEATURE_VOICE_CALL)) {
-        ALOGI("Skipping emergencyDial because voice call is not supported in device");
-        return;
-    } else if (!deviceSupportsFeature(FEATURE_TELEPHONY_GSM) &&
-               !deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
-        ALOGI("Skipping emergencyDial because gsm/cdma radio is not supported in device");
-        return;
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CALLING)) {
+            GTEST_SKIP() << "Skipping emergencyDial_withEmergencyRouting "
+                            "due to undefined FEATURE_TELEPHONY_CALLING";
+        }
     } else {
-        ALOGI("Running emergencyDial because voice call is supported in device");
+        if (!deviceSupportsFeature(FEATURE_VOICE_CALL)) {
+            ALOGI("Skipping emergencyDial because voice call is not supported in device");
+            return;
+        } else if (!deviceSupportsFeature(FEATURE_TELEPHONY_GSM) &&
+                   !deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
+            ALOGI("Skipping emergencyDial because gsm/cdma radio is not supported in device");
+            return;
+        } else {
+            ALOGI("Running emergencyDial because voice call is supported in device");
+        }
     }
 
     serial = GetRandomSerialNumber();
@@ -256,6 +277,13 @@
  * Test IRadioVoice.getCurrentCalls() for the response returned.
  */
 TEST_P(RadioVoiceTest, getCurrentCalls) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CALLING)) {
+            GTEST_SKIP() << "Skipping getCurrentCalls "
+                            "due to undefined FEATURE_TELEPHONY_CALLING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     radio_voice->getCurrentCalls(serial);
     EXPECT_EQ(std::cv_status::no_timeout, wait());
@@ -268,6 +296,13 @@
  * Test IRadioVoice.getClir() for the response returned.
  */
 TEST_P(RadioVoiceTest, getClir) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CALLING)) {
+            GTEST_SKIP() << "Skipping getClir "
+                            "due to undefined FEATURE_TELEPHONY_CALLING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_voice->getClir(serial);
@@ -286,6 +321,13 @@
  * Test IRadioVoice.setClir() for the response returned.
  */
 TEST_P(RadioVoiceTest, setClir) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CALLING)) {
+            GTEST_SKIP() << "Skipping setClir "
+                            "due to undefined FEATURE_TELEPHONY_CALLING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     int32_t status = 1;
 
@@ -304,6 +346,13 @@
  * Test IRadioVoice.getClip() for the response returned.
  */
 TEST_P(RadioVoiceTest, getClip) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CALLING)) {
+            GTEST_SKIP() << "Skipping getClip "
+                            "due to undefined FEATURE_TELEPHONY_CALLING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_voice->getClip(serial);
@@ -322,6 +371,13 @@
  * Test IRadioVoice.getTtyMode() for the response returned.
  */
 TEST_P(RadioVoiceTest, getTtyMode) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CALLING)) {
+            GTEST_SKIP() << "Skipping getTtyMode "
+                            "due to undefined FEATURE_TELEPHONY_CALLING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_voice->getTtyMode(serial);
@@ -338,6 +394,13 @@
  * Test IRadioVoice.setTtyMode() for the response returned.
  */
 TEST_P(RadioVoiceTest, setTtyMode) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CALLING)) {
+            GTEST_SKIP() << "Skipping setTtyMode "
+                            "due to undefined FEATURE_TELEPHONY_CALLING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_voice->setTtyMode(serial, TtyMode::OFF);
@@ -354,6 +417,13 @@
  * Test IRadioVoice.setPreferredVoicePrivacy() for the response returned.
  */
 TEST_P(RadioVoiceTest, setPreferredVoicePrivacy) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CALLING)) {
+            GTEST_SKIP() << "Skipping setPreferredVoicePrivacy "
+                            "due to undefined FEATURE_TELEPHONY_CALLING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_voice->setPreferredVoicePrivacy(serial, true);
@@ -371,6 +441,13 @@
  * Test IRadioVoice.getPreferredVoicePrivacy() for the response returned.
  */
 TEST_P(RadioVoiceTest, getPreferredVoicePrivacy) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CALLING)) {
+            GTEST_SKIP() << "Skipping getPreferredVoicePrivacy "
+                            "due to undefined FEATURE_TELEPHONY_CALLING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_voice->getPreferredVoicePrivacy(serial);
@@ -388,6 +465,13 @@
  * Test IRadioVoice.exitEmergencyCallbackMode() for the response returned.
  */
 TEST_P(RadioVoiceTest, exitEmergencyCallbackMode) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CALLING)) {
+            GTEST_SKIP() << "Skipping exitEmergencyCallbackMode "
+                            "due to undefined FEATURE_TELEPHONY_CALLING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_voice->exitEmergencyCallbackMode(serial);
@@ -406,6 +490,13 @@
  * Test IRadioVoice.handleStkCallSetupRequestFromSim() for the response returned.
  */
 TEST_P(RadioVoiceTest, handleStkCallSetupRequestFromSim) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CALLING)) {
+            GTEST_SKIP() << "Skipping handleStkCallSetupRequestFromSim "
+                            "due to undefined FEATURE_TELEPHONY_CALLING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     bool accept = false;
 
@@ -427,6 +518,13 @@
  * Test IRadioVoice.dial() for the response returned.
  */
 TEST_P(RadioVoiceTest, dial) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CALLING)) {
+            GTEST_SKIP() << "Skipping dial "
+                            "due to undefined FEATURE_TELEPHONY_CALLING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     Dial dialInfo;
@@ -454,6 +552,13 @@
  * Test IRadioVoice.hangup() for the response returned.
  */
 TEST_P(RadioVoiceTest, hangup) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CALLING)) {
+            GTEST_SKIP() << "Skipping hangup "
+                            "due to undefined FEATURE_TELEPHONY_CALLING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_voice->hangup(serial, 1);
@@ -473,6 +578,13 @@
  * Test IRadioVoice.hangupWaitingOrBackground() for the response returned.
  */
 TEST_P(RadioVoiceTest, hangupWaitingOrBackground) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CALLING)) {
+            GTEST_SKIP() << "Skipping hangupWaitingOrBackground "
+                            "due to undefined FEATURE_TELEPHONY_CALLING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_voice->hangupWaitingOrBackground(serial);
@@ -491,6 +603,13 @@
  * Test IRadioVoice.hangupForegroundResumeBackground() for the response returned.
  */
 TEST_P(RadioVoiceTest, hangupForegroundResumeBackground) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CALLING)) {
+            GTEST_SKIP() << "Skipping hangupForegroundResumeBackground "
+                            "due to undefined FEATURE_TELEPHONY_CALLING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_voice->hangupForegroundResumeBackground(serial);
@@ -509,6 +628,13 @@
  * Test IRadioVoice.switchWaitingOrHoldingAndActive() for the response returned.
  */
 TEST_P(RadioVoiceTest, switchWaitingOrHoldingAndActive) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CALLING)) {
+            GTEST_SKIP() << "Skipping switchWaitingOrHoldingAndActive "
+                            "due to undefined FEATURE_TELEPHONY_CALLING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_voice->switchWaitingOrHoldingAndActive(serial);
@@ -527,6 +653,13 @@
  * Test IRadioVoice.conference() for the response returned.
  */
 TEST_P(RadioVoiceTest, conference) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CALLING)) {
+            GTEST_SKIP() << "Skipping conference "
+                            "due to undefined FEATURE_TELEPHONY_CALLING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_voice->conference(serial);
@@ -545,6 +678,13 @@
  * Test IRadioVoice.rejectCall() for the response returned.
  */
 TEST_P(RadioVoiceTest, rejectCall) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CALLING)) {
+            GTEST_SKIP() << "Skipping rejectCall "
+                            "due to undefined FEATURE_TELEPHONY_CALLING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_voice->rejectCall(serial);
@@ -563,6 +703,13 @@
  * Test IRadioVoice.getLastCallFailCause() for the response returned.
  */
 TEST_P(RadioVoiceTest, getLastCallFailCause) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CALLING)) {
+            GTEST_SKIP() << "Skipping getLastCallFailCause "
+                            "due to undefined FEATURE_TELEPHONY_CALLING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_voice->getLastCallFailCause(serial);
@@ -580,6 +727,13 @@
  * Test IRadioVoice.getCallForwardStatus() for the response returned.
  */
 TEST_P(RadioVoiceTest, getCallForwardStatus) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CALLING)) {
+            GTEST_SKIP() << "Skipping getCallForwardStatus "
+                            "due to undefined FEATURE_TELEPHONY_CALLING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     CallForwardInfo callInfo;
     memset(&callInfo, 0, sizeof(callInfo));
@@ -602,6 +756,13 @@
  * Test IRadioVoice.setCallForward() for the response returned.
  */
 TEST_P(RadioVoiceTest, setCallForward) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CALLING)) {
+            GTEST_SKIP() << "Skipping setCallForward "
+                            "due to undefined FEATURE_TELEPHONY_CALLING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     CallForwardInfo callInfo;
     memset(&callInfo, 0, sizeof(callInfo));
@@ -624,6 +785,13 @@
  * Test IRadioVoice.getCallWaiting() for the response returned.
  */
 TEST_P(RadioVoiceTest, getCallWaiting) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CALLING)) {
+            GTEST_SKIP() << "Skipping getCallWaiting "
+                            "due to undefined FEATURE_TELEPHONY_CALLING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_voice->getCallWaiting(serial, 1);
@@ -643,6 +811,13 @@
  * Test IRadioVoice.setCallWaiting() for the response returned.
  */
 TEST_P(RadioVoiceTest, setCallWaiting) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CALLING)) {
+            GTEST_SKIP() << "Skipping setCallWaiting "
+                            "due to undefined FEATURE_TELEPHONY_CALLING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_voice->setCallWaiting(serial, true, 1);
@@ -662,6 +837,13 @@
  * Test IRadioVoice.acceptCall() for the response returned.
  */
 TEST_P(RadioVoiceTest, acceptCall) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CALLING)) {
+            GTEST_SKIP() << "Skipping acceptCall "
+                            "due to undefined FEATURE_TELEPHONY_CALLING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_voice->acceptCall(serial);
@@ -680,6 +862,13 @@
  * Test IRadioVoice.separateConnection() for the response returned.
  */
 TEST_P(RadioVoiceTest, separateConnection) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CALLING)) {
+            GTEST_SKIP() << "Skipping separateConnection "
+                            "due to undefined FEATURE_TELEPHONY_CALLING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_voice->separateConnection(serial, 1);
@@ -699,6 +888,13 @@
  * Test IRadioVoice.explicitCallTransfer() for the response returned.
  */
 TEST_P(RadioVoiceTest, explicitCallTransfer) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CALLING)) {
+            GTEST_SKIP() << "Skipping explicitCallTransfer "
+                            "due to undefined FEATURE_TELEPHONY_CALLING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_voice->explicitCallTransfer(serial);
@@ -717,6 +913,13 @@
  * Test IRadioVoice.sendCdmaFeatureCode() for the response returned.
  */
 TEST_P(RadioVoiceTest, sendCdmaFeatureCode) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) {
+            GTEST_SKIP() << "Skipping sendCdmaFeatureCode "
+                            "due to undefined FEATURE_TELEPHONY_CDMA";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_voice->sendCdmaFeatureCode(serial, std::string());
@@ -737,6 +940,13 @@
  * Test IRadioVoice.sendDtmf() for the response returned.
  */
 TEST_P(RadioVoiceTest, sendDtmf) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CALLING)) {
+            GTEST_SKIP() << "Skipping sendDtmf "
+                            "due to undefined FEATURE_TELEPHONY_CALLING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_voice->sendDtmf(serial, "1");
@@ -757,6 +967,13 @@
  * Test IRadioVoice.startDtmf() for the response returned.
  */
 TEST_P(RadioVoiceTest, startDtmf) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CALLING)) {
+            GTEST_SKIP() << "Skipping startDtmf "
+                            "due to undefined FEATURE_TELEPHONY_CALLING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_voice->startDtmf(serial, "1");
@@ -777,6 +994,13 @@
  * Test IRadioVoice.stopDtmf() for the response returned.
  */
 TEST_P(RadioVoiceTest, stopDtmf) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CALLING)) {
+            GTEST_SKIP() << "Skipping stopDtmf "
+                            "due to undefined FEATURE_TELEPHONY_CALLING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_voice->stopDtmf(serial);
@@ -796,6 +1020,13 @@
  * Test IRadioVoice.setMute() for the response returned.
  */
 TEST_P(RadioVoiceTest, setMute) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CALLING)) {
+            GTEST_SKIP() << "Skipping setMute "
+                            "due to undefined FEATURE_TELEPHONY_CALLING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_voice->setMute(serial, true);
@@ -814,6 +1045,13 @@
  * Test IRadioVoice.getMute() for the response returned.
  */
 TEST_P(RadioVoiceTest, getMute) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CALLING)) {
+            GTEST_SKIP() << "Skipping getMute "
+                            "due to undefined FEATURE_TELEPHONY_CALLING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_voice->getMute(serial);
@@ -830,6 +1068,13 @@
  * Test IRadioVoice.sendBurstDtmf() for the response returned.
  */
 TEST_P(RadioVoiceTest, sendBurstDtmf) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CALLING)) {
+            GTEST_SKIP() << "Skipping sendBurstDtmf "
+                            "due to undefined FEATURE_TELEPHONY_CALLING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_voice->sendBurstDtmf(serial, "1", 0, 0);
@@ -849,6 +1094,13 @@
  * Test IRadioVoice.sendUssd() for the response returned.
  */
 TEST_P(RadioVoiceTest, sendUssd) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CALLING)) {
+            GTEST_SKIP() << "Skipping sendUssd "
+                            "due to undefined FEATURE_TELEPHONY_CALLING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
     radio_voice->sendUssd(serial, std::string("test"));
     EXPECT_EQ(std::cv_status::no_timeout, wait());
@@ -867,6 +1119,13 @@
  * Test IRadioVoice.cancelPendingUssd() for the response returned.
  */
 TEST_P(RadioVoiceTest, cancelPendingUssd) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_CALLING)) {
+            GTEST_SKIP() << "Skipping cancelPendingUssd "
+                            "due to undefined FEATURE_TELEPHONY_CALLING";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_voice->cancelPendingUssd(serial);
@@ -886,6 +1145,13 @@
  * Test IRadioVoice.isVoNrEnabled() for the response returned.
  */
 TEST_P(RadioVoiceTest, isVoNrEnabled) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_IMS)) {
+            GTEST_SKIP() << "Skipping isVoNrEnabled "
+                            "due to undefined FEATURE_TELEPHONY_IMS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_voice->isVoNrEnabled(serial);
@@ -901,6 +1167,13 @@
  * Test IRadioVoice.setVoNrEnabled() for the response returned.
  */
 TEST_P(RadioVoiceTest, setVoNrEnabled) {
+    if (telephony_flags::enforce_telephony_feature_mapping()) {
+        if (!deviceSupportsFeature(FEATURE_TELEPHONY_IMS)) {
+            GTEST_SKIP() << "Skipping setVoNrEnabled "
+                            "due to undefined FEATURE_TELEPHONY_IMS";
+        }
+    }
+
     serial = GetRandomSerialNumber();
 
     radio_voice->setVoNrEnabled(serial, true);
diff --git a/radio/config/1.0/vts/functional/OWNERS b/radio/config/1.0/vts/functional/OWNERS
deleted file mode 100644
index badd6d7..0000000
--- a/radio/config/1.0/vts/functional/OWNERS
+++ /dev/null
@@ -1,6 +0,0 @@
-# Bug component: 20868
-jminjie@google.com
-sarahchin@google.com
-amitmahajan@google.com
-shuoq@google.com
-jackyu@google.com
diff --git a/radio/config/1.1/vts/OWNERS b/radio/config/1.1/vts/OWNERS
deleted file mode 100644
index 4109967..0000000
--- a/radio/config/1.1/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 20868
-include /radio/1.0/vts/OWNERS
diff --git a/radio/config/1.2/vts/OWNERS b/radio/config/1.2/vts/OWNERS
deleted file mode 100644
index 4109967..0000000
--- a/radio/config/1.2/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 20868
-include /radio/1.0/vts/OWNERS
diff --git a/rebootescrow/OWNERS b/rebootescrow/OWNERS
new file mode 100644
index 0000000..c9701ff
--- /dev/null
+++ b/rebootescrow/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 63928581
+
+kroot@google.com
+paulcrowley@google.com
diff --git a/rebootescrow/aidl/default/Android.bp b/rebootescrow/aidl/default/Android.bp
index 4409314..7f9b6d6 100644
--- a/rebootescrow/aidl/default/Android.bp
+++ b/rebootescrow/aidl/default/Android.bp
@@ -42,10 +42,10 @@
 
 cc_binary {
     name: "android.hardware.rebootescrow-service.default",
-    init_rc: ["rebootescrow-default.rc"],
     relative_install_path: "hw",
-    vintf_fragments: ["rebootescrow-default.xml"],
     vendor: true,
+    installable: false, // installed in APEX
+
     srcs: [
         "service.cpp",
     ],
@@ -53,12 +53,14 @@
         "-Wall",
         "-Werror",
     ],
+    stl: "c++_static",
     shared_libs: [
-        "libbase",
         "libbinder_ndk",
-        "android.hardware.rebootescrow-V1-ndk",
+        "liblog",
     ],
     static_libs: [
+        "android.hardware.rebootescrow-V1-ndk",
+        "libbase",
         "libhadamardutils",
         "librebootescrowdefaultimpl",
     ],
@@ -97,3 +99,35 @@
     ],
     test_suites: ["device-tests"],
 }
+
+prebuilt_etc {
+    name: "rebootescrow-default.rc",
+    src: "rebootescrow-default.rc",
+    installable: false,
+}
+
+prebuilt_etc {
+    name: "rebootescrow-default.xml",
+    src: "rebootescrow-default.xml",
+    sub_dir: "vintf",
+    installable: false,
+}
+
+apex {
+    name: "com.android.hardware.rebootescrow",
+    manifest: "apex_manifest.json",
+    file_contexts: "apex_file_contexts",
+    key: "com.android.hardware.key",
+    certificate: ":com.android.hardware.certificate",
+    vendor: true,
+    updatable: false,
+
+    binaries: [
+        "android.hardware.rebootescrow-service.default",
+    ],
+    prebuilts: [
+        "rebootescrow-default.rc",
+        "rebootescrow-default.xml",
+        "android.hardware.reboot_escrow.prebuilt.xml", // <feature>
+    ],
+}
diff --git a/rebootescrow/aidl/default/OWNERS b/rebootescrow/aidl/default/OWNERS
deleted file mode 100644
index c5288d6..0000000
--- a/rebootescrow/aidl/default/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-kroot@google.com
-paulcrowley@google.com
diff --git a/rebootescrow/aidl/default/apex_file_contexts b/rebootescrow/aidl/default/apex_file_contexts
new file mode 100644
index 0000000..aa84984
--- /dev/null
+++ b/rebootescrow/aidl/default/apex_file_contexts
@@ -0,0 +1,3 @@
+(/.*)?                                                      u:object_r:vendor_file:s0
+/etc(/.*)?                                                  u:object_r:vendor_configs_file:s0
+/bin/hw/android\.hardware\.rebootescrow-service\.default    u:object_r:hal_rebootescrow_default_exec:s0
diff --git a/rebootescrow/aidl/default/apex_manifest.json b/rebootescrow/aidl/default/apex_manifest.json
new file mode 100644
index 0000000..8be495b
--- /dev/null
+++ b/rebootescrow/aidl/default/apex_manifest.json
@@ -0,0 +1,4 @@
+{
+    "name": "com.android.hardware.rebootescrow",
+    "version": 1
+}
\ No newline at end of file
diff --git a/rebootescrow/aidl/default/rebootescrow-default.rc b/rebootescrow/aidl/default/rebootescrow-default.rc
index ad90465..024dd6d 100644
--- a/rebootescrow/aidl/default/rebootescrow-default.rc
+++ b/rebootescrow/aidl/default/rebootescrow-default.rc
@@ -1,4 +1,4 @@
-service vendor.rebootescrow-default /vendor/bin/hw/android.hardware.rebootescrow-service.default
+service vendor.rebootescrow-default /apex/com.android.hardware.rebootescrow/bin/hw/android.hardware.rebootescrow-service.default
     interface aidl android.hardware.rebootescrow.IRebootEscrow/default
     class hal
     user system
diff --git a/rebootescrow/aidl/vts/OWNERS b/rebootescrow/aidl/vts/OWNERS
deleted file mode 100644
index c5288d6..0000000
--- a/rebootescrow/aidl/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-kroot@google.com
-paulcrowley@google.com
diff --git a/renderscript/1.0/default/Android.bp b/renderscript/1.0/default/Android.bp
index c68e370..23fa252 100644
--- a/renderscript/1.0/default/Android.bp
+++ b/renderscript/1.0/default/Android.bp
@@ -27,6 +27,12 @@
         "android.hardware.renderscript@1.0",
     ],
 
+    runtime_libs: [
+        "libRS_internal",
+        //TODO(b/313564579) Install libRSDriver as dependency of libRS_internal
+        "libRSDriver",
+    ],
+
     product_variables: {
         override_rs_driver: {
             cflags: ["-DOVERRIDE_RS_DRIVER=%s"],
diff --git a/renderscript/1.0/vts/functional/OWNERS b/renderscript/1.0/vts/functional/OWNERS
deleted file mode 100644
index d785790..0000000
--- a/renderscript/1.0/vts/functional/OWNERS
+++ /dev/null
@@ -1,6 +0,0 @@
-# Bug component: 43047
-butlermichael@google.com
-dgross@google.com
-jeanluc@google.com
-miaowang@google.com
-xusongw@google.com
diff --git a/renderscript/OWNERS b/renderscript/OWNERS
new file mode 100644
index 0000000..443ebff
--- /dev/null
+++ b/renderscript/OWNERS
@@ -0,0 +1,6 @@
+# Bug component: 43047
+
+butlermichael@google.com
+dgross@google.com
+miaowang@google.com
+xusongw@google.com
diff --git a/scripts/OWNERS b/scripts/OWNERS
new file mode 100644
index 0000000..a07824e
--- /dev/null
+++ b/scripts/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 298954331
+
+include platform/hardware/interfaces:/OWNERS
diff --git a/secure_element/1.0/vts/functional/VtsHalSecureElementV1_0TargetTest.cpp b/secure_element/1.0/vts/functional/VtsHalSecureElementV1_0TargetTest.cpp
index 63c2eca..1623960 100644
--- a/secure_element/1.0/vts/functional/VtsHalSecureElementV1_0TargetTest.cpp
+++ b/secure_element/1.0/vts/functional/VtsHalSecureElementV1_0TargetTest.cpp
@@ -75,6 +75,7 @@
         se_->init(se_cb_);
         auto res = se_cb_->WaitForCallback(kCallbackNameOnStateChange);
         EXPECT_TRUE(res.no_timeout);
+        ASSERT_TRUE(res.args);
         EXPECT_TRUE(res.args->state_);
     }
 
diff --git a/secure_element/1.1/vts/functional/VtsHalSecureElementV1_1TargetTest.cpp b/secure_element/1.1/vts/functional/VtsHalSecureElementV1_1TargetTest.cpp
index 234c33c..d7e4546 100644
--- a/secure_element/1.1/vts/functional/VtsHalSecureElementV1_1TargetTest.cpp
+++ b/secure_element/1.1/vts/functional/VtsHalSecureElementV1_1TargetTest.cpp
@@ -72,6 +72,7 @@
         se_->init_1_1(se_cb_);
         auto res = se_cb_->WaitForCallback(kCallbackNameOnStateChange);
         EXPECT_TRUE(res.no_timeout);
+        ASSERT_TRUE(res.args);
         EXPECT_TRUE(res.args->state_);
         EXPECT_NE(res.args->reason_, "");
     }
diff --git a/secure_element/1.2/vts/functional/VtsHalSecureElementV1_2TargetTest.cpp b/secure_element/1.2/vts/functional/VtsHalSecureElementV1_2TargetTest.cpp
index 66d581e..26b2ded 100644
--- a/secure_element/1.2/vts/functional/VtsHalSecureElementV1_2TargetTest.cpp
+++ b/secure_element/1.2/vts/functional/VtsHalSecureElementV1_2TargetTest.cpp
@@ -73,6 +73,7 @@
         se_->init_1_1(se_cb_);
         auto res = se_cb_->WaitForCallback(kCallbackNameOnStateChange);
         EXPECT_TRUE(res.no_timeout);
+        ASSERT_TRUE(res.args);
         EXPECT_TRUE(res.args->state_);
         EXPECT_NE(res.args->reason_, "");
     }
@@ -93,10 +94,12 @@
 
     auto res = se_cb_->WaitForCallback(kCallbackNameOnStateChange);
     EXPECT_TRUE(res.no_timeout);
+    ASSERT_TRUE(res.args);
     EXPECT_FALSE(res.args->state_);
 
     res = se_cb_->WaitForCallback(kCallbackNameOnStateChange);
     EXPECT_TRUE(res.no_timeout);
+    ASSERT_TRUE(res.args);
     EXPECT_TRUE(res.args->state_);
 }
 
diff --git a/secure_element/aidl/default/Android.bp b/secure_element/aidl/default/Android.bp
index d1bb393..b382822 100644
--- a/secure_element/aidl/default/Android.bp
+++ b/secure_element/aidl/default/Android.bp
@@ -11,14 +11,50 @@
     name: "android.hardware.secure_element-service.example",
     relative_install_path: "hw",
     vendor: true,
-    init_rc: ["secure_element.rc"],
-    vintf_fragments: ["secure_element.xml"],
+    installable: false, // installed in APEX
+
+    stl: "c++_static",
     shared_libs: [
-        "libbase",
         "libbinder_ndk",
+        "liblog",
+    ],
+    static_libs: [
         "android.hardware.secure_element-V1-ndk",
+        "libbase",
     ],
     srcs: [
         "main.cpp",
     ],
 }
+
+prebuilt_etc {
+    name: "secure_element.rc",
+    src: "secure_element.rc",
+    installable: false,
+}
+
+prebuilt_etc {
+    name: "secure_element.xml",
+    src: "secure_element.xml",
+    sub_dir: "vintf",
+    installable: false,
+}
+
+apex {
+    name: "com.android.hardware.secure_element",
+    manifest: "apex_manifest.json",
+    file_contexts: "apex_file_contexts",
+    key: "com.android.hardware.key",
+    certificate: ":com.android.hardware.certificate",
+    vendor: true,
+    updatable: false,
+
+    binaries: [
+        "android.hardware.secure_element-service.example",
+    ],
+    prebuilts: [
+        "secure_element.rc",
+        "secure_element.xml",
+        "android.hardware.se.omapi.ese.prebuilt.xml", // <feature>
+    ],
+}
diff --git a/secure_element/aidl/default/apex_file_contexts b/secure_element/aidl/default/apex_file_contexts
new file mode 100644
index 0000000..e9e811e
--- /dev/null
+++ b/secure_element/aidl/default/apex_file_contexts
@@ -0,0 +1,3 @@
+(/.*)?                                                      u:object_r:vendor_file:s0
+/etc(/.*)?                                                  u:object_r:vendor_configs_file:s0
+/bin/hw/android\.hardware\.secure_element-service\.example  u:object_r:hal_secure_element_default_exec:s0
\ No newline at end of file
diff --git a/secure_element/aidl/default/apex_manifest.json b/secure_element/aidl/default/apex_manifest.json
new file mode 100644
index 0000000..6e04c11
--- /dev/null
+++ b/secure_element/aidl/default/apex_manifest.json
@@ -0,0 +1,4 @@
+{
+    "name": "com.android.hardware.secure_element",
+    "version": 1
+}
\ No newline at end of file
diff --git a/secure_element/aidl/default/secure_element.rc b/secure_element/aidl/default/secure_element.rc
index 7d21666..b74b2ee 100644
--- a/secure_element/aidl/default/secure_element.rc
+++ b/secure_element/aidl/default/secure_element.rc
@@ -1,4 +1,4 @@
-service vendor.secure_element /vendor/bin/hw/android.hardware.secure_element-service.example
+service vendor.secure_element /apex/com.android.hardware.secure_element/bin/hw/android.hardware.secure_element-service.example
     class hal
     user nobody
     group nobody
diff --git a/secure_element/aidl/vts/AndroidTest.xml b/secure_element/aidl/vts/AndroidTest.xml
new file mode 100644
index 0000000..94dfa82
--- /dev/null
+++ b/secure_element/aidl/vts/AndroidTest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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 VtsHalSecureElementTargetTest.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+    <option name="config-descriptor:metadata" key="token" value="SECURE_ELEMENT_SIM_CARD" />
+
+    <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="VtsHalSecureElementTargetTest->/data/local/tmp/VtsHalSecureElementTargetTest" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="VtsHalSecureElementTargetTest" />
+    </test>
+</configuration>
diff --git a/security/README.md b/security/README.md
new file mode 100644
index 0000000..c5b5ba8
--- /dev/null
+++ b/security/README.md
@@ -0,0 +1,109 @@
+# Security-Related HALs
+
+The `security/` subdirectory holds various security-related HALs.  (The final two sections of this
+document also describe security-related HALs that are in other places under `hardware/interfaces/`.)
+
+The most significant HAL is KeyMint (**`IKeyMintDevice`** in the
+`hardware/interfaces/security/keymint/` directory), which allows access to cryptographic
+functionality where the key material is restricted to a secure environment.  This functionality is
+used by Android system services, and is also made available to apps via Android Keystore.
+
+A KeyMint implementation (or an implementation of its predecessor, Keymaster) that runs in an
+isolated execution environment (e.g. ARM TrustZone) is required for most Android devices; see [CDD
+9.11](https://source.android.com/docs/compatibility/13/android-13-cdd#911_keys_and_credentials).
+
+A device may optionally also support a second KeyMint instance, running in a dedicated secure
+processor; this is known as StrongBox ([CDD
+9.11.2](https://source.android.com/docs/compatibility/13/android-13-cdd#9112_strongbox)).
+
+Two specific features of KeyMint are worth highlighting, as they have an impact on the other
+security-related HALs:
+
+- KeyMint supports keys that can only be used when the operation is authenticated by the user,
+  either by their lock screen knowledge factor (LSKF, e.g. PIN or pattern) or by a strong biometric
+  (e.g. fingerprint).
+- KeyMint supports *attestation* of public keys: when an asymmetric keypair is created, the secure
+  environment produces a chain of signed certificates:
+  - starting from a trusted root certificate
+  - terminating in a leaf certificate that holds the public key; this leaf certificate may also
+    describe the state of the device and the policies attached to the key.
+
+## Authentication Verification
+
+User authentication must also take place in a secure environment (see the final section below), but
+the results of that authentication are communicated to KeyMint via Android.  As such, the
+authentication result (a *hardware auth token*) is signed with a per-boot shared HMAC key known only
+to the secure components, so that it's authenticity can be verified.
+
+If an authenticator, for example GateKeeper (described by the **`IGatekeeper`** HAL in
+`hardware/interfaces/gatekeeper/`), is co-located in the same secure environment as KeyMint, it can
+use a local, vendor-specific, method to communicate the shared HMAC key.
+
+However, if the authenticator is in a different environment than the KeyMint instance then a local
+communication mechanism may not be possible.  For example, a StrongBox KeyMint instance running in a
+separate secure processor may not have a communication channel with a TEE on the main processor.
+
+To allow for this, the **`ISharedSecret`** HAL (in `hardware/interfaces/security/sharedsecret`)
+describes an N-party shared key agreement protocol for per-boot derivation of the shared HMAC key,
+based on a pre-provisioned shared secret.  This HAL can be implemented by any security component
+&ndash; whether KeyMint instance or authenticator &ndash; that needs access to the shared HMAC key.
+
+User authentication operations are also timestamped, but a StrongBox KeyMint instance may not have
+access to a secure time source that is aligned with the authenticator's time source.
+
+To allow for this, the **`ISecureClock`** HAL (in `hardware/interfaces/secureclock`) describes a
+challenge-based timestamp authentication protocol.  This HAL is optional; it need only be
+implemented if there is a KeyMint instance without a secure source of time.
+
+## Attestation Key Provisioning
+
+As noted above, key generation may also generate an attestation certificate chain, which requires
+that the secure environment have access to a signing key which in turn chains back to the Google
+root.
+
+Historically these signing keys were created by Google and provided to vendors for installation in
+batches of devices (to prevent their use as unique device identifiers).  However, this mechanism had
+significant disadvantages, as it required secure handling of key material and only allowed for
+coarse-grained revocation.
+
+The remote key provisioning HAL (**`IRemotelyProvisionedComponent`** in
+`hardware/interfaces/security/rkp/`) provides a mechanism whereby signing certificates for
+attestation can be retrieved at runtime from Google servers based on pre-registered device identity
+information.  This mechanism is used to provision certificates for KeyMint's signing keys, but is
+not restricted to that purpose; it can also be used in other scenarios where keys need to be
+provisioned (for example, for [Widevine](https://developers.google.com/widevine/drm/overview)).
+
+## Keymaster
+
+The Keymaster HAL (**`IKeymasterDevice`** in `hardware/interfaces/keymaster/`) is the historical
+ancestor of many of the HALs here (and may still be present on older devices).  Its functionality is
+effectively the union of the following current HALs:
+
+- **`IKeyMintDevice`**
+- **`ISharedSecret`**
+- **`ISecureClock`**
+
+## Related Authentication HALs
+
+Authentication of users needs to happen in a secure environment, using vendor-specific
+functionality, and so involves the use of one of the following HALs (all of which are outside the
+`security/` subdirectory).
+
+- The **`IGatekeeper`** HAL (in `hardware/interfaces/gatekeeper/`) provides user authentication
+  functionality based on the user's lock-screen knowledge factor (LSKF), including throttling
+  behaviour to prevent attacks.  Authentication tokens produced by this HAL are consumed by KeyMint,
+  validated using the shared HMAC key described above.
+  - The optional **`IWeaver`** HAL (in `hardware/interfaces/weaver`) improves the security of LSKF
+    authentication by converting the user's LSKF into a *synthetic password* via hashing and
+    stretching. This is required to be implemented on a separate secure element, which prevents
+    offline attacks on Gatekeeper storage. Note that Weaver does not directly interact with KeyMint;
+    the synthetic password is fed into Gatekeeper in place of the plain user password, and then
+    Gatekeeper interacts with KeyMint as normal.
+- The **`IFingerprint`** and **`IFace`** HAL definitions (under `hardware/interfaces/biometrics/`)
+  allow access to biometric authentication functionality that is implemented in a secure
+  environment.  Authentication tokens produced by these HALs are consumed by KeyMint, validated
+  using the shared HMAC key described above.
+- The optional **`IConfirmationUI`** HAL (in `hardware/interfaces/confirmationui`) supports
+  functionality where the user confirms that they have seen a specific message in a secure manner.
+  Confirmation tokens produced by this HAL are consumed by KeyMint, validated using the shared HMAC
+  key described above.
diff --git a/security/authgraph/aidl/Android.bp b/security/authgraph/aidl/Android.bp
new file mode 100644
index 0000000..f3d1281
--- /dev/null
+++ b/security/authgraph/aidl/Android.bp
@@ -0,0 +1,88 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES 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.security.authgraph",
+    vendor_available: true,
+    srcs: [
+        "android/hardware/security/authgraph/*.aidl",
+    ],
+    stability: "vintf",
+    frozen: false,
+    backend: {
+        java: {
+            platform_apis: true,
+        },
+        ndk: {
+            enabled: true,
+        },
+        rust: {
+            enabled: true,
+            apex_available: [
+                "//apex_available:platform",
+                "com.android.virt",
+            ],
+        },
+    },
+}
+
+// cc_defaults that includes the latest Authgraph AIDL library.
+// Modules that depend on Authgraph directly can include this cc_defaults to avoid
+// managing dependency versions explicitly.
+cc_defaults {
+    name: "authgraph_use_latest_hal_aidl_ndk_static",
+    static_libs: [
+        "android.hardware.security.authgraph-V1-ndk",
+    ],
+}
+
+cc_defaults {
+    name: "authgraph_use_latest_hal_aidl_ndk_shared",
+    shared_libs: [
+        "android.hardware.security.authgraph-V1-ndk",
+    ],
+}
+
+cc_defaults {
+    name: "authgraph_use_latest_hal_aidl_cpp_static",
+    static_libs: [
+        "android.hardware.security.authgraph-V1-cpp",
+    ],
+}
+
+cc_defaults {
+    name: "authgraph_use_latest_hal_aidl_cpp_shared",
+    shared_libs: [
+        "android.hardware.security.authgraph-V1-cpp",
+    ],
+}
+
+// A rust_defaults that includes the latest Authgraph AIDL library.
+// Modules that depend on Authgraph directly can include this rust_defaults to avoid
+// managing dependency versions explicitly.
+rust_defaults {
+    name: "authgraph_use_latest_hal_aidl_rust",
+    rustlibs: [
+        "android.hardware.security.authgraph-V1-rust",
+    ],
+}
diff --git a/security/authgraph/aidl/aidl_api/android.hardware.security.authgraph/current/android/hardware/security/authgraph/Arc.aidl b/security/authgraph/aidl/aidl_api/android.hardware.security.authgraph/current/android/hardware/security/authgraph/Arc.aidl
new file mode 100644
index 0000000..dc86fbd
--- /dev/null
+++ b/security/authgraph/aidl/aidl_api/android.hardware.security.authgraph/current/android/hardware/security/authgraph/Arc.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.authgraph;
+/* @hide */
+@RustDerive(Clone=true, Eq=true, PartialEq=true) @VintfStability
+parcelable Arc {
+  byte[] arc;
+}
diff --git a/security/authgraph/aidl/aidl_api/android.hardware.security.authgraph/current/android/hardware/security/authgraph/Error.aidl b/security/authgraph/aidl/aidl_api/android.hardware.security.authgraph/current/android/hardware/security/authgraph/Error.aidl
new file mode 100644
index 0000000..1a78b54
--- /dev/null
+++ b/security/authgraph/aidl/aidl_api/android.hardware.security.authgraph/current/android/hardware/security/authgraph/Error.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.authgraph;
+/* @hide */
+@Backing(type="int") @VintfStability
+enum Error {
+  OK = 0,
+  INVALID_PEER_NONCE = (-1) /* -1 */,
+  INVALID_PEER_KE_KEY = (-2) /* -2 */,
+  INVALID_IDENTITY = (-3) /* -3 */,
+  INVALID_CERT_CHAIN = (-4) /* -4 */,
+  INVALID_SIGNATURE = (-5) /* -5 */,
+  INVALID_KE_KEY = (-6) /* -6 */,
+  INVALID_PUB_KEY_IN_KEY = (-7) /* -7 */,
+  INVALID_PRIV_KEY_ARC_IN_KEY = (-8) /* -8 */,
+  INVALID_SHARED_KEY_ARCS = (-9) /* -9 */,
+  MEMORY_ALLOCATION_FAILED = (-10) /* -10 */,
+  INCOMPATIBLE_PROTOCOL_VERSION = (-11) /* -11 */,
+}
diff --git a/security/authgraph/aidl/aidl_api/android.hardware.security.authgraph/current/android/hardware/security/authgraph/IAuthGraphKeyExchange.aidl b/security/authgraph/aidl/aidl_api/android.hardware.security.authgraph/current/android/hardware/security/authgraph/IAuthGraphKeyExchange.aidl
new file mode 100644
index 0000000..2c56f33
--- /dev/null
+++ b/security/authgraph/aidl/aidl_api/android.hardware.security.authgraph/current/android/hardware/security/authgraph/IAuthGraphKeyExchange.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.authgraph;
+/* @hide */
+@VintfStability
+interface IAuthGraphKeyExchange {
+  android.hardware.security.authgraph.SessionInitiationInfo create();
+  android.hardware.security.authgraph.KeInitResult init(in android.hardware.security.authgraph.PubKey peerPubKey, in android.hardware.security.authgraph.Identity peerId, in byte[] peerNonce, in int peerVersion);
+  android.hardware.security.authgraph.SessionInfo finish(in android.hardware.security.authgraph.PubKey peerPubKey, in android.hardware.security.authgraph.Identity peerId, in android.hardware.security.authgraph.SessionIdSignature peerSignature, in byte[] peerNonce, in int peerVersion, in android.hardware.security.authgraph.Key ownKey);
+  android.hardware.security.authgraph.Arc[2] authenticationComplete(in android.hardware.security.authgraph.SessionIdSignature peerSignature, in android.hardware.security.authgraph.Arc[2] sharedKeys);
+}
diff --git a/security/authgraph/aidl/aidl_api/android.hardware.security.authgraph/current/android/hardware/security/authgraph/Identity.aidl b/security/authgraph/aidl/aidl_api/android.hardware.security.authgraph/current/android/hardware/security/authgraph/Identity.aidl
new file mode 100644
index 0000000..bd5453e
--- /dev/null
+++ b/security/authgraph/aidl/aidl_api/android.hardware.security.authgraph/current/android/hardware/security/authgraph/Identity.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.authgraph;
+@RustDerive(Clone=true, Eq=true, PartialEq=true) @VintfStability
+parcelable Identity {
+  byte[] identity;
+}
diff --git a/security/authgraph/aidl/aidl_api/android.hardware.security.authgraph/current/android/hardware/security/authgraph/KeInitResult.aidl b/security/authgraph/aidl/aidl_api/android.hardware.security.authgraph/current/android/hardware/security/authgraph/KeInitResult.aidl
new file mode 100644
index 0000000..8c91523
--- /dev/null
+++ b/security/authgraph/aidl/aidl_api/android.hardware.security.authgraph/current/android/hardware/security/authgraph/KeInitResult.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.authgraph;
+@RustDerive(Clone=true, Eq=true, PartialEq=true) @VintfStability
+parcelable KeInitResult {
+  android.hardware.security.authgraph.SessionInitiationInfo sessionInitiationInfo;
+  android.hardware.security.authgraph.SessionInfo sessionInfo;
+}
diff --git a/security/authgraph/aidl/aidl_api/android.hardware.security.authgraph/current/android/hardware/security/authgraph/Key.aidl b/security/authgraph/aidl/aidl_api/android.hardware.security.authgraph/current/android/hardware/security/authgraph/Key.aidl
new file mode 100644
index 0000000..5b4ebbf
--- /dev/null
+++ b/security/authgraph/aidl/aidl_api/android.hardware.security.authgraph/current/android/hardware/security/authgraph/Key.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.authgraph;
+@RustDerive(Clone=true, Eq=true, PartialEq=true) @VintfStability
+parcelable Key {
+  @nullable android.hardware.security.authgraph.PubKey pubKey;
+  @nullable android.hardware.security.authgraph.Arc arcFromPBK;
+}
diff --git a/security/authgraph/aidl/aidl_api/android.hardware.security.authgraph/current/android/hardware/security/authgraph/PlainPubKey.aidl b/security/authgraph/aidl/aidl_api/android.hardware.security.authgraph/current/android/hardware/security/authgraph/PlainPubKey.aidl
new file mode 100644
index 0000000..f070bfa
--- /dev/null
+++ b/security/authgraph/aidl/aidl_api/android.hardware.security.authgraph/current/android/hardware/security/authgraph/PlainPubKey.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.authgraph;
+@RustDerive(Clone=true, Eq=true, PartialEq=true) @VintfStability
+parcelable PlainPubKey {
+  byte[] plainPubKey;
+}
diff --git a/security/authgraph/aidl/aidl_api/android.hardware.security.authgraph/current/android/hardware/security/authgraph/PubKey.aidl b/security/authgraph/aidl/aidl_api/android.hardware.security.authgraph/current/android/hardware/security/authgraph/PubKey.aidl
new file mode 100644
index 0000000..4c3376e
--- /dev/null
+++ b/security/authgraph/aidl/aidl_api/android.hardware.security.authgraph/current/android/hardware/security/authgraph/PubKey.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.authgraph;
+@RustDerive(Clone=true, Eq=true, PartialEq=true) @VintfStability
+union PubKey {
+  android.hardware.security.authgraph.PlainPubKey plainKey;
+  android.hardware.security.authgraph.SignedPubKey signedKey;
+}
diff --git a/security/authgraph/aidl/aidl_api/android.hardware.security.authgraph/current/android/hardware/security/authgraph/SessionIdSignature.aidl b/security/authgraph/aidl/aidl_api/android.hardware.security.authgraph/current/android/hardware/security/authgraph/SessionIdSignature.aidl
new file mode 100644
index 0000000..6dabc0a
--- /dev/null
+++ b/security/authgraph/aidl/aidl_api/android.hardware.security.authgraph/current/android/hardware/security/authgraph/SessionIdSignature.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.authgraph;
+@RustDerive(Clone=true, Eq=true, PartialEq=true) @VintfStability
+parcelable SessionIdSignature {
+  byte[] signature;
+}
diff --git a/security/authgraph/aidl/aidl_api/android.hardware.security.authgraph/current/android/hardware/security/authgraph/SessionInfo.aidl b/security/authgraph/aidl/aidl_api/android.hardware.security.authgraph/current/android/hardware/security/authgraph/SessionInfo.aidl
new file mode 100644
index 0000000..427962b
--- /dev/null
+++ b/security/authgraph/aidl/aidl_api/android.hardware.security.authgraph/current/android/hardware/security/authgraph/SessionInfo.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.authgraph;
+@RustDerive(Clone=true, Eq=true, PartialEq=true) @VintfStability
+parcelable SessionInfo {
+  android.hardware.security.authgraph.Arc[2] sharedKeys;
+  byte[] sessionId;
+  android.hardware.security.authgraph.SessionIdSignature signature;
+}
diff --git a/security/authgraph/aidl/aidl_api/android.hardware.security.authgraph/current/android/hardware/security/authgraph/SessionInitiationInfo.aidl b/security/authgraph/aidl/aidl_api/android.hardware.security.authgraph/current/android/hardware/security/authgraph/SessionInitiationInfo.aidl
new file mode 100644
index 0000000..bf55e74
--- /dev/null
+++ b/security/authgraph/aidl/aidl_api/android.hardware.security.authgraph/current/android/hardware/security/authgraph/SessionInitiationInfo.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.authgraph;
+@RustDerive(Clone=true, Eq=true, PartialEq=true) @VintfStability
+parcelable SessionInitiationInfo {
+  android.hardware.security.authgraph.Key key;
+  android.hardware.security.authgraph.Identity identity;
+  byte[] nonce;
+  int version;
+}
diff --git a/security/authgraph/aidl/aidl_api/android.hardware.security.authgraph/current/android/hardware/security/authgraph/SignedPubKey.aidl b/security/authgraph/aidl/aidl_api/android.hardware.security.authgraph/current/android/hardware/security/authgraph/SignedPubKey.aidl
new file mode 100644
index 0000000..3dbaed8
--- /dev/null
+++ b/security/authgraph/aidl/aidl_api/android.hardware.security.authgraph/current/android/hardware/security/authgraph/SignedPubKey.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.authgraph;
+@RustDerive(Clone=true, Eq=true, PartialEq=true) @VintfStability
+parcelable SignedPubKey {
+  byte[] signedPubKey;
+}
diff --git a/security/authgraph/aidl/android/hardware/security/authgraph/Arc.aidl b/security/authgraph/aidl/android/hardware/security/authgraph/Arc.aidl
new file mode 100644
index 0000000..855ce5c
--- /dev/null
+++ b/security/authgraph/aidl/android/hardware/security/authgraph/Arc.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.security.authgraph;
+
+/**
+ * This is the definition of the data format of an Arc.
+ * @hide
+ */
+@VintfStability
+@RustDerive(Clone=true, Eq=true, PartialEq=true)
+parcelable Arc {
+    /**
+     * The messages exchanged between the domains in the AuthGraph protocol are called Arcs.
+     * An arc is simply AES-GCM. Encryption of a payload P with a key K and additional
+     * authentication data (AAD) D: (i.e. Arc = Enc(K, P, D)).
+     *
+     * Data is CBOR-encoded according to the `Arc` CDDL definition in Arc.cddl.
+     */
+    byte[] arc;
+}
diff --git a/security/authgraph/aidl/android/hardware/security/authgraph/Arc.cddl b/security/authgraph/aidl/android/hardware/security/authgraph/Arc.cddl
new file mode 100644
index 0000000..0bc39d6
--- /dev/null
+++ b/security/authgraph/aidl/android/hardware/security/authgraph/Arc.cddl
@@ -0,0 +1,113 @@
+;
+; Copyright (C) 2023 The Android Open Source Project
+;
+; Licensed under the Apache License, Version 2.0 (the "License");
+; you may not use this file except in compliance with the License.
+; You may obtain a copy of the License at
+;
+;      http://www.apache.org/licenses/LICENSE-2.0
+;
+; Unless required by applicable law or agreed to in writing, software
+; distributed under the License is distributed on an "AS IS" BASIS,
+; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+; See the License for the specific language governing permissions and
+; limitations under the License.
+;
+Arc = [                            ; COSE_Encrypt0 [RFC9052 s5.2]
+    protected : bstr .cbor ArcProtectedHeaders,
+    unprotected : {
+        5 : bstr .size 12          ; IV
+    },
+    ciphertext : bstr    ; Enc(K, bstr .cbor Payload, encoded ArcEncStruct)
+]
+
+ArcProtectedHeaders = {
+           1 : 3,                  ; Algorithm: AES-GCM mode w/ 256-bit key, 128-bit tag
+    ? -70001 : { + Permission }, ; One or more Permissions
+    ? -70002 : { + Limitation }, ; One or more Limitations
+    ? -70003 : int,   ; Timestamp in milliseconds since some starting point (generally
+                      ; the most recent device boot) which all of the applications within
+                      ; the secure domain must agree upon
+    ? -70004 : bstr .size 16,      ; Nonce (a cryptographic random number of 16 bytes) used in key
+                                   ; exchange methods
+    ? -70005 : PayloadType,        ; Payload type, if needed to disambiguate, when processing an arc
+    ? -70006 : int,                ; Version of the payload structure (if applicable)
+    ? -70007 : int,                ; Sequence number (if needed to prevent replay attacks)
+    ? -70008 : Direction           ; Direction of the encryption key (i.e. whether it is used to
+                                   ; encrypt incoming messages or outgoing messages)
+    ? -70009 : bool,               ; "authentication_completed" - this is used during authenticated
+                                   ; key exchange to indicate whether signature verification is done
+    ? -70010 : bstr .size 32       ; "session_id" computed during the key exchange protocol
+}
+
+; Permissions indicate what an arc can be used with.
+Permission = &(
+    -4770552 : IdentityEncoded,  ; "source_id" - in the operations performed by a source, the
+                                 ; source adds its own identity to the permissions of an arc.
+    -4770553 : IdentityEncoded,  ; "sink_id" - in the operations performed by a sink, the sink
+                                 ; adds its own identity to the permissions of an arc.
+    -4770555 : [ +IdentityEncoded ]  ; "minting_allowed" - defines the set of TA identities
+                                     ; to whom the payload key is allowed to be minted.
+    -4770556 : bool                  ; "deleted_on_biometric_change" - A Boolean value that
+                                     ; indicates whether an auth key issued from a biometric TA is
+                                     ; invalidated on new biometric enrollment or removal of all
+                                     ; biometrics.
+)
+
+; Limitations indicate what restrictions are applied on the usage of an arc.
+Limitation = &(
+    -4770554 : bstr,      ; "challenge" - is added to an arc that encrypts an auth key from a
+                          ; channel key, in order to ensure the freshness of the authentication.
+                          ; A challenge is issued by a sink (e.g. Keymint TA, Biometric TAs).
+)
+
+; INCLUDE Identity.cddl for: Identity
+IdentityEncoded = bstr .cbor Identity
+
+Direction = &(
+    In:  1,
+    Out: 2,
+)
+
+PayloadType = &(
+    SecretKey: 1,
+    Arc: 2,
+    ; Any other payload types should also be defined here
+)
+
+Payload = &(
+    SecretKey,
+    Arc,
+    ; Any other payload formats should also be defined here
+)
+
+SecretKey = &(
+    SymmetricKey,
+    ECPrivateKey,    ; Private key of a key pair generated for key exchange
+)
+
+ECPrivateKey = {              ; COSE_Key [RFC9052 s7]
+    1 : 2,                    ; Key type : EC2
+    3 : -25,                  ; Algorithm: ECDH ES w/ HKDF 256 - generate key directly
+ ?  4 : [7],                  ; Key_ops: [derive key]
+   -1 : 1,                    ; Curve: P-256
+ ? -2 : bstr,                 ; x coordinate
+ ? -3 : bstr,                 ; y coordinate
+   -4 : bstr,                 ; private key (d)
+}
+
+SymmetricKey = {              ; COSE_Key [RFC9052 s7] - For symmetric key encryption
+    1 : 4,                    ; Key type : Symmetric
+    3 : 3,                    ; Algorithm : AES-GCM mode w/ 256-bit key, 128-bit tag
+    4 : [ 4 ],                ; Key_ops: [decrypt]
+   -1 : bstr .size 32,        ; Key value (k)
+}
+
+ArcEncStruct = [              ; COSE_Enc_structure [RFC9052 s5.3]
+    context   : "Encrypt0",
+    protected : bstr .cbor ArcProtectedHeaders,
+    external_aad : bstr .size 0,
+]
+
+; INCLUDE generateCertificateRequestV2.cddl for: PubKeyEd25519, PubKeyECDSA256, PubKeyECDSA384
+; from hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/
diff --git a/security/authgraph/aidl/android/hardware/security/authgraph/DicePolicy.cddl b/security/authgraph/aidl/android/hardware/security/authgraph/DicePolicy.cddl
new file mode 100644
index 0000000..a7dcbc6
--- /dev/null
+++ b/security/authgraph/aidl/android/hardware/security/authgraph/DicePolicy.cddl
@@ -0,0 +1,33 @@
+;
+; Copyright (C) 2023 The Android Open Source Project
+;
+; Licensed under the Apache License, Version 2.0 (the "License");
+; you may not use this file except in compliance with the License.
+; You may obtain a copy of the License at
+;
+;      http://www.apache.org/licenses/LICENSE-2.0
+;
+; Unless required by applicable law or agreed to in writing, software
+; distributed under the License is distributed on an "AS IS" BASIS,
+; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+; See the License for the specific language governing permissions and
+; limitations under the License.
+;
+DicePolicy = [
+    1, ; dice policy version
+    + nodeConstraintList ; for each entry in dice chain
+]
+
+nodeConstraintList = [
+    * nodeConstraint
+]
+
+; We may add a hashConstraint item later
+nodeConstraint = exactMatchConstraint / geConstraint
+
+exactMatchConstraint = [1, keySpec, value]
+geConstraint = [2, keySpec, int]
+
+keySpec = [value+]
+
+value = bool / int / tstr / bstr
\ No newline at end of file
diff --git a/security/authgraph/aidl/android/hardware/security/authgraph/Error.aidl b/security/authgraph/aidl/android/hardware/security/authgraph/Error.aidl
new file mode 100644
index 0000000..1ad6054
--- /dev/null
+++ b/security/authgraph/aidl/android/hardware/security/authgraph/Error.aidl
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.security.authgraph;
+
+/**
+ * AuthGraph error codes. Aidl will return these error codes as service specific errors in
+ * EX_SERVICE_SPECIFIC.
+ * @hide
+ */
+@VintfStability
+@Backing(type="int")
+enum Error {
+    /* Success */
+    OK = 0,
+    /* Invalid peer nonce for key exchange */
+    INVALID_PEER_NONCE = -1,
+    /* Invalid key exchange public key by the peer */
+    INVALID_PEER_KE_KEY = -2,
+    /* Invalid identity of the peer */
+    INVALID_IDENTITY = -3,
+    /* Invalid certificate chain in the identity of the peer */
+    INVALID_CERT_CHAIN = -4,
+    /* Invalid signature by the peer */
+    INVALID_SIGNATURE = -5,
+    /* Invalid key exchange key created by a particular party themselves to be used as a handle */
+    INVALID_KE_KEY = -6,
+    /* Invalid public key in the `Key` struct */
+    INVALID_PUB_KEY_IN_KEY = -7,
+    /* Invalid private key arc in the `Key` struct */
+    INVALID_PRIV_KEY_ARC_IN_KEY = -8,
+    /* Invalid shared key arcs */
+    INVALID_SHARED_KEY_ARCS = -9,
+    /* Memory allocation failed */
+    MEMORY_ALLOCATION_FAILED = -10,
+    /* The protocol version negotiated with the sink is incompatible */
+    INCOMPATIBLE_PROTOCOL_VERSION = -11,
+}
diff --git a/security/authgraph/aidl/android/hardware/security/authgraph/ExplicitKeyDiceCertChain.cddl b/security/authgraph/aidl/android/hardware/security/authgraph/ExplicitKeyDiceCertChain.cddl
new file mode 100644
index 0000000..2d6c696
--- /dev/null
+++ b/security/authgraph/aidl/android/hardware/security/authgraph/ExplicitKeyDiceCertChain.cddl
@@ -0,0 +1,29 @@
+;
+; Copyright (C) 2023 The Android Open Source Project
+;
+; Licensed under the Apache License, Version 2.0 (the "License");
+; you may not use this file except in compliance with the License.
+; You may obtain a copy of the License at
+;
+;      http://www.apache.org/licenses/LICENSE-2.0
+;
+; Unless required by applicable law or agreed to in writing, software
+; distributed under the License is distributed on an "AS IS" BASIS,
+; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+; See the License for the specific language governing permissions and
+; limitations under the License.
+;
+ExplicitKeyDiceCertChain = [
+    1, ; version, hopefully will never change
+    DiceCertChainInitialPayload,
+    * DiceChainEntry
+]
+
+; Encoded in accordance with Core Deterministic Encoding Requirements [RFC 8949 s4.2.1]
+DiceCertChainInitialPayload = bstr .cbor PubKeyEd25519
+                            / bstr .cbor PubKeyECDSA256
+                            / bstr .cbor PubKeyECDSA384 ; subjectPublicKey
+
+; INCLUDE generateCertificateRequestV2.cddl for: PubKeyEd25519, PubKeyECDSA256, PubKeyECDSA384,
+;                                                DiceChainEntry
+; from hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/
diff --git a/security/authgraph/aidl/android/hardware/security/authgraph/IAuthGraphKeyExchange.aidl b/security/authgraph/aidl/android/hardware/security/authgraph/IAuthGraphKeyExchange.aidl
new file mode 100644
index 0000000..a3fb959
--- /dev/null
+++ b/security/authgraph/aidl/android/hardware/security/authgraph/IAuthGraphKeyExchange.aidl
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.security.authgraph;
+
+import android.hardware.security.authgraph.Arc;
+import android.hardware.security.authgraph.Identity;
+import android.hardware.security.authgraph.KeInitResult;
+import android.hardware.security.authgraph.Key;
+import android.hardware.security.authgraph.PubKey;
+import android.hardware.security.authgraph.SessionIdSignature;
+import android.hardware.security.authgraph.SessionInfo;
+import android.hardware.security.authgraph.SessionInitiationInfo;
+
+/**
+ * AuthGraph interface definition for authenticated key exchange between two parties: P1 (source)
+ * and P2 (sink).
+ * Pre-requisites: each participant should have a:
+ *     1. Persistent identity - e.g. a signing key pair with a self signed certificate or a DICE
+ *        certificate chain.
+ *     2. A symmetric encryption key kept in memory with per-boot life time of the participant
+ *        (a.k.a per-boot key)
+ *
+ * ErrorCodes are defined in android.hardware.security.authgraph.ErrorCode.aidl.
+ * @hide
+ */
+@VintfStability
+interface IAuthGraphKeyExchange {
+    /**
+     * This method is invoked on P1 (source).
+     * Create an ephermeral EC key pair on NIST curve P-256 and a nonce (a cryptographic random
+     * number of 16 bytes) for key exchange.
+     *
+     * @return SessionInitiationInfo including the `Key` containing the public key of the created
+     * key pair and an arc from the per-boot key to the private key, the nonce, the persistent
+     * identity and the latest protocol version (i.e. AIDL version) supported.
+     *
+     * Note: The arc from the per-boot key to the private key in `Key` of the return type:
+     * `SessionInitiationInfo` serves two purposes:
+     * i. A mapping to correlate `create` and `finish` calls to P1 in a particular instance of the
+     *    key exchange protocol.
+     * ii.A way to minimize the in-memory storage of P1 allocated for key exchange (P1 can include
+     *    the nonce in the protected headers of the arc).
+     * However, P1 should maintain some form of in-memory record to be able to verify that the input
+     * `Key` sent to `finish` is from an unfinished instance of a key exchange protocol, to prevent
+     * any replay attacks in `finish`.
+     */
+    SessionInitiationInfo create();
+
+    /**
+     * This method is invoked on P2 (sink).
+     * Perform the following steps for key exchange:
+     *     0. If either `peerPubKey`, `peerId`, `peerNonce` is not in the expected format, return
+     *        errors: INVALID_PEER_KE_KEY, INVALID_IDENTITY, INVALID_PEER_NONCE respectively.
+     *     1. Create an ephemeral EC key pair on NIST curve P-256.
+     *     2. Create a nonce (a cryptographic random number of 16 bytes).
+     *     3. Compute the Diffie-Hellman shared secret: Z.
+     *     4. Compute a salt_input = bstr .cbor [
+     *            source_version:    int,                    ; from input `peerVersion`
+     *            sink_pub_key:      bstr .cbor PlainPubKey, ; from step #1
+     *            source_pub_key:    bstr .cbor PlainPubKey, ; from input `peerPubKey`
+     *            sink_nonce:        bstr .size 16,          ; from step #2
+     *            source_nonce:      bstr .size 16,          ; from input `peerNonce`
+     *            sink_cert_chain:   bstr .cbor ExplicitKeyDiceCertChain, ; from own identity
+     *            source_cert_chain: bstr .cbor ExplicitKeyDiceCertChain, ; from input `peerId`
+     *        ]
+     *     5. Extract a cryptographic secret S from Z, using the SHA256 digest of the salt_input
+     *        as the salt.
+     *     6. Derive two symmetric encryption keys of 256 bits with:
+     *        i. b"KE_ENCRYPTION_KEY_SOURCE_TO_SINK" as context for the key used to encrypt incoming
+     *           messages
+     *       ii. b"KE_ENCRYPTION_KEY_SINK_TO_SOURCE" as context for the key used to encrypt outgoing
+     *           messages
+     *     7. Create arcs from the per-boot key to each of the two shared keys from step #6 and
+     *        mark authentication_complete = false in arcs' protected headers.
+     *     8. Derive a MAC key with b"KE_HMAC_KEY" as the context.
+     *     9. Compute session_id_input = bstr .cbor [
+     *            sink_nonce:     bstr .size 16,
+     *            source_nonce:   bstr .size 16,
+     *        ],
+     *     10.Compute a session_id as a 256 bits HMAC over the session_id_input from step#9 with
+     *        the key from step #8.
+     *     11.Create a signature over the session_id from step #10, using the signing key which is
+     *        part of the party's identity.
+     *
+     * @param peerPubKey - the public key of the key pair created by the peer (P1) for key exchange
+     *                     in `create`
+     *
+     * @param peerId - the persistent identity of the peer
+     *
+     * @param peerNonce - nonce created by the peer in `create`
+     *
+     * @param peerVersion - an integer representing the latest protocol version (i.e. AIDL version)
+     *                      supported by the peer
+     *
+     * @return KeInitResult including the `Key` containing the public key of the key pair created in
+     * step #1, the nonce from step #2, the persistent identity of P2, two shared key arcs
+     * from step #7, session id from step #10, signature over the session id from step #11 and the
+     * negotiated protocol version. The negotiated protocol version should be less than or equal to
+     * the `peerVersion`.
+     *
+     * Note: The two shared key arcs in the return type: `KeInitResult` serve two purposes:
+     * i. A mapping to correlate `init` and `authenticationComplete` calls to P2 in a particular
+     *    instance of the key exchange protocol.
+     * ii.A way to minimize the in-memory storage of P2 allocated for key exchange.
+     * However, P2 should maintain some in-memory record to be able to verify that the input
+     * `sharedkeys` sent to `authenticationComplete` are from an unfinished instance of a key
+     * exchange protocol carried out with the party identified by `peerId`, to prevent any replay
+     * attacks in `authenticationComplete`.
+     */
+    KeInitResult init(
+            in PubKey peerPubKey, in Identity peerId, in byte[] peerNonce, in int peerVersion);
+
+    /**
+     * This method is invoked on P1 (source).
+     * Perform the following steps:
+     *     0. If either `peerPubKey`, `peerId`, `peerNonce` is not in the expected format, return
+     *        errors: INVALID_PEER_KE_KEY, INVALID_IDENTITY, INVALID_PEER_NONCE respectively. If
+     *        `peerVersion` is greater than the version advertised in `create`, return error:
+     *        INCOMPATIBLE_PROTOCOL_VERSION.
+     *        If `ownKey` is not in the in-memory records for unfinished instances of a key
+     *        exchange protocol, return error: INVALID_KE_KEY. Similarly, if the public key or the
+     *        arc containing the private key in `ownKey` is invalid, return INVALID_PUB_KEY_IN_KEY
+     *        and INVALID_PRIV_KEY_ARC_IN_KEY respectively.
+     *     1. Compute the Diffie-Hellman shared secret: Z.
+     *     2. Compute a salt_input = bstr .cbor [
+     *            source_version:    int,                    ; the protocol version used in `create`
+     *            sink_pub_key:      bstr .cbor PlainPubKey, ; from input `peerPubKey`
+     *            source_pub_key:    bstr .cbor PlainPubKey, ; from the output of `create`
+     *            sink_nonce:        bstr .size 16,          ; from input `peerNonce`
+     *            source_nonce:      bstr .size 16,          ; from the output of `create`
+     *            sink_cert_chain:   bstr .cbor ExplicitKeyDiceCertChain, ; from input `peerId`
+     *            source_cert_chain: bstr .cbor ExplicitKeyDiceCertChain, ; from own identity
+     *        ]
+     *     3. Extract a cryptographic secret S from Z, using the SHA256 digest of the salt_input
+     *        as the salt.
+     *     4. Derive two symmetric encryption keys of 256 bits with:
+     *        i. b"KE_ENCRYPTION_KEY_SOURCE_TO_SINK" as context for the key used to encrypt outgoing
+     *           messages
+     *       ii. b"KE_ENCRYPTION_KEY_SINK_TO_SOURCE" as context for the key used to encrypt incoming
+     *           messages
+     *     5. Derive a MAC key with b"KE_HMAC_KEY" as the context.
+     *     6. Compute session_id_input = bstr .cbor [
+     *            sink_nonce:     bstr .size 16,
+     *            source_nonce:   bstr .size 16,
+     *        ],
+     *     7. Compute a session_id as a 256 bits HMAC over the session_id_input from step #6 with
+     *        the key from step #5.
+     *     8. Verify the peer's signature over the session_id from step #7. If successful, proceed,
+     *        otherwise, return error: INVALID_SIGNATURE.
+     *     9. Create arcs from the per-boot key to each of the two shared keys from step #4 and
+     *        mark authentication_complete = true in arcs' protected headers.
+     *     10.Create a signature over the session_id from step #7, using the signing key which is
+     *        part of the party's identity.
+     *
+     * @param peerPubKey - the public key of the key pair created by the peer (P2) for key exchange
+     *                     in `init`
+     *
+     * @param peerId - the persistent identity of the peer
+     *
+     * @param peerSignature - the signature created by the peer over the session id computed by the
+     *                        peer in `init`
+     *
+     * @param peerNonce - nonce created by the peer in `init`
+     *
+     * @param peerVersion - an integer representing the protocol version (i.e. AIDL version)
+     *                      negotiated with the peer
+     *
+     * @param ownKey - the key created by P1 (source) in `create` for key exchange
+     *
+     * @return SessionInfo including the two shared key arcs from step #9, session id from step #7
+     * and the signature over the session id from step #10.
+     *
+     * Note: The two shared key arcs in the return type: `SessionInfo` serve two purposes:
+     * i. A mapping to correlate the key exchange protocol taken place with a particular peer and
+     *    subsequent AuthGraph protocols executed with the same peer.
+     * ii.A way to minimize the in-memory storage for shared keys.
+     * However, P1 should maintain some in-memory record to be able to verify that the shared key
+     * arcs sent to any subsequent AuthGraph protocol methods are valid shared keys agreed with the
+     * party identified by `peerId`, to prevent any replay attacks.
+     */
+    SessionInfo finish(in PubKey peerPubKey, in Identity peerId,
+            in SessionIdSignature peerSignature, in byte[] peerNonce, in int peerVersion,
+            in Key ownKey);
+
+    /**
+     * This method is invoked on P2 (sink).
+     * Perform the following steps:
+     *   0. If input `sharedKeys` is invalid (i.e. they cannot be decrypted with P2's per-boot key
+     *      or they are not in P2's in-memory records for unfinished instances of a key exchange
+     *      protocol carried out with the party identified by the identity included in the
+     *      `source_id` protected header of the shared key arcs),
+     *      return error: INVALID_SHARED_KEY_ARCS.
+     *   1. Verify that both shared key arcs have the same session id and peer identity.
+     *   2. Verify the `peerSignature` over the session id included in the `session_id` protected
+     *      header of the shared key arcs.
+     *      If successful, proceed, otherwise, return error: INVALID_SIGNATURE.
+     *   3. Mark authentication_complete = true in the shared key arcs' headers.
+     *
+     * @param peerSignature - the signature created by the peer over the session id computed by the
+     *                        peer in `finish`
+     *
+     * @param sharedKeys - two shared key arcs created by P2 in `init`. P2 obtains from the arcs'
+     *                     protected headers, the session id and the peer's identity to verify the
+     *                     peer's signature over the session id.
+     *
+     * @return Arc[] - an array of two updated shared key arcs
+     *
+     * Note: The two returned shared key arcs serve two purposes:
+     * i. A mapping to correlate the key exchange protocol taken place with a particular peer and
+     *    subsequent AuthGraph protocols executed with the same peer.
+     * ii.A way to minimize the in-memory storage for shared keys.
+     * However, P2 should maintain some in-memory record to be able to verify that the shared key
+     * arcs sent to any subsequent AuthGraph protocol methods are valid shared keys agreed with the
+     * party identified by the identity included in the `source_id` protected header of the shared
+     * key arcs, to prevent any replay attacks.
+     */
+    Arc[2] authenticationComplete(in SessionIdSignature peerSignature, in Arc[2] sharedKeys);
+}
diff --git a/security/authgraph/aidl/android/hardware/security/authgraph/Identity.aidl b/security/authgraph/aidl/android/hardware/security/authgraph/Identity.aidl
new file mode 100644
index 0000000..9e350e8
--- /dev/null
+++ b/security/authgraph/aidl/android/hardware/security/authgraph/Identity.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.security.authgraph;
+
+/**
+ * Persistent (versioned) identity of a participant of Authgraph key exchange.
+ * Identity consists of two main parts:
+ *     1. a certificate chain (e.g. a DICE certificate chain)
+ *     2. (optional) a policy specifying how to verify the certificate chain - if a policy is not
+ *        provided, a simple byte-to-byte comparison of the certificate chain is assumed.
+ *
+ * During identity verification, the certificate chain of the identity attached to the access
+ * request is compared against the policy of the identity attached to the persistent resources.
+ *
+ * The usage of policy based identity verification in Authgraph is three-fold:
+ *        1. Retain access to persistent resources for the newer versions of the party who
+ *           created them, even when parts of the certificate chain are updated in the new version.
+ *        2. Deny access to the new persistent resources for the older versions of the party
+ *           who created the new persistent resources.
+ *        3. Trigger rotation of critical keys encrypted in persistent arcs created by the previous
+ *           version of the party, by including an updated policy in the identity attached to the
+ *           access request.
+ */
+@VintfStability
+@RustDerive(Clone=true, Eq=true, PartialEq=true)
+parcelable Identity {
+    /* Data is CBOR-encoded according to the `Identity` CDDL definition in Identity.cddl */
+    byte[] identity;
+}
diff --git a/security/authgraph/aidl/android/hardware/security/authgraph/Identity.cddl b/security/authgraph/aidl/android/hardware/security/authgraph/Identity.cddl
new file mode 100644
index 0000000..0419421
--- /dev/null
+++ b/security/authgraph/aidl/android/hardware/security/authgraph/Identity.cddl
@@ -0,0 +1,23 @@
+;
+; Copyright (C) 2023 The Android Open Source Project
+;
+; Licensed under the Apache License, Version 2.0 (the "License");
+; you may not use this file except in compliance with the License.
+; You may obtain a copy of the License at
+;
+;      http://www.apache.org/licenses/LICENSE-2.0
+;
+; Unless required by applicable law or agreed to in writing, software
+; distributed under the License is distributed on an "AS IS" BASIS,
+; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+; See the License for the specific language governing permissions and
+; limitations under the License.
+;
+Identity = [
+    1, ; Version
+    cert_chain: bstr .cbor ExplicitKeyDiceCertChain,
+    policy: bstr .cbor DicePolicy / nil,
+]
+
+; INCLUDE ExplicitKeyDiceCertChain.cddl for: ExplicitKeyDiceCertChain
+; INCLUDE DicePolicy.cddl for: DicePolicy
diff --git a/security/authgraph/aidl/android/hardware/security/authgraph/KeInitResult.aidl b/security/authgraph/aidl/android/hardware/security/authgraph/KeInitResult.aidl
new file mode 100644
index 0000000..b4ae451
--- /dev/null
+++ b/security/authgraph/aidl/android/hardware/security/authgraph/KeInitResult.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.security.authgraph;
+
+import android.hardware.security.authgraph.SessionInfo;
+import android.hardware.security.authgraph.SessionInitiationInfo;
+
+/**
+ * The return type for the init() step of authenticated key exchange.
+ */
+@VintfStability
+@RustDerive(Clone=true, Eq=true, PartialEq=true)
+parcelable KeInitResult {
+    /**
+     * Session initiation information.
+     */
+    SessionInitiationInfo sessionInitiationInfo;
+
+    /**
+     * Session information.
+     */
+    SessionInfo sessionInfo;
+}
diff --git a/security/authgraph/aidl/android/hardware/security/authgraph/Key.aidl b/security/authgraph/aidl/android/hardware/security/authgraph/Key.aidl
new file mode 100644
index 0000000..11fe174
--- /dev/null
+++ b/security/authgraph/aidl/android/hardware/security/authgraph/Key.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.security.authgraph;
+
+import android.hardware.security.authgraph.Arc;
+import android.hardware.security.authgraph.PubKey;
+
+/**
+ * The type that encapsulates a key. Key can be either a symmetric key or an asymmetric key.
+ * If it is an asymmetric key, it is used for key exchange.
+ */
+@VintfStability
+@RustDerive(Clone=true, Eq=true, PartialEq=true)
+parcelable Key {
+    /**
+     * If the Key is an asymmetric key, public key should be present.
+     */
+    @nullable PubKey pubKey;
+
+    /**
+     * Arc from the per-boot key to the payload key. The payload key is either the symmetric key
+     * or the private key of an asymmetric key, based on the type of the key being created.
+     * This is marked as optional because there are instances where only the public key is returned,
+     * e.g. `init` method in the key exchange protocol.
+     */
+    @nullable Arc arcFromPBK;
+}
diff --git a/security/authgraph/aidl/android/hardware/security/authgraph/PlainPubKey.aidl b/security/authgraph/aidl/android/hardware/security/authgraph/PlainPubKey.aidl
new file mode 100644
index 0000000..5483ec5
--- /dev/null
+++ b/security/authgraph/aidl/android/hardware/security/authgraph/PlainPubKey.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.security.authgraph;
+
+/**
+ * One of the two enum variants of the enum type: `PubKey`. This represents the plain public key
+ * material encoded as a COSE_Key.
+ */
+@VintfStability
+@RustDerive(Clone=true, Eq=true, PartialEq=true)
+parcelable PlainPubKey {
+    /* Data is CBOR-encoded according to the `PlainPubKey` CDDL definition in PlainPubKey.cddl */
+    byte[] plainPubKey;
+}
diff --git a/security/authgraph/aidl/android/hardware/security/authgraph/PlainPubKey.cddl b/security/authgraph/aidl/android/hardware/security/authgraph/PlainPubKey.cddl
new file mode 100644
index 0000000..34b316b
--- /dev/null
+++ b/security/authgraph/aidl/android/hardware/security/authgraph/PlainPubKey.cddl
@@ -0,0 +1,24 @@
+;
+; Copyright (C) 2023 The Android Open Source Project
+;
+; Licensed under the Apache License, Version 2.0 (the "License");
+; you may not use this file except in compliance with the License.
+; You may obtain a copy of the License at
+;
+;      http://www.apache.org/licenses/LICENSE-2.0
+;
+; Unless required by applicable law or agreed to in writing, software
+; distributed under the License is distributed on an "AS IS" BASIS,
+; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+; See the License for the specific language governing permissions and
+; limitations under the License.
+;
+
+; P-256 public key for key exchange.
+PlainPubKey = [ ; COSE_Key [RFC9052 s7]
+    1 : 2,                       ; Key type : EC2
+    3 : -27,                     ; Algorithm : ECDH-SS + HKDF-256
+    -1 : 1,                      ; Curve: P256
+    -2 : bstr,                   ; X coordinate, big-endian
+    -3 : bstr                    ; Y coordinate, big-endian
+]
diff --git a/security/authgraph/aidl/android/hardware/security/authgraph/PubKey.aidl b/security/authgraph/aidl/android/hardware/security/authgraph/PubKey.aidl
new file mode 100644
index 0000000..8640871
--- /dev/null
+++ b/security/authgraph/aidl/android/hardware/security/authgraph/PubKey.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.security.authgraph;
+
+import android.hardware.security.authgraph.PlainPubKey;
+import android.hardware.security.authgraph.SignedPubKey;
+
+/**
+ * The enum type representing the public key of an asymmetric key pair.
+ */
+@VintfStability
+@RustDerive(Clone=true, Eq=true, PartialEq=true)
+union PubKey {
+    /**
+     * Plain public key material encoded as a COSE_Key.
+     */
+    PlainPubKey plainKey;
+
+    /**
+     * Public key signed with the long term signing key of the party.
+     */
+    SignedPubKey signedKey;
+}
diff --git a/security/authgraph/aidl/android/hardware/security/authgraph/SessionIdSignature.aidl b/security/authgraph/aidl/android/hardware/security/authgraph/SessionIdSignature.aidl
new file mode 100644
index 0000000..2fa8b4c
--- /dev/null
+++ b/security/authgraph/aidl/android/hardware/security/authgraph/SessionIdSignature.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.security.authgraph;
+
+/**
+ * Signature computed by a party over the session id during authenticated key exchange.
+ */
+@VintfStability
+@RustDerive(Clone=true, Eq=true, PartialEq=true)
+parcelable SessionIdSignature {
+    /* Data is CBOR-encoded according to the `SessionIdSignature` CDDL definition in
+     * SessionIdSignature.cddl */
+    byte[] signature;
+}
diff --git a/security/authgraph/aidl/android/hardware/security/authgraph/SessionIdSignature.cddl b/security/authgraph/aidl/android/hardware/security/authgraph/SessionIdSignature.cddl
new file mode 100644
index 0000000..038a0f0
--- /dev/null
+++ b/security/authgraph/aidl/android/hardware/security/authgraph/SessionIdSignature.cddl
@@ -0,0 +1,33 @@
+;
+; Copyright (C) 2023 The Android Open Source Project
+;
+; Licensed under the Apache License, Version 2.0 (the "License");
+; you may not use this file except in compliance with the License.
+; You may obtain a copy of the License at
+;
+;      http://www.apache.org/licenses/LICENSE-2.0
+;
+; Unless required by applicable law or agreed to in writing, software
+; distributed under the License is distributed on an "AS IS" BASIS,
+; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+; See the License for the specific language governing permissions and
+; limitations under the License.
+;
+SessionIdSignature = [ ; COSE_Sign1 (untagged) [RFC9052 s4.2]
+    protected: bstr .cbor SessionIdSignatureProtected,
+    unprotected: {},
+    payload: nil,       ; session ID payload to be transported separately
+    signature: bstr     ; PureEd25519(privateKey, SessionIdSignatureSigStruct) /
+                        ; ECDSA(privateKey, SessionIdSignatureSigStruct)
+]
+
+SessionIdSignatureProtected = {
+    1 : AlgorithmEdDSA / AlgorithmES256,
+}
+
+SessionIdSignatureSigStruct = [ ; Sig_structure for SessionIdSignature [ RFC9052 s4.4]
+    context: "Signature1",
+    protected: bstr SessionIdSignatureProtected,
+    external_aad: bstr .size 0,
+    payload: bstr,       ; session ID payload provided separately
+]
diff --git a/security/authgraph/aidl/android/hardware/security/authgraph/SessionInfo.aidl b/security/authgraph/aidl/android/hardware/security/authgraph/SessionInfo.aidl
new file mode 100644
index 0000000..82b8c17
--- /dev/null
+++ b/security/authgraph/aidl/android/hardware/security/authgraph/SessionInfo.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.security.authgraph;
+
+import android.hardware.security.authgraph.Arc;
+import android.hardware.security.authgraph.SessionIdSignature;
+
+/**
+ * Session information returned as part of authenticated key exchange.
+ */
+@VintfStability
+@RustDerive(Clone=true, Eq=true, PartialEq=true)
+parcelable SessionInfo {
+    /**
+     * The arcs that encrypt the two derived symmetric encryption keys (for two-way communication).
+     * The encryption key is the party's per-boot key.
+     */
+    Arc[2] sharedKeys;
+
+    /**
+     * The value of the session id computed by the two parties during the authenticate key
+     * exchange. Apart from the usage of the session id by the two peers, session id is also useful
+     * to verify (by a third party) that the key exchange was successful.
+     */
+    byte[] sessionId;
+
+    /**
+     * The signature over the session id, created by the party who computed the session id.
+     *
+     * If there is one or more `DiceChainEntry` in the `ExplicitKeyDiceCertChain` of the party's
+     * identity, the signature is verified with the public key in the leaf of the chain of
+     * DiceChainEntries (i.e the public key in the last of the array of DiceChainEntries).
+     * Otherwise, the signature is verified with the `DiceCertChainInitialPayload`.
+     */
+    SessionIdSignature signature;
+}
diff --git a/security/authgraph/aidl/android/hardware/security/authgraph/SessionInitiationInfo.aidl b/security/authgraph/aidl/android/hardware/security/authgraph/SessionInitiationInfo.aidl
new file mode 100644
index 0000000..8179ac2
--- /dev/null
+++ b/security/authgraph/aidl/android/hardware/security/authgraph/SessionInitiationInfo.aidl
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.security.authgraph;
+
+import android.hardware.security.authgraph.Arc;
+import android.hardware.security.authgraph.Identity;
+import android.hardware.security.authgraph.Key;
+
+/**
+ * Session initiation information returned as part of authenticated key exchange.
+ */
+@VintfStability
+@RustDerive(Clone=true, Eq=true, PartialEq=true)
+parcelable SessionInitiationInfo {
+    /**
+     * An ephemeral EC key created for the Elliptic-curve Diffie-Hellman (ECDH) process.
+     */
+    Key key;
+
+    /**
+     * The identity of the party who creates this `SessionInitiationInfo`.
+     */
+    Identity identity;
+
+    /**
+     * Nonce (a cryptographic random number of 16 bytes) specific to this session.
+     * The nonce serves three purposes:
+     * 1. freshness of key exchange
+     * 2. creating a session id (a publicly known value related to the exchanged keys)
+     * 3. usage as salt into the HKDF-EXTRACT function during key derivation from the Diffie-Hellman
+     *    shared secret
+     */
+    byte[] nonce;
+
+    /**
+     * The protocol version (i.e. AIDL version) - This is used to prevent version downgrade attacks
+     * as follows:
+     * 1. In `create`, the source advertises the latest protocol version supported by the source,
+     *    which is given as input to the `init` call on the sink in the input parameter:
+     *    `peerVersion`.
+     * 2. In `init`, the sink includes the `peerVersion` in the inputs to the derivation of the
+     *    shared keys. Then the sink returns the latest protocol version supported by the sink,
+     *    which is given as input to the `finish` call on the source in the input parameter:
+     *    `peerVersion`.
+     * 3. In `finish`, the source first checks whether the sink's version is equal or less than the
+     *    source's version and includes in the source's version in the inputs to the derivation of
+     *    the shared keys.
+     * Analysis: if an attacker-in-the-middle wanted the two parties to use an older (vulnerable)
+     * version of the protocol, they can invoke `init` with a version that is lower than the version
+     * advertised by the source in `create`. However, since both parties include the source's
+     * version in the inputs to the derivation of the shared keys, the two parties won't end up with
+     * the same shared keys in the presence of such an attack. This is detected when checking the
+     * signature on the session id in `finish`, at which point the protocol aborts. Therefore,
+     * an attacker cannot successfully launch a version downgrade attack on this protocol.
+     */
+    int version;
+}
diff --git a/security/authgraph/aidl/android/hardware/security/authgraph/SignedPubKey.aidl b/security/authgraph/aidl/android/hardware/security/authgraph/SignedPubKey.aidl
new file mode 100644
index 0000000..72ee219
--- /dev/null
+++ b/security/authgraph/aidl/android/hardware/security/authgraph/SignedPubKey.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.security.authgraph;
+
+/**
+ * One of the two enum variants of the enum type: `PubKey`. This represents the public key signed
+ * with the long term signing key of the party.
+ */
+@VintfStability
+@RustDerive(Clone=true, Eq=true, PartialEq=true)
+parcelable SignedPubKey {
+    /* Data is CBOR-encoded according to the `SignedPubKey` CDDL definition in SignedPubKey.cddl */
+    byte[] signedPubKey;
+}
diff --git a/security/authgraph/aidl/android/hardware/security/authgraph/SignedPubKey.cddl b/security/authgraph/aidl/android/hardware/security/authgraph/SignedPubKey.cddl
new file mode 100644
index 0000000..f23a492
--- /dev/null
+++ b/security/authgraph/aidl/android/hardware/security/authgraph/SignedPubKey.cddl
@@ -0,0 +1,41 @@
+;
+; Copyright (C) 2023 The Android Open Source Project
+;
+; Licensed under the Apache License, Version 2.0 (the "License");
+; you may not use this file except in compliance with the License.
+; You may obtain a copy of the License at
+;
+;      http://www.apache.org/licenses/LICENSE-2.0
+;
+; Unless required by applicable law or agreed to in writing, software
+; distributed under the License is distributed on an "AS IS" BASIS,
+; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+; See the License for the specific language governing permissions and
+; limitations under the License.
+;
+SignedPubKey = [ ; COSE_Sign1 (untagged) [RFC9052 s4.2]
+    protected: bstr .cbor SignedPubKeyProtected,
+    unprotected: {},
+    payload: bstr .cbor PlainPubKey,
+    signature: bstr     ; PureEd25519(privateKey, SignedPubKeySigStruct) /
+                        ; ECDSA(privateKey, SignedPubKeySigStruct)
+]
+
+SignedPubKeyProtected = {
+           1 : AlgorithmEdDSA / AlgorithmES256,
+    ? -70011 : Identity,        ; the party who performs the signing operation adds its own
+                                ; identity to the protected headers.
+}
+
+SignedPubKeySigStruct = [ ; Sig_structure for SignedPubKey [ RFC9052 s4.4]
+    context: "Signature1",
+    protected: bstr SignedPubKeyProtected,
+    external_aad: bstr .size 0,
+    payload: bstr .cbor PlainPubKey,
+]
+
+AlgorithmES256 = -7              ; [RFC9053 s2.1]
+AlgorithmEdDSA = -8              ; [RFC9053 s2.2]
+
+; INCLUDE PlainPubKey.cddl for: PlainPubKey
+; INCLUDE Identity.cddl for: Identity
\ No newline at end of file
diff --git a/security/authgraph/aidl/vts/functional/Android.bp b/security/authgraph/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..28a70e2
--- /dev/null
+++ b/security/authgraph/aidl/vts/functional/Android.bp
@@ -0,0 +1,82 @@
+//
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES 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: "VtsAidlAuthGraphSessionTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "authgraph_use_latest_hal_aidl_ndk_static",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    cflags: [
+        "-Wall",
+        "-Wextra",
+    ],
+    srcs: [
+        "AuthGraphSessionTest.cpp",
+    ],
+    shared_libs: [
+        "libbinder_ndk",
+        "libcrypto",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
+
+rust_test {
+    name: "VtsAidlAuthGraphRoleTest",
+    srcs: ["role_test.rs"],
+    require_root: true,
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+    defaults: [
+        "authgraph_use_latest_hal_aidl_rust",
+    ],
+    rustlibs: [
+        "libauthgraph_vts_test",
+        "libbinder_rs",
+    ],
+}
+
+rust_library {
+    name: "libauthgraph_vts_test",
+    crate_name: "authgraph_vts_test",
+    srcs: ["lib.rs"],
+    defaults: [
+        "authgraph_use_latest_hal_aidl_rust",
+    ],
+    rustlibs: [
+        "libauthgraph_boringssl",
+        "libauthgraph_core",
+        "libauthgraph_hal",
+        "libauthgraph_nonsecure",
+        "libbinder_rs",
+        "libcoset",
+    ],
+}
diff --git a/security/authgraph/aidl/vts/functional/AuthGraphSessionTest.cpp b/security/authgraph/aidl/vts/functional/AuthGraphSessionTest.cpp
new file mode 100644
index 0000000..d9dea77
--- /dev/null
+++ b/security/authgraph/aidl/vts/functional/AuthGraphSessionTest.cpp
@@ -0,0 +1,375 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "authgraph_session_test"
+#include <android-base/logging.h>
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/security/authgraph/Error.h>
+#include <aidl/android/hardware/security/authgraph/IAuthGraphKeyExchange.h>
+#include <android/binder_manager.h>
+#include <binder/ProcessState.h>
+#include <gtest/gtest.h>
+#include <vector>
+
+namespace aidl::android::hardware::security::authgraph::test {
+using ::aidl::android::hardware::security::authgraph::Error;
+
+namespace {
+
+// Check that the signature in the encoded COSE_Sign1 data is correct, and that the payload matches.
+// TODO: maybe drop separate payload, and extract it from cose_sign1.payload (and return it).
+void CheckSignature(std::vector<uint8_t>& /*pub_cose_key*/, std::vector<uint8_t>& /*payload*/,
+                    std::vector<uint8_t>& /*cose_sign1*/) {
+    // TODO: implement me
+}
+
+void CheckSignature(std::vector<uint8_t>& pub_cose_key, std::vector<uint8_t>& payload,
+                    SessionIdSignature& signature) {
+    return CheckSignature(pub_cose_key, payload, signature.signature);
+}
+
+std::vector<uint8_t> SigningKeyFromIdentity(const Identity& identity) {
+    // TODO: This is a CBOR-encoded `Identity` which currently happens to be a COSE_Key with the
+    // pubkey This will change in future.
+    return identity.identity;
+}
+
+}  // namespace
+
+class AuthGraphSessionTest : public ::testing::TestWithParam<std::string> {
+  public:
+    enum ErrorType { AIDL_ERROR, BINDER_ERROR };
+
+    union ErrorValue {
+        Error aidl_error;
+        int32_t binder_error;
+    };
+
+    struct ReturnedError {
+        ErrorType err_type;
+        ErrorValue err_val;
+
+        friend bool operator==(const ReturnedError& lhs, const ReturnedError& rhs) {
+            return lhs.err_type == rhs.err_type;
+            switch (lhs.err_type) {
+                case ErrorType::AIDL_ERROR:
+                    return lhs.err_val.aidl_error == rhs.err_val.aidl_error;
+                case ErrorType::BINDER_ERROR:
+                    return lhs.err_val.binder_error == rhs.err_val.binder_error;
+            }
+        }
+    };
+
+    const ReturnedError OK = {.err_type = ErrorType::AIDL_ERROR, .err_val.aidl_error = Error::OK};
+
+    ReturnedError GetReturnError(const ::ndk::ScopedAStatus& result) {
+        if (result.isOk()) {
+            return OK;
+        }
+        int32_t exception_code = result.getExceptionCode();
+        int32_t error_code = result.getServiceSpecificError();
+        if (exception_code == EX_SERVICE_SPECIFIC && error_code != 0) {
+            ReturnedError re = {.err_type = ErrorType::AIDL_ERROR,
+                                .err_val.aidl_error = static_cast<Error>(error_code)};
+            return re;
+        }
+        ReturnedError re = {.err_type = ErrorType::BINDER_ERROR,
+                            .err_val.binder_error = exception_code};
+        return re;
+    }
+
+    // Build the parameters for the VTS test by enumerating the available HAL instances
+    static std::vector<std::string> build_params() {
+        auto params = ::android::getAidlHalInstanceNames(IAuthGraphKeyExchange::descriptor);
+        return params;
+    }
+
+    void SetUp() override {
+        ASSERT_TRUE(AServiceManager_isDeclared(GetParam().c_str()))
+                << "No instance declared for " << GetParam();
+        ::ndk::SpAIBinder binder(AServiceManager_waitForService(GetParam().c_str()));
+        authNode_ = IAuthGraphKeyExchange::fromBinder(binder);
+        ASSERT_NE(authNode_, nullptr) << "Failed to get Binder reference for " << GetParam();
+    }
+
+    void TearDown() override {}
+
+  protected:
+    std::shared_ptr<IAuthGraphKeyExchange> authNode_;
+};
+
+TEST_P(AuthGraphSessionTest, Mainline) {
+    std::shared_ptr<IAuthGraphKeyExchange> source = authNode_;
+    std::shared_ptr<IAuthGraphKeyExchange> sink = authNode_;
+
+    // Step 1: create an ephemeral ECDH key at the source.
+    SessionInitiationInfo source_init_info;
+    ASSERT_EQ(OK, GetReturnError(source->create(&source_init_info)));
+    ASSERT_TRUE(source_init_info.key.pubKey.has_value());
+    ASSERT_TRUE(source_init_info.key.arcFromPBK.has_value());
+
+    // Step 2: pass the source's ECDH public key and other session info to the sink.
+    KeInitResult init_result;
+    ASSERT_EQ(OK, GetReturnError(sink->init(source_init_info.key.pubKey.value(),
+                                            source_init_info.identity, source_init_info.nonce,
+                                            source_init_info.version, &init_result)));
+    SessionInitiationInfo sink_init_info = init_result.sessionInitiationInfo;
+    ASSERT_TRUE(sink_init_info.key.pubKey.has_value());
+    // The sink_init_info.arcFromPBK need not be populated, as the ephemeral key agreement
+    // key is no longer needed.
+
+    SessionInfo sink_info = init_result.sessionInfo;
+    ASSERT_EQ((int)sink_info.sharedKeys.size(), 2) << "Expect two symmetric keys from init()";
+    ASSERT_GT((int)sink_info.sessionId.size(), 0) << "Expect non-empty session ID from sink";
+    std::vector<uint8_t> sink_signing_key = SigningKeyFromIdentity(sink_init_info.identity);
+    CheckSignature(sink_signing_key, sink_info.sessionId, sink_info.signature);
+
+    // Step 3: pass the sink's ECDH public key and other session info to the source, so it can
+    // calculate the same pair of symmetric keys.
+    SessionInfo source_info;
+    ASSERT_EQ(OK, GetReturnError(source->finish(sink_init_info.key.pubKey.value(),
+                                                sink_init_info.identity, sink_info.signature,
+                                                sink_init_info.nonce, sink_init_info.version,
+                                                source_init_info.key, &source_info)));
+    ASSERT_EQ((int)source_info.sharedKeys.size(), 2) << "Expect two symmetric keys from finsh()";
+    ASSERT_GT((int)source_info.sessionId.size(), 0) << "Expect non-empty session ID from source";
+    std::vector<uint8_t> source_signing_key = SigningKeyFromIdentity(source_init_info.identity);
+    CheckSignature(source_signing_key, source_info.sessionId, source_info.signature);
+
+    // Both ends should agree on the session ID.
+    ASSERT_EQ(source_info.sessionId, sink_info.sessionId);
+
+    // Step 4: pass the source's session ID info back to the sink, so it can check it and
+    // update the symmetric keys so they're marked as authentication complete.
+    std::array<Arc, 2> auth_complete_result;
+    ASSERT_EQ(OK, GetReturnError(sink->authenticationComplete(
+                          source_info.signature, sink_info.sharedKeys, &auth_complete_result)));
+    ASSERT_EQ((int)auth_complete_result.size(), 2)
+            << "Expect two symmetric keys from authComplete()";
+    sink_info.sharedKeys = auth_complete_result;
+
+    // At this point the sink and source have agreed on the same pair of symmetric keys,
+    // encoded as `sink_info.sharedKeys` and `source_info.sharedKeys`.
+}
+
+TEST_P(AuthGraphSessionTest, ParallelSink) {
+    std::shared_ptr<IAuthGraphKeyExchange> source = authNode_;
+    std::shared_ptr<IAuthGraphKeyExchange> sink1 = authNode_;
+    std::shared_ptr<IAuthGraphKeyExchange> sink2 = authNode_;
+
+    // Step 1: create ephemeral ECDH keys at the source.
+    SessionInitiationInfo source_init1_info;
+    ASSERT_EQ(OK, GetReturnError(source->create(&source_init1_info)));
+    ASSERT_TRUE(source_init1_info.key.pubKey.has_value());
+    ASSERT_TRUE(source_init1_info.key.arcFromPBK.has_value());
+    SessionInitiationInfo source_init2_info;
+    ASSERT_EQ(OK, GetReturnError(source->create(&source_init2_info)));
+    ASSERT_TRUE(source_init2_info.key.pubKey.has_value());
+    ASSERT_TRUE(source_init2_info.key.arcFromPBK.has_value());
+
+    // Step 2: pass the source's ECDH public keys and other session info to the sinks.
+    KeInitResult init1_result;
+    ASSERT_EQ(OK, GetReturnError(sink1->init(source_init1_info.key.pubKey.value(),
+                                             source_init1_info.identity, source_init1_info.nonce,
+                                             source_init1_info.version, &init1_result)));
+    SessionInitiationInfo sink1_init_info = init1_result.sessionInitiationInfo;
+    ASSERT_TRUE(sink1_init_info.key.pubKey.has_value());
+
+    SessionInfo sink1_info = init1_result.sessionInfo;
+    ASSERT_EQ((int)sink1_info.sharedKeys.size(), 2) << "Expect two symmetric keys from init()";
+    ASSERT_GT((int)sink1_info.sessionId.size(), 0) << "Expect non-empty session ID from sink";
+    std::vector<uint8_t> sink1_signing_key = SigningKeyFromIdentity(sink1_init_info.identity);
+    CheckSignature(sink1_signing_key, sink1_info.sessionId, sink1_info.signature);
+    KeInitResult init2_result;
+    ASSERT_EQ(OK, GetReturnError(sink2->init(source_init2_info.key.pubKey.value(),
+                                             source_init2_info.identity, source_init2_info.nonce,
+                                             source_init2_info.version, &init2_result)));
+    SessionInitiationInfo sink2_init_info = init2_result.sessionInitiationInfo;
+    ASSERT_TRUE(sink2_init_info.key.pubKey.has_value());
+
+    SessionInfo sink2_info = init2_result.sessionInfo;
+    ASSERT_EQ((int)sink2_info.sharedKeys.size(), 2) << "Expect two symmetric keys from init()";
+    ASSERT_GT((int)sink2_info.sessionId.size(), 0) << "Expect non-empty session ID from sink";
+    std::vector<uint8_t> sink2_signing_key = SigningKeyFromIdentity(sink2_init_info.identity);
+    CheckSignature(sink2_signing_key, sink2_info.sessionId, sink2_info.signature);
+
+    // Step 3: pass each sink's ECDH public key and other session info to the source, so it can
+    // calculate the same pair of symmetric keys.
+    SessionInfo source_info1;
+    ASSERT_EQ(OK, GetReturnError(source->finish(sink1_init_info.key.pubKey.value(),
+                                                sink1_init_info.identity, sink1_info.signature,
+                                                sink1_init_info.nonce, sink1_init_info.version,
+                                                source_init1_info.key, &source_info1)));
+    ASSERT_EQ((int)source_info1.sharedKeys.size(), 2) << "Expect two symmetric keys from finsh()";
+    ASSERT_GT((int)source_info1.sessionId.size(), 0) << "Expect non-empty session ID from source";
+    std::vector<uint8_t> source_signing_key1 = SigningKeyFromIdentity(source_init1_info.identity);
+    CheckSignature(source_signing_key1, source_info1.sessionId, source_info1.signature);
+    SessionInfo source_info2;
+    ASSERT_EQ(OK, GetReturnError(source->finish(sink2_init_info.key.pubKey.value(),
+                                                sink2_init_info.identity, sink2_info.signature,
+                                                sink2_init_info.nonce, sink2_init_info.version,
+                                                source_init2_info.key, &source_info2)));
+    ASSERT_EQ((int)source_info2.sharedKeys.size(), 2) << "Expect two symmetric keys from finsh()";
+    ASSERT_GT((int)source_info2.sessionId.size(), 0) << "Expect non-empty session ID from source";
+    std::vector<uint8_t> source_signing_key2 = SigningKeyFromIdentity(source_init2_info.identity);
+    CheckSignature(source_signing_key2, source_info2.sessionId, source_info2.signature);
+
+    // Both ends should agree on the session ID.
+    ASSERT_EQ(source_info1.sessionId, sink1_info.sessionId);
+    ASSERT_EQ(source_info2.sessionId, sink2_info.sessionId);
+
+    // Step 4: pass the source's session ID info back to the sink, so it can check it and
+    // update the symmetric keys so they're marked as authentication complete.
+    std::array<Arc, 2> auth_complete_result1;
+    ASSERT_EQ(OK, GetReturnError(sink1->authenticationComplete(
+                          source_info1.signature, sink1_info.sharedKeys, &auth_complete_result1)));
+    ASSERT_EQ((int)auth_complete_result1.size(), 2)
+            << "Expect two symmetric keys from authComplete()";
+    sink1_info.sharedKeys = auth_complete_result1;
+    std::array<Arc, 2> auth_complete_result2;
+    ASSERT_EQ(OK, GetReturnError(sink2->authenticationComplete(
+                          source_info2.signature, sink2_info.sharedKeys, &auth_complete_result2)));
+    ASSERT_EQ((int)auth_complete_result2.size(), 2)
+            << "Expect two symmetric keys from authComplete()";
+    sink2_info.sharedKeys = auth_complete_result2;
+}
+
+TEST_P(AuthGraphSessionTest, ParallelSource) {
+    std::shared_ptr<IAuthGraphKeyExchange> source1 = authNode_;
+    std::shared_ptr<IAuthGraphKeyExchange> source2 = authNode_;
+    std::shared_ptr<IAuthGraphKeyExchange> sink = authNode_;
+
+    // Step 1: create an ephemeral ECDH key at each of the sources.
+    SessionInitiationInfo source1_init_info;
+    ASSERT_EQ(OK, GetReturnError(source1->create(&source1_init_info)));
+    ASSERT_TRUE(source1_init_info.key.pubKey.has_value());
+    ASSERT_TRUE(source1_init_info.key.arcFromPBK.has_value());
+    SessionInitiationInfo source2_init_info;
+    ASSERT_EQ(OK, GetReturnError(source1->create(&source2_init_info)));
+    ASSERT_TRUE(source2_init_info.key.pubKey.has_value());
+    ASSERT_TRUE(source2_init_info.key.arcFromPBK.has_value());
+
+    // Step 2: pass each source's ECDH public key and other session info to the sink.
+    KeInitResult init1_result;
+    ASSERT_EQ(OK, GetReturnError(sink->init(source1_init_info.key.pubKey.value(),
+                                            source1_init_info.identity, source1_init_info.nonce,
+                                            source1_init_info.version, &init1_result)));
+    SessionInitiationInfo sink_init1_info = init1_result.sessionInitiationInfo;
+    ASSERT_TRUE(sink_init1_info.key.pubKey.has_value());
+
+    SessionInfo sink_info1 = init1_result.sessionInfo;
+    ASSERT_EQ((int)sink_info1.sharedKeys.size(), 2) << "Expect two symmetric keys from init()";
+    ASSERT_GT((int)sink_info1.sessionId.size(), 0) << "Expect non-empty session ID from sink";
+    std::vector<uint8_t> sink_signing_key1 = SigningKeyFromIdentity(sink_init1_info.identity);
+    CheckSignature(sink_signing_key1, sink_info1.sessionId, sink_info1.signature);
+
+    KeInitResult init2_result;
+    ASSERT_EQ(OK, GetReturnError(sink->init(source2_init_info.key.pubKey.value(),
+                                            source2_init_info.identity, source2_init_info.nonce,
+                                            source2_init_info.version, &init2_result)));
+    SessionInitiationInfo sink_init2_info = init2_result.sessionInitiationInfo;
+    ASSERT_TRUE(sink_init2_info.key.pubKey.has_value());
+
+    SessionInfo sink_info2 = init2_result.sessionInfo;
+    ASSERT_EQ((int)sink_info2.sharedKeys.size(), 2) << "Expect two symmetric keys from init()";
+    ASSERT_GT((int)sink_info2.sessionId.size(), 0) << "Expect non-empty session ID from sink";
+    std::vector<uint8_t> sink_signing_key2 = SigningKeyFromIdentity(sink_init2_info.identity);
+    CheckSignature(sink_signing_key2, sink_info2.sessionId, sink_info2.signature);
+
+    // Step 3: pass the sink's ECDH public keys and other session info to the each of the sources.
+    SessionInfo source1_info;
+    ASSERT_EQ(OK, GetReturnError(source1->finish(sink_init1_info.key.pubKey.value(),
+                                                 sink_init1_info.identity, sink_info1.signature,
+                                                 sink_init1_info.nonce, sink_init1_info.version,
+                                                 source1_init_info.key, &source1_info)));
+    ASSERT_EQ((int)source1_info.sharedKeys.size(), 2) << "Expect two symmetric keys from finsh()";
+    ASSERT_GT((int)source1_info.sessionId.size(), 0) << "Expect non-empty session ID from source";
+    std::vector<uint8_t> source1_signing_key = SigningKeyFromIdentity(source1_init_info.identity);
+    CheckSignature(source1_signing_key, source1_info.sessionId, source1_info.signature);
+
+    SessionInfo source2_info;
+    ASSERT_EQ(OK, GetReturnError(source2->finish(sink_init2_info.key.pubKey.value(),
+                                                 sink_init2_info.identity, sink_info2.signature,
+                                                 sink_init2_info.nonce, sink_init2_info.version,
+                                                 source2_init_info.key, &source2_info)));
+    ASSERT_EQ((int)source2_info.sharedKeys.size(), 2) << "Expect two symmetric keys from finsh()";
+    ASSERT_GT((int)source2_info.sessionId.size(), 0) << "Expect non-empty session ID from source";
+    std::vector<uint8_t> source2_signing_key = SigningKeyFromIdentity(source2_init_info.identity);
+    CheckSignature(source2_signing_key, source2_info.sessionId, source2_info.signature);
+
+    // Both ends should agree on the session ID.
+    ASSERT_EQ(source1_info.sessionId, sink_info1.sessionId);
+    ASSERT_EQ(source2_info.sessionId, sink_info2.sessionId);
+
+    // Step 4: pass the each source's session ID info back to the sink, so it can check it and
+    // update the symmetric keys so they're marked as authentication complete.
+    std::array<Arc, 2> auth_complete_result1;
+    ASSERT_EQ(OK, GetReturnError(sink->authenticationComplete(
+                          source1_info.signature, sink_info1.sharedKeys, &auth_complete_result1)));
+    ASSERT_EQ((int)auth_complete_result1.size(), 2)
+            << "Expect two symmetric keys from authComplete()";
+    sink_info1.sharedKeys = auth_complete_result1;
+    std::array<Arc, 2> auth_complete_result2;
+    ASSERT_EQ(OK, GetReturnError(sink->authenticationComplete(
+                          source2_info.signature, sink_info2.sharedKeys, &auth_complete_result2)));
+    ASSERT_EQ((int)auth_complete_result2.size(), 2)
+            << "Expect two symmetric keys from authComplete()";
+    sink_info2.sharedKeys = auth_complete_result2;
+}
+
+TEST_P(AuthGraphSessionTest, FreshNonces) {
+    std::shared_ptr<IAuthGraphKeyExchange> source = authNode_;
+    std::shared_ptr<IAuthGraphKeyExchange> sink = authNode_;
+
+    SessionInitiationInfo source_init_info1;
+    ASSERT_EQ(OK, GetReturnError(source->create(&source_init_info1)));
+    SessionInitiationInfo source_init_info2;
+    ASSERT_EQ(OK, GetReturnError(source->create(&source_init_info2)));
+
+    // Two calls to create() should result in the same identity but different nonce values.
+    ASSERT_EQ(source_init_info1.identity, source_init_info2.identity);
+    ASSERT_NE(source_init_info1.nonce, source_init_info2.nonce);
+    ASSERT_NE(source_init_info1.key.pubKey, source_init_info2.key.pubKey);
+    ASSERT_NE(source_init_info1.key.arcFromPBK, source_init_info2.key.arcFromPBK);
+
+    KeInitResult init_result1;
+    ASSERT_EQ(OK, GetReturnError(sink->init(source_init_info1.key.pubKey.value(),
+                                            source_init_info1.identity, source_init_info1.nonce,
+                                            source_init_info1.version, &init_result1)));
+    KeInitResult init_result2;
+    ASSERT_EQ(OK, GetReturnError(sink->init(source_init_info2.key.pubKey.value(),
+                                            source_init_info2.identity, source_init_info2.nonce,
+                                            source_init_info2.version, &init_result2)));
+
+    // Two calls to init() should result in the same identity buf different nonces and session IDs.
+    ASSERT_EQ(init_result1.sessionInitiationInfo.identity,
+              init_result2.sessionInitiationInfo.identity);
+    ASSERT_NE(init_result1.sessionInitiationInfo.nonce, init_result2.sessionInitiationInfo.nonce);
+    ASSERT_NE(init_result1.sessionInfo.sessionId, init_result2.sessionInfo.sessionId);
+}
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, AuthGraphSessionTest,
+                         testing::ValuesIn(AuthGraphSessionTest::build_params()),
+                         ::android::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AuthGraphSessionTest);
+
+}  // namespace aidl::android::hardware::security::authgraph::test
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    return RUN_ALL_TESTS();
+}
diff --git a/security/authgraph/aidl/vts/functional/lib.rs b/security/authgraph/aidl/vts/functional/lib.rs
new file mode 100644
index 0000000..f4c1da9
--- /dev/null
+++ b/security/authgraph/aidl/vts/functional/lib.rs
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! VTS test library for AuthGraph functionality.
+//!
+//! This test code is bundled as a library, not as `[cfg(test)]`, to allow it to be
+//! re-used inside the (Rust) VTS tests of components that use AuthGraph.
+
+use android_hardware_security_authgraph::aidl::android::hardware::security::authgraph::{
+    Error::Error, IAuthGraphKeyExchange::IAuthGraphKeyExchange, Identity::Identity,
+    PlainPubKey::PlainPubKey, PubKey::PubKey, SessionIdSignature::SessionIdSignature,
+};
+use authgraph_boringssl as boring;
+use authgraph_core::{error::Error as AgError, keyexchange as ke};
+use coset::CborSerializable;
+use std::{cell::RefCell, rc::Rc};
+
+pub mod sink;
+pub mod source;
+
+/// Return an AuthGraphParticipant suitable for testing.
+pub fn test_ag_participant() -> Result<ke::AuthGraphParticipant, AgError> {
+    Ok(ke::AuthGraphParticipant::new(
+        boring::crypto_trait_impls(),
+        Rc::new(RefCell::new(boring::test_device::AgDevice::default())),
+        ke::MAX_OPENED_SESSIONS,
+    )?)
+}
+
+fn build_plain_pub_key(pub_key: &Option<Vec<u8>>) -> PubKey {
+    PubKey::PlainKey(PlainPubKey {
+        plainPubKey: pub_key.clone().unwrap(),
+    })
+}
+
+fn extract_plain_pub_key(pub_key: &Option<PubKey>) -> &PlainPubKey {
+    match pub_key {
+        Some(PubKey::PlainKey(pub_key)) => pub_key,
+        Some(PubKey::SignedKey(_)) => panic!("expect unsigned public key"),
+        None => panic!("expect pubKey to be populated"),
+    }
+}
+
+fn vec_to_identity(data: &[u8]) -> Identity {
+    Identity {
+        identity: data.to_vec(),
+    }
+}
+
+fn vec_to_signature(data: &[u8]) -> SessionIdSignature {
+    SessionIdSignature {
+        signature: data.to_vec(),
+    }
+}
diff --git a/security/authgraph/aidl/vts/functional/role_test.rs b/security/authgraph/aidl/vts/functional/role_test.rs
new file mode 100644
index 0000000..3075d8a
--- /dev/null
+++ b/security/authgraph/aidl/vts/functional/role_test.rs
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! Tests of individual AuthGraph role (source or sink) functionality.
+
+#![cfg(test)]
+
+use authgraph_vts_test as vts;
+use android_hardware_security_authgraph::aidl::android::hardware::security::authgraph::{
+    IAuthGraphKeyExchange::IAuthGraphKeyExchange,
+};
+use binder::StatusCode;
+
+const AUTH_GRAPH_NONSECURE: &str =
+    "android.hardware.security.authgraph.IAuthGraphKeyExchange/nonsecure";
+
+/// Retrieve the /nonsecure instance of AuthGraph, which supports both sink and source roles.
+fn get_nonsecure() -> Option<binder::Strong<dyn IAuthGraphKeyExchange>> {
+    match binder::get_interface(AUTH_GRAPH_NONSECURE) {
+        Ok(ag) => Some(ag),
+        Err(StatusCode::NAME_NOT_FOUND) => None,
+        Err(e) => panic!("failed to get AuthGraph/nonsecure: {e:?}"),
+    }
+}
+
+/// Macro to require availability of a /nonsecure instance of AuthGraph.
+///
+/// Note that this macro triggers `return` if not found.
+macro_rules! require_nonsecure {
+    {} => {
+        match get_nonsecure() {
+            Some(v) => v,
+            None => {
+                eprintln!("Skipping test as no /nonsecure impl found");
+                return;
+            }
+        }
+    }
+}
+
+#[test]
+fn test_nonsecure_source_mainline() {
+    let mut sink = vts::test_ag_participant().expect("failed to create a local sink");
+    vts::source::test_mainline(&mut sink, require_nonsecure!());
+}
+#[test]
+fn test_nonsecure_source_corrupt_sig() {
+    let mut sink = vts::test_ag_participant().expect("failed to create a local sink");
+    vts::source::test_corrupt_sig(&mut sink, require_nonsecure!());
+}
+#[test]
+fn test_nonsecure_source_corrupt_keys() {
+    let mut sink = vts::test_ag_participant().expect("failed to create a local sink");
+    vts::source::test_corrupt_key(&mut sink, require_nonsecure!());
+}
+#[test]
+fn test_nonsecure_sink_mainline() {
+    let mut source = vts::test_ag_participant().expect("failed to create a local source");
+    vts::sink::test_mainline(&mut source, require_nonsecure!());
+}
+#[test]
+fn test_nonsecure_sink_corrupt_sig() {
+    let mut source = vts::test_ag_participant().expect("failed to create a local source");
+    vts::sink::test_corrupt_sig(&mut source, require_nonsecure!());
+}
+#[test]
+fn test_nonsecure_sink_corrupt_keys() {
+    let mut source = vts::test_ag_participant().expect("failed to create a local source");
+    vts::sink::test_corrupt_keys(&mut source, require_nonsecure!());
+}
diff --git a/security/authgraph/aidl/vts/functional/sink.rs b/security/authgraph/aidl/vts/functional/sink.rs
new file mode 100644
index 0000000..a331eef
--- /dev/null
+++ b/security/authgraph/aidl/vts/functional/sink.rs
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! VTS tests for sinks
+use super::*;
+use authgraph_core::{key, keyexchange as ke};
+
+/// Run AuthGraph tests against the provided sink, using a local test source implementation.
+pub fn test(
+    local_source: &mut ke::AuthGraphParticipant,
+    sink: binder::Strong<dyn IAuthGraphKeyExchange>,
+) {
+    test_mainline(local_source, sink.clone());
+    test_corrupt_sig(local_source, sink.clone());
+    test_corrupt_keys(local_source, sink);
+}
+
+/// Perform mainline AuthGraph key exchange with the provided sink and local implementation.
+/// Return the agreed AES keys in plaintext, together with the session ID.
+pub fn test_mainline(
+    local_source: &mut ke::AuthGraphParticipant,
+    sink: binder::Strong<dyn IAuthGraphKeyExchange>,
+) -> ([key::AesKey; 2], Vec<u8>) {
+    // Step 1: create an ephemeral ECDH key at the (local) source.
+    let source_init_info = local_source
+        .create()
+        .expect("failed to create() with local impl");
+
+    // Step 2: pass the source's ECDH public key and other session info to the (remote) sink.
+    let init_result = sink
+        .init(
+            &build_plain_pub_key(&source_init_info.ke_key.pub_key),
+            &vec_to_identity(&source_init_info.identity),
+            &source_init_info.nonce,
+            source_init_info.version,
+        )
+        .expect("failed to init() with remote impl");
+    let sink_init_info = init_result.sessionInitiationInfo;
+    let sink_pub_key = extract_plain_pub_key(&sink_init_info.key.pubKey);
+
+    let sink_info = init_result.sessionInfo;
+    assert!(!sink_info.sessionId.is_empty());
+
+    // The AuthGraph core library will verify the session ID signature, but do it here too.
+    let sink_verification_key = local_source
+        .peer_verification_key_from_identity(&sink_init_info.identity.identity)
+        .expect("failed to get peer verification from identity");
+    local_source
+        .verify_signature_on_session_id(
+            &sink_verification_key,
+            &sink_info.sessionId,
+            &sink_info.signature.signature,
+        )
+        .expect("failed verification of signed session ID");
+
+    // Step 3: pass the sink's ECDH public key and other session info to the (local) source, so it
+    // can calculate the same pair of symmetric keys.
+    let source_info = local_source
+        .finish(
+            &sink_pub_key.plainPubKey,
+            &sink_init_info.identity.identity,
+            &sink_info.signature.signature,
+            &sink_init_info.nonce,
+            sink_init_info.version,
+            source_init_info.ke_key,
+        )
+        .expect("failed to finish() with local impl");
+    assert!(!source_info.session_id.is_empty());
+
+    // The AuthGraph core library will verify the session ID signature, but do it here too.
+    let source_verification_key = key::Identity::from_slice(&source_init_info.identity)
+        .expect("invalid identity CBOR")
+        .cert_chain
+        .root_key;
+    local_source
+        .verify_signature_on_session_id(
+            &source_verification_key,
+            &source_info.session_id,
+            &source_info.session_id_signature,
+        )
+        .expect("failed verification of signed session ID");
+
+    // Both ends should agree on the session ID.
+    assert_eq!(source_info.session_id, sink_info.sessionId);
+
+    // Step 4: pass the (local) source's session ID signature back to the sink, so it can check it
+    // and update the symmetric keys so they're marked as authentication complete.
+    let _sink_arcs = sink
+        .authenticationComplete(
+            &vec_to_signature(&source_info.session_id_signature),
+            &sink_info.sharedKeys,
+        )
+        .expect("failed to authenticationComplete() with remote sink");
+    // Decrypt and return the session keys.
+    let decrypted_shared_keys = local_source
+        .decipher_shared_keys_from_arcs(&source_info.shared_keys)
+        .expect("failed to decrypt shared key arcs")
+        .try_into();
+    let decrypted_shared_keys_array = match decrypted_shared_keys {
+        Ok(array) => array,
+        Err(_) => panic!("wrong number of decrypted shared key arcs"),
+    };
+    (decrypted_shared_keys_array, sink_info.sessionId)
+}
+
+/// Perform mainline AuthGraph key exchange with the provided sink, but provide an invalid
+/// session ID signature.
+pub fn test_corrupt_sig(
+    local_source: &mut ke::AuthGraphParticipant,
+    sink: binder::Strong<dyn IAuthGraphKeyExchange>,
+) {
+    // Step 1: create an ephemeral ECDH key at the (local) source.
+    let source_init_info = local_source
+        .create()
+        .expect("failed to create() with local impl");
+
+    // Step 2: pass the source's ECDH public key and other session info to the (remote) sink.
+    let init_result = sink
+        .init(
+            &build_plain_pub_key(&source_init_info.ke_key.pub_key),
+            &vec_to_identity(&source_init_info.identity),
+            &source_init_info.nonce,
+            source_init_info.version,
+        )
+        .expect("failed to init() with remote impl");
+    let sink_init_info = init_result.sessionInitiationInfo;
+    let sink_pub_key = extract_plain_pub_key(&sink_init_info.key.pubKey);
+
+    let sink_info = init_result.sessionInfo;
+    assert!(!sink_info.sessionId.is_empty());
+
+    // Step 3: pass the sink's ECDH public key and other session info to the (local) source, so it
+    // can calculate the same pair of symmetric keys.
+    let source_info = local_source
+        .finish(
+            &sink_pub_key.plainPubKey,
+            &sink_init_info.identity.identity,
+            &sink_info.signature.signature,
+            &sink_init_info.nonce,
+            sink_init_info.version,
+            source_init_info.ke_key,
+        )
+        .expect("failed to finish() with local impl");
+    assert!(!source_info.session_id.is_empty());
+
+    // Build a corrupted version of the (local) source's session ID signature.
+    let mut corrupt_signature = source_info.session_id_signature.clone();
+    let sig_len = corrupt_signature.len();
+    corrupt_signature[sig_len - 1] ^= 0x01;
+
+    // Step 4: pass the (local) source's **invalid** session ID signature back to the sink,
+    // which should reject it.
+    let result =
+        sink.authenticationComplete(&vec_to_signature(&corrupt_signature), &sink_info.sharedKeys);
+    let err = result.expect_err("expect failure with corrupt signature");
+    assert_eq!(
+        err,
+        binder::Status::new_service_specific_error(Error::INVALID_SIGNATURE.0, None)
+    );
+}
+
+/// Perform mainline AuthGraph key exchange with the provided sink, but provide an invalid
+/// Arc for the sink's key.
+pub fn test_corrupt_keys(
+    local_source: &mut ke::AuthGraphParticipant,
+    sink: binder::Strong<dyn IAuthGraphKeyExchange>,
+) {
+    // Step 1: create an ephemeral ECDH key at the (local) source.
+    let source_init_info = local_source
+        .create()
+        .expect("failed to create() with local impl");
+
+    // Step 2: pass the source's ECDH public key and other session info to the (remote) sink.
+    let init_result = sink
+        .init(
+            &build_plain_pub_key(&source_init_info.ke_key.pub_key),
+            &vec_to_identity(&source_init_info.identity),
+            &source_init_info.nonce,
+            source_init_info.version,
+        )
+        .expect("failed to init() with remote impl");
+    let sink_init_info = init_result.sessionInitiationInfo;
+    let sink_pub_key = extract_plain_pub_key(&sink_init_info.key.pubKey);
+
+    let sink_info = init_result.sessionInfo;
+    assert!(!sink_info.sessionId.is_empty());
+
+    // Step 3: pass the sink's ECDH public key and other session info to the (local) source, so it
+    // can calculate the same pair of symmetric keys.
+    let source_info = local_source
+        .finish(
+            &sink_pub_key.plainPubKey,
+            &sink_init_info.identity.identity,
+            &sink_info.signature.signature,
+            &sink_init_info.nonce,
+            sink_init_info.version,
+            source_init_info.ke_key,
+        )
+        .expect("failed to finish() with local impl");
+    assert!(!source_info.session_id.is_empty());
+
+    // Deliberately corrupt the sink's shared key Arcs before returning them
+    let mut corrupt_keys = sink_info.sharedKeys.clone();
+    let len0 = corrupt_keys[0].arc.len();
+    let len1 = corrupt_keys[1].arc.len();
+    corrupt_keys[0].arc[len0 - 1] ^= 0x01;
+    corrupt_keys[1].arc[len1 - 1] ^= 0x01;
+
+    // Step 4: pass the (local) source's session ID signature back to the sink, but with corrupted
+    // keys, which should be rejected.
+    let result = sink.authenticationComplete(
+        &vec_to_signature(&source_info.session_id_signature),
+        &corrupt_keys,
+    );
+    let err = result.expect_err("expect failure with corrupt keys");
+    assert_eq!(
+        err,
+        binder::Status::new_service_specific_error(Error::INVALID_SHARED_KEY_ARCS.0, None)
+    );
+}
diff --git a/security/authgraph/aidl/vts/functional/source.rs b/security/authgraph/aidl/vts/functional/source.rs
new file mode 100644
index 0000000..019e1e8
--- /dev/null
+++ b/security/authgraph/aidl/vts/functional/source.rs
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! VTS tests for sources
+use super::*;
+use authgraph_core::{key, keyexchange as ke};
+
+/// Run AuthGraph tests against the provided source, using a local test sink implementation.
+pub fn test(
+    local_sink: &mut ke::AuthGraphParticipant,
+    source: binder::Strong<dyn IAuthGraphKeyExchange>,
+) {
+    test_mainline(local_sink, source.clone());
+    test_corrupt_sig(local_sink, source.clone());
+    test_corrupt_key(local_sink, source);
+}
+
+/// Perform mainline AuthGraph key exchange with the provided source.
+/// Return the agreed AES keys in plaintext, together with the session ID.
+pub fn test_mainline(
+    local_sink: &mut ke::AuthGraphParticipant,
+    source: binder::Strong<dyn IAuthGraphKeyExchange>,
+) -> ([key::AesKey; 2], Vec<u8>) {
+    // Step 1: create an ephemeral ECDH key at the (remote) source.
+    let source_init_info = source
+        .create()
+        .expect("failed to create() with remote impl");
+    assert!(source_init_info.key.pubKey.is_some());
+    assert!(source_init_info.key.arcFromPBK.is_some());
+    let source_pub_key = extract_plain_pub_key(&source_init_info.key.pubKey);
+
+    // Step 2: pass the source's ECDH public key and other session info to the (local) sink.
+    let init_result = local_sink
+        .init(
+            &source_pub_key.plainPubKey,
+            &source_init_info.identity.identity,
+            &source_init_info.nonce,
+            source_init_info.version,
+        )
+        .expect("failed to init() with local impl");
+    let sink_init_info = init_result.session_init_info;
+    let sink_pub_key = sink_init_info
+        .ke_key
+        .pub_key
+        .expect("expect pub_key to be populated");
+
+    let sink_info = init_result.session_info;
+    assert!(!sink_info.session_id.is_empty());
+
+    // The AuthGraph core library will verify the session ID signature, but do it here too.
+    let sink_verification_key = key::Identity::from_slice(&sink_init_info.identity)
+        .expect("invalid identity CBOR")
+        .cert_chain
+        .root_key;
+    local_sink
+        .verify_signature_on_session_id(
+            &sink_verification_key,
+            &sink_info.session_id,
+            &sink_info.session_id_signature,
+        )
+        .expect("failed verification of signed session ID");
+
+    // Step 3: pass the sink's ECDH public key and other session info to the (remote) source, so it
+    // can calculate the same pair of symmetric keys.
+    let source_info = source
+        .finish(
+            &PubKey::PlainKey(PlainPubKey {
+                plainPubKey: sink_pub_key,
+            }),
+            &Identity {
+                identity: sink_init_info.identity,
+            },
+            &vec_to_signature(&sink_info.session_id_signature),
+            &sink_init_info.nonce,
+            sink_init_info.version,
+            &source_init_info.key,
+        )
+        .expect("failed to finish() with remote impl");
+    assert!(!source_info.sessionId.is_empty());
+
+    // The AuthGraph core library will verify the session ID signature, but do it here too.
+    let source_verification_key = local_sink
+        .peer_verification_key_from_identity(&source_init_info.identity.identity)
+        .expect("failed to get peer verification from identity");
+    local_sink
+        .verify_signature_on_session_id(
+            &source_verification_key,
+            &source_info.sessionId,
+            &source_info.signature.signature,
+        )
+        .expect("failed verification of signed session ID");
+
+    // Both ends should agree on the session ID.
+    assert_eq!(source_info.sessionId, sink_info.session_id);
+
+    // Step 4: pass the (remote) source's session ID signature back to the sink, so it can check it
+    // and update the symmetric keys so they're marked as authentication complete.
+    let sink_arcs = local_sink
+        .authentication_complete(&source_info.signature.signature, sink_info.shared_keys)
+        .expect("failed to authenticationComplete() with local sink");
+    // Decrypt and return the session keys.
+    let decrypted_shared_keys = local_sink
+        .decipher_shared_keys_from_arcs(&sink_arcs)
+        .expect("failed to decrypt shared key arcs")
+        .try_into();
+    let decrypted_shared_keys_array = match decrypted_shared_keys {
+        Ok(array) => array,
+        Err(_) => panic!("wrong number of decrypted shared key arcs"),
+    };
+    (decrypted_shared_keys_array, source_info.sessionId)
+}
+
+/// Perform mainline AuthGraph key exchange with the provided source, but provide an invalid session
+/// ID signature.
+pub fn test_corrupt_sig(
+    local_sink: &mut ke::AuthGraphParticipant,
+    source: binder::Strong<dyn IAuthGraphKeyExchange>,
+) {
+    // Step 1: create an ephemeral ECDH key at the (remote) source.
+    let source_init_info = source
+        .create()
+        .expect("failed to create() with remote impl");
+    assert!(source_init_info.key.pubKey.is_some());
+    assert!(source_init_info.key.arcFromPBK.is_some());
+    let source_pub_key = extract_plain_pub_key(&source_init_info.key.pubKey);
+
+    // Step 2: pass the source's ECDH public key and other session info to the (local) sink.
+    let init_result = local_sink
+        .init(
+            &source_pub_key.plainPubKey,
+            &source_init_info.identity.identity,
+            &source_init_info.nonce,
+            source_init_info.version,
+        )
+        .expect("failed to init() with local impl");
+    let sink_init_info = init_result.session_init_info;
+    let sink_pub_key = sink_init_info
+        .ke_key
+        .pub_key
+        .expect("expect pub_key to be populated");
+    let sink_info = init_result.session_info;
+    assert!(!sink_info.session_id.is_empty());
+
+    // Deliberately corrupt the sink's session ID signature.
+    let mut corrupt_signature = sink_info.session_id_signature.clone();
+    let sig_len = corrupt_signature.len();
+    corrupt_signature[sig_len - 1] ^= 0x01;
+
+    // Step 3: pass the sink's ECDH public key and other session info to the (remote) source, so it
+    // can calculate the same pair of symmetric keys.
+    let result = source.finish(
+        &PubKey::PlainKey(PlainPubKey {
+            plainPubKey: sink_pub_key,
+        }),
+        &Identity {
+            identity: sink_init_info.identity,
+        },
+        &vec_to_signature(&corrupt_signature),
+        &sink_init_info.nonce,
+        sink_init_info.version,
+        &source_init_info.key,
+    );
+    let err = result.expect_err("expect failure with corrupt signature");
+    assert_eq!(
+        err,
+        binder::Status::new_service_specific_error(Error::INVALID_SIGNATURE.0, None)
+    );
+}
+
+/// Perform mainline AuthGraph key exchange with the provided source, but give it back
+/// a corrupted key.
+pub fn test_corrupt_key(
+    local_sink: &mut ke::AuthGraphParticipant,
+    source: binder::Strong<dyn IAuthGraphKeyExchange>,
+) {
+    // Step 1: create an ephemeral ECDH key at the (remote) source.
+    let source_init_info = source
+        .create()
+        .expect("failed to create() with remote impl");
+    assert!(source_init_info.key.pubKey.is_some());
+    assert!(source_init_info.key.arcFromPBK.is_some());
+    let source_pub_key = extract_plain_pub_key(&source_init_info.key.pubKey);
+
+    // Step 2: pass the source's ECDH public key and other session info to the (local) sink.
+    let init_result = local_sink
+        .init(
+            &source_pub_key.plainPubKey,
+            &source_init_info.identity.identity,
+            &source_init_info.nonce,
+            source_init_info.version,
+        )
+        .expect("failed to init() with local impl");
+    let sink_init_info = init_result.session_init_info;
+    let sink_pub_key = sink_init_info
+        .ke_key
+        .pub_key
+        .expect("expect pub_key to be populated");
+
+    let sink_info = init_result.session_info;
+    assert!(!sink_info.session_id.is_empty());
+
+    // The AuthGraph core library will verify the session ID signature, but do it here too.
+    let sink_verification_key = key::Identity::from_slice(&sink_init_info.identity)
+        .expect("invalid identity CBOR")
+        .cert_chain
+        .root_key;
+    local_sink
+        .verify_signature_on_session_id(
+            &sink_verification_key,
+            &sink_info.session_id,
+            &sink_info.session_id_signature,
+        )
+        .expect("failed verification of signed session ID");
+
+    // Deliberately corrupt the source's encrypted key.
+    let mut corrupt_key = source_init_info.key.clone();
+    match &mut corrupt_key.arcFromPBK {
+        Some(a) => {
+            let len = a.arc.len();
+            a.arc[len - 1] ^= 0x01;
+        }
+        None => panic!("no arc data"),
+    }
+
+    // Step 3: pass the sink's ECDH public key and other session info to the (remote) source, but
+    // give it back a corrupted version of its own key.
+    let result = source.finish(
+        &PubKey::PlainKey(PlainPubKey {
+            plainPubKey: sink_pub_key,
+        }),
+        &Identity {
+            identity: sink_init_info.identity,
+        },
+        &vec_to_signature(&sink_info.session_id_signature),
+        &sink_init_info.nonce,
+        sink_init_info.version,
+        &corrupt_key,
+    );
+
+    let err = result.expect_err("expect failure with corrupt key");
+    assert!(
+        err == binder::Status::new_service_specific_error(Error::INVALID_KE_KEY.0, None)
+            || err
+                == binder::Status::new_service_specific_error(
+                    Error::INVALID_PRIV_KEY_ARC_IN_KEY.0,
+                    None
+                )
+    );
+}
diff --git a/security/authgraph/default/Android.bp b/security/authgraph/default/Android.bp
new file mode 100644
index 0000000..7894477
--- /dev/null
+++ b/security/authgraph/default/Android.bp
@@ -0,0 +1,113 @@
+//
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES 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"],
+}
+
+rust_library {
+    name: "libauthgraph_nonsecure",
+    crate_name: "authgraph_nonsecure",
+    defaults: [
+        "authgraph_use_latest_hal_aidl_rust",
+    ],
+    vendor_available: true,
+    rustlibs: [
+        "libandroid_logger",
+        "libauthgraph_boringssl",
+        "libauthgraph_core",
+        "libauthgraph_hal",
+        "libbinder_rs",
+        "liblibc",
+        "liblog_rust",
+    ],
+    srcs: ["src/lib.rs"],
+
+}
+
+rust_binary {
+    name: "android.hardware.security.authgraph-service.nonsecure",
+    relative_install_path: "hw",
+    vendor: true,
+    installable: false, // install com.android.hardware.security.authgraph
+    defaults: [
+        "authgraph_use_latest_hal_aidl_rust",
+    ],
+    prefer_rlib: true,
+    rustlibs: [
+        "libandroid_logger",
+        "libauthgraph_hal",
+        "libauthgraph_nonsecure",
+        "libbinder_rs",
+        "liblibc",
+        "liblog_rust",
+    ],
+    srcs: [
+        "src/main.rs",
+    ],
+}
+
+rust_fuzz {
+    name: "android.hardware.authgraph-service.nonsecure_fuzzer",
+    rustlibs: [
+        "libauthgraph_hal",
+        "libauthgraph_nonsecure",
+        "libbinder_random_parcel_rs",
+        "libbinder_rs",
+    ],
+    srcs: ["src/fuzzer.rs"],
+    fuzz_config: {
+        cc: [
+            "drysdale@google.com",
+            "hasinitg@google.com",
+        ],
+    },
+}
+
+prebuilt_etc {
+    name: "authgraph.xml",
+    src: "authgraph.xml",
+    sub_dir: "vintf",
+    installable: false,
+}
+
+prebuilt_etc {
+    name: "authgraph.rc",
+    src: "authgraph.rc",
+    installable: false,
+}
+
+apex {
+    name: "com.android.hardware.security.authgraph",
+    manifest: "apex_manifest.json",
+    file_contexts: "apex_file_contexts",
+    key: "com.android.hardware.key",
+    certificate: ":com.android.hardware.certificate",
+    vendor: true,
+    updatable: false,
+
+    binaries: [
+        "android.hardware.security.authgraph-service.nonsecure",
+    ],
+    prebuilts: [
+        "authgraph.rc",
+        "authgraph.xml",
+    ],
+}
diff --git a/security/authgraph/default/apex_file_contexts b/security/authgraph/default/apex_file_contexts
new file mode 100644
index 0000000..9a54613
--- /dev/null
+++ b/security/authgraph/default/apex_file_contexts
@@ -0,0 +1,3 @@
+(/.*)?                                          u:object_r:vendor_file:s0
+/etc(/.*)?                                      u:object_r:vendor_configs_file:s0
+/bin/hw/android\.hardware\.security\.authgraph-service\.nonsecure  u:object_r:hal_authgraph_default_exec:s0
diff --git a/security/authgraph/default/apex_manifest.json b/security/authgraph/default/apex_manifest.json
new file mode 100644
index 0000000..0723846
--- /dev/null
+++ b/security/authgraph/default/apex_manifest.json
@@ -0,0 +1,4 @@
+{
+    "name": "com.android.hardware.security.authgraph",
+    "version": 1
+}
\ No newline at end of file
diff --git a/security/authgraph/default/authgraph.rc b/security/authgraph/default/authgraph.rc
new file mode 100644
index 0000000..2d07542
--- /dev/null
+++ b/security/authgraph/default/authgraph.rc
@@ -0,0 +1,5 @@
+service vendor.authgraph /apex/com.android.hardware.security.authgraph/bin/hw/android.hardware.security.authgraph-service.nonsecure
+    interface aidl android.hardware.security.authgraph.IAuthGraph/nonsecure
+    class hal
+    user nobody
+    group nobody
diff --git a/security/authgraph/default/authgraph.xml b/security/authgraph/default/authgraph.xml
new file mode 100644
index 0000000..9529a0a
--- /dev/null
+++ b/security/authgraph/default/authgraph.xml
@@ -0,0 +1,10 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.security.authgraph</name>
+        <version>1</version>
+        <interface>
+            <name>IAuthGraphKeyExchange</name>
+            <instance>nonsecure</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/security/authgraph/default/src/fuzzer.rs b/security/authgraph/default/src/fuzzer.rs
new file mode 100644
index 0000000..387d72f
--- /dev/null
+++ b/security/authgraph/default/src/fuzzer.rs
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#![allow(missing_docs)]
+#![no_main]
+extern crate libfuzzer_sys;
+
+use authgraph_hal::service::AuthGraphService;
+use authgraph_nonsecure::LocalTa;
+use binder_random_parcel_rs::fuzz_service;
+use libfuzzer_sys::fuzz_target;
+
+fuzz_target!(|data: &[u8]| {
+    let local_ta = LocalTa::new().expect("Failed to create an AuthGraph local TA.");
+    let service = AuthGraphService::new_as_binder(local_ta);
+    fuzz_service(&mut service.as_binder(), data);
+});
diff --git a/security/authgraph/default/src/lib.rs b/security/authgraph/default/src/lib.rs
new file mode 100644
index 0000000..1d6ffb3
--- /dev/null
+++ b/security/authgraph/default/src/lib.rs
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! Common functionality for non-secure/testing instance of AuthGraph.
+
+use authgraph_boringssl as boring;
+use authgraph_core::{
+    error, keyexchange,
+    ta::{AuthGraphTa, Role},
+};
+use authgraph_hal::channel::SerializedChannel;
+use log::error;
+use std::cell::RefCell;
+use std::rc::Rc;
+use std::sync::{mpsc, Mutex};
+
+/// Implementation of the AuthGraph TA that runs locally in-process (and which is therefore
+/// insecure).
+pub struct LocalTa {
+    channels: Mutex<Channels>,
+}
+
+struct Channels {
+    in_tx: mpsc::Sender<Vec<u8>>,
+    out_rx: mpsc::Receiver<Vec<u8>>,
+}
+
+impl LocalTa {
+    /// Create a new instance.
+    pub fn new() -> Result<Self, error::Error> {
+        // Create a pair of channels to communicate with the TA thread.
+        let (in_tx, in_rx) = mpsc::channel();
+        let (out_tx, out_rx) = mpsc::channel();
+
+        // The TA code expects to run single threaded, so spawn a thread to run it in.
+        std::thread::spawn(move || {
+            let mut ta = AuthGraphTa::new(
+                keyexchange::AuthGraphParticipant::new(
+                    boring::crypto_trait_impls(),
+                    Rc::new(RefCell::new(boring::test_device::AgDevice::default())),
+                    keyexchange::MAX_OPENED_SESSIONS,
+                )
+                .expect("failed to create AG participant"),
+                Role::Both,
+            );
+            // Loop forever processing request messages.
+            loop {
+                let req_data: Vec<u8> = match in_rx.recv() {
+                    Ok(data) => data,
+                    Err(_) => {
+                        error!("local TA failed to receive request!");
+                        break;
+                    }
+                };
+                let rsp_data = ta.process(&req_data);
+                match out_tx.send(rsp_data) {
+                    Ok(_) => {}
+                    Err(_) => {
+                        error!("local TA failed to send out response");
+                        break;
+                    }
+                }
+            }
+            error!("local TA terminating!");
+        });
+        Ok(Self {
+            channels: Mutex::new(Channels { in_tx, out_rx }),
+        })
+    }
+}
+
+impl SerializedChannel for LocalTa {
+    const MAX_SIZE: usize = usize::MAX;
+
+    fn execute(&self, req_data: &[u8]) -> binder::Result<Vec<u8>> {
+        // Serialize across both request and response.
+        let channels = self.channels.lock().unwrap();
+        channels
+            .in_tx
+            .send(req_data.to_vec())
+            .expect("failed to send in request");
+        Ok(channels.out_rx.recv().expect("failed to receive response"))
+    }
+}
diff --git a/security/authgraph/default/src/main.rs b/security/authgraph/default/src/main.rs
new file mode 100644
index 0000000..ced7567
--- /dev/null
+++ b/security/authgraph/default/src/main.rs
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! Default implementation of the AuthGraph key exchange HAL.
+//!
+//! This implementation of the HAL is only intended to allow testing and policy compliance.  A real
+//! implementation of the AuthGraph HAL would be implemented in a secure environment, and would not
+//! be independently registered with service manager (a secure component that uses AuthGraph would
+//! expose an entrypoint that allowed retrieval of the specific IAuthGraphKeyExchange instance that
+//! is correlated with the component).
+
+use authgraph_hal::service;
+use authgraph_nonsecure::LocalTa;
+use log::{error, info};
+
+static SERVICE_NAME: &str = "android.hardware.security.authgraph.IAuthGraphKeyExchange";
+static SERVICE_INSTANCE: &str = "nonsecure";
+
+/// Local error type for failures in the HAL service.
+#[derive(Debug, Clone)]
+struct HalServiceError(String);
+
+impl From<String> for HalServiceError {
+    fn from(s: String) -> Self {
+        Self(s)
+    }
+}
+
+fn main() {
+    if let Err(e) = inner_main() {
+        panic!("HAL service failed: {:?}", e);
+    }
+}
+
+fn inner_main() -> Result<(), HalServiceError> {
+    // Initialize Android logging.
+    android_logger::init_once(
+        android_logger::Config::default()
+            .with_tag("authgraph-hal-nonsecure")
+            .with_min_level(log::Level::Info)
+            .with_log_id(android_logger::LogId::System),
+    );
+    // Redirect panic messages to logcat.
+    std::panic::set_hook(Box::new(|panic_info| {
+        error!("{}", panic_info);
+    }));
+
+    info!("Insecure AuthGraph key exchange HAL service is starting.");
+
+    info!("Starting thread pool now.");
+    binder::ProcessState::start_thread_pool();
+
+    // Register the service
+    let local_ta = LocalTa::new().map_err(|e| format!("Failed to create the TA because: {e:?}"))?;
+    let service = service::AuthGraphService::new_as_binder(local_ta);
+    let service_name = format!("{}/{}", SERVICE_NAME, SERVICE_INSTANCE);
+    binder::add_service(&service_name, service.as_binder()).map_err(|e| {
+        format!(
+            "Failed to register service {} because of {:?}.",
+            service_name, e
+        )
+    })?;
+
+    info!("Successfully registered AuthGraph HAL services.");
+    binder::ProcessState::join_thread_pool();
+    info!("AuthGraph HAL service is terminating."); // should not reach here
+    Ok(())
+}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
index 2e4fc15..aeb0163 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
@@ -379,6 +379,12 @@
      *   validate it against the key material.  In the event of a mismatch, importKey must return
      *   ErrorCode::IMPORT_PARAMETER_MISMATCH.
      *
+     * o Tag::EC_CURVE is not necessary in the input parameters for import of EC keys. If not
+     *   provided the IKeyMintDevice must deduce the value from the provided key material and add
+     *   the tag and value to the key characteristics.  If Tag::EC_CURVE is provided, the
+     *   IKeyMintDevice must validate it against the key material.  In the event of a mismatch,
+     *   importKey must return ErrorCode::IMPORT_PARAMETER_MISMATCH.
+     *
      * o Tag::RSA_PUBLIC_EXPONENT (for RSA keys only) is not necessary in the input parameters.  If
      *   not provided, the IKeyMintDevice must deduce the value from the provided key material and
      *   add the tag and value to the key characteristics.  If Tag::RSA_PUBLIC_EXPONENT is provided,
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintOperation.aidl b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintOperation.aidl
index 82c8a0d..a4fab55 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintOperation.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintOperation.aidl
@@ -126,8 +126,8 @@
      *
      *   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().
+     *   o The challenge field in the timestamp 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:
@@ -139,9 +139,6 @@
      *
      *   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.
 
diff --git a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
index d401247..be29f59 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
@@ -643,6 +643,8 @@
      * Tag::ATTESTATION_CHALLENGE is used to deliver a "challenge" value to the attested key
      * generation/import methods, which must place the value in the KeyDescription SEQUENCE of the
      * attestation extension.
+     * The challenge value may be up to 128 bytes. If the caller provides a bigger challenge,
+     * INVALID_INPUT_LENGTH error should be returned.
      *
      * Must never appear in KeyCharacteristics.
      */
@@ -971,7 +973,9 @@
      * Tag::CERTIFICATE_NOT_BEFORE the beginning of the validity of the certificate in UNIX epoch
      * time in milliseconds.  This value is used when generating attestation or self signed
      * certificates.  ErrorCode::MISSING_NOT_BEFORE must be returned if this tag is not provided if
-     * this tag is not provided to generateKey or importKey.
+     * this tag is not provided to generateKey or importKey.  For importWrappedKey, there is no way
+     * to specify the value of this tag for a wrapped asymmetric key, so a value of 0 is suggested
+     * for certificate generation.
      */
     CERTIFICATE_NOT_BEFORE = TagType.DATE | 1008,
 
@@ -979,7 +983,9 @@
      * Tag::CERTIFICATE_NOT_AFTER the end of the validity of the certificate in UNIX epoch time in
      * milliseconds.  This value is used when generating attestation or self signed certificates.
      * ErrorCode::MISSING_NOT_AFTER must be returned if this tag is not provided to generateKey or
-     * importKey.
+     * importKey.  For importWrappedKey, there is no way to specify the value of this tag for a
+     * wrapped asymmetric key, so a value of 253402300799000 is suggested for certificate
+     * generation.
      */
     CERTIFICATE_NOT_AFTER = TagType.DATE | 1009,
 
diff --git a/security/keymint/aidl/default/android.hardware.security.keymint-service.xml b/security/keymint/aidl/default/android.hardware.security.keymint-service.xml
index a4d0302..0568ae6 100644
--- a/security/keymint/aidl/default/android.hardware.security.keymint-service.xml
+++ b/security/keymint/aidl/default/android.hardware.security.keymint-service.xml
@@ -1,12 +1,12 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.security.keymint</name>
-        <version>2</version>
+        <version>3</version>
         <fqname>IKeyMintDevice/default</fqname>
     </hal>
     <hal format="aidl">
         <name>android.hardware.security.keymint</name>
-        <version>2</version>
+        <version>3</version>
         <fqname>IRemotelyProvisionedComponent/default</fqname>
     </hal>
 </manifest>
diff --git a/security/keymint/aidl/default/service.cpp b/security/keymint/aidl/default/service.cpp
index dc0c618..10cbf07 100644
--- a/security/keymint/aidl/default/service.cpp
+++ b/security/keymint/aidl/default/service.cpp
@@ -44,6 +44,8 @@
 }
 
 int main() {
+    // The global logger object required by keymaster's logging macros in keymaster/logger.h.
+    keymaster::SoftKeymasterLogger km_logger;
     // Zero threads seems like a useless pool, but below we'll join this thread to it, increasing
     // the pool size to 1.
     ABinderProcess_setThreadPoolMaxThreadCount(0);
diff --git a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
index 6d289ec..cc97c13 100644
--- a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
+++ b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
@@ -82,13 +82,12 @@
 
     string imei = ::android::base::Trim(out[0]);
     if (imei.compare("null") == 0) {
-        LOG(ERROR) << "Error in getting IMEI from Telephony service: value is null. Cmd: " << cmd;
+        LOG(WARNING) << "Failed to get IMEI from Telephony service: value is null. Cmd: " << cmd;
         return "";
     }
 
     return imei;
 }
-
 }  // namespace
 
 class AttestKeyTest : public KeyMintAidlTestBase {
@@ -120,6 +119,7 @@
                                             .SetDefaultValidity(),
                                     {} /* attestation signing key */, &attest_key.keyBlob,
                                     &attest_key_characteristics, &attest_key_cert_chain));
+        KeyBlobDeleter attest_deleter(keymint_, attest_key.keyBlob);
 
         ASSERT_GT(attest_key_cert_chain.size(), 0);
         EXPECT_EQ(attest_key_cert_chain.size(), 1);
@@ -132,7 +132,7 @@
         vector<uint8_t> attested_key_blob;
         vector<KeyCharacteristics> attested_key_characteristics;
         vector<Certificate> attested_key_cert_chain;
-        EXPECT_EQ(ErrorCode::OK,
+        ASSERT_EQ(ErrorCode::OK,
                   GenerateKey(AuthorizationSetBuilder()
                                       .RsaSigningKey(2048, 65537)
                                       .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -141,12 +141,13 @@
                                       .SetDefaultValidity(),
                               attest_key, &attested_key_blob, &attested_key_characteristics,
                               &attested_key_cert_chain));
+        KeyBlobDeleter attested_deleter(keymint_, attested_key_blob);
 
-        CheckedDeleteKey(&attested_key_blob);
+        ASSERT_GT(attested_key_cert_chain.size(), 0);
 
         AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
         AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
-        EXPECT_TRUE(verify_attestation_record(AidlVersion(), "foo", "bar", sw_enforced, hw_enforced,
+        ASSERT_TRUE(verify_attestation_record(AidlVersion(), "foo", "bar", sw_enforced, hw_enforced,
                                               SecLevel(),
                                               attested_key_cert_chain[0].encodedCertificate));
 
@@ -163,7 +164,7 @@
          */
         attested_key_characteristics.resize(0);
         attested_key_cert_chain.resize(0);
-        EXPECT_EQ(ErrorCode::OK,
+        ASSERT_EQ(ErrorCode::OK,
                   GenerateKey(AuthorizationSetBuilder()
                                       .RsaEncryptionKey(2048, 65537)
                                       .Digest(Digest::NONE)
@@ -174,12 +175,13 @@
                                       .SetDefaultValidity(),
                               attest_key, &attested_key_blob, &attested_key_characteristics,
                               &attested_key_cert_chain));
+        KeyBlobDeleter attested_deleter2(keymint_, attested_key_blob);
 
-        CheckedDeleteKey(&attested_key_blob);
+        ASSERT_GT(attested_key_cert_chain.size(), 0);
 
         hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
         sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
-        EXPECT_TRUE(verify_attestation_record(AidlVersion(), "foo2", "bar2", sw_enforced,
+        ASSERT_TRUE(verify_attestation_record(AidlVersion(), "foo2", "bar2", sw_enforced,
                                               hw_enforced, SecLevel(),
                                               attested_key_cert_chain[0].encodedCertificate));
 
@@ -197,7 +199,7 @@
         attested_key_characteristics.resize(0);
         attested_key_cert_chain.resize(0);
         uint64_t timestamp = 1619621648000;
-        EXPECT_EQ(ErrorCode::OK,
+        ASSERT_EQ(ErrorCode::OK,
                   GenerateKey(AuthorizationSetBuilder()
                                       .EcdsaSigningKey(EcCurve::P_256)
                                       .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -207,6 +209,9 @@
                                       .SetDefaultValidity(),
                               attest_key, &attested_key_blob, &attested_key_characteristics,
                               &attested_key_cert_chain));
+        KeyBlobDeleter attested_deleter3(keymint_, attested_key_blob);
+
+        ASSERT_GT(attested_key_cert_chain.size(), 0);
 
         // The returned key characteristics will include CREATION_DATETIME (checked below)
         // in SecurityLevel::KEYSTORE; this will be stripped out in the CheckCharacteristics()
@@ -214,9 +219,6 @@
         // any SecurityLevel::KEYSTORE characteristics).
         CheckCharacteristics(attested_key_blob, attested_key_characteristics);
 
-        CheckedDeleteKey(&attested_key_blob);
-        CheckedDeleteKey(&attest_key.keyBlob);
-
         hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
         sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
 
@@ -226,7 +228,7 @@
         EXPECT_TRUE(sw_enforced.Contains(TAG_CREATION_DATETIME, timestamp))
                 << "expected CREATION_TIMESTAMP in sw_enforced:" << sw_enforced
                 << " not in hw_enforced:" << hw_enforced;
-        EXPECT_TRUE(verify_attestation_record(AidlVersion(), "foo", "bar", sw_enforced, hw_enforced,
+        ASSERT_TRUE(verify_attestation_record(AidlVersion(), "foo", "bar", sw_enforced, hw_enforced,
                                               SecLevel(),
                                               attested_key_cert_chain[0].encodedCertificate));
 
@@ -308,6 +310,7 @@
         if (result == ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED) return;
     }
     ASSERT_EQ(ErrorCode::OK, result);
+    KeyBlobDeleter attest_deleter(keymint_, attest_key.keyBlob);
 
     EXPECT_GT(attest_key_cert_chain.size(), 1);
     verify_subject_and_serial(attest_key_cert_chain[0], serial_int, subject, false);
@@ -315,7 +318,7 @@
 
     AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attest_key_characteristics);
     AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attest_key_characteristics);
-    EXPECT_TRUE(verify_attestation_record(AidlVersion(), challenge, app_id,  //
+    ASSERT_TRUE(verify_attestation_record(AidlVersion(), challenge, app_id,  //
                                           sw_enforced, hw_enforced, SecLevel(),
                                           attest_key_cert_chain[0].encodedCertificate));
 
@@ -333,7 +336,7 @@
     uint64_t serial_int2 = 255;
     vector<uint8_t> serial_blob2(build_serial_blob(serial_int2));
 
-    EXPECT_EQ(ErrorCode::OK,
+    ASSERT_EQ(ErrorCode::OK,
               GenerateKey(AuthorizationSetBuilder()
                                   .RsaSigningKey(2048, 65537)
                                   .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -344,13 +347,13 @@
                                   .SetDefaultValidity(),
                           attest_key, &attested_key_blob, &attested_key_characteristics,
                           &attested_key_cert_chain));
+    KeyBlobDeleter attested_deleter(keymint_, attested_key_blob);
 
-    CheckedDeleteKey(&attested_key_blob);
-    CheckedDeleteKey(&attest_key.keyBlob);
+    ASSERT_GT(attested_key_cert_chain.size(), 0);
 
     AuthorizationSet hw_enforced2 = HwEnforcedAuthorizations(attested_key_characteristics);
     AuthorizationSet sw_enforced2 = SwEnforcedAuthorizations(attested_key_characteristics);
-    EXPECT_TRUE(verify_attestation_record(AidlVersion(), "foo", "bar", sw_enforced2, hw_enforced2,
+    ASSERT_TRUE(verify_attestation_record(AidlVersion(), "foo", "bar", sw_enforced2, hw_enforced2,
                                           SecLevel(),
                                           attested_key_cert_chain[0].encodedCertificate));
 
@@ -376,6 +379,7 @@
     const int chain_size = 6;
     vector<vector<uint8_t>> key_blob_list(chain_size);
     vector<vector<Certificate>> cert_chain_list(chain_size);
+    vector<KeyBlobDeleter> deleters;
 
     for (int i = 0; i < chain_size; i++) {
         string sub = "attest key chaining ";
@@ -412,11 +416,12 @@
             if (result == ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED) return;
         }
         ASSERT_EQ(ErrorCode::OK, result);
+        deleters.push_back(KeyBlobDeleter(keymint_, key_blob_list[i]));
 
         AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
         AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
         ASSERT_GT(cert_chain_list[i].size(), 0);
-        EXPECT_TRUE(verify_attestation_record(AidlVersion(), "foo", "bar", sw_enforced, hw_enforced,
+        ASSERT_TRUE(verify_attestation_record(AidlVersion(), "foo", "bar", sw_enforced, hw_enforced,
                                               SecLevel(),
                                               cert_chain_list[i][0].encodedCertificate));
 
@@ -437,10 +442,6 @@
         EXPECT_GT(cert_chain_list[i].size(), i + 1);
         verify_subject_and_serial(cert_chain_list[i][0], serial_int, subject, false);
     }
-
-    for (int i = 0; i < chain_size; i++) {
-        CheckedDeleteKey(&key_blob_list[i]);
-    }
 }
 
 /*
@@ -453,6 +454,7 @@
     const int chain_size = 6;
     vector<vector<uint8_t>> key_blob_list(chain_size);
     vector<vector<Certificate>> cert_chain_list(chain_size);
+    vector<KeyBlobDeleter> deleters;
 
     for (int i = 0; i < chain_size; i++) {
         string sub = "Ec attest key chaining ";
@@ -489,11 +491,12 @@
             if (result == ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED) return;
         }
         ASSERT_EQ(ErrorCode::OK, result);
+        deleters.push_back(KeyBlobDeleter(keymint_, key_blob_list[i]));
 
         AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
         AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
         ASSERT_GT(cert_chain_list[i].size(), 0);
-        EXPECT_TRUE(verify_attestation_record(AidlVersion(), "foo", "bar", sw_enforced, hw_enforced,
+        ASSERT_TRUE(verify_attestation_record(AidlVersion(), "foo", "bar", sw_enforced, hw_enforced,
                                               SecLevel(),
                                               cert_chain_list[i][0].encodedCertificate));
 
@@ -514,10 +517,6 @@
         EXPECT_GT(cert_chain_list[i].size(), i + 1);
         verify_subject_and_serial(cert_chain_list[i][0], serial_int, subject, false);
     }
-
-    for (int i = 0; i < chain_size; i++) {
-        CheckedDeleteKey(&key_blob_list[i]);
-    }
 }
 
 /*
@@ -557,6 +556,7 @@
     const int chain_size = 6;
     vector<vector<uint8_t>> key_blob_list(chain_size);
     vector<vector<Certificate>> cert_chain_list(chain_size);
+    vector<KeyBlobDeleter> deleters;
 
     for (int i = 0; i < chain_size; i++) {
         string sub = "Alt attest key chaining ";
@@ -607,11 +607,12 @@
             if (result == ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED) return;
         }
         ASSERT_EQ(ErrorCode::OK, result);
+        deleters.push_back(KeyBlobDeleter(keymint_, key_blob_list[i]));
 
         AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
         AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
         ASSERT_GT(cert_chain_list[i].size(), 0);
-        EXPECT_TRUE(verify_attestation_record(AidlVersion(), "foo", "bar", sw_enforced, hw_enforced,
+        ASSERT_TRUE(verify_attestation_record(AidlVersion(), "foo", "bar", sw_enforced, hw_enforced,
                                               SecLevel(),
                                               cert_chain_list[i][0].encodedCertificate));
 
@@ -632,10 +633,6 @@
         EXPECT_GT(cert_chain_list[i].size(), i + 1);
         verify_subject_and_serial(cert_chain_list[i][0], serial_int, subject, false);
     }
-
-    for (int i = 0; i < chain_size; i++) {
-        CheckedDeleteKey(&key_blob_list[i]);
-    }
 }
 
 TEST_P(AttestKeyTest, MissingChallenge) {
@@ -653,6 +650,7 @@
                                             .SetDefaultValidity(),
                                     {} /* attestation signing key */, &attest_key.keyBlob,
                                     &attest_key_characteristics, &attest_key_cert_chain));
+        KeyBlobDeleter attest_deleter(keymint_, attest_key.keyBlob);
 
         EXPECT_EQ(attest_key_cert_chain.size(), 1);
         EXPECT_TRUE(IsSelfSigned(attest_key_cert_chain)) << "Failed on size " << size;
@@ -664,7 +662,7 @@
         vector<uint8_t> attested_key_blob;
         vector<KeyCharacteristics> attested_key_characteristics;
         vector<Certificate> attested_key_cert_chain;
-        EXPECT_EQ(ErrorCode::ATTESTATION_CHALLENGE_MISSING,
+        ASSERT_EQ(ErrorCode::ATTESTATION_CHALLENGE_MISSING,
                   GenerateKey(AuthorizationSetBuilder()
                                       .RsaSigningKey(2048, 65537)
                                       .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -673,7 +671,7 @@
                               attest_key, &attested_key_blob, &attested_key_characteristics,
                               &attested_key_cert_chain));
 
-        EXPECT_EQ(ErrorCode::ATTESTATION_CHALLENGE_MISSING,
+        ASSERT_EQ(ErrorCode::ATTESTATION_CHALLENGE_MISSING,
                   GenerateKey(AuthorizationSetBuilder()
                                       .EcdsaSigningKey(EcCurve::P_256)
                                       .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -681,8 +679,6 @@
                                       .SetDefaultValidity(),
                               attest_key, &attested_key_blob, &attested_key_characteristics,
                               &attested_key_cert_chain));
-
-        CheckedDeleteKey(&attest_key.keyBlob);
     }
 }
 
@@ -700,6 +696,7 @@
                         AuthorizationSetBuilder().EcdsaKey(curve).AttestKey().SetDefaultValidity(),
                         {} /* attestation signing key */, &attest_key.keyBlob,
                         &attest_key_characteristics, &attest_key_cert_chain));
+        KeyBlobDeleter attest_deleter(keymint_, attest_key.keyBlob);
 
         ASSERT_GT(attest_key_cert_chain.size(), 0);
         EXPECT_EQ(attest_key_cert_chain.size(), 1);
@@ -712,7 +709,7 @@
         vector<uint8_t> attested_key_blob;
         vector<KeyCharacteristics> attested_key_characteristics;
         vector<Certificate> attested_key_cert_chain;
-        EXPECT_EQ(ErrorCode::OK,
+        ASSERT_EQ(ErrorCode::OK,
                   GenerateKey(AuthorizationSetBuilder()
                                       .RsaSigningKey(2048, 65537)
                                       .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -721,13 +718,13 @@
                                       .SetDefaultValidity(),
                               attest_key, &attested_key_blob, &attested_key_characteristics,
                               &attested_key_cert_chain));
+        KeyBlobDeleter attested_deleter(keymint_, attested_key_blob);
 
         ASSERT_GT(attested_key_cert_chain.size(), 0);
-        CheckedDeleteKey(&attested_key_blob);
 
         AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
         AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
-        EXPECT_TRUE(verify_attestation_record(AidlVersion(), "foo", "bar", sw_enforced, hw_enforced,
+        ASSERT_TRUE(verify_attestation_record(AidlVersion(), "foo", "bar", sw_enforced, hw_enforced,
                                               SecLevel(),
                                               attested_key_cert_chain[0].encodedCertificate));
 
@@ -743,7 +740,7 @@
         /*
          * Use attestation key to sign EC key
          */
-        EXPECT_EQ(ErrorCode::OK,
+        ASSERT_EQ(ErrorCode::OK,
                   GenerateKey(AuthorizationSetBuilder()
                                       .EcdsaSigningKey(EcCurve::P_256)
                                       .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -752,14 +749,13 @@
                                       .SetDefaultValidity(),
                               attest_key, &attested_key_blob, &attested_key_characteristics,
                               &attested_key_cert_chain));
+        KeyBlobDeleter attested_deleter2(keymint_, attested_key_blob);
 
         ASSERT_GT(attested_key_cert_chain.size(), 0);
-        CheckedDeleteKey(&attested_key_blob);
-        CheckedDeleteKey(&attest_key.keyBlob);
 
         hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
         sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
-        EXPECT_TRUE(verify_attestation_record(AidlVersion(), "foo", "bar", sw_enforced, hw_enforced,
+        ASSERT_TRUE(verify_attestation_record(AidlVersion(), "foo", "bar", sw_enforced, hw_enforced,
                                               SecLevel(),
                                               attested_key_cert_chain[0].encodedCertificate));
 
@@ -797,7 +793,7 @@
     vector<uint8_t> attested_key_blob;
     vector<KeyCharacteristics> attested_key_characteristics;
     vector<Certificate> attested_key_cert_chain;
-    EXPECT_EQ(ErrorCode::INCOMPATIBLE_PURPOSE,
+    ASSERT_EQ(ErrorCode::INCOMPATIBLE_PURPOSE,
               GenerateKey(AuthorizationSetBuilder()
                                   .EcdsaSigningKey(EcCurve::P_256)
                                   .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -809,11 +805,6 @@
 }
 
 TEST_P(AttestKeyTest, EcdsaAttestationID) {
-    if (is_gsi_image()) {
-        // GSI sets up a standard set of device identifiers that may not match
-        // the device identifiers held by the device.
-        GTEST_SKIP() << "Test not applicable under GSI";
-    }
     // Create attestation key.
     AttestationKey attest_key;
     vector<KeyCharacteristics> attest_key_characteristics;
@@ -825,6 +816,7 @@
                                         .SetDefaultValidity(),
                                 {} /* attestation signing key */, &attest_key.keyBlob,
                                 &attest_key_characteristics, &attest_key_cert_chain));
+    KeyBlobDeleter attest_deleter(keymint_, attest_key.keyBlob);
     attest_key.issuerSubjectName = make_name_from_str("Android Keystore Key");
     ASSERT_GT(attest_key_cert_chain.size(), 0);
     EXPECT_EQ(attest_key_cert_chain.size(), 1);
@@ -832,39 +824,12 @@
 
     // Collection of valid attestation ID tags.
     auto attestation_id_tags = AuthorizationSetBuilder();
-    // Use ro.product.brand_for_attestation property for attestation if it is present else fallback
-    // to ro.product.brand
-    std::string prop_value =
-            ::android::base::GetProperty("ro.product.brand_for_attestation", /* default= */ "");
-    if (!prop_value.empty()) {
-        add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_BRAND,
-                          "ro.product.brand_for_attestation");
-    } else {
-        add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_BRAND, "ro.product.brand");
-    }
-    add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_DEVICE, "ro.product.device");
-    // Use ro.product.name_for_attestation property for attestation if it is present else fallback
-    // to ro.product.name
-    prop_value = ::android::base::GetProperty("ro.product.name_for_attestation", /* default= */ "");
-    if (!prop_value.empty()) {
-        add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_PRODUCT,
-                          "ro.product.name_for_attestation");
-    } else {
-        add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_PRODUCT, "ro.product.name");
-    }
+    add_attestation_id(&attestation_id_tags, TAG_ATTESTATION_ID_BRAND, "brand");
+    add_attestation_id(&attestation_id_tags, TAG_ATTESTATION_ID_DEVICE, "device");
+    add_attestation_id(&attestation_id_tags, TAG_ATTESTATION_ID_PRODUCT, "name");
+    add_attestation_id(&attestation_id_tags, TAG_ATTESTATION_ID_MANUFACTURER, "manufacturer");
+    add_attestation_id(&attestation_id_tags, TAG_ATTESTATION_ID_MODEL, "model");
     add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serialno");
-    add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MANUFACTURER,
-                      "ro.product.manufacturer");
-    // Use ro.product.model_for_attestation property for attestation if it is present else fallback
-    // to ro.product.model
-    prop_value =
-            ::android::base::GetProperty("ro.product.model_for_attestation", /* default= */ "");
-    if (!prop_value.empty()) {
-        add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MODEL,
-                          "ro.product.model_for_attestation");
-    } else {
-        add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MODEL, "ro.product.model");
-    }
 
     string imei = get_imei(0);
     if (!imei.empty()) {
@@ -891,8 +856,8 @@
         }
 
         ASSERT_EQ(result, ErrorCode::OK);
-
-        CheckedDeleteKey(&attested_key_blob);
+        ASSERT_GT(attested_key_cert_chain.size(), 0);
+        KeyBlobDeleter attested_deleter(keymint_, attested_key_blob);
 
         AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
         AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
@@ -902,11 +867,10 @@
         // attestation extension should contain them, so make sure the extra tag is added.
         hw_enforced.push_back(tag);
 
-        EXPECT_TRUE(verify_attestation_record(AidlVersion(), "challenge", "foo", sw_enforced,
+        ASSERT_TRUE(verify_attestation_record(AidlVersion(), "challenge", "foo", sw_enforced,
                                               hw_enforced, SecLevel(),
                                               attested_key_cert_chain[0].encodedCertificate));
     }
-    CheckedDeleteKey(&attest_key.keyBlob);
 }
 
 TEST_P(AttestKeyTest, EcdsaAttestationMismatchID) {
@@ -921,6 +885,7 @@
                                         .SetDefaultValidity(),
                                 {} /* attestation signing key */, &attest_key.keyBlob,
                                 &attest_key_characteristics, &attest_key_cert_chain));
+    KeyBlobDeleter attest_deleter(keymint_, attest_key.keyBlob);
     attest_key.issuerSubjectName = make_name_from_str("Android Keystore Key");
     ASSERT_GT(attest_key_cert_chain.size(), 0);
     EXPECT_EQ(attest_key_cert_chain.size(), 1);
@@ -939,7 +904,9 @@
                     .Authorization(TAG_ATTESTATION_ID_MODEL, "malicious-model");
 
     if (isSecondImeiIdAttestationRequired()) {
-        attestation_id_tags.Authorization(TAG_ATTESTATION_ID_SECOND_IMEI, "invalid-second-imei");
+        // Note: the invalid value here is < 16 bytes long to avoid triggering any implementation
+        // checks on valid IMEI lengths.
+        attestation_id_tags.Authorization(TAG_ATTESTATION_ID_SECOND_IMEI, "invalid-imei2");
     }
     vector<uint8_t> key_blob;
     vector<KeyCharacteristics> key_characteristics;
@@ -963,16 +930,9 @@
                                   &attested_key_characteristics, &attested_key_cert_chain);
         device_id_attestation_check_acceptable_error(invalid_tag.tag, result);
     }
-    CheckedDeleteKey(&attest_key.keyBlob);
 }
 
 TEST_P(AttestKeyTest, SecondIMEIAttestationIDSuccess) {
-    if (is_gsi_image()) {
-        // GSI sets up a standard set of device identifiers that may not match
-        // the device identifiers held by the device.
-        GTEST_SKIP() << "Test not applicable under GSI";
-    }
-
     // Skip the test if there is no second IMEI exists.
     string second_imei = get_imei(1);
     if (second_imei.empty()) {
@@ -994,6 +954,7 @@
                                         .SetDefaultValidity(),
                                 {} /* attestation signing key */, &attest_key.keyBlob,
                                 &attest_key_characteristics, &attest_key_cert_chain));
+    KeyBlobDeleter attest_deleter(keymint_, attest_key.keyBlob);
     attest_key.issuerSubjectName = make_name_from_str("Android Keystore Key");
     EXPECT_EQ(attest_key_cert_chain.size(), 1);
     EXPECT_TRUE(IsSelfSigned(attest_key_cert_chain));
@@ -1022,8 +983,8 @@
     }
 
     ASSERT_EQ(result, ErrorCode::OK);
-
-    CheckedDeleteKey(&attested_key_blob);
+    ASSERT_GT(attested_key_cert_chain.size(), 0);
+    KeyBlobDeleter attested_deleter(keymint_, attested_key_blob);
 
     AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
     AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
@@ -1035,20 +996,12 @@
     KeyParameter imei_tag = Authorization(TAG_ATTESTATION_ID_SECOND_IMEI, imei_blob);
     hw_enforced.push_back(imei_tag);
 
-    EXPECT_TRUE(verify_attestation_record(AidlVersion(), "challenge", "foo", sw_enforced,
+    ASSERT_TRUE(verify_attestation_record(AidlVersion(), "challenge", "foo", sw_enforced,
                                           hw_enforced, SecLevel(),
                                           attested_key_cert_chain[0].encodedCertificate));
-
-    CheckedDeleteKey(&attest_key.keyBlob);
 }
 
 TEST_P(AttestKeyTest, MultipleIMEIAttestationIDSuccess) {
-    if (is_gsi_image()) {
-        // GSI sets up a standard set of device identifiers that may not match
-        // the device identifiers held by the device.
-        GTEST_SKIP() << "Test not applicable under GSI";
-    }
-
     // Skip the test if there is no first IMEI exists.
     string imei = get_imei(0);
     if (imei.empty()) {
@@ -1076,6 +1029,7 @@
                                         .SetDefaultValidity(),
                                 {} /* attestation signing key */, &attest_key.keyBlob,
                                 &attest_key_characteristics, &attest_key_cert_chain));
+    KeyBlobDeleter attest_deleter(keymint_, attest_key.keyBlob);
     attest_key.issuerSubjectName = make_name_from_str("Android Keystore Key");
     EXPECT_EQ(attest_key_cert_chain.size(), 1);
     EXPECT_TRUE(IsSelfSigned(attest_key_cert_chain));
@@ -1101,8 +1055,8 @@
     }
 
     ASSERT_EQ(result, ErrorCode::OK);
-
-    CheckedDeleteKey(&attested_key_blob);
+    ASSERT_GT(attested_key_cert_chain.size(), 0);
+    KeyBlobDeleter attested_deleter(keymint_, attested_key_blob);
 
     AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
     AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
@@ -1117,11 +1071,9 @@
     KeyParameter sec_imei_tag = Authorization(TAG_ATTESTATION_ID_SECOND_IMEI, sec_imei_blob);
     hw_enforced.push_back(sec_imei_tag);
 
-    EXPECT_TRUE(verify_attestation_record(AidlVersion(), "challenge", "foo", sw_enforced,
+    ASSERT_TRUE(verify_attestation_record(AidlVersion(), "challenge", "foo", sw_enforced,
                                           hw_enforced, SecLevel(),
                                           attested_key_cert_chain[0].encodedCertificate));
-
-    CheckedDeleteKey(&attest_key.keyBlob);
 }
 
 INSTANTIATE_KEYMINT_AIDL_TEST(AttestKeyTest);
diff --git a/security/keymint/aidl/vts/functional/AuthTest.cpp b/security/keymint/aidl/vts/functional/AuthTest.cpp
index 6499f14..eb5db68 100644
--- a/security/keymint/aidl/vts/functional/AuthTest.cpp
+++ b/security/keymint/aidl/vts/functional/AuthTest.cpp
@@ -93,17 +93,21 @@
     void TearDown() {
         if (gk_ == nullptr) return;
         gk_->deleteUser(uid_);
+        if (alt_uid_ != 0) {
+            gk_->deleteUser(alt_uid_);
+        }
     }
 
     bool GatekeeperAvailable() { return (gk_ != nullptr) || (hidl_gk_ != nullptr); }
 
-    std::optional<GatekeeperEnrollResponse> doEnroll(const std::vector<uint8_t>& newPwd,
+    std::optional<GatekeeperEnrollResponse> doEnroll(uint32_t uid,
+                                                     const std::vector<uint8_t>& newPwd,
                                                      const std::vector<uint8_t>& curHandle = {},
                                                      const std::vector<uint8_t>& curPwd = {}) {
         if (gk_ != nullptr) {
             while (true) {
                 GatekeeperEnrollResponse rsp;
-                Status status = gk_->enroll(uid_, curHandle, curPwd, newPwd, &rsp);
+                Status status = gk_->enroll(uid, curHandle, curPwd, newPwd, &rsp);
                 if (!status.isOk() && status.getExceptionCode() == EX_SERVICE_SPECIFIC &&
                     status.getServiceSpecificError() == IGatekeeper::ERROR_RETRY_TIMEOUT) {
                     sleep(1);
@@ -120,7 +124,7 @@
             while (true) {
                 HidlGatekeeperResponse rsp;
                 auto status = hidl_gk_->enroll(
-                        uid_, curHandle, curPwd, newPwd,
+                        uid, curHandle, curPwd, newPwd,
                         [&rsp](const HidlGatekeeperResponse& cbRsp) { rsp = cbRsp; });
                 if (!status.isOk()) {
                     GTEST_LOG_(ERROR) << "doEnroll(HIDL) failed";
@@ -155,20 +159,23 @@
         }
     }
 
-    std::optional<GatekeeperEnrollResponse> doEnroll(const string& newPwd,
+    std::optional<GatekeeperEnrollResponse> doEnroll(uint32_t uid, const string& newPwd,
                                                      const std::vector<uint8_t>& curHandle = {},
                                                      const string& curPwd = {}) {
-        return doEnroll(std::vector<uint8_t>(newPwd.begin(), newPwd.end()), curHandle,
+        return doEnroll(uid, std::vector<uint8_t>(newPwd.begin(), newPwd.end()), curHandle,
                         std::vector<uint8_t>(curPwd.begin(), curPwd.end()));
     }
+    std::optional<GatekeeperEnrollResponse> doEnroll(const string& newPwd) {
+        return doEnroll(uid_, newPwd);
+    }
 
-    std::optional<HardwareAuthToken> doVerify(uint64_t challenge,
+    std::optional<HardwareAuthToken> doVerify(uint32_t uid, uint64_t challenge,
                                               const std::vector<uint8_t>& handle,
                                               const std::vector<uint8_t>& pwd) {
         if (gk_ != nullptr) {
             while (true) {
                 GatekeeperVerifyResponse rsp;
-                Status status = gk_->verify(uid_, challenge, handle, pwd, &rsp);
+                Status status = gk_->verify(uid, challenge, handle, pwd, &rsp);
                 if (!status.isOk() && status.getExceptionCode() == EX_SERVICE_SPECIFIC &&
                     status.getServiceSpecificError() == IGatekeeper::ERROR_RETRY_TIMEOUT) {
                     sleep(1);
@@ -185,7 +192,7 @@
             while (true) {
                 HidlGatekeeperResponse rsp;
                 auto status = hidl_gk_->verify(
-                        uid_, challenge, handle, pwd,
+                        uid, challenge, handle, pwd,
                         [&rsp](const HidlGatekeeperResponse& cbRsp) { rsp = cbRsp; });
                 if (!status.isOk()) {
                     GTEST_LOG_(ERROR) << "doVerify(HIDL) failed";
@@ -220,10 +227,15 @@
             return std::nullopt;
         }
     }
+    std::optional<HardwareAuthToken> doVerify(uint32_t uid, uint64_t challenge,
+                                              const std::vector<uint8_t>& handle,
+                                              const string& pwd) {
+        return doVerify(uid, challenge, handle, std::vector<uint8_t>(pwd.begin(), pwd.end()));
+    }
     std::optional<HardwareAuthToken> doVerify(uint64_t challenge,
                                               const std::vector<uint8_t>& handle,
                                               const string& pwd) {
-        return doVerify(challenge, handle, std::vector<uint8_t>(pwd.begin(), pwd.end()));
+        return doVerify(uid_, challenge, handle, pwd);
     }
 
     // Variants of the base class methods but with authentication information included.
@@ -268,6 +280,13 @@
         return plaintext;
     }
 
+    string SignMessage(const vector<uint8_t>& key_blob, const string& message,
+                       const AuthorizationSet& in_params, AuthorizationSet* out_params,
+                       const HardwareAuthToken& hat) {
+        SCOPED_TRACE("SignMessage");
+        return ProcessMessage(key_blob, KeyPurpose::SIGN, message, in_params, out_params, hat);
+    }
+
   protected:
     std::shared_ptr<IGatekeeper> gk_;
     sp<IHidlGatekeeper> hidl_gk_;
@@ -275,6 +294,8 @@
     string password_;
     uint32_t uid_;
     int64_t sid_;
+    uint32_t alt_uid_;
+    int64_t alt_sid_;
     std::vector<uint8_t> handle_;
 };
 
@@ -350,6 +371,126 @@
     }
 }
 
+// Test use of a key that requires user-authentication within recent history, but where
+// the `TimestampToken` provided to the device is unrelated to the in-progress operation.
+TEST_P(AuthTest, TimeoutAuthenticationIncorrectTimestampToken) {
+    if (!GatekeeperAvailable()) {
+        GTEST_SKIP() << "No Gatekeeper available";
+    }
+    if (!timestamp_token_required_) {
+        GTEST_SKIP() << "Test only applies to devices with no secure clock";
+    }
+    if (clock_ == nullptr) {
+        GTEST_SKIP() << "Device requires timestamps and no ISecureClock available";
+    }
+
+    // Create an AES key that requires authentication within the last 3 seconds.
+    const uint32_t timeout_secs = 3;
+    auto builder = AuthorizationSetBuilder()
+                           .AesEncryptionKey(256)
+                           .BlockMode(BlockMode::ECB)
+                           .Padding(PaddingMode::PKCS7)
+                           .Authorization(TAG_USER_SECURE_ID, sid_)
+                           .Authorization(TAG_USER_AUTH_TYPE, HardwareAuthenticatorType::PASSWORD)
+                           .Authorization(TAG_AUTH_TIMEOUT, timeout_secs);
+    vector<uint8_t> keyblob;
+    vector<KeyCharacteristics> key_characteristics;
+    vector<Certificate> cert_chain;
+    ASSERT_EQ(ErrorCode::OK,
+              GenerateKey(builder, std::nullopt, &keyblob, &key_characteristics, &cert_chain));
+
+    // Verify to get a HAT, arbitrary challenge.
+    const uint64_t challenge = 42;
+    const std::optional<HardwareAuthToken> hat = doVerify(challenge, handle_, password_);
+    ASSERT_TRUE(hat.has_value());
+    EXPECT_EQ(hat->userId, sid_);
+
+    // KeyMint implementation has no clock, so only detects timeout via timestamp token provided
+    // on update()/finish().  However, for this test we ensure that that the timestamp token has a
+    // *different* challenge value.
+    const string message = "Hello World!";
+    auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+    AuthorizationSet out_params;
+    ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, keyblob, params, &out_params, hat));
+
+    secureclock::TimeStampToken time_token;
+    EXPECT_EQ(ErrorCode::OK,
+              GetReturnErrorCode(clock_->generateTimeStamp(challenge_ + 1, &time_token)));
+    string output;
+    EXPECT_EQ(ErrorCode::KEY_USER_NOT_AUTHENTICATED,
+              Finish(message, {} /* signature */, &output, hat, time_token));
+}
+
+// Test use of a key with multiple USER_SECURE_ID values.  For variety, use an EC signing key
+// generated with attestation.
+TEST_P(AuthTest, TimeoutAuthenticationMultiSid) {
+    if (!GatekeeperAvailable()) {
+        GTEST_SKIP() << "No Gatekeeper available";
+    }
+    if (timestamp_token_required_ && clock_ == nullptr) {
+        GTEST_SKIP() << "Device requires timestamps and no ISecureClock available";
+    }
+
+    // Enroll a password for a second user.
+    alt_uid_ = 20001;
+    const string alt_password = "correcthorsebatterystaple2";
+    std::optional<GatekeeperEnrollResponse> rsp = doEnroll(alt_uid_, alt_password);
+    ASSERT_TRUE(rsp.has_value());
+    alt_sid_ = rsp->secureUserId;
+    const std::vector<uint8_t> alt_handle = rsp->data;
+
+    // Create an attested EC key that requires authentication within the last 3 seconds from either
+    // secure ID. Also allow any authenticator type.
+    const uint32_t timeout_secs = 3;
+    auto builder = AuthorizationSetBuilder()
+                           .EcdsaSigningKey(EcCurve::P_256)
+                           .Digest(Digest::NONE)
+                           .Digest(Digest::SHA_2_256)
+                           .SetDefaultValidity()
+                           .AttestationChallenge("challenge")
+                           .AttestationApplicationId("app_id")
+                           .Authorization(TAG_USER_SECURE_ID, alt_sid_)
+                           .Authorization(TAG_USER_SECURE_ID, sid_)
+                           .Authorization(TAG_USER_AUTH_TYPE, HardwareAuthenticatorType::ANY)
+                           .Authorization(TAG_AUTH_TIMEOUT, timeout_secs);
+    vector<uint8_t> keyblob;
+    vector<KeyCharacteristics> key_characteristics;
+    vector<Certificate> cert_chain;
+    auto result = GenerateKey(builder, std::nullopt, &keyblob, &key_characteristics, &cert_chain);
+    if (SecLevel() == SecurityLevel::STRONGBOX) {
+        if (result == ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED) {
+            result = GenerateKeyWithSelfSignedAttestKey(AuthorizationSetBuilder()
+                                                                .EcdsaKey(EcCurve::P_256)
+                                                                .AttestKey()
+                                                                .SetDefaultValidity(),
+                                                        builder, &keyblob, &key_characteristics,
+                                                        &cert_chain);
+        }
+    }
+    ASSERT_EQ(ErrorCode::OK, result);
+
+    // Verify first user to get a HAT that should work.
+    const uint64_t challenge = 42;
+    const std::optional<HardwareAuthToken> hat = doVerify(uid_, challenge, handle_, password_);
+    ASSERT_TRUE(hat.has_value());
+    EXPECT_EQ(hat->userId, sid_);
+
+    const string message = "Hello World!";
+    auto params = AuthorizationSetBuilder().Digest(Digest::SHA_2_256);
+    AuthorizationSet out_params;
+    const string signature = SignMessage(keyblob, message, params, &out_params, hat.value());
+
+    // Verify second user to get a HAT that should work.
+    const uint64_t alt_challenge = 43;
+    const std::optional<HardwareAuthToken> alt_hat =
+            doVerify(alt_uid_, alt_challenge, alt_handle, alt_password);
+    ASSERT_TRUE(alt_hat.has_value());
+    EXPECT_EQ(alt_hat->userId, alt_sid_);
+
+    const string alt_signature =
+            SignMessage(keyblob, message, params, &out_params, alt_hat.value());
+}
+
 // Test use of a key that requires an auth token for each action on the operation, with
 // a per-operation challenge value included.
 TEST_P(AuthTest, AuthPerOperation) {
@@ -407,6 +548,93 @@
     ASSERT_GT(dodgy_hat->mac.size(), 0);
     dodgy_hat->mac[0] ^= 0x01;
     EXPECT_EQ(ErrorCode::KEY_USER_NOT_AUTHENTICATED,
+              Finish(message, {} /* signature */, &ciphertext, dodgy_hat.value()));
+}
+
+// Test use of a key that requires an auth token for each action on the operation, with
+// a per-operation challenge value included, with multiple secure IDs allowed.
+TEST_P(AuthTest, AuthPerOperationMultiSid) {
+    if (!GatekeeperAvailable()) {
+        GTEST_SKIP() << "No Gatekeeper available";
+    }
+
+    // Enroll a password for a second user.
+    alt_uid_ = 20001;
+    const string alt_password = "correcthorsebatterystaple2";
+    std::optional<GatekeeperEnrollResponse> rsp = doEnroll(alt_uid_, alt_password);
+    ASSERT_TRUE(rsp.has_value());
+    alt_sid_ = rsp->secureUserId;
+    const std::vector<uint8_t> alt_handle = rsp->data;
+
+    // Create an AES key that requires authentication per-action.
+    auto builder = AuthorizationSetBuilder()
+                           .AesEncryptionKey(256)
+                           .BlockMode(BlockMode::ECB)
+                           .Padding(PaddingMode::PKCS7)
+                           .Authorization(TAG_USER_SECURE_ID, sid_)
+                           .Authorization(TAG_USER_SECURE_ID, alt_sid_)
+                           .Authorization(TAG_USER_AUTH_TYPE, HardwareAuthenticatorType::ANY);
+    vector<uint8_t> keyblob;
+    vector<KeyCharacteristics> key_characteristics;
+    vector<Certificate> cert_chain;
+    ASSERT_EQ(ErrorCode::OK,
+              GenerateKey(builder, std::nullopt, &keyblob, &key_characteristics, &cert_chain));
+
+    // Get a HAT for first user with the challenge from an in-progress operation.
+    const string message = "Hello World!";
+    auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+    AuthorizationSet out_params;
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, keyblob, params, &out_params));
+    const std::optional<HardwareAuthToken> hat = doVerify(uid_, challenge_, handle_, password_);
+    ASSERT_TRUE(hat.has_value());
+    EXPECT_EQ(hat->userId, sid_);
+    string ciphertext;
+    EXPECT_EQ(ErrorCode::OK, Finish(message, {} /* signature */, &ciphertext, hat.value()));
+
+    // Get a HAT for second user with the challenge from an in-progress operation.
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, keyblob, params, &out_params));
+    const std::optional<HardwareAuthToken> alt_hat =
+            doVerify(alt_uid_, challenge_, alt_handle, alt_password);
+    ASSERT_TRUE(alt_hat.has_value());
+    EXPECT_EQ(alt_hat->userId, alt_sid_);
+    string alt_ciphertext;
+    EXPECT_EQ(ErrorCode::OK, Finish(message, {} /* signature */, &ciphertext, alt_hat.value()));
+}
+
+// Test use of a key that requires an auth token for each action on the operation, but
+// which gets passed a HAT of the wrong type
+TEST_P(AuthTest, AuthPerOperationWrongAuthType) {
+    if (!GatekeeperAvailable()) {
+        GTEST_SKIP() << "No Gatekeeper available";
+    }
+
+    // Create an AES key that requires authentication per-action, but with no valid authenticator
+    // types.
+    auto builder =
+            AuthorizationSetBuilder()
+                    .AesEncryptionKey(256)
+                    .BlockMode(BlockMode::ECB)
+                    .Padding(PaddingMode::PKCS7)
+                    .Authorization(TAG_USER_SECURE_ID, sid_)
+                    .Authorization(TAG_USER_AUTH_TYPE, HardwareAuthenticatorType::FINGERPRINT);
+    vector<uint8_t> keyblob;
+    vector<KeyCharacteristics> key_characteristics;
+    vector<Certificate> cert_chain;
+    ASSERT_EQ(ErrorCode::OK,
+              GenerateKey(builder, std::nullopt, &keyblob, &key_characteristics, &cert_chain));
+
+    // Get a HAT with the challenge from an in-progress operation.
+    const string message = "Hello World!";
+    auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+    AuthorizationSet out_params;
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, keyblob, params, &out_params));
+    const std::optional<HardwareAuthToken> hat = doVerify(challenge_, handle_, password_);
+    ASSERT_TRUE(hat.has_value());
+    EXPECT_EQ(hat->userId, sid_);
+
+    // Should fail because auth type doesn't (can't) match.
+    string ciphertext;
+    EXPECT_EQ(ErrorCode::KEY_USER_NOT_AUTHENTICATED,
               Finish(message, {} /* signature */, &ciphertext, hat.value()));
 }
 
diff --git a/security/keymint/aidl/vts/functional/KeyBlobUpgradeTest.cpp b/security/keymint/aidl/vts/functional/KeyBlobUpgradeTest.cpp
index fb014cf..c2509b8 100644
--- a/security/keymint/aidl/vts/functional/KeyBlobUpgradeTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyBlobUpgradeTest.cpp
@@ -36,11 +36,14 @@
 //
 //      adb push keymint-blobs /data/local/tmp/keymint-blobs
 //
-// 5) Run the "*After*" subset of these tests with the `--keyblob_dir <dir>` command-line argument
-//    pointing to the directory with the keyblobs:
+// 5) Run the "*After*" subset of these tests, with the following command-line arguments
+//    `--keyblob_dir <dir>`: pointing to the directory with the keyblobs.
+//    `--expect_upgrade {yes|no}` (Optional): To specify if users expect an upgrade on the keyBlobs,
+//                                            will be "yes" by default.
 //
 //      VtsAidlKeyMintTargetTest --gtest_filter="*KeyBlobUpgradeTest*After*" \
-//                               --keyblob_dir /data/local/tmp/keymint-blobs
+//                               --keyblob_dir /data/local/tmp/keymint-blobs \
+//                               --expect_upgrade {yes|no}
 //
 //    (Note that this skips the `CreateKeyBlobs` test, which would otherwise replace the saved
 //    keyblobs with freshly generated ones.).
@@ -255,7 +258,8 @@
 
                 if (upgraded_keyblob.empty()) {
                     std::cerr << "Keyblob '" << name << "' did not require upgrade\n";
-                    EXPECT_TRUE(!expectUpgrade) << "Keyblob '" << name << "' unexpectedly upgraded";
+                    EXPECT_FALSE(expectUpgrade)
+                            << "Keyblob '" << name << "' unexpectedly left as-is";
                 } else {
                     // Ensure the old format keyblob is deleted (so any secure deletion data is
                     // cleaned up).
@@ -272,8 +276,7 @@
                     save_keyblob(subdir, name, upgraded_keyblob, key_characteristics);
                     // Cert file is left unchanged.
                     std::cerr << "Keyblob '" << name << "' upgraded\n";
-                    EXPECT_TRUE(expectUpgrade)
-                            << "Keyblob '" << name << "' unexpectedly left as-is";
+                    EXPECT_TRUE(expectUpgrade) << "Keyblob '" << name << "' unexpectedly upgraded";
                 }
             }
         }
@@ -426,12 +429,18 @@
 //
 //     VtsAidlKeyMintTargetTest --gtest_filter="*KeyBlobUpgradeTest.UpgradeKeyBlobsAfter*" \
 //                              --keyblob_dir /data/local/tmp/keymint-blobs
+//                              --expect_upgrade {yes|no}
 //
 // - this replaces the keyblob contents in that directory; if needed, save the upgraded keyblobs
 //   with:
 //      adb pull /data/local/tmp/keymint-blobs/
 TEST_P(KeyBlobUpgradeTest, UpgradeKeyBlobsAfter) {
-    UpgradeKeyBlobs(/* expectUpgrade= */ true);
+    bool expectUpgrade = true;  // this test expects upgrade to happen by default
+    if (expect_upgrade.has_value() && expect_upgrade == false) {
+        std::cout << "Not expecting key upgrade due to --expect_upgrade no\n";
+        expectUpgrade = false;
+    }
+    UpgradeKeyBlobs(expectUpgrade);
 }
 
 // To run this test:
@@ -574,7 +583,7 @@
                                               .SetDefaultValidity(),
                                       attest_key, &attested_key_blob, &attested_key_characteristics,
                                       &attested_key_cert_chain));
-                CheckedDeleteKey(&attested_key_blob);
+                KeyBlobDeleter(keymint_, attested_key_blob);
             } else {
                 FAIL() << "Unexpected name: " << name;
             }
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index 433857c..d3f6ae3 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -71,10 +71,16 @@
 // additional overhead, for the digest algorithmIdentifier required by PKCS#1.
 const size_t kPkcs1UndigestedSignaturePaddingOverhead = 11;
 
+size_t count_tag_invalid_entries(const std::vector<KeyParameter>& authorizations) {
+    return std::count_if(authorizations.begin(), authorizations.end(),
+                         [](const KeyParameter& e) -> bool { return e.tag == Tag::INVALID; });
+}
+
 typedef KeyMintAidlTestBase::KeyData KeyData;
 // Predicate for testing basic characteristics validity in generation or import.
 bool KeyCharacteristicsBasicallyValid(SecurityLevel secLevel,
-                                      const vector<KeyCharacteristics>& key_characteristics) {
+                                      const vector<KeyCharacteristics>& key_characteristics,
+                                      int32_t aidl_version) {
     if (key_characteristics.empty()) return false;
 
     std::unordered_set<SecurityLevel> levels_seen;
@@ -84,6 +90,13 @@
             return false;
         }
 
+        // There was no test to assert that INVALID tag should not present in authorization list
+        // before Keymint V3, so there are some Keymint implementations where asserting for INVALID
+        // tag fails(b/297306437), hence skipping for Keymint < 3.
+        if (aidl_version >= 3) {
+            EXPECT_EQ(count_tag_invalid_entries(entry.authorizations), 0);
+        }
+
         // Just ignore the SecurityLevel::KEYSTORE as the KM won't do any enforcement on this.
         if (entry.securityLevel == SecurityLevel::KEYSTORE) continue;
 
@@ -174,6 +187,18 @@
 bool KeyMintAidlTestBase::arm_deleteAllKeys = false;
 bool KeyMintAidlTestBase::dump_Attestations = false;
 std::string KeyMintAidlTestBase::keyblob_dir;
+std::optional<bool> KeyMintAidlTestBase::expect_upgrade = std::nullopt;
+
+KeyBlobDeleter::~KeyBlobDeleter() {
+    if (key_blob_.empty()) {
+        return;
+    }
+    Status result = keymint_->deleteKey(key_blob_);
+    key_blob_.clear();
+    EXPECT_TRUE(result.isOk()) << result.getServiceSpecificError() << "\n";
+    ErrorCode rc = GetReturnErrorCode(result);
+    EXPECT_TRUE(rc == ErrorCode::OK || rc == ErrorCode::UNIMPLEMENTED) << result << "\n";
+}
 
 uint32_t KeyMintAidlTestBase::boot_patch_level(
         const vector<KeyCharacteristics>& key_characteristics) {
@@ -228,16 +253,6 @@
     return version >= 2;
 }
 
-ErrorCode KeyMintAidlTestBase::GetReturnErrorCode(const Status& result) {
-    if (result.isOk()) return ErrorCode::OK;
-
-    if (result.getExceptionCode() == EX_SERVICE_SPECIFIC) {
-        return static_cast<ErrorCode>(result.getServiceSpecificError());
-    }
-
-    return ErrorCode::UNKNOWN_ERROR;
-}
-
 void KeyMintAidlTestBase::InitializeKeyMint(std::shared_ptr<IKeyMintDevice> keyMint) {
     ASSERT_NE(keyMint, nullptr);
     keymint_ = std::move(keyMint);
@@ -255,7 +270,7 @@
     vendor_patch_level_ = getVendorPatchlevel();
 }
 
-int32_t KeyMintAidlTestBase::AidlVersion() {
+int32_t KeyMintAidlTestBase::AidlVersion() const {
     int32_t version = 0;
     auto status = keymint_->getInterfaceVersion(&version);
     if (!status.isOk()) {
@@ -285,8 +300,8 @@
     KeyCreationResult creationResult;
     Status result = keymint_->generateKey(key_desc.vector_data(), attest_key, &creationResult);
     if (result.isOk()) {
-        EXPECT_PRED2(KeyCharacteristicsBasicallyValid, SecLevel(),
-                     creationResult.keyCharacteristics);
+        EXPECT_PRED3(KeyCharacteristicsBasicallyValid, SecLevel(),
+                     creationResult.keyCharacteristics, AidlVersion());
         EXPECT_GT(creationResult.keyBlob.size(), 0);
         *key_blob = std::move(creationResult.keyBlob);
         *key_characteristics = std::move(creationResult.keyCharacteristics);
@@ -358,8 +373,8 @@
                                  {} /* attestationSigningKeyBlob */, &creationResult);
 
     if (result.isOk()) {
-        EXPECT_PRED2(KeyCharacteristicsBasicallyValid, SecLevel(),
-                     creationResult.keyCharacteristics);
+        EXPECT_PRED3(KeyCharacteristicsBasicallyValid, SecLevel(),
+                     creationResult.keyCharacteristics, AidlVersion());
         EXPECT_GT(creationResult.keyBlob.size(), 0);
 
         *key_blob = std::move(creationResult.keyBlob);
@@ -402,8 +417,8 @@
             unwrapping_params.vector_data(), password_sid, biometric_sid, &creationResult);
 
     if (result.isOk()) {
-        EXPECT_PRED2(KeyCharacteristicsBasicallyValid, SecLevel(),
-                     creationResult.keyCharacteristics);
+        EXPECT_PRED3(KeyCharacteristicsBasicallyValid, SecLevel(),
+                     creationResult.keyCharacteristics, AidlVersion());
         EXPECT_GT(creationResult.keyBlob.size(), 0);
 
         key_blob_ = std::move(creationResult.keyBlob);
@@ -512,13 +527,9 @@
     return GetReturnErrorCode(result);
 }
 
-void KeyMintAidlTestBase::CheckedDeleteKey(vector<uint8_t>* key_blob, bool keep_key_blob) {
-    ErrorCode result = DeleteKey(key_blob, keep_key_blob);
-    EXPECT_TRUE(result == ErrorCode::OK || result == ErrorCode::UNIMPLEMENTED) << result << endl;
-}
-
 void KeyMintAidlTestBase::CheckedDeleteKey() {
-    CheckedDeleteKey(&key_blob_);
+    ErrorCode result = DeleteKey(&key_blob_, /* keep_key_blob = */ false);
+    EXPECT_TRUE(result == ErrorCode::OK || result == ErrorCode::UNIMPLEMENTED) << result << endl;
 }
 
 ErrorCode KeyMintAidlTestBase::Begin(KeyPurpose purpose, const vector<uint8_t>& key_blob,
@@ -836,7 +847,7 @@
         int vendor_api_level = property_get_int32("ro.vendor.api_level", 0);
         if (SecLevel() == SecurityLevel::STRONGBOX) {
             // This is known to be broken on older vendor implementations.
-            if (vendor_api_level < __ANDROID_API_T__) {
+            if (vendor_api_level <= __ANDROID_API_U__) {
                 compare_output = false;
             } else {
                 additional_information = " (b/194134359) ";
@@ -1602,7 +1613,8 @@
     auto res = property_get("ro.vendor.qti.soc_model", buffer.data(), nullptr);
     if (res <= 0) return false;
 
-    const string allowed_soc_models[] = {"SM8450", "SM8475", "SM8550", "SXR2230P"};
+    const string allowed_soc_models[] = {"SM8450", "SM8475", "SM8550", "SXR2230P",
+                                         "SM4450", "SM7450", "SM6450"};
 
     for (const string model : allowed_soc_models) {
         if (model.compare(buffer.data()) == 0) {
@@ -1780,6 +1792,12 @@
     std::string empty_boot_key(32, '\0');
     std::string verified_boot_key_str((const char*)verified_boot_key.data(),
                                       verified_boot_key.size());
+    if (get_vsr_api_level() >= __ANDROID_API_V__) {
+        // The attestation should contain the SHA-256 hash of the verified boot
+        // key.  However, this was not checked for earlier versions of the KeyMint
+        // HAL so only be strict for VSR-V and above.
+        EXPECT_LE(verified_boot_key.size(), 32);
+    }
     EXPECT_NE(property_get("ro.boot.verifiedbootstate", property_value, ""), 0);
     if (!strcmp(property_value, "green")) {
         EXPECT_EQ(verified_boot_state, VerifiedBoot::VERIFIED);
@@ -2003,6 +2021,16 @@
     return AssertionSuccess();
 }
 
+ErrorCode GetReturnErrorCode(const Status& result) {
+    if (result.isOk()) return ErrorCode::OK;
+
+    if (result.getExceptionCode() == EX_SERVICE_SPECIFIC) {
+        return static_cast<ErrorCode>(result.getServiceSpecificError());
+    }
+
+    return ErrorCode::UNKNOWN_ERROR;
+}
+
 X509_Ptr parse_cert_blob(const vector<uint8_t>& blob) {
     const uint8_t* p = blob.data();
     return X509_Ptr(d2i_X509(nullptr /* allocate new */, &p, blob.size()));
@@ -2052,6 +2080,36 @@
     return retval;
 }
 
+void KeyMintAidlTestBase::assert_mgf_digests_present_or_not_in_key_characteristics(
+        std::vector<android::hardware::security::keymint::Digest>& expected_mgf_digests,
+        bool is_mgf_digest_expected) const {
+    assert_mgf_digests_present_or_not_in_key_characteristics(
+            key_characteristics_, expected_mgf_digests, is_mgf_digest_expected);
+}
+
+void KeyMintAidlTestBase::assert_mgf_digests_present_or_not_in_key_characteristics(
+        const vector<KeyCharacteristics>& key_characteristics,
+        std::vector<android::hardware::security::keymint::Digest>& expected_mgf_digests,
+        bool is_mgf_digest_expected) const {
+    // There was no test to assert that MGF1 digest was present in generated/imported key
+    // characteristics before Keymint V3, so there are some Keymint implementations where
+    // asserting for MGF1 digest fails(b/297306437), hence skipping for Keymint < 3.
+    if (AidlVersion() < 3) {
+        return;
+    }
+    AuthorizationSet auths;
+    for (auto& entry : key_characteristics) {
+        auths.push_back(AuthorizationSet(entry.authorizations));
+    }
+    for (auto digest : expected_mgf_digests) {
+        if (is_mgf_digest_expected) {
+            ASSERT_TRUE(auths.Contains(TAG_RSA_OAEP_MGF_DIGEST, digest));
+        } else {
+            ASSERT_FALSE(auths.Contains(TAG_RSA_OAEP_MGF_DIGEST, digest));
+        }
+    }
+}
+
 namespace {
 
 void check_cose_key(const vector<uint8_t>& data, bool testMode) {
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
index d8c9f11..4fb711c 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
@@ -57,6 +57,18 @@
 const string FEATURE_KEYSTORE_APP_ATTEST_KEY = "android.hardware.keystore.app_attest_key";
 const string FEATURE_STRONGBOX_KEYSTORE = "android.hardware.strongbox_keystore";
 
+// RAII class to ensure that a keyblob is deleted regardless of how a test exits.
+class KeyBlobDeleter {
+  public:
+    KeyBlobDeleter(const shared_ptr<IKeyMintDevice>& keymint, const vector<uint8_t>& key_blob)
+        : keymint_(keymint), key_blob_(key_blob) {}
+    ~KeyBlobDeleter();
+
+  private:
+    shared_ptr<IKeyMintDevice> keymint_;
+    vector<uint8_t> key_blob_;
+};
+
 class KeyMintAidlTestBase : public ::testing::TestWithParam<string> {
   public:
     struct KeyData {
@@ -70,6 +82,8 @@
     // Directory to store/retrieve keyblobs, using subdirectories named for the
     // KeyMint instance in question (e.g. "./default/", "./strongbox/").
     static std::string keyblob_dir;
+    // To specify if users expect an upgrade on the keyBlobs.
+    static std::optional<bool> expect_upgrade;
 
     void SetUp() override;
     void TearDown() override {
@@ -81,7 +95,7 @@
 
     void InitializeKeyMint(std::shared_ptr<IKeyMintDevice> keyMint);
     IKeyMintDevice& keyMint() { return *keymint_; }
-    int32_t AidlVersion();
+    int32_t AidlVersion() const;
     uint32_t os_version() { return os_version_; }
     uint32_t os_patch_level() { return os_patch_level_; }
     uint32_t vendor_patch_level() { return vendor_patch_level_; }
@@ -92,8 +106,6 @@
 
     bool Curve25519Supported();
 
-    ErrorCode GetReturnErrorCode(const Status& result);
-
     ErrorCode GenerateKey(const AuthorizationSet& key_desc, vector<uint8_t>* key_blob,
                           vector<KeyCharacteristics>* key_characteristics) {
         return GenerateKey(key_desc, std::nullopt /* attest_key */, key_blob, key_characteristics,
@@ -157,7 +169,6 @@
 
     ErrorCode DestroyAttestationIds();
 
-    void CheckedDeleteKey(vector<uint8_t>* key_blob, bool keep_key_blob = false);
     void CheckedDeleteKey();
 
     ErrorCode Begin(KeyPurpose purpose, const vector<uint8_t>& key_blob,
@@ -362,6 +373,15 @@
     bool shouldSkipAttestKeyTest(void) const;
     void skipAttestKeyTest(void) const;
 
+    void assert_mgf_digests_present_or_not_in_key_characteristics(
+            const vector<KeyCharacteristics>& key_characteristics,
+            std::vector<android::hardware::security::keymint::Digest>& expected_mgf_digests,
+            bool is_mgf_digest_expected) const;
+
+    void assert_mgf_digests_present_or_not_in_key_characteristics(
+            std::vector<android::hardware::security::keymint::Digest>& expected_mgf_digests,
+            bool is_mgf_digest_expected) const;
+
   protected:
     std::shared_ptr<IKeyMintDevice> keymint_;
     uint32_t os_version_;
@@ -430,12 +450,37 @@
 ::testing::AssertionResult ChainSignaturesAreValid(const vector<Certificate>& chain,
                                                    bool strict_issuer_check = true);
 
+ErrorCode GetReturnErrorCode(const Status& result);
+
 #define INSTANTIATE_KEYMINT_AIDL_TEST(name)                                          \
     INSTANTIATE_TEST_SUITE_P(PerInstance, name,                                      \
                              testing::ValuesIn(KeyMintAidlTestBase::build_params()), \
                              ::android::PrintInstanceNameToString);                  \
     GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(name);
 
+// Use `ro.product.<property>_for_attestation` property for attestation if it is present else
+// fallback to use `ro.product.vendor.<property>` if it is present else fallback to
+// `ro.product.<property>`. Similar logic can be seen in Java method `getVendorDeviceIdProperty`
+// in frameworks/base/core/java/android/os/Build.java.
+template <Tag tag>
+void add_attestation_id(AuthorizationSetBuilder* attestation_id_tags,
+                        TypedTag<TagType::BYTES, tag> tag_type, const char* prop) {
+    ::android::String8 prop_name =
+            ::android::String8::format("ro.product.%s_for_attestation", prop);
+    std::string prop_value = ::android::base::GetProperty(prop_name.c_str(), /* default= */ "");
+    if (!prop_value.empty()) {
+        add_tag_from_prop(attestation_id_tags, tag_type, prop_name.c_str());
+    } else {
+        prop_name = ::android::String8::format("ro.product.vendor.%s", prop);
+        prop_value = ::android::base::GetProperty(prop_name.c_str(), /* default= */ "");
+        if (!prop_value.empty()) {
+            add_tag_from_prop(attestation_id_tags, tag_type, prop_name.c_str());
+        } else {
+            prop_name = ::android::String8::format("ro.product.%s", prop);
+            add_tag_from_prop(attestation_id_tags, tag_type, prop_name.c_str());
+        }
+    }
+}
 }  // namespace test
 
 }  // namespace aidl::android::hardware::security::keymint
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index 2e6fa3b..a2e20dc 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -693,6 +693,7 @@
                     builder.Authorization(TAG_MIN_MAC_LENGTH, 128);
                 }
                 ASSERT_EQ(ErrorCode::OK, GenerateKey(builder, &key_blob, &key_characteristics));
+                KeyBlobDeleter deleter(keymint_, key_blob);
 
                 EXPECT_GT(key_blob.size(), 0U);
                 CheckSymmetricParams(key_characteristics);
@@ -703,8 +704,6 @@
                 EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::AES));
                 EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size))
                         << "Key size " << key_size << "missing";
-
-                CheckedDeleteKey(&key_blob);
             }
         }
     }
@@ -877,6 +876,7 @@
                                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                                              .SetDefaultValidity(),
                                                      &key_blob, &key_characteristics));
+                KeyBlobDeleter deleter(keymint_, key_blob);
 
                 EXPECT_GT(key_blob.size(), 0U);
                 CheckSymmetricParams(key_characteristics);
@@ -887,8 +887,6 @@
                 EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::TRIPLE_DES));
                 EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size))
                         << "Key size " << key_size << "missing";
-
-                CheckedDeleteKey(&key_blob);
             }
         }
     }
@@ -924,6 +922,7 @@
                                                              .AttestationApplicationId(app_id)
                                                              .SetDefaultValidity(),
                                                      &key_blob, &key_characteristics));
+                KeyBlobDeleter deleter(keymint_, key_blob);
 
                 EXPECT_GT(key_blob.size(), 0U);
                 CheckSymmetricParams(key_characteristics);
@@ -934,8 +933,6 @@
                 EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::TRIPLE_DES));
                 EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size))
                         << "Key size " << key_size << "missing";
-
-                CheckedDeleteKey(&key_blob);
             }
         }
     }
@@ -1003,6 +1000,7 @@
                                                      .Padding(PaddingMode::NONE)
                                                      .SetDefaultValidity(),
                                              &key_blob, &key_characteristics));
+        KeyBlobDeleter deleter(keymint_, key_blob);
 
         ASSERT_GT(key_blob.size(), 0U);
         CheckBaseParams(key_characteristics);
@@ -1014,8 +1012,6 @@
         EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size))
                 << "Key size " << key_size << "missing";
         EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 65537U));
-
-        CheckedDeleteKey(&key_blob);
     }
 }
 
@@ -1139,6 +1135,7 @@
             }
         }
         ASSERT_EQ(ErrorCode::OK, result);
+        KeyBlobDeleter deleter(keymint_, key_blob);
         ASSERT_GT(key_blob.size(), 0U);
         CheckBaseParams(key_characteristics);
         CheckCharacteristics(key_blob, key_characteristics);
@@ -1159,8 +1156,6 @@
         EXPECT_TRUE(verify_attestation_record(AidlVersion(), challenge, app_id,  //
                                               sw_enforced, hw_enforced, SecLevel(),
                                               cert_chain_[0].encodedCertificate));
-
-        CheckedDeleteKey(&key_blob);
     }
 }
 
@@ -1214,6 +1209,7 @@
                                       .Authorization(TAG_NO_AUTH_REQUIRED)
                                       .SetDefaultValidity(),
                               attestation_key, &key_blob, &key_characteristics, &cert_chain_));
+        KeyBlobDeleter deleter(keymint_, key_blob);
 
         ASSERT_GT(key_blob.size(), 0U);
         CheckBaseParams(key_characteristics);
@@ -1240,8 +1236,6 @@
         ASSERT_TRUE(X509_verify(key_cert.get(), signing_pubkey.get()))
                 << "Verification of attested certificate failed "
                 << "OpenSSL error string: " << ERR_error_string(ERR_get_error(), NULL);
-
-        CheckedDeleteKey(&key_blob);
     }
 }
 
@@ -1294,6 +1288,7 @@
                                       .Authorization(TAG_NO_AUTH_REQUIRED)
                                       .SetDefaultValidity(),
                               attestation_key, &key_blob, &key_characteristics, &cert_chain_));
+        KeyBlobDeleter deleter(keymint_, key_blob);
 
         ASSERT_GT(key_blob.size(), 0U);
         CheckBaseParams(key_characteristics);
@@ -1318,8 +1313,6 @@
         ASSERT_TRUE(X509_verify(key_cert.get(), signing_pubkey.get()))
                 << "Verification of attested certificate failed "
                 << "OpenSSL error string: " << ERR_error_string(ERR_get_error(), NULL);
-
-        CheckedDeleteKey(&key_blob);
     }
 }
 
@@ -1365,6 +1358,7 @@
         }
     }
     ASSERT_EQ(ErrorCode::OK, result);
+    KeyBlobDeleter deleter(keymint_, key_blob);
 
     ASSERT_GT(key_blob.size(), 0U);
     AuthorizationSet auths;
@@ -1405,8 +1399,6 @@
     EXPECT_TRUE(verify_attestation_record(AidlVersion(), challenge, app_id,  //
                                           sw_enforced, hw_enforced, SecLevel(),
                                           cert_chain_[0].encodedCertificate));
-
-    CheckedDeleteKey(&key_blob);
 }
 
 /*
@@ -1437,6 +1429,7 @@
                                       .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
                                       .SetDefaultValidity(),
                               &key_blob, &key_characteristics));
+        KeyBlobDeleter deleter(keymint_, key_blob);
 
         ASSERT_GT(key_blob.size(), 0U);
         CheckBaseParams(key_characteristics);
@@ -1452,8 +1445,6 @@
         ASSERT_EQ(cert_chain_.size(), 1);
         verify_subject_and_serial(cert_chain_[0], serial_int, subject, false);
         EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
-
-        CheckedDeleteKey(&key_blob);
     }
 }
 
@@ -1518,6 +1509,7 @@
                                   .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
                                   .SetDefaultValidity(),
                           &key_blob, &key_characteristics));
+    KeyBlobDeleter deleter(keymint_, key_blob);
 
     ASSERT_GT(key_blob.size(), 0U);
     CheckBaseParams(key_characteristics);
@@ -1534,8 +1526,6 @@
     verify_subject_and_serial(cert_chain_[0], serial_int, subject, false);
     EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
     ASSERT_EQ(cert_chain_.size(), 1);
-
-    CheckedDeleteKey(&key_blob);
 }
 
 /*
@@ -1556,6 +1546,7 @@
                                                      .Authorization(TAG_USAGE_COUNT_LIMIT, 1)
                                                      .SetDefaultValidity(),
                                              &key_blob, &key_characteristics));
+        KeyBlobDeleter deleter(keymint_, key_blob);
 
         ASSERT_GT(key_blob.size(), 0U);
         CheckBaseParams(key_characteristics);
@@ -1575,8 +1566,6 @@
         }
         EXPECT_TRUE(auths.Contains(TAG_USAGE_COUNT_LIMIT, 1U))
                 << "key usage count limit " << 1U << " missing";
-
-        CheckedDeleteKey(&key_blob);
     }
 }
 
@@ -1625,6 +1614,7 @@
             }
         }
         ASSERT_EQ(ErrorCode::OK, result);
+        KeyBlobDeleter deleter(keymint_, key_blob);
 
         ASSERT_GT(key_blob.size(), 0U);
         CheckBaseParams(key_characteristics);
@@ -1655,8 +1645,6 @@
         EXPECT_TRUE(verify_attestation_record(AidlVersion(), challenge, app_id,  //
                                               sw_enforced, hw_enforced, SecLevel(),
                                               cert_chain_[0].encodedCertificate));
-
-        CheckedDeleteKey(&key_blob);
     }
 }
 
@@ -1726,6 +1714,7 @@
                                                      .Digest(Digest::NONE)
                                                      .SetDefaultValidity(),
                                              &key_blob, &key_characteristics));
+        KeyBlobDeleter deleter(keymint_, key_blob);
         ASSERT_GT(key_blob.size(), 0U);
         CheckBaseParams(key_characteristics);
         CheckCharacteristics(key_blob, key_characteristics);
@@ -1734,8 +1723,6 @@
 
         EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::EC));
         EXPECT_TRUE(crypto_params.Contains(TAG_EC_CURVE, curve)) << "Curve " << curve << "missing";
-
-        CheckedDeleteKey(&key_blob);
     }
 }
 
@@ -1759,6 +1746,8 @@
                                            .SetDefaultValidity(),
                                    &key_blob, &key_characteristics);
     ASSERT_EQ(result, ErrorCode::OK);
+    KeyBlobDeleter deleter(keymint_, key_blob);
+
     ASSERT_GT(key_blob.size(), 0U);
 
     EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
@@ -1771,8 +1760,6 @@
 
     EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::EC));
     EXPECT_TRUE(crypto_params.Contains(TAG_EC_CURVE, curve)) << "Curve " << curve << "missing";
-
-    CheckedDeleteKey(&key_blob);
 }
 
 /*
@@ -1879,6 +1866,7 @@
             }
         }
         ASSERT_EQ(ErrorCode::OK, result);
+        KeyBlobDeleter deleter(keymint_, key_blob);
         ASSERT_GT(key_blob.size(), 0U);
         CheckBaseParams(key_characteristics);
         CheckCharacteristics(key_blob, key_characteristics);
@@ -1897,8 +1885,6 @@
         EXPECT_TRUE(verify_attestation_record(AidlVersion(), challenge, app_id,  //
                                               sw_enforced, hw_enforced, SecLevel(),
                                               cert_chain_[0].encodedCertificate));
-
-        CheckedDeleteKey(&key_blob);
     }
 }
 
@@ -1936,6 +1922,7 @@
                                            .SetDefaultValidity(),
                                    &key_blob, &key_characteristics);
     ASSERT_EQ(ErrorCode::OK, result);
+    KeyBlobDeleter deleter(keymint_, key_blob);
     ASSERT_GT(key_blob.size(), 0U);
     CheckBaseParams(key_characteristics);
     CheckCharacteristics(key_blob, key_characteristics);
@@ -1954,8 +1941,6 @@
     EXPECT_TRUE(verify_attestation_record(AidlVersion(), challenge, app_id,  //
                                           sw_enforced, hw_enforced, SecLevel(),
                                           cert_chain_[0].encodedCertificate));
-
-    CheckedDeleteKey(&key_blob);
 }
 
 /*
@@ -2024,6 +2009,7 @@
             }
         }
         ASSERT_EQ(result, ErrorCode::OK);
+        KeyBlobDeleter deleter(keymint_, key_blob);
         ASSERT_GT(key_blob.size(), 0U);
 
         EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
@@ -2043,8 +2029,6 @@
         EXPECT_TRUE(verify_attestation_record(AidlVersion(), challenge, app_id, sw_enforced,
                                               hw_enforced, SecLevel(),
                                               cert_chain_[0].encodedCertificate));
-
-        CheckedDeleteKey(&key_blob);
     }
 
     // Collection of invalid attestation ID tags.
@@ -2098,11 +2082,6 @@
  * attestation extension.
  */
 TEST_P(NewKeyGenerationTest, EcdsaAttestationIdTags) {
-    if (is_gsi_image()) {
-        // GSI sets up a standard set of device identifiers that may not match
-        // the device identifiers held by the device.
-        GTEST_SKIP() << "Test not applicable under GSI";
-    }
     auto challenge = "hello";
     auto app_id = "foo";
     auto subject = "cert subj 2";
@@ -2122,38 +2101,12 @@
 
     // Various ATTESTATION_ID_* tags that map to fields in the attestation extension ASN.1 schema.
     auto extra_tags = AuthorizationSetBuilder();
-    // Use ro.product.brand_for_attestation property for attestation if it is present else fallback
-    // to ro.product.brand
-    std::string prop_value =
-            ::android::base::GetProperty("ro.product.brand_for_attestation", /* default= */ "");
-    if (!prop_value.empty()) {
-        add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_BRAND,
-                          "ro.product.brand_for_attestation");
-    } else {
-        add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_BRAND, "ro.product.brand");
-    }
-    add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_DEVICE, "ro.product.device");
-    // Use ro.product.name_for_attestation property for attestation if it is present else fallback
-    // to ro.product.name
-    prop_value = ::android::base::GetProperty("ro.product.name_for_attestation", /* default= */ "");
-    if (!prop_value.empty()) {
-        add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_PRODUCT,
-                          "ro.product.name_for_attestation");
-    } else {
-        add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_PRODUCT, "ro.product.name");
-    }
+    add_attestation_id(&extra_tags, TAG_ATTESTATION_ID_BRAND, "brand");
+    add_attestation_id(&extra_tags, TAG_ATTESTATION_ID_DEVICE, "device");
+    add_attestation_id(&extra_tags, TAG_ATTESTATION_ID_PRODUCT, "name");
+    add_attestation_id(&extra_tags, TAG_ATTESTATION_ID_MANUFACTURER, "manufacturer");
+    add_attestation_id(&extra_tags, TAG_ATTESTATION_ID_MODEL, "model");
     add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serialno");
-    add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_MANUFACTURER, "ro.product.manufacturer");
-    // Use ro.product.model_for_attestation property for attestation if it is present else fallback
-    // to ro.product.model
-    prop_value =
-            ::android::base::GetProperty("ro.product.model_for_attestation", /* default= */ "");
-    if (!prop_value.empty()) {
-        add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_MODEL,
-                          "ro.product.model_for_attestation");
-    } else {
-        add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_MODEL, "ro.product.model");
-    }
 
     for (const KeyParameter& tag : extra_tags) {
         SCOPED_TRACE(testing::Message() << "tag-" << tag);
@@ -2171,6 +2124,7 @@
             continue;
         }
         ASSERT_EQ(result, ErrorCode::OK);
+        KeyBlobDeleter deleter(keymint_, key_blob);
         ASSERT_GT(key_blob.size(), 0U);
 
         EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
@@ -2190,8 +2144,6 @@
         EXPECT_TRUE(verify_attestation_record(AidlVersion(), challenge, app_id, sw_enforced,
                                               hw_enforced, SecLevel(),
                                               cert_chain_[0].encodedCertificate));
-
-        CheckedDeleteKey(&key_blob);
     }
 }
 
@@ -2346,6 +2298,7 @@
         }
     }
     ASSERT_EQ(result, ErrorCode::OK);
+    KeyBlobDeleter deleter(keymint_, key_blob);
     ASSERT_GT(key_blob.size(), 0U);
 
     EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
@@ -2365,8 +2318,6 @@
     ASSERT_EQ(std::search(cert_chain_[0].encodedCertificate.begin(),
                           cert_chain_[0].encodedCertificate.end(), needle.begin(), needle.end()),
               cert_chain_[0].encodedCertificate.end());
-
-    CheckedDeleteKey(&key_blob);
 }
 
 /*
@@ -2394,6 +2345,7 @@
                                       .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
                                       .SetDefaultValidity(),
                               &key_blob, &key_characteristics));
+        KeyBlobDeleter deleter(keymint_, key_blob);
         ASSERT_GT(key_blob.size(), 0U);
         CheckBaseParams(key_characteristics);
         CheckCharacteristics(key_blob, key_characteristics);
@@ -2409,8 +2361,6 @@
 
         AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics);
         AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics);
-
-        CheckedDeleteKey(&key_blob);
     }
 }
 
@@ -2464,6 +2414,7 @@
                                                      .AttestationApplicationId(app_id)
                                                      .SetDefaultValidity(),
                                              &key_blob, &key_characteristics));
+        KeyBlobDeleter deleter(keymint_, key_blob);
 
         ASSERT_GT(key_blob.size(), 0U);
         CheckBaseParams(key_characteristics);
@@ -2479,8 +2430,6 @@
 
         AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics);
         AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics);
-
-        CheckedDeleteKey(&key_blob);
     }
 }
 
@@ -2522,6 +2471,7 @@
             }
         }
         ASSERT_EQ(ErrorCode::OK, result);
+        KeyBlobDeleter deleter(keymint_, key_blob);
         ASSERT_GT(key_blob.size(), 0U);
         CheckBaseParams(key_characteristics);
         CheckCharacteristics(key_blob, key_characteristics);
@@ -2539,8 +2489,6 @@
         EXPECT_TRUE(verify_attestation_record(AidlVersion(), challenge, app_id,  //
                                               sw_enforced, hw_enforced, SecLevel(),
                                               cert_chain_[0].encodedCertificate));
-
-        CheckedDeleteKey(&key_blob);
     }
 }
 
@@ -2561,6 +2509,7 @@
                                                      .Authorization(TAG_USAGE_COUNT_LIMIT, 1)
                                                      .SetDefaultValidity(),
                                              &key_blob, &key_characteristics));
+        KeyBlobDeleter deleter(keymint_, key_blob);
 
         ASSERT_GT(key_blob.size(), 0U);
         CheckBaseParams(key_characteristics);
@@ -2578,8 +2527,6 @@
         }
         EXPECT_TRUE(auths.Contains(TAG_USAGE_COUNT_LIMIT, 1U))
                 << "key usage count limit " << 1U << " missing";
-
-        CheckedDeleteKey(&key_blob);
     }
 }
 
@@ -2587,22 +2534,24 @@
  * NewKeyGenerationTest.EcdsaDefaultSize
  *
  * Verifies that failing to specify a curve for EC key generation returns
- * UNSUPPORTED_KEY_SIZE.
+ * UNSUPPORTED_KEY_SIZE or UNSUPPORTED_EC_CURVE.
  */
 TEST_P(NewKeyGenerationTest, EcdsaDefaultSize) {
-    ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE,
-              GenerateKey(AuthorizationSetBuilder()
-                                  .Authorization(TAG_ALGORITHM, Algorithm::EC)
-                                  .SigningKey()
-                                  .Digest(Digest::NONE)
-                                  .SetDefaultValidity()));
+    auto result = GenerateKey(AuthorizationSetBuilder()
+                                      .Authorization(TAG_ALGORITHM, Algorithm::EC)
+                                      .SigningKey()
+                                      .Digest(Digest::NONE)
+                                      .SetDefaultValidity());
+    ASSERT_TRUE(result == ErrorCode::UNSUPPORTED_KEY_SIZE ||
+                result == ErrorCode::UNSUPPORTED_EC_CURVE)
+            << "unexpected result " << result;
 }
 
 /*
  * NewKeyGenerationTest.EcdsaInvalidCurve
  *
  * Verifies that specifying an invalid curve for EC key generation returns
- * UNSUPPORTED_KEY_SIZE.
+ * UNSUPPORTED_KEY_SIZE or UNSUPPORTED_EC_CURVE.
  */
 TEST_P(NewKeyGenerationTest, EcdsaInvalidCurve) {
     for (auto curve : InvalidCurves()) {
@@ -2615,7 +2564,8 @@
                                           .SetDefaultValidity(),
                                   &key_blob, &key_characteristics);
         ASSERT_TRUE(result == ErrorCode::UNSUPPORTED_KEY_SIZE ||
-                    result == ErrorCode::UNSUPPORTED_EC_CURVE);
+                    result == ErrorCode::UNSUPPORTED_EC_CURVE)
+                << "unexpected result " << result;
     }
 
     ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE,
@@ -2711,6 +2661,7 @@
                           AuthorizationSetBuilder().HmacKey(key_size).Digest(digest).Authorization(
                                   TAG_MIN_MAC_LENGTH, 128),
                           &key_blob, &key_characteristics));
+        KeyBlobDeleter deleter(keymint_, key_blob);
 
         ASSERT_GT(key_blob.size(), 0U);
         CheckBaseParams(key_characteristics);
@@ -2720,8 +2671,6 @@
         EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::HMAC));
         EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size))
                 << "Key size " << key_size << "missing";
-
-        CheckedDeleteKey(&key_blob);
     }
 }
 
@@ -2747,6 +2696,7 @@
                                                      .AttestationApplicationId(app_id)
                                                      .Authorization(TAG_MIN_MAC_LENGTH, 128),
                                              &key_blob, &key_characteristics));
+        KeyBlobDeleter deleter(keymint_, key_blob);
 
         ASSERT_GT(key_blob.size(), 0U);
         ASSERT_EQ(cert_chain_.size(), 0);
@@ -2757,8 +2707,6 @@
         EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::HMAC));
         EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size))
                 << "Key size " << key_size << "missing";
-
-        CheckedDeleteKey(&key_blob);
     }
 }
 
@@ -2780,6 +2728,7 @@
                                                      .Authorization(TAG_MIN_MAC_LENGTH, 128)
                                                      .Authorization(TAG_USAGE_COUNT_LIMIT, 1),
                                              &key_blob, &key_characteristics));
+        KeyBlobDeleter deleter(keymint_, key_blob);
 
         ASSERT_GT(key_blob.size(), 0U);
         CheckBaseParams(key_characteristics);
@@ -2797,8 +2746,6 @@
         }
         EXPECT_TRUE(auths.Contains(TAG_USAGE_COUNT_LIMIT, 1U))
                 << "key usage count limit " << 1U << " missing";
-
-        CheckedDeleteKey(&key_blob);
     }
 }
 
@@ -3456,7 +3403,6 @@
  * Verifies ECDSA signature/verification for all digests and required curves.
  */
 TEST_P(SigningOperationsTest, EcdsaAllDigestsAndCurves) {
-
     string message = "1234567890";
     string corrupt_message = "2234567890";
     for (auto curve : ValidCurves()) {
@@ -3892,6 +3838,7 @@
                                 .Digest(Digest::SHA_2_256)
                                 .Authorization(TAG_MIN_MAC_LENGTH, 160),
                         KeyFormat::RAW, key_material, &signing_key, &signing_key_chars));
+    KeyBlobDeleter sign_deleter(keymint_, signing_key);
     EXPECT_EQ(ErrorCode::OK,
               ImportKey(AuthorizationSetBuilder()
                                 .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -3900,6 +3847,7 @@
                                 .Digest(Digest::SHA_2_256)
                                 .Authorization(TAG_MIN_MAC_LENGTH, 160),
                         KeyFormat::RAW, key_material, &verification_key, &verification_key_chars));
+    KeyBlobDeleter verify_deleter(keymint_, verification_key);
 
     string message = "This is a message.";
     string signature = SignMessage(
@@ -3915,9 +3863,6 @@
     // Verification key should work.
     VerifyMessage(verification_key, message, signature,
                   AuthorizationSetBuilder().Digest(Digest::SHA_2_256));
-
-    CheckedDeleteKey(&signing_key);
-    CheckedDeleteKey(&verification_key);
 }
 
 /*
@@ -3938,6 +3883,7 @@
                                 .Digest(Digest::SHA_2_256)
                                 .Authorization(TAG_MIN_MAC_LENGTH, 160),
                         KeyFormat::RAW, key_material, &signing_key, &signing_key_chars));
+    KeyBlobDeleter sign_deleter(keymint_, signing_key);
     EXPECT_EQ(ErrorCode::OK,
               ImportKey(AuthorizationSetBuilder()
                                 .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -3946,6 +3892,7 @@
                                 .Digest(Digest::SHA_2_256)
                                 .Authorization(TAG_MIN_MAC_LENGTH, 160),
                         KeyFormat::RAW, key_material, &verification_key, &verification_key_chars));
+    KeyBlobDeleter verify_deleter(keymint_, verification_key);
 
     string message = "This is a message.";
     string signature = SignMessage(
@@ -3967,9 +3914,6 @@
 
     signature[0] += 1;  // Corrupt a signature
     EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(message, signature, &output));
-
-    CheckedDeleteKey(&signing_key);
-    CheckedDeleteKey(&verification_key);
 }
 
 INSTANTIATE_KEYMINT_AIDL_TEST(VerificationOperationsTest);
@@ -4173,6 +4117,42 @@
 }
 
 /*
+ * ImportKeyTest.EcdsaSuccessCurveNotSpecified
+ *
+ * Verifies that importing and using an ECDSA P-256 key pair works correctly
+ * when the EC_CURVE is not explicitly specified.
+ */
+TEST_P(ImportKeyTest, EcdsaSuccessCurveNotSpecified) {
+    if (get_vsr_api_level() < __ANDROID_API_V__) {
+        /*
+         * The KeyMint spec was previously not clear as to whether EC_CURVE was optional on import
+         * of EC keys. However, this was not checked at the time so we can only be strict about
+         * checking this for implementations at VSR-V or later.
+         */
+        GTEST_SKIP() << "Skipping EC_CURVE on import only strict >= VSR-V";
+    }
+
+    ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+                                               .Authorization(TAG_NO_AUTH_REQUIRED)
+                                               .Authorization(TAG_ALGORITHM, Algorithm::EC)
+                                               .SigningKey()
+                                               .Digest(Digest::SHA_2_256)
+                                               .SetDefaultValidity(),
+                                       KeyFormat::PKCS8, ec_256_key));
+
+    CheckCryptoParam(TAG_ALGORITHM, Algorithm::EC);
+    CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256);
+    CheckCryptoParam(TAG_EC_CURVE, EcCurve::P_256);
+
+    CheckOrigin();
+
+    string message(32, 'a');
+    auto params = AuthorizationSetBuilder().Digest(Digest::SHA_2_256);
+    string signature = SignMessage(message, params);
+    LocalVerifyMessage(message, signature, params);
+}
+
+/*
  * ImportKeyTest.EcdsaP256RFC5915Success
  *
  * Verifies that importing and using an ECDSA P-256 key pair encoded using RFC5915 works
@@ -4755,6 +4735,109 @@
     }
 }
 
+/*
+ * ImportKeyTest.RsaOaepMGFDigestSuccess
+ *
+ * Include MGF-Digest explicitly in import key authorization list.
+ * Test should import RSA key with OAEP padding and mgf-digests and verify that imported key
+ * should have the correct characteristics.
+ */
+TEST_P(ImportKeyTest, RsaOaepMGFDigestSuccess) {
+    // There was no test to assert that MGF1 digest was present in generated/imported key
+    // characteristics before Keymint V3, so there are some Keymint implementations where
+    // this test case fails(b/297306437), hence this test is skipped for Keymint < 3.
+    if (AidlVersion() < 3) {
+        GTEST_SKIP() << "Test not applicable to Keymint < V3";
+    }
+    auto mgf_digests = ValidDigests(false /* withNone */, true /* withMD5 */);
+    size_t key_size = 2048;
+
+    ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+                                               .OaepMGFDigest(mgf_digests)
+                                               .Authorization(TAG_NO_AUTH_REQUIRED)
+                                               .RsaEncryptionKey(key_size, 65537)
+                                               .Digest(Digest::SHA_2_256)
+                                               .Padding(PaddingMode::RSA_OAEP)
+                                               .SetDefaultValidity(),
+                                       KeyFormat::PKCS8, rsa_2048_key));
+
+    CheckCryptoParam(TAG_ALGORITHM, Algorithm::RSA);
+    CheckCryptoParam(TAG_KEY_SIZE, key_size);
+    CheckCryptoParam(TAG_RSA_PUBLIC_EXPONENT, 65537U);
+    CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256);
+    CheckCryptoParam(TAG_PADDING, PaddingMode::RSA_OAEP);
+    CheckOrigin();
+
+    // Make sure explicitly specified mgf-digests exist in key characteristics.
+    assert_mgf_digests_present_or_not_in_key_characteristics(mgf_digests, true);
+
+    string message = "Hello";
+
+    for (auto digest : mgf_digests) {
+        SCOPED_TRACE(testing::Message() << "digest-" << digest);
+        auto params = AuthorizationSetBuilder()
+                              .Authorization(TAG_RSA_OAEP_MGF_DIGEST, digest)
+                              .Digest(Digest::SHA_2_256)
+                              .Padding(PaddingMode::RSA_OAEP);
+        string ciphertext1 = LocalRsaEncryptMessage(message, params);
+        if (HasNonfatalFailure()) std::cout << "-->" << digest << std::endl;
+        EXPECT_EQ(key_size / 8, ciphertext1.size());
+
+        string ciphertext2 = LocalRsaEncryptMessage(message, params);
+        if (HasNonfatalFailure()) std::cout << "-->" << digest << std::endl;
+        EXPECT_EQ(key_size / 8, ciphertext2.size());
+
+        // OAEP randomizes padding so every result should be different (with astronomically high
+        // probability).
+        EXPECT_NE(ciphertext1, ciphertext2);
+
+        string plaintext1 = DecryptMessage(ciphertext1, params);
+        EXPECT_EQ(message, plaintext1) << "RSA-OAEP failed with digest " << digest;
+        string plaintext2 = DecryptMessage(ciphertext2, params);
+        EXPECT_EQ(message, plaintext2) << "RSA-OAEP failed with digest " << digest;
+
+        // Decrypting corrupted ciphertext should fail.
+        size_t offset_to_corrupt = ciphertext1.size() - 1;
+        char corrupt_byte = ~ciphertext1[offset_to_corrupt];
+        ciphertext1[offset_to_corrupt] = corrupt_byte;
+
+        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
+        string result;
+        EXPECT_NE(ErrorCode::OK, Finish(ciphertext1, &result));
+        EXPECT_EQ(0U, result.size());
+    }
+}
+
+/*
+ * ImportKeyTest.RsaOaepMGFDigestDefaultSuccess
+ *
+ * Don't specify MGF-Digest explicitly in import key authorization list.
+ * Test should import RSA key with OAEP padding and default mgf-digest (SHA1) and
+ * verify that imported key should have the correct characteristics. Default
+ * mgf-digest shouldn't be included in key charecteristics.
+ */
+TEST_P(ImportKeyTest, RsaOaepMGFDigestDefaultSuccess) {
+    size_t key_size = 2048;
+    ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+                                               .Authorization(TAG_NO_AUTH_REQUIRED)
+                                               .RsaEncryptionKey(key_size, 65537)
+                                               .Digest(Digest::SHA_2_256)
+                                               .Padding(PaddingMode::RSA_OAEP)
+                                               .SetDefaultValidity(),
+                                       KeyFormat::PKCS8, rsa_2048_key));
+
+    CheckCryptoParam(TAG_ALGORITHM, Algorithm::RSA);
+    CheckCryptoParam(TAG_KEY_SIZE, key_size);
+    CheckCryptoParam(TAG_RSA_PUBLIC_EXPONENT, 65537U);
+    CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256);
+    CheckCryptoParam(TAG_PADDING, PaddingMode::RSA_OAEP);
+    CheckOrigin();
+
+    vector defaultDigest = {Digest::SHA1};
+    // Make sure default mgf-digest (SHA1) is not included in Key characteristics.
+    assert_mgf_digests_present_or_not_in_key_characteristics(defaultDigest, false);
+}
+
 INSTANTIATE_KEYMINT_AIDL_TEST(ImportKeyTest);
 
 auto wrapped_key = hex2str(
@@ -5180,16 +5263,19 @@
  */
 TEST_P(EncryptionOperationsTest, RsaOaepSuccess) {
     auto digests = ValidDigests(false /* withNone */, true /* withMD5 */);
+    auto mgf_digest = vector{Digest::SHA1};
 
     size_t key_size = 2048;  // Need largish key for SHA-512 test.
-    ASSERT_EQ(ErrorCode::OK,
-              GenerateKey(AuthorizationSetBuilder()
-                                  .Authorization(TAG_NO_AUTH_REQUIRED)
-                                  .RsaEncryptionKey(key_size, 65537)
-                                  .Padding(PaddingMode::RSA_OAEP)
-                                  .Digest(digests)
-                                  .Authorization(TAG_RSA_OAEP_MGF_DIGEST, Digest::SHA1)
-                                  .SetDefaultValidity()));
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .RsaEncryptionKey(key_size, 65537)
+                                                 .Padding(PaddingMode::RSA_OAEP)
+                                                 .Digest(digests)
+                                                 .OaepMGFDigest(mgf_digest)
+                                                 .SetDefaultValidity()));
+
+    // Make sure explicitly specified mgf-digest exist in key characteristics.
+    assert_mgf_digests_present_or_not_in_key_characteristics(mgf_digest, true);
 
     string message = "Hello";
 
@@ -5226,7 +5312,7 @@
 
         EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
         string result;
-        EXPECT_EQ(ErrorCode::UNKNOWN_ERROR, Finish(ciphertext1, &result));
+        EXPECT_NE(ErrorCode::OK, Finish(ciphertext1, &result));
         EXPECT_EQ(0U, result.size());
     }
 }
@@ -5293,7 +5379,7 @@
                                                                 .Digest(Digest::SHA_2_256)
                                                                 .Padding(PaddingMode::RSA_OAEP)));
     string result;
-    EXPECT_EQ(ErrorCode::UNKNOWN_ERROR, Finish(ciphertext, &result));
+    EXPECT_NE(ErrorCode::OK, Finish(ciphertext, &result));
     EXPECT_EQ(0U, result.size());
 }
 
@@ -5314,7 +5400,21 @@
                                                  .Padding(PaddingMode::RSA_OAEP)
                                                  .Digest(Digest::SHA_2_256)
                                                  .SetDefaultValidity()));
+    if (AidlVersion() >= 3) {
+        std::vector<Digest> mgf1DigestsInAuths;
+        mgf1DigestsInAuths.reserve(digests.size());
+        const auto& hw_auths = SecLevelAuthorizations(key_characteristics_);
+        std::for_each(hw_auths.begin(), hw_auths.end(), [&](auto& param) {
+            if (param.tag == Tag::RSA_OAEP_MGF_DIGEST) {
+                KeyParameterValue value = param.value;
+                mgf1DigestsInAuths.push_back(param.value.template get<KeyParameterValue::digest>());
+            }
+        });
 
+        std::sort(digests.begin(), digests.end());
+        std::sort(mgf1DigestsInAuths.begin(), mgf1DigestsInAuths.end());
+        EXPECT_EQ(digests, mgf1DigestsInAuths);
+    }
     string message = "Hello";
 
     for (auto digest : digests) {
@@ -5349,7 +5449,7 @@
 
         EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
         string result;
-        EXPECT_EQ(ErrorCode::UNKNOWN_ERROR, Finish(ciphertext1, &result));
+        EXPECT_NE(ErrorCode::OK, Finish(ciphertext1, &result));
         EXPECT_EQ(0U, result.size());
     }
 }
@@ -5369,6 +5469,10 @@
                                                  .Digest(Digest::SHA_2_256)
                                                  .SetDefaultValidity()));
 
+    vector defaultDigest = vector{Digest::SHA1};
+    // Make sure default mgf-digest (SHA1) is not included in Key characteristics.
+    assert_mgf_digests_present_or_not_in_key_characteristics(defaultDigest, false);
+
     // Do local RSA encryption using the default MGF digest of SHA-1.
     string message = "Hello";
     auto params =
@@ -5390,7 +5494,7 @@
 
     EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
     string result;
-    EXPECT_EQ(ErrorCode::UNKNOWN_ERROR, Finish(ciphertext, &result));
+    EXPECT_NE(ErrorCode::OK, Finish(ciphertext, &result));
     EXPECT_EQ(0U, result.size());
 }
 
@@ -5403,14 +5507,20 @@
  */
 TEST_P(EncryptionOperationsTest, RsaOaepMGFDigestDefaultFail) {
     size_t key_size = 2048;
-    ASSERT_EQ(ErrorCode::OK,
-              GenerateKey(AuthorizationSetBuilder()
-                                  .Authorization(TAG_NO_AUTH_REQUIRED)
-                                  .Authorization(TAG_RSA_OAEP_MGF_DIGEST, Digest::SHA_2_256)
-                                  .RsaEncryptionKey(key_size, 65537)
-                                  .Padding(PaddingMode::RSA_OAEP)
-                                  .Digest(Digest::SHA_2_256)
-                                  .SetDefaultValidity()));
+    auto mgf_digest = vector{Digest::SHA_2_256};
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .OaepMGFDigest(mgf_digest)
+                                                 .RsaEncryptionKey(key_size, 65537)
+                                                 .Padding(PaddingMode::RSA_OAEP)
+                                                 .Digest(Digest::SHA_2_256)
+                                                 .SetDefaultValidity()));
+
+    // Make sure explicitly specified mgf-digest exist in key characteristics.
+    assert_mgf_digests_present_or_not_in_key_characteristics(mgf_digest, true);
+    vector defaultDigest = vector{Digest::SHA1};
+    // Make sure default mgf-digest is not included in key characteristics.
+    assert_mgf_digests_present_or_not_in_key_characteristics(defaultDigest, false);
 
     // Do local RSA encryption using the default MGF digest of SHA-1.
     string message = "Hello";
@@ -5434,14 +5544,18 @@
  * with incompatible MGF digest.
  */
 TEST_P(EncryptionOperationsTest, RsaOaepWithMGFIncompatibleDigest) {
-    ASSERT_EQ(ErrorCode::OK,
-              GenerateKey(AuthorizationSetBuilder()
-                                  .Authorization(TAG_RSA_OAEP_MGF_DIGEST, Digest::SHA_2_256)
-                                  .Authorization(TAG_NO_AUTH_REQUIRED)
-                                  .RsaEncryptionKey(2048, 65537)
-                                  .Padding(PaddingMode::RSA_OAEP)
-                                  .Digest(Digest::SHA_2_256)
-                                  .SetDefaultValidity()));
+    auto mgf_digest = vector{Digest::SHA_2_256};
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .OaepMGFDigest(mgf_digest)
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .RsaEncryptionKey(2048, 65537)
+                                                 .Padding(PaddingMode::RSA_OAEP)
+                                                 .Digest(Digest::SHA_2_256)
+                                                 .SetDefaultValidity()));
+
+    // Make sure explicitly specified mgf-digest exist in key characteristics.
+    assert_mgf_digests_present_or_not_in_key_characteristics(mgf_digest, true);
+
     string message = "Hello World!";
 
     auto params = AuthorizationSetBuilder()
@@ -5458,14 +5572,18 @@
  * with unsupported MGF digest.
  */
 TEST_P(EncryptionOperationsTest, RsaOaepWithMGFUnsupportedDigest) {
-    ASSERT_EQ(ErrorCode::OK,
-              GenerateKey(AuthorizationSetBuilder()
-                                  .Authorization(TAG_RSA_OAEP_MGF_DIGEST, Digest::SHA_2_256)
-                                  .Authorization(TAG_NO_AUTH_REQUIRED)
-                                  .RsaEncryptionKey(2048, 65537)
-                                  .Padding(PaddingMode::RSA_OAEP)
-                                  .Digest(Digest::SHA_2_256)
-                                  .SetDefaultValidity()));
+    auto mgf_digest = vector{Digest::SHA_2_256};
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .OaepMGFDigest(mgf_digest)
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .RsaEncryptionKey(2048, 65537)
+                                                 .Padding(PaddingMode::RSA_OAEP)
+                                                 .Digest(Digest::SHA_2_256)
+                                                 .SetDefaultValidity()));
+
+    // Make sure explicitly specified mgf-digest exist in key characteristics.
+    assert_mgf_digests_present_or_not_in_key_characteristics(mgf_digest, true);
+
     string message = "Hello World!";
 
     auto params = AuthorizationSetBuilder()
@@ -5511,7 +5629,7 @@
 
     EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
     string result;
-    EXPECT_EQ(ErrorCode::UNKNOWN_ERROR, Finish(ciphertext1, &result));
+    EXPECT_NE(ErrorCode::OK, Finish(ciphertext1, &result));
     EXPECT_EQ(0U, result.size());
 }
 
@@ -8498,16 +8616,16 @@
     // Early boot keys can be created after early boot.
     auto [aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData] =
             CreateTestKeys(TAG_EARLY_BOOT_ONLY, ErrorCode::OK);
+    KeyBlobDeleter aes_deleter(keymint_, aesKeyData.blob);
+    KeyBlobDeleter hmac_deleter(keymint_, hmacKeyData.blob);
+    KeyBlobDeleter rsa_deleter(keymint_, rsaKeyData.blob);
+    KeyBlobDeleter ecdsa_deleter(keymint_, ecdsaKeyData.blob);
 
     for (const auto& keyData : {aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData}) {
         ASSERT_GT(keyData.blob.size(), 0U);
         AuthorizationSet crypto_params = SecLevelAuthorizations(keyData.characteristics);
         EXPECT_TRUE(crypto_params.Contains(TAG_EARLY_BOOT_ONLY)) << crypto_params;
     }
-    CheckedDeleteKey(&aesKeyData.blob);
-    CheckedDeleteKey(&hmacKeyData.blob);
-    CheckedDeleteKey(&rsaKeyData.blob);
-    CheckedDeleteKey(&ecdsaKeyData.blob);
 }
 
 /*
@@ -8521,6 +8639,10 @@
                 builder->AttestationChallenge("challenge");
                 builder->AttestationApplicationId("app_id");
             });
+    KeyBlobDeleter aes_deleter(keymint_, aesKeyData.blob);
+    KeyBlobDeleter hmac_deleter(keymint_, hmacKeyData.blob);
+    KeyBlobDeleter rsa_deleter(keymint_, rsaKeyData.blob);
+    KeyBlobDeleter ecdsa_deleter(keymint_, ecdsaKeyData.blob);
 
     for (const auto& keyData : {aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData}) {
         // Strongbox may not support factory attestation. Key creation might fail with
@@ -8532,14 +8654,6 @@
         AuthorizationSet crypto_params = SecLevelAuthorizations(keyData.characteristics);
         EXPECT_TRUE(crypto_params.Contains(TAG_EARLY_BOOT_ONLY)) << crypto_params;
     }
-    CheckedDeleteKey(&aesKeyData.blob);
-    CheckedDeleteKey(&hmacKeyData.blob);
-    if (rsaKeyData.blob.size() != 0U) {
-        CheckedDeleteKey(&rsaKeyData.blob);
-    }
-    if (ecdsaKeyData.blob.size() != 0U) {
-        CheckedDeleteKey(&ecdsaKeyData.blob);
-    }
 }
 
 /*
@@ -8584,6 +8698,11 @@
 TEST_P(EarlyBootKeyTest, DISABLED_FullTest) {
     auto [aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData] =
             CreateTestKeys(TAG_EARLY_BOOT_ONLY, ErrorCode::OK);
+    KeyBlobDeleter aes_deleter(keymint_, aesKeyData.blob);
+    KeyBlobDeleter hmac_deleter(keymint_, hmacKeyData.blob);
+    KeyBlobDeleter rsa_deleter(keymint_, rsaKeyData.blob);
+    KeyBlobDeleter ecdsa_deleter(keymint_, ecdsaKeyData.blob);
+
     // TAG_EARLY_BOOT_ONLY should be in hw-enforced.
     EXPECT_TRUE(HwEnforcedAuthorizations(aesKeyData.characteristics).Contains(TAG_EARLY_BOOT_ONLY));
     EXPECT_TRUE(
@@ -8608,19 +8727,13 @@
     EXPECT_EQ(ErrorCode::EARLY_BOOT_ENDED, UseRsaKey(rsaKeyData.blob));
     EXPECT_EQ(ErrorCode::EARLY_BOOT_ENDED, UseEcdsaKey(ecdsaKeyData.blob));
 
-    CheckedDeleteKey(&aesKeyData.blob);
-    CheckedDeleteKey(&hmacKeyData.blob);
-    CheckedDeleteKey(&rsaKeyData.blob);
-    CheckedDeleteKey(&ecdsaKeyData.blob);
-
     // Should not be able to create new keys
-    std::tie(aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData) =
+    auto [aesKeyData2, hmacKeyData2, rsaKeyData2, ecdsaKeyData2] =
             CreateTestKeys(TAG_EARLY_BOOT_ONLY, ErrorCode::EARLY_BOOT_ENDED);
-
-    CheckedDeleteKey(&aesKeyData.blob);
-    CheckedDeleteKey(&hmacKeyData.blob);
-    CheckedDeleteKey(&rsaKeyData.blob);
-    CheckedDeleteKey(&ecdsaKeyData.blob);
+    KeyBlobDeleter aes_deleter2(keymint_, aesKeyData2.blob);
+    KeyBlobDeleter hmac_deleter2(keymint_, hmacKeyData2.blob);
+    KeyBlobDeleter rsa_deleter2(keymint_, rsaKeyData2.blob);
+    KeyBlobDeleter ecdsa_deleter2(keymint_, ecdsaKeyData2.blob);
 }
 
 INSTANTIATE_KEYMINT_AIDL_TEST(EarlyBootKeyTest);
@@ -8638,6 +8751,10 @@
 TEST_P(UnlockedDeviceRequiredTest, DISABLED_KeysBecomeUnusable) {
     auto [aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData] =
             CreateTestKeys(TAG_UNLOCKED_DEVICE_REQUIRED, ErrorCode::OK);
+    KeyBlobDeleter aes_deleter(keymint_, aesKeyData.blob);
+    KeyBlobDeleter hmac_deleter(keymint_, hmacKeyData.blob);
+    KeyBlobDeleter rsa_deleter(keymint_, rsaKeyData.blob);
+    KeyBlobDeleter ecdsa_deleter(keymint_, ecdsaKeyData.blob);
 
     EXPECT_EQ(ErrorCode::OK, UseAesKey(aesKeyData.blob));
     EXPECT_EQ(ErrorCode::OK, UseHmacKey(hmacKeyData.blob));
@@ -8651,17 +8768,13 @@
     EXPECT_EQ(ErrorCode::DEVICE_LOCKED, UseHmacKey(hmacKeyData.blob));
     EXPECT_EQ(ErrorCode::DEVICE_LOCKED, UseRsaKey(rsaKeyData.blob));
     EXPECT_EQ(ErrorCode::DEVICE_LOCKED, UseEcdsaKey(ecdsaKeyData.blob));
-
-    CheckedDeleteKey(&aesKeyData.blob);
-    CheckedDeleteKey(&hmacKeyData.blob);
-    CheckedDeleteKey(&rsaKeyData.blob);
-    CheckedDeleteKey(&ecdsaKeyData.blob);
 }
 
 INSTANTIATE_KEYMINT_AIDL_TEST(UnlockedDeviceRequiredTest);
 
 using VsrRequirementTest = KeyMintAidlTestBase;
 
+// @VsrTest = VSR-3.10-008
 TEST_P(VsrRequirementTest, Vsr13Test) {
     int vsr_api_level = get_vsr_api_level();
     if (vsr_api_level < __ANDROID_API_T__) {
@@ -8670,6 +8783,7 @@
     EXPECT_GE(AidlVersion(), 2) << "VSR 13+ requires KeyMint version 2";
 }
 
+// @VsrTest = VSR-3.10-013.001
 TEST_P(VsrRequirementTest, Vsr14Test) {
     int vsr_api_level = get_vsr_api_level();
     if (vsr_api_level < __ANDROID_API_U__) {
@@ -8682,10 +8796,11 @@
 
 }  // namespace aidl::android::hardware::security::keymint::test
 
+using aidl::android::hardware::security::keymint::test::KeyMintAidlTestBase;
+
 int main(int argc, char** argv) {
     std::cout << "Testing ";
-    auto halInstances =
-            aidl::android::hardware::security::keymint::test::KeyMintAidlTestBase::build_params();
+    auto halInstances = KeyMintAidlTestBase::build_params();
     std::cout << "HAL instances:\n";
     for (auto& entry : halInstances) {
         std::cout << "    " << entry << '\n';
@@ -8695,12 +8810,10 @@
     for (int i = 1; i < argc; ++i) {
         if (argv[i][0] == '-') {
             if (std::string(argv[i]) == "--arm_deleteAllKeys") {
-                aidl::android::hardware::security::keymint::test::KeyMintAidlTestBase::
-                        arm_deleteAllKeys = true;
+                KeyMintAidlTestBase::arm_deleteAllKeys = true;
             }
             if (std::string(argv[i]) == "--dump_attestations") {
-                aidl::android::hardware::security::keymint::test::KeyMintAidlTestBase::
-                        dump_Attestations = true;
+                KeyMintAidlTestBase::dump_Attestations = true;
             } else {
                 std::cout << "NOT dumping attestations" << std::endl;
             }
@@ -8715,8 +8828,26 @@
                     std::cerr << "Missing argument for --keyblob_dir\n";
                     return 1;
                 }
-                aidl::android::hardware::security::keymint::test::KeyMintAidlTestBase::keyblob_dir =
-                        std::string(argv[i + 1]);
+                KeyMintAidlTestBase::keyblob_dir = std::string(argv[i + 1]);
+                ++i;
+            }
+            if (std::string(argv[i]) == "--expect_upgrade") {
+                if (i + 1 >= argc) {
+                    std::cerr << "Missing argument for --expect_upgrade\n";
+                    return 1;
+                }
+                std::string arg = argv[i + 1];
+                KeyMintAidlTestBase::expect_upgrade =
+                        arg == "yes" ? true
+                                     : (arg == "no" ? false : std::optional<bool>(std::nullopt));
+                if (KeyMintAidlTestBase::expect_upgrade.has_value()) {
+                    std::cout << "expect_upgrade = "
+                              << (KeyMintAidlTestBase::expect_upgrade.value() ? "true" : "false")
+                              << std::endl;
+                } else {
+                    std::cerr << "Error! Option --expect_upgrade " << arg << " unrecognized"
+                              << std::endl;
+                }
                 ++i;
             }
         }
diff --git a/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp b/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp
index c9a156d..9f7322a 100644
--- a/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp
+++ b/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp
@@ -114,6 +114,12 @@
         const auto& vbKey = rot->asArray()->get(pos++);
         ASSERT_TRUE(vbKey);
         ASSERT_TRUE(vbKey->asBstr());
+        if (get_vsr_api_level() >= __ANDROID_API_V__) {
+            // The attestation should contain the SHA-256 hash of the verified boot
+            // key.  However, this not was checked for earlier versions of the KeyMint
+            // HAL so only be strict for VSR-V and above.
+            ASSERT_LE(vbKey->asBstr()->value().size(), 32);
+        }
 
         const auto& deviceLocked = rot->asArray()->get(pos++);
         ASSERT_TRUE(deviceLocked);
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 79189a1..b8c69eb 100644
--- a/security/keymint/support/include/remote_prov/remote_prov_utils.h
+++ b/security/keymint/support/include/remote_prov/remote_prov_utils.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <memory>
+#include <string>
 #include <vector>
 #include "aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.h"
 
@@ -129,8 +130,8 @@
  *     "name": <string>
  *   }
  */
-JsonOutput jsonEncodeCsrWithBuild(const std::string instance_name,
-                                  const cppbor::Array& csr);
+JsonOutput jsonEncodeCsrWithBuild(const std::string& instance_name, const cppbor::Array& csr,
+                                  const std::string& serialno_prop);
 
 /**
  * Parses a DeviceInfo structure from the given CBOR data. The parsed data is then validated to
diff --git a/security/keymint/support/remote_prov_utils.cpp b/security/keymint/support/remote_prov_utils.cpp
index c9c3e4d..a830041 100644
--- a/security/keymint/support/remote_prov_utils.cpp
+++ b/security/keymint/support/remote_prov_utils.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <iomanip>
 #include <iterator>
 #include <memory>
 #include <set>
@@ -336,9 +337,9 @@
     return result;
 }
 
-JsonOutput jsonEncodeCsrWithBuild(const std::string instance_name, const cppbor::Array& csr) {
+JsonOutput jsonEncodeCsrWithBuild(const std::string& instance_name, const cppbor::Array& csr,
+                                  const std::string& serialno_prop) {
     const std::string kFingerprintProp = "ro.build.fingerprint";
-    const std::string kSerialNoProp = "ro.serialno";
 
     if (!::android::base::WaitForPropertyCreation(kFingerprintProp)) {
         return JsonOutput::Error("Unable to read build fingerprint");
@@ -363,7 +364,7 @@
     Json::Value json(Json::objectValue);
     json["name"] = instance_name;
     json["build_fingerprint"] = ::android::base::GetProperty(kFingerprintProp, /*default=*/"");
-    json["serialno"] = ::android::base::GetProperty(kSerialNoProp, /*default=*/"");
+    json["serialno"] = ::android::base::GetProperty(serialno_prop, /*default=*/"");
     json["csr"] = base64.data();  // Boring writes a NUL-terminated c-string
 
     Json::StreamWriterBuilder factory;
@@ -420,6 +421,36 @@
     return entryName + " has an invalid value.\n";
 }
 
+std::string checkMapPatchLevelEntry(bool isFactory, const cppbor::Map& devInfo,
+                                    const std::string& entryName) {
+    std::string error = checkMapEntry(isFactory, devInfo, cppbor::UINT, entryName);
+    if (!error.empty()) {
+        return error;
+    }
+
+    if (isFactory) {
+        return "";
+    }
+
+    const std::unique_ptr<cppbor::Item>& val = devInfo.get(entryName);
+    std::string dateString = std::to_string(val->asUint()->unsignedValue());
+    if (dateString.size() == 6) {
+        dateString += "01";
+    }
+    if (dateString.size() != 8) {
+        return entryName + " should in the format YYYYMMDD or YYYYMM\n";
+    }
+
+    std::tm t;
+    std::istringstream ss(dateString);
+    ss >> std::get_time(&t, "%Y%m%d");
+    if (!ss) {
+        return entryName + " should in the format YYYYMMDD or YYYYMM\n";
+    }
+
+    return "";
+}
+
 bool isTeeDeviceInfo(const cppbor::Map& devInfo) {
     return devInfo.get("security_level") && devInfo.get("security_level")->asTstr() &&
            devInfo.get("security_level")->asTstr()->value() == "tee";
@@ -489,6 +520,15 @@
                    std::to_string(info.versionNumber) + ").";
         }
     }
+    // Bypasses the device info validation since the device info in AVF is currently
+    // empty. Check b/299256925 for more information.
+    //
+    // TODO(b/300911665): This check is temporary and will be replaced once the markers
+    // on the DICE chain become available. We need to determine if the CSR is from the
+    // RKP VM using the markers on the DICE chain.
+    if (info.uniqueId == "AVF Remote Provisioning 1") {
+        return std::move(parsed);
+    }
 
     std::string error;
     std::string tmp;
@@ -520,6 +560,10 @@
                     error += "Err: Unrecognized key entry: <" + key->asTstr()->value() + ">,\n";
                 }
             }
+            // Checks that only apply to v3.
+            error += checkMapPatchLevelEntry(isFactory, *parsed, "system_patch_level");
+            error += checkMapPatchLevelEntry(isFactory, *parsed, "boot_patch_level");
+            error += checkMapPatchLevelEntry(isFactory, *parsed, "vendor_patch_level");
             FALLTHROUGH_INTENDED;
         case 2:
             for (const auto& entry : kAttestationIdEntrySet) {
@@ -927,6 +971,20 @@
     return signedRequest->value();
 }
 
+ErrMsgOr<hwtrust::DiceChain::Kind> getDiceChainKind() {
+    int vendor_api_level = ::android::base::GetIntProperty("ro.vendor.api_level", -1);
+    switch (vendor_api_level) {
+        case __ANDROID_API_T__:
+            return hwtrust::DiceChain::Kind::kVsr13;
+        case __ANDROID_API_U__:
+            return hwtrust::DiceChain::Kind::kVsr14;
+        case 202404: /* TODO(b/315056516) Use a version macro for vendor API 24Q2 */
+            return hwtrust::DiceChain::Kind::kVsr15;
+        default:
+            return "Unsupported vendor API level: " + std::to_string(vendor_api_level);
+    }
+}
+
 ErrMsgOr<bytevec> parseAndValidateAuthenticatedRequest(const std::vector<uint8_t>& request,
                                                        const std::vector<uint8_t>& challenge) {
     auto [parsedRequest, _, csrErrMsg] = cppbor::parse(request);
@@ -961,7 +1019,12 @@
     }
 
     // DICE chain is [ pubkey, + DiceChainEntry ].
-    auto diceContents = validateBcc(diceCertChain, hwtrust::DiceChain::Kind::kVsr14);
+    auto diceChainKind = getDiceChainKind();
+    if (!diceChainKind) {
+        return diceChainKind.message();
+    }
+
+    auto diceContents = validateBcc(diceCertChain, *diceChainKind);
     if (!diceContents) {
         return diceContents.message() + "\n" + prettyPrint(diceCertChain);
     }
diff --git a/security/keymint/support/remote_prov_utils_test.cpp b/security/keymint/support/remote_prov_utils_test.cpp
index eaaba45..630f7bb 100644
--- a/security/keymint/support/remote_prov_utils_test.cpp
+++ b/security/keymint/support/remote_prov_utils_test.cpp
@@ -182,10 +182,11 @@
 }
 
 TEST(RemoteProvUtilsTest, JsonEncodeCsr) {
+    const std::string kSerialNoProp = "ro.serialno";
     cppbor::Array array;
     array.add(1);
 
-    auto [json, error] = jsonEncodeCsrWithBuild(std::string("test"), array);
+    auto [json, error] = jsonEncodeCsrWithBuild(std::string("test"), array, kSerialNoProp);
 
     ASSERT_TRUE(error.empty()) << error;
 
diff --git a/security/rkp/README.md b/security/rkp/README.md
index 5a93734..2d00b83 100644
--- a/security/rkp/README.md
+++ b/security/rkp/README.md
@@ -3,7 +3,7 @@
 ## Objective
 
 Design a HAL to support over-the-air provisioning of certificates for asymmetric
-keys. The HAL must interact effectively with Keystore (and other daemons) and
+keys. The HAL must interact effectively with Keystore (and other services) and
 protect device privacy and security.
 
 Note that this API was originally designed for KeyMint, with the intention that
@@ -20,125 +20,54 @@
 To more securely and reliably get keys and certificates to Android devices, we
 need to create a system where no party outside of the device's secure components
 is responsible for managing private keys. The strategy we've chosen is to
-deliver certificates over the air, using an asymmetric key pair created
-on-device in the factory as a root of trust to create an authenticated, secure
-channel. In this document we refer to this device-unique asymmetric key pair as
-Device Key (DK), its public half DK\_pub, its private half DK\_priv and a Device
-Key Certificate containing DK\_pub is denoted DKC.
+deliver certificates over the air, using an asymmetric key pair derived from a
+unique device secret (UDS) as a root of trust for authenticated requests from
+the secure components. We refer to the public half of this asymmetric key pair
+as UDS\_pub.
 
-In order for the provisioning service to use DK (or a key authenticated by DK),
-it must know whether a given DK\_pub is known and trusted. To prove trust, we
-ask device OEMs to use one of two mechanisms:
+In order for the provisioning service to trust UDS\_pub we ask device OEMs to
+use one of two mechanisms:
 
-1.  (Preferred, recommended) The device OEM extracts DK\_pub from each device it
-    manufactures and uploads the public keys to a backend server.
+1.  (Preferred, recommended) The device OEM extracts the UDS\_pub from each
+    device they manufacture and uploads the public keys to a backend server.
 
-1.  The device OEM signs the DK\_pub to produce DKC and stores it on the device.
-    This has the advantage that they don't need to upload a DK\_pub for every
-    device immediately, but the disadvantage that they have to manage their
-    private signing keys, which means they have to have HSMs, configure and
-    secure them correctly, etc. Some backend providers may also require that the
-    OEM passes a factory security audit, and additionally promises to upload the
-    keys eventually as well.
+1.  The device OEM signs the UDS\_pub and stores the certificates on the device
+    rather than uploading a UDS\_pub for every device immediately. However,
+    there are many disadvantages and costs associated with this option as the
+    OEM will need to pass a security audit of their factory's physical security,
+    CA and HSM configuration, and incident response processes before the OEM's
+    public key is registered with the provisioning server.
 
-Note that in the full elaboration of this plan, DK\_pub is not the key used to
-establish a secure channel. Instead, DK\_pub is just the first public key in a
-chain of public keys which ends with the KeyMint public key, KM\_pub. All keys
-in the chain are device-unique and are joined in a certificate chain called the
-_Boot Certificate Chain_ (BCC), because in phases 2 and 3 of the remote
-provisioning project it is a chain of certificates corresponding to boot phases.
-We speak of the BCC even for phase 1, though in phase 1 it contains only a
-single self-signed DKC. This is described in more depth in the Phases section
-below.
+Note that in the full elaboration of this plan, UDS\_pub is not the key used to
+sign certificate requests. Instead, UDS\_pub is just the first public key in a
+chain of public keys that end the KeyMint public key. All keys in the chain are
+transitively derived from the UDS and joined in a certificate chain following
+the specification of the [Android Profile for DICE](android-profile-for-dice).
 
-The BCC is authenticated by DK\_pub. To authenticate DK\_pub, we may have
-additional DKCs, from the SoC vendor, the device OEM, or both. Those are not
-part of the BCC but included as optional fields in the certificate request
-structure.
-
-The format of the the DK and BCC is specified within [Open Profile for DICE]
-(https://pigweed.googlesource.com/open-dice/+/HEAD/docs/specification.md).  To
-map phrases within this document to their equivalent terminology in the DICE
-specification, read the terms as follows: the DK corresponds to the UDS-derived
-key pair, DKC corresponds to the UDS certificate, and the BCC entries between
-DK\_pub and KM\_pub correspond to a chain of CDI certificates.
-
-Note: In addition to allowing 32 byte hash values for fields in the BCC payload,
-this spec additionally constrains some of the choices allowed in open-DICE.
-Specifically, these include which entries are required and which are optional in
-the BCC payload, and which algorithms are acceptable for use.
+[android-profile-for-dice]: https://pigweed.googlesource.com/open-dice/+/refs/heads/main/docs/android.md
 
 ### Phases
 
-RKP will be deployed in three phases, in terms of managing the root of trust
+RKP will be deployed with phased management of the root of trust
 binding between the device and the backend. To briefly describe them:
 
-* Phase 1: In phase 1 there is only one entry in the BCC; DK_pub and KM_pub are
-  the same key and the certificate is self-signed.
-* Phase 2: This is identical to phase 1, except it leverages the hardware root
-  of trust process described by DICE. Instead of trust being rooted in the TEE,
-  it is now rooted in the ROM by key material blown into fuses which are only
-  accessible to the ROM code.
-* Phase 3: This is identical to Phase 2, except the SoC vendor also does the
-  public key extraction or certification in their facilities, along with the OEM
-  doing it in the factory. This tightens up the "supply chain" and aims to make
-  key upload management more secure.
+* Degenerate DICE (Phase 1): A TEE root of trust key pair is used to sign
+  certificate requests; a single self-signed certificate signifies this phase.
+* DICE (Phase 2): A hardware root of trust key pair is only accessible to ROM
+  or ROM extension code; the boot process follows the [Android Profile for
+  DICE](android-profile-for-dice).
+* SoC vendor certified DICE (Phase 3): This is identical to Phase 2, except the
+  SoC vendor also does the UDS\_pub extraction or certification in their
+  facilities, along with the OEM doing it in the factory. This tightens up the
+  "supply chain" and aims to make key upload management more secure.
 
 ### Privacy considerations
 
-Because DK and the DKCs are unique, immutable, unspoofable hardware-bound
-identifiers for the device, we must limit access to them to the absolute minimum
-possible. We do this in two ways:
-
-1.  We require KeyMint (which knows the BCC and either knows or at least has the
-ability to use KM\_priv) to refuse to ever divulge the BCC or additional
-signatures in plaintext. Instead, KeyMint requires the caller to provide an
-_Endpoint Encryption Key_ (EEK), with which it will encrypt the data before
-returning it. When provisioning production keys, the EEK must be signed by an
-approved authority whose public key is embedded in KeyMint. When certifying test
-keys, KeyMint will accept any EEK without checking the signature, but will
-encrypt and return a test BCC, rather than the real one.  The result is that
-only an entity in possession of an Trusted EEK (TEEK) private key can discover
-the plaintext of the production BCC.
-1.  Having thus limited access to the public keys to the trusted party only, we
-need to prevent the entity from abusing this unique device identifier.  The
-approach and mechanisms for doing that are beyond the scope of this document
-(they must be addressed in the server design), but generally involve taking care
-to ensure that we do not create any links between user IDs, IP addresses or
-issued certificates and the device pubkey.
-
-Although the details of the mechanisms for preventing the entity from abusing
-the BCC are, as stated, beyond the scope of this document, there is a subtle
-design decision here made specifically to enable abuse prevention. Specifically
-the `CertificateRequest` message sent to the server is (in
-[CDDL](https://tools.ietf.org/html/rfc8610)):
-
-```
-cddl
-CertificateRequest = [
-    DeviceInfo,
-    challenge : bstr,
-    ProtectedData,
-    MacedKeysToSign
-]
-```
-
-The public keys to be attested by the server are in `MacedKeysToSign`, which is
-a COSE\_Mac0 structure, MACed with a key that is found in `ProtectedData`. The
-MAC key is signed by DK\_pub.
-
-This structure allows the backend component that has access to EEK\_priv to
-decrypt `ProtectedData`, validate that the request is from an authorized device,
-check that the request is fresh and verify and extract the MAC key. That backend
-component never sees any data related to the keys to be signed, but can provide
-the MAC key to another backend component that can verify `MacedKeysToSign` and
-proceed to generate the certificates.
-
-In this way, we can partition the provisioning server into one component that
-knows the device identity, as represented by DK\_pub, but never sees the keys to
-be certified or certificates generated, and another component that sees the keys
-to be certified and certificates generated but does not know the device
-identity.
+Because the UDS, CDIs and derived values are unique, immutable, unspoofable
+hardware-bound identifiers for the device, we must limit access to them. We
+require that the values are never exposed in public APIs and are only available
+to the minimum set of system components that require access to them to function
+correctly.
 
 ### Key and cryptographic message formatting
 
@@ -195,24 +124,6 @@
 choice for algorithm implies the implementor should also choose the P256 public
 key group further down in the COSE structure.
 
-### Testability
-
-It's critical that the remote provisioning implementation be testable, to
-minimize the probability that broken devices are sold to end users. To support
-testing, the remote provisioning HAL methods take a `testMode` argument. Keys
-created in test mode are tagged to indicate this. The provisioning server will
-check for the test mode tag and issue test certificates that do not chain back
-to a trusted public key. In test mode, any EEK will be accepted, enabling
-testing tools to use EEKs for which they have the private key so they can
-validate the content of certificate requests. The BCC included in the
-`CertificateRequest` must contain freshly-generated keys, not the real BCC keys.
-
-Keystore (or similar) will need to be able to handle both testMode keys and
-production keys and keep them distinct, generating test certificate requests
-when asked with a test EEK and production certificate requests when asked with a
-production EEK. Likewise, the interface used to instruct Keystore to create keys
-will need to be able to specify whether test or production keys are desired.
-
 ## Design
 
 ### Certificate provisioning flow
@@ -220,25 +131,20 @@
 TODO(jbires): Replace this with a `.png` containing a sequence diagram.  The
 provisioning flow looks something like this:
 
-Provisioner -> Keystore: Prepare N keys
-Keystore -> KeyMint: generateKeyPair
-KeyMint -> KeyMint: Generate  key pair
-KeyMint --> Keystore: key\_blob,pubkey
-Keystore -> Keystore: Store key\_blob,pubkey
-Provisioner -> Server: Get TEEK
-Server --> Provisioner: TEEK
-Provisioner -> Keystore: genCertReq(N, TEEK)
-Keystore -> KeyMint: genCertReq(pubkeys, TEEK)
-KeyMint -> KeyMint: Sign pubkeys & encrypt BCC
-KeyMint --> Keystore: signature, encrypted BCC
-Keystore -> Keystore: Construct cert\_request
-Keystore --> Provisioner: cert\_request
-Provisioner --> Server: cert\_request
-Server -> Server: Validate cert\_request
+rkpd -> KeyMint: generateKeyPair
+KeyMint -> KeyMint: Generate key pair
+KeyMint --> rkpd: key\_blob,pubkey
+rkpd -> rkpd: Store key\_blob,pubkey
+rkpd -> Server: Get challenge
+Server --> rkpd: challenge
+rkpd -> KeyMint: genCertReq(pubkeys, challenge)
+KeyMint -> KeyMint: Sign CSR
+KeyMint --> rkpd: signed CSR
+rkpd --> Server: CSR
+Server -> Server: Validate CSR
 Server -> Server: Generate certificates
-Server --> Provisioner: certificates
-Provisioner -> Keystore: certificates
-Keystore -> Keystore: Store certificates
+Server --> rkpd: certificates
+rkpd -> rkpd: Store certificates
 
 The actors in the above diagram are:
 
@@ -246,10 +152,12 @@
     the uploaded device public keys and is responsible for providing encryption
     keys, decrypting and validating requests, and generating certificates in
     response to requests.
-*   **Provisioner** is an application that is responsible for communicating with
-    the server and all of the system components that require key certificates
-    from the server. It also implements the policy that defines how many key
-    pairs each client should keep in their pool.
+*   **rkpd** is, optionally, a modular system component that is responsible for
+    communicating with the server and all of the system components that require
+    key certificates from the server. It also implements the policy that defines
+    how many key pairs each client should keep in their pool. When a system
+    ships with rkpd as a modular component, it may be updated independently from
+    the rest of the system.
 *   **Keystore** is the [Android keystore
     daemon](https://developer.android.com/training/articles/keystore) (or, more
     generally, whatever system component manages communications with a
@@ -257,116 +165,6 @@
 *   **KeyMint** is the secure area component that manages cryptographic keys and
     performs attestations (or perhaps some other secure area component).
 
-### `BCC`
-
-The _Boot Certificate Chain_ (BCC) is the chain of certificates that contains
-DK\_pub as well as other often device-unique certificates. The BCC is
-represented as a COSE\_Key containing DK\_pub followed by an array of
-COSE\_Sign1 "certificates" containing public keys and optional additional
-information, ordered from root to leaf, with each certificate signing the next.
-The first certificate in the array is signed by DK\_pub, the last certificate
-has the KeyMint (or whatever) signing key's public key, KM\_pub. In phase 1
-there is only one entry; DK\_pub and KM\_pub are the same key and the
-certificate is self-signed.
-
-Each COSE\_Sign1 certificate is a CBOR Web Token (CWT) as described in [RFC
-8392](https://tools.ietf.org/html/rfc8392) with additional fields as described
-in the Open Profile for DICE. Of these additional fields, only the
-_subjectPublicKey_ and _keyUsage_ fields are expected to be present for the
-KM\_pub entry (that is, the last entry) in a BCC, but all fields required by the
-Open Profile for DICE are expected for other entries (each of which corresponds
-to a particular firmware component or boot stage). The CWT fields _iss_ and
-_sub_ identify the issuer and subject of the certificate and are consistent
-along the BCC entries; the issuer of a given entry matches the subject of the
-previous entry.
-
-The BCC is designed to be constructed using the Open Profile for DICE. In this
-case the DK key pair is derived from the UDS as described by that profile and
-all BCC entries before the leaf are CBOR CDI certificates chained from DK\_pub.
-The KM key pair is not part of the derived DICE chain. It is generated (not
-derived) by the KeyMint module, certified by the last key in the DICE chain, and
-added as the leaf BCC entry. The key usage field in this leaf certificate must
-indicate the key is not used to sign certificates. If a UDS certificate is
-available on the device it should appear in the certificate request as the leaf
-of a DKCertChain in AdditionalDKSignatures (see
-[CertificateRequest](#certificaterequest)).
-
-#### Mode
-
-The Open Profile for DICE specifies four possible modes with the most important
-mode being `normal`. A certificate must only set the mode to `normal` when all
-of the following conditions are met when loading and verifying the software
-component that is being described by the certificate:
-
-*   verified boot with anti-rollback protection is enabled
-*   only the verified boot authorities for production images are enabled
-*   debug ports, fuses or other debug facilities are disabled
-*   device booted software from the normal primary source e.g. internal flash
-
-If any of these conditions are not met then it is recommended to explicitly
-acknowledge this fact by using the `debug` mode. The mode should never be `not
-configured`.
-
-#### Configuration descriptor
-
-The Open Profile for DICE allows for an arbitrary configuration descriptor. For
-BCC entries, this configuration descriptor is a CBOR map with the following
-optional fields. If no fields are relevant, an empty map should be encoded.
-Additional implementation-specific fields may be added using key values not in
-the range \[-70000, -70999\] (these are reserved for future additions here).
-
-```
-| Name              | Key    | Value type | Meaning                           |
-| ----------------- | ------ | ---------- | ----------------------------------|
-| Component name    | -70002 | tstr       | Name of firmware component / boot |
-:                   :        :            : stage                             :
-| Component version | -70003 | int / tstr | Version of firmware component /   |
-:                   :        :            : boot stage                        :
-| Resettable        | -70004 | null       | If present, key changes on factory|
-:                   :        :            : reset                             :
-| Security version  | -70005 | uint       | Machine-comparable, monotonically |
-:                   :        :            : increasing version of the firmware:
-:                   :        :            : component / boot stage where a    :
-:                   :        :            : greater value indicates a newer   :
-:                   :        :            : version                           :
-```
-
-Please see
-[ProtectedData.aidl](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/ProtectedData.aidl)
-for a full CDDL definition of the BCC.
-
-### `CertificateRequest`
-
-The full CBOR message that will be sent to the server to request certificates
-is:
-
-```cddl
-CertificateRequest = [
-    DeviceInfo,
-    challenge : bstr,       // Provided by the server
-    ProtectedData,          // See ProtectedData.aidl
-    MacedKeysToSign         // See IRemotelyProvisionedComponent.aidl
-]
-
-DeviceInfo = [
-    VerifiedDeviceInfo,     // See DeviceInfo.aidl
-    UnverifiedDeviceInfo
-]
-
-// Unverified info is anything provided by the HLOS. Subject to change out of
-// step with the HAL.
-UnverifiedDeviceInfo = {
-    ? "fingerprint" : tstr,
-}
-
-```
-
-It will be the responsibility of Keystore and the Provisioner to construct the
-`CertificateRequest`. The HAL provides a method to generate the elements that
-need to be constructed on the secure side, which are the tag field of
-`MacedKeysToSign`, `VerifiedDeviceInfo`, and the ciphertext field of
-`ProtectedData`.
-
 ### HAL
 
 The remote provisioning HAL provides a simple interface that can be implemented
@@ -392,3 +190,30 @@
 *   [RpcHardwareInfo](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl)
 *   [DeviceInfo](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/DeviceInfo.aidl)
 
+### Support for Android Virtualization Framework
+
+The Android Virtualization Framwork (AVF) relies on RKP to provision keys for VMs. A
+privileged vm, the RKP VM, is reponsible for generating and managing the keys for client
+VMs that run virtualized workloads. See the following for more background information on the
+RKP VM:
+*    [rkp-vm](https://android.googlesource.com/platform/packages/modules/Virtualization/+/main/service_vm/README.md#rkp-vm-remote-key-provisioning-virtual-machine)
+*    [rkp-service](https://source.android.com/docs/core/ota/modular-system/remote-key-provisioning#stack-architecture)
+
+It is important to distinquish the RKP VM from other components, such as KeyMint. An
+[RKP VM marker](https://pigweed.googlesource.com/open-dice/+/HEAD/docs/android.md#configuration-descriptor)
+(key `-70006) is used for this purpose. The existence or absence of this marker is used to
+identify the type of component decribed by a given DICE chain.
+
+The following describes which certificate types may be request based on the RKP VM marker:
+1. "rkp-vm": If a DICE chain has zero or more certificates without the RKP VM
+   marker followed by one or more certificates with the marker, then that chain
+   describes an RKP VM. If there are further certificates without the RKP VM
+   marker, then the chain does not describe an RKP VM.
+
+   Implementations must include the first RKP VM marker as early as possible
+   after the point of divergence between TEE and non-TEE components in the DICE
+   chain, prior to loading the Android Bootloader (ABL).
+2. "widevine" or "keymint": If there are no certificates with the RKP VM
+   marker then it describes a TEE component.
+3. None: Any component described by a DICE chain that does not match the above
+   two categories.
diff --git a/security/rkp/aidl/Android.bp b/security/rkp/aidl/Android.bp
index e2ce649..adc63f6 100644
--- a/security/rkp/aidl/Android.bp
+++ b/security/rkp/aidl/Android.bp
@@ -25,9 +25,16 @@
                 "//apex_available:platform",
                 "com.android.rkpd",
             ],
+            lint: {
+                baseline_filename: "lint-baseline.xml",
+            },
         },
         rust: {
             enabled: true,
+            apex_available: [
+                "//apex_available:platform",
+                "com.android.virt",
+            ],
         },
     },
     versions_with_info: [
diff --git a/security/rkp/aidl/android/hardware/security/keymint/DeviceInfo.aidl b/security/rkp/aidl/android/hardware/security/keymint/DeviceInfo.aidl
index 8456148..f668536 100644
--- a/security/rkp/aidl/android/hardware/security/keymint/DeviceInfo.aidl
+++ b/security/rkp/aidl/android/hardware/security/keymint/DeviceInfo.aidl
@@ -32,79 +32,9 @@
      * non-canonical to group similar entries semantically.
      *
      * The DeviceInfo has changed across versions 1, 2, and 3 of the HAL. All versions of the
-     * DeviceInfo CDDL are described as follows. Please refer to the CDDL structure version
-     * that corresponds to the HAL version you are working with:
+     * DeviceInfo CDDL are described in the DeviceInfoV*.cddl files. Please refer to the CDDL
+     * structure version that corresponds to the HAL version you are working with.
      *
-     * Version 3, introduced in Android 14:
-     *     DeviceInfo = {
-     *         "brand" : tstr,
-     *         "manufacturer" : tstr,
-     *         "product" : tstr,
-     *         "model" : tstr,
-     *         "device" : tstr,
-     *         "vb_state" : "green" / "yellow" / "orange",    ; Taken from the AVB values
-     *         "bootloader_state" : "locked" / "unlocked",    ; Taken from the AVB values
-     *         "vbmeta_digest": bstr,                         ; Taken from the AVB values
-     *         ? "os_version" : tstr,                         ; Same as
-     *                                                        ; android.os.Build.VERSION.release
-     *                                                        ; Not optional for TEE.
-     *         "system_patch_level" : uint,     ; YYYYMM, must match KeyMint OS_PATCHLEVEL
-     *         "boot_patch_level" : uint,       ; YYYYMMDD, must match KeyMint BOOT_PATCHLEVEL
-     *         "vendor_patch_level" : uint,     ; YYYYMMDD, must match KeyMint VENDOR_PATCHLEVEL
-     *         "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.
-     *     }
-     *
-     * ---------------------------------------------------------------------------------------------
-     *
-     * Version 2, introduced in Android 13:
-     *     DeviceInfo = {
-     *         "brand" : tstr,
-     *         "manufacturer" : tstr,
-     *         "product" : tstr,
-     *         "model" : tstr,
-     *         "device" : tstr,
-     *         "vb_state" : "green" / "yellow" / "orange",    ; Taken from the AVB values
-     *         "bootloader_state" : "locked" / "unlocked",    ; Taken from the AVB values
-     *         "vbmeta_digest": bstr,                         ; Taken from the AVB values
-     *         ? "os_version" : tstr,                         ; Same as
-     *                                                        ; android.os.Build.VERSION.release
-     *                                                        ; Not optional for TEE.
-     *         "system_patch_level" : uint,     ; YYYYMM, must match KeyMint OS_PATCHLEVEL
-     *         "boot_patch_level" : uint,       ; YYYYMMDD, must match KeyMint BOOT_PATCHLEVEL
-     *         "vendor_patch_level" : uint,     ; YYYYMMDD, must match KeyMint VENDOR_PATCHLEVEL
-     *         "version" : 2,                                 ; The CDDL schema version.
-     *         "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.
-     *
-     * ---------------------------------------------------------------------------------------------
-     *
-     * Version 1, introduced in Android 12:
-     *     DeviceInfo = {
-     *         ? "brand" : tstr,
-     *         ? "manufacturer" : tstr,
-     *         ? "product" : tstr,
-     *         ? "model" : tstr,
-     *         ? "board" : tstr,
-     *         ? "vb_state" : "green" / "yellow" / "orange",  ; Taken from the AVB values
-     *         ? "bootloader_state" : "locked" / "unlocked",  ; Taken from the AVB values
-     *         ? "vbmeta_digest": bstr,                       ; Taken from the AVB values
-     *         ? "os_version" : tstr,                         ; Same as
-     *                                                        ; android.os.Build.VERSION.release
-     *         ? "system_patch_level" : uint,     ; YYYYMM, must match KeyMint OS_PATCHLEVEL
-     *         ? "boot_patch_level" : uint,       ; YYYYMMDD, must match KeyMint BOOT_PATCHLEVEL
-     *         ? "vendor_patch_level" : uint,     ; YYYYMMDD, must match KeyMint VENDOR_PATCHLEVEL
-     *         "version" : 1,                                 ; The CDDL schema version.
-     *         "security_level" : "tee" / "strongbox"
-     *         "att_id_state": "locked" / "open",  ; Attestation IDs State. If "locked", this
-     *                                             ; indicates a device's attestable IDs are
-     *                                             ; factory-locked and immutable. If "open",
-     *                                             ; this indicates the device is still in a
-     *                                             ; provisionable state and the attestable IDs
-     *                                             ; are not yet frozen.
-     *     }
      */
     byte[] deviceInfo;
 }
diff --git a/security/rkp/aidl/android/hardware/security/keymint/DeviceInfoV1.cddl b/security/rkp/aidl/android/hardware/security/keymint/DeviceInfoV1.cddl
new file mode 100644
index 0000000..056316b
--- /dev/null
+++ b/security/rkp/aidl/android/hardware/security/keymint/DeviceInfoV1.cddl
@@ -0,0 +1,24 @@
+; Version 1, introduced in Android 12:
+DeviceInfo = {
+    ? "brand" : tstr,
+    ? "manufacturer" : tstr,
+    ? "product" : tstr,
+    ? "model" : tstr,
+    ? "board" : tstr,
+    ? "vb_state" : "green" / "yellow" / "orange",  ; Taken from the AVB values
+    ? "bootloader_state" : "locked" / "unlocked",  ; Taken from the AVB values
+    ? "vbmeta_digest": bstr,                       ; Taken from the AVB values
+    ? "os_version" : tstr,                         ; Same as
+                                                   ; android.os.Build.VERSION.release
+    ? "system_patch_level" : uint,     ; YYYYMM, must match KeyMint OS_PATCHLEVEL
+    ? "boot_patch_level" : uint,       ; YYYYMMDD, must match KeyMint BOOT_PATCHLEVEL
+    ? "vendor_patch_level" : uint,     ; YYYYMMDD, must match KeyMint VENDOR_PATCHLEVEL
+    "version" : 1,                                 ; The CDDL schema version.
+    "security_level" : "tee" / "strongbox"
+    "att_id_state": "locked" / "open",  ; Attestation IDs State. If "locked", this
+                                        ; indicates a device's attestable IDs are
+                                        ; factory-locked and immutable. If "open",
+                                        ; this indicates the device is still in a
+                                        ; provisionable state and the attestable IDs
+                                        ; are not yet frozen.
+}
diff --git a/security/rkp/aidl/android/hardware/security/keymint/DeviceInfoV2.cddl b/security/rkp/aidl/android/hardware/security/keymint/DeviceInfoV2.cddl
new file mode 100644
index 0000000..e49471e
--- /dev/null
+++ b/security/rkp/aidl/android/hardware/security/keymint/DeviceInfoV2.cddl
@@ -0,0 +1,21 @@
+; Version 2, introduced in Android 13:
+DeviceInfo = {
+    "brand" : tstr,
+    "manufacturer" : tstr,
+    "product" : tstr,
+    "model" : tstr,
+    "device" : tstr,
+    "vb_state" : "green" / "yellow" / "orange",    ; Taken from the AVB values
+    "bootloader_state" : "locked" / "unlocked",    ; Taken from the AVB values
+    "vbmeta_digest": bstr,                         ; Taken from the AVB values
+    ? "os_version" : tstr,                         ; Same as
+                                                   ; android.os.Build.VERSION.release
+                                                   ; Not optional for TEE.
+    "system_patch_level" : uint,     ; YYYYMM, must match KeyMint OS_PATCHLEVEL
+    "boot_patch_level" : uint,       ; YYYYMMDD, must match KeyMint BOOT_PATCHLEVEL
+    "vendor_patch_level" : uint,     ; YYYYMMDD, must match KeyMint VENDOR_PATCHLEVEL
+    "version" : 2,                                 ; The CDDL schema version.
+    "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.
+}
\ No newline at end of file
diff --git a/security/rkp/aidl/android/hardware/security/keymint/DeviceInfoV3.cddl b/security/rkp/aidl/android/hardware/security/keymint/DeviceInfoV3.cddl
new file mode 100644
index 0000000..e841706
--- /dev/null
+++ b/security/rkp/aidl/android/hardware/security/keymint/DeviceInfoV3.cddl
@@ -0,0 +1,20 @@
+; Version 3, introduced in Android 14:
+DeviceInfo = {
+    "brand" : tstr,
+    "manufacturer" : tstr,
+    "product" : tstr,
+    "model" : tstr,
+    "device" : tstr,
+    "vb_state" : "green" / "yellow" / "orange",    ; Taken from the AVB values
+    "bootloader_state" : "locked" / "unlocked",    ; Taken from the AVB values
+    "vbmeta_digest": bstr,                         ; Taken from the AVB values
+    ? "os_version" : tstr,                         ; Same as
+                                                   ; android.os.Build.VERSION.release
+                                                   ; Not optional for TEE.
+    "system_patch_level" : uint,     ; YYYYMM, must match KeyMint OS_PATCHLEVEL
+    "boot_patch_level" : uint,       ; YYYYMMDD, must match KeyMint BOOT_PATCHLEVEL
+    "vendor_patch_level" : uint,     ; YYYYMMDD, must match KeyMint VENDOR_PATCHLEVEL
+    "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.
+}
diff --git a/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl b/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
index 7fed363..21c5315 100644
--- a/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
+++ b/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
@@ -185,77 +185,7 @@
      *
      *        In either case, the root is self-signed.
      *
-     *            EekChain = [ + SignedSignatureKey, SignedEek ]
-     *
-     *            SignedSignatureKey = [              ; COSE_Sign1
-     *                protected: bstr .cbor {
-     *                    1 : AlgorithmEdDSA / AlgorithmES256,  ; Algorithm
-     *                },
-     *                unprotected: {},
-     *                payload: bstr .cbor SignatureKeyEd25519 /
-     *                         bstr .cbor SignatureKeyP256,
-     *                signature: bstr PureEd25519(.cbor SignatureKeySignatureInput) /
-     *                           bstr ECDSA(.cbor SignatureKeySignatureInput)
-     *            ]
-     *
-     *            SignatureKeyEd25519 = {             ; COSE_Key
-     *                 1 : 1,                         ; Key type : Octet Key Pair
-     *                 3 : AlgorithmEdDSA,            ; Algorithm
-     *                 -1 : 6,                        ; Curve : Ed25519
-     *                 -2 : bstr                      ; Ed25519 public key
-     *            }
-     *
-     *            SignatureKeyP256 = {                ; COSE_Key
-     *                 1 : 2,                         ; Key type : EC2
-     *                 3 : AlgorithmES256,            ; Algorithm
-     *                 -1 : 1,                        ; Curve: P256
-     *                 -2 : bstr,                     ; X coordinate
-     *                 -3 : bstr                      ; Y coordinate
-     *            }
-     *
-     *            SignatureKeySignatureInput = [
-     *                context: "Signature1",
-     *                body_protected: bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 },
-     *                external_aad: bstr .size 0,
-     *                payload: bstr .cbor SignatureKeyEd25519 /
-     *                         bstr .cbor SignatureKeyP256
-     *            ]
-     *
-     *            ; COSE_Sign1
-     *            SignedEek = [
-     *                protected: bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 },
-     *                unprotected: {},
-     *                payload: bstr .cbor EekX25519 / .cbor EekP256,
-     *                signature: bstr PureEd25519(.cbor EekSignatureInput) /
-     *                           bstr ECDSA(.cbor EekSignatureInput)
-     *            ]
-     *
-     *            EekX25519 = {            ; COSE_Key
-     *                1 : 1,               ; Key type : Octet Key Pair
-     *                2 : bstr             ; KID : EEK ID
-     *                3 : -25,             ; Algorithm : ECDH-ES + HKDF-256
-     *                -1 : 4,              ; Curve : X25519
-     *                -2 : bstr            ; X25519 public key, little-endian
-     *            }
-     *
-     *            EekP256 = {              ; COSE_Key
-     *                1 : 2,               ; Key type : EC2
-     *                2 : bstr             ; KID : EEK ID
-     *                3 : -25,             ; Algorithm : ECDH-ES + HKDF-256
-     *                -1 : 1,              ; Curve : P256
-     *                -2 : bstr            ; Sender X coordinate
-     *                -3 : bstr            ; Sender Y coordinate
-     *            }
-     *
-     *            EekSignatureInput = [
-     *                context: "Signature1",
-     *                body_protected: bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 },
-     *                external_aad: bstr .size 0,
-     *                payload: bstr .cbor EekX25519 / .cbor EekP256
-     *            ]
-     *
-     *            AlgorithmES256 = -7      ; RFC 8152 section 8.1
-     *            AlgorithmEdDSA = -8      ; RFC 8152 section 8.2
+     *        See generateCertificateRequest.cddl for CDDL definitions.
      *
      *        If the contents of endpointEncryptionKey do not match the SignedEek structure above,
      *        the method must return STATUS_INVALID_EEK.
@@ -283,25 +213,9 @@
      *            HMAC-256(EK_mac, .cbor KeysToMacStructure)
      *
      *        Where EK_mac is an ephemeral MAC key, found in ProtectedData (see below).  The MACed
-     *        data is the "tag" field of a COSE_Mac0 structure like:
+     *        data is the "tag" field of a MacedKeys COSE_Mac0 structure.
      *
-     *            MacedKeys = [                            ; COSE_Mac0
-     *                protected : bstr .cbor {
-     *                    1 : 5,                           ; Algorithm : HMAC-256
-     *                },
-     *                unprotected : {},
-     *                ; Payload is PublicKeys from keysToSign argument, in provided order.
-     *                payload: bstr .cbor [ * PublicKey ],
-     *                tag: bstr
-     *            ]
-     *
-     *            KeysToMacStructure = [
-     *                context : "MAC0",
-     *                protected : bstr .cbor { 1 : 5 },    ; Algorithm : HMAC-256
-     *                external_aad : bstr .size 0,
-     *                ; Payload is PublicKeys from keysToSign argument, in provided order.
-     *                payload : bstr .cbor [ * PublicKey ]
-     *            ]
+     *        See generateCertificateRequest.cddl for CDDL definitions.
      */
     byte[] generateCertificateRequest(in boolean testMode, in MacedPublicKey[] keysToSign,
             in byte[] endpointEncryptionCertChain, in byte[] challenge, out DeviceInfo deviceInfo,
@@ -322,168 +236,9 @@
      *        use different semantic data for this field, but the supported sizes must be between 0
      *        and 64 bytes, inclusive.
      *
-     * @return the following CBOR Certificate Signing Request (Csr) serialized into a byte array:
+     * @return a CBOR Certificate Signing Request (Csr) serialized into a byte array.
      *
-     * Csr = AuthenticatedRequest<CsrPayload>
-     *
-     * CsrPayload = [                      ; CBOR Array defining the payload for Csr
-     *     version: 3,                     ; The CsrPayload CDDL Schema version.
-     *     CertificateType,                ; The type of certificate being requested.
-     *     DeviceInfo,                     ; Defined in DeviceInfo.aidl
-     *     KeysToSign,                     ; Provided by the method parameters
-     * ]
-     *
-     *  ; A tstr identifying the type of certificate. The set of supported certificate types may
-     *  ; be extended without requiring a version bump of the HAL. Custom certificate types may
-     *  ; be used, but the provisioning server may reject the request for an unknown certificate
-     *  ; type. The currently defined certificate types are:
-     *  ;  - "widevine"
-     *  ;  - "keymint"
-     *  CertificateType = tstr
-     *
-     * KeysToSign = [ * PublicKey ]   ; Please see MacedPublicKey.aidl for the PublicKey definition.
-     *
-     * AuthenticatedRequest<T> = [
-     *     version: 1,              ; The AuthenticatedRequest CDDL Schema version.
-     *     UdsCerts,
-     *     DiceCertChain,
-     *     SignedData<[
-     *         challenge: bstr .size (0..64), ; Provided by the method parameters
-     *         bstr .cbor T,
-     *     ]>,
-     * ]
-     *
-     * ; COSE_Sign1 (untagged)
-     * SignedData<Data> = [
-     *     protected: bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 / AlgorithmES384 },
-     *     unprotected: {},
-     *     payload: bstr .cbor Data / nil,
-     *     signature: bstr      ; PureEd25519(CDI_Leaf_Priv, SignedDataSigStruct<Data>) /
-     *                          ; ECDSA(CDI_Leaf_Priv, SignedDataSigStruct<Data>)
-     * ]
-     *
-     * ; Sig_structure for SignedData
-     * SignedDataSigStruct<Data> = [
-     *     context: "Signature1",
-     *     protected: bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 / AlgorithmES384 },
-     *     external_aad: bstr .size 0,
-     *     payload: bstr .cbor Data / nil,
-     * ]
-     *
-     * ; UdsCerts allows the platform to provide additional certifications for the UDS_Pub. For
-     * ; example, this could be provided by the hardware vendor, who certifies all of their chips.
-     * ; The SignerName is a free-form string describing who generated the signature. The root
-     * ; certificate will need to be communicated to the verifier out of band, along with the
-     * ; SignerName that is expected for the given root certificate.
-     * UdsCerts = {
-     *     * SignerName => UdsCertChain
-     * }
-     *
-     * ; SignerName is a string identifier that indicates both the signing authority as
-     * ; well as the format of the UdsCertChain
-     * SignerName = tstr
-     *
-     * UdsCertChain = [
-     *     2* X509Certificate       ; Root -> ... -> Leaf. "Root" is the vendor self-signed
-     *                              ; cert, "Leaf" contains UDS_Public. There may also be
-     *                              ; intermediate certificates between Root and Leaf.
-     * ]
-     *
-     * ; A bstr containing a DER-encoded X.509 certificate (RSA, NIST P-curve, or EdDSA)
-     * X509Certificate = bstr
-     *
-     * ; The DICE Chain contains measurements about the device firmware.
-     * ; The first entry in the DICE Chain is the UDS_Pub, encoded as a COSE_key. All entries
-     * ; after the first describe a link in the boot chain (e.g. bootloaders: BL1, BL2, ... BLN)
-     * ; Note that there is no DiceChainEntry for UDS_pub, only a "bare" COSE_key.
-     * DiceCertChain = [
-     *     PubKeyEd25519 / PubKeyECDSA256 / PubKeyECDSA384,  ; UDS_Pub
-     *     + DiceChainEntry,                ; First CDI_Certificate -> Last CDI_Certificate
-     *                                      ; Last certificate corresponds to KeyMint's DICE key.
-     * ]
-     *
-     * ; This is the signed payload for each entry in the DICE chain. Note that the "Configuration
-     * ; Input Values" described by the Open Profile are not used here. Instead, the DICE chain
-     * ; defines its own configuration values for the Configuration Descriptor field. See
-     * ; the Open Profile for DICE for more details on the fields. SHA256, SHA384 and SHA512 are
-     * ; acceptable hash algorithms. The digest bstr values in the payload are the digest values
-     * ; without any padding. Note that this implies that the digest is a 32-byte bstr for SHA256
-     * ; and a 48-byte bstr for SHA384. This is an intentional, minor deviation from Open Profile
-     * ; for DICE, which specifies all digests are 64 bytes.
-     * DiceChainEntryPayload = {                    ; CWT [RFC8392]
-     *     1 : tstr,                                ; Issuer
-     *     2 : tstr,                                ; Subject
-     *     -4670552 : bstr .cbor PubKeyEd25519 /
-     *                bstr .cbor PubKeyECDSA256,
-     *                bstr .cbor PubKeyECDSA384,    ; Subject Public Key
-     *     -4670553 : bstr                          ; Key Usage
-     *
-     *     ; NOTE: All of the following fields may be omitted for a "Degenerate DICE Chain", as
-     *     ;       described above.
-     *     -4670545 : bstr,                         ; Code Hash
-     *     ? -4670546 : bstr,                       ; Code Descriptor
-     *     ? -4670547 : bstr,                       ; Configuration Hash
-     *     -4670548 : bstr .cbor {                  ; Configuration Descriptor
-     *         ? -70002 : tstr,                         ; Component name
-     *         ? -70003 : int / tstr,                   ; Component version
-     *         ? -70004 : null,                         ; Resettable
-     *         ? -70005 : uint,                         ; Security version
-     *     },
-     *     -4670549 : bstr,                         ; Authority Hash
-     *     ? -4670550 : bstr,                       ; Authority Descriptor
-     *     -4670551 : bstr,                         ; Mode
-     * }
-     *
-     * ; Each entry in the DICE chain is a DiceChainEntryPayload signed by the key from the previous
-     * ; entry in the DICE chain array.
-     * DiceChainEntry = [                            ; COSE_Sign1 (untagged)
-     *     protected : bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 / AlgorithmES384 },
-     *     unprotected: {},
-     *     payload: bstr .cbor DiceChainEntryPayload,
-     *     signature: bstr ; PureEd25519(SigningKey, DiceChainEntryInput) /
-     *                     ; ECDSA(SigningKey, DiceChainEntryInput)
-     *                     ; See RFC 8032 for details of how to encode the signature value
-     *                     ; for Ed25519.
-     * ]
-     *
-     * DiceChainEntryInput = [
-     *     context: "Signature1",
-     *     protected: bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 / AlgorithmES384 },
-     *     external_aad: bstr .size 0,
-     *     payload: bstr .cbor DiceChainEntryPayload
-     * ]
-     *
-     * ; The following section defines some types that are reused throughout the above
-     * ; data structures.
-     * ; NOTE: Integer encoding is different for Ed25519 and P256 keys:
-     * ;       - Ed25519 is LE: https://www.rfc-editor.org/rfc/rfc8032#section-3.1
-     * ;       - P256 is BE: https://www.secg.org/sec1-v2.pdf#page=19 (section 2.3.7)
-     * PubKeyEd25519 = {                ; COSE_Key
-     *     1 : 1,                       ; Key type : octet key pair
-     *     3 : AlgorithmEdDSA,          ; Algorithm : EdDSA
-     *     -1 : 6,                      ; Curve : Ed25519
-     *     -2 : bstr                    ; X coordinate, little-endian
-     * }
-     *
-     * PubKeyECDSA256 = {               ; COSE_Key
-     *     1 : 2,                       ; Key type : EC2
-     *     3 : AlgorithmES256,          ; Algorithm : ECDSA w/ SHA-256
-     *     -1 : 1,                      ; Curve: P256
-     *     -2 : bstr,                   ; X coordinate, big-endian
-     *     -3 : bstr                    ; Y coordinate, big-endian
-     * }
-     *
-     * PubKeyECDSA384 = {               ; COSE_Key
-     *     1 : 2,                       ; Key type : EC2
-     *     3 : AlgorithmES384,          ; Algorithm : ECDSA w/ SHA-384
-     *     -1 : 2,                      ; Curve: P384
-     *     -2 : bstr,                   ; X coordinate
-     *     -3 : bstr                    ; Y coordinate
-     * }
-     *
-     * AlgorithmES256 = -7
-     * AlgorithmES384 = -35
-     * AlgorithmEdDSA = -8
+     *         See generateCertificateRequestV2.cddl for CDDL definitions.
      */
     byte[] generateCertificateRequestV2(in MacedPublicKey[] keysToSign, in byte[] challenge);
 }
diff --git a/security/rkp/aidl/android/hardware/security/keymint/MacedPublicKey.aidl b/security/rkp/aidl/android/hardware/security/keymint/MacedPublicKey.aidl
index 1e41d1b..a290817 100644
--- a/security/rkp/aidl/android/hardware/security/keymint/MacedPublicKey.aidl
+++ b/security/rkp/aidl/android/hardware/security/keymint/MacedPublicKey.aidl
@@ -28,33 +28,8 @@
      * only to the secure environment, as proof that the public key was generated by that
      * environment. In CDDL, assuming the contained key is a P-256 public key:
      *
-     *     MacedPublicKey = [                     ; COSE_Mac0
-     *         protected: bstr .cbor { 1 : 5},    ; Algorithm : HMAC-256
-     *         unprotected: { },
-     *         payload : bstr .cbor PublicKey,
-     *         tag : bstr HMAC-256(K_mac, MAC_structure)
-     *     ]
+     * See MacedPublicKey.cddl for CDDL definition.
      *
-     *     ; NOTE: -70000 is deprecated for v3 HAL implementations.
-     *     ; NOTE: Integer encoding is different for Ed25519 and P256 keys:
-     *     ;       - Ed25519 is LE: https://www.rfc-editor.org/rfc/rfc8032#section-3.1
-     *     ;       - P256 is BE: https://www.secg.org/sec1-v2.pdf#page=19 (section 2.3.7)
-     *     PublicKey = {               ; COSE_Key
-     *         1 : 2,                  ; Key type : EC2
-     *         3 : -7,                 ; Algorithm : ES256
-     *         -1 : 1,                 ; Curve : P256
-     *         -2 : bstr,              ; X coordinate, big-endian
-     *         -3 : bstr,              ; Y coordinate, big-endian
-     *         -70000 : nil            ; Presence indicates this is a test key. If set, K_mac is
-     *                                 ; all zeros.
-     *     },
-     *
-     *     MAC_structure = [
-     *         context : "MAC0",
-     *         protected : bstr .cbor { 1 : 5 },
-     *         external_aad : bstr .size 0,
-     *         payload : bstr .cbor PublicKey
-     *     ]
      */
     byte[] macedKey;
 }
diff --git a/security/rkp/aidl/android/hardware/security/keymint/MacedPublicKey.cddl b/security/rkp/aidl/android/hardware/security/keymint/MacedPublicKey.cddl
new file mode 100644
index 0000000..6ae4be4
--- /dev/null
+++ b/security/rkp/aidl/android/hardware/security/keymint/MacedPublicKey.cddl
@@ -0,0 +1,15 @@
+MacedPublicKey = [                     ; COSE_Mac0 [RFC9052 s6.2]
+    protected: bstr .cbor { 1 : 5},    ; Algorithm : HMAC-256
+    unprotected: { },
+    payload : bstr .cbor PublicKey,
+    tag : bstr ; HMAC-256(K_mac, MAC_structure)
+]
+
+MAC_structure = [                      ; [RFC9052 s6.3]
+    context : "MAC0",
+    protected : bstr .cbor { 1 : 5 },
+    external_aad : bstr .size 0,
+    payload : bstr .cbor PublicKey
+]
+
+; INCLUDE PublicKey.cddl for: PublicKey
diff --git a/security/rkp/aidl/android/hardware/security/keymint/PublicKey.cddl b/security/rkp/aidl/android/hardware/security/keymint/PublicKey.cddl
new file mode 100644
index 0000000..4c1050d
--- /dev/null
+++ b/security/rkp/aidl/android/hardware/security/keymint/PublicKey.cddl
@@ -0,0 +1,13 @@
+; NOTE: -70000 is deprecated for v3 HAL implementations.
+; NOTE: Integer encoding is different for Ed25519 and P256 keys:
+;       - Ed25519 is LE: https://www.rfc-editor.org/rfc/rfc8032#section-3.1
+;       - P256 is BE: https://www.secg.org/sec1-v2.pdf#page=19 (section 2.3.7)
+PublicKey = {               ; COSE_Key [RFC9052 s7]
+    1 : 2,                  ; Key type : EC2
+    3 : -7,                 ; Algorithm : ES256
+    -1 : 1,                 ; Curve : P256
+    -2 : bstr,              ; X coordinate, big-endian
+    -3 : bstr,              ; Y coordinate, big-endian
+    ? -70000 : nil          ; Presence indicates this is a test key. If set, K_mac is
+                            ; all zeros.
+}
diff --git a/security/rkp/aidl/android/hardware/security/keymint/generateCertificateRequest.cddl b/security/rkp/aidl/android/hardware/security/keymint/generateCertificateRequest.cddl
new file mode 100644
index 0000000..fb11492
--- /dev/null
+++ b/security/rkp/aidl/android/hardware/security/keymint/generateCertificateRequest.cddl
@@ -0,0 +1,93 @@
+; CDDL for the deprecated version 1 generateCertificateRequest method
+; in IRemotelyProvisionedComponent.aidl
+
+EekChain = [ + SignedSignatureKey, SignedEek ]
+
+SignedSignatureKey = [              ; COSE_Sign1 [RFC9052 s4.2]
+    protected: bstr .cbor {
+        1 : AlgorithmEdDSA / AlgorithmES256,  ; Algorithm
+    },
+    unprotected: {},
+    payload: bstr .cbor SignatureKeyEd25519 /
+                bstr .cbor SignatureKeyP256,
+    signature: bstr ; PureEd25519(.cbor SignatureKeySignatureInput) /
+                    ; ECDSA(.cbor SignatureKeySignatureInput)
+]
+
+SignatureKeyEd25519 = {             ; COSE_Key [RFC9052 s7]
+        1 : 1,                         ; Key type : Octet Key Pair
+        3 : AlgorithmEdDSA,            ; Algorithm
+        -1 : 6,                        ; Curve : Ed25519
+        -2 : bstr                      ; Ed25519 public key
+}
+
+SignatureKeyP256 = {                ; COSE_Key [RC9052 s7]
+        1 : 2,                         ; Key type : EC2
+        3 : AlgorithmES256,            ; Algorithm
+        -1 : 1,                        ; Curve: P256
+        -2 : bstr,                     ; X coordinate
+        -3 : bstr                      ; Y coordinate
+}
+
+SignatureKeySignatureInput = [
+    context: "Signature1",
+    body_protected: bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 },
+    external_aad: bstr .size 0,
+    payload: bstr .cbor SignatureKeyEd25519 /
+                bstr .cbor SignatureKeyP256
+]
+
+SignedEek = [                       ; COSE_Sign1 [RFC9052 s4.2]
+    protected: bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 },
+    unprotected: {},
+    payload: bstr .cbor EekX25519 / EekP256,
+    signature: bstr ; PureEd25519(.cbor EekSignatureInput) /
+                    ; ECDSA(.cbor EekSignatureInput)
+]
+
+EekX25519 = {            ; COSE_Key [RFC9052 s7]
+    1 : 1,               ; Key type : Octet Key Pair
+    2 : bstr             ; KID : EEK ID
+    3 : -25,             ; Algorithm : ECDH-ES + HKDF-256
+    -1 : 4,              ; Curve : X25519
+    -2 : bstr            ; X25519 public key, little-endian
+}
+
+EekP256 = {              ; COSE_Key [RFC9052 s7]
+    1 : 2,               ; Key type : EC2
+    2 : bstr             ; KID : EEK ID
+    3 : -25,             ; Algorithm : ECDH-ES + HKDF-256
+    -1 : 1,              ; Curve : P256
+    -2 : bstr            ; Sender X coordinate
+    -3 : bstr            ; Sender Y coordinate
+}
+
+EekSignatureInput = [
+    context: "Signature1",
+    body_protected: bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 },
+    external_aad: bstr .size 0,
+    payload: bstr .cbor EekX25519 / EekP256
+]
+
+AlgorithmES256 = -7      ; [RFC8152 s8.1]
+AlgorithmEdDSA = -8      ; [RFC8152 s8.2]
+
+MacedKeys = [                            ; COSE_Mac0 [RFC9052 s6.2]
+    protected : bstr .cbor {
+        1 : 5,                           ; Algorithm : HMAC-256
+    },
+    unprotected : {},
+    ; Payload is PublicKeys from keysToSign argument, in provided order.
+    payload: bstr .cbor [ * PublicKey ],
+    tag: bstr
+]
+
+KeysToMacStructure = [                   ; [RFC9052 s6.3]
+    context : "MAC0",
+    protected : bstr .cbor { 1 : 5 },    ; Algorithm : HMAC-256
+    external_aad : bstr .size 0,
+    ; Payload is PublicKeys from keysToSign argument, in provided order.
+    payload : bstr .cbor [ * PublicKey ]
+]
+
+; INCLUDE PublicKey.cddl for: PublicKey
diff --git a/security/rkp/aidl/android/hardware/security/keymint/generateCertificateRequestV2.cddl b/security/rkp/aidl/android/hardware/security/keymint/generateCertificateRequestV2.cddl
new file mode 100644
index 0000000..3c43238
--- /dev/null
+++ b/security/rkp/aidl/android/hardware/security/keymint/generateCertificateRequestV2.cddl
@@ -0,0 +1,171 @@
+; CDDL for the generateCertificateRequestV2 method in
+; IRemotelyProvisionedComponent.aidl
+
+Csr = AuthenticatedRequest<CsrPayload>
+
+CsrPayload = [                      ; CBOR Array defining the payload for Csr
+    version: 3,                     ; The CsrPayload CDDL Schema version.
+    CertificateType,                ; The type of certificate being requested.
+    DeviceInfo,                     ; Defined in the relevant DeviceInfoV*.cddl file.
+    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" -- Widevine content protection system
+;  * "keymint"  -- KeyMint HAL
+;  * "rkp-vm"   -- See "Support for Android Virtualization Framework" in the README.md file.
+CertificateType = tstr
+
+KeysToSign = [ * PublicKey ]   ; Please see PublicKey.cddl for the PublicKey definition.
+
+AuthenticatedRequest<T> = [
+    version: 1,              ; The AuthenticatedRequest CDDL Schema version.
+    UdsCerts,
+    DiceCertChain,
+    SignedData<[
+        challenge: bstr .size (0..64), ; Provided by the method parameters
+        bstr .cbor T,
+    ]>,
+]
+
+; COSE_Sign1 (untagged) [RFC9052 s4.2]
+SignedData<Data> = [
+    protected: bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 / AlgorithmES384 },
+    unprotected: {},
+    payload: bstr .cbor Data / nil,
+    signature: bstr     ; PureEd25519(CDI_Leaf_Priv, SignedDataSigStruct<Data>) /
+                        ; ECDSA(CDI_Leaf_Priv, SignedDataSigStruct<Data>)
+]
+
+; Sig_structure for SignedData [ RFC9052 s4.4]
+SignedDataSigStruct<Data> = [
+    context: "Signature1",
+    protected: bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 / AlgorithmES384 },
+    external_aad: bstr .size 0,
+    payload: bstr .cbor Data / nil,
+]
+
+; UdsCerts allows the platform to provide additional certifications for the UDS_Pub. For
+; example, this could be provided by the hardware vendor, who certifies all of their chips.
+; The SignerName is a free-form string describing who generated the signature. The root
+; certificate will need to be communicated to the verifier out of band, along with the
+; SignerName that is expected for the given root certificate.
+UdsCerts = {
+    * SignerName => UdsCertChain
+}
+
+; SignerName is a string identifier that indicates both the signing authority as
+; well as the format of the UdsCertChain
+SignerName = tstr
+
+UdsCertChain = [
+    2* X509Certificate      ; Root -> ... -> Leaf. "Root" is the vendor self-signed
+                            ; cert, "Leaf" contains UDS_Public. There may also be
+                            ; intermediate certificates between Root and Leaf.
+]
+
+; A bstr containing a DER-encoded X.509 certificate (RSA, NIST P-curve, or EdDSA)
+X509Certificate = bstr
+
+; The DICE Chain contains measurements about the device firmware.
+; The first entry in the DICE Chain is the UDS_Pub, encoded as a COSE_key. All entries
+; after the first describe a link in the boot chain (e.g. bootloaders: BL1, BL2, ... BLN)
+; Note that there is no DiceChainEntry for UDS_pub, only a "bare" COSE_key.
+DiceCertChain = [
+    PubKeyEd25519 / PubKeyECDSA256 / PubKeyECDSA384,  ; UDS_Pub
+    + DiceChainEntry,               ; First CDI_Certificate -> Last CDI_Certificate
+                                    ; Last certificate corresponds to KeyMint's DICE key.
+]
+
+; This is the signed payload for each entry in the DICE chain. Note that the "Configuration
+; Input Values" described by the Open Profile are not used here. Instead, the DICE chain
+; defines its own configuration values for the Configuration Descriptor field. See
+; the Open Profile for DICE for more details on the fields. SHA256, SHA384 and SHA512 are
+; acceptable hash algorithms. The digest bstr values in the payload are the digest values
+; without any padding. Note that this implies that the digest is a 32-byte bstr for SHA256
+; and a 48-byte bstr for SHA384. This is an intentional, minor deviation from Open Profile
+; for DICE, which specifies all digests are 64 bytes.
+DiceChainEntryPayload = {                    ; CWT [RFC8392]
+    1 : tstr,                                ; Issuer
+    2 : tstr,                                ; Subject
+    -4670554 : "android.15",                 ; Profile Name
+    -4670552 : bstr .cbor PubKeyEd25519 /
+            bstr .cbor PubKeyECDSA256 /
+            bstr .cbor PubKeyECDSA384,       ; Subject Public Key
+    -4670553 : bstr                          ; Key Usage
+
+    ; NOTE: All of the following fields may be omitted for a "Degenerate DICE Chain", as
+    ;       described above.
+    -4670545 : bstr,                         ; Code Hash
+    ? -4670546 : bstr,                       ; Code Descriptor
+    -4670547 : bstr,                         ; Configuration Hash
+    -4670548 : bstr .cbor ConfigurationDescriptor,
+    -4670549 : bstr,                         ; Authority Hash
+    ? -4670550 : bstr,                       ; Authority Descriptor
+    -4670551 : bstr,                         ; Mode
+}
+
+ConfigurationDescriptor = {                  ; Configuration Descriptor
+    ? -70002 : tstr,                         ; Component name
+    ? -70003 : int / tstr,                   ; Component version
+    ? -70004 : null,                         ; Resettable
+    ? -70005 : uint,                         ; Security version
+    ? -70006 : null,                         ; RKP VM marker
+}
+
+; 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), [RFC9052 s4.2]
+    protected : bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 / AlgorithmES384 },
+    unprotected: {},
+    payload: bstr .cbor DiceChainEntryPayload,
+    signature: bstr ; PureEd25519(SigningKey, DiceChainEntryInput) /
+                    ; ECDSA(SigningKey, DiceChainEntryInput)
+                    ; See RFC 8032 for details of how to encode the signature value
+                    ; for Ed25519.
+]
+
+DiceChainEntryInput = [
+    context: "Signature1",
+    protected: bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 / AlgorithmES384 },
+    external_aad: bstr .size 0,
+    payload: bstr .cbor DiceChainEntryPayload
+]
+
+; The following section defines some types that are reused throughout the above
+; data structures.
+; NOTE: Integer encoding is different for Ed25519 and P256 keys:
+;       - Ed25519 is LE: https://www.rfc-editor.org/rfc/rfc8032#section-3.1
+;       - P256 is BE: https://www.secg.org/sec1-v2.pdf#page=19 (section 2.3.7)
+PubKeyEd25519 = {                ; COSE_Key [RFC9052 s7]
+    1 : 1,                       ; Key type : octet key pair
+    3 : AlgorithmEdDSA,          ; Algorithm : EdDSA
+    -1 : 6,                      ; Curve : Ed25519
+    -2 : bstr                    ; X coordinate, little-endian
+}
+
+PubKeyECDSA256 = {               ; COSE_Key [RFC9052 s7]
+    1 : 2,                       ; Key type : EC2
+    3 : AlgorithmES256,          ; Algorithm : ECDSA w/ SHA-256
+    -1 : 1,                      ; Curve: P256
+    -2 : bstr,                   ; X coordinate, big-endian
+    -3 : bstr                    ; Y coordinate, big-endian
+}
+
+PubKeyECDSA384 = {               ; COSE_Key [RFC9052 s7]
+    1 : 2,                       ; Key type : EC2
+    3 : AlgorithmES384,          ; Algorithm : ECDSA w/ SHA-384
+    -1 : 2,                      ; Curve: P384
+    -2 : bstr,                   ; X coordinate, big-endian
+    -3 : bstr                    ; Y coordinate, big-endian
+}
+
+AlgorithmES256 = -7              ; [RFC9053 s2.1]
+AlgorithmES384 = -35             ; [RFC9053 s2.1]
+AlgorithmEdDSA = -8              ; [RFC9053 s2.2]
+
+; INCLUDE PublicKey.cddl for: PublicKey
+; INCLUDE DeviceInfoV3.cddl for: DeviceInfo
diff --git a/security/rkp/aidl/lint-baseline.xml b/security/rkp/aidl/lint-baseline.xml
index d25d383..8e98094 100644
--- a/security/rkp/aidl/lint-baseline.xml
+++ b/security/rkp/aidl/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.0.0-dev" type="baseline" dependencies="true" variant="all" version="8.0.0-dev">
+<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01">
 
     <issue
         id="NewApi"
@@ -7,8 +7,8 @@
         errorLine1="      this.markVintfStability();"
         errorLine2="           ~~~~~~~~~~~~~~~~~~">
         <location
-            file="out/.intermediates/hardware/interfaces/security/rkp/aidl/android.hardware.security.rkp-V1-java-source/gen/android/hardware/security/keymint/IRemotelyProvisionedComponent.java"
-            line="50"
+            file="out/soong/.intermediates/hardware/interfaces/security/rkp/aidl/android.hardware.security.rkp-V1-java-source/gen/android/hardware/security/keymint/IRemotelyProvisionedComponent.java"
+            line="52"
             column="12"/>
     </issue>
 
@@ -18,8 +18,8 @@
         errorLine1="      this.markVintfStability();"
         errorLine2="           ~~~~~~~~~~~~~~~~~~">
         <location
-            file="out/.intermediates/hardware/interfaces/security/rkp/aidl/android.hardware.security.rkp-V2-java-source/gen/android/hardware/security/keymint/IRemotelyProvisionedComponent.java"
-            line="50"
+            file="out/soong/.intermediates/hardware/interfaces/security/rkp/aidl/android.hardware.security.rkp-V2-java-source/gen/android/hardware/security/keymint/IRemotelyProvisionedComponent.java"
+            line="52"
             column="12"/>
     </issue>
 
@@ -29,8 +29,19 @@
         errorLine1="      this.markVintfStability();"
         errorLine2="           ~~~~~~~~~~~~~~~~~~">
         <location
-            file="out/.intermediates/hardware/interfaces/security/rkp/aidl/android.hardware.security.rkp-V3-java-source/gen/android/hardware/security/keymint/IRemotelyProvisionedComponent.java"
-            line="495"
+            file="out/soong/.intermediates/hardware/interfaces/security/rkp/aidl/android.hardware.security.rkp-V3-java-source/gen/android/hardware/security/keymint/IRemotelyProvisionedComponent.java"
+            line="56"
+            column="12"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 34 (current min is 33): `android.os.Binder#markVintfStability`"
+        errorLine1="      this.markVintfStability();"
+        errorLine2="           ~~~~~~~~~~~~~~~~~~">
+        <location
+            file="out/soong/.intermediates/hardware/interfaces/security/rkp/aidl/android.hardware.security.rkp-V4-java-source/gen/android/hardware/security/keymint/IRemotelyProvisionedComponent.java"
+            line="257"
             column="12"/>
     </issue>
 
diff --git a/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
index 62463eb..68b966c 100644
--- a/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
+++ b/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
@@ -55,6 +55,8 @@
 
 constexpr uint8_t MIN_CHALLENGE_SIZE = 0;
 constexpr uint8_t MAX_CHALLENGE_SIZE = 64;
+const string RKP_VM_INSTANCE_NAME =
+        "android.hardware.security.keymint.IRemotelyProvisionedComponent/avf";
 
 #define INSTANTIATE_REM_PROV_AIDL_TEST(name)                                         \
     GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(name);                             \
@@ -181,7 +183,12 @@
             provisionable_ = IRemotelyProvisionedComponent::fromBinder(binder);
         }
         ASSERT_NE(provisionable_, nullptr);
-        ASSERT_TRUE(provisionable_->getHardwareInfo(&rpcHardwareInfo).isOk());
+        auto status = provisionable_->getHardwareInfo(&rpcHardwareInfo);
+        if (GetParam() == RKP_VM_INSTANCE_NAME &&
+            status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+            GTEST_SKIP() << "The RKP VM is not supported on this system.";
+        }
+        ASSERT_TRUE(status.isOk());
     }
 
     static vector<string> build_params() {
@@ -207,7 +214,11 @@
         ASSERT_NE(rpc, nullptr);
 
         RpcHardwareInfo hwInfo;
-        ASSERT_TRUE(rpc->getHardwareInfo(&hwInfo).isOk());
+        auto status = rpc->getHardwareInfo(&hwInfo);
+        if (hal == RKP_VM_INSTANCE_NAME && status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+            GTEST_SKIP() << "The RKP VM is not supported on this system.";
+        }
+        ASSERT_TRUE(status.isOk());
 
         if (hwInfo.versionNumber >= VERSION_WITH_UNIQUE_ID_SUPPORT) {
             ASSERT_TRUE(hwInfo.uniqueId);
@@ -391,7 +402,7 @@
         for (auto& key : keysToSign_) {
             bytevec privateKeyBlob;
             auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &key, &privateKeyBlob);
-            ASSERT_TRUE(status.isOk()) << status.getMessage();
+            ASSERT_TRUE(status.isOk()) << status.getDescription();
 
             vector<uint8_t> payload_value;
             check_maced_pubkey(key, testMode, &payload_value);
@@ -436,7 +447,7 @@
         auto status = provisionable_->generateCertificateRequest(
                 testMode, {} /* keysToSign */, testEekChain_.chain, challenge_, &deviceInfo,
                 &protectedData, &keysToSignMac);
-        ASSERT_TRUE(status.isOk()) << status.getMessage();
+        ASSERT_TRUE(status.isOk()) << status.getDescription();
 
         auto result = verifyProductionProtectedData(
                 deviceInfo, cppbor::Array(), keysToSignMac, protectedData, testEekChain_, eekId_,
@@ -461,7 +472,7 @@
     auto status = provisionable_->generateCertificateRequest(
             testMode, {} /* keysToSign */, testEekChain_.chain, challenge_, &deviceInfo,
             &protectedData, &keysToSignMac);
-    ASSERT_TRUE(status.isOk()) << status.getMessage();
+    ASSERT_TRUE(status.isOk()) << status.getDescription();
 
     auto firstBcc = verifyProductionProtectedData(
             deviceInfo, /*keysToSign=*/cppbor::Array(), keysToSignMac, protectedData, testEekChain_,
@@ -471,7 +482,7 @@
     status = provisionable_->generateCertificateRequest(
             testMode, {} /* keysToSign */, testEekChain_.chain, challenge_, &deviceInfo,
             &protectedData, &keysToSignMac);
-    ASSERT_TRUE(status.isOk()) << status.getMessage();
+    ASSERT_TRUE(status.isOk()) << status.getDescription();
 
     auto secondBcc = verifyProductionProtectedData(
             deviceInfo, /*keysToSign=*/cppbor::Array(), keysToSignMac, protectedData, testEekChain_,
@@ -521,7 +532,7 @@
         auto status = provisionable_->generateCertificateRequest(
                 testMode, keysToSign_, testEekChain_.chain, challenge_, &deviceInfo, &protectedData,
                 &keysToSignMac);
-        ASSERT_TRUE(status.isOk()) << status.getMessage();
+        ASSERT_TRUE(status.isOk()) << status.getDescription();
 
         auto result = verifyProductionProtectedData(
                 deviceInfo, cborKeysToSign_, keysToSignMac, protectedData, testEekChain_, eekId_,
@@ -565,7 +576,7 @@
     auto status = provisionable_->generateCertificateRequest(
             testMode, {keyWithCorruptMac}, testEekChain_.chain, challenge_, &deviceInfo,
             &protectedData, &keysToSignMac);
-    ASSERT_FALSE(status.isOk()) << status.getMessage();
+    ASSERT_FALSE(status.isOk()) << status.getDescription();
     EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
 }
 
@@ -585,7 +596,7 @@
     auto status = provisionable_->generateCertificateRequest(
             testMode, {keyWithCorruptMac}, getProdEekChain(rpcHardwareInfo.supportedEekCurve),
             challenge_, &deviceInfo, &protectedData, &keysToSignMac);
-    ASSERT_FALSE(status.isOk()) << status.getMessage();
+    ASSERT_FALSE(status.isOk()) << status.getDescription();
     EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
 }
 
@@ -711,7 +722,7 @@
         auto challenge = randomBytes(size);
         auto status =
                 provisionable_->generateCertificateRequestV2({} /* keysToSign */, challenge, &csr);
-        ASSERT_TRUE(status.isOk()) << status.getMessage();
+        ASSERT_TRUE(status.isOk()) << status.getDescription();
 
         auto result = verifyProductionCsr(cppbor::Array(), csr, provisionable_.get(), challenge);
         ASSERT_TRUE(result) << result.message();
@@ -732,7 +743,7 @@
         SCOPED_TRACE(testing::Message() << "challenge[" << size << "]");
         auto challenge = randomBytes(size);
         auto status = provisionable_->generateCertificateRequestV2(keysToSign_, challenge, &csr);
-        ASSERT_TRUE(status.isOk()) << status.getMessage();
+        ASSERT_TRUE(status.isOk()) << status.getDescription();
 
         auto result = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge);
         ASSERT_TRUE(result) << result.message();
@@ -747,7 +758,7 @@
 
     auto status = provisionable_->generateCertificateRequestV2(
             /* keysToSign */ {}, randomBytes(MAX_CHALLENGE_SIZE + 1), &csr);
-    EXPECT_FALSE(status.isOk()) << status.getMessage();
+    EXPECT_FALSE(status.isOk()) << status.getDescription();
     EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_FAILED);
 }
 
@@ -762,13 +773,13 @@
     bytevec csr;
 
     auto status = provisionable_->generateCertificateRequestV2(keysToSign_, challenge_, &csr);
-    ASSERT_TRUE(status.isOk()) << status.getMessage();
+    ASSERT_TRUE(status.isOk()) << status.getDescription();
 
     auto firstCsr = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge_);
     ASSERT_TRUE(firstCsr) << firstCsr.message();
 
     status = provisionable_->generateCertificateRequestV2(keysToSign_, challenge_, &csr);
-    ASSERT_TRUE(status.isOk()) << status.getMessage();
+    ASSERT_TRUE(status.isOk()) << status.getDescription();
 
     auto secondCsr = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge_);
     ASSERT_TRUE(secondCsr) << secondCsr.message();
@@ -786,7 +797,7 @@
     bytevec csr;
 
     auto status = provisionable_->generateCertificateRequestV2(keysToSign_, challenge_, &csr);
-    ASSERT_TRUE(status.isOk()) << status.getMessage();
+    ASSERT_TRUE(status.isOk()) << status.getDescription();
 
     auto result = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge_);
     ASSERT_TRUE(result) << result.message();
@@ -804,7 +815,7 @@
     bytevec csr;
     auto status =
             provisionable_->generateCertificateRequestV2({keyWithCorruptMac}, challenge_, &csr);
-    ASSERT_FALSE(status.isOk()) << status.getMessage();
+    ASSERT_FALSE(status.isOk()) << status.getDescription();
     EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
 }
 
@@ -818,7 +829,7 @@
     auto status = provisionable_->generateCertificateRequest(
             false /* testMode */, {} /* keysToSign */, {} /* EEK chain */, challenge_, &deviceInfo,
             &protectedData, &keysToSignMac);
-    ASSERT_FALSE(status.isOk()) << status.getMessage();
+    ASSERT_FALSE(status.isOk()) << status.getDescription();
     EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_REMOVED);
 }
 
@@ -832,7 +843,7 @@
     auto status = provisionable_->generateCertificateRequest(
             true /* testMode */, {} /* keysToSign */, {} /* EEK chain */, challenge_, &deviceInfo,
             &protectedData, &keysToSignMac);
-    ASSERT_FALSE(status.isOk()) << status.getMessage();
+    ASSERT_FALSE(status.isOk()) << status.getDescription();
     EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_REMOVED);
 }
 
@@ -916,7 +927,7 @@
     bytevec csr;
     irpcStatus =
             provisionable_->generateCertificateRequestV2({} /* keysToSign */, challenge_, &csr);
-    ASSERT_TRUE(irpcStatus.isOk()) << irpcStatus.getMessage();
+    ASSERT_TRUE(irpcStatus.isOk()) << irpcStatus.getDescription();
 
     auto result = verifyProductionCsr(cppbor::Array(), csr, provisionable_.get(), challenge_);
     ASSERT_TRUE(result) << result.message();
diff --git a/security/secretkeeper/OWNERS b/security/secretkeeper/OWNERS
new file mode 100644
index 0000000..acf4c6c
--- /dev/null
+++ b/security/secretkeeper/OWNERS
@@ -0,0 +1,6 @@
+# Bug component: 867125
+
+alanstokes@google.com
+drysdale@google.com
+hasinitg@google.com
+shikhapanwar@google.com
diff --git a/security/secretkeeper/aidl/Android.bp b/security/secretkeeper/aidl/Android.bp
new file mode 100644
index 0000000..ac923ca
--- /dev/null
+++ b/security/secretkeeper/aidl/Android.bp
@@ -0,0 +1,84 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES 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.security.secretkeeper",
+    vendor_available: true,
+    srcs: ["android/hardware/security/secretkeeper/*.aidl"],
+    imports: [
+        "android.hardware.security.authgraph-V1",
+    ],
+    stability: "vintf",
+    frozen: false,
+    backend: {
+        java: {
+            enabled: false,
+        },
+        ndk: {
+            enabled: true,
+        },
+        rust: {
+            enabled: true,
+            apex_available: [
+                "//apex_available:platform",
+                "com.android.virt",
+            ],
+        },
+    },
+}
+
+// cc_defaults that includes the latest Secretkeeper AIDL library.
+// Modules that depend on Secretkeeper directly can include this cc_defaults to avoid
+// managing dependency versions explicitly.
+cc_defaults {
+    name: "secretkeeper_use_latest_hal_aidl_ndk_static",
+    static_libs: [
+        "android.hardware.security.secretkeeper-V1-ndk",
+    ],
+}
+
+cc_defaults {
+    name: "secretkeeper_use_latest_hal_aidl_ndk_shared",
+    shared_libs: [
+        "android.hardware.security.secretkeeper-V1-ndk",
+    ],
+}
+
+cc_defaults {
+    name: "secretkeeper_use_latest_hal_aidl_cpp_static",
+    static_libs: [
+        "android.hardware.security.secretkeeper-V1-cpp",
+    ],
+}
+
+cc_defaults {
+    name: "secretkeeper_use_latest_hal_aidl_cpp_shared",
+    shared_libs: [
+        "android.hardware.security.secretkeeper-V1-cpp",
+    ],
+}
+
+// A rust_defaults that includes the latest Secretkeeper AIDL library.
+// Modules that depend on Secretkeeper directly can include this rust_defaults to avoid
+// managing dependency versions explicitly.
+rust_defaults {
+    name: "secretkeeper_use_latest_hal_aidl_rust",
+    rustlibs: [
+        "android.hardware.security.secretkeeper-V1-rust",
+    ],
+}
diff --git a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ISecretkeeper.aidl b/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ISecretkeeper.aidl
new file mode 100644
index 0000000..8ce37cd
--- /dev/null
+++ b/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ISecretkeeper.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.secretkeeper;
+@VintfStability
+interface ISecretkeeper {
+  android.hardware.security.authgraph.IAuthGraphKeyExchange getAuthGraphKe();
+  byte[] processSecretManagementRequest(in byte[] request);
+  void deleteIds(in android.hardware.security.secretkeeper.SecretId[] ids);
+  void deleteAll();
+  const int ERROR_UNKNOWN_KEY_ID = 1;
+  const int ERROR_INTERNAL_ERROR = 2;
+  const int ERROR_REQUEST_MALFORMED = 3;
+}
diff --git a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/SecretId.aidl b/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/SecretId.aidl
new file mode 100644
index 0000000..9887066
--- /dev/null
+++ b/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/SecretId.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.secretkeeper;
+/* @hide */
+@VintfStability
+parcelable SecretId {
+  byte[64] id;
+}
diff --git a/security/secretkeeper/aidl/android/hardware/security/secretkeeper/ISecretkeeper.aidl b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/ISecretkeeper.aidl
new file mode 100644
index 0000000..b07dba8
--- /dev/null
+++ b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/ISecretkeeper.aidl
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.security.secretkeeper;
+
+import android.hardware.security.authgraph.IAuthGraphKeyExchange;
+import android.hardware.security.secretkeeper.SecretId;
+
+@VintfStability
+/**
+ * Secretkeeper service definition.
+ *
+ * An ISecretkeeper instance provides secure storage of secrets on behalf of other components in
+ * Android, in particular for protected virtual machine instances. From the perspective of security
+ * privilege, Secretkeeper must be implemented in an environment with privilege higher than any of
+ * its clients. Since AVF based protected Virtual Machines are one set of its clients, the
+ * implementation of ISecretkeeper should live in a secure environment, such as:
+ * - A trusted execution environment such as ARM TrustZone.
+ * - A completely separate, purpose-built and certified secure CPU.
+ *
+ */
+interface ISecretkeeper {
+    const int ERROR_UNKNOWN_KEY_ID = 1;
+    const int ERROR_INTERNAL_ERROR = 2;
+    const int ERROR_REQUEST_MALFORMED = 3;
+
+    /**
+     * Retrieve the instance of the `IAuthGraphKeyExchange` HAL that should be used for shared
+     * session key establishment. These keys are used to perform encryption of messages as
+     * described in SecretManagement.cddl, allowing the client and Secretkeeper to have a
+     * cryptographically secure channel. In the key exchange protocol the client acts as P1
+     * (source) and Secretkeeper as P2 (sink). The interface returned here can be used to invoke
+     * methods on the sink.
+     *
+     * The client's identity is its DICE chain; Secretkeeper's identity is a
+     * per-boot key pair.
+     */
+    IAuthGraphKeyExchange getAuthGraphKe();
+
+    /**
+     * processSecretManagementRequest method is used for interacting with the Secret Management API
+     *
+     * Secret Management API: The clients can use this API to store (& get) 32 bytes of data.
+     * The API is a CBOR based protocol, which follows request/response model.
+     * See SecretManagement.cddl for the API spec.
+     *
+     * Further, the requests (from client) & responses (from service) must be encrypted into
+     * ProtectedRequestPacket & ProtectedResponsePacket using symmetric keys agreed between
+     * the client & service. This cryptographic protection is required because the messages are
+     * ferried via Android, which is allowed to be outside the TCB of clients (for example protected
+     * Virtual Machines). For this, service (& client) must implement the AuthGraph key exchange
+     * protocol to establish a secure channel between them.
+     *
+     * If an encrypted response cannot be generated, then a service-specific Binder error using one
+     * of the ERROR_ codes above will be returned.
+     *
+     * Secretkeeper database should guarantee the following properties:
+     *
+     * 1. Confidentiality: No entity (of security privilege lower than Secretkeeper) should
+     *    be able to get a client's data in clear.
+     *
+     * 2. Integrity: The data is protected against malicious Android OS tampering with database.
+     *    ie, if Android (userspace & kernel) tampers with the client's secret, the Secretkeeper
+     *    service must be able to detect it & return error when clients requests for their secrets.
+     *    Note: the integrity requirements also include Antirollback protection ie, reverting the
+     *    database into an old state should be detected.
+     *
+     * 3. The data is persistent across device boot.
+     *    Note: Denial of service is not in scope. A malicious Android may be able to delete data,
+     *    but for ideal Android, the data should be persistent.
+     *
+     * @param CBOR-encoded ProtectedRequestPacket. See SecretManagement.cddl for its definition.
+     * @return CBOR-encoded ProtectedResponsePacket. See SecretManagement.cddl for its definition
+     */
+    byte[] processSecretManagementRequest(in byte[] request);
+
+    /**
+     * Delete the data corresponding to a collection of IDs.
+     *
+     * Note that unlike `processSecretManagementRequest`, the contents of this method are in
+     * plaintext, and no client authentication is required.
+     *
+     * @param Secret identifiers to delete.
+     */
+    void deleteIds(in SecretId[] ids);
+
+    /**
+     * Delete data of all clients.
+     */
+    void deleteAll();
+}
diff --git a/security/secretkeeper/aidl/android/hardware/security/secretkeeper/SecretId.aidl b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/SecretId.aidl
new file mode 100644
index 0000000..b17917f
--- /dev/null
+++ b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/SecretId.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.security.secretkeeper;
+
+/**
+ * SecretId contains an identifier for a secret held by Secretkeeper.
+ * @hide
+ */
+@VintfStability
+parcelable SecretId {
+    /**
+     * 64-byte identifier for a secret.
+     */
+    byte[64] id;
+}
diff --git a/security/secretkeeper/aidl/android/hardware/security/secretkeeper/SecretManagement.cddl b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/SecretManagement.cddl
new file mode 100644
index 0000000..6a824c9
--- /dev/null
+++ b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/SecretManagement.cddl
@@ -0,0 +1,116 @@
+; CDDL for the Secret Management API.
+
+; The input parameter to the `processSecretManagementRequest` operation in
+; `ISecretkeeper.aidl` is always an encrypted request message, CBOR-encoded as a
+; COSE_Encrypt0 object.  The encryption uses the first of the keys agreed using
+; the associated AuthGraph instance, referred to as `KeySourceToSink`. Additionally,
+; an external aad is used - RequestSeqNum.
+ProtectedRequestPacket = CryptoPayload<RequestPacket, KeySourceToSink, RequestSeqNum>
+
+CryptoPayload<Payload, Key, SeqNum> = [ ; COSE_Encrypt0 (untagged), [RFC 9052 s5.2]
+    protected: bstr .cbor {
+        1 : 3,                  ; Algorithm: AES-GCM mode w/ 256-bit key, 128-bit tag
+        4 : bstr                ; key identifier set to session ID produced
+                                ; by AuthGraph key exchange.
+    },
+    unprotected: {
+        5 : bstr .size 12       ; IV
+    },
+    ciphertext : bstr           ; AES-GCM-256(Key, bstr .cbor Payload)
+                                ; AAD for the encryption is CBOR-serialized
+                                ; Enc_structure (RFC 9052 s5.3) with SeqNum as the external_aad.
+]
+
+; Once decrypted, the request packet is an encoded CBOR array holding:
+; - An initial integer indicating which request is present.
+; - Subsequent objects holding the parameters for that specific request.
+RequestPacket =
+    [GetVersionOpcode, GetVersionParams] /
+    [StoreSecretOpcode, StoreSecretParams] /
+    [GetSecretOpcode, GetSecretParams]
+
+GetVersionOpcode = 1            ; Get version of the SecretManagement API
+StoreSecretOpcode = 2           ; Store a secret
+GetSecretOpcode = 3             ; Get the secret
+
+; Retrieve Secretkeeper version.
+GetVersionParams = ()
+
+; Store a secret identified by the given ID, with access to the secret policed
+; by the associated sealing policy.
+StoreSecretParams = (
+    id : SecretId,
+    secret : Secret,
+    sealing_policy : bstr .cbor DicePolicy,
+)
+
+; INCLUDE DicePolicy.cddl for: DicePolicy
+
+; Retrieve a secret identified by the given ID, policed according to the sealing
+; policy that was associated with the secret.  If successful, optionally also
+; update the sealing policy for the secret.
+GetSecretParams = (
+    id : SecretId,
+    ; Retrieving the value of a secret may optionally also update the sealing
+    ; policy associated with a secret.
+    updated_sealing_policy : bstr .cbor DicePolicy / nil,
+)
+
+SecretId = bstr .size 64        ; Unique identifier of the secret.
+Secret = bstr .size 32          ; The secret value.
+
+; A monotonically incrementing number is associated with each RequestPacket to prevent replay
+; of messages within a session. This starts with 0 and is incremented (by 1) for each request
+; in a session. Secretkeeper implementation must maintain an expected RequestSeqNum for each
+; session (increasing it by 1 for each SecretManagement request received). This will be used in
+; in decryption (external_aad).
+RequestSeqNum = bstr .cbor uint     ; Encoded in accordance with Core Deterministic Encoding
+                                    ; Requirements [RFC 8949 s4.2.1]
+
+; The return value from a successful `processSecretManagementRequest` operation is a
+; response message encrypted with the second of the keys agreed using the associated
+; AuthGraph instance, referred to as `KeySinkToSource`.
+ProtectedResponsePacket = CryptoPayload<ResponsePacket, KeySinkToSource, ResponseSeqNum>
+
+; Once decrypted, the inner response message is encoded as a CBOR array holding:
+; - An initial integer return code value.
+; - Subsequently:
+;    - If the return code is zero: result value(s).
+;    - If the return code is non-zero: an error message.
+ResponsePacket =
+    [0, Result] /
+    [error_code: ErrorCode, error_message: tstr]
+
+; An error code in the inner response message indicates a failure in
+; secret management processing.
+ErrorCode = &(
+    ; Use this as if no other error code can be used.
+    ErrorCode_UnexpectedServerError: 1,
+    ; Indicate the Request was malformed & hence couldnt be served.
+    ErrorCode_RequestMalformed: 2,
+    ; Requested Entry not found.
+    ErrorCode_EntryNotFound: 3,
+    ; Error happened while serialization or deserialization.
+    ErrorCode_SerializationError: 4,
+    ; Indicates that Dice Policy matching did not succeed & hence access not granted.
+    ErrorCode_DicePolicyError: 5,
+)
+
+; The particular result variant present is determined by which request
+; message was originally sent.
+Result = &(
+    GetVersionResult,
+    StoreSecretResult,
+    GetSecretResult,
+)
+
+GetVersionResult = (1)
+
+StoreSecretResult = ()
+
+GetSecretResult = (secret : Secret)
+
+; Analogous to RequestSeqNum, Secretkeeper must maintain ResponseSeqNum for each session.
+; This will be input to the encryption (ProtectedResponsePacket) as external_aad.
+ResponseSeqNum = bstr .cbor uint    ; Encoded in accordance with Core Deterministic Encoding
+                                    ; Requirements [RFC 8949 s4.2.1]
diff --git a/security/secretkeeper/aidl/vts/Android.bp b/security/secretkeeper/aidl/vts/Android.bp
new file mode 100644
index 0000000..9d1701a
--- /dev/null
+++ b/security/secretkeeper/aidl/vts/Android.bp
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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"],
+}
+
+rust_library {
+    name: "libsecretkeeper_test",
+    crate_name: "secretkeeper_test",
+    srcs: ["lib.rs"],
+    rustlibs: [
+        "libciborium",
+        "libcoset",
+        "libdiced_open_dice",
+        "liblog_rust",
+        "libsecretkeeper_client",
+    ],
+}
+
+rust_test {
+    name: "VtsSecretkeeperTargetTest",
+    srcs: ["secretkeeper_test_client.rs"],
+    defaults: [
+        "rdroidtest.defaults",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+    test_config: "AndroidTest.xml",
+    rustlibs: [
+        "android.hardware.security.secretkeeper-V1-rust",
+        "libauthgraph_boringssl",
+        "libauthgraph_core",
+        "libauthgraph_vts_test",
+        "libbinder_rs",
+        "libciborium",
+        "libcoset",
+        "libdice_policy",
+        "liblog_rust",
+        "libsecretkeeper_client",
+        "libsecretkeeper_comm_nostd",
+        "libsecretkeeper_core_nostd",
+        "libsecretkeeper_test",
+    ],
+    require_root: true,
+}
+
+rust_binary {
+    name: "secretkeeper_cli",
+    srcs: ["secretkeeper_cli.rs"],
+    lints: "android",
+    rlibs: [
+        "android.hardware.security.secretkeeper-V1-rust",
+        "libanyhow",
+        "libauthgraph_boringssl",
+        "libauthgraph_core",
+        "libbinder_rs",
+        "libclap",
+        "libcoset",
+        "libdice_policy",
+        "libhex",
+        "liblog_rust",
+        "libsecretkeeper_client",
+        "libsecretkeeper_comm_nostd",
+        "libsecretkeeper_test",
+    ],
+}
diff --git a/security/secretkeeper/aidl/vts/AndroidTest.xml b/security/secretkeeper/aidl/vts/AndroidTest.xml
new file mode 100644
index 0000000..4fee78f
--- /dev/null
+++ b/security/secretkeeper/aidl/vts/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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="Config for Secretkeeper VTS tests.">
+  <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+
+  <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+    <option name="push-file" key="VtsSecretkeeperTargetTest" value="/data/local/tmp/VtsSecretkeeperTargetTest" />
+  </target_preparer>
+
+  <test class="com.android.tradefed.testtype.rust.RustBinaryTest" >
+    <option name="test-device-path" value="/data/local/tmp" />
+    <option name="module-name" value="VtsSecretkeeperTargetTest" />
+    <!-- Rust tests are run in parallel by default. Run these ones
+         single-threaded, so that one test's secrets don't affect
+         the behaviour of a different test. -->
+    <option name="native-test-flag" value="--test-threads=1" />
+  </test>
+</configuration>
diff --git a/security/secretkeeper/aidl/vts/dice_sample.rs b/security/secretkeeper/aidl/vts/dice_sample.rs
new file mode 100644
index 0000000..db532b1
--- /dev/null
+++ b/security/secretkeeper/aidl/vts/dice_sample.rs
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! This module provides a set of sample DICE chains for testing purpose only. Note that this
+//! module duplicates a large chunk of code in libdiced_sample_inputs. We avoid modifying the
+//! latter for testing purposes because it is installed on device.
+
+use ciborium::{de, ser, value::Value};
+use core::ffi::CStr;
+use coset::{iana, Algorithm, AsCborValue, CoseKey, KeyOperation, KeyType, Label};
+use diced_open_dice::{
+    derive_cdi_private_key_seed, keypair_from_seed, retry_bcc_format_config_descriptor,
+    retry_bcc_main_flow, retry_dice_main_flow, Config, DiceArtifacts, DiceConfigValues, DiceError,
+    DiceMode, InputValues, OwnedDiceArtifacts, CDI_SIZE, HASH_SIZE, HIDDEN_SIZE,
+};
+use log::error;
+use secretkeeper_client::dice::OwnedDiceArtifactsWithExplicitKey;
+
+/// Sample UDS used to perform the root DICE flow by `make_sample_bcc_and_cdis`.
+const UDS: &[u8; CDI_SIZE] = &[
+    0x65, 0x4f, 0xab, 0xa9, 0xa5, 0xad, 0x0f, 0x5e, 0x15, 0xc3, 0x12, 0xf7, 0x77, 0x45, 0xfa, 0x55,
+    0x18, 0x6a, 0xa6, 0x34, 0xb6, 0x7c, 0x82, 0x7b, 0x89, 0x4c, 0xc5, 0x52, 0xd3, 0x27, 0x35, 0x8e,
+];
+
+const CODE_HASH_ABL: [u8; HASH_SIZE] = [
+    0x16, 0x48, 0xf2, 0x55, 0x53, 0x23, 0xdd, 0x15, 0x2e, 0x83, 0x38, 0xc3, 0x64, 0x38, 0x63, 0x26,
+    0x0f, 0xcf, 0x5b, 0xd1, 0x3a, 0xd3, 0x40, 0x3e, 0x23, 0xf8, 0x34, 0x4c, 0x6d, 0xa2, 0xbe, 0x25,
+    0x1c, 0xb0, 0x29, 0xe8, 0xc3, 0xfb, 0xb8, 0x80, 0xdc, 0xb1, 0xd2, 0xb3, 0x91, 0x4d, 0xd3, 0xfb,
+    0x01, 0x0f, 0xe4, 0xe9, 0x46, 0xa2, 0xc0, 0x26, 0x57, 0x5a, 0xba, 0x30, 0xf7, 0x15, 0x98, 0x14,
+];
+const AUTHORITY_HASH_ABL: [u8; HASH_SIZE] = [
+    0xf9, 0x00, 0x9d, 0xc2, 0x59, 0x09, 0xe0, 0xb6, 0x98, 0xbd, 0xe3, 0x97, 0x4a, 0xcb, 0x3c, 0xe7,
+    0x6b, 0x24, 0xc3, 0xe4, 0x98, 0xdd, 0xa9, 0x6a, 0x41, 0x59, 0x15, 0xb1, 0x23, 0xe6, 0xc8, 0xdf,
+    0xfb, 0x52, 0xb4, 0x52, 0xc1, 0xb9, 0x61, 0xdd, 0xbc, 0x5b, 0x37, 0x0e, 0x12, 0x12, 0xb2, 0xfd,
+    0xc1, 0x09, 0xb0, 0xcf, 0x33, 0x81, 0x4c, 0xc6, 0x29, 0x1b, 0x99, 0xea, 0xae, 0xfd, 0xaa, 0x0d,
+];
+const HIDDEN_ABL: [u8; HIDDEN_SIZE] = [
+    0xa2, 0x01, 0xd0, 0xc0, 0xaa, 0x75, 0x3c, 0x06, 0x43, 0x98, 0x6c, 0xc3, 0x5a, 0xb5, 0x5f, 0x1f,
+    0x0f, 0x92, 0x44, 0x3b, 0x0e, 0xd4, 0x29, 0x75, 0xe3, 0xdb, 0x36, 0xda, 0xc8, 0x07, 0x97, 0x4d,
+    0xff, 0xbc, 0x6a, 0xa4, 0x8a, 0xef, 0xc4, 0x7f, 0xf8, 0x61, 0x7d, 0x51, 0x4d, 0x2f, 0xdf, 0x7e,
+    0x8c, 0x3d, 0xa3, 0xfc, 0x63, 0xd4, 0xd4, 0x74, 0x8a, 0xc4, 0x14, 0x45, 0x83, 0x6b, 0x12, 0x7e,
+];
+const CODE_HASH_AVB: [u8; HASH_SIZE] = [
+    0xa4, 0x0c, 0xcb, 0xc1, 0xbf, 0xfa, 0xcc, 0xfd, 0xeb, 0xf4, 0xfc, 0x43, 0x83, 0x7f, 0x46, 0x8d,
+    0xd8, 0xd8, 0x14, 0xc1, 0x96, 0x14, 0x1f, 0x6e, 0xb3, 0xa0, 0xd9, 0x56, 0xb3, 0xbf, 0x2f, 0xfa,
+    0x88, 0x70, 0x11, 0x07, 0x39, 0xa4, 0xd2, 0xa9, 0x6b, 0x18, 0x28, 0xe8, 0x29, 0x20, 0x49, 0x0f,
+    0xbb, 0x8d, 0x08, 0x8c, 0xc6, 0x54, 0xe9, 0x71, 0xd2, 0x7e, 0xa4, 0xfe, 0x58, 0x7f, 0xd3, 0xc7,
+];
+const AUTHORITY_HASH_AVB: [u8; HASH_SIZE] = [
+    0xb2, 0x69, 0x05, 0x48, 0x56, 0xb5, 0xfa, 0x55, 0x6f, 0xac, 0x56, 0xd9, 0x02, 0x35, 0x2b, 0xaa,
+    0x4c, 0xba, 0x28, 0xdd, 0x82, 0x3a, 0x86, 0xf5, 0xd4, 0xc2, 0xf1, 0xf9, 0x35, 0x7d, 0xe4, 0x43,
+    0x13, 0xbf, 0xfe, 0xd3, 0x36, 0xd8, 0x1c, 0x12, 0x78, 0x5c, 0x9c, 0x3e, 0xf6, 0x66, 0xef, 0xab,
+    0x3d, 0x0f, 0x89, 0xa4, 0x6f, 0xc9, 0x72, 0xee, 0x73, 0x43, 0x02, 0x8a, 0xef, 0xbc, 0x05, 0x98,
+];
+const HIDDEN_AVB: [u8; HIDDEN_SIZE] = [
+    0x5b, 0x3f, 0xc9, 0x6b, 0xe3, 0x95, 0x59, 0x40, 0x5e, 0x64, 0xe5, 0x64, 0x3f, 0xfd, 0x21, 0x09,
+    0x9d, 0xf3, 0xcd, 0xc7, 0xa4, 0x2a, 0xe2, 0x97, 0xdd, 0xe2, 0x4f, 0xb0, 0x7d, 0x7e, 0xf5, 0x8e,
+    0xd6, 0x4d, 0x84, 0x25, 0x54, 0x41, 0x3f, 0x8f, 0x78, 0x64, 0x1a, 0x51, 0x27, 0x9d, 0x55, 0x8a,
+    0xe9, 0x90, 0x35, 0xab, 0x39, 0x80, 0x4b, 0x94, 0x40, 0x84, 0xa2, 0xfd, 0x73, 0xeb, 0x35, 0x7a,
+];
+const AUTHORITY_HASH_ANDROID: [u8; HASH_SIZE] = [
+    0x04, 0x25, 0x5d, 0x60, 0x5f, 0x5c, 0x45, 0x0d, 0xf2, 0x9a, 0x6e, 0x99, 0x30, 0x03, 0xb8, 0xd6,
+    0xe1, 0x99, 0x71, 0x1b, 0xf8, 0x44, 0xfa, 0xb5, 0x31, 0x79, 0x1c, 0x37, 0x68, 0x4e, 0x1d, 0xc0,
+    0x24, 0x74, 0x68, 0xf8, 0x80, 0x20, 0x3e, 0x44, 0xb1, 0x43, 0xd2, 0x9c, 0xfc, 0x12, 0x9e, 0x77,
+    0x0a, 0xde, 0x29, 0x24, 0xff, 0x2e, 0xfa, 0xc7, 0x10, 0xd5, 0x73, 0xd4, 0xc6, 0xdf, 0x62, 0x9f,
+];
+
+/// Encode the public key to CBOR Value. The input (raw 32 bytes) is wrapped into CoseKey.
+fn ed25519_public_key_to_cbor_value(public_key: &[u8]) -> Value {
+    let key = CoseKey {
+        kty: KeyType::Assigned(iana::KeyType::OKP),
+        alg: Some(Algorithm::Assigned(iana::Algorithm::EdDSA)),
+        key_ops: vec![KeyOperation::Assigned(iana::KeyOperation::Verify)].into_iter().collect(),
+        params: vec![
+            (
+                Label::Int(iana::Ec2KeyParameter::Crv as i64),
+                Value::from(iana::EllipticCurve::Ed25519 as u64),
+            ),
+            (Label::Int(iana::Ec2KeyParameter::X as i64), Value::Bytes(public_key.to_vec())),
+        ],
+        ..Default::default()
+    };
+    key.to_cbor_value().unwrap()
+}
+
+/// Makes a DICE chain (BCC) from the sample input.
+///
+/// The DICE chain is of the following format:
+/// public key derived from UDS -> ABL certificate -> AVB certificate -> Android certificate
+/// The `security_version` is included in the Android certificate.
+pub fn make_explicit_owned_dice(security_version: u64) -> OwnedDiceArtifactsWithExplicitKey {
+    let dice = make_sample_bcc_and_cdis(security_version);
+    OwnedDiceArtifactsWithExplicitKey::from_owned_artifacts(dice).unwrap()
+}
+
+fn make_sample_bcc_and_cdis(security_version: u64) -> OwnedDiceArtifacts {
+    let private_key_seed = derive_cdi_private_key_seed(UDS).unwrap();
+
+    // Gets the root public key in DICE chain (BCC).
+    let (public_key, _) = keypair_from_seed(private_key_seed.as_array()).unwrap();
+    let ed25519_public_key_value = ed25519_public_key_to_cbor_value(&public_key);
+
+    // Gets the ABL certificate to as the root certificate of DICE chain.
+    let config_values = DiceConfigValues {
+        component_name: Some(CStr::from_bytes_with_nul(b"ABL\0").unwrap()),
+        component_version: Some(1),
+        resettable: true,
+        ..Default::default()
+    };
+    let config_descriptor = retry_bcc_format_config_descriptor(&config_values).unwrap();
+    let input_values = InputValues::new(
+        CODE_HASH_ABL,
+        Config::Descriptor(config_descriptor.as_slice()),
+        AUTHORITY_HASH_ABL,
+        DiceMode::kDiceModeNormal,
+        HIDDEN_ABL,
+    );
+    let (cdi_values, cert) = retry_dice_main_flow(UDS, UDS, &input_values).unwrap();
+    let bcc_value =
+        Value::Array(vec![ed25519_public_key_value, de::from_reader(&cert[..]).unwrap()]);
+    let mut bcc: Vec<u8> = vec![];
+    ser::into_writer(&bcc_value, &mut bcc).unwrap();
+
+    // Appends AVB certificate to DICE chain.
+    let config_values = DiceConfigValues {
+        component_name: Some(CStr::from_bytes_with_nul(b"AVB\0").unwrap()),
+        component_version: Some(1),
+        resettable: true,
+        ..Default::default()
+    };
+    let config_descriptor = retry_bcc_format_config_descriptor(&config_values).unwrap();
+    let input_values = InputValues::new(
+        CODE_HASH_AVB,
+        Config::Descriptor(config_descriptor.as_slice()),
+        AUTHORITY_HASH_AVB,
+        DiceMode::kDiceModeNormal,
+        HIDDEN_AVB,
+    );
+    let dice_artifacts =
+        retry_bcc_main_flow(&cdi_values.cdi_attest, &cdi_values.cdi_seal, &bcc, &input_values)
+            .unwrap();
+
+    // Appends Android certificate to DICE chain.
+    let config_values = DiceConfigValues {
+        component_name: Some(CStr::from_bytes_with_nul(b"Android\0").unwrap()),
+        component_version: Some(12),
+        security_version: Some(security_version),
+        resettable: true,
+        ..Default::default()
+    };
+    let config_descriptor = retry_bcc_format_config_descriptor(&config_values).unwrap();
+    let input_values = InputValues::new(
+        [0u8; HASH_SIZE], // code_hash
+        Config::Descriptor(config_descriptor.as_slice()),
+        AUTHORITY_HASH_ANDROID,
+        DiceMode::kDiceModeNormal,
+        [0u8; HIDDEN_SIZE], // hidden
+    );
+    retry_bcc_main_flow(
+        dice_artifacts.cdi_attest(),
+        dice_artifacts.cdi_seal(),
+        dice_artifacts
+            .bcc()
+            .ok_or_else(|| {
+                error!("bcc is none");
+                DiceError::InvalidInput
+            })
+            .unwrap(),
+        &input_values,
+    )
+    .unwrap()
+}
diff --git a/security/secretkeeper/aidl/vts/lib.rs b/security/secretkeeper/aidl/vts/lib.rs
new file mode 100644
index 0000000..9f98165
--- /dev/null
+++ b/security/secretkeeper/aidl/vts/lib.rs
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! Test helper functions.
+
+pub mod dice_sample;
+
+// Constants for DICE map keys.
+
+/// Map key for authority hash.
+pub const AUTHORITY_HASH: i64 = -4670549;
+/// Map key for config descriptor.
+pub const CONFIG_DESC: i64 = -4670548;
+/// Map key for component name.
+pub const COMPONENT_NAME: i64 = -70002;
+/// Map key for component version.
+pub const COMPONENT_VERSION: i64 = -70003;
+/// Map key for security version.
+pub const SECURITY_VERSION: i64 = -70005;
+/// Map key for mode.
+pub const MODE: i64 = -4670551;
diff --git a/security/secretkeeper/aidl/vts/rustfmt.toml b/security/secretkeeper/aidl/vts/rustfmt.toml
new file mode 120000
index 0000000..ed2086b
--- /dev/null
+++ b/security/secretkeeper/aidl/vts/rustfmt.toml
@@ -0,0 +1 @@
+../../../../../../build/soong/scripts/rustfmt.toml
\ No newline at end of file
diff --git a/security/secretkeeper/aidl/vts/secretkeeper_cli.rs b/security/secretkeeper/aidl/vts/secretkeeper_cli.rs
new file mode 100644
index 0000000..5f08482
--- /dev/null
+++ b/security/secretkeeper/aidl/vts/secretkeeper_cli.rs
@@ -0,0 +1,347 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! Command line test tool for interacting with Secretkeeper.
+
+use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper::{
+    ISecretkeeper::ISecretkeeper, SecretId::SecretId,
+};
+use anyhow::{anyhow, bail, Context, Result};
+use authgraph_boringssl::BoringSha256;
+use authgraph_core::traits::Sha256;
+use clap::{Args, Parser, Subcommand};
+use coset::CborSerializable;
+use dice_policy::{ConstraintSpec, ConstraintType, DicePolicy, MissingAction};
+use secretkeeper_client::{dice::OwnedDiceArtifactsWithExplicitKey, SkSession};
+use secretkeeper_comm::data_types::{
+    error::SecretkeeperError,
+    packet::{ResponsePacket, ResponseType},
+    request::Request,
+    request_response_impl::{GetSecretRequest, GetSecretResponse, StoreSecretRequest},
+    response::Response,
+    {Id, Secret},
+};
+use secretkeeper_test::{
+    dice_sample::make_explicit_owned_dice, AUTHORITY_HASH, CONFIG_DESC, MODE, SECURITY_VERSION,
+};
+use std::io::Write;
+
+#[derive(Parser, Debug)]
+#[command(about = "Interact with Secretkeeper HAL")]
+#[command(version = "0.1")]
+#[command(propagate_version = true)]
+struct Cli {
+    #[command(subcommand)]
+    command: Command,
+
+    /// Secretkeeper instance to connect to.
+    #[arg(long, short)]
+    instance: Option<String>,
+
+    /// Security version in leaf DICE node.
+    #[clap(default_value_t = 100)]
+    #[arg(long, short = 'v')]
+    dice_version: u64,
+
+    /// Show hex versions of secrets and their IDs.
+    #[clap(default_value_t = false)]
+    #[arg(long, short = 'v')]
+    hex: bool,
+}
+
+#[derive(Subcommand, Debug)]
+enum Command {
+    /// Store a secret value.
+    Store(StoreArgs),
+    /// Get a secret value.
+    Get(GetArgs),
+    /// Delete a secret value.
+    Delete(DeleteArgs),
+    /// Delete all secret values.
+    DeleteAll(DeleteAllArgs),
+}
+
+#[derive(Args, Debug)]
+struct StoreArgs {
+    /// Identifier for the secret, as either a short (< 32 byte) string, or as 32 bytes of hex.
+    id: String,
+    /// Value to use as the secret value. If specified as 32 bytes of hex, the decoded value
+    /// will be used as-is; otherwise, a string (less than 31 bytes in length) will be encoded
+    /// as the secret.
+    value: String,
+}
+
+#[derive(Args, Debug)]
+struct GetArgs {
+    /// Identifier for the secret, as either a short (< 32 byte) string, or as 32 bytes of hex.
+    id: String,
+}
+
+#[derive(Args, Debug)]
+struct DeleteArgs {
+    /// Identifier for the secret, as either a short (< 32 byte) string, or as 32 bytes of hex.
+    id: String,
+}
+
+#[derive(Args, Debug)]
+struct DeleteAllArgs {
+    /// Confirm deletion of all secrets.
+    yes: bool,
+}
+
+const SECRETKEEPER_SERVICE: &str = "android.hardware.security.secretkeeper.ISecretkeeper";
+
+/// Secretkeeper client information.
+struct SkClient {
+    sk: binder::Strong<dyn ISecretkeeper>,
+    session: SkSession,
+    dice_artifacts: OwnedDiceArtifactsWithExplicitKey,
+}
+
+impl SkClient {
+    fn new(instance: &str, dice_artifacts: OwnedDiceArtifactsWithExplicitKey) -> Self {
+        let sk: binder::Strong<dyn ISecretkeeper> =
+            binder::get_interface(&format!("{SECRETKEEPER_SERVICE}/{instance}")).unwrap();
+        let session = SkSession::new(sk.clone(), &dice_artifacts).unwrap();
+        Self { sk, session, dice_artifacts }
+    }
+
+    fn secret_management_request(&mut self, req_data: &[u8]) -> Result<Vec<u8>> {
+        self.session
+            .secret_management_request(req_data)
+            .map_err(|e| anyhow!("secret management: {e:?}"))
+    }
+
+    /// Construct a sealing policy on the DICE chain with constraints:
+    /// 1. `ExactMatch` on `AUTHORITY_HASH` (non-optional).
+    /// 2. `ExactMatch` on `MODE` (non-optional).
+    /// 3. `GreaterOrEqual` on `SECURITY_VERSION` (optional).
+    fn sealing_policy(&self) -> Result<Vec<u8>> {
+        let dice =
+            self.dice_artifacts.explicit_key_dice_chain().context("extract explicit DICE chain")?;
+
+        let constraint_spec = [
+            ConstraintSpec::new(
+                ConstraintType::ExactMatch,
+                vec![AUTHORITY_HASH],
+                MissingAction::Fail,
+            ),
+            ConstraintSpec::new(ConstraintType::ExactMatch, vec![MODE], MissingAction::Fail),
+            ConstraintSpec::new(
+                ConstraintType::GreaterOrEqual,
+                vec![CONFIG_DESC, SECURITY_VERSION],
+                MissingAction::Ignore,
+            ),
+        ];
+        DicePolicy::from_dice_chain(dice, &constraint_spec)
+            .unwrap()
+            .to_vec()
+            .context("serialize DICE policy")
+    }
+
+    fn store(&mut self, id: &Id, secret: &Secret) -> Result<()> {
+        let store_request = StoreSecretRequest {
+            id: id.clone(),
+            secret: secret.clone(),
+            sealing_policy: self.sealing_policy().context("build sealing policy")?,
+        };
+        let store_request =
+            store_request.serialize_to_packet().to_vec().context("serialize StoreSecretRequest")?;
+
+        let store_response = self.secret_management_request(&store_request)?;
+        let store_response =
+            ResponsePacket::from_slice(&store_response).context("deserialize ResponsePacket")?;
+        let response_type = store_response.response_type().unwrap();
+        if response_type == ResponseType::Success {
+            Ok(())
+        } else {
+            let err = *SecretkeeperError::deserialize_from_packet(store_response).unwrap();
+            Err(anyhow!("STORE failed: {err:?}"))
+        }
+    }
+
+    fn get(&mut self, id: &Id) -> Result<Option<Secret>> {
+        let get_request = GetSecretRequest { id: id.clone(), updated_sealing_policy: None }
+            .serialize_to_packet()
+            .to_vec()
+            .context("serialize GetSecretRequest")?;
+
+        let get_response = self.secret_management_request(&get_request).context("secret mgmt")?;
+        let get_response =
+            ResponsePacket::from_slice(&get_response).context("deserialize ResponsePacket")?;
+
+        if get_response.response_type().unwrap() == ResponseType::Success {
+            let get_response = *GetSecretResponse::deserialize_from_packet(get_response).unwrap();
+            Ok(Some(Secret(get_response.secret.0)))
+        } else {
+            // Only expect a not-found failure.
+            let err = *SecretkeeperError::deserialize_from_packet(get_response).unwrap();
+            if err == SecretkeeperError::EntryNotFound {
+                Ok(None)
+            } else {
+                Err(anyhow!("GET failed: {err:?}"))
+            }
+        }
+    }
+
+    /// Helper method to delete secrets.
+    fn delete(&self, ids: &[&Id]) -> Result<()> {
+        let ids: Vec<SecretId> = ids.iter().map(|id| SecretId { id: id.0 }).collect();
+        self.sk.deleteIds(&ids).context("deleteIds")
+    }
+
+    /// Helper method to delete everything.
+    fn delete_all(&self) -> Result<()> {
+        self.sk.deleteAll().context("deleteAll")
+    }
+}
+
+/// Convert a string input into an `Id`.  Input can be 64 bytes of hex, or a string
+/// that will be hashed to give the `Id` value. Returns the `Id` and a display string.
+fn string_to_id(s: &str, show_hex: bool) -> (Id, String) {
+    if let Ok(data) = hex::decode(s) {
+        if data.len() == 64 {
+            // Assume something that parses as 64 bytes of hex is it.
+            return (Id(data.try_into().unwrap()), s.to_string().to_lowercase());
+        }
+    }
+    // Create a secret ID by repeating the SHA-256 hash of the string twice.
+    let hash = BoringSha256.compute_sha256(s.as_bytes()).unwrap();
+    let mut id = Id([0; 64]);
+    id.0[..32].copy_from_slice(&hash);
+    id.0[32..].copy_from_slice(&hash);
+    if show_hex {
+        let hex_id = hex::encode(&id.0);
+        (id, format!("'{s}' (as {hex_id})"))
+    } else {
+        (id, format!("'{s}'"))
+    }
+}
+
+/// Convert a string input into a `Secret`.  Input can be 32 bytes of hex, or a short string
+/// that will be encoded as the `Secret` value. Returns the `Secret` and a display string.
+fn value_to_secret(s: &str, show_hex: bool) -> Result<(Secret, String)> {
+    if let Ok(data) = hex::decode(s) {
+        if data.len() == 32 {
+            // Assume something that parses as 32 bytes of hex is it.
+            return Ok((Secret(data.try_into().unwrap()), s.to_string().to_lowercase()));
+        }
+    }
+    let data = s.as_bytes();
+    if data.len() > 31 {
+        return Err(anyhow!("secret too long"));
+    }
+    let mut secret = Secret([0; 32]);
+    secret.0[0] = data.len() as u8;
+    secret.0[1..1 + data.len()].copy_from_slice(data);
+    Ok(if show_hex {
+        let hex_secret = hex::encode(&secret.0);
+        (secret, format!("'{s}' (as {hex_secret})"))
+    } else {
+        (secret, format!("'{s}'"))
+    })
+}
+
+/// Convert a `Secret` into a displayable string. If the secret looks like an encoded
+/// string, show that, otherwise show the value in hex.
+fn secret_to_value_display(secret: &Secret, show_hex: bool) -> String {
+    let hex = hex::encode(&secret.0);
+    secret_to_value(secret)
+        .map(|s| if show_hex { format!("'{s}' (from {hex})") } else { format!("'{s}'") })
+        .unwrap_or_else(|_e| format!("{hex}"))
+}
+
+/// Attempt to convert a `Secret` back to a string.
+fn secret_to_value(secret: &Secret) -> Result<String> {
+    let len = secret.0[0] as usize;
+    if len > 31 {
+        return Err(anyhow!("too long"));
+    }
+    std::str::from_utf8(&secret.0[1..1 + len]).map(|s| s.to_string()).context("not UTF-8 string")
+}
+
+fn main() -> Result<()> {
+    let cli = Cli::parse();
+
+    // Figure out which Secretkeeper instance is desired, and connect to it.
+    let instance = if let Some(instance) = &cli.instance {
+        // Explicitly specified.
+        instance.clone()
+    } else {
+        // If there's only one instance, use that.
+        let instances: Vec<String> = binder::get_declared_instances(SECRETKEEPER_SERVICE)
+            .unwrap_or_default()
+            .into_iter()
+            .collect();
+        match instances.len() {
+            0 => bail!("No Secretkeeper instances available on device!"),
+            1 => instances[0].clone(),
+            _ => {
+                bail!(
+                    concat!(
+                        "Multiple Secretkeeper instances available on device: {}\n",
+                        "Use --instance <instance> to specify one."
+                    ),
+                    instances.join(", ")
+                );
+            }
+        }
+    };
+    let dice = make_explicit_owned_dice(cli.dice_version);
+    let mut sk_client = SkClient::new(&instance, dice);
+
+    match cli.command {
+        Command::Get(args) => {
+            let (id, display_id) = string_to_id(&args.id, cli.hex);
+            print!("GET key {display_id}: ");
+            match sk_client.get(&id).context("GET") {
+                Ok(None) => println!("not found"),
+                Ok(Some(s)) => println!("{}", secret_to_value_display(&s, cli.hex)),
+                Err(e) => {
+                    println!("failed!");
+                    return Err(e);
+                }
+            }
+        }
+        Command::Store(args) => {
+            let (id, display_id) = string_to_id(&args.id, cli.hex);
+            let (secret, display_secret) = value_to_secret(&args.value, cli.hex)?;
+            println!("STORE key {display_id}: {display_secret}");
+            sk_client.store(&id, &secret).context("STORE")?;
+        }
+        Command::Delete(args) => {
+            let (id, display_id) = string_to_id(&args.id, cli.hex);
+            println!("DELETE key {display_id}");
+            sk_client.delete(&[&id]).context("DELETE")?;
+        }
+        Command::DeleteAll(args) => {
+            if !args.yes {
+                // Request confirmation.
+                println!("Confirm delete all secrets: [y/N]");
+                let _ = std::io::stdout().flush();
+                let mut input = String::new();
+                std::io::stdin().read_line(&mut input)?;
+                let c = input.chars().next();
+                if c != Some('y') && c != Some('Y') {
+                    bail!("DELETE_ALL not confirmed");
+                }
+            }
+            println!("DELETE_ALL");
+            sk_client.delete_all().context("DELETE_ALL")?;
+        }
+    }
+    Ok(())
+}
diff --git a/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs b/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs
new file mode 100644
index 0000000..8c33f04
--- /dev/null
+++ b/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs
@@ -0,0 +1,565 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper::ISecretkeeper::ISecretkeeper;
+use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper::SecretId::SecretId;
+use authgraph_vts_test as ag_vts;
+use authgraph_boringssl as boring;
+use authgraph_core::key;
+use coset::{CborSerializable, CoseEncrypt0};
+use dice_policy::{ConstraintSpec, ConstraintType, DicePolicy, MissingAction};
+use rdroidtest::{ignore_if, rdroidtest};
+use secretkeeper_client::dice::OwnedDiceArtifactsWithExplicitKey;
+use secretkeeper_client::SkSession;
+use secretkeeper_core::cipher;
+use secretkeeper_comm::data_types::error::SecretkeeperError;
+use secretkeeper_comm::data_types::request::Request;
+use secretkeeper_comm::data_types::request_response_impl::{
+    GetVersionRequest, GetVersionResponse, GetSecretRequest, GetSecretResponse, StoreSecretRequest,
+    StoreSecretResponse };
+use secretkeeper_comm::data_types::{Id, Secret, SeqNum};
+use secretkeeper_comm::data_types::response::Response;
+use secretkeeper_comm::data_types::packet::{ResponsePacket, ResponseType};
+use secretkeeper_test::{
+    AUTHORITY_HASH, MODE, CONFIG_DESC, SECURITY_VERSION,
+    dice_sample::make_explicit_owned_dice
+};
+
+const SECRETKEEPER_SERVICE: &str = "android.hardware.security.secretkeeper.ISecretkeeper";
+const CURRENT_VERSION: u64 = 1;
+
+// Random bytes (of ID_SIZE/SECRET_SIZE) generated for tests.
+const ID_EXAMPLE: Id = Id([
+    0xF1, 0xB2, 0xED, 0x3B, 0xD1, 0xBD, 0xF0, 0x7D, 0xE1, 0xF0, 0x01, 0xFC, 0x61, 0x71, 0xD3, 0x42,
+    0xE5, 0x8A, 0xAF, 0x33, 0x6C, 0x11, 0xDC, 0xC8, 0x6F, 0xAE, 0x12, 0x5C, 0x26, 0x44, 0x6B, 0x86,
+    0xCC, 0x24, 0xFD, 0xBF, 0x91, 0x4A, 0x54, 0x84, 0xF9, 0x01, 0x59, 0x25, 0x70, 0x89, 0x38, 0x8D,
+    0x5E, 0xE6, 0x91, 0xDF, 0x68, 0x60, 0x69, 0x26, 0xBE, 0xFE, 0x79, 0x58, 0xF7, 0xEA, 0x81, 0x7D,
+]);
+const ID_EXAMPLE_2: Id = Id([
+    0x6A, 0xCC, 0xB1, 0xEB, 0xBB, 0xAB, 0xE3, 0xEA, 0x44, 0xBD, 0xDC, 0x75, 0x75, 0x7D, 0xC0, 0xE5,
+    0xC7, 0x86, 0x41, 0x56, 0x39, 0x66, 0x96, 0x10, 0xCB, 0x43, 0x10, 0x79, 0x03, 0xDC, 0xE6, 0x9F,
+    0x12, 0x2B, 0xEF, 0x28, 0x9C, 0x1E, 0x32, 0x46, 0x5F, 0xA3, 0xE7, 0x8D, 0x53, 0x63, 0xE8, 0x30,
+    0x5A, 0x17, 0x6F, 0xEF, 0x42, 0xD6, 0x58, 0x7A, 0xF0, 0xCB, 0xD4, 0x40, 0x58, 0x96, 0x32, 0xF4,
+]);
+const ID_NOT_STORED: Id = Id([
+    0x56, 0xD0, 0x4E, 0xAA, 0xC1, 0x7B, 0x55, 0x6B, 0xA0, 0x2C, 0x65, 0x43, 0x39, 0x0A, 0x6C, 0xE9,
+    0x1F, 0xD0, 0x0E, 0x20, 0x3E, 0xFB, 0xF5, 0xF9, 0x3F, 0x5B, 0x11, 0x1B, 0x18, 0x73, 0xF6, 0xBB,
+    0xAB, 0x9F, 0xF2, 0xD6, 0xBD, 0xBA, 0x25, 0x68, 0x22, 0x30, 0xF2, 0x1F, 0x90, 0x05, 0xF3, 0x64,
+    0xE7, 0xEF, 0xC6, 0xB6, 0xA0, 0x85, 0xC9, 0x40, 0x40, 0xF0, 0xB4, 0xB9, 0xD8, 0x28, 0xEE, 0x9C,
+]);
+const SECRET_EXAMPLE: Secret = Secret([
+    0xA9, 0x89, 0x97, 0xFE, 0xAE, 0x97, 0x55, 0x4B, 0x32, 0x35, 0xF0, 0xE8, 0x93, 0xDA, 0xEA, 0x24,
+    0x06, 0xAC, 0x36, 0x8B, 0x3C, 0x95, 0x50, 0x16, 0x67, 0x71, 0x65, 0x26, 0xEB, 0xD0, 0xC3, 0x98,
+]);
+
+fn get_instances() -> Vec<(String, String)> {
+    // Determine which instances are available.
+    binder::get_declared_instances(SECRETKEEPER_SERVICE)
+        .unwrap_or_default()
+        .into_iter()
+        .map(|v| (v.clone(), v))
+        .collect()
+}
+
+fn get_connection(instance: &str) -> binder::Strong<dyn ISecretkeeper> {
+    let name = format!("{SECRETKEEPER_SERVICE}/{instance}");
+    binder::get_interface(&name).unwrap()
+}
+
+/// Secretkeeper client information.
+struct SkClient {
+    sk: binder::Strong<dyn ISecretkeeper>,
+    session: SkSession,
+    dice_artifacts: OwnedDiceArtifactsWithExplicitKey,
+}
+
+impl Drop for SkClient {
+    fn drop(&mut self) {
+        // Delete any IDs that may be left over.
+        self.delete(&[&ID_EXAMPLE, &ID_EXAMPLE_2]);
+    }
+}
+
+impl SkClient {
+    /// Create an `SkClient` using the default `OwnedDiceArtifactsWithExplicitKey` for identity.
+    fn new(instance: &str) -> Self {
+        let default_dice = make_explicit_owned_dice(/*Security version in a node */ 5);
+        Self::with_identity(instance, default_dice)
+    }
+
+    /// Create an `SkClient` using the given `OwnedDiceArtifactsWithExplicitKey` for identity.
+    fn with_identity(instance: &str, dice_artifacts: OwnedDiceArtifactsWithExplicitKey) -> Self {
+        let sk = get_connection(instance);
+        Self {
+            sk: sk.clone(),
+            session: SkSession::new(sk, &dice_artifacts).unwrap(),
+            dice_artifacts,
+        }
+    }
+
+    /// This method is wrapper that use `SkSession::secret_management_request` which handles
+    /// encryption and decryption.
+    fn secret_management_request(&mut self, req_data: &[u8]) -> Result<Vec<u8>, Error> {
+        Ok(self.session.secret_management_request(req_data)?)
+    }
+
+    /// Unlike the method [`secret_management_request`], this method directly uses
+    /// `cipher::encrypt_message` & `cipher::decrypt_message`, allowing finer control of request
+    /// & response aad.
+    fn secret_management_request_custom_aad(
+        &self,
+        req_data: &[u8],
+        req_aad: &[u8],
+        expected_res_aad: &[u8],
+    ) -> Result<Vec<u8>, Error> {
+        let aes_gcm = boring::BoringAes;
+        let rng = boring::BoringRng;
+        let request_bytes = cipher::encrypt_message(
+            &aes_gcm,
+            &rng,
+            self.session.encryption_key(),
+            self.session.session_id(),
+            &req_data,
+            req_aad,
+        )
+        .map_err(|e| secretkeeper_client::Error::CipherError(e))?;
+
+        // Binder call!
+        let response_bytes = self.sk.processSecretManagementRequest(&request_bytes)?;
+
+        let response_encrypt0 = CoseEncrypt0::from_slice(&response_bytes)?;
+        Ok(cipher::decrypt_message(
+            &aes_gcm,
+            self.session.decryption_key(),
+            &response_encrypt0,
+            expected_res_aad,
+        )
+        .map_err(|e| secretkeeper_client::Error::CipherError(e))?)
+    }
+
+    /// Helper method to store a secret. This uses the default compatible sealing_policy on
+    /// dice_chain.
+    fn store(&mut self, id: &Id, secret: &Secret) -> Result<(), Error> {
+        let sealing_policy = sealing_policy(
+            self.dice_artifacts.explicit_key_dice_chain().ok_or(Error::UnexpectedError)?,
+        );
+        let store_request =
+            StoreSecretRequest { id: id.clone(), secret: secret.clone(), sealing_policy };
+        let store_request = store_request.serialize_to_packet().to_vec()?;
+
+        let store_response = self.secret_management_request(&store_request)?;
+        let store_response = ResponsePacket::from_slice(&store_response)?;
+
+        assert_eq!(store_response.response_type()?, ResponseType::Success);
+        // Really just checking that the response is indeed StoreSecretResponse
+        let _ = StoreSecretResponse::deserialize_from_packet(store_response)?;
+        Ok(())
+    }
+
+    /// Helper method to get a secret.
+    fn get(&mut self, id: &Id) -> Result<Secret, Error> {
+        let get_request = GetSecretRequest { id: id.clone(), updated_sealing_policy: None };
+        let get_request = get_request.serialize_to_packet().to_vec()?;
+
+        let get_response = self.secret_management_request(&get_request)?;
+        let get_response = ResponsePacket::from_slice(&get_response)?;
+
+        if get_response.response_type()? == ResponseType::Success {
+            let get_response = *GetSecretResponse::deserialize_from_packet(get_response)?;
+            Ok(Secret(get_response.secret.0))
+        } else {
+            let err = *SecretkeeperError::deserialize_from_packet(get_response)?;
+            Err(Error::SecretkeeperError(err))
+        }
+    }
+
+    /// Helper method to delete secrets.
+    fn delete(&self, ids: &[&Id]) {
+        let ids: Vec<SecretId> = ids.iter().map(|id| SecretId { id: id.0 }).collect();
+        self.sk.deleteIds(&ids).unwrap();
+    }
+
+    /// Helper method to delete everything.
+    fn delete_all(&self) {
+        self.sk.deleteAll().unwrap();
+    }
+}
+
+#[derive(Debug)]
+enum Error {
+    // Errors from Secretkeeper API errors. These are thrown by core SecretManagement and
+    // not visible without decryption.
+    SecretkeeperError(SecretkeeperError),
+    InfraError(secretkeeper_client::Error),
+    UnexpectedError,
+}
+
+impl From<secretkeeper_client::Error> for Error {
+    fn from(e: secretkeeper_client::Error) -> Self {
+        Self::InfraError(e)
+    }
+}
+
+impl From<SecretkeeperError> for Error {
+    fn from(e: SecretkeeperError) -> Self {
+        Self::SecretkeeperError(e)
+    }
+}
+
+impl From<coset::CoseError> for Error {
+    fn from(e: coset::CoseError) -> Self {
+        Self::InfraError(secretkeeper_client::Error::from(e))
+    }
+}
+
+impl From<binder::Status> for Error {
+    fn from(s: binder::Status) -> Self {
+        Self::InfraError(secretkeeper_client::Error::from(s))
+    }
+}
+
+impl From<secretkeeper_comm::data_types::error::Error> for Error {
+    fn from(e: secretkeeper_comm::data_types::error::Error) -> Self {
+        Self::InfraError(secretkeeper_client::Error::from(e))
+    }
+}
+
+// Assert that the error is EntryNotFound
+fn assert_entry_not_found(res: Result<Secret, Error>) {
+    assert!(matches!(res.unwrap_err(), Error::SecretkeeperError(SecretkeeperError::EntryNotFound)))
+}
+
+/// Construct a sealing policy on the dice chain. This method uses the following set of
+/// constraints which are compatible with sample DICE chains used in VTS.
+/// 1. ExactMatch on AUTHORITY_HASH (non-optional).
+/// 2. ExactMatch on MODE (non-optional).
+/// 3. GreaterOrEqual on SECURITY_VERSION (optional).
+fn sealing_policy(dice: &[u8]) -> Vec<u8> {
+    let constraint_spec = [
+        ConstraintSpec::new(ConstraintType::ExactMatch, vec![AUTHORITY_HASH], MissingAction::Fail),
+        ConstraintSpec::new(ConstraintType::ExactMatch, vec![MODE], MissingAction::Fail),
+        ConstraintSpec::new(
+            ConstraintType::GreaterOrEqual,
+            vec![CONFIG_DESC, SECURITY_VERSION],
+            MissingAction::Ignore,
+        ),
+    ];
+
+    DicePolicy::from_dice_chain(dice, &constraint_spec).unwrap().to_vec().unwrap()
+}
+
+/// Perform AuthGraph key exchange, returning the session keys and session ID.
+fn authgraph_key_exchange(sk: binder::Strong<dyn ISecretkeeper>) -> ([key::AesKey; 2], Vec<u8>) {
+    let sink = sk.getAuthGraphKe().expect("failed to get AuthGraph");
+    let mut source = ag_vts::test_ag_participant().expect("failed to create a local source");
+    ag_vts::sink::test_mainline(&mut source, sink)
+}
+
+// Test that the AuthGraph instance returned by SecretKeeper correctly performs
+// mainline key exchange against a local source implementation.
+#[rdroidtest(get_instances())]
+fn authgraph_mainline(instance: String) {
+    let sk = get_connection(&instance);
+    let (_aes_keys, _session_id) = authgraph_key_exchange(sk);
+}
+
+// Test that the AuthGraph instance returned by SecretKeeper correctly rejects
+// a corrupted session ID signature.
+#[rdroidtest(get_instances())]
+fn authgraph_corrupt_sig(instance: String) {
+    let sk = get_connection(&instance);
+    let sink = sk.getAuthGraphKe().expect("failed to get AuthGraph");
+    let mut source = ag_vts::test_ag_participant().expect("failed to create a local source");
+    ag_vts::sink::test_corrupt_sig(&mut source, sink);
+}
+
+// Test that the AuthGraph instance returned by SecretKeeper correctly detects
+// when corrupted keys are returned to it.
+#[rdroidtest(get_instances())]
+fn authgraph_corrupt_keys(instance: String) {
+    let sk = get_connection(&instance);
+    let sink = sk.getAuthGraphKe().expect("failed to get AuthGraph");
+    let mut source = ag_vts::test_ag_participant().expect("failed to create a local source");
+    ag_vts::sink::test_corrupt_keys(&mut source, sink);
+}
+
+// TODO(b/2797757): Add tests that match different HAL defined objects (like request/response)
+// with expected bytes.
+
+#[rdroidtest(get_instances())]
+fn secret_management_get_version(instance: String) {
+    let mut sk_client = SkClient::new(&instance);
+
+    let request = GetVersionRequest {};
+    let request_packet = request.serialize_to_packet();
+    let request_bytes = request_packet.to_vec().unwrap();
+
+    let response_bytes = sk_client.secret_management_request(&request_bytes).unwrap();
+
+    let response_packet = ResponsePacket::from_slice(&response_bytes).unwrap();
+    assert_eq!(response_packet.response_type().unwrap(), ResponseType::Success);
+    let get_version_response =
+        *GetVersionResponse::deserialize_from_packet(response_packet).unwrap();
+    assert_eq!(get_version_response.version, CURRENT_VERSION);
+}
+
+#[rdroidtest(get_instances())]
+fn secret_management_malformed_request(instance: String) {
+    let mut sk_client = SkClient::new(&instance);
+
+    let request = GetVersionRequest {};
+    let request_packet = request.serialize_to_packet();
+    let mut request_bytes = request_packet.to_vec().unwrap();
+
+    // Deform the request
+    request_bytes[0] = !request_bytes[0];
+
+    let response_bytes = sk_client.secret_management_request(&request_bytes).unwrap();
+
+    let response_packet = ResponsePacket::from_slice(&response_bytes).unwrap();
+    assert_eq!(response_packet.response_type().unwrap(), ResponseType::Error);
+    let err = *SecretkeeperError::deserialize_from_packet(response_packet).unwrap();
+    assert_eq!(err, SecretkeeperError::RequestMalformed);
+}
+
+#[rdroidtest(get_instances())]
+fn secret_management_store_get_secret_found(instance: String) {
+    let mut sk_client = SkClient::new(&instance);
+
+    sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE).unwrap();
+
+    // Get the secret that was just stored
+    assert_eq!(sk_client.get(&ID_EXAMPLE).unwrap(), SECRET_EXAMPLE);
+}
+
+#[rdroidtest(get_instances())]
+fn secret_management_store_get_secret_not_found(instance: String) {
+    let mut sk_client = SkClient::new(&instance);
+
+    // Store a secret (corresponding to an id).
+    sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE).unwrap();
+
+    // Get the secret that was never stored
+    assert_entry_not_found(sk_client.get(&ID_NOT_STORED));
+}
+
+#[rdroidtest(get_instances())]
+fn secretkeeper_store_delete_ids(instance: String) {
+    let mut sk_client = SkClient::new(&instance);
+
+    sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE).unwrap();
+    sk_client.store(&ID_EXAMPLE_2, &SECRET_EXAMPLE).unwrap();
+    sk_client.delete(&[&ID_EXAMPLE]);
+    assert_entry_not_found(sk_client.get(&ID_EXAMPLE));
+    assert_eq!(sk_client.get(&ID_EXAMPLE_2).unwrap(), SECRET_EXAMPLE);
+
+    sk_client.delete(&[&ID_EXAMPLE_2]);
+
+    assert_entry_not_found(sk_client.get(&ID_EXAMPLE));
+    assert_entry_not_found(sk_client.get(&ID_EXAMPLE_2));
+}
+
+#[rdroidtest(get_instances())]
+fn secretkeeper_store_delete_multiple_ids(instance: String) {
+    let mut sk_client = SkClient::new(&instance);
+
+    sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE).unwrap();
+    sk_client.store(&ID_EXAMPLE_2, &SECRET_EXAMPLE).unwrap();
+    sk_client.delete(&[&ID_EXAMPLE, &ID_EXAMPLE_2]);
+
+    assert_entry_not_found(sk_client.get(&ID_EXAMPLE));
+    assert_entry_not_found(sk_client.get(&ID_EXAMPLE_2));
+}
+#[rdroidtest(get_instances())]
+fn secretkeeper_store_delete_duplicate_ids(instance: String) {
+    let mut sk_client = SkClient::new(&instance);
+
+    sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE).unwrap();
+    sk_client.store(&ID_EXAMPLE_2, &SECRET_EXAMPLE).unwrap();
+    // Delete the same secret twice.
+    sk_client.delete(&[&ID_EXAMPLE, &ID_EXAMPLE]);
+
+    assert_entry_not_found(sk_client.get(&ID_EXAMPLE));
+    assert_eq!(sk_client.get(&ID_EXAMPLE_2).unwrap(), SECRET_EXAMPLE);
+}
+
+#[rdroidtest(get_instances())]
+fn secretkeeper_store_delete_nonexistent(instance: String) {
+    let mut sk_client = SkClient::new(&instance);
+
+    sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE).unwrap();
+    sk_client.store(&ID_EXAMPLE_2, &SECRET_EXAMPLE).unwrap();
+    sk_client.delete(&[&ID_NOT_STORED]);
+
+    assert_eq!(sk_client.get(&ID_EXAMPLE).unwrap(), SECRET_EXAMPLE);
+    assert_eq!(sk_client.get(&ID_EXAMPLE_2).unwrap(), SECRET_EXAMPLE);
+    assert_entry_not_found(sk_client.get(&ID_NOT_STORED));
+}
+
+// Don't run deleteAll() on a secure device, as it might affect real secrets.
+#[rdroidtest(get_instances())]
+#[ignore_if(|p| p != "nonsecure")]
+fn secretkeeper_store_delete_all(instance: String) {
+    let mut sk_client = SkClient::new(&instance);
+
+    sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE).unwrap();
+    sk_client.store(&ID_EXAMPLE_2, &SECRET_EXAMPLE).unwrap();
+
+    sk_client.delete_all();
+
+    assert_entry_not_found(sk_client.get(&ID_EXAMPLE));
+    assert_entry_not_found(sk_client.get(&ID_EXAMPLE_2));
+
+    // Store a new secret (corresponding to an id).
+    sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE).unwrap();
+
+    // Get the restored secret.
+    assert_eq!(sk_client.get(&ID_EXAMPLE).unwrap(), SECRET_EXAMPLE);
+
+    // (Try to) Get the secret that was never stored
+    assert_entry_not_found(sk_client.get(&ID_NOT_STORED));
+}
+
+// This test checks that Secretkeeper uses the expected [`RequestSeqNum`] as aad while
+// decrypting requests and the responses are encrypted with correct [`ResponseSeqNum`] for the
+// first few messages.
+#[rdroidtest(get_instances())]
+fn secret_management_replay_protection_seq_num(instance: String) {
+    let dice_chain = make_explicit_owned_dice(/*Security version in a node */ 5);
+    let sealing_policy = sealing_policy(dice_chain.explicit_key_dice_chain().unwrap());
+    let sk_client = SkClient::with_identity(&instance, dice_chain);
+    // Construct encoded request packets for the test
+    let (req_1, req_2, req_3) = construct_secret_management_requests(sealing_policy);
+
+    // Lets now construct the seq_numbers(in request & expected in response)
+    let mut seq_a = SeqNum::new();
+    let [seq_0, seq_1, seq_2] = std::array::from_fn(|_| seq_a.get_then_increment().unwrap());
+
+    // Check first request/response is successful
+    let res = ResponsePacket::from_slice(
+        &sk_client.secret_management_request_custom_aad(&req_1, &seq_0, &seq_0).unwrap(),
+    )
+    .unwrap();
+    assert_eq!(res.response_type().unwrap(), ResponseType::Success);
+
+    // Check 2nd request/response is successful
+    let res = ResponsePacket::from_slice(
+        &sk_client.secret_management_request_custom_aad(&req_2, &seq_1, &seq_1).unwrap(),
+    )
+    .unwrap();
+    assert_eq!(res.response_type().unwrap(), ResponseType::Success);
+
+    // Check 3rd request/response is successful
+    let res = ResponsePacket::from_slice(
+        &sk_client.secret_management_request_custom_aad(&req_3, &seq_2, &seq_2).unwrap(),
+    )
+    .unwrap();
+    assert_eq!(res.response_type().unwrap(), ResponseType::Success);
+}
+
+// This test checks that Secretkeeper uses fresh [`RequestSeqNum`] & [`ResponseSeqNum`]
+// for new sessions.
+#[rdroidtest(get_instances())]
+fn secret_management_replay_protection_seq_num_per_session(instance: String) {
+    let dice_chain = make_explicit_owned_dice(/*Security version in a node */ 5);
+    let sealing_policy = sealing_policy(dice_chain.explicit_key_dice_chain().unwrap());
+    let sk_client = SkClient::with_identity(&instance, dice_chain);
+
+    // Construct encoded request packets for the test
+    let (req_1, _, _) = construct_secret_management_requests(sealing_policy);
+
+    // Lets now construct the seq_number (in request & expected in response)
+    let mut seq_a = SeqNum::new();
+    let seq_0 = seq_a.get_then_increment().unwrap();
+    // Check first request/response is successful
+    let res = ResponsePacket::from_slice(
+        &sk_client.secret_management_request_custom_aad(&req_1, &seq_0, &seq_0).unwrap(),
+    )
+    .unwrap();
+    assert_eq!(res.response_type().unwrap(), ResponseType::Success);
+
+    // Start another session
+    let sk_client_diff = SkClient::new(&instance);
+    // Check first request/response is with seq_0 is successful
+    let res = ResponsePacket::from_slice(
+        &sk_client_diff.secret_management_request_custom_aad(&req_1, &seq_0, &seq_0).unwrap(),
+    )
+    .unwrap();
+    assert_eq!(res.response_type().unwrap(), ResponseType::Success);
+}
+
+// This test checks that Secretkeeper rejects requests with out of order [`RequestSeqNum`]
+// TODO(b/317416663): This test fails, when HAL is not present in the device. Refactor to fix this.
+#[rdroidtest(get_instances())]
+fn secret_management_replay_protection_out_of_seq_req_not_accepted(instance: String) {
+    let dice_chain = make_explicit_owned_dice(/*Security version in a node */ 5);
+    let sealing_policy = sealing_policy(dice_chain.explicit_key_dice_chain().unwrap());
+    let sk_client = SkClient::with_identity(&instance, dice_chain);
+
+    // Construct encoded request packets for the test
+    let (req_1, req_2, _) = construct_secret_management_requests(sealing_policy);
+
+    // Lets now construct the seq_numbers(in request & expected in response)
+    let mut seq_a = SeqNum::new();
+    let [seq_0, seq_1, seq_2] = std::array::from_fn(|_| seq_a.get_then_increment().unwrap());
+
+    // Assume First request/response is successful
+    sk_client.secret_management_request_custom_aad(&req_1, &seq_0, &seq_0).unwrap();
+
+    // Check 2nd request/response with skipped seq_num in request is a binder error
+    let res = sk_client
+        .secret_management_request_custom_aad(&req_2, /*Skipping seq_1*/ &seq_2, &seq_1);
+    let err = res.expect_err("Out of Seq messages accepted!");
+    // Incorrect sequence numbers lead to failed decryption. The resultant error should be
+    // thrown in clear text & wrapped in Binder errors.
+    assert!(matches!(err, Error::InfraError(secretkeeper_client::Error::BinderStatus(_e))));
+}
+
+// This test checks DICE policy based access control of Secretkeeper.
+#[rdroidtest(get_instances())]
+fn secret_management_policy_gate(instance: String) {
+    let dice_chain = make_explicit_owned_dice(/*Security version in a node */ 100);
+    let mut sk_client = SkClient::with_identity(&instance, dice_chain);
+    sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE).unwrap();
+
+    // Start a session with higher security_version & get the stored secret.
+    let dice_chain_upgraded = make_explicit_owned_dice(/*Security version in a node */ 101);
+    let mut sk_client_upgraded = SkClient::with_identity(&instance, dice_chain_upgraded);
+    assert_eq!(sk_client_upgraded.get(&ID_EXAMPLE).unwrap(), SECRET_EXAMPLE);
+
+    // Start a session with lower security_version (This should be denied access to the secret).
+    let dice_chain_downgraded = make_explicit_owned_dice(/*Security version in a node */ 99);
+    let mut sk_client_downgraded = SkClient::with_identity(&instance, dice_chain_downgraded);
+    assert!(matches!(
+        sk_client_downgraded.get(&ID_EXAMPLE).unwrap_err(),
+        Error::SecretkeeperError(SecretkeeperError::DicePolicyError)
+    ));
+}
+
+// Helper method that constructs 3 SecretManagement requests. Callers would usually not care about
+// what each of the request concretely is.
+fn construct_secret_management_requests(sealing_policy: Vec<u8>) -> (Vec<u8>, Vec<u8>, Vec<u8>) {
+    let version_request = GetVersionRequest {};
+    let version_request = version_request.serialize_to_packet().to_vec().unwrap();
+    let store_request =
+        StoreSecretRequest { id: ID_EXAMPLE, secret: SECRET_EXAMPLE, sealing_policy };
+    let store_request = store_request.serialize_to_packet().to_vec().unwrap();
+    let get_request = GetSecretRequest { id: ID_EXAMPLE, updated_sealing_policy: None };
+    let get_request = get_request.serialize_to_packet().to_vec().unwrap();
+    (version_request, store_request, get_request)
+}
+
+rdroidtest::test_main!();
diff --git a/security/secretkeeper/default/Android.bp b/security/secretkeeper/default/Android.bp
new file mode 100644
index 0000000..d8ccb63
--- /dev/null
+++ b/security/secretkeeper/default/Android.bp
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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"],
+}
+
+rust_library {
+    name: "libsecretkeeper_nonsecure",
+    crate_name: "secretkeeper_nonsecure",
+    srcs: [
+        "src/lib.rs",
+    ],
+    vendor_available: true,
+    defaults: [
+        "authgraph_use_latest_hal_aidl_rust",
+    ],
+    rustlibs: [
+        "android.hardware.security.secretkeeper-V1-rust",
+        "libauthgraph_boringssl",
+        "libauthgraph_core",
+        "libauthgraph_hal",
+        "libbinder_rs",
+        "libcoset",
+        "liblog_rust",
+        "libsecretkeeper_core_nostd",
+        "libsecretkeeper_comm_nostd",
+    ],
+}
+
+rust_binary {
+    name: "android.hardware.security.secretkeeper-service.nonsecure",
+    relative_install_path: "hw",
+    vendor: true,
+    installable: false, // install APEX
+    prefer_rlib: true,
+    defaults: [
+        "authgraph_use_latest_hal_aidl_rust",
+    ],
+    rustlibs: [
+        "android.hardware.security.secretkeeper-V1-rust",
+        "libandroid_logger",
+        "libbinder_rs",
+        "liblog_rust",
+        "libsecretkeeper_hal",
+        "libsecretkeeper_nonsecure",
+    ],
+    srcs: [
+        "src/main.rs",
+    ],
+}
+
+rust_fuzz {
+    name: "android.hardware.security.secretkeeper-service.nonsecure_fuzzer",
+    rustlibs: [
+        "libsecretkeeper_hal",
+        "libsecretkeeper_nonsecure",
+        "libbinder_random_parcel_rs",
+        "libbinder_rs",
+    ],
+    srcs: ["src/fuzzer.rs"],
+    fuzz_config: {
+        cc: [
+            "alanstokes@google.com",
+            "drysdale@google.com",
+            "shikhapanwar@google.com",
+        ],
+    },
+}
+
+prebuilt_etc {
+    name: "secretkeeper.rc",
+    src: "secretkeeper.rc",
+    installable: false,
+}
+
+prebuilt_etc {
+    name: "secretkeeper.xml",
+    src: "secretkeeper.xml",
+    sub_dir: "vintf",
+    installable: false,
+}
+
+apex {
+    name: "com.android.hardware.security.secretkeeper",
+    manifest: "apex_manifest.json",
+    file_contexts: "apex_file_contexts",
+    key: "com.android.hardware.key",
+    certificate: ":com.android.hardware.certificate",
+    vendor: true,
+    updatable: false,
+
+    binaries: [
+        "android.hardware.security.secretkeeper-service.nonsecure",
+    ],
+    prebuilts: [
+        "secretkeeper.rc",
+        "secretkeeper.xml",
+    ],
+}
diff --git a/security/secretkeeper/default/apex_file_contexts b/security/secretkeeper/default/apex_file_contexts
new file mode 100644
index 0000000..71369a8
--- /dev/null
+++ b/security/secretkeeper/default/apex_file_contexts
@@ -0,0 +1,3 @@
+(/.*)?                                          u:object_r:vendor_file:s0
+/etc(/.*)?                                      u:object_r:vendor_configs_file:s0
+/bin/hw/android\.hardware\.security\.secretkeeper-service\.nonsecure  u:object_r:hal_secretkeeper_default_exec:s0
diff --git a/security/secretkeeper/default/apex_manifest.json b/security/secretkeeper/default/apex_manifest.json
new file mode 100644
index 0000000..7287095
--- /dev/null
+++ b/security/secretkeeper/default/apex_manifest.json
@@ -0,0 +1,4 @@
+{
+    "name": "com.android.hardware.security.secretkeeper",
+    "version": 1
+}
\ No newline at end of file
diff --git a/security/secretkeeper/default/secretkeeper.rc b/security/secretkeeper/default/secretkeeper.rc
new file mode 100644
index 0000000..38ee50d
--- /dev/null
+++ b/security/secretkeeper/default/secretkeeper.rc
@@ -0,0 +1,5 @@
+service vendor.secretkeeper /apex/com.android.hardware.security.secretkeeper/bin/hw/android.hardware.security.secretkeeper-service.nonsecure
+    interface aidl android.hardware.security.secretkeeper.ISecretkeeper/nonsecure
+    class hal
+    user nobody
+    group nobody
diff --git a/security/secretkeeper/default/secretkeeper.xml b/security/secretkeeper/default/secretkeeper.xml
new file mode 100644
index 0000000..40aebe0
--- /dev/null
+++ b/security/secretkeeper/default/secretkeeper.xml
@@ -0,0 +1,28 @@
+<manifest version="1.0" type="device">
+<!--
+/*
+** Copyright 2022, The Android Open Source Project.
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+    <hal format="aidl">
+        <name>android.hardware.security.secretkeeper</name>
+        <version>1</version>
+        <interface>
+            <name>ISecretkeeper</name>
+            <instance>nonsecure</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/security/secretkeeper/default/src/fuzzer.rs b/security/secretkeeper/default/src/fuzzer.rs
new file mode 100644
index 0000000..914ebe6
--- /dev/null
+++ b/security/secretkeeper/default/src/fuzzer.rs
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#![allow(missing_docs)]
+#![no_main]
+extern crate libfuzzer_sys;
+
+use binder_random_parcel_rs::fuzz_service;
+use libfuzzer_sys::fuzz_target;
+use secretkeeper_hal::SecretkeeperService;
+use secretkeeper_nonsecure::{AuthGraphChannel, LocalTa, SecretkeeperChannel};
+use std::sync::{Arc, Mutex};
+
+fuzz_target!(|data: &[u8]| {
+    let ta = Arc::new(Mutex::new(LocalTa::new()));
+    let ag_channel = AuthGraphChannel(ta.clone());
+    let sk_channel = SecretkeeperChannel(ta.clone());
+
+    let service = SecretkeeperService::new_as_binder(sk_channel, ag_channel);
+    fuzz_service(&mut service.as_binder(), data);
+});
diff --git a/security/secretkeeper/default/src/lib.rs b/security/secretkeeper/default/src/lib.rs
new file mode 100644
index 0000000..eb7817c
--- /dev/null
+++ b/security/secretkeeper/default/src/lib.rs
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! Non-secure implementation of a local Secretkeeper TA.
+
+use authgraph_boringssl as boring;
+use authgraph_core::keyexchange::{AuthGraphParticipant, MAX_OPENED_SESSIONS};
+use authgraph_core::ta::{AuthGraphTa, Role};
+use authgraph_hal::channel::SerializedChannel;
+use log::error;
+use secretkeeper_core::ta::SecretkeeperTa;
+use std::cell::RefCell;
+use std::rc::Rc;
+use std::sync::mpsc;
+use std::sync::{Arc, Mutex};
+
+mod store;
+
+/// Implementation of the Secrekeeper TA that runs locally in-process (and which is therefore
+/// insecure).
+pub struct LocalTa {
+    in_tx: mpsc::Sender<Vec<u8>>,
+    out_rx: mpsc::Receiver<Vec<u8>>,
+}
+
+/// Prefix byte for messages intended for the AuthGraph TA.
+const AG_MESSAGE_PREFIX: u8 = 0x00;
+/// Prefix byte for messages intended for the Secretkeeper TA.
+const SK_MESSAGE_PREFIX: u8 = 0x01;
+
+impl LocalTa {
+    /// Create a new instance.
+    pub fn new() -> Self {
+        // Create a pair of channels to communicate with the TA thread.
+        let (in_tx, in_rx) = mpsc::channel();
+        let (out_tx, out_rx) = mpsc::channel();
+
+        // The TA code expects to run single threaded, so spawn a thread to run it in.
+        std::thread::spawn(move || {
+            let mut crypto_impls = boring::crypto_trait_impls();
+            let storage_impl = Box::new(store::InMemoryStore::default());
+            let sk_ta = Rc::new(RefCell::new(
+                SecretkeeperTa::new(
+                    &mut crypto_impls,
+                    storage_impl,
+                    coset::iana::EllipticCurve::Ed25519,
+                )
+                .expect("Failed to create local Secretkeeper TA"),
+            ));
+            let mut ag_ta = AuthGraphTa::new(
+                AuthGraphParticipant::new(crypto_impls, sk_ta.clone(), MAX_OPENED_SESSIONS)
+                    .expect("Failed to create local AuthGraph TA"),
+                Role::Sink,
+            );
+
+            // Loop forever processing request messages.
+            loop {
+                let req_data: Vec<u8> = match in_rx.recv() {
+                    Ok(data) => data,
+                    Err(_) => {
+                        error!("local TA failed to receive request!");
+                        break;
+                    }
+                };
+                let rsp_data = match req_data[0] {
+                    AG_MESSAGE_PREFIX => ag_ta.process(&req_data[1..]),
+                    SK_MESSAGE_PREFIX => {
+                        // It's safe to `borrow_mut()` because this code is not a callback
+                        // from AuthGraph (the only other holder of an `Rc`), and so there
+                        // can be no live `borrow()`s in this (single) thread.
+                        sk_ta.borrow_mut().process(&req_data[1..])
+                    }
+                    prefix => panic!("unexpected messageprefix {prefix}!"),
+                };
+                match out_tx.send(rsp_data) {
+                    Ok(_) => {}
+                    Err(_) => {
+                        error!("local TA failed to send out response");
+                        break;
+                    }
+                }
+            }
+            error!("local TA terminating!");
+        });
+        Self { in_tx, out_rx }
+    }
+
+    fn execute_for(&mut self, prefix: u8, req_data: &[u8]) -> Vec<u8> {
+        let mut prefixed_req = Vec::with_capacity(req_data.len() + 1);
+        prefixed_req.push(prefix);
+        prefixed_req.extend_from_slice(req_data);
+        self.in_tx
+            .send(prefixed_req)
+            .expect("failed to send in request");
+        self.out_rx.recv().expect("failed to receive response")
+    }
+}
+
+pub struct AuthGraphChannel(pub Arc<Mutex<LocalTa>>);
+
+impl SerializedChannel for AuthGraphChannel {
+    const MAX_SIZE: usize = usize::MAX;
+    fn execute(&self, req_data: &[u8]) -> binder::Result<Vec<u8>> {
+        Ok(self
+            .0
+            .lock()
+            .unwrap()
+            .execute_for(AG_MESSAGE_PREFIX, req_data))
+    }
+}
+
+pub struct SecretkeeperChannel(pub Arc<Mutex<LocalTa>>);
+
+impl SerializedChannel for SecretkeeperChannel {
+    const MAX_SIZE: usize = usize::MAX;
+    fn execute(&self, req_data: &[u8]) -> binder::Result<Vec<u8>> {
+        Ok(self
+            .0
+            .lock()
+            .unwrap()
+            .execute_for(SK_MESSAGE_PREFIX, req_data))
+    }
+}
diff --git a/security/secretkeeper/default/src/main.rs b/security/secretkeeper/default/src/main.rs
new file mode 100644
index 0000000..436f9a7
--- /dev/null
+++ b/security/secretkeeper/default/src/main.rs
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! Non-secure implementation of the Secretkeeper HAL.
+
+use log::{error, info, Level};
+use secretkeeper_hal::SecretkeeperService;
+use secretkeeper_nonsecure::{AuthGraphChannel, SecretkeeperChannel, LocalTa};
+use std::sync::{Arc, Mutex};
+use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper::ISecretkeeper::{
+    BpSecretkeeper, ISecretkeeper,
+};
+
+fn main() {
+    // Initialize Android logging.
+    android_logger::init_once(
+        android_logger::Config::default()
+            .with_tag("NonSecureSecretkeeper")
+            .with_min_level(Level::Info)
+            .with_log_id(android_logger::LogId::System),
+    );
+    // Redirect panic messages to logcat.
+    std::panic::set_hook(Box::new(|panic_info| {
+        error!("{}", panic_info);
+    }));
+
+    let ta = Arc::new(Mutex::new(LocalTa::new()));
+    let ag_channel = AuthGraphChannel(ta.clone());
+    let sk_channel = SecretkeeperChannel(ta.clone());
+
+    let service = SecretkeeperService::new_as_binder(sk_channel, ag_channel);
+    let service_name = format!(
+        "{}/nonsecure",
+        <BpSecretkeeper as ISecretkeeper>::get_descriptor()
+    );
+    binder::add_service(&service_name, service.as_binder()).unwrap_or_else(|e| {
+        panic!("Failed to register service {service_name} because of {e:?}.",);
+    });
+    info!("Registered Binder service, joining threadpool.");
+    binder::ProcessState::join_thread_pool();
+}
diff --git a/security/secretkeeper/default/src/store.rs b/security/secretkeeper/default/src/store.rs
new file mode 100644
index 0000000..6c7dba1
--- /dev/null
+++ b/security/secretkeeper/default/src/store.rs
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! In-memory store for nonsecure Secretkeeper.
+
+use secretkeeper_comm::data_types::error::Error;
+use secretkeeper_core::store::KeyValueStore;
+use std::collections::HashMap;
+
+/// An in-memory implementation of [`KeyValueStore`]. Please note that this is entirely for testing
+/// purposes. Refer to the documentation of `PolicyGatedStorage` and Secretkeeper HAL for
+/// persistence requirements.
+#[derive(Default)]
+pub struct InMemoryStore(HashMap<Vec<u8>, Vec<u8>>);
+impl KeyValueStore for InMemoryStore {
+    fn store(&mut self, key: &[u8], val: &[u8]) -> Result<(), Error> {
+        // This will overwrite the value if key is already present.
+        let _ = self.0.insert(key.to_vec(), val.to_vec());
+        Ok(())
+    }
+
+    fn get(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Error> {
+        let optional_val = self.0.get(key);
+        Ok(optional_val.cloned())
+    }
+
+    fn delete(&mut self, key: &[u8]) -> Result<(), Error> {
+        self.0.remove(key);
+        Ok(())
+    }
+
+    fn delete_all(&mut self) -> Result<(), Error> {
+        self.0.clear();
+        Ok(())
+    }
+}
diff --git a/security/sharedsecret/aidl/vts/functional/SharedSecretAidlTest.cpp b/security/sharedsecret/aidl/vts/functional/SharedSecretAidlTest.cpp
index 51938ba..7599bce 100644
--- a/security/sharedsecret/aidl/vts/functional/SharedSecretAidlTest.cpp
+++ b/security/sharedsecret/aidl/vts/functional/SharedSecretAidlTest.cpp
@@ -164,7 +164,7 @@
     auto nonces = copyNonces(params);
     EXPECT_EQ(sharedSecrets.size(), nonces.size());
     std::sort(nonces.begin(), nonces.end());
-    std::unique(nonces.begin(), nonces.end());
+    nonces.erase(std::unique(nonces.begin(), nonces.end()), nonces.end());
     EXPECT_EQ(sharedSecrets.size(), nonces.size());
 
     auto responses = computeAllSharedSecrets(params);
diff --git a/sensors/2.1/vts/functional/AndroidTest.xml b/sensors/2.1/vts/functional/AndroidTest.xml
index 2ef8dc6..2d21c7f 100644
--- a/sensors/2.1/vts/functional/AndroidTest.xml
+++ b/sensors/2.1/vts/functional/AndroidTest.xml
@@ -22,13 +22,13 @@
 
     <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
         <option name="cleanup" value="true" />
-        <option name="push" value="VtsHalSensorsV2_1TargetTest->/data/local/tmp/VtsHalSensorsV2_1TargetTest" />
+        <option name="push" value="VtsHalSensorsV2_1TargetTest->/data/local/tests/unrestricted/VtsHalSensorsV2_1TargetTest" />
     </target_preparer>
 
     <test class="com.android.tradefed.testtype.GTest" >
         <option name="native-test-timeout" value="900000" />
         <option name="runtime-hint" value="300000"/>
-        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="native-test-device-path" value="/data/local/tests/unrestricted" />
         <option name="module-name" value="VtsHalSensorsV2_1TargetTest" />
     </test>
 </configuration>
diff --git a/sensors/2.1/vts/functional/TEST_MAPPING b/sensors/2.1/vts/functional/TEST_MAPPING
new file mode 100644
index 0000000..0129f39
--- /dev/null
+++ b/sensors/2.1/vts/functional/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "VtsHalSensorsV2_1TargetTest"
+    }
+  ],
+  "kernel-presubmit": [
+    {
+      "name": "VtsHalSensorsV2_1TargetTest"
+    }
+  ]
+}
diff --git a/sensors/aidl/TEST_MAPPING b/sensors/aidl/TEST_MAPPING
new file mode 100644
index 0000000..6de4549
--- /dev/null
+++ b/sensors/aidl/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "VtsAidlHalSensorsTargetTest"
+    }
+  ],
+  "kernel-presubmit": [
+    {
+      "name": "VtsAidlHalSensorsTargetTest"
+    }
+  ]
+}
diff --git a/sensors/aidl/default/Android.bp b/sensors/aidl/default/Android.bp
index 16b4d35..e93c391 100644
--- a/sensors/aidl/default/Android.bp
+++ b/sensors/aidl/default/Android.bp
@@ -23,16 +23,6 @@
     default_applicable_licenses: ["hardware_interfaces_license"],
 }
 
-filegroup {
-    name: "sensors-default.rc",
-    srcs: ["sensors-default.rc"],
-}
-
-filegroup {
-    name: "sensors-default.xml",
-    srcs: ["sensors-default.xml"],
-}
-
 cc_library_static {
     name: "libsensorsexampleimpl",
     vendor: true,
@@ -57,21 +47,55 @@
 cc_binary {
     name: "android.hardware.sensors-service.example",
     relative_install_path: "hw",
-    init_rc: [":sensors-default.rc"],
-    vintf_fragments: [":sensors-default.xml"],
+    installable: false, // install APEX below
+
     vendor: true,
     shared_libs: [
-        "libbase",
         "libbinder_ndk",
-        "libfmq",
-        "libpower",
-        "libcutils",
         "liblog",
-        "libutils",
-        "android.hardware.sensors-V2-ndk",
     ],
     static_libs: [
+        "android.hardware.common-V2-ndk",
+        "android.hardware.common.fmq-V1-ndk",
+        "android.hardware.sensors-V2-ndk",
+        "android.system.suspend-V1-ndk",
+        "libbase",
+        "libcutils",
+        "libfmq",
+        "libpower",
         "libsensorsexampleimpl",
+        "libutils",
     ],
     srcs: ["main.cpp"],
 }
+
+prebuilt_etc {
+    name: "sensors-default.rc",
+    src: "sensors-default.rc",
+    installable: false,
+}
+
+prebuilt_etc {
+    name: "sensors-default.xml",
+    src: "sensors-default.xml",
+    sub_dir: "vintf",
+    installable: false,
+}
+
+// Default vendor APEX for android.hardware.sensors.
+// Custom implementations may use override_apex based on this APEX.
+apex {
+    name: "com.android.hardware.sensors",
+    manifest: "apex_manifest.json",
+    key: "com.android.hardware.key",
+    certificate: ":com.android.hardware.certificate",
+    file_contexts: "file_contexts",
+    updatable: false,
+    vendor: true,
+
+    binaries: ["android.hardware.sensors-service.example"],
+    prebuilts: [
+        "sensors-default.rc", // init rc
+        "sensors-default.xml", // vintf fragment
+    ],
+}
diff --git a/sensors/aidl/default/Sensor.cpp b/sensors/aidl/default/Sensor.cpp
index 3bdd8b6..ca3eb14 100644
--- a/sensors/aidl/default/Sensor.cpp
+++ b/sensors/aidl/default/Sensor.cpp
@@ -268,7 +268,7 @@
     mSensorInfo.fifoReservedEventCount = 0;
     mSensorInfo.fifoMaxEventCount = 0;
     mSensorInfo.requiredPermission = "";
-    mSensorInfo.flags = 0;
+    mSensorInfo.flags = static_cast<uint32_t>(SensorInfo::SENSOR_FLAG_BITS_DATA_INJECTION);
 };
 
 void MagnetometerSensor::readEventPayload(EventPayload& payload) {
@@ -343,7 +343,7 @@
     mSensorInfo.fifoReservedEventCount = 0;
     mSensorInfo.fifoMaxEventCount = 0;
     mSensorInfo.requiredPermission = "";
-    mSensorInfo.flags = 0;
+    mSensorInfo.flags = static_cast<uint32_t>(SensorInfo::SENSOR_FLAG_BITS_DATA_INJECTION);
 };
 
 void GyroSensor::readEventPayload(EventPayload& payload) {
diff --git a/sensors/aidl/default/apex/Android.bp b/sensors/aidl/default/apex/Android.bp
deleted file mode 100644
index ceb428b..0000000
--- a/sensors/aidl/default/apex/Android.bp
+++ /dev/null
@@ -1,53 +0,0 @@
-package {
-    default_applicable_licenses: ["hardware_interfaces_license"],
-}
-
-apex_key {
-    name: "com.android.hardware.sensors.key",
-    public_key: "com.android.hardware.sensors.avbpubkey",
-    private_key: "com.android.hardware.sensors.pem",
-}
-
-android_app_certificate {
-    name: "com.android.hardware.sensors.certificate",
-    certificate: "com.android.hardware.sensors",
-}
-
-genrule {
-    name: "com.android.hardware.sensors.rc-gen",
-    srcs: [":sensors-default.rc"],
-    out: ["com.android.hardware.sensors.rc"],
-    cmd: "sed -E 's/\\/vendor/\\/apex\\/com.android.hardware.sensors/' $(in) > $(out)",
-}
-
-prebuilt_etc {
-    name: "com.android.hardware.sensors.rc",
-    src: ":com.android.hardware.sensors.rc-gen",
-    installable: false,
-}
-
-// Default vendor APEX for android.hardware.sensors.
-// Custom implementations may use override_apex based on this APEX.
-apex {
-    name: "com.android.hardware.sensors",
-    manifest: "apex_manifest.json",
-    key: "com.android.hardware.sensors.key",
-    certificate: ":com.android.hardware.sensors.certificate",
-    file_contexts: "file_contexts",
-    use_vndk_as_stable: true,
-    updatable: false,
-    // Install the apex in /vendor/apex
-    soc_specific: true,
-    binaries: ["android.hardware.sensors-service.example"],
-    prebuilts: [
-        "com.android.hardware.sensors.rc",
-        "android.hardware.sensor.ambient_temperature.prebuilt.xml",
-        "android.hardware.sensor.barometer.prebuilt.xml",
-        "android.hardware.sensor.gyroscope.prebuilt.xml",
-        "android.hardware.sensor.hinge_angle.prebuilt.xml",
-        "android.hardware.sensor.light.prebuilt.xml",
-        "android.hardware.sensor.proximity.prebuilt.xml",
-        "android.hardware.sensor.relative_humidity.prebuilt.xml",
-    ],
-    vintf_fragments: [":sensors-default.xml"],
-}
diff --git a/sensors/aidl/default/apex/com.android.hardware.sensors.avbpubkey b/sensors/aidl/default/apex/com.android.hardware.sensors.avbpubkey
deleted file mode 100644
index 98dfb71..0000000
--- a/sensors/aidl/default/apex/com.android.hardware.sensors.avbpubkey
+++ /dev/null
Binary files differ
diff --git a/sensors/aidl/default/apex/com.android.hardware.sensors.pem b/sensors/aidl/default/apex/com.android.hardware.sensors.pem
deleted file mode 100644
index a2f1833..0000000
--- a/sensors/aidl/default/apex/com.android.hardware.sensors.pem
+++ /dev/null
@@ -1,51 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIIJKAIBAAKCAgEArUwl9rjXtNrSqJ2rfEryTnVEte7uhZlsn42rXRHFZtuV8N03
-AKAFDDkhJIT+FqmVJLW1Whrno+goaKzA23BodZcSo/xOJuTopgQ/TVqIO2QZ2WUS
-1NiYT3+kydZgtBHhfS+ek9h6aTLgJUn/XBX2xgEA6kp/NkcLpGkqj9Xs7XUpG+n/
-KnyYg+/YFqooEKHTTi4dT9YgRblgzv5zhCKxjB9gqy8dmhwDTpbPGavNiMIZvnSs
-aQzXh7+UMwte+V4QdaEqonoVWm85vEh6rsPpvvmxvlkVnUstRWRwsvbA183gvwZg
-f7OmAgpVu0kEkSHpoJJWpDUhzxmTdxmwvmL92eCJqQUjvxLqak4uBt+epUgbgxcA
-nS7rNg6PsNlHhYl5wRArPP17iW/QK3qnoz8rKgJCtdxPPD13byA13eY9q+Fdwb2H
-uHxGu1iYlRxUAzptvb6pIED/v9MMw/g3yMJkR89WG+pBLbUXHko6H0qOVchYrd8C
-OtcGo7GBBPbJmj9ZGZDX7p5YBSdTZs8f9wWqJmXkfVR60zZE0dOnOchzL44c8oUh
-uwEZMee7Ae/2LfWnfIe5KBNTvvH1CzU8KbQUJJVbATbb3j/eYExgsbnk0WgFi6i4
-osuJZZmfC44tAg18gXozcji+xYuW3MIMV2+drdc3xXn7LXKn5JZCLVJ6n+cCAwEA
-AQKCAgATT6P/XVO0NJo67e75F8Tul0TD3U85FgKzuO66nUtZDekkgRIrAKnvVcJq
-tmM2FUmoYJNH6i2b5zfxiianjVwmlmIeYfQ3g1Slg12megsqSxpSTmAN1eELItcz
-Iq9+AWwWLiNGqF3jsSanIRrSoSPxppT6hrisTLhwZsO2aYlQYLjnAmlLy7yXHzf+
-NpHmYJISaTMc/Wh1PJYcGuC2fcM5MRntmX9799kqfcWwP6PUtIR347p+rk6qMuAJ
-3B+GPEQrR31fw6jzfed6Ir2BEhXPETYMVxMAhysRS4L/fl247pk30Dcao+NA4PPy
-vc1Devr0yLnc7IrK8DetkvBOFuvgl53gHPZ4f7ge2PQMPghwjBaFuXklcfY96PVw
-Yo/CyAN+VEANThFFcKUzovtHI6m3sNTlxE6F+AYvx5dE/WZKmE5/cYCSJ8bhLPJl
-G68VkdeNv0LMZ/7rf1OEWP/YWw/5/tQ7MJ0IO5GShjE2EAGG0SZgK8/fwHZZJFES
-oYVWlriGtGDfiYjPLqVIjdZI6iOo6BMQh6pl0TPIJpn3ODqtRy8gN3TMvG6VcTJy
-QE3Z+br7UsK4gXSw0+MNLC3VKhX2bjT5q9lVpVnLv4L7q1ad4kwHblFAo686ZbWt
-eKTUv7QTI3fFqYeZEgCqRBQZ3UoKyWOBg0MAbf26hZFTFFpbEQKCAQEA2JdW6wDM
-iO1haR168l497nUC382/f/fJA8vzFdJ7cHVM95Tx/5JNYNJSL30XDyux9RJNqnFu
-tByec4c5CVuX/Gv/B4Q++xaaI7OVT9hTl/aoTShObGRJGbVh8xZagb7on7dAfD6G
-1SzTaahxQT5neoiki13GvJ6teL+0ZbCxRDMfPyy79lRzH5d0mw+EQvtc0Vvkweyj
-zf/Mn0yMZHO19oCKjJo8QkciseOqaS2mpgtOiRDc01uuaFAcw6taiERrR86xK2Yl
-OowIx6Yu8n7jRyTGUfr2Oz97a/zDVMVRi3BuyePOyCD9PfUmoj9JyCFbQSS1Lq3N
-AWacnNwQpkDDiQKCAQEAzNQ3/hKhjrLyEm2ktQk1Tzyk4eGu/NElxSKM7uJTeU0k
-xxKuMNMQCJbZmklJKojVYZ0fsh6AyLEpBMV6mWTmVo0qA/A09jKD2tsKu52KGCMt
-vgrN4Gi5JJJACNbtpG7uSJstAYuUGYQSTuS/xCE+urgMVbWBTocsf0bEeEe0FRWX
-txhS/zdj6wspTd6lJ0SSahWG/BsV7990zaRDGYv0N1+SwF8/C0Ml99WbyRof6oP9
-jx0esKA+giWc5lSk+Ag2gpsTIH36aF53lQnDBZL3hqSgqP0ollKa9Uyjfmp65D1m
-TwoENrKnVNO5ZKteTM3SGQ+zsHxBPpinK7T2BPe77wKCAQBdS+Nu2ys/mDErnD1H
-hXzb6J9SVEg3ET8PWZzeO4pciMqcoxYS5qxaFn68Yf+60zGWxUmbL71l7CX80bSp
-6UBwxPxX+ok+kx/WXRbmC+MGRIN+qOwPGKu8XTtSAMD/voJpugAXBMADt4lhq+MN
-HZppV865Ea33tco3hyxn2VKic/rztYtJslrcstrRqD9qsufqbtD9D7gHljZIMCsR
-Yh5xjjEgG5f1XLr/MXhIUhfE0n4D4LWefZGE8W1Sg889f2tOxSPf8+H5dDSb+2Oh
-pTK1hIvA6H+ESfYaMAjbzRsxGz89y9lYr40mUSFRJj3b7TJnvy4ka00xW0f+8XRi
-iOcxAoIBAB0o8Te4i0t3akL5XQNw5if7qDWIHZNcaxYfjxTLH7sbIms825OT2KqA
-X0Y5vLLTfB1Dcym2cfsgTYiiXIvN84TK3/pjjgamtmLH4EVJbkl1aKOvghO6lPEB
-6R/ZCUfpiv7HKKcZqeHgDYMxyaMwYG/Ql+Dz0A7P66PK/VlqS9bclha43cf7qLvj
-gOPXGIf4mSeFHQxzBrJ5i3VjNzJB3GitsIS2ipEd5B/eRylgEL8gP07KhH38silx
-FV8tGbc95BS/4v8zMBz/peKP2zXF8Hs4oK6uK8MKy4i0emoa2pf3rcL+2A65bF0F
-L1WHmAszGf/7Xkd3yQoSTWpJfuTCJ/0CggEBAJjkBaEoiRYp0RBq1Ty0wa+xbPHp
-gAcpco+VC3T8uqniKBDrf5QsMDm7+P9IZRYrfgyy0KFeG4mHrTt61JgOLnhSTOyz
-EEChc8SOn6+vqMB36FmSSqVb6CdLEZhv5dtTzzHgyd3xS3cwga9Mf2SCoG/l34HJ
-XzfoQyLKvqF0kWOq/76k+kBM5QwWIGc2fVXcpJpWaAuPWKDQJnkvTcPp8XPyEADv
-z2YbSDDqqcwczX2DWepf2t2RU1fdyjS5wS6pNDvsuyd6gwUTQT1P5ODHbIdAwcdi
-5Gxui8voJmzvrfabIsN6H73ZS4Lw20ZB+ejYyiwxZcb0os45C1coicMJ9wQ=
------END RSA PRIVATE KEY-----
diff --git a/sensors/aidl/default/apex/com.android.hardware.sensors.pk8 b/sensors/aidl/default/apex/com.android.hardware.sensors.pk8
deleted file mode 100644
index 7a1cca0..0000000
--- a/sensors/aidl/default/apex/com.android.hardware.sensors.pk8
+++ /dev/null
Binary files differ
diff --git a/sensors/aidl/default/apex/com.android.hardware.sensors.x509.pem b/sensors/aidl/default/apex/com.android.hardware.sensors.x509.pem
deleted file mode 100644
index 20a06f9..0000000
--- a/sensors/aidl/default/apex/com.android.hardware.sensors.x509.pem
+++ /dev/null
@@ -1,34 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIF3TCCA8UCFAbIl4RS714WSLo4k64MHsINz4VEMA0GCSqGSIb3DQEBCwUAMIGp
-MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91
-bnRhaW4gVmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UECwwHQW5kcm9pZDEi
-MCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTElMCMGA1UEAwwcY29t
-LmFuZHJvaWQuaGFyZHdhcmUuc2Vuc29yczAgFw0yMTA5MDMxNjEyNDNaGA80NzU5
-MDczMTE2MTI0M1owgakxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlh
-MRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYD
-VQQLDAdBbmRyb2lkMSIwIAYJKoZIhvcNAQkBFhNhbmRyb2lkQGFuZHJvaWQuY29t
-MSUwIwYDVQQDDBxjb20uYW5kcm9pZC5oYXJkd2FyZS5zZW5zb3JzMIICIjANBgkq
-hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAnluNTPcq4pDEeb5gEYszRYQCawq8czUY
-J+x2b0i7qO2wLidX45CX6BLZ9N7c5veoV3FvC1wMTRR6lGAyg7UbD80vVmPdmr6R
-vw2AdIqrghXinvAEv6gxQQPVQa8UHkCL4lULLXo2gdmoCBM8VJHihjO/2F8ZLsP/
-nKhYx9Nr6w9LEyalmHTkXOgNyrNprpbJwugdk3hDXbAK+j5nF9fsz/iWFoXnPuNe
-oqdWj21YhXKDAbewBXaM6l3qmTdGsVVJL4HmVURGUY2f2UZwMWTEjpy9UDzyfqqg
-CSdH1RLmGVAINyfNI3Zswo0CjnOCf0jW6mq9/6mfGYu8hBCrky/rOH8reDwYZTGe
-H6JbNj0dhEN5HzQcxGEQQ43L1nmH7XlnuPO0xPSsw5binPVuUvURivR3PSsFgpPl
-0Uche62XgLAXCXhNV2uUQtZLVFGug7JcGgS4O3GoKr6w35Q+W9SEXanXFMW6X+wN
-hkbhB4MDSuKTZrjEnZEyxMOLG8ILN9i7osa+yjWONTn9bZc6q3Y9jyu3u84o8kC8
-KDcvr8YZEL63nQsQXO44GiQmqBptuB+ehcAC6uRCKkY9tQ95EQ7laGQ3C85d3gPj
-NcGjT7SSuUir7n+LI9pZsotedd9+rGhiiyT8CM4sVWiYJFnA2UX/bsnkZyAOq9Po
-jz1aMdHc4wUCAwEAATANBgkqhkiG9w0BAQsFAAOCAgEATEPN2SZk8pJc4DaWmhyR
-MUklzVeuN0J0Mij1mHuVmID7Q5IhBBXxtVmwRIo208rHSvFLAo7Z4FnuZCV3A/c9
-TlXT3S2t+iYG5eOyXSsoSc/uerJ7kIBcOe27qIrO9GwcK5CQlTaXP+CG1gbLp1nl
-IaqKAT+eb/ji5wmFxMI77wo3uKLPTCfpaptFNaYlRqvxiXdJsCZwCPgmCtXJUeeZ
-R/HKOA4PcS2QB+HwhYePY5kUJPwt6MwJEyno72oenfl49FrGHj0BzVmQ7KMfiYjZ
-eRSB2Wbo50xfiICkPlUcvWD8rRNg7N9CM/Q5O0MW3ivAe42aGap/8qfXUa+L5vu4
-9vaxgQvBVcPXE/pyeCYM8beB84Us+FOYPC7gIUhcctBqGYAQmHzp3sXvIg0DVxz7
-0aqolFGpjRFqbgheS9WRkDHFpYrhR1XMVOQjussHqWEyRcvliqeFlZr8+JNkJNi+
-lmGMdnEAWZs8PL0/AEf+8y0Nr/w0k3Y6IZCDcwpxbpJQOU5pAbkfUzEJHkxMfuvW
-ZshvqIMOaLWCGxZaxlbLRxWGuarWYzfmDY3n9TwJmAIUdMLiswv3UsCmLBJO1XGX
-SUWfgi4fyG1/phfzhdU3efMvmN+XT16/ykMrY8P5S+ghwK12IZ3DgTl0ooLFABUj
-zYeQ8LLz3SP9LNgeLnPP/po=
------END CERTIFICATE-----
diff --git a/sensors/aidl/default/apex/file_contexts b/sensors/aidl/default/apex/file_contexts
deleted file mode 100644
index 27be16b..0000000
--- a/sensors/aidl/default/apex/file_contexts
+++ /dev/null
@@ -1,5 +0,0 @@
-(/.*)?							u:object_r:vendor_file:s0
-# Permission XMLs
-/etc/permissions(/.*)?					u:object_r:vendor_configs_file:s0
-# Service binary
-/bin/hw/android\.hardware\.sensors-service\.example	u:object_r:hal_sensors_default_exec:s0
\ No newline at end of file
diff --git a/sensors/aidl/default/apex/apex_manifest.json b/sensors/aidl/default/apex_manifest.json
similarity index 100%
rename from sensors/aidl/default/apex/apex_manifest.json
rename to sensors/aidl/default/apex_manifest.json
diff --git a/sensors/aidl/default/file_contexts b/sensors/aidl/default/file_contexts
new file mode 100644
index 0000000..6d231f8
--- /dev/null
+++ b/sensors/aidl/default/file_contexts
@@ -0,0 +1,3 @@
+(/.*)?                                                u:object_r:vendor_file:s0
+/etc(/.*)?                                            u:object_r:vendor_configs_file:s0
+/bin/hw/android\.hardware\.sensors-service\.example   u:object_r:hal_sensors_default_exec:s0
\ No newline at end of file
diff --git a/sensors/aidl/default/multihal/Android.bp b/sensors/aidl/default/multihal/Android.bp
index a20d6d7..40cb2d9 100644
--- a/sensors/aidl/default/multihal/Android.bp
+++ b/sensors/aidl/default/multihal/Android.bp
@@ -45,11 +45,6 @@
         "HalProxyAidl.cpp",
         "ConvertUtils.cpp",
     ],
-    visibility: [
-        ":__subpackages__",
-        "//hardware/interfaces/sensors/aidl/multihal:__subpackages__",
-        "//hardware/interfaces/tests/extension/sensors:__subpackages__",
-    ],
     static_libs: [
         "android.hardware.sensors@1.0-convert",
         "android.hardware.sensors@2.X-multihal",
diff --git a/sensors/aidl/default/sensors-default.rc b/sensors/aidl/default/sensors-default.rc
index 96da85d..e0b0ef0 100644
--- a/sensors/aidl/default/sensors-default.rc
+++ b/sensors/aidl/default/sensors-default.rc
@@ -1,4 +1,4 @@
-service vendor.sensors-default /vendor/bin/hw/android.hardware.sensors-service.example
+service vendor.sensors-default /apex/com.android.hardware.sensors/bin/hw/android.hardware.sensors-service.example
     class hal
     user system
     group system
diff --git a/sensors/aidl/vts/AndroidTest.xml b/sensors/aidl/vts/AndroidTest.xml
index 99caf28..2d3382e 100644
--- a/sensors/aidl/vts/AndroidTest.xml
+++ b/sensors/aidl/vts/AndroidTest.xml
@@ -22,13 +22,13 @@
 
     <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
         <option name="cleanup" value="true" />
-        <option name="push" value="VtsAidlHalSensorsTargetTest->/data/local/tmp/VtsAidlHalSensorsTargetTest" />
+        <option name="push" value="VtsAidlHalSensorsTargetTest->/data/local/tests/unrestricted/VtsAidlHalSensorsTargetTest" />
     </target_preparer>
 
     <test class="com.android.tradefed.testtype.GTest" >
         <option name="native-test-timeout" value="900000" />
         <option name="runtime-hint" value="300000"/>
-        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="native-test-device-path" value="/data/local/tests/unrestricted" />
         <option name="module-name" value="VtsAidlHalSensorsTargetTest" />
     </test>
 </configuration>
diff --git a/sensors/aidl/vts/SensorsAidlTestSharedMemory.h b/sensors/aidl/vts/SensorsAidlTestSharedMemory.h
index 4b5916a..200f26f 100644
--- a/sensors/aidl/vts/SensorsAidlTestSharedMemory.h
+++ b/sensors/aidl/vts/SensorsAidlTestSharedMemory.h
@@ -17,7 +17,11 @@
 #ifndef ANDROID_SENSORS_AIDL_TEST_SHARED_MEMORY_H
 #define ANDROID_SENSORS_AIDL_TEST_SHARED_MEMORY_H
 
-#include "sensors-vts-utils/GrallocWrapper.h"
+#include <aidl/android/hardware/graphics/common/BufferUsage.h>
+#include <aidl/android/hardware/graphics/common/PixelFormat.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicBufferAllocator.h>
+#include <ui/GraphicBufferMapper.h>
 
 #include <aidlcommonsupport/NativeHandle.h>
 #include <android-base/macros.h>
@@ -28,6 +32,8 @@
 
 #include <cutils/ashmem.h>
 
+using ::aidl::android::hardware::graphics::common::BufferUsage;
+using ::aidl::android::hardware::graphics::common::PixelFormat;
 using ::aidl::android::hardware::sensors::BnSensors;
 using ::aidl::android::hardware::sensors::Event;
 using ::aidl::android::hardware::sensors::ISensors;
@@ -53,12 +59,22 @@
     }
 
     ISensors::SharedMemInfo getSharedMemInfo() const {
-        ISensors::SharedMemInfo mem = {
-                .type = mType,
-                .format = ISensors::SharedMemInfo::SharedMemFormat::SENSORS_EVENT,
-                .size = static_cast<int32_t>(mSize),
-                .memoryHandle = android::dupToAidl(mNativeHandle)};
-        return mem;
+        if (mType == ISensors::SharedMemInfo::SharedMemType::GRALLOC) {
+            ISensors::SharedMemInfo mem = {
+                    .type = mType,
+                    .format = ISensors::SharedMemInfo::SharedMemFormat::SENSORS_EVENT,
+                    .size = static_cast<int32_t>(mSize),
+                    .memoryHandle = android::dupToAidl(mBufferHandle)};
+            return mem;
+
+        } else {
+            ISensors::SharedMemInfo mem = {
+                    .type = mType,
+                    .format = ISensors::SharedMemInfo::SharedMemFormat::SENSORS_EVENT,
+                    .size = static_cast<int32_t>(mSize),
+                    .memoryHandle = android::dupToAidl(mNativeHandle)};
+            return mem;
+        }
     }
     char* getBuffer() const { return mBuffer; }
     size_t getSize() const { return mSize; }
@@ -141,17 +157,26 @@
             }
             case ISensors::SharedMemInfo::SharedMemType::GRALLOC: {
                 if (mSize != 0) {
-                    mGrallocWrapper->freeBuffer(mNativeHandle);
-                    mNativeHandle = nullptr;
+                    android::status_t status =
+                            android::GraphicBufferAllocator::get().free(mBufferHandle);
+                    if (status != android::OK) {
+                        ALOGE("SensorsAidlTestSharedMemory Gralloc failed to free buffer. Status: "
+                              "%s",
+                              android::statusToString(status).c_str());
+                    }
+                    mBufferHandle = nullptr;
+                    mBuffer = nullptr;
                     mSize = 0;
                 }
                 break;
             }
             default: {
-                if (mNativeHandle != nullptr || mSize != 0 || mBuffer != nullptr) {
+                if (mNativeHandle != nullptr || mSize != 0 || mBuffer != nullptr ||
+                    mBufferHandle != nullptr) {
                     ALOGE("SensorsAidlTestSharedMemory %p not properly destructed: "
-                          "type %d, native handle %p, size %zu, buffer %p",
-                          this, static_cast<int>(mType), mNativeHandle, mSize, mBuffer);
+                          "type %d, native handle %p, size %zu, buffer %p, buffer handle %p",
+                          this, static_cast<int>(mType), mNativeHandle, mSize, mBuffer,
+                          mBufferHandle);
                 }
                 break;
             }
@@ -185,14 +210,33 @@
                 break;
             }
             case ISensors::SharedMemInfo::SharedMemType::GRALLOC: {
-                mGrallocWrapper = std::make_unique<::android::GrallocWrapper>();
-                if (!mGrallocWrapper->isInitialized()) {
+                static constexpr uint64_t kBufferUsage =
+                        static_cast<uint64_t>(BufferUsage::SENSOR_DIRECT_DATA) |
+                        static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN) |
+                        static_cast<uint64_t>(BufferUsage::CPU_WRITE_RARELY);
+
+                uint32_t stride = 0;
+                buffer_handle_t bufferHandle;
+                android::status_t status = android::GraphicBufferAllocator::get().allocate(
+                        size, 1, static_cast<int>(PixelFormat::BLOB), 1, kBufferUsage,
+                        &bufferHandle, &stride, "SensorVts");
+                if (status != android::OK) {
+                    ALOGE("SensorsAidlTestSharedMemory failed to allocate memory. Status: %s",
+                          android::statusToString(status).c_str());
                     break;
                 }
-
-                std::pair<native_handle_t*, void*> buf = mGrallocWrapper->allocate(size);
-                handle = buf.first;
-                buffer = static_cast<char*>(buf.second);
+                // Per the HAL, all-zeros Rect means the entire buffer
+                android::Rect rect = {0, 0, 0, 0};
+                void* ret;
+                status = android::GraphicBufferMapper::get().lock(bufferHandle, kBufferUsage, rect,
+                                                                  &ret);
+                if (status != android::OK) {
+                    ALOGE("SensorsAidlTestSharedMemory failed to import buffer: Status: %s",
+                          android::statusToString(status).c_str());
+                } else {
+                    buffer = static_cast<char*>(ret);
+                    mBufferHandle = bufferHandle;
+                }
                 break;
             }
             default:
@@ -208,9 +252,9 @@
 
     ISensors::SharedMemInfo::SharedMemType mType;
     native_handle_t* mNativeHandle;
+    buffer_handle_t mBufferHandle;
     size_t mSize;
     char* mBuffer;
-    std::unique_ptr<::android::GrallocWrapper> mGrallocWrapper;
 
     DISALLOW_COPY_AND_ASSIGN(SensorsAidlTestSharedMemory);
 };
diff --git a/sensors/aidl/vts/VtsAidlHalSensorsTargetTest.cpp b/sensors/aidl/vts/VtsAidlHalSensorsTargetTest.cpp
index be11b87..0b15d12 100644
--- a/sensors/aidl/vts/VtsAidlHalSensorsTargetTest.cpp
+++ b/sensors/aidl/vts/VtsAidlHalSensorsTargetTest.cpp
@@ -931,9 +931,15 @@
             continue;
         }
 
+        // Skip sensors with no events
+        const std::vector<Event> events = callback.getEvents(sensor.sensorHandle);
+        if (events.empty()) {
+            continue;
+        }
+
         // Ensure that the first event received is not stale by ensuring that its timestamp is
         // sufficiently different from the previous event
-        const Event newEvent = callback.getEvents(sensor.sensorHandle).front();
+        const Event newEvent = events.front();
         std::chrono::milliseconds delta =
                 duration_cast<std::chrono::milliseconds>(std::chrono::nanoseconds(
                         newEvent.timestamp - lastEventTimestampMap[sensor.sensorHandle]));
diff --git a/sensors/common/default/2.X/Sensor.cpp b/sensors/common/default/2.X/Sensor.cpp
index 2c1cdfb..f8c857b 100644
--- a/sensors/common/default/2.X/Sensor.cpp
+++ b/sensors/common/default/2.X/Sensor.cpp
@@ -40,6 +40,7 @@
     : mIsEnabled(false),
       mSamplingPeriodNs(0),
       mLastSampleTimeNs(0),
+      mStopThread(false),
       mCallback(callback),
       mMode(OperationMode::NORMAL) {
     mRunThread = std::thread(startThread, this);
diff --git a/sensors/common/vts/2_X/VtsHalSensorsV2_XTargetTest.h b/sensors/common/vts/2_X/VtsHalSensorsV2_XTargetTest.h
index aa6e881..becc93c 100644
--- a/sensors/common/vts/2_X/VtsHalSensorsV2_XTargetTest.h
+++ b/sensors/common/vts/2_X/VtsHalSensorsV2_XTargetTest.h
@@ -52,8 +52,6 @@
 using ::android::hardware::sensors::V1_0::Vec3;
 using ::android::hardware::sensors::V2_1::implementation::convertToOldSensorInfos;
 using std::chrono::duration_cast;
-using std::chrono::microseconds;
-using std::chrono::milliseconds;
 using std::chrono::nanoseconds;
 
 using EventV1_0 = ::android::hardware::sensors::V1_0::Event;
@@ -91,7 +89,7 @@
     }
 
     void waitForFlushEvents(const std::vector<SensorInfoType>& sensorsToWaitFor,
-                            int32_t numCallsToFlush, milliseconds timeout) {
+                            int32_t numCallsToFlush, std::chrono::milliseconds timeout) {
         std::unique_lock<std::recursive_mutex> lock(mFlushMutex);
         mFlushCV.wait_for(lock, timeout,
                           [&] { return flushesReceived(sensorsToWaitFor, numCallsToFlush); });
@@ -102,7 +100,8 @@
         return mEventMap[sensorHandle];
     }
 
-    void waitForEvents(const std::vector<SensorInfoType>& sensorsToWaitFor, milliseconds timeout) {
+    void waitForEvents(const std::vector<SensorInfoType>& sensorsToWaitFor,
+                       std::chrono::milliseconds timeout) {
         std::unique_lock<std::recursive_mutex> lock(mEventMutex);
         mEventCV.wait_for(lock, timeout, [&] { return eventsReceived(sensorsToWaitFor); });
     }
@@ -472,7 +471,7 @@
     }
 
     // Wait for events to be written back to the Event FMQ
-    callback.waitForEvents(sensors, milliseconds(1000) /* timeout */);
+    callback.waitForEvents(sensors, std::chrono::milliseconds(1000) /* timeout */);
     getEnvironment()->unregisterCallback();
 
     for (const auto& s : sensors) {
@@ -623,7 +622,7 @@
     }
 
     // Wait up to one second for the flush events
-    callback.waitForFlushEvents(sensors, flushCalls, milliseconds(1000) /* timeout */);
+    callback.waitForFlushEvents(sensors, flushCalls, std::chrono::milliseconds(1000) /* timeout */);
 
     // Deactivate all sensors after waiting for flush events so pending flush events are not
     // abandoned by the HAL.
@@ -748,8 +747,8 @@
 }
 
 TEST_P(SensorsHidlTest, NoStaleEvents) {
-    constexpr milliseconds kFiveHundredMs(500);
-    constexpr milliseconds kOneSecond(1000);
+    constexpr std::chrono::milliseconds kFiveHundredMs(500);
+    constexpr std::chrono::milliseconds kOneSecond(1000);
 
     // Register the callback to receive sensor events
     EventCallback callback;
@@ -757,10 +756,11 @@
 
     // This test is not valid for one-shot, on-change or special-report-mode sensors
     const std::vector<SensorInfoType> sensors = getNonOneShotAndNonOnChangeAndNonSpecialSensors();
-    milliseconds maxMinDelay(0);
+    std::chrono::milliseconds maxMinDelay(0);
     for (const SensorInfoType& sensor : sensors) {
-        milliseconds minDelay = duration_cast<milliseconds>(microseconds(sensor.minDelay));
-        maxMinDelay = milliseconds(std::max(maxMinDelay.count(), minDelay.count()));
+        std::chrono::milliseconds minDelay = duration_cast<std::chrono::milliseconds>(
+                std::chrono::microseconds(sensor.minDelay));
+        maxMinDelay = std::chrono::milliseconds(std::max(maxMinDelay.count(), minDelay.count()));
     }
 
     // Activate the sensors so that they start generating events
@@ -787,7 +787,7 @@
     }
 
     // Allow some time to pass, reset the callback, then reactivate the sensors
-    usleep(duration_cast<microseconds>(kOneSecond + (5 * maxMinDelay)).count());
+    usleep(duration_cast<std::chrono::microseconds>(kOneSecond + (5 * maxMinDelay)).count());
     callback.reset();
     activateAllSensors(true);
     callback.waitForEvents(sensors, kFiveHundredMs + (5 * maxMinDelay));
@@ -806,12 +806,19 @@
             continue;
         }
 
+        // Skip sensors with no events
+        const std::vector<EventType> events = callback.getEvents(sensor.sensorHandle);
+        if (events.empty()) {
+            continue;
+        }
+
         // Ensure that the first event received is not stale by ensuring that its timestamp is
         // sufficiently different from the previous event
-        const EventType newEvent = callback.getEvents(sensor.sensorHandle).front();
-        milliseconds delta = duration_cast<milliseconds>(
+        const EventType newEvent = events.front();
+        std::chrono::milliseconds delta = duration_cast<std::chrono::milliseconds>(
                 nanoseconds(newEvent.timestamp - lastEventTimestampMap[sensor.sensorHandle]));
-        milliseconds sensorMinDelay = duration_cast<milliseconds>(microseconds(sensor.minDelay));
+        std::chrono::milliseconds sensorMinDelay = duration_cast<std::chrono::milliseconds>(
+                std::chrono::microseconds(sensor.minDelay));
         ASSERT_GE(delta, kFiveHundredMs + (3 * sensorMinDelay));
     }
 }
diff --git a/sensors/common/vts/utils/Android.bp b/sensors/common/vts/utils/Android.bp
index b35280a..ab3984c 100644
--- a/sensors/common/vts/utils/Android.bp
+++ b/sensors/common/vts/utils/Android.bp
@@ -35,6 +35,7 @@
         "libbinder_ndk",
         "libutils",
         "libvndksupport",
+        "libui",
     ],
     static_libs: [
         "libaidlcommonsupport",
@@ -50,9 +51,6 @@
         "android.hardware.graphics.common-ndk_shared",
     ],
     cflags: ["-DLOG_TAG=\"sensors_hidl_hal_test\""],
-    srcs: [
-        "GrallocWrapper.cpp",
-    ],
     export_include_dirs: [
         "include",
     ],
@@ -64,6 +62,7 @@
         "libbinder_ndk",
         "libutils",
         "libvndksupport",
+        "libui",
     ],
     static_libs: [
         "android.hardware.sensors@1.0",
@@ -71,13 +70,4 @@
         "android.hardware.sensors@2.1",
         "libaidlcommonsupport",
     ],
-    whole_static_libs: [
-        "android.hardware.graphics.allocator@2.0",
-        "android.hardware.graphics.allocator@3.0",
-        "android.hardware.graphics.allocator@4.0",
-        "android.hardware.graphics.mapper@2.0",
-        "android.hardware.graphics.mapper@2.1",
-        "android.hardware.graphics.mapper@3.0",
-        "android.hardware.graphics.mapper@4.0",
-    ],
 }
diff --git a/sensors/common/vts/utils/GrallocWrapper.cpp b/sensors/common/vts/utils/GrallocWrapper.cpp
deleted file mode 100644
index e6e0888..0000000
--- a/sensors/common/vts/utils/GrallocWrapper.cpp
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "GrallocWrapper.h"
-
-#include <aidl/android/hardware/graphics/allocator/IAllocator.h>
-#include <aidlcommonsupport/NativeHandle.h>
-#include <android/binder_manager.h>
-#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
-#include <android/hardware/graphics/allocator/3.0/IAllocator.h>
-#include <android/hardware/graphics/allocator/4.0/IAllocator.h>
-#include <android/hardware/graphics/mapper/2.0/IMapper.h>
-#include <android/hardware/graphics/mapper/2.1/IMapper.h>
-#include <android/hardware/graphics/mapper/3.0/IMapper.h>
-#include <android/hardware/graphics/mapper/4.0/IMapper.h>
-
-#include <utils/Log.h>
-
-#include <cinttypes>
-#include <memory>
-#include <type_traits>
-
-using IAllocatorAidl = ::aidl::android::hardware::graphics::allocator::IAllocator;
-using IAllocator2 = ::android::hardware::graphics::allocator::V2_0::IAllocator;
-using IAllocator3 = ::android::hardware::graphics::allocator::V3_0::IAllocator;
-using IAllocator4 = ::android::hardware::graphics::allocator::V4_0::IAllocator;
-using IMapper2 = ::android::hardware::graphics::mapper::V2_0::IMapper;
-using IMapper2_1 = ::android::hardware::graphics::mapper::V2_1::IMapper;
-using IMapper3 = ::android::hardware::graphics::mapper::V3_0::IMapper;
-using IMapper4 = ::android::hardware::graphics::mapper::V4_0::IMapper;
-
-using Error2 = ::android::hardware::graphics::mapper::V2_0::Error;
-using Error3 = ::android::hardware::graphics::mapper::V3_0::Error;
-using Error4 = ::android::hardware::graphics::mapper::V4_0::Error;
-
-using ::aidl::android::hardware::common::NativeHandle;
-using ::aidl::android::hardware::graphics::allocator::AllocationResult;
-
-using ::android::hardware::graphics::common::V1_0::BufferUsage;
-using ::android::hardware::graphics::common::V1_0::PixelFormat;
-
-using ::android::hardware::hidl_handle;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-
-namespace android {
-
-// Since we use the same APIs across allocator/mapper HALs but they have major
-// version differences (meaning they are not related through inheritance), we
-// create a common interface abstraction for the IAllocator + IMapper combination
-// (major versions need to match in the current HALs, e.g. IAllocator 3.0 needs to
-// be paired with IMapper 3.0, so these are tied together)
-class IGrallocHalWrapper {
-  public:
-    virtual ~IGrallocHalWrapper() = default;
-
-    // IAllocator
-    virtual native_handle_t* allocate(uint32_t size) = 0;
-    virtual void freeBuffer(native_handle_t* bufferHandle) = 0;
-
-    // IMapper
-    virtual void* lock(native_handle_t* bufferHandle) = 0;
-    virtual void unlock(native_handle_t* bufferHandle) = 0;
-};
-
-namespace {
-
-bool failed(Error2 error) {
-    return (error != Error2::NONE);
-}
-bool failed(Error3 error) {
-    return (error != Error3::NONE);
-}
-bool failed(Error4 error) {
-    return (error != Error4::NONE);
-}
-
-template <typename>
-struct FirstArg;
-
-// Template specialization for pointer to a non-static member function, which exposes
-// the type of the first argument given to said function
-template <typename ReturnType, typename ClassT, typename Arg1, typename... OtherArgs>
-struct FirstArg<ReturnType (ClassT::*)(Arg1, OtherArgs...)> {
-    using type = Arg1;
-};
-
-// Alias to FirstArg which also removes any reference type and const associated
-template <typename T>
-using BaseTypeOfFirstArg = typename std::remove_const<
-        typename std::remove_reference<typename FirstArg<T>::type>::type>::type;
-
-// Since all the type and function names are the same for the things we use across the major HAL
-// versions, we use template magic to avoid repeating ourselves.
-template <typename AllocatorT, typename MapperT,
-          template <typename> typename AllocatorWrapperT = sp>
-class GrallocHalWrapper : public IGrallocHalWrapper {
-  public:
-    GrallocHalWrapper(const AllocatorWrapperT<AllocatorT>& allocator, const sp<MapperT>& mapper)
-        : mAllocator(allocator), mMapper(mapper) {
-        if (mapper->isRemote()) {
-            ALOGE("Mapper is in passthrough mode");
-        }
-    }
-
-    virtual native_handle_t* allocate(uint32_t size) override;
-    virtual void freeBuffer(native_handle_t* bufferHandle) override;
-
-    virtual void* lock(native_handle_t* bufferHandle) override;
-    virtual void unlock(native_handle_t* bufferHandle) override;
-
-  private:
-    static constexpr uint64_t kBufferUsage =
-            static_cast<uint64_t>(BufferUsage::SENSOR_DIRECT_DATA | BufferUsage::CPU_READ_OFTEN);
-    AllocatorWrapperT<AllocatorT> mAllocator;
-    sp<MapperT> mMapper;
-
-    // v2.0 and v3.0 use vec<uint32_t> for BufferDescriptor, but v4.0 uses vec<uint8_t>, so use
-    // some template magic to deduce the right type based off of the first argument to allocate(),
-    // which is always the version-specific BufferDescriptor type
-    typedef BaseTypeOfFirstArg<decltype(&AllocatorT::allocate)> BufferDescriptorT;
-
-    BufferDescriptorT getDescriptor(uint32_t size);
-    native_handle_t* importBuffer(const hidl_handle& rawHandle);
-};
-
-template <>
-native_handle_t* GrallocHalWrapper<IAllocatorAidl, IMapper4, std::shared_ptr>::allocate(
-        uint32_t size) {
-    constexpr uint32_t kBufferCount = 1;
-    BufferDescriptorT descriptor = getDescriptor(size);
-    native_handle_t* bufferHandle = nullptr;
-
-    AllocationResult result;
-    auto status = mAllocator->allocate(descriptor, kBufferCount, &result);
-    if (!status.isOk()) {
-        status_t error = status.getExceptionCode();
-        ALOGE("Failed to allocate buffer: %" PRId32, static_cast<int32_t>(error));
-    } else if (result.buffers.size() != kBufferCount) {
-        ALOGE("Invalid buffer array size (got %zu, expected %" PRIu32 ")", result.buffers.size(),
-              kBufferCount);
-    } else {
-        // Convert from AIDL NativeHandle to native_handle_t to hidl_handle
-        hidl_handle hidlHandle;
-        hidlHandle.setTo(dupFromAidl(result.buffers[0]), /*shouldOwn*/ true);
-        bufferHandle = importBuffer(hidlHandle);
-    }
-
-    return bufferHandle;
-}
-
-template <typename AllocatorT, typename MapperT, template <typename> typename AllocatorWrapperT>
-native_handle_t* GrallocHalWrapper<AllocatorT, MapperT, AllocatorWrapperT>::allocate(
-        uint32_t size) {
-    constexpr uint32_t kBufferCount = 1;
-    BufferDescriptorT descriptor = getDescriptor(size);
-    native_handle_t* bufferHandle = nullptr;
-
-    auto callback = [&](auto error, uint32_t /*stride*/, const hidl_vec<hidl_handle>& buffers) {
-        if (failed(error)) {
-            ALOGE("Failed to allocate buffer: %" PRId32, static_cast<int32_t>(error));
-        } else if (buffers.size() != kBufferCount) {
-            ALOGE("Invalid buffer array size (got %zu, expected %" PRIu32 ")", buffers.size(),
-                  kBufferCount);
-        } else {
-            bufferHandle = importBuffer(buffers[0]);
-        }
-    };
-
-    mAllocator->allocate(descriptor, kBufferCount, callback);
-    return bufferHandle;
-}
-
-template <typename AllocatorT, typename MapperT, template <typename> typename AllocatorWrapperT>
-void GrallocHalWrapper<AllocatorT, MapperT, AllocatorWrapperT>::freeBuffer(
-        native_handle_t* bufferHandle) {
-    auto error = mMapper->freeBuffer(bufferHandle);
-    if (!error.isOk() || failed(error)) {
-        ALOGE("Failed to free buffer %p", bufferHandle);
-    }
-}
-
-template <typename AllocatorT, typename MapperT, template <typename> typename AllocatorWrapperT>
-typename GrallocHalWrapper<AllocatorT, MapperT, AllocatorWrapperT>::BufferDescriptorT
-GrallocHalWrapper<AllocatorT, MapperT, AllocatorWrapperT>::getDescriptor(uint32_t size) {
-    typename MapperT::BufferDescriptorInfo descriptorInfo = {
-            .width = size,
-            .height = 1,
-            .layerCount = 1,
-            .format = static_cast<decltype(descriptorInfo.format)>(PixelFormat::BLOB),
-            .usage = kBufferUsage,
-    };
-
-    BufferDescriptorT descriptor;
-    auto callback = [&](auto error, const BufferDescriptorT& tmpDescriptor) {
-        if (failed(error)) {
-            ALOGE("Failed to create descriptor: %" PRId32, static_cast<int32_t>(error));
-        } else {
-            descriptor = tmpDescriptor;
-        }
-    };
-
-    mMapper->createDescriptor(descriptorInfo, callback);
-    return descriptor;
-}
-
-template <typename AllocatorT, typename MapperT, template <typename> typename AllocatorWrapperT>
-native_handle_t* GrallocHalWrapper<AllocatorT, MapperT, AllocatorWrapperT>::importBuffer(
-        const hidl_handle& rawHandle) {
-    native_handle_t* bufferHandle = nullptr;
-
-    mMapper->importBuffer(rawHandle, [&](auto error, void* tmpBuffer) {
-        if (failed(error)) {
-            ALOGE("Failed to import buffer %p: %" PRId32, rawHandle.getNativeHandle(),
-                  static_cast<int32_t>(error));
-        } else {
-            bufferHandle = static_cast<native_handle_t*>(tmpBuffer);
-        }
-    });
-
-    return bufferHandle;
-}
-
-template <typename AllocatorT, typename MapperT, template <typename> typename AllocatorWrapperT>
-void* GrallocHalWrapper<AllocatorT, MapperT, AllocatorWrapperT>::lock(
-        native_handle_t* bufferHandle) {
-    // Per the HAL, all-zeros Rect means the entire buffer
-    typename MapperT::Rect accessRegion = {};
-    hidl_handle acquireFenceHandle;  // No fence needed, already safe to lock
-
-    void* data = nullptr;
-    mMapper->lock(bufferHandle, kBufferUsage, accessRegion, acquireFenceHandle,
-                  [&](auto error, void* tmpData, ...) {  // V3/4 pass extra args we don't use
-                      if (failed(error)) {
-                          ALOGE("Failed to lock buffer %p: %" PRId32, bufferHandle,
-                                static_cast<int32_t>(error));
-                      } else {
-                          data = tmpData;
-                      }
-                  });
-
-    return data;
-}
-
-template <typename AllocatorT, typename MapperT, template <typename> typename AllocatorWrapperT>
-void GrallocHalWrapper<AllocatorT, MapperT, AllocatorWrapperT>::unlock(
-        native_handle_t* bufferHandle) {
-    mMapper->unlock(bufferHandle, [&](auto error, const hidl_handle& /*releaseFence*/) {
-        if (failed(error)) {
-            ALOGE("Failed to unlock buffer %p: %" PRId32, bufferHandle,
-                  static_cast<int32_t>(error));
-        }
-    });
-}
-
-}  // anonymous namespace
-
-GrallocWrapper::GrallocWrapper() {
-    sp<IAllocator4> allocator4 = IAllocator4::getService();
-    sp<IMapper4> mapper4 = IMapper4::getService();
-
-    const auto kAllocatorSvc = std::string(IAllocatorAidl::descriptor) + "/default";
-    std::shared_ptr<IAllocatorAidl> allocatorAidl;
-    if (AServiceManager_isDeclared(kAllocatorSvc.c_str())) {
-        allocatorAidl = IAllocatorAidl::fromBinder(
-                ndk::SpAIBinder(AServiceManager_checkService(kAllocatorSvc.c_str())));
-    }
-
-    // As of T, AIDL Allocator is supported only with HIDL Mapper4
-    // (ref: VtsHalGraphicsAllocatorAidl_TargetTest.cpp)
-    if (allocatorAidl != nullptr && mapper4 != nullptr) {
-        ALOGD("Using AIDL IAllocator + HIDL IMapper v4.0");
-        mGrallocHal = std::unique_ptr<IGrallocHalWrapper>(
-                new GrallocHalWrapper<IAllocatorAidl, IMapper4, std::shared_ptr>(allocatorAidl,
-                                                                                 mapper4));
-    } else if (allocator4 != nullptr && mapper4 != nullptr) {
-        ALOGD("AIDL IAllocator not found, using HIDL IAllocator/IMapper v4.0");
-        mGrallocHal = std::unique_ptr<IGrallocHalWrapper>(
-                new GrallocHalWrapper<IAllocator4, IMapper4>(allocator4, mapper4));
-    } else {
-        ALOGD("Graphics HALs 4.0 not found (allocator %d mapper %d), falling back to 3.0",
-              (allocator4 != nullptr), (mapper4 != nullptr));
-
-        sp<IAllocator3> allocator3 = IAllocator3::getService();
-        sp<IMapper3> mapper3 = IMapper3::getService();
-
-        if (allocator3 != nullptr && mapper3 != nullptr) {
-            mGrallocHal = std::unique_ptr<IGrallocHalWrapper>(
-                    new GrallocHalWrapper<IAllocator3, IMapper3>(allocator3, mapper3));
-        } else {
-            ALOGD("Graphics HALs 3.0 not found (allocator %d mapper %d), falling back to 2.x",
-                  (allocator3 != nullptr), (mapper3 != nullptr));
-
-            sp<IAllocator2> allocator2 = IAllocator2::getService();
-            sp<IMapper2> mapper2 = IMapper2_1::getService();
-            if (mapper2 == nullptr) {
-                mapper2 = IMapper2::getService();
-            }
-
-            if (allocator2 != nullptr && mapper2 != nullptr) {
-                mGrallocHal = std::unique_ptr<IGrallocHalWrapper>(
-                        new GrallocHalWrapper<IAllocator2, IMapper2>(allocator2, mapper2));
-            } else {
-                ALOGE("Couldn't open graphics HALs (2.x allocator %d mapper %d)",
-                      (allocator2 != nullptr), (mapper2 != nullptr));
-            }
-        }
-    }
-}
-
-GrallocWrapper::~GrallocWrapper() {
-    for (auto bufferHandle : mAllocatedBuffers) {
-        mGrallocHal->unlock(bufferHandle);
-        mGrallocHal->freeBuffer(bufferHandle);
-    }
-    mAllocatedBuffers.clear();
-}
-
-std::pair<native_handle_t*, void*> GrallocWrapper::allocate(uint32_t size) {
-    native_handle_t* bufferHandle = mGrallocHal->allocate(size);
-    void* buffer = nullptr;
-    if (bufferHandle) {
-        buffer = mGrallocHal->lock(bufferHandle);
-        if (buffer) {
-            mAllocatedBuffers.insert(bufferHandle);
-        } else {
-            mGrallocHal->freeBuffer(bufferHandle);
-            bufferHandle = nullptr;
-        }
-    }
-    return std::make_pair<>(bufferHandle, buffer);
-}
-
-void GrallocWrapper::freeBuffer(native_handle_t* bufferHandle) {
-    if (mAllocatedBuffers.erase(bufferHandle)) {
-        mGrallocHal->unlock(bufferHandle);
-        mGrallocHal->freeBuffer(bufferHandle);
-    }
-}
-
-}  // namespace android
diff --git a/sensors/common/vts/utils/include/sensors-vts-utils/GrallocWrapper.h b/sensors/common/vts/utils/include/sensors-vts-utils/GrallocWrapper.h
deleted file mode 100644
index ebbcb2c..0000000
--- a/sensors/common/vts/utils/include/sensors-vts-utils/GrallocWrapper.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <utils/NativeHandle.h>
-
-#include <memory>
-#include <string>
-#include <unordered_set>
-#include <utility>
-
-namespace android {
-
-class IGrallocHalWrapper;
-
-// Reference: hardware/interfaces/graphics/mapper/2.0/vts/functional/
-class GrallocWrapper {
-   public:
-    GrallocWrapper();
-    ~GrallocWrapper();
-
-    // After constructing this object, this function must be called to check the result. If it
-    // returns false, other methods are not safe to call.
-    bool isInitialized() const { return (mGrallocHal != nullptr); };
-
-    // Allocates a gralloc buffer suitable for direct channel sensors usage with the given size.
-    // The buffer should be freed using freeBuffer when it's not needed anymore; otherwise it'll
-    // be freed when this object is destroyed.
-    // Returns a handle to the buffer, and a CPU-accessible pointer for reading. On failure, both
-    // will be set to nullptr.
-    std::pair<native_handle_t*, void*> allocate(uint32_t size);
-
-    // Releases a gralloc buffer previously returned by allocate()
-    void freeBuffer(native_handle_t* bufferHandle);
-
-  private:
-    std::unique_ptr<IGrallocHalWrapper> mGrallocHal;
-
-    // Keep track of all cloned and imported handles.  When a test fails with
-    // ASSERT_*, the destructor will free the handles for the test.
-    std::unordered_set<native_handle_t*> mAllocatedBuffers;
-};
-
-}  // namespace android
diff --git a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsTestSharedMemory.h b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsTestSharedMemory.h
index 39084a4..b96adb3 100644
--- a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsTestSharedMemory.h
+++ b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsTestSharedMemory.h
@@ -17,7 +17,11 @@
 #ifndef ANDROID_SENSORS_TEST_SHARED_MEMORY_H
 #define ANDROID_SENSORS_TEST_SHARED_MEMORY_H
 
-#include "GrallocWrapper.h"
+#include <aidl/android/hardware/graphics/common/BufferUsage.h>
+#include <aidl/android/hardware/graphics/common/PixelFormat.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicBufferAllocator.h>
+#include <ui/GraphicBufferMapper.h>
 
 #include <android-base/macros.h>
 #include <log/log.h>
@@ -28,6 +32,8 @@
 #include <cutils/ashmem.h>
 
 using namespace ::android::hardware::sensors::V1_0;
+using ::aidl::android::hardware::graphics::common::BufferUsage;
+using ::aidl::android::hardware::graphics::common::PixelFormat;
 
 template <class SensorTypeVersion, class EventType>
 class SensorsTestSharedMemory {
@@ -48,11 +54,20 @@
     }
 
     SharedMemInfo getSharedMemInfo() const {
-        SharedMemInfo mem = {.type = mType,
-                             .format = SharedMemFormat::SENSORS_EVENT,
-                             .size = static_cast<uint32_t>(mSize),
-                             .memoryHandle = mNativeHandle};
-        return mem;
+        if (mType == SharedMemType::GRALLOC) {
+            SharedMemInfo mem = {.type = mType,
+                                 .format = SharedMemFormat::SENSORS_EVENT,
+                                 .size = static_cast<uint32_t>(mSize),
+                                 .memoryHandle = mBufferHandle};
+            return mem;
+
+        } else {
+            SharedMemInfo mem = {.type = mType,
+                                 .format = SharedMemFormat::SENSORS_EVENT,
+                                 .size = static_cast<uint32_t>(mSize),
+                                 .memoryHandle = mNativeHandle};
+            return mem;
+        }
     }
     char* getBuffer() const { return mBuffer; }
     size_t getSize() const { return mSize; }
@@ -128,17 +143,26 @@
             }
             case SharedMemType::GRALLOC: {
                 if (mSize != 0) {
-                    mGrallocWrapper->freeBuffer(mNativeHandle);
-                    mNativeHandle = nullptr;
+                    android::status_t status =
+                            android::GraphicBufferAllocator::get().free(mBufferHandle);
+                    if (status != android::OK) {
+                        ALOGE("SensorsAidlTestSharedMemory Gralloc failed to free buffer. Status: "
+                              "%s",
+                              android::statusToString(status).c_str());
+                    }
+                    mBufferHandle = nullptr;
+                    mBuffer = nullptr;
                     mSize = 0;
                 }
                 break;
             }
             default: {
-                if (mNativeHandle != nullptr || mSize != 0 || mBuffer != nullptr) {
-                    ALOGE("SensorsTestSharedMemory %p not properly destructed: "
-                          "type %d, native handle %p, size %zu, buffer %p",
-                          this, static_cast<int>(mType), mNativeHandle, mSize, mBuffer);
+                if (mNativeHandle != nullptr || mSize != 0 || mBuffer != nullptr ||
+                    mBufferHandle != nullptr) {
+                    ALOGE("SensorsAidlTestSharedMemory %p not properly destructed: "
+                          "type %d, native handle %p, size %zu, buffer %p, buffer handle %p",
+                          this, static_cast<int>(mType), mNativeHandle, mSize, mBuffer,
+                          mBufferHandle);
                 }
                 break;
             }
@@ -171,14 +195,33 @@
                 break;
             }
             case SharedMemType::GRALLOC: {
-                mGrallocWrapper = std::make_unique<::android::GrallocWrapper>();
-                if (!mGrallocWrapper->isInitialized()) {
+                static constexpr uint64_t kBufferUsage =
+                        static_cast<uint64_t>(BufferUsage::SENSOR_DIRECT_DATA) |
+                        static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN) |
+                        static_cast<uint64_t>(BufferUsage::CPU_WRITE_RARELY);
+
+                uint32_t stride = 0;
+                buffer_handle_t bufferHandle;
+                android::status_t status = android::GraphicBufferAllocator::get().allocate(
+                        size, 1, static_cast<int>(PixelFormat::BLOB), 1, kBufferUsage,
+                        &bufferHandle, &stride, "SensorVts");
+                if (status != android::OK) {
+                    ALOGE("SensorsAidlTestSharedMemory failed to allocate memory. Status: %s",
+                          android::statusToString(status).c_str());
                     break;
                 }
-
-                std::pair<native_handle_t*, void*> buf = mGrallocWrapper->allocate(size);
-                handle = buf.first;
-                buffer = static_cast<char*>(buf.second);
+                // Per the HAL, all-zeros Rect means the entire buffer
+                android::Rect rect = {0, 0, 0, 0};
+                void* ret;
+                status = android::GraphicBufferMapper::get().lock(bufferHandle, kBufferUsage, rect,
+                                                                  &ret);
+                if (status != android::OK) {
+                    ALOGE("SensorsAidlTestSharedMemory failed to import buffer: Status: %s",
+                          android::statusToString(status).c_str());
+                } else {
+                    buffer = static_cast<char*>(ret);
+                    mBufferHandle = bufferHandle;
+                }
                 break;
             }
             default:
@@ -194,9 +237,9 @@
 
     SharedMemType mType;
     native_handle_t* mNativeHandle;
+    buffer_handle_t mBufferHandle;
     size_t mSize;
     char* mBuffer;
-    std::unique_ptr<::android::GrallocWrapper> mGrallocWrapper;
 
     DISALLOW_COPY_AND_ASSIGN(SensorsTestSharedMemory);
 };
diff --git a/soundtrigger/2.0/default/OWNERS b/soundtrigger/2.0/default/OWNERS
deleted file mode 100644
index ed739cf..0000000
--- a/soundtrigger/2.0/default/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-elaurent@google.com
-mnaganov@google.com
-ytai@google.com
diff --git a/soundtrigger/2.0/vts/functional/OWNERS b/soundtrigger/2.0/vts/functional/OWNERS
deleted file mode 100644
index 3c24468..0000000
--- a/soundtrigger/2.0/vts/functional/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Bug component: 48436
-elaurent@google.com
-mdooley@google.com
-ytai@google.com
diff --git a/soundtrigger/2.1/vts/functional/OWNERS b/soundtrigger/2.1/vts/functional/OWNERS
deleted file mode 100644
index 3c24468..0000000
--- a/soundtrigger/2.1/vts/functional/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Bug component: 48436
-elaurent@google.com
-mdooley@google.com
-ytai@google.com
diff --git a/soundtrigger/2.2/vts/functional/OWNERS b/soundtrigger/2.2/vts/functional/OWNERS
deleted file mode 100644
index 43126f6..0000000
--- a/soundtrigger/2.2/vts/functional/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 48436
-ytai@google.com
-mdooley@google.com
diff --git a/soundtrigger/2.3/cli/OWNERS b/soundtrigger/2.3/cli/OWNERS
deleted file mode 100644
index 4fd27f3..0000000
--- a/soundtrigger/2.3/cli/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-include platform/frameworks/base:/services/core/java/com/android/server/soundtrigger_middleware/OWNERS
diff --git a/soundtrigger/2.3/vts/functional/OWNERS b/soundtrigger/2.3/vts/functional/OWNERS
deleted file mode 100644
index 3c24468..0000000
--- a/soundtrigger/2.3/vts/functional/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Bug component: 48436
-elaurent@google.com
-mdooley@google.com
-ytai@google.com
diff --git a/soundtrigger/OWNERS b/soundtrigger/OWNERS
new file mode 100644
index 0000000..3b35d27
--- /dev/null
+++ b/soundtrigger/OWNERS
@@ -0,0 +1,8 @@
+# Bug component: 48436
+
+include platform/frameworks/base:/media/aidl/android/media/soundtrigger_middleware/OWNERS
+include platform/frameworks/base:/services/core/java/com/android/server/soundtrigger_middleware/OWNERS
+
+elaurent@google.com
+mdooley@google.com
+mnaganov@google.com
diff --git a/soundtrigger/aidl/Android.bp b/soundtrigger/aidl/Android.bp
index 27d43d3..aa400c1 100644
--- a/soundtrigger/aidl/Android.bp
+++ b/soundtrigger/aidl/Android.bp
@@ -22,8 +22,8 @@
         "android/hardware/soundtrigger3/ISoundTriggerHwGlobalCallback.aidl",
     ],
     stability: "vintf",
-    imports: [
-        "android.media.soundtrigger.types-V1",
+    defaults: [
+        "latest_android_media_soundtrigger_types_import_interface",
     ],
     backend: {
         cpp: {
@@ -34,6 +34,7 @@
             sdk_version: "module_current",
         },
     },
+    frozen: false,
     versions_with_info: [
         {
             version: "1",
@@ -45,7 +46,7 @@
 }
 
 // Note: This should always be one version ahead of the last frozen version
-latest_android_hardware_soundtrigger3 = "android.hardware.soundtrigger3-V1"
+latest_android_hardware_soundtrigger3 = "android.hardware.soundtrigger3-V2"
 
 // Modules that depend on android.hardware.soundtrigger3 directly can include
 // the following java_defaults to avoid explicitly managing dependency versions
@@ -56,3 +57,10 @@
         latest_android_hardware_soundtrigger3 + "-java",
     ],
 }
+
+cc_defaults {
+    name: "latest_android_hardware_soundtrigger3_ndk_shared",
+    shared_libs: [
+        latest_android_hardware_soundtrigger3 + "-ndk",
+    ],
+}
diff --git a/soundtrigger/aidl/cli/OWNERS b/soundtrigger/aidl/cli/OWNERS
deleted file mode 100644
index 9f87c4c..0000000
--- a/soundtrigger/aidl/cli/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-include platform/frameworks/base:/media/aidl/android/media/soundtrigger_middleware/OWNERS
diff --git a/soundtrigger/aidl/cli/java/android/hardware/soundtrigger3/cli/SthalCli.java b/soundtrigger/aidl/cli/java/android/hardware/soundtrigger3/cli/SthalCli.java
index 127f062..41e2533 100644
--- a/soundtrigger/aidl/cli/java/android/hardware/soundtrigger3/cli/SthalCli.java
+++ b/soundtrigger/aidl/cli/java/android/hardware/soundtrigger3/cli/SthalCli.java
@@ -289,6 +289,8 @@
             Properties properties = new Properties();
             properties.implementor = "Android";
             properties.description = "Mock STHAL";
+            properties.uuid = "a5af2d2a-4cc4-4b69-a22f-c9d5b6d492c3";
+            properties.supportedModelArch = "Mock arch";
             properties.maxSoundModels = 2;
             properties.maxKeyPhrases = 1;
             properties.recognitionModes =
diff --git a/staging/OWNERS b/staging/OWNERS
new file mode 100644
index 0000000..a07824e
--- /dev/null
+++ b/staging/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 298954331
+
+include platform/hardware/interfaces:/OWNERS
diff --git a/staging/c2/aidl/Android.bp b/staging/c2/aidl/Android.bp
deleted file mode 100644
index b9da7ad..0000000
--- a/staging/c2/aidl/Android.bp
+++ /dev/null
@@ -1,39 +0,0 @@
-// This is the expected build file, but it may not be right in all cases
-
-package {
-    // See: http://go/android-license-faq
-    // A large-scale-change added 'default_applicable_licenses' to import
-    // all of the 'license_kinds' from "hardware_interfaces_license"
-    // to get the below license kinds:
-    //   SPDX-license-identifier-Apache-2.0
-    default_applicable_licenses: ["hardware_interfaces_license"],
-}
-
-aidl_interface {
-    name: "android.hardware.media.c2",
-    vendor_available: true,
-    double_loadable: true,
-    unstable: true,
-    srcs: ["android/hardware/media/c2/*.aidl"],
-    include_dirs: [
-        "frameworks/native/aidl/gui",
-    ],
-    imports: [
-        "android.hardware.common-V2",
-        "android.hardware.media.bufferpool2-V1",
-    ],
-    backend: {
-        cpp: {
-            enabled: false,
-        },
-        java: {
-            enabled: false,
-        },
-        ndk: {
-            enabled: true,
-            additional_shared_libraries: [
-                "libnativewindow",
-            ],
-        },
-    },
-}
diff --git a/staging/c2/aidl/android/hardware/media/c2/BaseBlock.aidl b/staging/c2/aidl/android/hardware/media/c2/BaseBlock.aidl
deleted file mode 100644
index 16e7653..0000000
--- a/staging/c2/aidl/android/hardware/media/c2/BaseBlock.aidl
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.media.c2;
-
-import android.hardware.common.NativeHandle;
-
-/**
- * Storage type for `BaseBlock`.
- *
- * A `BaseBlock` is a representation of a codec memory block. Coded data,
- * decoded data, codec-specific data, and other codec-related data are all sent
- * in the form of BaseBlocks.
- */
-union BaseBlock {
-    /**
-     * #nativeBlock is the opaque representation of a buffer.
-     */
-    NativeHandle nativeBlock;
-    /**
-     * #pooledBlock is a reference to a buffer handled by a BufferPool.
-     */
-    android.hardware.media.bufferpool2.BufferStatusMessage pooledBlock;
-}
diff --git a/staging/c2/aidl/android/hardware/media/c2/Block.aidl b/staging/c2/aidl/android/hardware/media/c2/Block.aidl
deleted file mode 100644
index 4da8490..0000000
--- a/staging/c2/aidl/android/hardware/media/c2/Block.aidl
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.media.c2;
-
-import android.hardware.common.NativeHandle;
-import android.hardware.media.c2.Params;
-
-/**
- * Reference to a @ref BaseBlock within a @ref WorkBundle.
- *
- * `Block` contains additional attributes that `BaseBlock` does not. These
- * attributes may differ among `Block` objects that refer to the same
- * `BaseBlock` in the same `WorkBundle`.
- */
-parcelable Block {
-    /**
-     * Identity of a `BaseBlock` within a `WorkBundle`. This is an index into
-     * #WorkBundle.baseBlocks.
-     */
-    int index;
-    /**
-     * Metadata associated with this `Block`.
-     */
-    Params meta;
-    /**
-     * Fence for synchronizing `Block` access.
-     */
-    NativeHandle fence;
-}
diff --git a/staging/c2/aidl/android/hardware/media/c2/Buffer.aidl b/staging/c2/aidl/android/hardware/media/c2/Buffer.aidl
deleted file mode 100644
index fe01b64..0000000
--- a/staging/c2/aidl/android/hardware/media/c2/Buffer.aidl
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.media.c2;
-
-import android.hardware.media.c2.Block;
-import android.hardware.media.c2.Params;
-
-/**
- * A codec buffer, which is a collection of @ref Block objects and metadata.
- *
- * This is a part of @ref FrameData.
- */
-parcelable Buffer {
-    /**
-     * Metadata associated with the buffer.
-     */
-    Params info;
-    /**
-     * Blocks contained in the buffer.
-     */
-    Block[] blocks;
-}
diff --git a/staging/c2/aidl/android/hardware/media/c2/FieldDescriptor.aidl b/staging/c2/aidl/android/hardware/media/c2/FieldDescriptor.aidl
deleted file mode 100644
index 3dd14cd..0000000
--- a/staging/c2/aidl/android/hardware/media/c2/FieldDescriptor.aidl
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.media.c2;
-
-import android.hardware.media.c2.FieldId;
-
-/**
- * Description of a field inside a C2Param structure.
- */
-parcelable FieldDescriptor {
-    /**
-     * Possible types of the field.
-     */
-    @Backing(type="int")
-    enum Type {
-        NO_INIT = 0,
-        INT32,
-        UINT32,
-        CNTR32,
-        INT64,
-        UINT64,
-        CNTR64,
-        FLOAT,
-        /**
-         * Fixed-size string (POD).
-         */
-        STRING = 0x100,
-        /**
-         * A blob has no sub-elements and can be thought of as an array of
-         * bytes. However, bytes cannot be individually addressed by clients.
-         */
-        BLOB,
-        /**
-         * The field is a structure that may contain other fields.
-         */
-        STRUCT = 0x20000,
-    }
-    /**
-     * Named value type. This is used for defining an enum value for a numeric
-     * type.
-     */
-    parcelable NamedValue {
-        /**
-         * Name of the enum value. This must be unique for each enum value in
-         * the same field.
-         */
-        String name;
-        /**
-         * Underlying value of the enum value. Multiple enum names may have the
-         * same underlying value.
-         */
-        long value;
-    }
-    /**
-     * Location of the field in the C2Param structure
-     */
-    FieldId fieldId;
-    /**
-     * Type of the field.
-     */
-    Type type;
-    /**
-     * If #type is #Type.STRUCT, #structIndex is the C2Param structure index;
-     * otherwise, #structIndex is not used.
-     */
-    int structIndex;
-    /**
-     * Extent of the field.
-     * - For a non-array field, #extent is 1.
-     * - For a fixed-length array field, #extent is the length. An array field
-     *   of length 1 is indistinguishable from a non-array field.
-     * - For a variable-length array field, #extent is 0. This can only occur as
-     *   the last member of a C2Param structure.
-     */
-    int extent;
-    /**
-     * Name of the field. This must be unique for each field in the same
-     * structure.
-     */
-    String name;
-    /**
-     * List of enum values. This is not used when #type is not one of the
-     * numeric types.
-     */
-    NamedValue[] namedValues;
-}
diff --git a/staging/c2/aidl/android/hardware/media/c2/FieldId.aidl b/staging/c2/aidl/android/hardware/media/c2/FieldId.aidl
deleted file mode 100644
index c53f7a5..0000000
--- a/staging/c2/aidl/android/hardware/media/c2/FieldId.aidl
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.media.c2;
-
-/**
- * Identifying information of a field relative to a known C2Param structure.
- *
- * Within a given C2Param structure, each field is uniquely identified by @ref
- * FieldId.
- */
-parcelable FieldId {
-    /**
-     * Offset of the field in bytes.
-     */
-    int offset;
-    /**
-     * Size of the field in bytes.
-     */
-    int sizeBytes;
-}
diff --git a/staging/c2/aidl/android/hardware/media/c2/FieldSupportedValues.aidl b/staging/c2/aidl/android/hardware/media/c2/FieldSupportedValues.aidl
deleted file mode 100644
index 5f4ad2a..0000000
--- a/staging/c2/aidl/android/hardware/media/c2/FieldSupportedValues.aidl
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.media.c2;
-
-import android.hardware.media.c2.ValueRange;
-
-/*
- * Description of supported values for a field of C2Param.
- *
- * This can be a continuous range or a discrete set of values.
- *
- * The intended type of values must be made clear in the context where
- * `FieldSupportedValues` is used.
- */
-union FieldSupportedValues {
-    /**
-     * No supported values
-     */
-    boolean empty;
-    /**
-     * Numeric range, described in a #ValueRange structure
-     */
-    ValueRange range;
-    /**
-     * List of values
-     */
-    long[] values;
-    /**
-     * List of flags that can be OR-ed.
-     *
-     * The list contains { min-mask, flag1, flag2... }. Basically, the first
-     * value is the required set of flags to be set, and the rest of the values are flags that can
-     * be set independently. FLAGS is only supported for integral types. Supported flags should
-     * not overlap, as it can make validation non-deterministic. The standard validation method
-     * is that starting from the original value, if each flag is removed when fully present (the
-     * min-mask must be fully present), we shall arrive at 0.
-     */
-    long[] flags;
-}
diff --git a/staging/c2/aidl/android/hardware/media/c2/FieldSupportedValuesQuery.aidl b/staging/c2/aidl/android/hardware/media/c2/FieldSupportedValuesQuery.aidl
deleted file mode 100644
index 33a8170..0000000
--- a/staging/c2/aidl/android/hardware/media/c2/FieldSupportedValuesQuery.aidl
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.media.c2;
-
-import android.hardware.media.c2.ParamField;
-
-/**
- * Query information for supported values of a field. This is used as input to
- * IConfigurable::querySupportedValues().
- */
-parcelable FieldSupportedValuesQuery {
-    @Backing(type="int")
-    enum Type {
-        /**
-         * Query all possible values regardless of other settings.
-         */
-        POSSIBLE = 0,
-        /**
-         * Query currently possible values given dependent settings.
-         */
-        CURRENT,
-    }
-    /**
-     * Identity of the field to query.
-     */
-    ParamField field;
-    /**
-     * Type of the query. See #Type for more information.
-     */
-    Type type;
-}
diff --git a/staging/c2/aidl/android/hardware/media/c2/FieldSupportedValuesQueryResult.aidl b/staging/c2/aidl/android/hardware/media/c2/FieldSupportedValuesQueryResult.aidl
deleted file mode 100644
index 133712a..0000000
--- a/staging/c2/aidl/android/hardware/media/c2/FieldSupportedValuesQueryResult.aidl
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.media.c2;
-
-import android.hardware.media.c2.FieldSupportedValues;
-import android.hardware.media.c2.Status;
-
-/**
- * This structure is used to hold the result from
- * IConfigurable::querySupportedValues().
- */
-parcelable FieldSupportedValuesQueryResult {
-    /**
-     * Result of the query. Possible values are
-     * - `Status::OK`: The query was successful.
-     * - `Status::BAD_STATE`: The query was requested when the `IConfigurable` instance
-     *   was in a bad state.
-     * - `Status::BAD_INDEX`: The requested field was not recognized.
-     * - `Status::TIMED_OUT`: The query could not be completed in a timely manner.
-     * - `Status::BLOCKING`: The query must block, but the parameter `mayBlock` in the
-     *   call to `querySupportedValues()` was `false`.
-     * - `Status::CORRUPTED`: Some unknown error occurred.
-     */
-    Status status;
-    /**
-     * Supported values. This is meaningful only when #status is `OK`.
-     */
-    FieldSupportedValues values;
-}
diff --git a/staging/c2/aidl/android/hardware/media/c2/FrameData.aidl b/staging/c2/aidl/android/hardware/media/c2/FrameData.aidl
deleted file mode 100644
index 81c76be..0000000
--- a/staging/c2/aidl/android/hardware/media/c2/FrameData.aidl
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.media.c2;
-
-import android.hardware.media.c2.Buffer;
-import android.hardware.media.c2.InfoBuffer;
-import android.hardware.media.c2.Params;
-import android.hardware.media.c2.WorkOrdinal;
-
-/**
- * Data for an input frame or an output frame.
- *
- * This structure represents a @e frame with its metadata. A @e frame consists
- * of an ordered set of buffers, configuration changes, and info buffers along
- * with some non-configuration metadata.
- *
- * @note `FrameData` is the HIDL counterpart of `C2FrameData` in the Codec 2.0
- * standard.
- */
-parcelable FrameData {
-    /** List of frame flags */
-    /**
-     * For input frames: no output frame shall be generated when processing
-     * this frame, but metadata must still be processed.
-     *
-     * For output frames: this frame must be discarded but metadata is still
-     * valid.
-     */
-    const int DROP_FRAME = (1 << 0);
-    /**
-     * This frame is the last frame of the current stream. Further frames
-     * are part of a new stream.
-     */
-    const int END_OF_STREAM = (1 << 1);
-    /**
-     * This frame must be discarded with its metadata.
-     *
-     * This flag is only set by components, e.g. as a response to the flush
-     * command.
-     */
-    const int DISCARD_FRAME = (1 << 2);
-    /**
-     * This frame is not the last frame produced for the input.
-     *
-     * This flag is normally set by the component - e.g. when an input frame
-     * results in multiple output frames, this flag is set on all but the
-     * last output frame.
-     *
-     * Also, when components are chained, this flag should be propagated
-     * down the work chain. That is, if set on an earlier frame of a
-     * work-chain, it should be propagated to all later frames in that
-     * chain. Additionally, components down the chain could set this flag
-     * even if not set earlier, e.g. if multiple output frames are generated
-     * at that component for the input frame.
-     */
-    const int FLAG_INCOMPLETE = (1 << 3);
-    /**
-     * This frame contains only codec-specific configuration data, and no
-     * actual access unit.
-     */
-    const int CODEC_CONFIG = (1 << 31);
-    /**
-     * Frame flags, as described above.
-     */
-    int flags;
-    /**
-     * @ref WorkOrdinal of the frame.
-     */
-    WorkOrdinal ordinal;
-    /**
-     * List of frame buffers.
-     */
-    Buffer[] buffers;
-    /**
-     * List of configuration updates.
-     */
-    Params configUpdate;
-    /**
-     * List of info buffers.
-     */
-    InfoBuffer[] infoBuffers;
-}
diff --git a/staging/c2/aidl/android/hardware/media/c2/IComponent.aidl b/staging/c2/aidl/android/hardware/media/c2/IComponent.aidl
deleted file mode 100644
index bea4b70..0000000
--- a/staging/c2/aidl/android/hardware/media/c2/IComponent.aidl
+++ /dev/null
@@ -1,303 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.media.c2;
-
-import android.hardware.common.NativeHandle;
-import android.view.Surface;
-
-import android.hardware.media.c2.IComponentInterface;
-import android.hardware.media.c2.IConfigurable;
-import android.hardware.media.c2.WorkBundle;
-import android.hardware.media.c2.SurfaceSyncObj;
-
-/**
- * Interface for an AIDL Codec2 component.
- * Components have two states: stopped and running. The running state has three
- * sub-states: executing, tripped and error.
- *
- * All methods in `IComponent` must not block. If a method call cannot be
- * completed in a timely manner, it must throw `Status::TIMED_OUT`.
- */
-interface IComponent {
-    /**
-     * The reference object from framwork to HAL C2BlockPool.
-     *
-     * The object will be returned when C2BlockPool is created by a framework
-     * request. The object also can be destroyed using blockPoolId.
-     * Using configurable framework can query/config the object in HAL(IComponent).
-     */
-    parcelable BlockPool {
-        long blockPoolId;
-        IConfigurable configurable;
-    }
-    /**
-     * Configures a component for a tunneled playback mode.
-     *
-     * A successful call to this method puts the component in the *tunneled*
-     * mode. In this mode, the output `Worklet`s returned in
-     * IComponentListener::onWorkDone() may not contain any buffers. The output
-     * buffers are passed directly to the consumer end of a buffer queue whose
-     * producer side is configured with the returned @p sidebandStream passed
-     * to IGraphicBufferProducer::setSidebandStream().
-     *
-     * The component is initially in the non-tunneled mode by default. The
-     * tunneled mode can be toggled on only before the component starts
-     * processing. Once the component is put into the tunneled mode, it shall
-     * stay in the tunneled mode until and only until reset() is called.
-     *
-     * @param avSyncHwId A resource ID for hardware sync. The generator of sync
-     *     IDs must ensure that this number is unique among all services at any
-     *     given time. For example, if both the audio HAL and the tuner HAL
-     *     support this feature, sync IDs from the audio HAL must not clash
-     *     with sync IDs from the tuner HAL.
-     * @return Codec-allocated sideband stream NativeHandle. This can
-     *     be passed to IGraphicBufferProducer::setSidebandStream() to
-     *     establish a direct channel to the consumer.
-     * @throws ServiceSpecificException with one of the following values:
-     *   - `Status::OMITTED`   - The component does not support video tunneling.
-     *   - `Status::BAD_STATE` - The component is already running.
-     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
-     *   - `Status::CORRUPTED` - Some unknown error occurred.
-     */
-    NativeHandle configureVideoTunnel(in int avSyncHwId);
-
-    /**
-     * Creates a local `C2BlockPool` backed by the given allocator and returns
-     * its id.
-     *
-     * The returned @p blockPoolId is the only way the client can refer to a
-     * `C2BlockPool` object in the component. The id can be passed to
-     * setOutputSurface() or used in some C2Param objects later.
-     *
-     * The created `C2BlockPool` object can be destroyed by calling
-     * destroyBlockPool(), reset() or release(). reset() and release() must
-     * destroy all `C2BlockPool` objects that have been created.
-     *
-     * @param allocatorId Id of a `C2Allocator`.
-     * @param out configurable Configuration interface for the created pool. This
-     *     must not be null.
-     * @return Created block pool information. This could be used to config/query and
-     * also be used in setOutputSurface() if the allocator
-     * @throws ServiceSpecificException with one of the following values:
-     *   - `Status::NO_MEMORY` - Not enough memory to create the pool.
-     *   - `Status::BAD_VALUE` - @p allocatorId is not recognized.
-     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
-     *   - `Status::CORRUPTED` - Some unknown error occurred.
-     */
-    BlockPool createBlockPool(in int allocatorId);
-
-    /**
-     * Destroys a local block pool previously created by createBlockPool().
-     *
-     * @param blockPoolId Id of a `C2BlockPool` that was previously returned by
-     *      createBlockPool().
-     * @throws ServiceSpecificException with one of the following values:
-     *   - `Status::NOT_FOUND` - The supplied blockPoolId is not valid.
-     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
-     *   - `Status::CORRUPTED` - Some unknown error occurred.
-     */
-    void destroyBlockPool(in long blockPoolId);
-
-    /**
-     * Drains the component, and optionally downstream components. This is a
-     * signalling method; as such it does not wait for any work completion.
-     *
-     * The last `Work` item is marked as "drain-till-here", so the component is
-     * notified not to wait for further `Work` before it processes what is
-     * already queued. This method can also be used to set the end-of-stream
-     * flag after `Work` has been queued. Client can continue to queue further
-     * `Work` immediately after this method returns.
-     *
-     * This method must be supported in running (including tripped) states.
-     *
-     * `Work` that is completed must be returned via
-     * IComponentListener::onWorkDone().
-     *
-     * @param withEos Whether to drain the component with marking end-of-stream.
-     * @throws ServiceSpecificException with one of the following values:
-     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
-     *   - `Status::CORRUPTED` - Some unknown error occurred.
-     */
-    void drain(in boolean withEos);
-
-    /**
-     * Discards and abandons any pending `Work` items for the component.
-     *
-     * This method must be supported in running (including tripped) states.
-     *
-     * `Work` that could be immediately abandoned/discarded must be returned in
-     * @p flushedWorkBundle. The order in which queued `Work` items are
-     * discarded can be arbitrary.
-     *
-     * `Work` that could not be abandoned or discarded immediately must be
-     * marked to be discarded at the earliest opportunity, and must be returned
-     * via IComponentListener::onWorkDone(). This must be completed within
-     * 500ms.
-     *
-     * @return `WorkBundle` object containing flushed `Work` items.
-     * @throws ServiceSpecificException with one of the following values:
-     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
-     *   - `Status::CORRUPTED` - Some unknown error occurred.
-     */
-    WorkBundle flush();
-
-    /**
-     * Returns the @ref IComponentInterface instance associated to this
-     * component.
-     *
-     * An @ref IConfigurable instance for the component can be obtained by calling
-     * IComponentInterface::getConfigurable() on the returned @p intf.
-     *
-     * @return `IComponentInterface` instance. This must not be null.
-     */
-    IComponentInterface getInterface();
-
-    /**
-     * Queues up work for the component.
-     *
-     * This method must be supported in running (including tripped) states.
-     *
-     * It is acceptable for this method to return `OK` and return an error value
-     * using the IComponentListener::onWorkDone() callback.
-     *
-     * @param workBundle `WorkBundle` object containing a list of `Work` objects
-     *     to queue to the component.
-     * @throws ServiceSpecificException with one of the following values:
-     *   - `Status::BAD_INDEX` - Some component id in some `Worklet` is not valid.
-     *   - `Status::CANNOT_DO` - The components are not tunneled but some `Work` object
-     *                   contains tunneling information.
-     *   - `Status::NO_MEMORY` - Not enough memory to queue @p workBundle.
-     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
-     *   - `Status::CORRUPTED` - Some unknown error occurred.
-     */
-    void queue(in WorkBundle workBundle);
-
-    /**
-     * Releases the component.
-     *
-     * This method must be supported in stopped state.
-     *
-     * This method destroys the component. Upon return, if @p status is `OK` or
-     * `DUPLICATE`, all resources must have been released.
-     *
-     * @throws ServiceSpecificException with one of the following values:
-     *   - `Status::BAD_STATE` - The component is running.
-     *   - `Status::DUPLICATE` - The component is already released.
-     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
-     *   - `Status::CORRUPTED` - Some unknown error occurred.
-     */
-    void release();
-
-    /**
-     * Resets the component.
-     *
-     * This method must be supported in all (including tripped) states other
-     * than released.
-     *
-     * This method must be supported during any other blocking call.
-     *
-     * This method must return within 500ms.
-     *
-     * When this call returns, if @p status is `OK`, all `Work` items must
-     * have been abandoned, and all resources (including `C2BlockPool` objects
-     * previously created by createBlockPool()) must have been released.
-     *
-     * If the return value is `BAD_STATE` or `DUPLICATE`, no state change is
-     * expected as a response to this call. For all other return values, the
-     * component must be in the stopped state.
-     *
-     * This brings settings back to their default, "guaranteeing" no tripped
-     * state.
-     *
-     * @throws ServiceSpecificException with one of the following values:
-     *   - `Status::BAD_STATE` - Component is in released state.
-     *   - `Status::DUPLICATE` - When called during another reset call from another
-     *                   thread.
-     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
-     *   - `Status::CORRUPTED` - Some unknown error occurred.
-     */
-    void reset();
-
-    /**
-     * Starts using a surface for output with a synchronization object
-     *
-     * This method must not block.
-     *
-     * @param blockPoolId Id of the `C2BlockPool` to be associated with the
-     *     output surface.
-     * @param surface Output surface.
-     * @param syncObject synchronization object for buffer allocation between
-     *     Framework and Component.
-     * @throws ServiceSpecificException with one of the following values:
-     *   - `Status::CANNOT_DO` - The component does not support an output surface.
-     *   - `Status::REFUSED`   - The output surface cannot be accessed.
-     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
-     *   - `Status::CORRUPTED` - Some unknown error occurred.
-     */
-    void setOutputSurface(in long blockPoolId, in Surface surface,
-        in SurfaceSyncObj syncObject);
-
-    /**
-     * Starts the component.
-     *
-     * This method must be supported in stopped state as well as tripped state.
-     *
-     * If the return value is `OK`, the component must be in the running state.
-     * If the return value is `BAD_STATE` or `DUPLICATE`, no state change is
-     * expected as a response to this call. Otherwise, the component must be in
-     * the stopped state.
-     *
-     * If a component is in the tripped state and start() is called while the
-     * component configuration still results in a trip, start() must succeed and
-     * a new onTripped() callback must be used to communicate the configuration
-     * conflict that results in the new trip.
-     *
-     * @throws ServiceSpecificException with one of the following values:
-     *   - `Status::BAD_STATE` - Component is not in stopped or tripped state.
-     *   - `Status::DUPLICATE` - When called during another start call from another
-     *                   thread.
-     *   - `Status::NO_MEMORY` - Not enough memory to start the component.
-     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
-     *   - `Status::CORRUPTED` - Some unknown error occurred.
-     */
-    void start();
-
-    /**
-     * Stops the component.
-     *
-     * This method must be supported in running (including tripped) state.
-     *
-     * This method must return within 500ms.
-     *
-     * Upon this call, all pending `Work` must be abandoned.
-     *
-     * If the return value is `BAD_STATE` or `DUPLICATE`, no state change is
-     * expected as a response to this call. For all other return values, the
-     * component must be in the stopped state.
-     *
-     * This does not alter any settings and tunings that may have resulted in a
-     * tripped state.
-     *
-     * @throws ServiceSpecificException with one of the following values:
-     *   - `Status::BAD_STATE` - Component is not in running state.
-     *   - `Status::DUPLICATE` - When called during another stop call from another
-     *                   thread.
-     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
-     *   - `Status::CORRUPTED` - Some unknown error occurred.
-     */
-    void stop();
-}
diff --git a/staging/c2/aidl/android/hardware/media/c2/IComponentInterface.aidl b/staging/c2/aidl/android/hardware/media/c2/IComponentInterface.aidl
deleted file mode 100644
index 4589115..0000000
--- a/staging/c2/aidl/android/hardware/media/c2/IComponentInterface.aidl
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.media.c2;
-
-import android.hardware.media.c2.IConfigurable;
-
-/**
- * Component interface object. This object contains all of the configurations of
- * a potential or actual component. It can be created and used independently of
- * an actual Codec2 component to query supported parameters for various
- * component settings, and configurations for a potential component.
- *
- * An actual component exposes this interface via IComponent::getInterface().
- */
-interface IComponentInterface {
-    /**
-     * Returns the @ref IConfigurable instance associated to this component
-     * interface.
-     *
-     * @return `IConfigurable` instance. This must not be null.
-     */
-    IConfigurable getConfigurable();
-}
diff --git a/staging/c2/aidl/android/hardware/media/c2/IComponentListener.aidl b/staging/c2/aidl/android/hardware/media/c2/IComponentListener.aidl
deleted file mode 100644
index 786c8f1..0000000
--- a/staging/c2/aidl/android/hardware/media/c2/IComponentListener.aidl
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.media.c2;
-
-import android.hardware.media.c2.SettingResult;
-import android.hardware.media.c2.Status;
-import android.hardware.media.c2.WorkBundle;
-
-/**
- * Callback interface for handling notifications from @ref IComponent.
- */
-oneway interface IComponentListener {
-    /**
-     * Identifying information for an input buffer previously queued to the
-     * component via IComponent::queue().
-     */
-    parcelable InputBuffer {
-        /**
-         * This value comes from `Work::input.ordinal.frameIndex` in a `Work`
-         * object that was previously queued.
-         */
-        long frameIndex;
-        /**
-         * This value is an index into `Work::input.buffers` (which is an array)
-         * in a `Work` object that was previously queued.
-         */
-        int arrayIndex;
-    }
-    /**
-     * Information about rendering of a frame to a `Surface`.
-     */
-    parcelable RenderedFrame {
-        /**
-         * Id of the `BufferQueue` containing the rendered buffer.
-         *
-         * This value must have been obtained by an earlier call to
-         * IGraphicBufferProducer::getUniqueId().
-         */
-        long bufferQueueId;
-        /**
-         * Id of the slot of the rendered buffer.
-         *
-         * This value must have been obtained by an earlier call to
-         * IGraphicBufferProducer::dequeueBuffer() or
-         * IGraphicBufferProducer::attachBuffer().
-         */
-        int slotId;
-        /**
-         * Timestamp the rendering happened.
-         *
-         * The reference point for the timestamp is determined by the
-         * `BufferQueue` that performed the rendering.
-         */
-        long timestampNs;
-    }
-    /**
-     * Notify the listener of an error.
-     *
-     * @param status Error type. @p status may be `OK`, which means that an
-     *     error has occurred, but the error type does not fit into the type
-     *     `Status`. In this case, additional information is provided by
-     *     @p errorCode.
-     * @param errorCode Additional error information. The framework may not
-     *     recognize the meaning of this value.
-     */
-    void onError(in Status status, in int errorCode);
-
-    /**
-     * Notify the listener that frames have been rendered.
-     *
-     * @param renderedFrames List of @ref RenderedFrame objects.
-     */
-    void onFramesRendered(in RenderedFrame[] renderedFrames);
-
-    /**
-     * Notify the listener that some input buffers are no longer needed by the
-     * component, and hence can be released or reused by the client.
-     *
-     * Input buffers that are contained in a `Work` object returned by an
-     * earlier onWorkDone() call are assumed released, so they must not appear
-     * in any onInputBuffersReleased() calls. That means
-     * onInputBuffersReleased() must only report input buffers that are released
-     * before the output in the same `Work` item is produced. However, it is
-     * possible for an input buffer to be returned by onWorkDone() after it has
-     * been reported by onInputBuffersReleased().
-     *
-     * @note onWorkDone() and onInputBuffersReleased() both notify the client
-     * that input buffers are no longer needed. However, in order to minimize
-     * IPC calls, onInputBuffersReleased() should be called only when
-     * onWorkDone() cannot be called, e.g., the component needs more input
-     * before an output can be produced.
-     *
-     * @param inputBuffers List of `InputBuffer` objects, identifying input
-     * buffers that are no longer needed by the component.
-     */
-    void onInputBuffersReleased(in InputBuffer[] inputBuffers);
-
-    /**
-     * Notify the listener that the component is tripped.
-     *
-     * @param settingResults List of failures.
-     */
-    void onTripped(in SettingResult[] settingResults);
-
-    /**
-     * Notify the listener that some `Work` items have been completed.
-     *
-     * All the input buffers in the returned `Work` objects must not be used by
-     * the component after onWorkDone() is called.
-     *
-     * @param workBundle List of completed `Work` objects.
-     */
-    void onWorkDone(in WorkBundle workBundle);
-}
diff --git a/staging/c2/aidl/android/hardware/media/c2/IComponentStore.aidl b/staging/c2/aidl/android/hardware/media/c2/IComponentStore.aidl
deleted file mode 100644
index d332bd3..0000000
--- a/staging/c2/aidl/android/hardware/media/c2/IComponentStore.aidl
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.media.c2;
-
-import android.hardware.media.c2.Buffer;
-import android.hardware.media.c2.IComponent;
-import android.hardware.media.c2.IComponentInterface;
-import android.hardware.media.c2.IComponentListener;
-import android.hardware.media.c2.IConfigurable;
-import android.hardware.media.c2.StructDescriptor;
-
-/**
- * Entry point for Codec2 HAL.
- *
- * All methods in `IComponentStore` must not block. If a method call cannot be
- * completed in a timely manner, it must throw `Status::TIMED_OUT`. The only
- * exceptions are getPoolClientManager() and getConfigurable(),  which must
- * always return immediately.
- *
- * @note This is an extension of version 1.1 of `IComponentStore`. The purpose
- * of the extension is to add support for blocking output buffer allocator.
- */
-interface IComponentStore {
-    /**
-     * Component traits.
-     */
-    parcelable ComponentTraits {
-        @Backing(type="int")
-        enum Kind {
-            OTHER = 0,
-            DECODER,
-            ENCODER,
-        }
-        @Backing(type="int")
-        enum Domain {
-            OTHER = 0,
-            VIDEO,
-            AUDIO,
-            IMAGE,
-        }
-        /**
-         * Name of the component. This must be unique for each component.
-         *
-         * This name is use to identify the component to create in
-         * createComponent() and createComponentInterface().
-         */
-        String name;
-        /**
-         * Component domain.
-         */
-        Domain domain;
-        /**
-         * Component kind.
-         */
-        Kind kind;
-        /**
-         * Rank used by `MediaCodecList` to determine component ordering. Lower
-         * value means higher priority.
-         */
-        int rank;
-        /**
-         * MIME type.
-         */
-        String mediaType;
-        /**
-         * Aliases for component name for backward compatibility.
-         *
-         * Multiple components can have the same alias (but not the same
-         * component name) as long as their media types differ.
-         */
-        String[] aliases;
-    }
-
-    /**
-     * Copies the contents of @p src into @p dst without changing the format of
-     * @p dst.
-     *
-     * @param src Source buffer.
-     * @param dst Destination buffer.
-     * @throws ServiceSpecificException with one of the following values:
-     *   - `Status::CANNOT_DO` - @p src and @p dst are not compatible.
-     *   - `Status::REFUSED`   - No permission to copy.
-     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
-     *   - `Status::CORRUPTED` - Some unknown error occurred.
-     */
-    void copyBuffer(in Buffer src, in Buffer dst);
-
-    /**
-     * Creates a component by name.
-     *
-     * @param name Name of the component to create. This must match one of the
-     *     names returned by listComponents().
-     * @param listener Callback receiver.
-     * @param pool `IClientManager` object of the BufferPool in the client
-     *     process. This may be null if the client does not own a BufferPool.
-     * @return The created component.
-     * @throws ServiceSpecificException with one of the following values:
-     *   - `Status::NOT_FOUND` - There is no component with the given name.
-     *   - `Status::NO_MEMORY` - Not enough memory to create the component.
-     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
-     *   - `Status::CORRUPTED` - Some unknown error occurred.
-     *
-     * @sa IComponentListener.
-     */
-    IComponent createComponent(in String name, in IComponentListener listener,
-        in android.hardware.media.bufferpool2.IClientManager pool);
-
-    /**
-     * Creates a component interface by name.
-     *
-     * @param name Name of the component interface to create. This should match
-     *     one of the names returned by listComponents().
-     * @return The created component interface.
-     * @throws ServiceSpecificException with one of the following values:
-     *   - `Status::NOT_FOUND` - There is no component interface with the given name.
-     *   - `Status::NO_MEMORY` - Not enough memory to create the component interface.
-     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
-     *   - `Status::CORRUPTED` - Some unknown error occurred.
-     */
-    IComponentInterface createInterface(in String name);
-
-    /**
-     * Returns the @ref IConfigurable instance associated to this component
-     * store.
-     *
-     * @return `IConfigurable` instance. This must not be null.
-     */
-    IConfigurable getConfigurable();
-
-    /**
-     * Returns the `IClientManager` object for the component's BufferPool.
-     *
-     * @return If the component store supports receiving buffers via
-     *     BufferPool API, @p pool must be a valid `IClientManager` instance.
-     *     Otherwise, @p pool must be null.
-     */
-    android.hardware.media.bufferpool2.IClientManager getPoolClientManager();
-
-    /**
-     * Returns a list of `StructDescriptor` objects for a set of requested
-     * C2Param structure indices that this store is aware of.
-     *
-     * This operation must be performed at best effort, e.g. the component
-     * store must simply ignore all struct indices that it is not aware of.
-     *
-     * @param indices Indices of C2Param structures to describe.
-     * @return List of `StructDescriptor` objects.
-     * @throws ServiceSpecificException with one of the following values:
-     *   - `Status::NOT_FOUND` - Some indices were not known.
-     *   - `Status::NO_MEMORY` - Not enough memory to complete this method.
-     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
-     *   - `Status::CORRUPTED` - Some unknown error occurred.
-     */
-    StructDescriptor[] getStructDescriptors(in int[] indices);
-
-    /**
-     * Returns the list of components supported by this component store.
-     *
-     * @return traits List of component traits for all components supported by
-     *     this store (in no particular order).
-     * @throws ServiceSpecificException with one of the following values:
-     *   - `Status::NO_MEMORY` - Not enough memory to complete this method.
-     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
-     *   - `Status::CORRUPTED` - Some unknown error occurred.
-     */
-    ComponentTraits[] listComponents();
-}
diff --git a/staging/c2/aidl/android/hardware/media/c2/IConfigurable.aidl b/staging/c2/aidl/android/hardware/media/c2/IConfigurable.aidl
deleted file mode 100644
index 9f79576..0000000
--- a/staging/c2/aidl/android/hardware/media/c2/IConfigurable.aidl
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.media.c2;
-
-import android.hardware.media.c2.FieldSupportedValuesQuery;
-import android.hardware.media.c2.FieldSupportedValuesQueryResult;
-import android.hardware.media.c2.ParamDescriptor;
-import android.hardware.media.c2.Params;
-import android.hardware.media.c2.SettingResult;
-
-/**
- * Generic configuration interface presented by all configurable Codec2 objects.
- *
- * This interface must be supported in all states of the owning object, and must
- * not change the state of the owning object.
- */
-interface IConfigurable {
-    /**
-     * Return parcelable for config() interface.
-     *
-     * This includes the successful config settings along with the failure reasons of
-     * the specified setting.
-     */
-    parcelable ConfigResult {
-        Params params;
-        SettingResult[] failures;
-    }
-
-    /**
-     * Sets a set of parameters for the object.
-     *
-     * Tuning is performed at best effort: the object must update all supported
-     * configurations at best effort and skip unsupported parameters. Any errors
-     * are communicated in the return value along with the failures.
-     *
-     * A non-strict parameter update with an unsupported value shall cause an
-     * update to the closest supported value. A strict parameter update with an
-     * unsupported value shall be skipped and a failure shall be returned.
-     *
-     * If @p mayBlock is false, this method must not block. An update that
-     * requires blocking shall be skipped and a failure shall be returned.
-     *
-     * If @p mayBlock is true, an update may block, but the whole method call
-     * has to complete in a timely manner, or `Status::TIMED_OUT` is thrown.
-     *
-     * The final values for all parameters set are propagated back to the caller
-     * in @p params.
-     *
-     * \par For IComponent
-     *
-     * When the object type is @ref IComponent, this method must be supported in
-     * any state except released.
-     *
-     * The blocking behavior of this method differs among states:
-     *   - In the stopped state, this must be non-blocking. @p mayBlock is
-     *     ignored. (The method operates as if @p mayBlock was false.)
-     *   - In any of the running states, this method may block momentarily if
-     *     @p mayBlock is true. However, if the call cannot be completed in a
-     *     timely manner, `Status::TIMED_OUT` is thrown.
-     *
-     * @note Parameter tuning @e does depend on the order of the tuning
-     * parameters, e.g., some parameter update may enable some subsequent
-     * parameter update.
-     *
-     * @param inParams Requested parameter updates.
-     * @param mayBlock Whether this call may block or not.
-     * @return result of config. Params in the result should be in same order
-     *     with @p inParams.
-     * @throws ServiceSpecificException with one of the following values:
-     *   - `Status::NO_MEMORY` - Some supported parameters could not be updated
-     *                   successfully because they contained unsupported values.
-     *                   These are returned in @p failures.
-     *   - `Status::BLOCKING`  - Setting some parameters requires blocking, but
-     *                   @p mayBlock is false.
-     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
-     *   - `Status::CORRUPTED` - Some unknown error occurred.
-     */
-    ConfigResult config(in Params inParams, in boolean mayBlock);
-
-    /**
-     * Returns the id of the object. This must be unique among all objects of
-     * the same type hosted by the same store.
-     *
-     * @return Id of the object.
-     */
-    int getId();
-
-    /**
-     * Returns the name of the object.
-     *
-     * This must match the name that was supplied during the creation of the
-     * object.
-     *
-     * @return Name of the object.
-     */
-    String getName();
-
-    /**
-     * Queries a set of parameters from the object.
-     *
-     * Querying is performed at best effort: the object must query all supported
-     * parameters and skip unsupported ones (which may include parameters that
-     * could not be allocated).
-     *
-     * If @p mayBlock is true, a query may block, but the whole method call
-     * has to complete in a timely manner, or `Status::TIMED_OUT` is thrown.
-     *
-     * If @p mayBlock is false, this method must not block(All parameter queries
-     * that require blocking must be skipped). Otherwise, this
-     * method is allowed to block for a certain period of time before completing
-     * the operation. If the operation is not completed in a timely manner,
-     * `Status::TIMED_OUT` is thrown.
-     *
-     * @note Since unsupported parameters will be skipped, the returned results
-     *     does not have every settings from @p indices, but the result will preserve
-     *     the original order from @p indices though unsupported settings are skipped.
-     *
-     * \par For IComponent
-     *
-     * When the object type is @ref IComponent, this method must be supported in
-     * any state except released. This call must not change the state nor the
-     * internal configuration of the component.
-     *
-     * The blocking behavior of this method differs among states:
-     *   - In the stopped state, this must be non-blocking. @p mayBlock is
-     *     ignored. (The method operates as if @p mayBlock was false.)
-     *   - In any of the running states, this method may block momentarily if
-     *     @p mayBlock is true. However, if the call cannot be completed in a
-     *     timely manner, `Status::status` is thrown.
-     *
-     * @param indices List of C2Param structure indices to query.
-     * @param mayBlock Whether this call may block or not.
-     * @return Flattened representation of std::vector<C2Param> object.
-     *     Unsupported settings are skipped in the results. The order in @p indices
-     *     still be preserved except skipped settings.
-     * @throws ServiceSpecificException with one of the following values:
-     *   - `Status::NO_MEMORY` - Could not allocate memory for a supported parameter.
-     *   - `Status::BLOCKING`  - Querying some parameters requires blocking, but
-     *                   @p mayBlock is false.
-     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
-     *   - `Status::CORRUPTED` - Some unknown error occurred.
-     */
-    Params query(in int[] indices, in boolean mayBlock);
-
-    /**
-     * Returns a list of supported parameters within a selected range of C2Param
-     * structure indices.
-     *
-     * @param start The first index of the selected range.
-     * @param count The length of the selected range.
-     * @return List of supported parameters in the selected range. This
-     *     list may have fewer than @p count elements if some indices in the
-     *     range are not supported.
-     * @throws ServiceSpecificException with one of the following values:
-     *   - `Status::NO_MEMORY` - Not enough memory to complete this method.
-     *
-     */
-    ParamDescriptor[] querySupportedParams(in int start, in int count);
-
-    /**
-     * Retrieves the supported values for the queried fields.
-     *
-     * The object must process all fields queried even if some queries fail.
-     *
-     * If @p mayBlock is false, this method must not block. Otherwise, this
-     * method is allowed to block for a certain period of time before completing
-     * the operation. If the operation cannot be completed in a timely manner,
-     * `Status::TIMED_OUT` is thrown.
-     *
-     * \par For IComponent
-     *
-     * When the object type is @ref IComponent, this method must be supported in
-     * any state except released.
-     *
-     * The blocking behavior of this method differs among states:
-     *   - In the stopped state, this must be non-blocking. @p mayBlock is
-     *     ignored. (The method operates as if @p mayBlock was false.)
-     *   - In any of the running states, this method may block momentarily if
-     *     @p mayBlock is true. However, if the call cannot be completed in a
-     *     timely manner, `Status::TIMED_OUT` is thrown.
-     *
-     * @param inFields List of field queries.
-     * @param mayBlock Whether this call may block or not.
-     * @return List of supported values and results for the
-     *     supplied queries.
-     * @throws ServiceSpecificException with one of the following values:
-     *   - `Status::BLOCKING`  - Querying some parameters requires blocking, but
-     *                   @p mayBlock is false.
-     *   - `Status::NO_MEMORY` - Not enough memory to complete this method.
-     *   - `Status::BLOCKING`  - Querying some fields requires blocking, but @p mayblock
-     *                   is false.
-     *   - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
-     *   - `Status::CORRUPTED` - Some unknown error occurred.
-     */
-    FieldSupportedValuesQueryResult[] querySupportedValues(
-            in FieldSupportedValuesQuery[] inFields, in boolean mayBlock);
-}
diff --git a/staging/c2/aidl/android/hardware/media/c2/InfoBuffer.aidl b/staging/c2/aidl/android/hardware/media/c2/InfoBuffer.aidl
deleted file mode 100644
index 7cfabcb..0000000
--- a/staging/c2/aidl/android/hardware/media/c2/InfoBuffer.aidl
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.media.c2;
-
-import android.hardware.media.c2.Buffer;
-
-/**
- * An extension of @ref Buffer that also contains a C2Param structure index.
- *
- * This is a part of @ref FrameData.
- */
-parcelable InfoBuffer {
-    /**
-     * A C2Param structure index.
-     */
-    int index;
-    /**
-     * Associated @ref Buffer object.
-     */
-    Buffer buffer;
-}
diff --git a/staging/c2/aidl/android/hardware/media/c2/ParamDescriptor.aidl b/staging/c2/aidl/android/hardware/media/c2/ParamDescriptor.aidl
deleted file mode 100644
index 716c07e..0000000
--- a/staging/c2/aidl/android/hardware/media/c2/ParamDescriptor.aidl
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.media.c2;
-
-/**
- * Usage description of a C2Param structure.
- *
- * @ref ParamDescriptor is returned by IConfigurable::querySupportedParams().
- */
-parcelable ParamDescriptor {
-    /** The list of bit flags for attrib */
-    /**
-     * The parameter is required to be specified.
-     */
-    const int ATTRIBUTE_REQUIRED = 1 << 0;
-    /**
-     * The parameter retains its value.
-     */
-    const int ATTRIBUTE_PERSISTENT = 1 << 1;
-    /**
-     * The parameter is strict.
-     */
-    const int ATTRIBUTE_STRICT = 1 << 2;
-    /**
-     * The parameter is publicly read-only.
-     */
-    const int ATTRIBUTE_READ_ONLY = 1 << 3;
-    /**
-     * The parameter must not be visible to clients.
-     */
-    const int ATTRIBUTE_HIDDEN = 1 << 4;
-    /**
-     * The parameter must not be used by framework (other than testing).
-     */
-    const int ATTRIBUTE_INTERNAL = 1 << 5;
-    /**
-     * The parameter is publicly constant (hence read-only).
-     */
-    const int ATTRIBUTE_CONST = 1 << 6;
-
-    /**
-     * Index of the C2Param structure being described.
-     */
-    int index;
-    /**
-     * bit flag for attribute defined in the above.
-     */
-    int attrib;
-    /**
-     * Name of the structure. This must be unique for each structure.
-     */
-    String name;
-    /**
-     * Indices of other C2Param structures that this C2Param structure depends
-     * on.
-     */
-    int[] dependencies;
-}
diff --git a/staging/c2/aidl/android/hardware/media/c2/ParamField.aidl b/staging/c2/aidl/android/hardware/media/c2/ParamField.aidl
deleted file mode 100644
index 94f737d..0000000
--- a/staging/c2/aidl/android/hardware/media/c2/ParamField.aidl
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.media.c2;
-
-import android.hardware.media.c2.FieldId;
-
-/**
- * Reference to a field in a C2Param structure.
- */
-parcelable ParamField {
-    /**
-     * Index of the C2Param structure.
-     */
-    int index;
-    /**
-     * Identifier of the field inside the C2Param structure.
-     */
-    FieldId fieldId;
-}
diff --git a/staging/c2/aidl/android/hardware/media/c2/ParamFieldValues.aidl b/staging/c2/aidl/android/hardware/media/c2/ParamFieldValues.aidl
deleted file mode 100644
index 4bb9a91..0000000
--- a/staging/c2/aidl/android/hardware/media/c2/ParamFieldValues.aidl
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.media.c2;
-
-import android.hardware.media.c2.FieldSupportedValues;
-import android.hardware.media.c2.ParamField;
-
-/**
- * Supported values for a field.
- *
- * This is a pair of the field specifier together with an optional supported
- * values object. This structure is used when reporting parameter configuration
- * failures and conflicts.
- */
-parcelable ParamFieldValues {
-    /**
-     * Reference to a field or a C2Param structure.
-     */
-    ParamField paramOrField;
-    /**
-     * Optional supported values for the field if #paramOrField specifies an
-     * actual field that is numeric (non struct, blob or string). Supported
-     * values for arrays (including string and blobs) describe the supported
-     * values for each element (character for string, and bytes for blobs). It
-     * is optional for read-only strings and blobs.
-     */
-    FieldSupportedValues[] values;
-}
diff --git a/staging/c2/aidl/android/hardware/media/c2/Params.aidl b/staging/c2/aidl/android/hardware/media/c2/Params.aidl
deleted file mode 100644
index 3c1a321..0000000
--- a/staging/c2/aidl/android/hardware/media/c2/Params.aidl
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.media.c2;
-
-/**
- * Flattened representation of std::vector<C2Param> object.
- *
- * The `Params` type is an array of bytes made up by concatenating a list of
- * C2Param objects. The start index (offset into @ref Params) of each C2Param
- * object in the list is divisible by 8. Up to 7 padding bytes may be added
- * after each C2Param object to achieve this 64-bit alignment.
- *
- * Each C2Param object has the following layout:
- * - 4 bytes: C2Param structure index (of type @ref ParamIndex) identifying the
- *   type of the C2Param object.
- * - 4 bytes: size of the C2Param object (unsigned 4-byte integer).
- * - (size - 8) bytes: data of the C2Param object.
- */
-parcelable Params {
-    byte[] params;
-}
diff --git a/staging/c2/aidl/android/hardware/media/c2/SettingResult.aidl b/staging/c2/aidl/android/hardware/media/c2/SettingResult.aidl
deleted file mode 100644
index a270146..0000000
--- a/staging/c2/aidl/android/hardware/media/c2/SettingResult.aidl
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.media.c2;
-
-import android.hardware.media.c2.ParamFieldValues;
-
-/**
- * Information describing the reason the parameter settings may fail, or may be
- * overridden.
- */
-parcelable SettingResult {
-    /**
-     * Failure code
-     */
-    @Backing(type="int")
-    enum Failure {
-        /**
-         * Parameter is not supported.
-         */
-        BAD_TYPE,
-        /**
-         * Parameter is not supported on the specific port.
-         */
-        BAD_PORT,
-        /**
-         * Parameter is not supported on the specific stream.
-         */
-        BAD_INDEX,
-        /**
-         * Parameter is read-only and cannot be set.
-         */
-        READ_ONLY,
-        /**
-         * Parameter mismatches input data.
-         */
-        MISMATCH,
-        /**
-         * Strict parameter does not accept value for the field at all.
-         */
-        BAD_VALUE,
-        /**
-         * Strict parameter field value is in conflict with an/other
-         * setting(s).
-         */
-        CONFLICT,
-        /**
-         * Parameter field is out of range due to other settings. (This failure
-         * mode can only be used for strict calculated parameters.)
-         */
-        UNSUPPORTED,
-        /**
-         * Field does not access the requested parameter value at all. It has
-         * been corrected to the closest supported value. This failure mode is
-         * provided to give guidance as to what are the currently supported
-         * values for this field (which may be a subset of the at-all-potential
-         * values).
-         */
-        INFO_BAD_VALUE,
-        /**
-         * Requested parameter value is in conflict with an/other setting(s)
-         * and has been corrected to the closest supported value. This failure
-         * mode is given to provide guidance as to what are the currently
-         * supported values as well as to optionally provide suggestion to the
-         * client as to how to enable the requested parameter value.
-         */
-        INFO_CONFLICT,
-    }
-    Failure failure;
-    /**
-     * Failing (or corrected) field or parameter and optionally, currently
-     * supported values for the field. Values must only be set for field
-     * failures other than `BAD_VALUE`, and only if they are different from the
-     * globally supported values (e.g. due to restrictions by another parameter
-     * or input data).
-     */
-    ParamFieldValues field;
-    /**
-     * Conflicting parameters or fields with (optional) suggested values for any
-     * conflicting fields to avoid the conflict. Values must only be set for
-     * `CONFLICT`, `UNSUPPORTED` or `INFO_CONFLICT` failure code.
-     */
-    ParamFieldValues[] conflicts;
-}
diff --git a/staging/c2/aidl/android/hardware/media/c2/Status.aidl b/staging/c2/aidl/android/hardware/media/c2/Status.aidl
deleted file mode 100644
index 660db57..0000000
--- a/staging/c2/aidl/android/hardware/media/c2/Status.aidl
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.media.c2;
-
-/**
- * Common return values for Codec2 operations.
- */
-parcelable Status {
-    /**
-     * Operation completed successfully.
-     */
-    const int OK = 0;
-    /**
-     * Argument has invalid value (user error).
-     */
-    const int BAD_VALUE = -22;
-    /**
-     * Argument uses invalid index (user error).
-     */
-    const int BAD_INDEX = -75;
-    /**
-     * Argument/Index is valid but not possible.
-     */
-    const int CANNOT_DO = -2147483646;
-    /**
-     * Object already exists.
-     */
-    const int DUPLICATE = -17;
-    /**
-     * Object not found.
-     */
-    const int NOT_FOUND = -2;
-    /**
-     * Operation is not permitted in the current state.
-     */
-    const int BAD_STATE = -38;
-    /**
-     * Operation would block but blocking is not permitted.
-     */
-    const int BLOCKING = -9930;
-    /**
-     * Not enough memory to complete operation.
-     */
-    const int NO_MEMORY = -12;
-    /**
-     * Missing permission to complete operation.
-     */
-    const int REFUSED = -1;
-    /**
-     * Operation did not complete within timeout.
-     */
-    const int TIMED_OUT = -110;
-    /**
-     * Operation is not implemented/supported (optional only).
-     */
-    const int OMITTED = -74;
-    /**
-     * Some unexpected error prevented the operation.
-     */
-    const int CORRUPTED = -2147483648;
-    /**
-     * Status has not been initialized.
-     */
-    const int NO_INIT = -19;
-
-    int status;
-}
diff --git a/staging/c2/aidl/android/hardware/media/c2/StructDescriptor.aidl b/staging/c2/aidl/android/hardware/media/c2/StructDescriptor.aidl
deleted file mode 100644
index 5d6d2eb..0000000
--- a/staging/c2/aidl/android/hardware/media/c2/StructDescriptor.aidl
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.media.c2;
-
-import android.hardware.media.c2.FieldDescriptor;
-
-/**
- * Description of a C2Param structure. It consists of an index and a list of
- * `FieldDescriptor`s.
- */
-parcelable StructDescriptor {
-    /**
-     * Index of the structure.
-     *
-     * Actually C2Param::CoreIndex
-     * Core index is the underlying parameter type for a parameter. It is used to describe the
-     * layout of the parameter structure regardless of the component or parameter kind/scope.
-     *
-     * It is used to identify and distinguish global parameters, and also parameters on a given
-     * port or stream. They must be unique for the set of global parameters, as well as for the
-     * set of parameters on each port or each stream, but the same core index can be used for
-     * parameters on different streams or ports, as well as for global parameters and port/stream
-     * parameters.
-     */
-    int type;
-    /**
-     * List of fields in the structure.
-     *
-     * Fields are ordered by their offsets. A field that is a structure is
-     * ordered before its members.
-     */
-    FieldDescriptor[] fields;
-}
diff --git a/staging/c2/aidl/android/hardware/media/c2/SurfaceSyncObj.aidl b/staging/c2/aidl/android/hardware/media/c2/SurfaceSyncObj.aidl
deleted file mode 100644
index 2e7330e..0000000
--- a/staging/c2/aidl/android/hardware/media/c2/SurfaceSyncObj.aidl
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.media.c2;
-
-import android.hardware.common.NativeHandle;
-/**
- * Surface(BufferQueue/IGBP) synchronization object regarding # of dequeued
- * output buffers. This keeps # of dequeued buffers from Surface less than
- * configured max # of dequeued buffers all the time.
- */
-parcelable SurfaceSyncObj {
-    /**
-     * ASharedMemory for synchronization data. Layout is below
-     *
-     * |lock(futex)                               4bytes|
-     * |conditional_variable(futex)               4bytes|
-     * |# of max dequeable buffer                 4bytes|
-     * |# of dequeued buffer                      4bytes|
-     * |Status of the surface                     4bytes|
-     *      INIT        = 0, Configuring surface is not finished.
-     *      ACTIVE      = 1, Surface is ready to allocate(dequeue).
-     *      SWITCHING   = 2, Switching to the new surface. It is blocked
-     *                       to allocate(dequeue) a buffer until switching
-     *                       completes.
-     */
-    NativeHandle syncMemory;
-    /**
-     * BufferQueue id.
-     */
-    long bqId;
-    /**
-     * Generation id.
-     */
-    int generationId;
-    /**
-     * Consumer usage flags. See +ndk
-     * libnativewindow#AHardwareBuffer_UsageFlags for possible values.
-     */
-    long consumerUsage;
-}
diff --git a/staging/c2/aidl/android/hardware/media/c2/ValueRange.aidl b/staging/c2/aidl/android/hardware/media/c2/ValueRange.aidl
deleted file mode 100644
index 6707a25..0000000
--- a/staging/c2/aidl/android/hardware/media/c2/ValueRange.aidl
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.media.c2;
-
-/**
- * Description of a set of values.
- *
- * If the `step` member is 0, and `num` and `denom` are both 1, the `Range`
- * structure represents a closed interval bounded by `min` and `max`.
- *
- * Otherwise, the #ValueRange structure represents a finite sequence of numbers
- * produced from the following recurrence relation:
- *
- * @code
- * v[0] = min
- * v[i] = v[i - 1] * num / denom + step ; i >= 1
- * @endcode
- *
- * Both the ratio `num / denom` and the value `step` must be positive. The
- * last number in the sequence described by this #Range structure is the
- * largest number in the sequence that is smaller than or equal to `max`.
- *
- * @note
- * The division in the formula may truncate the result if the data type of
- * these values is an integral type.
- */
-parcelable ValueRange {
-    /**
-     * Lower end of the range (inclusive).
-     */
-    long min;
-    /**
-     * Upper end of the range (inclusive).
-     */
-    long max;
-    /**
-     * The non-homogeneous term in the recurrence relation.
-     */
-    long step;
-    /**
-     * The numerator of the scale coefficient in the recurrence relation.
-     */
-    long num;
-    /**
-     * The denominator of the scale coefficient in the recurrence relation.
-     */
-    long denom;
-}
diff --git a/staging/c2/aidl/android/hardware/media/c2/Work.aidl b/staging/c2/aidl/android/hardware/media/c2/Work.aidl
deleted file mode 100644
index 0732479..0000000
--- a/staging/c2/aidl/android/hardware/media/c2/Work.aidl
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.media.c2;
-
-import android.hardware.media.c2.FrameData;
-import android.hardware.media.c2.Status;
-import android.hardware.media.c2.Worklet;
-
-/**
- * A collection of input data to and output data from the component.
- *
- * A `Work` object holds information about a single work item. It is created by
- * the client and passed to the component via IComponent::queue(). The component
- * has two ways of returning a `Work` object to the client:
- *   1. If the queued `Work` object has been successfully processed,
- *      IComponentListener::onWorkDone() shall be called to notify the listener,
- *      and the output shall be included in the returned `Work` object.
- *   2. If the client calls IComponent::flush(), a `Work` object that has not
- *      been processed shall be returned.
- *
- * `Work` is a part of @ref WorkBundle.
- */
-parcelable Work {
-    /**
-     * Additional work chain info not part of this work.
-     */
-    byte[] chainInfo;
-    /**
-     * @ref FrameData for the input.
-     */
-    FrameData input;
-    /**
-     * The chain of `Worklet`s.
-     *
-     * The length of #worklets is 1 when tunneling is not enabled.
-     *
-     * If #worklets has more than a single element, the tunnels between
-     * successive components of the work chain must have been successfully
-     * pre-registered at the time that the `Work` is submitted. Allocating the
-     * output buffers in the `Worklet`s is the responsibility of each component
-     * in the chain.
-     *
-     * Upon `Work` submission, #worklets must be an appropriately sized vector
-     * containing `Worklet`s with @ref Worklet.hasOutput set to `false`. After a
-     * successful processing, all but the final `Worklet` in the returned
-     * #worklets must have @ref Worklet.hasOutput set to `false`.
-     */
-    Worklet[] worklets;
-    /**
-     * The number of `Worklet`s successfully processed in this chain.
-     *
-     * This must be initialized to 0 by the client when the `Work` is submitted,
-     * and it must contain the number of `Worklet`s that were successfully
-     * processed when the `Work` is returned to the client.
-     *
-     * #workletsProcessed cannot exceed the length of #worklets. If
-     * #workletsProcessed is smaller than the length of #worklets, #result
-     * cannot be `OK`.
-     */
-    int workletsProcessed;
-    /**
-     * The final outcome of the `Work` (corresponding to #workletsProcessed).
-     *
-     * The value of @ref Status.OK implies that all `Worklet`s have been
-     * successfully processed.
-     */
-    Status result;
-}
diff --git a/staging/c2/aidl/android/hardware/media/c2/WorkBundle.aidl b/staging/c2/aidl/android/hardware/media/c2/WorkBundle.aidl
deleted file mode 100644
index 79b4cdb..0000000
--- a/staging/c2/aidl/android/hardware/media/c2/WorkBundle.aidl
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.media.c2;
-
-import android.hardware.media.c2.BaseBlock;
-import android.hardware.media.c2.Work;
-
-/**
- * List of `Work` objects.
- *
- * `WorkBundle` is used in IComponent::queue(), IComponent::flush() and
- * IComponentListener::onWorkDone(). A `WorkBundle` object consists of a list of
- * `Work` objects and a list of `BaseBlock` objects. Bundling multiple `Work`
- * objects together provides two benefits:
- *   1. Batching of `Work` objects can reduce the number of IPC calls.
- *   2. If multiple `Work` objects contain `Block`s that refer to the same
- *      `BaseBlock`, the number of `BaseBlock`s that is sent between processes
- *      is also reduced.
- *
- * @note `WorkBundle` is the AIDL counterpart of the vector of `C2Work` in the
- * Codec 2.0 standard. The presence of #baseBlocks helps with minimizing the
- * data transferred over an IPC.
- */
-parcelable WorkBundle {
-    /**
-     * A list of Work items.
-     */
-    Work[] works;
-    /**
-     * A list of blocks indexed by elements of #works.
-     */
-    BaseBlock[] baseBlocks;
-}
diff --git a/staging/c2/aidl/android/hardware/media/c2/WorkOrdinal.aidl b/staging/c2/aidl/android/hardware/media/c2/WorkOrdinal.aidl
deleted file mode 100644
index eb8b244..0000000
--- a/staging/c2/aidl/android/hardware/media/c2/WorkOrdinal.aidl
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.media.c2;
-
-/**
- * Ordering information of @ref FrameData objects. Each member is used for
- * comparing urgency: a smaller difference from a reference value indicates that
- * the associated Work object is more urgent. The reference value for each
- * member is initialized the first time it is communicated between the client
- * and the codec, and it may be updated to later values that are communicated.
- *
- * Each member of `WorkOrdinal` is stored as an unsigned integer, but the actual
- * order it represents is derived by subtracting the reference value, then
- * interpreting the result as a signed number with the same storage size (using
- * two's complement).
- *
- * @note `WorkOrdinal` is the HIDL counterpart of `C2WorkOrdinalStruct` in the
- * Codec 2.0 standard.
- */
-parcelable WorkOrdinal {
-    /**
-     * Timestamp in microseconds.
-     */
-    long timestampUs;
-    /**
-     * Frame index.
-     */
-    long frameIndex;
-    /**
-     * Component specific frame ordinal.
-     */
-    long customOrdinal;
-}
diff --git a/staging/c2/aidl/android/hardware/media/c2/Worklet.aidl b/staging/c2/aidl/android/hardware/media/c2/Worklet.aidl
deleted file mode 100644
index 04c59c1..0000000
--- a/staging/c2/aidl/android/hardware/media/c2/Worklet.aidl
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.media.c2;
-
-import android.hardware.media.c2.FrameData;
-import android.hardware.media.c2.SettingResult;
-
-/**
- * In/out structure containing some instructions for and results from output
- * processing.
- *
- * This is a part of @ref Work. One `Worklet` corresponds to one output
- * @ref FrameData. The client must construct an original `Worklet` object inside
- * a @ref Work object for each expected output before calling
- * IComponent::queue().
- */
-parcelable Worklet {
-    /**
-     * Component id. (Input)
-     *
-     * This is used only when tunneling is enabled.
-     *
-     * When used, this must match the return value from IConfigurable::getId().
-     */
-    int componentId;
-    /**
-     * List of C2Param objects describing tunings to be applied before
-     * processing this `Worklet`. (Input)
-     */
-    byte[] tunings;
-    /**
-     * List of failures. (Output)
-     */
-    SettingResult[] failures;
-    /**
-     * Output frame data. (Output)
-     */
-    FrameData output;
-}
diff --git a/staging/threadnetwork/OWNERS b/staging/threadnetwork/OWNERS
deleted file mode 100644
index 037215d..0000000
--- a/staging/threadnetwork/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-# Bug component: 1203089
-
-wgtdkp@google.com
-xyk@google.com
-zhanglongxia@google.com
diff --git a/staging/threadnetwork/README.md b/staging/threadnetwork/README.md
deleted file mode 100644
index 12104e5..0000000
--- a/staging/threadnetwork/README.md
+++ /dev/null
@@ -1,12 +0,0 @@
-# Staging threadnetwork HAL interface
-
-The directory includes the unstable/unreleased version of `hardware/interfaces/threadnetwork`
-code which should **NOT** be used in production. But vendors may start verifying their hardware
-with the HAL interface.
-
-This directory will be cleaned up when the stable Thread HAL interface is added in
-`hardware/interfaces/threadnetwork` by version `V` or later.
-
-More information about _Thread_:
-- https://www.threadgroup.org
-- https://openthread.io
diff --git a/staging/threadnetwork/aidl/Android.bp b/staging/threadnetwork/aidl/Android.bp
deleted file mode 100644
index b59d6da..0000000
--- a/staging/threadnetwork/aidl/Android.bp
+++ /dev/null
@@ -1,26 +0,0 @@
-package {
-    // See: http://go/android-license-faq
-    // A large-scale-change added 'default_applicable_licenses' to import
-    // all of the 'license_kinds' from "hardware_interfaces_license"
-    // to get the below license kinds:
-    //   SPDX-license-identifier-Apache-2.0
-    default_applicable_licenses: ["hardware_interfaces_license"],
-}
-
-aidl_interface {
-    name: "android.hardware.threadnetwork",
-    host_supported: true,
-    vendor_available: true,
-
-    srcs: [
-        "android/hardware/threadnetwork/*.aidl",
-    ],
-
-    unstable: true,
-
-    backend: {
-        ndk: {
-            enabled: true,
-        },
-    },
-}
diff --git a/staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl b/staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl
deleted file mode 100644
index 3c57149..0000000
--- a/staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.threadnetwork;
-
-import android.hardware.threadnetwork.IThreadChipCallback;
-
-/**
- * Controls a Thread radio chip on the device.
- */
-
-interface IThreadChip {
-    /**
-     * The operation failed for the internal error.
-     */
-    const int ERROR_FAILED = 1;
-
-    /**
-     * Insufficient buffers available to send frames.
-     */
-    const int ERROR_NO_BUFS = 2;
-
-    /**
-     * Service is busy and could not service the operation.
-     */
-    const int ERROR_BUSY = 3;
-
-    /**
-     * This method initializes the Thread HAL instance. If open completes
-     * successfully, then the Thread HAL instance is ready to accept spinel
-     * messages through sendSpinelFrame() API.
-     *
-     * @param callback  A IThreadChipCallback callback instance. If multiple
-     *                  callbacks are passed in, the open() will return ERROR_BUSY.
-     *
-     * @throws EX_ILLEGAL_ARGUMENT  if the callback handle is invalid (for example, it is null).
-     * @throws ServiceSpecificException with one of the following values:
-     *     - ERROR_FAILED        The interface cannot be opened due to an internal error.
-     *     - ERROR_BUSY          This interface is in use.
-     */
-    void open(in IThreadChipCallback callback);
-
-    /**
-     * Close the Thread HAL instance. Must free all resources.
-     *
-     * @throws EX_ILLEGAL_STATE  if the Thread HAL instance is not opened.
-     *
-     */
-    void close();
-
-    /**
-     * This method resets the Thread HAL internal state. The callback registered by
-     * `open()` won’t be reset and the resource allocated by `open()` won’t be free.
-     *
-     */
-    void reset();
-
-    /**
-     * This method sends a spinel frame to the Thread HAL.
-     *
-     * This method should block until the frame is sent out successfully or
-     * the method throws errors immediately.
-     *
-     * Spinel Protocol:
-     *     https://github.com/openthread/openthread/blob/main/src/lib/spinel/spinel.h
-     *
-     * @param frame  The spinel frame to be sent.
-     *
-     * @throws ServiceSpecificException with one of the following values:
-     *         - ERROR_FAILED The Thread HAL failed to send the frame for an internal reason.
-     *         - ERROR_NO_BUFS Insufficient buffer space to send the frame.
-     *         - ERROR_BUSY The Thread HAL is busy.
-     */
-    void sendSpinelFrame(in byte[] frame);
-}
diff --git a/staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChipCallback.aidl b/staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChipCallback.aidl
deleted file mode 100644
index a0fe88c..0000000
--- a/staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChipCallback.aidl
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.threadnetwork;
-
-interface IThreadChipCallback {
-    /**
-     * This method is called when a spinel frame is received. Thread network
-     * will process the received spinel frame.
-     *
-     * Spinel Protocol:
-     *     https://github.com/openthread/openthread/blob/main/src/lib/spinel/spinel.h
-     *
-     * @param frame  The received spinel frame.
-     */
-    oneway void onReceiveSpinelFrame(in byte[] frame);
-}
diff --git a/staging/threadnetwork/aidl/default/Android.bp b/staging/threadnetwork/aidl/default/Android.bp
deleted file mode 100644
index 8fc22ad..0000000
--- a/staging/threadnetwork/aidl/default/Android.bp
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright (C) 2022 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package {
-    // See: http://go/android-license-faq
-    // A large-scale-change added 'default_applicable_licenses' to import
-    // all of the 'license_kinds' from "hardware_interfaces_license"
-    // to get the below license kinds:
-    //   SPDX-license-identifier-Apache-2.0
-    default_applicable_licenses: ["hardware_interfaces_license"],
-}
-
-cc_defaults {
-    name: "threadnetwork_service_default",
-    vendor: true,
-    relative_install_path: "hw",
-
-    shared_libs: [
-        "android.hardware.threadnetwork-ndk",
-        "libbase",
-        "libbinder_ndk",
-        "libcutils",
-        "liblog",
-        "libutils",
-    ],
-
-    static_libs: [
-        "openthread-common",
-        "openthread-hdlc",
-        "openthread-platform",
-        "openthread-posix",
-        "openthread-url",
-    ],
-
-    srcs: [
-        "main.cpp",
-        "service.cpp",
-        "thread_chip.cpp",
-        "utils.cpp",
-    ],
-}
-
-cc_binary {
-    name: "android.hardware.threadnetwork-service.sim",
-    defaults: ["threadnetwork_service_default"],
-    init_rc: ["android.hardware.threadnetwork-service.sim.rc"],
-}
-
-cc_binary {
-    name: "android.hardware.threadnetwork-service",
-    defaults: ["threadnetwork_service_default"],
-}
diff --git a/staging/threadnetwork/aidl/default/android.hardware.threadnetwork-service.sim.rc b/staging/threadnetwork/aidl/default/android.hardware.threadnetwork-service.sim.rc
deleted file mode 100644
index 2fb409c..0000000
--- a/staging/threadnetwork/aidl/default/android.hardware.threadnetwork-service.sim.rc
+++ /dev/null
@@ -1,3 +0,0 @@
-service vendor.threadnetwork_hal /vendor/bin/hw/android.hardware.threadnetwork-service.sim spinel+hdlc+forkpty:///vendor/bin/ot-rcp?forkpty-arg=1
-    class hal
-    user thread_network
diff --git a/staging/threadnetwork/aidl/default/main.cpp b/staging/threadnetwork/aidl/default/main.cpp
deleted file mode 100644
index b6c8bbb..0000000
--- a/staging/threadnetwork/aidl/default/main.cpp
+++ /dev/null
@@ -1,30 +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 <android-base/logging.h>
-#include <utils/Log.h>
-
-#include "service.hpp"
-
-int main(int argc, char* argv[]) {
-    CHECK_GT(argc, 1);
-    aidl::android::hardware::threadnetwork::Service service(&argv[1], argc - 1);
-
-    ALOGI("Thread Network HAL is running");
-
-    service.startLoop();
-    return EXIT_FAILURE;  // should not reach
-}
diff --git a/staging/threadnetwork/aidl/default/service.cpp b/staging/threadnetwork/aidl/default/service.cpp
deleted file mode 100644
index 8047214..0000000
--- a/staging/threadnetwork/aidl/default/service.cpp
+++ /dev/null
@@ -1,90 +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 "service.hpp"
-
-#include <android-base/logging.h>
-#include <android/binder_manager.h>
-#include <android/binder_process.h>
-#include <utils/Log.h>
-
-#include "thread_chip.hpp"
-
-namespace aidl {
-namespace android {
-namespace hardware {
-namespace threadnetwork {
-
-Service::Service(char* urls[], int numUrls) : mBinderFd(-1) {
-    int fd;
-
-    CHECK_NE(urls, nullptr);
-    CHECK_GT(numUrls, 0);
-
-    for (int i = 0; i < numUrls; i++) {
-        auto threadChip = ndk::SharedRefBase::make<ThreadChip>(i, urls[i]);
-        CHECK_NE(threadChip, nullptr);
-        mThreadChips.push_back(std::move(threadChip));
-    }
-
-    binder_status_t status = ABinderProcess_setupPolling(&fd);
-    CHECK_EQ(status, ::STATUS_OK);
-    CHECK_GE(fd, 0);
-    mBinderFd.reset(fd);
-}
-
-void Service::Update(otSysMainloopContext& context) {
-    FD_SET(mBinderFd.get(), &context.mReadFdSet);
-    context.mMaxFd = std::max(context.mMaxFd, mBinderFd.get());
-}
-
-void Service::Process(const otSysMainloopContext& context) {
-    if (FD_ISSET(mBinderFd.get(), &context.mReadFdSet)) {
-        ABinderProcess_handlePolledCommands();
-    }
-}
-
-void Service::startLoop(void) {
-    const struct timeval kPollTimeout = {1, 0};
-    otSysMainloopContext context;
-    int rval;
-
-    ot::Posix::Mainloop::Manager::Get().Add(*this);
-
-    while (true) {
-        context.mMaxFd = -1;
-        context.mTimeout = kPollTimeout;
-
-        FD_ZERO(&context.mReadFdSet);
-        FD_ZERO(&context.mWriteFdSet);
-        FD_ZERO(&context.mErrorFdSet);
-
-        ot::Posix::Mainloop::Manager::Get().Update(context);
-
-        rval = select(context.mMaxFd + 1, &context.mReadFdSet, &context.mWriteFdSet,
-                      &context.mErrorFdSet, &context.mTimeout);
-
-        if (rval >= 0) {
-            ot::Posix::Mainloop::Manager::Get().Process(context);
-        } else if (errno != EINTR) {
-            ALOGE("select() failed: %s", strerror(errno));
-            break;
-        }
-    }
-}
-}  // namespace threadnetwork
-}  // namespace hardware
-}  // namespace android
-}  // namespace aidl
diff --git a/staging/threadnetwork/aidl/default/service.hpp b/staging/threadnetwork/aidl/default/service.hpp
deleted file mode 100644
index 6e6e868..0000000
--- a/staging/threadnetwork/aidl/default/service.hpp
+++ /dev/null
@@ -1,42 +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 <android-base/unique_fd.h>
-
-#include "mainloop.hpp"
-#include "thread_chip.hpp"
-
-namespace aidl {
-namespace android {
-namespace hardware {
-namespace threadnetwork {
-
-class Service : public ot::Posix::Mainloop::Source {
-  public:
-    Service(char* urls[], int numUrls);
-
-    void Update(otSysMainloopContext& context) override;
-    void Process(const otSysMainloopContext& context) override;
-    void startLoop(void);
-
-  private:
-    ::android::base::unique_fd mBinderFd;
-    std::vector<std::shared_ptr<ThreadChip>> mThreadChips;
-};
-}  // namespace threadnetwork
-}  // namespace hardware
-}  // namespace android
-}  // namespace aidl
diff --git a/staging/threadnetwork/aidl/default/thread_chip.cpp b/staging/threadnetwork/aidl/default/thread_chip.cpp
deleted file mode 100644
index 38abad4..0000000
--- a/staging/threadnetwork/aidl/default/thread_chip.cpp
+++ /dev/null
@@ -1,197 +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 "thread_chip.hpp"
-
-#include <android-base/logging.h>
-#include <android/binder_auto_utils.h>
-#include <android/binder_ibinder.h>
-#include <android/binder_manager.h>
-#include <android/binder_process.h>
-#include <utils/Log.h>
-
-namespace aidl {
-namespace android {
-namespace hardware {
-namespace threadnetwork {
-
-static ndk::ScopedAStatus errorStatus(int32_t error, const char* message) {
-    return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(error, message));
-}
-
-ThreadChip::ThreadChip(uint8_t id, char* url)
-    : mUrl(),
-      mInterface(handleReceivedFrame, this, mRxFrameBuffer),
-      mRxFrameBuffer(),
-      mCallback(nullptr) {
-    const std::string name(std::string() + IThreadChip::descriptor + "/chip" + std::to_string(id));
-    binder_status_t status;
-
-    ALOGI("ServiceName: %s, Url: %s", name.c_str(), url);
-    CHECK_EQ(mUrl.Init(url), 0);
-    status = AServiceManager_addService(asBinder().get(), name.c_str());
-    CHECK_EQ(status, STATUS_OK);
-
-    mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(
-            AIBinder_DeathRecipient_new(ThreadChip::onBinderDied));
-    AIBinder_DeathRecipient_setOnUnlinked(mDeathRecipient.get(), ThreadChip::onBinderUnlinked);
-}
-
-ThreadChip::~ThreadChip() {
-    AIBinder_DeathRecipient_delete(mDeathRecipient.get());
-}
-
-void ThreadChip::onBinderDied(void* context) {
-    reinterpret_cast<ThreadChip*>(context)->onBinderDied();
-}
-
-void ThreadChip::onBinderDied(void) {
-    ALOGW("Thread Network HAL client is dead.");
-}
-
-void ThreadChip::onBinderUnlinked(void* context) {
-    reinterpret_cast<ThreadChip*>(context)->onBinderUnlinked();
-}
-
-void ThreadChip::onBinderUnlinked(void) {
-    ALOGW("ThreadChip binder is unlinked.");
-    deinitChip();
-}
-
-void ThreadChip::handleReceivedFrame(void* context) {
-    reinterpret_cast<ThreadChip*>(context)->handleReceivedFrame();
-}
-
-void ThreadChip::handleReceivedFrame(void) {
-    if (mCallback != nullptr) {
-        mCallback->onReceiveSpinelFrame(std::vector<uint8_t>(
-                mRxFrameBuffer.GetFrame(), mRxFrameBuffer.GetFrame() + mRxFrameBuffer.GetLength()));
-    }
-
-    mRxFrameBuffer.DiscardFrame();
-}
-
-ndk::ScopedAStatus ThreadChip::open(const std::shared_ptr<IThreadChipCallback>& in_callback) {
-    ndk::ScopedAStatus status = initChip(in_callback);
-
-    if (status.isOk()) {
-        AIBinder_linkToDeath(in_callback->asBinder().get(), mDeathRecipient.get(), this);
-        ALOGI("Open IThreadChip successfully.");
-    } else {
-        ALOGW("Open IThreadChip failed, error: %s", status.getDescription().c_str());
-    }
-
-    return status;
-}
-
-ndk::ScopedAStatus ThreadChip::initChip(const std::shared_ptr<IThreadChipCallback>& in_callback) {
-    if (in_callback == nullptr) {
-        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
-    } else if (mCallback == nullptr) {
-        if (mInterface.Init(mUrl) != OT_ERROR_NONE) {
-            return errorStatus(ERROR_FAILED, "Failed to initialize the interface");
-        }
-
-        mCallback = in_callback;
-        ot::Posix::Mainloop::Manager::Get().Add(*this);
-        return ndk::ScopedAStatus::ok();
-    } else {
-        return errorStatus(ERROR_BUSY, "Interface is already opened");
-    }
-}
-
-ndk::ScopedAStatus ThreadChip::close() {
-    ndk::ScopedAStatus status;
-    std::shared_ptr<IThreadChipCallback> callback = mCallback;
-
-    status = deinitChip();
-    if (status.isOk()) {
-        if (callback != nullptr) {
-            AIBinder_unlinkToDeath(callback->asBinder().get(), mDeathRecipient.get(), this);
-        }
-
-        ALOGI("Close IThreadChip successfully");
-    } else {
-        ALOGW("Close IThreadChip failed, error: %s", status.getDescription().c_str());
-    }
-
-    return status;
-}
-
-ndk::ScopedAStatus ThreadChip::deinitChip() {
-    if (mCallback != nullptr) {
-        mInterface.Deinit();
-        ot::Posix::Mainloop::Manager::Get().Remove(*this);
-        mCallback = nullptr;
-        return ndk::ScopedAStatus::ok();
-    }
-
-    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
-}
-
-ndk::ScopedAStatus ThreadChip::sendSpinelFrame(const std::vector<uint8_t>& in_frame) {
-    ndk::ScopedAStatus status;
-    otError error;
-
-    if (mCallback == nullptr) {
-        status = errorStatus(ERROR_FAILED, "The interface is not open");
-    } else {
-        error = mInterface.SendFrame(reinterpret_cast<const uint8_t*>(in_frame.data()),
-                                     in_frame.size());
-        if (error == OT_ERROR_NONE) {
-            status = ndk::ScopedAStatus::ok();
-        } else if (error == OT_ERROR_NO_BUFS) {
-            status = errorStatus(ERROR_NO_BUFS, "Insufficient buffer space to send");
-        } else if (error == OT_ERROR_BUSY) {
-            status = errorStatus(ERROR_BUSY, "The interface is busy");
-        } else {
-            status = errorStatus(ERROR_FAILED, "Failed to send the spinel frame");
-        }
-    }
-
-    if (!status.isOk()) {
-        ALOGW("Send spinel frame failed, error: %s", status.getDescription().c_str());
-    }
-
-    return status;
-}
-
-ndk::ScopedAStatus ThreadChip::reset() {
-    mInterface.OnRcpReset();
-    ALOGI("reset()");
-    return ndk::ScopedAStatus::ok();
-}
-
-void ThreadChip::Update(otSysMainloopContext& context) {
-    if (mCallback != nullptr) {
-        mInterface.UpdateFdSet(context.mReadFdSet, context.mWriteFdSet, context.mMaxFd,
-                               context.mTimeout);
-    }
-}
-
-void ThreadChip::Process(const otSysMainloopContext& context) {
-    struct RadioProcessContext radioContext;
-
-    if (mCallback != nullptr) {
-        radioContext.mReadFdSet = &context.mReadFdSet;
-        radioContext.mWriteFdSet = &context.mWriteFdSet;
-        mInterface.Process(radioContext);
-    }
-}
-}  // namespace threadnetwork
-}  // namespace hardware
-}  // namespace android
-}  // namespace aidl
diff --git a/staging/threadnetwork/aidl/default/thread_chip.hpp b/staging/threadnetwork/aidl/default/thread_chip.hpp
deleted file mode 100644
index da5cba7..0000000
--- a/staging/threadnetwork/aidl/default/thread_chip.hpp
+++ /dev/null
@@ -1,68 +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/threadnetwork/BnThreadChip.h>
-#include <aidl/android/hardware/threadnetwork/IThreadChipCallback.h>
-
-#include "hdlc_interface.hpp"
-#include "lib/spinel/spinel_interface.hpp"
-#include "mainloop.hpp"
-
-#include <android/binder_auto_utils.h>
-#include <android/binder_ibinder.h>
-#include <utils/Mutex.h>
-
-namespace aidl {
-namespace android {
-namespace hardware {
-namespace threadnetwork {
-
-class ThreadChip : public BnThreadChip, ot::Posix::Mainloop::Source {
-  public:
-    ThreadChip(uint8_t id, char* url);
-    ~ThreadChip();
-
-    ndk::ScopedAStatus open(const std::shared_ptr<IThreadChipCallback>& in_callback) override;
-    ndk::ScopedAStatus close() override;
-    ndk::ScopedAStatus sendSpinelFrame(const std::vector<uint8_t>& in_frame) override;
-    ndk::ScopedAStatus reset() override;
-    void Update(otSysMainloopContext& context) override;
-    void Process(const otSysMainloopContext& context) override;
-
-  private:
-    static void onBinderDied(void* context);
-    void onBinderDied(void);
-    static void onBinderUnlinked(void* context);
-    void onBinderUnlinked(void);
-    static void handleReceivedFrame(void* context);
-    void handleReceivedFrame(void);
-
-    ndk::ScopedAStatus initChip(const std::shared_ptr<IThreadChipCallback>& in_callback);
-    ndk::ScopedAStatus deinitChip();
-
-    ot::Url::Url mUrl;
-    ot::Posix::HdlcInterface mInterface;
-    ot::Spinel::SpinelInterface::RxFrameBuffer mRxFrameBuffer;
-    std::shared_ptr<IThreadChipCallback> mCallback;
-    ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
-};
-
-}  // namespace threadnetwork
-}  // namespace hardware
-}  // namespace android
-}  // namespace aidl
diff --git a/staging/threadnetwork/aidl/default/utils.cpp b/staging/threadnetwork/aidl/default/utils.cpp
deleted file mode 100644
index d3b4062..0000000
--- a/staging/threadnetwork/aidl/default/utils.cpp
+++ /dev/null
@@ -1,34 +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 <openthread/logging.h>
-#include <utils/Log.h>
-
-void otLogCritPlat(const char* format, ...) {
-    va_list args;
-
-    va_start(args, format);
-    __android_log_vprint(ANDROID_LOG_FATAL, LOG_TAG, format, args);
-    va_end(args);
-}
-
-void otLogWarnPlat(const char* format, ...) {
-    va_list args;
-
-    va_start(args, format);
-    __android_log_vprint(ANDROID_LOG_WARN, LOG_TAG, format, args);
-    va_end(args);
-}
diff --git a/staging/threadnetwork/aidl/vts/Android.bp b/staging/threadnetwork/aidl/vts/Android.bp
deleted file mode 100644
index e2609ed..0000000
--- a/staging/threadnetwork/aidl/vts/Android.bp
+++ /dev/null
@@ -1,47 +0,0 @@
-//
-// Copyright (C) 2022 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-package {
-    // See: http://go/android-license-faq
-    // A large-scale-change added 'default_applicable_licenses' to import
-    // all of the 'license_kinds' from "hardware_interfaces_license"
-    // to get the below license kinds:
-    //   SPDX-license-identifier-Apache-2.0
-    default_applicable_licenses: ["hardware_interfaces_license"],
-}
-
-cc_test {
-    name: "VtsHalThreadNetworkTargetTest",
-    defaults: [
-        "VtsHalTargetTestDefaults",
-        "use_libaidlvintf_gtest_helper_static",
-    ],
-    srcs: [
-        "VtsHalThreadNetworkTargetTest.cpp",
-    ],
-
-    shared_libs: [
-        "libbinder",
-        "libbinder_ndk",
-    ],
-    static_libs: [
-        "android.hardware.threadnetwork-ndk",
-    ],
-    test_suites: [
-        "general-tests",
-        "vts",
-    ],
-}
diff --git a/staging/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp b/staging/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp
deleted file mode 100644
index 3e43f9c..0000000
--- a/staging/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "ThreadNetworkHalTargetTest"
-
-#include <future>
-
-#include <aidl/Gtest.h>
-#include <aidl/Vintf.h>
-#include <android-base/logging.h>
-#include <android/binder_auto_utils.h>
-#include <android/binder_manager.h>
-#include <binder/IServiceManager.h>
-#include <binder/ProcessState.h>
-#include <log/log.h>
-
-#include <aidl/android/hardware/threadnetwork/BnThreadChipCallback.h>
-#include <aidl/android/hardware/threadnetwork/IThreadChip.h>
-
-using aidl::android::hardware::threadnetwork::BnThreadChipCallback;
-using aidl::android::hardware::threadnetwork::IThreadChip;
-using android::ProcessState;
-using ndk::ScopedAStatus;
-using ndk::SpAIBinder;
-
-namespace {
-constexpr static int kCallbackTimeoutMs = 5000;
-}  // namespace
-
-class ThreadChipCallback : public BnThreadChipCallback {
-  public:
-    ThreadChipCallback(const std::function<void(const std::vector<uint8_t>&)>& on_spinel_message_cb)
-        : on_spinel_message_cb_(on_spinel_message_cb) {}
-
-    ScopedAStatus onReceiveSpinelFrame(const std::vector<uint8_t>& in_aFrame) {
-        on_spinel_message_cb_(in_aFrame);
-        return ScopedAStatus::ok();
-    }
-
-  private:
-    std::function<void(const std::vector<uint8_t>&)> on_spinel_message_cb_;
-};
-
-class ThreadNetworkAidl : public testing::TestWithParam<std::string> {
-  public:
-    virtual void SetUp() override {
-        std::string serviceName = GetParam();
-
-        ALOGI("serviceName: %s", serviceName.c_str());
-
-        thread_chip = IThreadChip::fromBinder(
-                SpAIBinder(AServiceManager_waitForService(serviceName.c_str())));
-        ASSERT_NE(thread_chip, nullptr);
-    }
-
-    virtual void TearDown() override { thread_chip->close(); }
-
-    std::shared_ptr<IThreadChip> thread_chip;
-};
-
-TEST_P(ThreadNetworkAidl, Open) {
-    std::shared_ptr<ThreadChipCallback> callback =
-            ndk::SharedRefBase::make<ThreadChipCallback>([](auto /* data */) {});
-
-    EXPECT_TRUE(thread_chip->open(callback).isOk());
-    EXPECT_EQ(thread_chip->open(callback).getServiceSpecificError(), IThreadChip::ERROR_BUSY);
-}
-
-TEST_P(ThreadNetworkAidl, Close) {
-    std::shared_ptr<ThreadChipCallback> callback =
-            ndk::SharedRefBase::make<ThreadChipCallback>([](auto /* data */) {});
-
-    EXPECT_TRUE(thread_chip->open(callback).isOk());
-    EXPECT_TRUE(thread_chip->close().isOk());
-    EXPECT_EQ(thread_chip->close().getExceptionCode(), EX_ILLEGAL_STATE);
-}
-
-TEST_P(ThreadNetworkAidl, Reset) {
-    std::shared_ptr<ThreadChipCallback> callback =
-            ndk::SharedRefBase::make<ThreadChipCallback>([](auto /* data */) {});
-
-    EXPECT_TRUE(thread_chip->open(callback).isOk());
-    EXPECT_TRUE(thread_chip->reset().isOk());
-}
-
-TEST_P(ThreadNetworkAidl, SendSpinelFrame) {
-    const uint8_t kCmdOffset = 2;
-    const uint8_t kMajorVersionOffset = 3;
-    const uint8_t kMinorVersionOffset = 4;
-    const std::vector<uint8_t> kGetSpinelProtocolVersion({0x81, 0x02, 0x01});
-    const std::vector<uint8_t> kGetSpinelProtocolVersionResponse({0x81, 0x06, 0x01, 0x04, 0x03});
-    uint8_t min_major_version = kGetSpinelProtocolVersionResponse[kMajorVersionOffset];
-    uint8_t min_minor_version = kGetSpinelProtocolVersionResponse[kMinorVersionOffset];
-    uint8_t major_version;
-    uint8_t minor_version;
-    std::promise<void> open_cb_promise;
-    std::future<void> open_cb_future{open_cb_promise.get_future()};
-    std::shared_ptr<ThreadChipCallback> callback;
-    std::vector<uint8_t> received_frame;
-    std::chrono::milliseconds timeout{kCallbackTimeoutMs};
-
-    callback = ndk::SharedRefBase::make<ThreadChipCallback>(
-            [&](const std::vector<uint8_t>& in_aFrame) {
-                if (in_aFrame.size() == kGetSpinelProtocolVersionResponse.size() &&
-                    in_aFrame[kCmdOffset] == kGetSpinelProtocolVersionResponse[kCmdOffset]) {
-                    major_version = in_aFrame[kMajorVersionOffset];
-                    minor_version = in_aFrame[kMinorVersionOffset];
-                    open_cb_promise.set_value();
-                }
-            });
-
-    ASSERT_NE(callback, nullptr);
-
-    EXPECT_TRUE(thread_chip->open(callback).isOk());
-
-    EXPECT_TRUE(thread_chip->sendSpinelFrame(kGetSpinelProtocolVersion).isOk());
-    EXPECT_EQ(open_cb_future.wait_for(timeout), std::future_status::ready);
-
-    EXPECT_GE(major_version, min_major_version);
-    if (major_version == min_major_version) {
-        EXPECT_GE(minor_version, min_minor_version);
-    }
-}
-
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ThreadNetworkAidl);
-INSTANTIATE_TEST_SUITE_P(
-        Thread, ThreadNetworkAidl,
-        testing::ValuesIn(android::getAidlHalInstanceNames(IThreadChip::descriptor)),
-        android::PrintInstanceNameToString);
-
-int main(int argc, char** argv) {
-    ::testing::InitGoogleTest(&argc, argv);
-    ProcessState::self()->setThreadPoolMaxThreadCount(1);
-    ProcessState::self()->startThreadPool();
-    return RUN_ALL_TESTS();
-}
diff --git a/tests/OWNERS b/tests/OWNERS
new file mode 100644
index 0000000..a07824e
--- /dev/null
+++ b/tests/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 298954331
+
+include platform/hardware/interfaces:/OWNERS
diff --git a/tests/multithread/1.0/default/Multithread.h b/tests/multithread/1.0/default/Multithread.h
index 0d4a007..7df75cc 100644
--- a/tests/multithread/1.0/default/Multithread.h
+++ b/tests/multithread/1.0/default/Multithread.h
@@ -33,7 +33,7 @@
     std::condition_variable mCv;
     std::mutex mCvMutex;
 
-    static constexpr auto kTimeoutDuration = 100ms;
+    static constexpr auto kTimeoutDuration = 1000ms;
 };
 
 extern "C" IMultithread* HIDL_FETCH_IMultithread(const char* name);
diff --git a/tetheroffload/OWNERS b/tetheroffload/OWNERS
new file mode 100644
index 0000000..e033269
--- /dev/null
+++ b/tetheroffload/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 261923493
+
+include platform/packages/modules/Connectivity:/Tethering/OWNERS
+
+kenghua@google.com
diff --git a/tetheroffload/aidl/Android.bp b/tetheroffload/aidl/Android.bp
index 6de27c3..e091c5b 100644
--- a/tetheroffload/aidl/Android.bp
+++ b/tetheroffload/aidl/Android.bp
@@ -18,6 +18,9 @@
             ],
             min_sdk_version: "30",
             enabled: true,
+            lint: {
+                baseline_filename: "lint-baseline.xml",
+            },
         },
         ndk: {
             apps_enabled: false,
diff --git a/tetheroffload/aidl/default/Android.bp b/tetheroffload/aidl/default/Android.bp
index 8f0739c..8c96990 100644
--- a/tetheroffload/aidl/default/Android.bp
+++ b/tetheroffload/aidl/default/Android.bp
@@ -19,18 +19,52 @@
 cc_binary {
     name: "android.hardware.tetheroffload-service.example",
     relative_install_path: "hw",
-    init_rc: ["tetheroffload-example.rc"],
-    vintf_fragments: ["tetheroffload-example.xml"],
     vendor: true,
-    shared_libs: [
+
+    stl: "c++_static",
+    static_libs: [
         "android.hardware.tetheroffload-V1-ndk",
         "libbase",
+    ],
+    shared_libs: [
         "libbinder_ndk",
-        "libcutils",
-        "libutils",
+        "liblog",
     ],
     srcs: [
         "main.cpp",
         "Offload.cpp",
     ],
+
+    installable: false, // installed in APEX
+}
+
+prebuilt_etc {
+    name: "tetheroffload-example.rc",
+    src: "tetheroffload-example.rc",
+    installable: false,
+}
+
+prebuilt_etc {
+    name: "tetheroffload-example.xml",
+    src: "tetheroffload-example.xml",
+    sub_dir: "vintf",
+    installable: false,
+}
+
+apex {
+    name: "com.android.hardware.tetheroffload",
+    manifest: "apex_manifest.json",
+    file_contexts: "apex_file_contexts",
+    key: "com.android.hardware.key",
+    certificate: ":com.android.hardware.certificate",
+    updatable: false,
+    vendor: true,
+
+    binaries: [
+        "android.hardware.tetheroffload-service.example",
+    ],
+    prebuilts: [
+        "tetheroffload-example.rc",
+        "tetheroffload-example.xml",
+    ],
 }
diff --git a/tetheroffload/aidl/default/apex_file_contexts b/tetheroffload/aidl/default/apex_file_contexts
new file mode 100644
index 0000000..a520101
--- /dev/null
+++ b/tetheroffload/aidl/default/apex_file_contexts
@@ -0,0 +1,3 @@
+(/.*)?                                                          u:object_r:vendor_file:s0
+/etc(/.*)?                                                      u:object_r:vendor_configs_file:s0
+/bin/hw/android\.hardware\.tetheroffload-service\.example       u:object_r:hal_tetheroffload_default_exec:s0
diff --git a/tetheroffload/aidl/default/apex_manifest.json b/tetheroffload/aidl/default/apex_manifest.json
new file mode 100644
index 0000000..4c90889
--- /dev/null
+++ b/tetheroffload/aidl/default/apex_manifest.json
@@ -0,0 +1,4 @@
+{
+    "name": "com.android.hardware.tetheroffload",
+    "version": 1
+}
diff --git a/tetheroffload/aidl/default/tetheroffload-example.rc b/tetheroffload/aidl/default/tetheroffload-example.rc
index 46cda61..b95544b 100644
--- a/tetheroffload/aidl/default/tetheroffload-example.rc
+++ b/tetheroffload/aidl/default/tetheroffload-example.rc
@@ -1,4 +1,4 @@
-service vendor.tetheroffload-example /vendor/bin/hw/android.hardware.tetheroffload-service.example
+service vendor.tetheroffload-example /apex/com.android.hardware.tetheroffload/bin/hw/android.hardware.tetheroffload-service.example
     class hal
     user nobody
     group nobody
diff --git a/tetheroffload/aidl/lint-baseline.xml b/tetheroffload/aidl/lint-baseline.xml
new file mode 100644
index 0000000..62924b1
--- /dev/null
+++ b/tetheroffload/aidl/lint-baseline.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01">
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.os.Binder#markVintfStability`"
+        errorLine1="      this.markVintfStability();"
+        errorLine2="           ~~~~~~~~~~~~~~~~~~">
+        <location
+            file="out/soong/.intermediates/hardware/interfaces/tetheroffload/aidl/android.hardware.tetheroffload-V1-java-source/gen/android/hardware/tetheroffload/IOffload.java"
+            line="64"
+            column="12"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.os.Binder#markVintfStability`"
+        errorLine1="      this.markVintfStability();"
+        errorLine2="           ~~~~~~~~~~~~~~~~~~">
+        <location
+            file="out/soong/.intermediates/hardware/interfaces/tetheroffload/aidl/android.hardware.tetheroffload-V1-java-source/gen/android/hardware/tetheroffload/ITetheringOffloadCallback.java"
+            line="45"
+            column="12"/>
+    </issue>
+
+</issues>
\ No newline at end of file
diff --git a/tetheroffload/config/1.0/Android.bp b/tetheroffload/config/1.0/Android.bp
index 116c9b6..b5c4185 100644
--- a/tetheroffload/config/1.0/Android.bp
+++ b/tetheroffload/config/1.0/Android.bp
@@ -19,4 +19,8 @@
         "android.hidl.base@1.0",
     ],
     gen_java: true,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.tethering",
+    ],
 }
diff --git a/tetheroffload/control/1.0/Android.bp b/tetheroffload/control/1.0/Android.bp
index acb5ee8..6589ee2 100644
--- a/tetheroffload/control/1.0/Android.bp
+++ b/tetheroffload/control/1.0/Android.bp
@@ -21,4 +21,8 @@
         "android.hidl.base@1.0",
     ],
     gen_java: true,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.tethering",
+    ],
 }
diff --git a/tetheroffload/control/1.1/Android.bp b/tetheroffload/control/1.1/Android.bp
index 7871c2c..0daa90e 100644
--- a/tetheroffload/control/1.1/Android.bp
+++ b/tetheroffload/control/1.1/Android.bp
@@ -22,7 +22,7 @@
         "android.hidl.base@1.0",
     ],
     apex_available: [
-        "//apex_available:platform", // Used by InProcessTethering
+        "//apex_available:platform",
         "com.android.tethering",
     ],
     gen_java: true,
diff --git a/thermal/2.0/default/Android.bp b/thermal/2.0/default/Android.bp
index f743ade..83afa97 100644
--- a/thermal/2.0/default/Android.bp
+++ b/thermal/2.0/default/Android.bp
@@ -22,23 +22,13 @@
     default_applicable_licenses: ["hardware_interfaces_license"],
 }
 
-filegroup {
-    name: "android.hardware.thermal@2.0-service.xml",
-    srcs: ["android.hardware.thermal@2.0-service.xml"],
-}
-
-filegroup {
-    name: "android.hardware.thermal@2.0-service.rc",
-    srcs: ["android.hardware.thermal@2.0-service.rc"],
-}
-
 cc_binary {
     name: "android.hardware.thermal@2.0-service.mock",
     defaults: ["hidl_defaults"],
     relative_install_path: "hw",
     vendor: true,
-    init_rc: [":android.hardware.thermal@2.0-service.rc"],
-    vintf_fragments: [":android.hardware.thermal@2.0-service.xml"],
+    init_rc: ["android.hardware.thermal@2.0-service.rc"],
+    vintf_fragments: ["android.hardware.thermal@2.0-service.xml"],
     srcs: [
         "Thermal.cpp",
         "service.cpp",
diff --git a/thermal/2.0/default/apex/Android.bp b/thermal/2.0/default/apex/Android.bp
deleted file mode 100644
index 914a3a8..0000000
--- a/thermal/2.0/default/apex/Android.bp
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright (C) 2022 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package {
-    default_applicable_licenses: ["hardware_interfaces_license"],
-}
-
-apex_key {
-    name: "com.android.hardware.thermal.key",
-    public_key: "com.android.hardware.thermal.avbpubkey",
-    private_key: "com.android.hardware.thermal.pem",
-}
-
-android_app_certificate {
-    name: "com.android.hardware.thermal.certificate",
-    certificate: "com.android.hardware.thermal",
-}
-
-genrule {
-    name: "com.android.hardware.thermal.rc-gen",
-    srcs: [":android.hardware.thermal@2.0-service.rc"],
-    out: ["com.android.hardware.thermal.rc"],
-    cmd: "sed -E 's/\\/vendor/\\/apex\\/com.android.hardware.thermal.mock/' $(in) > $(out)",
-}
-
-prebuilt_etc {
-    name: "com.android.hardware.thermal.rc",
-    src: ":com.android.hardware.thermal.rc-gen",
-    installable: false,
-}
-
-apex {
-    name: "com.android.hardware.thermal.mock",
-    manifest: "manifest.json",
-    file_contexts: "file_contexts",
-    key: "com.android.hardware.thermal.key",
-    certificate: ":com.android.hardware.thermal.certificate",
-    use_vndk_as_stable: true,
-    updatable: false,
-    soc_specific: true,
-    binaries: ["android.hardware.thermal@2.0-service.mock"],
-    prebuilts: ["com.android.hardware.thermal.rc"],
-    vintf_fragments: [":android.hardware.thermal@2.0-service.xml"],
-}
diff --git a/thermal/2.0/default/apex/com.android.hardware.thermal.avbpubkey b/thermal/2.0/default/apex/com.android.hardware.thermal.avbpubkey
deleted file mode 100644
index 8f7cf72..0000000
--- a/thermal/2.0/default/apex/com.android.hardware.thermal.avbpubkey
+++ /dev/null
Binary files differ
diff --git a/thermal/2.0/default/apex/com.android.hardware.thermal.pem b/thermal/2.0/default/apex/com.android.hardware.thermal.pem
deleted file mode 100644
index 4ea6e85..0000000
--- a/thermal/2.0/default/apex/com.android.hardware.thermal.pem
+++ /dev/null
@@ -1,51 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIIJKQIBAAKCAgEApXL2prEKqnU/xHlYeZB55x5EOrVAsfBuyHN5xOgUY877UuDC
-xoX+DOYAkCDSwMPmBj/Q9E70lId1PXMeI3y0obgYpdFubqRsoGNcEq2zG811tr6J
-BAE/7mAI0a4VVFWtauBNTiP5G31hsRpZNTE/dyZxs20GEVQqdvtBlEAuebCt7VIb
-fCwXnPCXSiYQ9WyjU0dwHoZPuy02qBuq3v9NYt5J6lYiPDqTWmpYBFm+SIZvth/j
-HUcaU3p+BlUad0qLhA8HYTPPBwJq2uHbTXeFrWXngt+UPCdzYubyUjG4WmgHIfee
-zSvoTjud2Gaofnd4/PcE5jFTMYUJuz0D4E+8StZArw+xegfxGcvqFZ4gfKAO1Vha
-eQBhw94P2eieUfh9metQEyKZ+A24sxG0awtAUOgcwr/WNv2TgJoN8+56DhuPXOuO
-U2qeIZuIrmE5xmyzrzJsCx+5vRQA7A3kpxRo1ZCgbJlzMgdAQaRTe2rqxyyoeFQR
-HbxUdsM7ZwDLE62UlaTTZFoJ1wzvZmsIJdkdRg97zcc3R3kYnVehCxAZ1KdAKzq6
-bhrw/kNAVA0zUHhlhHWGDnJQ/rkGfjQ9GGhS51IJYgKEoQc5M9hSgZD3idic8hso
-63r/P2Wn4S78gwLigfpzsGD7RrusTbMIRkebwpHwAYpB8qIykrtUKfunLtMCAwEA
-AQKCAgEAjiKbv0ytaw9bfwD4f0cdUu5vkzgPok55/f8mh4ERs0UoKGUrL74BKTeX
-GDr6k9w4CvpcGuaRu+A7WlVBeR8zVxN/KUUo6CidoZR6jxlmm+YA0MQTlbs1Hyal
-rO0vKcqJNx4Hi6/f3Dv0519JcCck7Mm8OHbbFZwG9zyXdDNHOggNA6rcLer7Rjpy
-3qKhQxbXoT3oFnEwog8Pu5A5VWZjJyLswULKGo//81cU0nf+vvOvmPj/9jEVbs32
-4p3OJNmHziXTIzCNFOqAvhX2fzDFSNgY8hf9k0gZGshpOS+5vwFLz2SZqo2j/0G8
-MyLOcgdVi4zzSobpf8tZNuAOKnCVwxteV3Ddl0o+qAf4cQCAXtuEkJvFWpAxrX4m
-J7nDDuvcTjKMlnchlm6XxmP27YNTKA2w5uNfrJQV5LR3IDs77PFpNiKOwERka6MU
-WE1LnjAFTCDxujT29NfIjC9z0iOY45TYut4okesaK7woe6pfK2H0ouvE6mZ+Lb7Y
-qZphPb4e4DZZZAVoELVvWflm/VC/xmBMA9vtzpjuvRXD+iYjgxbHaiG2UANLWmTd
-vADLqBadlbp10AvyrjKxHUhAiZnJgaVKRXtw5qk8YrwZOwypEHCQjY41fJuRScWF
-pD58/PYOLtSdwewzTijXSVwwPeqL1JMdJ+KWFk5zI410DtmHwoECggEBANM5dHEj
-L4ZOCcgHVG7aCLah7f/0Za7BBiPsZFD0uRIzWFTd77st3v8ulMw1JQiO3+xmpL7e
-iOP+onuSEMKgNQqeX9WCnv6pL+mjg0of2IEcGnvCpmfUZRA2x/MlyJRrQ1vHGqkV
-oBIIWgCGmIAWuFbHPmkNYx7mAJymAfzShkVtMw29oiGYyubqx9cTjD0odeyScbhZ
-LuMt72O5QeNsPREX4SsSRAL+vZbz1+8iRI8Fon89csZym3hos3DA4QSml+FNHnLe
-YFD6AfU7pdn79YhhNkn4jE0BxLaEkXhMs8RRTU2Q3o990ZxrAZGQz4zqOm5sOIQT
-JaXFXxGvOwEysrMCggEBAMiFaTzkhJSLEmLEu0T3gNEC2d3jE9kt4Olv4mQmzD00
-AzDtkrkArLQCeG3CMn55oFcJRwr8gAEk7/f2mvJSoZQnw0J0tRI+QiHJG4zwdsQC
-UszqN89X8ef0yoobwVa31ZoWxK4/NvLO4GZQ6UUd9uni10jfYVWmwEwKBU61ihvT
-ntcZIXvROR6khxzLeXtglnsznnYcdYMPJUeN+cfK9/rL3V3jk1jes8y8XwYfxkUa
-99nEe1NkRCUznzKxvkRwnKunlMCEkZ5z4nNMlqEqiOlVEYgwKwNCP+qM7ZKUJg7t
-uOL91bqWFPj2qdzyUh0uP5V/dg2odnu0xSblKWhxI2ECggEBAKbZttJ8Idlsoath
-pt+d2c4yoadTLlNZ5HjSDfgpKFxpNLhtTCbGuGVJLX8V5/gXrGi4OCER9n5rMXx9
-SEIFfYCy1C77bI7rpI5hfJ88ArESOxVSEFLqYx7otw+p5AThqibAY533GCfGcxoB
-OEvOJrVd1D31tju9IfSb6ewFfM0w0mhjSMRTRswb39pUda4F3QkQMUaXJEOOkJBs
-0dBNOvvaqiJ03kajZa3tVsBuiEuV/uOV7ak29Pqrcjt6EQW0dzsgyRGh+eFda9iE
-0qEbt7uQVusdq+5UnEg09hhaNpK4SmEgM76Te9WcbXPIOTst9xQs5oPmABIvk8aL
-bgenPaMCggEAX9EAHIzFnYVm37NKGQZ7k2RdXt2nGlwF4QYJk/nGFmjILZUYSza7
-T7jueuQU5MKRj4VrYSCOuf1AfahlGe3KL9VgRF0oOPNu/l3uwEYXOkox7qDs0jMf
-8MrUDXJ9zEZD10GR8gFa7GNWbw2yqchLuC8g2D2FcTwhHzSanKW6vNk+SWJE0bmE
-JdRQi73e6smYnn5n9eBbdqjCE5MQDBw8qqbHvJmGSyz/lZFdhrugLl1YmcJ9e7ep
-qG0mYT71wBZfhtapCeVO//w39Qhf4dtFWNnBauY5Z3E8wYNd8nDATtnhQvYwLtyQ
-YPbc7CsOecsjrvgdHSGmnC4hFxjh1HpbgQKCAQBzEr35CFQpUfGsu06SqRrxp7mb
-BfQzLmqnt+ZLu21H/YjVbamMXNjbJFSdtFLxAK/s9vFGQzEWWEYia2pRZejlCXhQ
-RO+TREJ4rm4Erfdh+zS9z8MZlxe2ybIMs260XxjZ0gEltRtJ6P14zLBlChi/rQEY
-tGrOpfjvLc1Lryaucwj7snDLtMfyqvemAUmuJNn/6IEMuG4DcdtJ3Whh7t3xKfO0
-Hc71Oh7F30okQQ6Ctiwp1T77Y1EXlRJrUtpf1sLxeItP6/r3WXLNaiFdKqGJxiCM
-Gw11oUcBA9bvfAzeJIpVVbLtGPNOp4J1XpkgFcWzsTM+ZpxWwbj4yJL6rSN2
------END RSA PRIVATE KEY-----
diff --git a/thermal/2.0/default/apex/com.android.hardware.thermal.pk8 b/thermal/2.0/default/apex/com.android.hardware.thermal.pk8
deleted file mode 100644
index 3e5bf69..0000000
--- a/thermal/2.0/default/apex/com.android.hardware.thermal.pk8
+++ /dev/null
Binary files differ
diff --git a/thermal/2.0/default/apex/com.android.hardware.thermal.x509.pem b/thermal/2.0/default/apex/com.android.hardware.thermal.x509.pem
deleted file mode 100644
index 048e69a..0000000
--- a/thermal/2.0/default/apex/com.android.hardware.thermal.x509.pem
+++ /dev/null
@@ -1,34 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIF3TCCA8UCFFWeg2KJX/fyAqZPcKaFS61/a3GiMA0GCSqGSIb3DQEBCwUAMIGp
-MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91
-bnRhaW4gVmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UECwwHQW5kcm9pZDEi
-MCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTElMCMGA1UEAwwcY29t
-LmFuZHJvaWQuaGFyZHdhcmUudGhlcm1hbDAgFw0yMTExMTcxODE3MjRaGA80NzU5
-MTAxNDE4MTcyNFowgakxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlh
-MRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYD
-VQQLDAdBbmRyb2lkMSIwIAYJKoZIhvcNAQkBFhNhbmRyb2lkQGFuZHJvaWQuY29t
-MSUwIwYDVQQDDBxjb20uYW5kcm9pZC5oYXJkd2FyZS50aGVybWFsMIICIjANBgkq
-hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA2W8QhCKX0WoS5jhIWbWBoKulD6XhKASA
-CL0oU6Uci0U6id2m++ou/T0aHSlliS9kT1NEABNwbLeTDa9h1qg1lbajRzXbvzEz
-EvZYT+dlgYFNZ9zaVCIlMapoiN+nrM/Rs24UBjJrZu1B39+IcE5ciQz69PgrLKWF
-vFEdYzxWI246azOVr3fvdelQg+CyPgiGObVAGOHhAidvsjg4FssKnADzn+JNlTt6
-b9P65xUQErut8hz9YdLtfZ096iwe8eEpsMOQwCNdKNXVCcNjQWkOwRaU+0awHoH1
-4mArvF7yyvJxqzkNaR03BPqXAHPIAPu6xdfA19+HVIiz6bLEZ1mfCM6edXByCWZu
-K8o54OZph71r15ncv4DVd+cnBjNvBvfdlJSeGjSreFkUo5NkfAwqdmLfZx6CedHI
-sLx7X8vPYolQnR4UEvaX6yeNN0gs8Dd6ePMqOEiwWFVASD+cbpcUrp09uzlDStGV
-1DPx/9J2kw8eXPMqOSGThkLWuUMUFojyh7bNlL16oYmEeZW6/OOXCOXzAQgJ7NIs
-DA1/H2w1HMHWgSfF4y+Es2CiqcgVFOIU/07b31Edw4v56pjx1CUpRpJZjDA1JJNo
-A4YCnpA6JWTxzUTmv21fEYyY+poA3CuzvCfZ80z9h/UFW98oM9GawGvK0i2pLudS
-RaZXWeil08cCAwEAATANBgkqhkiG9w0BAQsFAAOCAgEAj2gpn/IpAHQLDlI52WwL
-IDc5uzlf1BGseLZ8M8uuMiwvN00nOjunQQZEIbhH7+03GYyMzRhTTI3nWwmX4Fnq
-vC5sR68yNlu9gOAMXaAHo/Rw73ak7sv8xGbb2FeQsHaMKDQ2nqxP17SWdQ0xWa1u
-5qNurPOdAPOw77noZcT7yYX7lcrOKxPIekPJxyeOlp4bQSmabSRgYr70B7GybPlv
-K1gkgCBxl5RiVjVxLo+7ESHSAaGLy0S7F2v6PJ9oj15TovWQ0py2iBKZ6HReB7s/
-umnQqkwXDLudlNmoXIsgIYn8vKFTYpy1GSNJqhRSLfvLR6NtuU0iCTvg/X7oPmS1
-dWUdjVeO7ZVvIpO3gLLEe4maBEYF2sOlt3bRmzIHydORJtkfTt5tiZ4wR9RfJbkj
-iBiDbNiX010bZPTAXmgMbuJzQXZEXCBy0qKeS1cHwf9M8FDoiLajXepfZIp+6syt
-D4lZk4eAV141JL5PfABfdZWwT3cTgFIqCYpqrMQJIu+GHEjUwD2yNPi0I1/ydFCW
-CPDnzWjYCi6yVB8hss3ZFbvhfyJzdm3LivNVbLGK0+TG0EOAz6d2aQ0UjESgMD1A
-U8hLzQt7MiFSG0bt2cVx6SgCHeYUqMntbFELEAURWrhAfPLMJtAvFgKbEiZEAkkW
-pdDVh603aIp4LjVCfTYp/mQ=
------END CERTIFICATE-----
diff --git a/thermal/2.0/default/apex/file_contexts b/thermal/2.0/default/apex/file_contexts
deleted file mode 100644
index e0d87c7..0000000
--- a/thermal/2.0/default/apex/file_contexts
+++ /dev/null
@@ -1,5 +0,0 @@
-(/.*)?                                                    u:object_r:vendor_file:s0
-# Permission XMLs
-/etc/permissions(/.*)?                                    u:object_r:vendor_configs_file:s0
-# binary
-/bin/hw/android\.hardware\.thermal@2\.0-service\.mock     u:object_r:hal_thermal_default_exec:s0
diff --git a/thermal/2.0/default/apex/manifest.json b/thermal/2.0/default/apex/manifest.json
deleted file mode 100644
index ee44dc1..0000000
--- a/thermal/2.0/default/apex/manifest.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
-  "name": "com.android.hardware.thermal.mock",
-  "version": 1
-}
diff --git a/thermal/aidl/Android.bp b/thermal/aidl/Android.bp
index efc763c..734aab7 100644
--- a/thermal/aidl/Android.bp
+++ b/thermal/aidl/Android.bp
@@ -35,6 +35,9 @@
         java: {
             platform_apis: true,
         },
+        rust: {
+            enabled: true,
+        },
     },
     versions_with_info: [
         {
@@ -42,6 +45,6 @@
             imports: [],
         },
     ],
-    frozen: true,
+    frozen: false,
 
 }
diff --git a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingDevice.aidl b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingDevice.aidl
index dff3c4c..7e1aed7 100644
--- a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingDevice.aidl
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingDevice.aidl
@@ -38,4 +38,7 @@
   android.hardware.thermal.CoolingType type;
   String name;
   long value;
+  long powerLimitMw;
+  long powerMw;
+  long timeWindowMs;
 }
diff --git a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingType.aidl b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingType.aidl
index 1f87cf2..5e88aa0 100644
--- a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingType.aidl
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingType.aidl
@@ -46,4 +46,8 @@
   POWER_AMPLIFIER,
   DISPLAY,
   SPEAKER,
+  WIFI,
+  CAMERA,
+  FLASHLIGHT,
+  USB_PORT,
 }
diff --git a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/ICoolingDeviceChangedCallback.aidl b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/ICoolingDeviceChangedCallback.aidl
new file mode 100644
index 0000000..ea75b1c
--- /dev/null
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/ICoolingDeviceChangedCallback.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible 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;
+/* @hide */
+@VintfStability
+interface ICoolingDeviceChangedCallback {
+  oneway void notifyCoolingDeviceChanged(in android.hardware.thermal.CoolingDevice coolingDevice);
+}
diff --git a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermal.aidl b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermal.aidl
index c9b6cab..904496c 100644
--- a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermal.aidl
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermal.aidl
@@ -44,4 +44,6 @@
   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);
+  void registerCoolingDeviceChangedCallbackWithType(in android.hardware.thermal.ICoolingDeviceChangedCallback callback, in android.hardware.thermal.CoolingType type);
+  void unregisterCoolingDeviceChangedCallback(in android.hardware.thermal.ICoolingDeviceChangedCallback callback);
 }
diff --git a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/TemperatureType.aidl b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/TemperatureType.aidl
index e9710a7..665a36e 100644
--- a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/TemperatureType.aidl
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/TemperatureType.aidl
@@ -35,7 +35,7 @@
 /* @hide */
 @Backing(type="int") @VintfStability
 enum TemperatureType {
-  UNKNOWN = (-1),
+  UNKNOWN = (-1) /* -1 */,
   CPU = 0,
   GPU = 1,
   BATTERY = 2,
@@ -50,4 +50,10 @@
   DISPLAY = 11,
   MODEM = 12,
   SOC = 13,
+  WIFI = 14,
+  CAMERA = 15,
+  FLASHLIGHT = 16,
+  SPEAKER = 17,
+  AMBIENT = 18,
+  POGO = 19,
 }
diff --git a/thermal/aidl/android/hardware/thermal/CoolingDevice.aidl b/thermal/aidl/android/hardware/thermal/CoolingDevice.aidl
index 0c5c17d..406733b 100644
--- a/thermal/aidl/android/hardware/thermal/CoolingDevice.aidl
+++ b/thermal/aidl/android/hardware/thermal/CoolingDevice.aidl
@@ -40,4 +40,16 @@
      * means deeper throttling.
      */
     long value;
+    /**
+     * Power budget (mW) of the cooling device.
+     */
+    long powerLimitMw;
+    /**
+     * Target cooling device's AVG power for the last time_window_ms.
+     */
+    long powerMw;
+    /**
+     * The time window (millisecond) to calculate the power consumption
+     */
+    long timeWindowMs;
 }
diff --git a/thermal/aidl/android/hardware/thermal/CoolingType.aidl b/thermal/aidl/android/hardware/thermal/CoolingType.aidl
index 08beb55..c00028d 100644
--- a/thermal/aidl/android/hardware/thermal/CoolingType.aidl
+++ b/thermal/aidl/android/hardware/thermal/CoolingType.aidl
@@ -34,4 +34,8 @@
     POWER_AMPLIFIER,
     DISPLAY,
     SPEAKER,
+    WIFI,
+    CAMERA,
+    FLASHLIGHT,
+    USB_PORT,
 }
diff --git a/thermal/aidl/android/hardware/thermal/ICoolingDeviceChangedCallback.aidl b/thermal/aidl/android/hardware/thermal/ICoolingDeviceChangedCallback.aidl
new file mode 100644
index 0000000..e6bb9fe
--- /dev/null
+++ b/thermal/aidl/android/hardware/thermal/ICoolingDeviceChangedCallback.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.Temperature;
+
+/**
+ * ICoolingDeviceChangedCallback send cooling device change notification to clients.
+ * @hide
+ */
+@VintfStability
+interface ICoolingDeviceChangedCallback {
+    /**
+     * Send a cooling device change event to all ThermalHAL
+     * cooling device event listeners.
+     *
+     * @param cooling_device The cooling device information associated with the
+     *     change event.
+     */
+    oneway void notifyCoolingDeviceChanged(in CoolingDevice coolingDevice);
+}
diff --git a/thermal/aidl/android/hardware/thermal/IThermal.aidl b/thermal/aidl/android/hardware/thermal/IThermal.aidl
index c94edcd..4aa4090 100644
--- a/thermal/aidl/android/hardware/thermal/IThermal.aidl
+++ b/thermal/aidl/android/hardware/thermal/IThermal.aidl
@@ -18,6 +18,7 @@
 
 import android.hardware.thermal.CoolingDevice;
 import android.hardware.thermal.CoolingType;
+import android.hardware.thermal.ICoolingDeviceChangedCallback;
 import android.hardware.thermal.IThermalChangedCallback;
 import android.hardware.thermal.Temperature;
 import android.hardware.thermal.TemperatureThreshold;
@@ -188,4 +189,40 @@
      *         getMessage() must be populated with human-readable error message.
      */
     void unregisterThermalChangedCallback(in IThermalChangedCallback callback);
+
+    /**
+     * Register an ICoolingDeviceChangedCallback for a given CoolingType, used by
+     * the Thermal HAL to receive CDEV events when cooling device status
+     * changed.
+     * Multiple registrations with different ICoolingDeviceChangedCallback must be allowed.
+     * Multiple registrations with same ICoolingDeviceChangedCallback is not allowed, client
+     * should unregister the given ICoolingDeviceChangedCallback first.
+     *
+     * @param callback the ICoolingChangedCallback to use for receiving
+     *    cooling device 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 EX_ILLEGAL_ARGUMENT If the callback is given nullptr or already registered. And the
+     *         getMessage() must be populated with human-readable error message.
+     * @throws EX_ILLEGAL_STATE If the Thermal HAL is not initialized successfully. And the
+     *         getMessage() must be populated with human-readable error message.
+     */
+    void registerCoolingDeviceChangedCallbackWithType(
+            in ICoolingDeviceChangedCallback callback, in CoolingType type);
+
+    /**
+     * Unregister an ICoolingDeviceChangedCallback, used by the Thermal HAL
+     * to receive CDEV events when cooling device status changed.
+     *
+     * @param callback the ICoolingDeviceChangedCallback to use for receiving
+     *    cooling device events. if nullptr callback is given, the status code will be
+     *    STATUS_BAD_VALUE and the operation will fail.
+     *
+     * @throws EX_ILLEGAL_ARGUMENT If the callback is given nullptr or not previously registered.
+     *         And the getMessage() must be populated with human-readable error message.
+     * @throws EX_ILLEGAL_STATE If the Thermal HAL is not initialized successfully. And the
+     *         getMessage() must be populated with human-readable error message.
+     */
+    void unregisterCoolingDeviceChangedCallback(in ICoolingDeviceChangedCallback callback);
 }
diff --git a/thermal/aidl/android/hardware/thermal/TemperatureType.aidl b/thermal/aidl/android/hardware/thermal/TemperatureType.aidl
index 467d096..ce2a9fc 100644
--- a/thermal/aidl/android/hardware/thermal/TemperatureType.aidl
+++ b/thermal/aidl/android/hardware/thermal/TemperatureType.aidl
@@ -44,4 +44,10 @@
     DISPLAY = 11,
     MODEM = 12,
     SOC = 13,
+    WIFI = 14,
+    CAMERA = 15,
+    FLASHLIGHT = 16,
+    SPEAKER = 17,
+    AMBIENT = 18,
+    POGO = 19,
 }
diff --git a/thermal/aidl/default/Android.bp b/thermal/aidl/default/Android.bp
index 49a578b..9fe62ce 100644
--- a/thermal/aidl/default/Android.bp
+++ b/thermal/aidl/default/Android.bp
@@ -24,26 +24,50 @@
 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: [
+    stl: "c++_static",
+    static_libs: [
+        "android.hardware.thermal-V2-ndk",
         "libbase",
+    ],
+    shared_libs: [
         "libbinder_ndk",
-        "android.hardware.thermal-V1-ndk",
+        "liblog",
     ],
     srcs: [
         "main.cpp",
         "Thermal.cpp",
     ],
+    installable: false,
 }
 
-filegroup {
+prebuilt_etc {
     name: "android.hardware.thermal.example.xml",
-    srcs: ["thermal-example.xml"],
+    src: "thermal-example.xml",
+    sub_dir: "vintf",
+    installable: false,
 }
 
-filegroup {
+prebuilt_etc {
     name: "android.hardware.thermal.example.rc",
-    srcs: ["thermal-example.rc"],
+    src: "thermal-example.rc",
+    installable: false,
+}
+
+apex {
+    name: "com.android.hardware.thermal",
+    manifest: "apex_manifest.json",
+    file_contexts: "apex_file_contexts",
+    key: "com.android.hardware.key",
+    certificate: ":com.android.hardware.certificate",
+    updatable: false,
+    vendor: true,
+
+    binaries: [
+        "android.hardware.thermal-service.example",
+    ],
+    prebuilts: [
+        "android.hardware.thermal.example.xml",
+        "android.hardware.thermal.example.rc",
+    ],
 }
diff --git a/thermal/aidl/default/Thermal.cpp b/thermal/aidl/default/Thermal.cpp
index f643d22..41d0be8 100644
--- a/thermal/aidl/default/Thermal.cpp
+++ b/thermal/aidl/default/Thermal.cpp
@@ -142,4 +142,53 @@
     return ScopedAStatus::ok();
 }
 
+ScopedAStatus Thermal::registerCoolingDeviceChangedCallbackWithType(
+        const std::shared_ptr<ICoolingDeviceChangedCallback>& in_callback, CoolingType in_type) {
+    LOG(VERBOSE) << __func__ << " ICoolingDeviceChangedCallback: " << in_callback
+                 << ", CoolingType: " << static_cast<int32_t>(in_type);
+    if (in_callback == nullptr) {
+        return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                "Invalid nullptr callback");
+    }
+    {
+        std::lock_guard<std::mutex> _lock(cdev_callback_mutex_);
+        if (std::any_of(cdev_callbacks_.begin(), cdev_callbacks_.end(),
+                        [&](const std::shared_ptr<ICoolingDeviceChangedCallback>& c) {
+                            return interfacesEqual(c, in_callback);
+                        })) {
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "Callback already registered");
+        }
+        cdev_callbacks_.push_back(in_callback);
+    }
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus Thermal::unregisterCoolingDeviceChangedCallback(
+        const std::shared_ptr<ICoolingDeviceChangedCallback>& in_callback) {
+    LOG(VERBOSE) << __func__ << " ICoolingDeviceChangedCallback: " << in_callback;
+    if (in_callback == nullptr) {
+        return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                "Invalid nullptr callback");
+    }
+    {
+        std::lock_guard<std::mutex> _lock(cdev_callback_mutex_);
+        bool removed = false;
+        cdev_callbacks_.erase(
+                std::remove_if(cdev_callbacks_.begin(), cdev_callbacks_.end(),
+                               [&](const std::shared_ptr<ICoolingDeviceChangedCallback>& c) {
+                                   if (interfacesEqual(c, in_callback)) {
+                                       removed = true;
+                                       return true;
+                                   }
+                                   return false;
+                               }),
+                cdev_callbacks_.end());
+        if (!removed) {
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "Callback wasn't registered");
+        }
+    }
+    return ScopedAStatus::ok();
+}
 }  // namespace aidl::android::hardware::thermal::impl::example
diff --git a/thermal/aidl/default/Thermal.h b/thermal/aidl/default/Thermal.h
index 8885e63..d3d8874 100644
--- a/thermal/aidl/default/Thermal.h
+++ b/thermal/aidl/default/Thermal.h
@@ -46,6 +46,7 @@
 
     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;
@@ -53,9 +54,18 @@
     ndk::ScopedAStatus unregisterThermalChangedCallback(
             const std::shared_ptr<IThermalChangedCallback>& in_callback) override;
 
+    ndk::ScopedAStatus registerCoolingDeviceChangedCallbackWithType(
+            const std::shared_ptr<ICoolingDeviceChangedCallback>& in_callback,
+            CoolingType in_type) override;
+
+    ndk::ScopedAStatus unregisterCoolingDeviceChangedCallback(
+            const std::shared_ptr<ICoolingDeviceChangedCallback>& in_callback) override;
+
   private:
     std::mutex thermal_callback_mutex_;
     std::vector<std::shared_ptr<IThermalChangedCallback>> thermal_callbacks_;
+    std::mutex cdev_callback_mutex_;
+    std::vector<std::shared_ptr<ICoolingDeviceChangedCallback>> cdev_callbacks_;
 };
 
 }  // namespace example
diff --git a/thermal/aidl/default/apex_file_contexts b/thermal/aidl/default/apex_file_contexts
new file mode 100644
index 0000000..9fa5339
--- /dev/null
+++ b/thermal/aidl/default/apex_file_contexts
@@ -0,0 +1,3 @@
+(/.*)?                                                          u:object_r:vendor_file:s0
+/etc(/.*)?                                                      u:object_r:vendor_configs_file:s0
+/bin/hw/android\.hardware\.thermal-service\.example             u:object_r:hal_thermal_default_exec:s0
diff --git a/thermal/aidl/default/apex_manifest.json b/thermal/aidl/default/apex_manifest.json
new file mode 100644
index 0000000..80420d5
--- /dev/null
+++ b/thermal/aidl/default/apex_manifest.json
@@ -0,0 +1,4 @@
+{
+    "name": "com.android.hardware.thermal",
+    "version": 1
+}
diff --git a/thermal/aidl/default/thermal-example.rc b/thermal/aidl/default/thermal-example.rc
index 591ca03..36dde0d 100644
--- a/thermal/aidl/default/thermal-example.rc
+++ b/thermal/aidl/default/thermal-example.rc
@@ -1,4 +1,4 @@
-service vendor.thermal-example /vendor/bin/hw/android.hardware.thermal-service.example
+service vendor.thermal-example /apex/com.android.hardware.thermal/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
index bdee744..08dc68c 100644
--- a/thermal/aidl/default/thermal-example.xml
+++ b/thermal/aidl/default/thermal-example.xml
@@ -1,7 +1,7 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.thermal</name>
-        <version>1</version>
+        <version>2</version>
         <fqname>IThermal/default</fqname>
     </hal>
 </manifest>
diff --git a/thermal/aidl/vts/Android.bp b/thermal/aidl/vts/Android.bp
index b00eb33..0812811 100644
--- a/thermal/aidl/vts/Android.bp
+++ b/thermal/aidl/vts/Android.bp
@@ -32,7 +32,7 @@
         "libbinder_ndk",
     ],
     static_libs: [
-        "android.hardware.thermal-V1-ndk",
+        "android.hardware.thermal-V2-ndk",
     ],
     test_suites: [
         "vts",
diff --git a/thermal/aidl/vts/VtsHalThermalTargetTest.cpp b/thermal/aidl/vts/VtsHalThermalTargetTest.cpp
index 835fbfa..403c6c8 100644
--- a/thermal/aidl/vts/VtsHalThermalTargetTest.cpp
+++ b/thermal/aidl/vts/VtsHalThermalTargetTest.cpp
@@ -26,6 +26,7 @@
 
 #include <aidl/Gtest.h>
 #include <aidl/Vintf.h>
+#include <aidl/android/hardware/thermal/BnCoolingDeviceChangedCallback.h>
 #include <aidl/android/hardware/thermal/BnThermal.h>
 #include <aidl/android/hardware/thermal/BnThermalChangedCallback.h>
 #include <android-base/logging.h>
@@ -59,6 +60,15 @@
         .throttlingStatus = ThrottlingSeverity::CRITICAL,
 };
 
+static const CoolingDevice kCoolingDevice = {
+        .type = CoolingType::CPU,
+        .name = "test cooling device",
+        .value = 1,
+        .powerLimitMw = 300,
+        .powerMw = 500,
+        .timeWindowMs = 7000,
+};
+
 // Callback class for receiving thermal event notifications from main class
 class ThermalCallback : public BnThermalChangedCallback {
   public:
@@ -85,6 +95,33 @@
     bool mInvoke = false;
 };
 
+// Callback class for receiving cooling device event notifications from main class
+class CoolingDeviceCallback : public BnCoolingDeviceChangedCallback {
+  public:
+    ndk::ScopedAStatus notifyCoolingDeviceChanged(const CoolingDevice&) override {
+        {
+            std::lock_guard<std::mutex> lock(mMutex);
+            mInvoke = true;
+        }
+        mNotifyCoolingDeviceChanged.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 = mNotifyCoolingDeviceChanged.wait_for(lock, duration,
+                                                      [this] { return this->mInvoke; });
+        mInvoke = false;
+        return r;
+    }
+
+  private:
+    std::mutex mMutex;
+    std::condition_variable mNotifyCoolingDeviceChanged;
+    bool mInvoke = false;
+};
+
 // The main test class for THERMAL HIDL HAL.
 class ThermalAidlTest : public testing::TestWithParam<std::string> {
   public:
@@ -97,19 +134,42 @@
         ASSERT_NE(mThermalCallback, nullptr);
         ::ndk::ScopedAStatus status = mThermal->registerThermalChangedCallback(mThermalCallback);
         ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+        auto ret = mThermal->getInterfaceVersion(&thermal_version);
+        ASSERT_TRUE(ret.isOk()) << ret;
+        if (thermal_version > 1) {
+            mCoolingDeviceCallback = ndk::SharedRefBase::make<CoolingDeviceCallback>();
+            ASSERT_NE(mCoolingDeviceCallback, nullptr);
+            status = mThermal->registerCoolingDeviceChangedCallbackWithType(mCoolingDeviceCallback,
+                                                                            kCoolingDevice.type);
+            ASSERT_TRUE(status.isOk()) << status.getMessage();
+        }
     }
 
     void TearDown() override {
         ::ndk::ScopedAStatus status = mThermal->unregisterThermalChangedCallback(mThermalCallback);
         ASSERT_TRUE(status.isOk()) << status.getMessage();
+
         // Expect to fail if unregister again
         status = mThermal->unregisterThermalChangedCallback(mThermalCallback);
         ASSERT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
+
+        auto ret = mThermal->getInterfaceVersion(&thermal_version);
+        ASSERT_TRUE(ret.isOk()) << ret;
+        if (thermal_version > 1) {
+            status = mThermal->unregisterCoolingDeviceChangedCallback(mCoolingDeviceCallback);
+            ASSERT_TRUE(status.isOk()) << status.getMessage();
+            status = mThermal->unregisterCoolingDeviceChangedCallback(mCoolingDeviceCallback);
+            ASSERT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
+        }
     }
+    // Stores thermal version
+    int32_t thermal_version;
 
   protected:
     std::shared_ptr<IThermal> mThermal;
     std::shared_ptr<ThermalCallback> mThermalCallback;
+    std::shared_ptr<CoolingDeviceCallback> mCoolingDeviceCallback;
 };
 
 // Test ThermalChangedCallback::notifyThrottling().
@@ -121,6 +181,21 @@
     ASSERT_TRUE(thermalCallback->waitForCallback(200ms));
 }
 
+// Test CoolingDeviceChangedCallback::notifyCoolingDeviceChanged().
+// This just calls into and back from our local CoolingDeviceChangedCallback impl.
+TEST_P(ThermalAidlTest, NotifyCoolingDeviceChangedTest) {
+    auto ret = mThermal->getInterfaceVersion(&thermal_version);
+    ASSERT_TRUE(ret.isOk()) << ret;
+    if (thermal_version < 2) {
+        return;
+    }
+    std::shared_ptr<CoolingDeviceCallback> cdevCallback =
+            ndk::SharedRefBase::make<CoolingDeviceCallback>();
+    ::ndk::ScopedAStatus status = cdevCallback->notifyCoolingDeviceChanged(kCoolingDevice);
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
+    ASSERT_TRUE(cdevCallback->waitForCallback(200ms));
+}
+
 // Test Thermal->registerThermalChangedCallback.
 TEST_P(ThermalAidlTest, RegisterThermalChangedCallbackTest) {
     // Expect to fail with same callback
@@ -128,7 +203,8 @@
     ASSERT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
     // Expect to fail with null callback
     status = mThermal->registerThermalChangedCallback(nullptr);
-    ASSERT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
+    ASSERT_TRUE(status.getExceptionCode() == EX_ILLEGAL_ARGUMENT
+        || status.getExceptionCode() == EX_NULL_POINTER);
     std::shared_ptr<ThermalCallback> localThermalCallback =
             ndk::SharedRefBase::make<ThermalCallback>();
     // Expect to succeed with different callback
@@ -139,7 +215,8 @@
     ASSERT_TRUE(status.isOk()) << status.getMessage();
     // Expect to fail with null callback
     status = mThermal->unregisterThermalChangedCallback(nullptr);
-    ASSERT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
+    ASSERT_TRUE(status.getExceptionCode() == EX_ILLEGAL_ARGUMENT
+        || status.getExceptionCode() == EX_NULL_POINTER);
 }
 
 // Test Thermal->registerThermalChangedCallbackWithType.
@@ -150,7 +227,8 @@
     ASSERT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
     // Expect to fail with null callback
     status = mThermal->registerThermalChangedCallbackWithType(nullptr, TemperatureType::SKIN);
-    ASSERT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
+    ASSERT_TRUE(status.getExceptionCode() == EX_ILLEGAL_ARGUMENT
+        || status.getExceptionCode() == EX_NULL_POINTER);
     std::shared_ptr<ThermalCallback> localThermalCallback =
             ndk::SharedRefBase::make<ThermalCallback>();
     // Expect to succeed with different callback
@@ -162,7 +240,39 @@
     ASSERT_TRUE(status.isOk()) << status.getMessage();
     // Expect to fail with null callback
     status = mThermal->unregisterThermalChangedCallback(nullptr);
+    ASSERT_TRUE(status.getExceptionCode() == EX_ILLEGAL_ARGUMENT
+        || status.getExceptionCode() == EX_NULL_POINTER);
+}
+
+// Test Thermal->registerCoolingDeviceChangedCallbackWithType.
+TEST_P(ThermalAidlTest, RegisterCoolingDeviceChangedCallbackWithTypeTest) {
+    auto ret = mThermal->getInterfaceVersion(&thermal_version);
+    ASSERT_TRUE(ret.isOk()) << ret;
+    if (thermal_version < 2) {
+        return;
+    }
+
+    // Expect to fail with same callback
+    ::ndk::ScopedAStatus status = mThermal->registerCoolingDeviceChangedCallbackWithType(
+            mCoolingDeviceCallback, CoolingType::CPU);
     ASSERT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
+    // Expect to fail with null callback
+    status = mThermal->registerCoolingDeviceChangedCallbackWithType(nullptr, CoolingType::CPU);
+    ASSERT_TRUE(status.getExceptionCode() == EX_ILLEGAL_ARGUMENT ||
+                status.getExceptionCode() == EX_NULL_POINTER);
+    std::shared_ptr<CoolingDeviceCallback> localCoolingDeviceCallback =
+            ndk::SharedRefBase::make<CoolingDeviceCallback>();
+    // Expect to succeed with different callback
+    status = mThermal->registerCoolingDeviceChangedCallbackWithType(localCoolingDeviceCallback,
+                                                                    CoolingType::CPU);
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
+    // Remove the local callback
+    status = mThermal->unregisterCoolingDeviceChangedCallback(localCoolingDeviceCallback);
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
+    // Expect to fail with null callback
+    status = mThermal->unregisterCoolingDeviceChangedCallback(nullptr);
+    ASSERT_TRUE(status.getExceptionCode() == EX_ILLEGAL_ARGUMENT ||
+                status.getExceptionCode() == EX_NULL_POINTER);
 }
 
 // Test Thermal->getCurrentTemperatures().
diff --git a/threadnetwork/aidl/Android.bp b/threadnetwork/aidl/Android.bp
new file mode 100644
index 0000000..7e674e0
--- /dev/null
+++ b/threadnetwork/aidl/Android.bp
@@ -0,0 +1,22 @@
+aidl_interface {
+    name: "android.hardware.threadnetwork",
+    vendor_available: true,
+    srcs: [
+        "android/hardware/threadnetwork/*.aidl",
+    ],
+
+    stability: "vintf",
+
+    backend: {
+        java: {
+            platform_apis: true,
+        },
+        ndk: {
+            apex_available: [
+                "//apex_available:platform",
+                "com.android.tethering",
+            ],
+            min_sdk_version: "30",
+        },
+    },
+}
diff --git a/threadnetwork/aidl/OWNERS b/threadnetwork/aidl/OWNERS
new file mode 100644
index 0000000..e3111c8
--- /dev/null
+++ b/threadnetwork/aidl/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 1288834
+zhanglongxia@google.com
+xyk@google.com
diff --git a/threadnetwork/aidl/aidl_api/android.hardware.threadnetwork/current/android/hardware/threadnetwork/IThreadChip.aidl b/threadnetwork/aidl/aidl_api/android.hardware.threadnetwork/current/android/hardware/threadnetwork/IThreadChip.aidl
new file mode 100644
index 0000000..607ceb3
--- /dev/null
+++ b/threadnetwork/aidl/aidl_api/android.hardware.threadnetwork/current/android/hardware/threadnetwork/IThreadChip.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.threadnetwork;
+@VintfStability
+interface IThreadChip {
+  void open(in android.hardware.threadnetwork.IThreadChipCallback callback);
+  void close();
+  void hardwareReset();
+  void sendSpinelFrame(in byte[] frame);
+  const int ERROR_FAILED = 1;
+  const int ERROR_NO_BUFS = 2;
+  const int ERROR_BUSY = 3;
+}
diff --git a/threadnetwork/aidl/aidl_api/android.hardware.threadnetwork/current/android/hardware/threadnetwork/IThreadChipCallback.aidl b/threadnetwork/aidl/aidl_api/android.hardware.threadnetwork/current/android/hardware/threadnetwork/IThreadChipCallback.aidl
new file mode 100644
index 0000000..e86b3ec
--- /dev/null
+++ b/threadnetwork/aidl/aidl_api/android.hardware.threadnetwork/current/android/hardware/threadnetwork/IThreadChipCallback.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.threadnetwork;
+@VintfStability
+interface IThreadChipCallback {
+  oneway void onReceiveSpinelFrame(in byte[] frame);
+}
diff --git a/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl b/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl
new file mode 100644
index 0000000..e695623
--- /dev/null
+++ b/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.threadnetwork;
+
+import android.hardware.threadnetwork.IThreadChipCallback;
+
+/**
+ * Controls a Thread radio chip on the device.
+ */
+
+@VintfStability
+interface IThreadChip {
+    /**
+     * The operation failed for the internal error.
+     */
+    const int ERROR_FAILED = 1;
+
+    /**
+     * Insufficient buffers available to send frames.
+     */
+    const int ERROR_NO_BUFS = 2;
+
+    /**
+     * Service is busy and could not service the operation.
+     */
+    const int ERROR_BUSY = 3;
+
+    /**
+     * This method initializes the Thread HAL instance. If open completes
+     * successfully, then the Thread HAL instance is ready to accept spinel
+     * messages through sendSpinelFrame() API.
+     *
+     * @param callback  A IThreadChipCallback callback instance.
+     *
+     * @throws EX_ILLEGAL_ARGUMENT  if the callback handle is invalid (for example, it is null).
+     *
+     * @throws ServiceSpecificException with one of the following values:
+     *     - ERROR_FAILED        The interface cannot be opened due to an internal error.
+     *     - ERROR_BUSY          This interface is in use.
+     */
+    void open(in IThreadChipCallback callback);
+
+    /**
+     * Close the Thread HAL instance. Must free all resources.
+     */
+    void close();
+
+    /**
+     * This method hardware resets the Thread radio chip via the physical reset pin.
+     * The callback registered by `open()` won’t be reset and the resource allocated
+     * by `open()` won’t be free.
+     *
+     * @throws EX_UNSUPPORTED_OPERATION  if the Thread radio chip doesn't support the hardware reset.
+     *
+     */
+    void hardwareReset();
+
+    /**
+     * This method sends a spinel frame to the Thread HAL.
+     *
+     * This method should block until the frame is sent out successfully or
+     * the method throws errors immediately.
+     *
+     * Spinel Protocol:
+     *     https://github.com/openthread/openthread/blob/main/src/lib/spinel/spinel.h
+     *
+     * @param frame  The spinel frame to be sent.
+     *
+     * @throws ServiceSpecificException with one of the following values:
+     *         - ERROR_FAILED The Thread HAL failed to send the frame for an internal reason.
+     *         - ERROR_NO_BUFS Insufficient buffer space to send the frame.
+     *         - ERROR_BUSY The Thread HAL is busy.
+     */
+    void sendSpinelFrame(in byte[] frame);
+}
diff --git a/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChipCallback.aidl b/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChipCallback.aidl
new file mode 100644
index 0000000..046edc3
--- /dev/null
+++ b/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChipCallback.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.threadnetwork;
+
+@VintfStability
+interface IThreadChipCallback {
+    /**
+     * This method is called when a spinel frame is received. Thread network
+     * will process the received spinel frame.
+     *
+     * Spinel Protocol:
+     *     https://github.com/openthread/openthread/blob/main/src/lib/spinel/spinel.h
+     *
+     * @param frame  The received spinel frame.
+     */
+    oneway void onReceiveSpinelFrame(in byte[] frame);
+}
diff --git a/threadnetwork/aidl/default/Android.bp b/threadnetwork/aidl/default/Android.bp
new file mode 100644
index 0000000..816f892
--- /dev/null
+++ b/threadnetwork/aidl/default/Android.bp
@@ -0,0 +1,110 @@
+//
+//  Copyright (c) 2022 Google LLC.
+//  All rights reserved.
+//
+//  This document is the property of Google LLC, Inc. It is
+//  considered proprietary and confidential information.
+//
+//  This document may not be reproduced or transmitted in any form,
+//  in whole or in part, without the express written permission of
+//  Google LLC.
+
+cc_binary {
+    name: "android.hardware.threadnetwork-service",
+    vendor: true,
+    relative_install_path: "hw",
+
+    shared_libs: [
+        "libbinder_ndk",
+        "liblog",
+    ],
+
+    static_libs: [
+        "android.hardware.threadnetwork-V1-ndk",
+        "libbase",
+        "libcutils",
+        "libutils",
+        "openthread-common",
+        "openthread-hdlc",
+        "openthread-platform",
+        "openthread-posix",
+        "openthread-spi",
+        "openthread-url",
+    ],
+
+    stl: "c++_static",
+
+    srcs: [
+        "main.cpp",
+        "service.cpp",
+        "thread_chip.cpp",
+        "utils.cpp",
+    ],
+}
+
+cc_fuzz {
+    name: "android.hardware.threadnetwork-service.fuzzer",
+
+    defaults: ["service_fuzzer_defaults"],
+    shared_libs: [
+        "libbinder_ndk",
+    ],
+
+    static_libs: [
+        "android.hardware.threadnetwork-V1-ndk",
+        "libbase",
+        "liblog",
+        "openthread-common",
+        "openthread-hdlc",
+        "openthread-platform",
+        "openthread-posix",
+        "openthread-spi",
+        "openthread-url",
+    ],
+
+    srcs: [
+        "thread_chip.cpp",
+        "utils.cpp",
+        "fuzzer.cpp",
+    ],
+
+    fuzz_config: {
+        cc: [
+            "zhanglongxia@google.com",
+        ],
+    },
+}
+
+prebuilt_etc {
+    name: "threadnetwork-default.xml",
+    src: "threadnetwork-default.xml",
+    sub_dir: "vintf",
+    installable: false,
+}
+
+prebuilt_etc {
+    name: "threadnetwork-service.rc",
+    src: "threadnetwork-service.rc",
+    installable: false,
+}
+
+apex {
+    name: "com.android.hardware.threadnetwork",
+    manifest: "manifest.json",
+    file_contexts: "file_contexts",
+    key: "com.android.hardware.key",
+    certificate: ":com.android.hardware.certificate",
+    updatable: false,
+    vendor: true,
+
+    binaries: [
+        "android.hardware.threadnetwork-service",
+        "ot-rcp",
+    ],
+
+    prebuilts: [
+        "threadnetwork-default.xml", // vintf_fragment
+        "threadnetwork-service.rc", // init_rc
+        "android.hardware.thread_network.prebuilt.xml", // permission
+    ],
+}
diff --git a/threadnetwork/aidl/default/file_contexts b/threadnetwork/aidl/default/file_contexts
new file mode 100644
index 0000000..39ba3b5
--- /dev/null
+++ b/threadnetwork/aidl/default/file_contexts
@@ -0,0 +1,4 @@
+(/.*)?                                                      u:object_r:vendor_file:s0
+/etc(/.*)?                                                  u:object_r:vendor_configs_file:s0
+/bin/hw/android\.hardware\.threadnetwork-service            u:object_r:hal_threadnetwork_default_exec:s0
+/bin/ot-rcp                                                 u:object_r:ot_rcp_exec:s0
diff --git a/threadnetwork/aidl/default/fuzzer.cpp b/threadnetwork/aidl/default/fuzzer.cpp
new file mode 100644
index 0000000..fb6e548
--- /dev/null
+++ b/threadnetwork/aidl/default/fuzzer.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fuzzbinder/libbinder_ndk_driver.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include "thread_chip.hpp"
+
+using aidl::android::hardware::threadnetwork::ThreadChip;
+using android::fuzzService;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    char url[] = "spinel+hdlc+null:///dev/null";
+    auto service = ndk::SharedRefBase::make<ThreadChip>(url);
+
+    fuzzService(service->asBinder().get(), FuzzedDataProvider(data, size));
+
+    return 0;
+}
+
diff --git a/threadnetwork/aidl/default/main.cpp b/threadnetwork/aidl/default/main.cpp
new file mode 100644
index 0000000..8419041
--- /dev/null
+++ b/threadnetwork/aidl/default/main.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/android/hardware/threadnetwork/IThreadChip.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <utils/Log.h>
+
+#include "service.hpp"
+#include "thread_chip.hpp"
+
+using aidl::android::hardware::threadnetwork::IThreadChip;
+using aidl::android::hardware::threadnetwork::ThreadChip;
+
+int main(int argc, char* argv[]) {
+    CHECK_GT(argc, 1);
+    std::vector<std::shared_ptr<ThreadChip>> threadChips;
+    aidl::android::hardware::threadnetwork::Service service;
+
+    for (int id = 0; id < argc - 1; id++) {
+        binder_status_t status;
+        const std::string serviceName(std::string() + IThreadChip::descriptor + "/chip" +
+                                      std::to_string(id));
+        auto threadChip = ndk::SharedRefBase::make<ThreadChip>(argv[id + 1]);
+
+        CHECK_NE(threadChip, nullptr);
+
+        status = AServiceManager_addService(threadChip->asBinder().get(), serviceName.c_str());
+        CHECK_EQ(status, STATUS_OK);
+
+        ALOGI("ServiceName: %s, Url: %s", serviceName.c_str(), argv[id + 1]);
+        threadChips.push_back(std::move(threadChip));
+    }
+
+    ALOGI("Thread Network HAL is running");
+
+    service.startLoop();
+    return EXIT_FAILURE;  // should not reach
+}
diff --git a/threadnetwork/aidl/default/manifest.json b/threadnetwork/aidl/default/manifest.json
new file mode 100644
index 0000000..61e6dc1
--- /dev/null
+++ b/threadnetwork/aidl/default/manifest.json
@@ -0,0 +1,4 @@
+{
+    "name": "com.android.hardware.threadnetwork",
+    "version": 1
+}
diff --git a/threadnetwork/aidl/default/service.cpp b/threadnetwork/aidl/default/service.cpp
new file mode 100644
index 0000000..7f583f4
--- /dev/null
+++ b/threadnetwork/aidl/default/service.cpp
@@ -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.
+ */
+#include "service.hpp"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <utils/Log.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace threadnetwork {
+
+Service::Service(void) : mBinderFd(-1) {
+    binder_status_t status = ABinderProcess_setupPolling(&mBinderFd);
+    CHECK_EQ(status, ::STATUS_OK);
+    CHECK_GE(mBinderFd, 0);
+}
+
+void Service::Update(otSysMainloopContext& context) {
+    FD_SET(mBinderFd, &context.mReadFdSet);
+    context.mMaxFd = std::max(context.mMaxFd, mBinderFd);
+}
+
+void Service::Process(const otSysMainloopContext& context) {
+    if (FD_ISSET(mBinderFd, &context.mReadFdSet)) {
+        ABinderProcess_handlePolledCommands();
+    }
+}
+
+void Service::startLoop(void) {
+    const struct timeval kPollTimeout = {1, 0};
+    otSysMainloopContext context;
+    int rval;
+
+    ot::Posix::Mainloop::Manager::Get().Add(*this);
+
+    while (true) {
+        context.mMaxFd = -1;
+        context.mTimeout = kPollTimeout;
+
+        FD_ZERO(&context.mReadFdSet);
+        FD_ZERO(&context.mWriteFdSet);
+        FD_ZERO(&context.mErrorFdSet);
+
+        ot::Posix::Mainloop::Manager::Get().Update(context);
+
+        rval = select(context.mMaxFd + 1, &context.mReadFdSet, &context.mWriteFdSet,
+                      &context.mErrorFdSet, &context.mTimeout);
+
+        if (rval >= 0) {
+            ot::Posix::Mainloop::Manager::Get().Process(context);
+        } else if (errno != EINTR) {
+            ALOGE("select() failed: %s", strerror(errno));
+            break;
+        }
+    }
+}
+}  // namespace threadnetwork
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/threadnetwork/aidl/default/service.hpp b/threadnetwork/aidl/default/service.hpp
new file mode 100644
index 0000000..6a94791
--- /dev/null
+++ b/threadnetwork/aidl/default/service.hpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mainloop.hpp"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace threadnetwork {
+
+class Service : public ot::Posix::Mainloop::Source {
+  public:
+    Service(void);
+
+    void Update(otSysMainloopContext& context) override;
+    void Process(const otSysMainloopContext& context) override;
+    void startLoop(void);
+
+  private:
+    int mBinderFd;
+};
+}  // namespace threadnetwork
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/threadnetwork/aidl/default/thread_chip.cpp b/threadnetwork/aidl/default/thread_chip.cpp
new file mode 100644
index 0000000..ed34e63
--- /dev/null
+++ b/threadnetwork/aidl/default/thread_chip.cpp
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "thread_chip.hpp"
+
+#include <android-base/logging.h>
+#include <android/binder_auto_utils.h>
+#include <android/binder_ibinder.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <utils/Log.h>
+
+#include "hdlc_interface.hpp"
+#include "spi_interface.hpp"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace threadnetwork {
+
+ThreadChip::ThreadChip(char* url) : mUrl(), mRxFrameBuffer(), mCallback(nullptr) {
+    const char* interfaceName;
+
+    CHECK_EQ(mUrl.Init(url), 0);
+
+    interfaceName = mUrl.GetProtocol();
+    CHECK_NE(interfaceName, nullptr);
+
+    if (ot::Posix::SpiInterface::IsInterfaceNameMatch(interfaceName)) {
+        mSpinelInterface = std::make_shared<ot::Posix::SpiInterface>(mUrl);
+    } else if (ot::Posix::HdlcInterface::IsInterfaceNameMatch(interfaceName)) {
+        mSpinelInterface = std::make_shared<ot::Posix::HdlcInterface>(mUrl);
+    } else {
+        ALOGE("The interface \"%s\" is not supported", interfaceName);
+        exit(EXIT_FAILURE);
+    }
+
+    CHECK_NE(mSpinelInterface, nullptr);
+
+    mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(
+            AIBinder_DeathRecipient_new(ThreadChip::onBinderDiedJump));
+    AIBinder_DeathRecipient_setOnUnlinked(mDeathRecipient.get(), ThreadChip::onBinderUnlinkedJump);
+}
+
+void ThreadChip::onBinderDiedJump(void* context) {
+    reinterpret_cast<ThreadChip*>(context)->onBinderDied();
+}
+
+void ThreadChip::onBinderDied(void) {
+    ALOGW("Thread Network HAL client is dead");
+}
+
+void ThreadChip::onBinderUnlinkedJump(void* context) {
+    reinterpret_cast<ThreadChip*>(context)->onBinderUnlinked();
+}
+
+void ThreadChip::onBinderUnlinked(void) {
+    ALOGW("ThreadChip binder is unlinked");
+    deinitChip();
+}
+
+void ThreadChip::handleReceivedFrameJump(void* context) {
+    static_cast<ThreadChip*>(context)->handleReceivedFrame();
+}
+
+void ThreadChip::handleReceivedFrame(void) {
+    if (mCallback != nullptr) {
+        mCallback->onReceiveSpinelFrame(std::vector<uint8_t>(
+                mRxFrameBuffer.GetFrame(), mRxFrameBuffer.GetFrame() + mRxFrameBuffer.GetLength()));
+    }
+
+    mRxFrameBuffer.DiscardFrame();
+}
+
+ndk::ScopedAStatus ThreadChip::open(const std::shared_ptr<IThreadChipCallback>& in_callback) {
+    ndk::ScopedAStatus status = initChip(in_callback);
+
+    if (status.isOk()) {
+        AIBinder_linkToDeath(in_callback->asBinder().get(), mDeathRecipient.get(), this);
+        ALOGI("Open IThreadChip successfully");
+    } else {
+        ALOGW("Failed to open IThreadChip: %s", status.getDescription().c_str());
+    }
+
+    return status;
+}
+
+ndk::ScopedAStatus ThreadChip::initChip(const std::shared_ptr<IThreadChipCallback>& in_callback) {
+    if (in_callback == nullptr) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    } else if (mCallback == nullptr) {
+        if (mSpinelInterface->Init(handleReceivedFrameJump, this, mRxFrameBuffer) !=
+            OT_ERROR_NONE) {
+            return errorStatus(ERROR_FAILED, "Failed to initialize the interface");
+        }
+
+        mCallback = in_callback;
+        ot::Posix::Mainloop::Manager::Get().Add(*this);
+        return ndk::ScopedAStatus::ok();
+    } else {
+        return errorStatus(ERROR_BUSY, "Interface has been opened");
+    }
+}
+
+ndk::ScopedAStatus ThreadChip::close() {
+    ndk::ScopedAStatus status;
+    std::shared_ptr<IThreadChipCallback> callback = mCallback;
+
+    status = deinitChip();
+    if (status.isOk()) {
+        if (callback != nullptr) {
+            AIBinder_unlinkToDeath(callback->asBinder().get(), mDeathRecipient.get(), this);
+        }
+
+        ALOGI("Close IThreadChip successfully");
+    } else {
+        ALOGW("Failed to close IThreadChip: %s", status.getDescription().c_str());
+    }
+
+    return status;
+}
+
+ndk::ScopedAStatus ThreadChip::deinitChip() {
+    if (mCallback != nullptr) {
+        mSpinelInterface->Deinit();
+        ot::Posix::Mainloop::Manager::Get().Remove(*this);
+        mCallback = nullptr;
+        return ndk::ScopedAStatus::ok();
+    }
+
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+}
+
+ndk::ScopedAStatus ThreadChip::sendSpinelFrame(const std::vector<uint8_t>& in_frame) {
+    ndk::ScopedAStatus status;
+    otError error;
+
+    if (mCallback == nullptr) {
+        status = errorStatus(ERROR_FAILED, "The interface is not open");
+    } else {
+        error = mSpinelInterface->SendFrame(reinterpret_cast<const uint8_t*>(in_frame.data()),
+                                            in_frame.size());
+        if (error == OT_ERROR_NONE) {
+            status = ndk::ScopedAStatus::ok();
+        } else if (error == OT_ERROR_NO_BUFS) {
+            status = errorStatus(ERROR_NO_BUFS, "Insufficient buffer space to send");
+        } else if (error == OT_ERROR_BUSY) {
+            status = errorStatus(ERROR_BUSY, "The interface is busy");
+        } else {
+            status = errorStatus(ERROR_FAILED, "Failed to send the spinel frame");
+        }
+    }
+
+    if (!status.isOk()) {
+        ALOGW("Send spinel frame failed, error: %s", status.getDescription().c_str());
+    }
+
+    return status;
+}
+
+ndk::ScopedAStatus ThreadChip::hardwareReset() {
+    if (mSpinelInterface->HardwareReset() == OT_ERROR_NOT_IMPLEMENTED) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    }
+
+    ALOGI("reset()");
+    return ndk::ScopedAStatus::ok();
+}
+
+void ThreadChip::Update(otSysMainloopContext& context) {
+    if (mCallback != nullptr) {
+        mSpinelInterface->UpdateFdSet(&context);
+    }
+}
+
+void ThreadChip::Process(const otSysMainloopContext& context) {
+    if (mCallback != nullptr) {
+        mSpinelInterface->Process(&context);
+    }
+}
+
+ndk::ScopedAStatus ThreadChip::errorStatus(int32_t error, const char* message) {
+    return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(error, message));
+}
+}  // namespace threadnetwork
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/threadnetwork/aidl/default/thread_chip.hpp b/threadnetwork/aidl/default/thread_chip.hpp
new file mode 100644
index 0000000..30046ef
--- /dev/null
+++ b/threadnetwork/aidl/default/thread_chip.hpp
@@ -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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/threadnetwork/BnThreadChip.h>
+#include <aidl/android/hardware/threadnetwork/IThreadChipCallback.h>
+
+#include "lib/spinel/spinel_interface.hpp"
+#include "lib/url/url.hpp"
+#include "mainloop.hpp"
+
+#include <android/binder_auto_utils.h>
+#include <android/binder_ibinder.h>
+#include <utils/Mutex.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace threadnetwork {
+
+class ThreadChip : public BnThreadChip, ot::Posix::Mainloop::Source {
+  public:
+    ThreadChip(char* url);
+    ~ThreadChip() {}
+
+    ndk::ScopedAStatus open(const std::shared_ptr<IThreadChipCallback>& in_callback) override;
+    ndk::ScopedAStatus close() override;
+    ndk::ScopedAStatus sendSpinelFrame(const std::vector<uint8_t>& in_frame) override;
+    ndk::ScopedAStatus hardwareReset() override;
+    void Update(otSysMainloopContext& context) override;
+    void Process(const otSysMainloopContext& context) override;
+
+  private:
+    static void onBinderDiedJump(void* context);
+    void onBinderDied(void);
+    static void onBinderUnlinkedJump(void* context);
+    void onBinderUnlinked(void);
+    static void handleReceivedFrameJump(void* context);
+    void handleReceivedFrame(void);
+    ndk::ScopedAStatus errorStatus(int32_t error, const char* message);
+    ndk::ScopedAStatus initChip(const std::shared_ptr<IThreadChipCallback>& in_callback);
+    ndk::ScopedAStatus deinitChip();
+
+    ot::Url::Url mUrl;
+    std::shared_ptr<ot::Spinel::SpinelInterface> mSpinelInterface;
+    ot::Spinel::SpinelInterface::RxFrameBuffer mRxFrameBuffer;
+    std::shared_ptr<IThreadChipCallback> mCallback;
+    ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
+};
+
+}  // namespace threadnetwork
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/threadnetwork/aidl/default/threadnetwork-default.xml b/threadnetwork/aidl/default/threadnetwork-default.xml
new file mode 100644
index 0000000..d7dee1e
--- /dev/null
+++ b/threadnetwork/aidl/default/threadnetwork-default.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.threadnetwork</name>
+        <fqname>IThreadChip/chip0</fqname>
+    </hal>
+</manifest>
diff --git a/threadnetwork/aidl/default/threadnetwork-service.rc b/threadnetwork/aidl/default/threadnetwork-service.rc
new file mode 100644
index 0000000..3b889eb
--- /dev/null
+++ b/threadnetwork/aidl/default/threadnetwork-service.rc
@@ -0,0 +1,3 @@
+service vendor.threadnetwork_hal /apex/com.android.hardware.threadnetwork/bin/hw/android.hardware.threadnetwork-service spinel+hdlc+forkpty:///apex/com.android.hardware.threadnetwork/bin/ot-rcp?forkpty-arg=1
+    class hal
+    user thread_network
diff --git a/threadnetwork/aidl/default/utils.cpp b/threadnetwork/aidl/default/utils.cpp
new file mode 100644
index 0000000..1cb42ec
--- /dev/null
+++ b/threadnetwork/aidl/default/utils.cpp
@@ -0,0 +1,80 @@
+
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <openthread/instance.h>
+#include <openthread/logging.h>
+#include <openthread/platform/alarm-milli.h>
+#include <utils/Log.h>
+
+void otLogCritPlat(const char* format, ...) {
+    va_list args;
+
+    va_start(args, format);
+    __android_log_vprint(ANDROID_LOG_FATAL, LOG_TAG, format, args);
+    va_end(args);
+}
+
+void otLogWarnPlat(const char* format, ...) {
+    va_list args;
+
+    va_start(args, format);
+    __android_log_vprint(ANDROID_LOG_WARN, LOG_TAG, format, args);
+    va_end(args);
+}
+
+void otLogNotePlat(const char* format, ...) {
+    va_list args;
+
+    va_start(args, format);
+    __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, format, args);
+    va_end(args);
+}
+
+void otLogInfoPlat(const char* format, ...) {
+    va_list args;
+
+    va_start(args, format);
+    __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, format, args);
+    va_end(args);
+}
+
+void otLogDebgPlat(const char* format, ...) {
+    va_list args;
+
+    va_start(args, format);
+    __android_log_vprint(ANDROID_LOG_DEBUG, LOG_TAG, format, args);
+    va_end(args);
+}
+
+void otDumpDebgPlat(const char* aText, const void* aData, uint16_t aDataLength) {
+    constexpr uint16_t kBufSize = 512;
+    char buf[kBufSize];
+
+    if ((aText != nullptr) && (aData != nullptr)) {
+        const uint8_t* data = reinterpret_cast<const uint8_t*>(aData);
+
+        for (uint16_t i = 0; (i < aDataLength) && (i < (kBufSize - 1) / 3); i++) {
+            snprintf(buf + (i * 3), (kBufSize - 1) - (i * 3), "%02x ", data[i]);
+        }
+
+        __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, "%s: %s", aText, buf);
+    }
+}
+
+OT_TOOL_WEAK void otPlatAlarmMilliFired(otInstance* aInstance) {
+    OT_UNUSED_VARIABLE(aInstance);
+}
diff --git a/threadnetwork/aidl/vts/Android.bp b/threadnetwork/aidl/vts/Android.bp
new file mode 100644
index 0000000..864e885
--- /dev/null
+++ b/threadnetwork/aidl/vts/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.
+//
+
+cc_test {
+    name: "VtsHalThreadNetworkTargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: [
+        "VtsHalThreadNetworkTargetTest.cpp",
+    ],
+
+    shared_libs: [
+        "libbinder",
+        "libbinder_ndk",
+    ],
+    static_libs: [
+        "android.hardware.threadnetwork-V1-ndk",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
diff --git a/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp b/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp
new file mode 100644
index 0000000..2f71b2f
--- /dev/null
+++ b/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ThreadNetworkHalTargetTest"
+
+#include <future>
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <android-base/logging.h>
+#include <android/binder_auto_utils.h>
+#include <android/binder_manager.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <log/log.h>
+
+#include <aidl/android/hardware/threadnetwork/BnThreadChipCallback.h>
+#include <aidl/android/hardware/threadnetwork/IThreadChip.h>
+
+using aidl::android::hardware::threadnetwork::BnThreadChipCallback;
+using aidl::android::hardware::threadnetwork::IThreadChip;
+using android::ProcessState;
+using ndk::ScopedAStatus;
+using ndk::SpAIBinder;
+
+namespace {
+constexpr static int kCallbackTimeoutMs = 5000;
+}  // namespace
+
+class ThreadChipCallback : public BnThreadChipCallback {
+  public:
+    ThreadChipCallback(const std::function<void(const std::vector<uint8_t>&)>& on_spinel_message_cb)
+        : on_spinel_message_cb_(on_spinel_message_cb) {}
+
+    ScopedAStatus onReceiveSpinelFrame(const std::vector<uint8_t>& in_aFrame) {
+        on_spinel_message_cb_(in_aFrame);
+        return ScopedAStatus::ok();
+    }
+
+  private:
+    std::function<void(const std::vector<uint8_t>&)> on_spinel_message_cb_;
+};
+
+class ThreadNetworkAidl : public testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        std::string serviceName = GetParam();
+
+        ALOGI("serviceName: %s", serviceName.c_str());
+
+        thread_chip = IThreadChip::fromBinder(
+                SpAIBinder(AServiceManager_waitForService(serviceName.c_str())));
+        ASSERT_NE(thread_chip, nullptr);
+    }
+
+    virtual void TearDown() override { thread_chip->close(); }
+
+    std::shared_ptr<IThreadChip> thread_chip;
+};
+
+TEST_P(ThreadNetworkAidl, Open) {
+    std::shared_ptr<ThreadChipCallback> callback =
+            ndk::SharedRefBase::make<ThreadChipCallback>([](auto /* data */) {});
+
+    EXPECT_TRUE(thread_chip->open(callback).isOk());
+}
+
+TEST_P(ThreadNetworkAidl, Close) {
+    std::shared_ptr<ThreadChipCallback> callback =
+            ndk::SharedRefBase::make<ThreadChipCallback>([](auto /* data */) {});
+
+    EXPECT_TRUE(thread_chip->open(callback).isOk());
+    EXPECT_TRUE(thread_chip->close().isOk());
+}
+
+TEST_P(ThreadNetworkAidl, Reset) {
+    ndk::ScopedAStatus status;
+    std::shared_ptr<ThreadChipCallback> callback =
+            ndk::SharedRefBase::make<ThreadChipCallback>([](auto /* data */) {});
+
+    EXPECT_TRUE(thread_chip->open(callback).isOk());
+    status = thread_chip->hardwareReset();
+    EXPECT_TRUE(status.isOk() || (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION));
+    if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+        GTEST_SKIP() << "Hardware reset is not supported";
+    }
+}
+
+TEST_P(ThreadNetworkAidl, SendSpinelFrame) {
+    const uint8_t kCmdOffset = 2;
+    const uint8_t kMajorVersionOffset = 3;
+    const uint8_t kMinorVersionOffset = 4;
+    const std::vector<uint8_t> kGetSpinelProtocolVersion({0x81, 0x02, 0x01});
+    const std::vector<uint8_t> kGetSpinelProtocolVersionResponse({0x81, 0x06, 0x01, 0x04, 0x03});
+    uint8_t min_major_version = kGetSpinelProtocolVersionResponse[kMajorVersionOffset];
+    uint8_t min_minor_version = kGetSpinelProtocolVersionResponse[kMinorVersionOffset];
+    uint8_t major_version;
+    uint8_t minor_version;
+    std::promise<void> open_cb_promise;
+    std::future<void> open_cb_future{open_cb_promise.get_future()};
+    std::shared_ptr<ThreadChipCallback> callback;
+    std::vector<uint8_t> received_frame;
+    std::chrono::milliseconds timeout{kCallbackTimeoutMs};
+
+    callback = ndk::SharedRefBase::make<ThreadChipCallback>(
+            [&](const std::vector<uint8_t>& in_aFrame) {
+                if (in_aFrame.size() == kGetSpinelProtocolVersionResponse.size() &&
+                    in_aFrame[kCmdOffset] == kGetSpinelProtocolVersionResponse[kCmdOffset]) {
+                    major_version = in_aFrame[kMajorVersionOffset];
+                    minor_version = in_aFrame[kMinorVersionOffset];
+                    open_cb_promise.set_value();
+                }
+            });
+
+    ASSERT_NE(callback, nullptr);
+
+    EXPECT_TRUE(thread_chip->open(callback).isOk());
+
+    EXPECT_TRUE(thread_chip->sendSpinelFrame(kGetSpinelProtocolVersion).isOk());
+    EXPECT_EQ(open_cb_future.wait_for(timeout), std::future_status::ready);
+
+    EXPECT_GE(major_version, min_major_version);
+    if (major_version == min_major_version) {
+        EXPECT_GE(minor_version, min_minor_version);
+    }
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ThreadNetworkAidl);
+INSTANTIATE_TEST_SUITE_P(
+        Thread, ThreadNetworkAidl,
+        testing::ValuesIn(android::getAidlHalInstanceNames(IThreadChip::descriptor)),
+        android::PrintInstanceNameToString);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ProcessState::self()->setThreadPoolMaxThreadCount(1);
+    ProcessState::self()->startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/tv/OWNERS b/tv/OWNERS
new file mode 100644
index 0000000..e051b28
--- /dev/null
+++ b/tv/OWNERS
@@ -0,0 +1,13 @@
+# TV tuner
+# Bug component: 136752
+# TV input
+# Bug component: 826094
+
+include platform/frameworks/base:/core/java/android/hardware/hdmi/OWNERS
+
+hgchen@google.com
+quxiangfang@google.com
+shubang@google.com
+yixiaoluo@google.com
+qingxun@google.com
+
diff --git a/tv/cec/1.0/default/OWNERS b/tv/cec/1.0/default/OWNERS
deleted file mode 100644
index c1d3f1d..0000000
--- a/tv/cec/1.0/default/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-include platform/frameworks/base:/core/java/android/hardware/hdmi/OWNERS
diff --git a/tv/cec/OWNERS b/tv/cec/OWNERS
deleted file mode 100644
index 71e74c0..0000000
--- a/tv/cec/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 826094
-include platform/frameworks/base:/core/java/android/hardware/hdmi/OWNERS
diff --git a/tv/hdmi/OWNERS b/tv/hdmi/OWNERS
deleted file mode 100644
index d9c6783..0000000
--- a/tv/hdmi/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 826094
-include platform/frameworks/base:/core/java/android/hardware/hdmi/OWNERS
\ No newline at end of file
diff --git a/tv/hdmi/cec/aidl/default/HdmiCecMock.cpp b/tv/hdmi/cec/aidl/default/HdmiCecMock.cpp
index 0212e7e..8a3c6f0 100644
--- a/tv/hdmi/cec/aidl/default/HdmiCecMock.cpp
+++ b/tv/hdmi/cec/aidl/default/HdmiCecMock.cpp
@@ -36,6 +36,7 @@
     ALOGE("HdmiCecMock died");
     auto hdmiCecMock = static_cast<HdmiCecMock*>(cookie);
     hdmiCecMock->mCecThreadRun = false;
+    pthread_join(hdmiCecMock->mThreadId, NULL);
 }
 
 ScopedAStatus HdmiCecMock::addLogicalAddress(CecLogicalAddress addr, Result* _aidl_return) {
@@ -89,7 +90,9 @@
     mCallback = callback;
 
     if (callback != nullptr) {
-        AIBinder_linkToDeath(this->asBinder().get(), mDeathRecipient.get(), 0 /* cookie */);
+        mDeathRecipient =
+                ndk::ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient_new(serviceDied));
+        AIBinder_linkToDeath(callback->asBinder().get(), mDeathRecipient.get(), this /* cookie */);
 
         mInputFile = open(CEC_MSG_IN_FIFO, O_RDWR | O_CLOEXEC);
         mOutputFile = open(CEC_MSG_OUT_FIFO, O_RDWR | O_CLOEXEC);
@@ -220,7 +223,7 @@
     int r = -1;
 
     // Open the input pipe
-    while (mInputFile < 0) {
+    while (mCecThreadRun && mInputFile < 0) {
         usleep(1000 * 1000);
         mInputFile = open(CEC_MSG_IN_FIFO, O_RDONLY | O_CLOEXEC);
     }
@@ -257,7 +260,15 @@
 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));
+    mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(nullptr);
+}
+
+HdmiCecMock::~HdmiCecMock() {
+    ALOGE("[halimp_aidl] HdmiCecMock shutting down.");
+    mCallback = nullptr;
+    mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(nullptr);
+    mCecThreadRun = false;
+    pthread_join(mThreadId, NULL);
 }
 
 }  // namespace implementation
diff --git a/tv/hdmi/cec/aidl/default/HdmiCecMock.h b/tv/hdmi/cec/aidl/default/HdmiCecMock.h
index aca0581..e78b1cf 100644
--- a/tv/hdmi/cec/aidl/default/HdmiCecMock.h
+++ b/tv/hdmi/cec/aidl/default/HdmiCecMock.h
@@ -40,6 +40,7 @@
 
 struct HdmiCecMock : public BnHdmiCec {
     HdmiCecMock();
+    ~HdmiCecMock();
     ::ndk::ScopedAStatus addLogicalAddress(CecLogicalAddress addr, Result* _aidl_return) override;
     ::ndk::ScopedAStatus clearLogicalAddress() override;
     ::ndk::ScopedAStatus enableAudioReturnChannel(int32_t portId, bool enable) override;
diff --git a/tv/hdmi/connection/aidl/default/HdmiConnectionMock.cpp b/tv/hdmi/connection/aidl/default/HdmiConnectionMock.cpp
index 8f4411b..954982e 100644
--- a/tv/hdmi/connection/aidl/default/HdmiConnectionMock.cpp
+++ b/tv/hdmi/connection/aidl/default/HdmiConnectionMock.cpp
@@ -15,12 +15,11 @@
  */
 
 #define LOG_TAG "android.hardware.tv.hdmi.connection"
+#include "HdmiConnectionMock.h"
 #include <android-base/logging.h>
 #include <fcntl.h>
 #include <utils/Log.h>
 
-#include "HdmiConnectionMock.h"
-
 using ndk::ScopedAStatus;
 
 namespace android {
@@ -34,6 +33,7 @@
     ALOGE("HdmiConnectionMock died");
     auto hdmi = static_cast<HdmiConnectionMock*>(cookie);
     hdmi->mHdmiThreadRun = false;
+    pthread_join(hdmi->mThreadId, NULL);
 }
 
 ScopedAStatus HdmiConnectionMock::getPortInfo(std::vector<HdmiPortInfo>* _aidl_return) {
@@ -55,12 +55,15 @@
 ScopedAStatus HdmiConnectionMock::setCallback(
         const std::shared_ptr<IHdmiConnectionCallback>& callback) {
     if (mCallback != nullptr) {
+        stopThread();
         mCallback = nullptr;
     }
-
     if (callback != nullptr) {
         mCallback = callback;
-        AIBinder_linkToDeath(this->asBinder().get(), mDeathRecipient.get(), 0 /* cookie */);
+        mDeathRecipient =
+                ndk::ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient_new(serviceDied));
+
+        AIBinder_linkToDeath(callback->asBinder().get(), mDeathRecipient.get(), this /* cookie */);
 
         mInputFile = open(HDMI_MSG_IN_FIFO, O_RDWR | O_CLOEXEC);
         pthread_create(&mThreadId, NULL, __threadLoop, this);
@@ -153,7 +156,7 @@
     int r = -1;
 
     // Open the input pipe
-    while (mInputFile < 0) {
+    while (mHdmiThreadRun && mInputFile < 0) {
         usleep(1000 * 1000);
         mInputFile = open(HDMI_MSG_IN_FIFO, O_RDONLY | O_CLOEXEC);
     }
@@ -193,7 +196,21 @@
                      .physicalAddress = mPhysicalAddress};
     mPortConnectionStatus[0] = false;
     mHpdSignal[0] = HpdSignal::HDMI_HPD_PHYSICAL;
-    mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient_new(serviceDied));
+    mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(nullptr);
+}
+
+void HdmiConnectionMock::stopThread() {
+    if (mCallback != nullptr) {
+        ALOGE("[halimp_aidl] HdmiConnectionMock shutting down.");
+        mCallback = nullptr;
+        mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(nullptr);
+        mHdmiThreadRun = false;
+        pthread_join(mThreadId, NULL);
+    }
+}
+
+HdmiConnectionMock::~HdmiConnectionMock() {
+    stopThread();
 }
 
 }  // namespace implementation
diff --git a/tv/hdmi/connection/aidl/default/HdmiConnectionMock.h b/tv/hdmi/connection/aidl/default/HdmiConnectionMock.h
index c013fdd..8c66f08 100644
--- a/tv/hdmi/connection/aidl/default/HdmiConnectionMock.h
+++ b/tv/hdmi/connection/aidl/default/HdmiConnectionMock.h
@@ -41,7 +41,7 @@
 
 struct HdmiConnectionMock : public BnHdmiConnection {
     HdmiConnectionMock();
-
+    ~HdmiConnectionMock();
     ::ndk::ScopedAStatus getPortInfo(std::vector<HdmiPortInfo>* _aidl_return) override;
     ::ndk::ScopedAStatus isConnected(int32_t portId, bool* _aidl_return) override;
     ::ndk::ScopedAStatus setCallback(
@@ -56,6 +56,7 @@
     void threadLoop();
     int readMessageFromFifo(unsigned char* buf, int msgCount);
     void handleHotplugMessage(unsigned char* msgBuf);
+    void stopThread();
 
   private:
     static void serviceDied(void* cookie);
diff --git a/tv/input/OWNERS b/tv/input/OWNERS
index ae65f67..1252e4e 100644
--- a/tv/input/OWNERS
+++ b/tv/input/OWNERS
@@ -1,5 +1 @@
-# Bug component: 105688
-hgchen@google.com
-shubang@google.com
-quxiangfang@google.com
-yixiaoluo@google.com
+# Bug component: 826094
diff --git a/tv/input/aidl/Android.bp b/tv/input/aidl/Android.bp
index 35f510a..cd69130 100644
--- a/tv/input/aidl/Android.bp
+++ b/tv/input/aidl/Android.bp
@@ -35,6 +35,5 @@
             ],
         },
     ],
-    frozen: true,
-
+    frozen: false,
 }
diff --git a/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/TvMessageEvent.aidl b/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/TvMessageEvent.aidl
index 94fe665..3c1cb74 100644
--- a/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/TvMessageEvent.aidl
+++ b/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/TvMessageEvent.aidl
@@ -37,4 +37,5 @@
   android.hardware.tv.input.TvMessageEventType type;
   int streamId;
   android.hardware.tv.input.TvMessage[] messages;
+  int deviceId;
 }
diff --git a/tv/input/aidl/android/hardware/tv/input/ITvInputCallback.aidl b/tv/input/aidl/android/hardware/tv/input/ITvInputCallback.aidl
index a3afd41..4121fc7 100644
--- a/tv/input/aidl/android/hardware/tv/input/ITvInputCallback.aidl
+++ b/tv/input/aidl/android/hardware/tv/input/ITvInputCallback.aidl
@@ -32,17 +32,20 @@
      * Notifies the client that an TV message event has occurred. For possible event types,
      * check {@link android.hardware.tv.input.TvMessageEventType}.
      *
-     * The first message in a list of messages contained in a
+     * <p> For implementations of version 1, The first message in a list of messages contained in a
      * {@link android.hardware.tv.input.TvMessageEvent} should always have a
      * {@link android.hardware.tv.input.TvMessage#subType} of "device_id",
      * otherwise the event is discarded. When the subType of a message is "device_id", the ID of
      * the device that sent the message should be contained in
-     * {@link android.hardware.tv.input.TvMessage#groupId}
+     * {@link android.hardware.tv.input.TvMessage#groupId}.
      *
-     * Invoking this callback for the first time immediately triggers
+     * <p> For version 2 and beyond, the device ID should be contained in
+     * {@link android.hardware.tv.input.TvMessageEvent#deviceId}.
+     *
+     * <p> Invoking this callback for the first time immediately triggers
      * {@link android.hardware.tv.input.ITvInput#getTvMessageQueueDesc}. It is
-     * expected for the queue to be ready with
-     * the relevant messages for the event before this callback is called.
+     * expected for the queue to be ready with the relevant messages for the event before this
+     * callback is called.
      *
      * @param event Event passed to the client.
      */
diff --git a/tv/input/aidl/android/hardware/tv/input/TvMessageEvent.aidl b/tv/input/aidl/android/hardware/tv/input/TvMessageEvent.aidl
index 74a078a..e04a725 100644
--- a/tv/input/aidl/android/hardware/tv/input/TvMessageEvent.aidl
+++ b/tv/input/aidl/android/hardware/tv/input/TvMessageEvent.aidl
@@ -25,4 +25,5 @@
 
     int streamId;
     TvMessage[] messages;
+    int deviceId;
 }
diff --git a/tv/input/aidl/default/TvInput.cpp b/tv/input/aidl/default/TvInput.cpp
index 2ee8bcf..f6a64c4 100644
--- a/tv/input/aidl/default/TvInput.cpp
+++ b/tv/input/aidl/default/TvInput.cpp
@@ -43,6 +43,9 @@
                                       new TvStreamConfigWrapper(11, 360, 480, false))}};
     mStreamConfigs[3] = {{5, shared_ptr<TvStreamConfigWrapper>(
                                      new TvStreamConfigWrapper(5, 1080, 1920, false))}};
+
+    mQueue = shared_ptr<AidlMessageQueue<int8_t, SynchronizedReadWrite>>(
+            new (std::nothrow) AidlMessageQueue<int8_t, SynchronizedReadWrite>(8));
 }
 
 ::ndk::ScopedAStatus TvInput::setCallback(const shared_ptr<ITvInputCallback>& in_callback) {
@@ -74,7 +77,9 @@
         return ::ndk::ScopedAStatus::fromServiceSpecificError(STATUS_INVALID_ARGUMENTS);
     }
 
+    // When calling notifyTvMessage, make sure to verify against this map.
     mTvMessageEventEnabled[deviceId][streamId][in_type] = enabled;
+
     return ::ndk::ScopedAStatus::ok();
 }
 
@@ -82,11 +87,17 @@
         MQDescriptor<int8_t, SynchronizedReadWrite>* out_queue, int32_t in_deviceId,
         int32_t in_streamId) {
     ALOGV("%s", __FUNCTION__);
+    ::ndk::ScopedAStatus status = ::ndk::ScopedAStatus::ok();
     if (mStreamConfigs.count(in_deviceId) == 0) {
         ALOGW("Device with id %d isn't available", in_deviceId);
-        return ::ndk::ScopedAStatus::fromServiceSpecificError(STATUS_INVALID_ARGUMENTS);
+        status = ::ndk::ScopedAStatus::fromServiceSpecificError(STATUS_INVALID_ARGUMENTS);
+    } else if (!mQueue->isValid()) {
+        ALOGE("Tv Message Queue was not properly initialized");
+        status = ::ndk::ScopedAStatus::fromServiceSpecificError(STATUS_INVALID_STATE);
+    } else {
+        *out_queue = mQueue->dupeDesc();
     }
-    return ::ndk::ScopedAStatus::ok();
+    return status;
 }
 
 ::ndk::ScopedAStatus TvInput::getStreamConfigurations(int32_t in_deviceId,
diff --git a/tv/input/aidl/default/TvInput.h b/tv/input/aidl/default/TvInput.h
index 5776961..595f017 100644
--- a/tv/input/aidl/default/TvInput.h
+++ b/tv/input/aidl/default/TvInput.h
@@ -66,6 +66,7 @@
     map<int32_t, shared_ptr<TvInputDeviceInfoWrapper>> mDeviceInfos;
     map<int32_t, map<int32_t, shared_ptr<TvStreamConfigWrapper>>> mStreamConfigs;
     TvMessageEnabledMap mTvMessageEventEnabled;
+    shared_ptr<AidlMessageQueue<int8_t, SynchronizedReadWrite>> mQueue;
 };
 
 }  // namespace input
diff --git a/tv/input/aidl/vts/functional/Android.bp b/tv/input/aidl/vts/functional/Android.bp
index 22487ea..930c5a8 100644
--- a/tv/input/aidl/vts/functional/Android.bp
+++ b/tv/input/aidl/vts/functional/Android.bp
@@ -32,7 +32,7 @@
         "libvndksupport",
         "libfmq",
         "android.hardware.common.fmq-V1-ndk",
-        "android.hardware.tv.input-V1-ndk",
+        "android.hardware.tv.input-V2-ndk",
     ],
     require_root: true,
 }
diff --git a/tv/input/aidl/vts/functional/VtsHalTvInputTargetTest.cpp b/tv/input/aidl/vts/functional/VtsHalTvInputTargetTest.cpp
index 8d3395b..7e095f1 100644
--- a/tv/input/aidl/vts/functional/VtsHalTvInputTargetTest.cpp
+++ b/tv/input/aidl/vts/functional/VtsHalTvInputTargetTest.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "tv_input_aidl_hal_test"
+
 #include "VtsHalTvInputTargetTest.h"
 
 #include <android-base/properties.h>
@@ -181,7 +183,9 @@
             ALOGD("OpenAndCloseStreamTest: open stream, device_id=%d, stream_id=%d", device_id,
                   stream_id);
             ASSERT_TRUE(tv_input_->openStream(device_id, stream_id, &handle).isOk());
-            ASSERT_TRUE(isValidHandle(handle));
+            if (VERIFY_SIDEBAND_STREAM_HANDLE) {
+                ASSERT_TRUE(isValidHandle(handle));
+            }
 
             ALOGD("OpenAndCloseStreamTest: close stream, device_id=%d, stream_id=%d", device_id,
                   stream_id);
@@ -283,7 +287,9 @@
 
     ALOGD("OpenAnOpenedStreamsTest: open stream, device_id=%d, stream_id=%d", device_id, stream_id);
     ASSERT_TRUE(tv_input_->openStream(device_id, stream_id, &handle).isOk());
-    ASSERT_TRUE(isValidHandle(handle));
+    if (VERIFY_SIDEBAND_STREAM_HANDLE) {
+        ASSERT_TRUE(isValidHandle(handle));
+    }
 
     ALOGD("OpenAnOpenedStreamsTest: open stream, device_id=%d, stream_id=%d", device_id, stream_id);
     ASSERT_TRUE(tv_input_->openStream(device_id, stream_id, &handle).getServiceSpecificError() ==
@@ -355,8 +361,12 @@
     }
     int32_t stream_id = streamConfigs[0].streamId;
     ALOGD("GetTvMessageQueueTest: device_id=%d, stream_id=%d", device_id, stream_id);
-    MQDescriptor<int8_t, SynchronizedReadWrite> queue;
-    tv_input_->getTvMessageQueueDesc(&queue, device_id, stream_id);
+    MQDescriptor<int8_t, SynchronizedReadWrite> queueDescriptor;
+    AidlMessageQueue<int8_t, SynchronizedReadWrite>* queue;
+    tv_input_->getTvMessageQueueDesc(&queueDescriptor, device_id, stream_id);
+    queue = new (std::nothrow) AidlMessageQueue<int8_t, SynchronizedReadWrite>(queueDescriptor);
+    ASSERT_TRUE(queue->isValid());
+    delete queue;
 }
 
 INSTANTIATE_TEST_SUITE_P(PerInstance, TvInputAidlTest,
diff --git a/tv/input/aidl/vts/functional/VtsHalTvInputTargetTest.h b/tv/input/aidl/vts/functional/VtsHalTvInputTargetTest.h
index 7e66a88..fd98a18 100644
--- a/tv/input/aidl/vts/functional/VtsHalTvInputTargetTest.h
+++ b/tv/input/aidl/vts/functional/VtsHalTvInputTargetTest.h
@@ -43,6 +43,7 @@
 
 #define WAIT_FOR_EVENT_TIMEOUT 5
 #define DEFAULT_ID INT32_MIN
+#define VERIFY_SIDEBAND_STREAM_HANDLE 1
 
 namespace VtsHalTvInputTargetTest {
 
diff --git a/tv/tuner/1.0/default/OWNERS b/tv/tuner/1.0/default/OWNERS
deleted file mode 100644
index 1b3d095..0000000
--- a/tv/tuner/1.0/default/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-nchalko@google.com
-amyjojo@google.com
-shubang@google.com
-quxiangfang@google.com
diff --git a/tv/tuner/1.0/vts/OWNERS b/tv/tuner/1.0/vts/OWNERS
deleted file mode 100644
index 9bdafca..0000000
--- a/tv/tuner/1.0/vts/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-# Bug component: 136752
-nchalko@google.com
-amyjojo@google.com
-shubang@google.com
-quxiangfang@google.com
diff --git a/tv/tuner/1.1/default/OWNERS b/tv/tuner/1.1/default/OWNERS
deleted file mode 100644
index 1b3d095..0000000
--- a/tv/tuner/1.1/default/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-nchalko@google.com
-amyjojo@google.com
-shubang@google.com
-quxiangfang@google.com
diff --git a/tv/tuner/1.1/vts/OWNERS b/tv/tuner/1.1/vts/OWNERS
deleted file mode 100644
index 9bdafca..0000000
--- a/tv/tuner/1.1/vts/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-# Bug component: 136752
-nchalko@google.com
-amyjojo@google.com
-shubang@google.com
-quxiangfang@google.com
diff --git a/tv/tuner/aidl/default/Android.bp b/tv/tuner/aidl/default/Android.bp
index 65fa821..ed97d9c 100644
--- a/tv/tuner/aidl/default/Android.bp
+++ b/tv/tuner/aidl/default/Android.bp
@@ -23,6 +23,7 @@
         "TimeFilter.cpp",
         "Tuner.cpp",
         "service.cpp",
+        "dtv_plugin.cpp",
     ],
     static_libs: [
         "libaidlcommonsupport",
diff --git a/tv/tuner/aidl/default/Demux.cpp b/tv/tuner/aidl/default/Demux.cpp
index 11e7131..de94467 100644
--- a/tv/tuner/aidl/default/Demux.cpp
+++ b/tv/tuner/aidl/default/Demux.cpp
@@ -20,7 +20,9 @@
 #include <aidl/android/hardware/tv/tuner/DemuxQueueNotifyBits.h>
 #include <aidl/android/hardware/tv/tuner/Result.h>
 
+#include <fmq/AidlMessageQueue.h>
 #include <utils/Log.h>
+#include <thread>
 #include "Demux.h"
 
 namespace aidl {
@@ -29,6 +31,15 @@
 namespace tv {
 namespace tuner {
 
+using ::aidl::android::hardware::common::fmq::MQDescriptor;
+using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using ::android::AidlMessageQueue;
+using ::android::hardware::EventFlag;
+
+using FilterMQ = AidlMessageQueue<int8_t, SynchronizedReadWrite>;
+using AidlMQ = AidlMessageQueue<int8_t, SynchronizedReadWrite>;
+using AidlMQDesc = MQDescriptor<int8_t, SynchronizedReadWrite>;
+
 #define WAIT_TIMEOUT 3000000000
 
 Demux::Demux(int32_t demuxId, uint32_t filterTypes) {
@@ -42,9 +53,128 @@
 
 Demux::~Demux() {
     ALOGV("%s", __FUNCTION__);
+    if (mDemuxIptvReadThread.joinable()) {
+        mDemuxIptvReadThread.join();
+    }
     close();
 }
 
+::ndk::ScopedAStatus Demux::openDvr(DvrType in_type, int32_t in_bufferSize,
+                                    const std::shared_ptr<IDvrCallback>& in_cb,
+                                    std::shared_ptr<IDvr>* _aidl_return) {
+    ALOGV("%s", __FUNCTION__);
+
+    if (in_cb == nullptr) {
+        ALOGW("[Demux] DVR callback can't be null");
+        *_aidl_return = nullptr;
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::INVALID_ARGUMENT));
+    }
+
+    set<int64_t>::iterator it;
+    switch (in_type) {
+        case DvrType::PLAYBACK:
+            mDvrPlayback = ndk::SharedRefBase::make<Dvr>(in_type, in_bufferSize, in_cb,
+                                                         this->ref<Demux>());
+            if (!mDvrPlayback->createDvrMQ()) {
+                ALOGE("[Demux] cannot create dvr message queue");
+                mDvrPlayback = nullptr;
+                *_aidl_return = mDvrPlayback;
+                return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                        static_cast<int32_t>(Result::UNKNOWN_ERROR));
+            }
+
+            for (it = mPlaybackFilterIds.begin(); it != mPlaybackFilterIds.end(); it++) {
+                if (!mDvrPlayback->addPlaybackFilter(*it, mFilters[*it])) {
+                    ALOGE("[Demux] Can't get filter info for DVR playback");
+                    mDvrPlayback = nullptr;
+                    *_aidl_return = mDvrPlayback;
+                    return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                            static_cast<int32_t>(Result::UNKNOWN_ERROR));
+                }
+            }
+
+            ALOGI("Playback normal case");
+
+            *_aidl_return = mDvrPlayback;
+            return ::ndk::ScopedAStatus::ok();
+        case DvrType::RECORD:
+            mDvrRecord = ndk::SharedRefBase::make<Dvr>(in_type, in_bufferSize, in_cb,
+                                                       this->ref<Demux>());
+            if (!mDvrRecord->createDvrMQ()) {
+                mDvrRecord = nullptr;
+                *_aidl_return = mDvrRecord;
+                return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                        static_cast<int32_t>(Result::UNKNOWN_ERROR));
+            }
+
+            *_aidl_return = mDvrRecord;
+            return ::ndk::ScopedAStatus::ok();
+        default:
+            *_aidl_return = nullptr;
+            return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                    static_cast<int32_t>(Result::INVALID_ARGUMENT));
+    }
+}
+
+void Demux::setIptvThreadRunning(bool isIptvThreadRunning) {
+    std::unique_lock<std::mutex> lock(mIsIptvThreadRunningMutex);
+    mIsIptvReadThreadRunning = isIptvThreadRunning;
+    mIsIptvThreadRunningCv.notify_all();
+}
+
+void Demux::readIptvThreadLoop(dtv_plugin* interface, dtv_streamer* streamer, size_t buf_size,
+                               int timeout_ms, int buffer_timeout) {
+    Timer *timer, *fullBufferTimer;
+    while (true) {
+        std::unique_lock<std::mutex> lock(mIsIptvThreadRunningMutex);
+        mIsIptvThreadRunningCv.wait(lock, [this] { return mIsIptvReadThreadRunning; });
+        if (mIsIptvDvrFMQFull && fullBufferTimer->get_elapsed_time_ms() > buffer_timeout) {
+            ALOGE("DVR FMQ has not been flushed within timeout of %d ms", buffer_timeout);
+            delete fullBufferTimer;
+            break;
+        }
+        timer = new Timer();
+        void* buf = malloc(sizeof(char) * IPTV_BUFFER_SIZE);
+        if (buf == nullptr) ALOGI("Buffer allocation failed");
+        ssize_t bytes_read = interface->read_stream(streamer, buf, buf_size, timeout_ms);
+        if (bytes_read == 0) {
+            double elapsed_time = timer->get_elapsed_time_ms();
+            if (elapsed_time > timeout_ms) {
+                ALOGE("[Demux] timeout reached - elapsed_time: %f, timeout: %d", elapsed_time,
+                      timeout_ms);
+            }
+            ALOGE("[Demux] Cannot read data from the socket");
+            delete timer;
+            break;
+        }
+
+        delete timer;
+        ALOGI("Number of bytes read: %zd", bytes_read);
+        int result = mDvrPlayback->writePlaybackFMQ(buf, bytes_read);
+
+        switch (result) {
+            case DVR_WRITE_FAILURE_REASON_FMQ_FULL:
+                if (!mIsIptvDvrFMQFull) {
+                    mIsIptvDvrFMQFull = true;
+                    fullBufferTimer = new Timer();
+                }
+                ALOGI("Waiting for client to flush DVR FMQ.");
+                break;
+            case DVR_WRITE_FAILURE_REASON_UNKNOWN:
+                ALOGE("Failed to write data into DVR FMQ for unknown reason");
+                break;
+            case DVR_WRITE_SUCCESS:
+                ALOGI("Wrote %zd bytes to DVR FMQ", bytes_read);
+                break;
+            default:
+                ALOGI("Invalid DVR Status");
+        }
+
+        free(buf);
+    }
+}
+
 ::ndk::ScopedAStatus Demux::setFrontendDataSource(int32_t in_frontendId) {
     ALOGV("%s", __FUNCTION__);
 
@@ -52,7 +182,6 @@
         return ::ndk::ScopedAStatus::fromServiceSpecificError(
                 static_cast<int32_t>(Result::NOT_INITIALIZED));
     }
-
     mFrontend = mTuner->getFrontendById(in_frontendId);
     if (mFrontend == nullptr) {
         return ::ndk::ScopedAStatus::fromServiceSpecificError(
@@ -61,6 +190,49 @@
 
     mTuner->setFrontendAsDemuxSource(in_frontendId, mDemuxId);
 
+    // if mFrontend is an IPTV frontend, create streamer to read TS data from socket
+    if (mFrontend->getFrontendType() == FrontendType::IPTV) {
+        // create a DVR instance on the demux
+        shared_ptr<IDvr> iptvDvr;
+
+        std::shared_ptr<IDvrCallback> dvrPlaybackCallback =
+                ::ndk::SharedRefBase::make<DvrPlaybackCallback>();
+
+        ::ndk::ScopedAStatus status =
+                openDvr(DvrType::PLAYBACK, IPTV_BUFFER_SIZE, dvrPlaybackCallback, &iptvDvr);
+        if (status.isOk()) {
+            ALOGI("DVR instance created");
+        }
+
+        // get plugin interface from frontend
+        dtv_plugin* interface = mFrontend->getIptvPluginInterface();
+        if (interface == nullptr) {
+            ALOGE("[Demux] getIptvPluginInterface(): plugin interface is null");
+            return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                    static_cast<int32_t>(Result::INVALID_STATE));
+        }
+        ALOGI("[Demux] getIptvPluginInterface(): plugin interface is not null");
+
+        // get streamer object from Frontend instance
+        dtv_streamer* streamer = mFrontend->getIptvPluginStreamer();
+        if (streamer == nullptr) {
+            ALOGE("[Demux] getIptvPluginStreamer(): streamer is null");
+            return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                    static_cast<int32_t>(Result::INVALID_STATE));
+        }
+        ALOGI("[Demux] getIptvPluginStreamer(): streamer is not null");
+
+        // get transport description from frontend
+        string transport_desc = mFrontend->getIptvTransportDescription();
+        ALOGI("[Demux] getIptvTransportDescription(): transport_desc: %s", transport_desc.c_str());
+
+        // call read_stream on the socket to populate the buffer with TS data
+        // while thread is alive, keep reading data
+        int timeout_ms = 20;
+        int buffer_timeout = 10000;  // 10s
+        mDemuxIptvReadThread = std::thread(&Demux::readIptvThreadLoop, this, interface, streamer,
+                                           IPTV_BUFFER_SIZE, timeout_ms, buffer_timeout);
+    }
     return ::ndk::ScopedAStatus::ok();
 }
 
@@ -193,61 +365,6 @@
     return ::ndk::ScopedAStatus::ok();
 }
 
-::ndk::ScopedAStatus Demux::openDvr(DvrType in_type, int32_t in_bufferSize,
-                                    const std::shared_ptr<IDvrCallback>& in_cb,
-                                    std::shared_ptr<IDvr>* _aidl_return) {
-    ALOGV("%s", __FUNCTION__);
-
-    if (in_cb == nullptr) {
-        ALOGW("[Demux] DVR callback can't be null");
-        *_aidl_return = nullptr;
-        return ::ndk::ScopedAStatus::fromServiceSpecificError(
-                static_cast<int32_t>(Result::INVALID_ARGUMENT));
-    }
-
-    set<int64_t>::iterator it;
-    switch (in_type) {
-        case DvrType::PLAYBACK:
-            mDvrPlayback = ndk::SharedRefBase::make<Dvr>(in_type, in_bufferSize, in_cb,
-                                                         this->ref<Demux>());
-            if (!mDvrPlayback->createDvrMQ()) {
-                mDvrPlayback = nullptr;
-                *_aidl_return = mDvrPlayback;
-                return ::ndk::ScopedAStatus::fromServiceSpecificError(
-                        static_cast<int32_t>(Result::UNKNOWN_ERROR));
-            }
-
-            for (it = mPlaybackFilterIds.begin(); it != mPlaybackFilterIds.end(); it++) {
-                if (!mDvrPlayback->addPlaybackFilter(*it, mFilters[*it])) {
-                    ALOGE("[Demux] Can't get filter info for DVR playback");
-                    mDvrPlayback = nullptr;
-                    *_aidl_return = mDvrPlayback;
-                    return ::ndk::ScopedAStatus::fromServiceSpecificError(
-                            static_cast<int32_t>(Result::UNKNOWN_ERROR));
-                }
-            }
-
-            *_aidl_return = mDvrPlayback;
-            return ::ndk::ScopedAStatus::ok();
-        case DvrType::RECORD:
-            mDvrRecord = ndk::SharedRefBase::make<Dvr>(in_type, in_bufferSize, in_cb,
-                                                       this->ref<Demux>());
-            if (!mDvrRecord->createDvrMQ()) {
-                mDvrRecord = nullptr;
-                *_aidl_return = mDvrRecord;
-                return ::ndk::ScopedAStatus::fromServiceSpecificError(
-                        static_cast<int32_t>(Result::UNKNOWN_ERROR));
-            }
-
-            *_aidl_return = mDvrRecord;
-            return ::ndk::ScopedAStatus::ok();
-        default:
-            *_aidl_return = nullptr;
-            return ::ndk::ScopedAStatus::fromServiceSpecificError(
-                    static_cast<int32_t>(Result::INVALID_ARGUMENT));
-    }
-}
-
 ::ndk::ScopedAStatus Demux::connectCiCam(int32_t in_ciCamId) {
     ALOGV("%s", __FUNCTION__);
 
diff --git a/tv/tuner/aidl/default/Demux.h b/tv/tuner/aidl/default/Demux.h
index 7d7aee4..ad7b7a7 100644
--- a/tv/tuner/aidl/default/Demux.h
+++ b/tv/tuner/aidl/default/Demux.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <aidl/android/hardware/tv/tuner/BnDemux.h>
+#include <aidl/android/hardware/tv/tuner/BnDvrCallback.h>
 
 #include <fmq/AidlMessageQueue.h>
 #include <math.h>
@@ -28,7 +29,9 @@
 #include "Filter.h"
 #include "Frontend.h"
 #include "TimeFilter.h"
+#include "Timer.h"
 #include "Tuner.h"
+#include "dtv_plugin.h"
 
 using namespace std;
 
@@ -44,6 +47,8 @@
 using ::android::hardware::EventFlag;
 
 using FilterMQ = AidlMessageQueue<int8_t, SynchronizedReadWrite>;
+using AidlMQ = AidlMessageQueue<int8_t, SynchronizedReadWrite>;
+using AidlMQDesc = MQDescriptor<int8_t, SynchronizedReadWrite>;
 
 class Dvr;
 class Filter;
@@ -51,6 +56,19 @@
 class TimeFilter;
 class Tuner;
 
+class DvrPlaybackCallback : public BnDvrCallback {
+  public:
+    virtual ::ndk::ScopedAStatus onPlaybackStatus(PlaybackStatus status) override {
+        ALOGD("demux.h: playback status %d", status);
+        return ndk::ScopedAStatus::ok();
+    }
+
+    virtual ::ndk::ScopedAStatus onRecordStatus(RecordStatus status) override {
+        ALOGD("Record Status %hhd", status);
+        return ndk::ScopedAStatus::ok();
+    }
+};
+
 class Demux : public BnDemux {
   public:
     Demux(int32_t demuxId, uint32_t filterTypes);
@@ -85,6 +103,8 @@
     void setIsRecording(bool isRecording);
     bool isRecording();
     void startFrontendInputLoop();
+    void readIptvThreadLoop(dtv_plugin* interface, dtv_streamer* streamer, size_t size,
+                            int timeout_ms, int buffer_timeout);
 
     /**
      * A dispatcher to read and dispatch input data to all the started filters.
@@ -104,6 +124,11 @@
     void setInUse(bool inUse);
     void setTunerService(std::shared_ptr<Tuner> tuner);
 
+    /**
+     * Setter for IPTV Reading thread
+     */
+    void setIptvThreadRunning(bool isIptvThreadRunning);
+
   private:
     // Tuner service
     std::shared_ptr<Tuner> mTuner;
@@ -167,6 +192,10 @@
 
     // Thread handlers
     std::thread mFrontendInputThread;
+    std::thread mDemuxIptvReadThread;
+
+    // track whether the DVR FMQ for IPTV Playback is full
+    bool mIsIptvDvrFMQFull = false;
 
     /**
      * If a specific filter's writing loop is still running
@@ -175,6 +204,13 @@
     std::atomic<bool> mKeepFetchingDataFromFrontend;
 
     /**
+     * Controls IPTV reading thread status
+     */
+    bool mIsIptvReadThreadRunning;
+    std::mutex mIsIptvThreadRunningMutex;
+    std::condition_variable mIsIptvThreadRunningCv;
+
+    /**
      * If the dvr recording is running.
      */
     bool mIsRecording = false;
diff --git a/tv/tuner/aidl/default/Dvr.cpp b/tv/tuner/aidl/default/Dvr.cpp
index c046ae3..393200c 100644
--- a/tv/tuner/aidl/default/Dvr.cpp
+++ b/tv/tuner/aidl/default/Dvr.cpp
@@ -236,6 +236,25 @@
     ALOGD("[Dvr] playback thread ended.");
 }
 
+void Dvr::maySendIptvPlaybackStatusCallback() {
+    lock_guard<mutex> lock(mPlaybackStatusLock);
+    int availableToRead = mDvrMQ->availableToRead();
+    int availableToWrite = mDvrMQ->availableToWrite();
+
+    PlaybackStatus newStatus = checkPlaybackStatusChange(availableToWrite, availableToRead,
+                                                         IPTV_PLAYBACK_STATUS_THRESHOLD_HIGH,
+                                                         IPTV_PLAYBACK_STATUS_THRESHOLD_LOW);
+    if (mPlaybackStatus != newStatus) {
+        map<int64_t, std::shared_ptr<Filter>>::iterator it;
+        for (it = mFilters.begin(); it != mFilters.end(); it++) {
+            std::shared_ptr<Filter> currentFilter = it->second;
+            currentFilter->setIptvDvrPlaybackStatus(newStatus);
+        }
+        mCallback->onPlaybackStatus(newStatus);
+        mPlaybackStatus = newStatus;
+    }
+}
+
 void Dvr::maySendPlaybackStatusCallback() {
     lock_guard<mutex> lock(mPlaybackStatusLock);
     int availableToRead = mDvrMQ->availableToRead();
@@ -379,7 +398,7 @@
 
     // Read es raw data from the FMQ per meta data built previously
     vector<int8_t> frameData;
-    map<int64_t, std::shared_ptr<IFilter>>::iterator it;
+    map<int64_t, std::shared_ptr<Filter>>::iterator it;
     int pid = 0;
     for (int i = 0; i < totalFrames; i++) {
         frameData.resize(esMeta[i].len);
@@ -411,7 +430,7 @@
 }
 
 void Dvr::startTpidFilter(vector<int8_t> data) {
-    map<int64_t, std::shared_ptr<IFilter>>::iterator it;
+    map<int64_t, std::shared_ptr<Filter>>::iterator it;
     for (it = mFilters.begin(); it != mFilters.end(); it++) {
         uint16_t pid = ((data[1] & 0x1f) << 8) | ((data[2] & 0xff));
         if (DEBUG_DVR) {
@@ -432,7 +451,7 @@
         }
     }
 
-    map<int64_t, std::shared_ptr<IFilter>>::iterator it;
+    map<int64_t, std::shared_ptr<Filter>>::iterator it;
     // Handle the output data per filter type
     for (it = mFilters.begin(); it != mFilters.end(); it++) {
         if (!mDemux->startFilterHandler(it->first).isOk()) {
@@ -443,6 +462,24 @@
     return true;
 }
 
+int Dvr::writePlaybackFMQ(void* buf, size_t size) {
+    lock_guard<mutex> lock(mWriteLock);
+    ALOGI("Playback status: %d", mPlaybackStatus);
+    if (mPlaybackStatus == PlaybackStatus::SPACE_FULL) {
+        ALOGW("[Dvr] stops writing and wait for the client side flushing.");
+        return DVR_WRITE_FAILURE_REASON_FMQ_FULL;
+    }
+    ALOGI("availableToWrite before: %zu", mDvrMQ->availableToWrite());
+    if (mDvrMQ->write((int8_t*)buf, size)) {
+        mDvrEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
+        ALOGI("availableToWrite: %zu", mDvrMQ->availableToWrite());
+        maySendIptvPlaybackStatusCallback();
+        return DVR_WRITE_SUCCESS;
+    }
+    maySendIptvPlaybackStatusCallback();
+    return DVR_WRITE_FAILURE_REASON_UNKNOWN;
+}
+
 bool Dvr::writeRecordFMQ(const vector<int8_t>& data) {
     lock_guard<mutex> lock(mWriteLock);
     if (mRecordStatus == RecordStatus::OVERFLOW) {
@@ -486,7 +523,7 @@
     return mRecordStatus;
 }
 
-bool Dvr::addPlaybackFilter(int64_t filterId, std::shared_ptr<IFilter> filter) {
+bool Dvr::addPlaybackFilter(int64_t filterId, std::shared_ptr<Filter> filter) {
     mFilters[filterId] = filter;
     return true;
 }
diff --git a/tv/tuner/aidl/default/Dvr.h b/tv/tuner/aidl/default/Dvr.h
index 293c533..07f95ad 100644
--- a/tv/tuner/aidl/default/Dvr.h
+++ b/tv/tuner/aidl/default/Dvr.h
@@ -43,6 +43,19 @@
 
 using DvrMQ = AidlMessageQueue<int8_t, SynchronizedReadWrite>;
 
+const int DVR_WRITE_SUCCESS = 0;
+const int DVR_WRITE_FAILURE_REASON_FMQ_FULL = 1;
+const int DVR_WRITE_FAILURE_REASON_UNKNOWN = 2;
+
+const int TS_SIZE = 188;
+const int IPTV_BUFFER_SIZE = TS_SIZE * 7 * 8;  // defined in service_streamer_udp in cbs v3 project
+
+// Thresholds are defined to indicate how full the buffers are.
+const double HIGH_THRESHOLD_PERCENT = 0.90;
+const double LOW_THRESHOLD_PERCENT = 0.15;
+const int IPTV_PLAYBACK_STATUS_THRESHOLD_HIGH = IPTV_BUFFER_SIZE * HIGH_THRESHOLD_PERCENT;
+const int IPTV_PLAYBACK_STATUS_THRESHOLD_LOW = IPTV_BUFFER_SIZE * LOW_THRESHOLD_PERCENT;
+
 struct MediaEsMetaData {
     bool isAudio;
     int startIndex;
@@ -80,8 +93,9 @@
      * Return false is any of the above processes fails.
      */
     bool createDvrMQ();
+    int writePlaybackFMQ(void* buf, size_t size);
     bool writeRecordFMQ(const std::vector<int8_t>& data);
-    bool addPlaybackFilter(int64_t filterId, std::shared_ptr<IFilter> filter);
+    bool addPlaybackFilter(int64_t filterId, std::shared_ptr<Filter> filter);
     bool removePlaybackFilter(int64_t filterId);
     bool readPlaybackFMQ(bool isVirtualFrontend, bool isRecording);
     bool processEsDataOnPlayback(bool isVirtualFrontend, bool isRecording);
@@ -96,12 +110,13 @@
     DvrType mType;
     uint32_t mBufferSize;
     std::shared_ptr<IDvrCallback> mCallback;
-    std::map<int64_t, std::shared_ptr<IFilter>> mFilters;
+    std::map<int64_t, std::shared_ptr<Filter>> mFilters;
 
     void deleteEventFlag();
     bool readDataFromMQ();
     void getMetaDataValue(int& index, int8_t* dataOutputBuffer, int& value);
     void maySendPlaybackStatusCallback();
+    void maySendIptvPlaybackStatusCallback();
     void maySendRecordStatusCallback();
     PlaybackStatus checkPlaybackStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
                                              int64_t highThreshold, int64_t lowThreshold);
diff --git a/tv/tuner/aidl/default/Filter.cpp b/tv/tuner/aidl/default/Filter.cpp
index ba9602e..212d329 100644
--- a/tv/tuner/aidl/default/Filter.cpp
+++ b/tv/tuner/aidl/default/Filter.cpp
@@ -326,6 +326,10 @@
     ALOGV("%s", __FUNCTION__);
     mFilterThreadRunning = true;
     std::vector<DemuxFilterEvent> events;
+
+    mFilterCount += 1;
+    mDemux->setIptvThreadRunning(true);
+
     // All the filter event callbacks in start are for testing purpose.
     switch (mType.mainType) {
         case DemuxFilterMainType::TS:
@@ -362,6 +366,11 @@
 ::ndk::ScopedAStatus Filter::stop() {
     ALOGV("%s", __FUNCTION__);
 
+    mFilterCount -= 1;
+    if (mFilterCount == 0) {
+        mDemux->setIptvThreadRunning(false);
+    }
+
     mFilterThreadRunning = false;
     if (mFilterThread.joinable()) {
         mFilterThread.join();
@@ -565,6 +574,8 @@
 
     ALOGD("[Filter] filter %" PRIu64 " threadLoop start.", mFilterId);
 
+    ALOGI("IPTV DVR Playback status on Filter: %d", mIptvDvrPlaybackStatus);
+
     // For the first time of filter output, implementation needs to send the filter
     // Event Callback without waiting for the DATA_CONSUMED to init the process.
     while (mFilterThreadRunning) {
diff --git a/tv/tuner/aidl/default/Filter.h b/tv/tuner/aidl/default/Filter.h
index 0985296..e2a0c7a 100644
--- a/tv/tuner/aidl/default/Filter.h
+++ b/tv/tuner/aidl/default/Filter.h
@@ -147,6 +147,7 @@
     bool isMediaFilter() { return mIsMediaFilter; };
     bool isPcrFilter() { return mIsPcrFilter; };
     bool isRecordFilter() { return mIsRecordFilter; };
+    void setIptvDvrPlaybackStatus(PlaybackStatus newStatus) { mIptvDvrPlaybackStatus = newStatus; };
 
   private:
     // Demux service
@@ -286,6 +287,9 @@
     int mStartId = 0;
     uint8_t mScramblingStatusMonitored = 0;
     uint8_t mIpCidMonitored = 0;
+
+    PlaybackStatus mIptvDvrPlaybackStatus;
+    std::atomic<int> mFilterCount = 0;
 };
 
 }  // namespace tuner
diff --git a/tv/tuner/aidl/default/Frontend.cpp b/tv/tuner/aidl/default/Frontend.cpp
index cd072bf..57ed1ba 100644
--- a/tv/tuner/aidl/default/Frontend.cpp
+++ b/tv/tuner/aidl/default/Frontend.cpp
@@ -34,6 +34,8 @@
     mTuner = nullptr;
     // Init callback to nullptr
     mCallback = nullptr;
+    mIptvPluginInterface = nullptr;
+    mIptvPluginStreamer = nullptr;
 
     switch (mType) {
         case FrontendType::ISDBS: {
@@ -213,20 +215,82 @@
     return ::ndk::ScopedAStatus::ok();
 }
 
-::ndk::ScopedAStatus Frontend::tune(const FrontendSettings& /* in_settings */) {
-    ALOGV("%s", __FUNCTION__);
+void Frontend::readTuneByte(dtv_streamer* streamer, void* buf, size_t buf_size, int timeout_ms) {
+    ssize_t bytes_read = mIptvPluginInterface->read_stream(streamer, buf, buf_size, timeout_ms);
+    if (bytes_read <= 0) {
+        ALOGI("[   ERROR   ] Tune byte couldn't be read.");
+        return;
+    }
+    mCallback->onEvent(FrontendEventType::LOCKED);
+    mIsLocked = true;
+}
+
+::ndk::ScopedAStatus Frontend::tune(const FrontendSettings& in_settings) {
     if (mCallback == nullptr) {
-        ALOGW("[   WARN   ] Frontend callback is not set when tune");
+        ALOGW("[   WARN   ] Frontend callback is not set for tunin0g");
         return ::ndk::ScopedAStatus::fromServiceSpecificError(
                 static_cast<int32_t>(Result::INVALID_STATE));
     }
 
     if (mType != FrontendType::IPTV) {
         mTuner->frontendStartTune(mId);
-    }
+        mCallback->onEvent(FrontendEventType::LOCKED);
+        mIsLocked = true;
+    } else {
+        // This is a reference implementation for IPTV. It uses an additional socket buffer.
+        // Vendors can use hardware memory directly to make the implementation more performant.
+        ALOGI("[   INFO   ] Frontend type is set to IPTV, tag = %d id=%d", in_settings.getTag(),
+              mId);
 
-    mCallback->onEvent(FrontendEventType::LOCKED);
-    mIsLocked = true;
+        // load udp plugin for reading TS data
+        const char* path = "/vendor/lib/iptv_udp_plugin.so";
+        DtvPlugin* plugin = new DtvPlugin(path);
+        if (!plugin) {
+            ALOGE("Failed to create DtvPlugin, plugin_path is invalid");
+            return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                    static_cast<int32_t>(Result::INVALID_ARGUMENT));
+        }
+        bool plugin_loaded = plugin->load();
+        if (!plugin_loaded) {
+            ALOGE("Failed to load plugin");
+            return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                    static_cast<int32_t>(Result::INVALID_ARGUMENT));
+        }
+        mIptvPluginInterface = plugin->interface();
+
+        // validate content_url format
+        std::string content_url = in_settings.get<FrontendSettings::Tag::iptv>()->contentUrl;
+        std::string transport_desc = "{ \"uri\": \"" + content_url + "\"}";
+        ALOGI("[   INFO   ] transport_desc: %s", transport_desc.c_str());
+        bool is_transport_desc_valid = plugin->validate(transport_desc.c_str());
+        if (!is_transport_desc_valid) {  // not of format protocol://ip:port
+            ALOGE("[   INFO   ] transport_desc is not valid");
+            return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                    static_cast<int32_t>(Result::INVALID_ARGUMENT));
+        }
+        mIptvTransportDescription = transport_desc;
+
+        // create a streamer and open it for reading data
+        dtv_streamer* streamer = mIptvPluginInterface->create_streamer();
+        mIptvPluginStreamer = streamer;
+        int open_fd = mIptvPluginInterface->open_stream(streamer, transport_desc.c_str());
+        if (open_fd < 0) {
+            ALOGE("[   INFO   ] could not open stream");
+            return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                    static_cast<int32_t>(Result::INVALID_ARGUMENT));
+        }
+        ALOGI("[   INFO   ] open_stream successful, open_fd=%d", open_fd);
+
+        size_t buf_size = 1;
+        int timeout_ms = 2000;
+        void* buf = malloc(sizeof(char) * buf_size);
+        if (buf == nullptr) ALOGI("malloc buf failed [TUNE]");
+        ALOGI("[   INFO   ] [Tune] Allocated buffer of size %zu", buf_size);
+        mIptvFrontendTuneThread =
+                std::thread(&Frontend::readTuneByte, this, streamer, buf, buf_size, timeout_ms);
+        if (mIptvFrontendTuneThread.joinable()) mIptvFrontendTuneThread.join();
+        free(buf);
+    }
 
     return ::ndk::ScopedAStatus::ok();
 }
@@ -1002,6 +1066,18 @@
     return mId;
 }
 
+dtv_plugin* Frontend::getIptvPluginInterface() {
+    return mIptvPluginInterface;
+}
+
+string Frontend::getIptvTransportDescription() {
+    return mIptvTransportDescription;
+}
+
+dtv_streamer* Frontend::getIptvPluginStreamer() {
+    return mIptvPluginStreamer;
+}
+
 bool Frontend::supportsSatellite() {
     return mType == FrontendType::DVBS || mType == FrontendType::ISDBS ||
            mType == FrontendType::ISDBS3;
diff --git a/tv/tuner/aidl/default/Frontend.h b/tv/tuner/aidl/default/Frontend.h
index 85bd636..17a1aee 100644
--- a/tv/tuner/aidl/default/Frontend.h
+++ b/tv/tuner/aidl/default/Frontend.h
@@ -21,6 +21,7 @@
 #include <iostream>
 #include <thread>
 #include "Tuner.h"
+#include "dtv_plugin.h"
 
 using namespace std;
 
@@ -60,6 +61,10 @@
     FrontendType getFrontendType();
     int32_t getFrontendId();
     string getSourceFile();
+    dtv_plugin* getIptvPluginInterface();
+    string getIptvTransportDescription();
+    dtv_streamer* getIptvPluginStreamer();
+    void readTuneByte(dtv_streamer* streamer, void* buf, size_t size, int timeout_ms);
     bool isLocked();
     void getFrontendInfo(FrontendInfo* _aidl_return);
     void setTunerService(std::shared_ptr<Tuner> tuner);
@@ -81,6 +86,10 @@
     std::ifstream mFrontendData;
     FrontendCapabilities mFrontendCaps;
     vector<FrontendStatusType> mFrontendStatusCaps;
+    dtv_plugin* mIptvPluginInterface;
+    string mIptvTransportDescription;
+    dtv_streamer* mIptvPluginStreamer;
+    std::thread mIptvFrontendTuneThread;
 };
 
 }  // namespace tuner
diff --git a/tv/tuner/aidl/default/OWNERS b/tv/tuner/aidl/default/OWNERS
deleted file mode 100644
index bf2b609..0000000
--- a/tv/tuner/aidl/default/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-hgchen@google.com
-shubang@google.com
-quxiangfang@google.com
diff --git a/tv/tuner/aidl/default/Timer.h b/tv/tuner/aidl/default/Timer.h
new file mode 100644
index 0000000..c6327cb
--- /dev/null
+++ b/tv/tuner/aidl/default/Timer.h
@@ -0,0 +1,17 @@
+#include <chrono>
+using namespace std::chrono;
+class Timer {
+  public:
+    Timer() { start_time = steady_clock::now(); }
+
+    ~Timer() { stop_time = steady_clock::now(); }
+
+    double get_elapsed_time_ms() {
+        auto current_time = std::chrono::steady_clock::now();
+        return duration_cast<milliseconds>(current_time - start_time).count();
+    }
+
+  private:
+    time_point<steady_clock> start_time;
+    time_point<steady_clock> stop_time;
+};
\ No newline at end of file
diff --git a/tv/tuner/aidl/default/dtv_plugin.cpp b/tv/tuner/aidl/default/dtv_plugin.cpp
new file mode 100644
index 0000000..4e73ee5
--- /dev/null
+++ b/tv/tuner/aidl/default/dtv_plugin.cpp
@@ -0,0 +1,130 @@
+#include "dtv_plugin.h"
+#include <dlfcn.h>
+#include <libgen.h>
+#include <utils/Log.h>
+
+DtvPlugin::DtvPlugin(const char* plugin_path) {
+    path_ = plugin_path;
+    basename_ = basename(path_);
+    module_ = NULL;
+    interface_ = NULL;
+    loaded_ = false;
+}
+
+DtvPlugin::~DtvPlugin() {
+    if (module_ != NULL) {
+        if (dlclose(module_)) ALOGE("DtvPlugin: Failed to close plugin '%s'", basename_);
+    }
+}
+
+bool DtvPlugin::load() {
+    ALOGI("Loading plugin '%s' from path '%s'", basename_, path_);
+
+    module_ = dlopen(path_, RTLD_LAZY);
+    if (module_ == NULL) {
+        ALOGE("DtvPlugin::Load::Failed to load plugin '%s'", basename_);
+        ALOGE("dlopen error: %s", dlerror());
+        return false;
+    }
+
+    interface_ = (dtv_plugin*)dlsym(module_, "plugin_entry");
+
+    if (interface_ == NULL) {
+        ALOGE("plugin_entry is NULL.");
+        goto error;
+    }
+
+    if (!interface_->get_transport_types || !interface_->get_streamer_count ||
+        !interface_->validate || !interface_->create_streamer || !interface_->destroy_streamer ||
+        !interface_->open_stream || !interface_->close_stream || !interface_->read_stream) {
+        ALOGW("Plugin: missing one or more callbacks");
+        goto error;
+    }
+
+    loaded_ = true;
+
+    return true;
+
+error:
+    if (dlclose(module_)) ALOGE("Failed to close plugin '%s'", basename_);
+
+    return false;
+}
+
+int DtvPlugin::getStreamerCount() {
+    if (!loaded_) {
+        ALOGE("DtvPlugin::GetStreamerCount: Plugin '%s' not loaded!", basename_);
+        return 0;
+    }
+
+    return interface_->get_streamer_count();
+}
+
+bool DtvPlugin::isTransportTypeSupported(const char* transport_type) {
+    const char** transport;
+
+    if (!loaded_) {
+        ALOGE("Plugin '%s' not loaded!", basename_);
+        return false;
+    }
+
+    transport = interface_->get_transport_types();
+    if (transport == NULL) return false;
+
+    while (*transport) {
+        if (strcmp(transport_type, *transport) == 0) return true;
+        transport++;
+    }
+
+    return false;
+}
+
+bool DtvPlugin::validate(const char* transport_desc) {
+    if (!loaded_) {
+        ALOGE("Plugin '%s' is not loaded!", basename_);
+        return false;
+    }
+
+    return interface_->validate(transport_desc);
+}
+
+bool DtvPlugin::getProperty(const char* key, void* value, int* size) {
+    if (!loaded_) {
+        ALOGE("Plugin '%s' is not loaded!", basename_);
+        return false;
+    }
+
+    if (!interface_->get_property) return false;
+
+    *size = interface_->get_property(NULL, key, value, *size);
+
+    return *size < 0 ? false : true;
+}
+
+bool DtvPlugin::setProperty(const char* key, const void* value, int size) {
+    int ret;
+
+    if (!loaded_) {
+        ALOGE("Plugin '%s': not loaded!", basename_);
+        return false;
+    }
+
+    if (!interface_->set_property) return false;
+
+    ret = interface_->set_property(NULL, key, value, size);
+
+    return ret < 0 ? false : true;
+}
+
+struct dtv_plugin* DtvPlugin::interface() {
+    if (!loaded_) {
+        ALOGE("Plugin '%s' is not loaded!", basename_);
+        return NULL;
+    }
+
+    return interface_;
+}
+
+const char* DtvPlugin::pluginBasename() {
+    return basename_;
+}
diff --git a/tv/tuner/aidl/default/dtv_plugin.h b/tv/tuner/aidl/default/dtv_plugin.h
new file mode 100644
index 0000000..0ee5489
--- /dev/null
+++ b/tv/tuner/aidl/default/dtv_plugin.h
@@ -0,0 +1,31 @@
+#ifndef LIVE_DTV_PLUGIN_H_
+#define LIVE_DTV_PLUGIN_H_
+
+#include <fstream>
+#include "dtv_plugin_api.h"
+
+class DtvPlugin {
+  public:
+    DtvPlugin(const char* plugin_path);
+    ~DtvPlugin();
+
+    bool load();
+    int getStreamerCount();
+    bool validate(const char* transport_desc);
+    bool isTransportTypeSupported(const char* transport_type);
+    //    /* plugin-wide properties */
+    bool getProperty(const char* key, void* value, int* size);
+    bool setProperty(const char* key, const void* value, int size);
+
+    struct dtv_plugin* interface();
+    const char* pluginBasename();
+
+  protected:
+    const char* path_;
+    char* basename_;
+    void* module_;
+    struct dtv_plugin* interface_;
+    bool loaded_;
+};
+
+#endif  // LIVE_DTV_PLUGIN_H_
diff --git a/tv/tuner/aidl/default/dtv_plugin_api.h b/tv/tuner/aidl/default/dtv_plugin_api.h
new file mode 100644
index 0000000..8fe7c1d
--- /dev/null
+++ b/tv/tuner/aidl/default/dtv_plugin_api.h
@@ -0,0 +1,137 @@
+#ifndef LIVE_DTV_PLUGIN_API_H_
+#define LIVE_DTV_PLUGIN_API_H_
+
+#include <stdint.h>
+
+struct dtv_streamer;
+
+struct dtv_plugin {
+    uint32_t version;
+
+    /**
+     * get_transport_types() - Retrieve a list of supported transport types.
+     *
+     * Return: A NULL-terminated list of supported transport types.
+     */
+    const char** (*get_transport_types)(void);
+
+    /**
+     * get_streamer_count() - Get number of streamers that can be created.
+     *
+     * Return: The number of streamers that can be created.
+     */
+    int (*get_streamer_count)(void);
+
+    /**
+     * validate() - Check if transport description is valid.
+     * @transport_desc: NULL-terminated transport description in json format.
+     *
+     * Return: 1 if valid, 0 otherwise.
+     */
+    int (*validate)(const char* transport_desc);
+
+    /**
+     * create_streamer() - Create a streamer object.
+     *
+     * Return: A pointer to a new streamer object.
+     */
+    struct dtv_streamer* (*create_streamer)(void);
+
+    /**
+     * destroy_streamer() - Free a streamer object and all associated resources.
+     * @st: Pointer to a streamer object
+     */
+    void (*destroy_streamer)(struct dtv_streamer* streamer);
+
+    /**
+     * set_property() - Set a key/value pair property.
+     * @streamer: Pointer to a streamer object (may be NULL for plugin-wide properties).
+     * @key: NULL-terminated property name.
+     * @value: Property value.
+     * @size: Property value size.
+     *
+     * Return: 0 if success, -1 otherwise.
+     */
+    int (*set_property)(struct dtv_streamer* streamer, const char* key, const void* value,
+                        size_t size);
+
+    /**
+     * get_property() - Get a property's value.
+     * @streamer: Pointer to a streamer (may be NULL for plugin-wide properties).
+     * @key: NULL-terminated property name.
+     * @value: Property value.
+     * @size: Property value size.
+     *
+     * Return: >= 0 if success, -1 otherwise.
+     *
+     * If size is 0, get_property will return the size needed to hold the value.
+     */
+    int (*get_property)(struct dtv_streamer* streamer, const char* key, void* value, size_t size);
+
+    /**
+     * add_pid() - Add a TS filter on a given pid.
+     * @streamer: The streamer that outputs the TS.
+     * @pid: The pid to add to the TS output.
+     *
+     * Return: 0 if success, -1 otherwise.
+     *
+     * This function is optional but can be useful if a hardware remux is
+     * available.
+     */
+    int (*add_pid)(struct dtv_streamer* streamer, int pid);
+
+    /**
+     * remove_pid() - Remove a TS filter on a given pid.
+     * @streamer: The streamer that outputs the TS.
+     * @pid: The pid to remove from the TS output.
+     *
+     * Return: 0 if success, -1 otherwise.
+     *
+     * This function is optional.
+     */
+    int (*remove_pid)(struct dtv_streamer* streamer, int pid);
+
+    /**
+     * open_stream() - Open a stream from a transport description.
+     * @streamer: The streamer which will handle the stream.
+     * @transport_desc: NULL-terminated transport description in json format.
+     *
+     * The streamer will allocate the resources and make the appropriate
+     * connections to handle this transport.
+     * This function returns a file descriptor that can be polled for events.
+     *
+     * Return: A file descriptor if success, -1 otherwise.
+     */
+    int (*open_stream)(struct dtv_streamer* streamer, const char* transport_desc);
+
+    /**
+     * close_stream() - Release an open stream.
+     * @streamer: The streamer from which the stream should be released.
+     */
+    void (*close_stream)(struct dtv_streamer* streamer);
+
+    /**
+     * read_stream() - Read stream data.
+     * @streamer: The streamer to read from.
+     * @buf: The destination buffer.
+     * @count: The number of bytes to read.
+     * @timeout_ms: Timeout in ms.
+     *
+     * Return: The number of bytes read, -1 if error.
+     */
+    ssize_t (*read_stream)(struct dtv_streamer* streamer, void* buf, size_t count, int timeout_ms);
+};
+
+struct dtv_plugin_event {
+    int id;
+    char data[0];
+};
+
+enum {
+    DTV_PLUGIN_EVENT_SIGNAL_LOST = 1,
+    DTV_PLUGIN_EVENT_SIGNAL_READY,
+};
+
+#define PROPERTY_STATISTICS "statistics"
+
+#endif  // LIVE_DTV_PLUGIN_API_H_
diff --git a/tv/tuner/aidl/vts/OWNERS b/tv/tuner/aidl/vts/OWNERS
deleted file mode 100644
index 5b33bf2..0000000
--- a/tv/tuner/aidl/vts/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-# Bug component: 136752
-
-hgchen@google.com
-shubang@google.com
-quxiangfang@google.com
diff --git a/tv/tuner/aidl/vts/functional/Android.bp b/tv/tuner/aidl/vts/functional/Android.bp
index 513007b..09e63fc 100644
--- a/tv/tuner/aidl/vts/functional/Android.bp
+++ b/tv/tuner/aidl/vts/functional/Android.bp
@@ -37,6 +37,7 @@
         "FrontendTests.cpp",
         "LnbTests.cpp",
         "VtsHalTvTunerTargetTest.cpp",
+        "utils/IpStreamer.cpp",
     ],
     generated_headers: [
         "tuner_testing_dynamic_configuration_V1_0_enums",
diff --git a/tv/tuner/aidl/vts/functional/FrontendTests.cpp b/tv/tuner/aidl/vts/functional/FrontendTests.cpp
index b0f614e..b7b0185 100644
--- a/tv/tuner/aidl/vts/functional/FrontendTests.cpp
+++ b/tv/tuner/aidl/vts/functional/FrontendTests.cpp
@@ -475,6 +475,10 @@
             << "FrontendConfig does not match the frontend info of the given id.";
 
     mIsSoftwareFe = config.isSoftwareFe;
+    std::unique_ptr<IpStreamer> ipThread = std::make_unique<IpStreamer>();
+    if (config.type == FrontendType::IPTV) {
+        ipThread->startIpStream();
+    }
     if (mIsSoftwareFe && testWithDemux) {
         if (getDvrTests()->openDvrInDemux(mDvrConfig.type, mDvrConfig.bufferSize) != success()) {
             ALOGW("[vts] Software frontend dvr configure openDvr failed.");
@@ -494,6 +498,9 @@
         getDvrTests()->startDvrPlayback();
     }
     mFrontendCallback->tuneTestOnLock(mFrontend, config.settings);
+    if (config.type == FrontendType::IPTV) {
+        ipThread->stopIpStream();
+    }
     return AssertionResult(true);
 }
 
diff --git a/tv/tuner/aidl/vts/functional/FrontendTests.h b/tv/tuner/aidl/vts/functional/FrontendTests.h
index 1746c8e..9c2ffc0 100644
--- a/tv/tuner/aidl/vts/functional/FrontendTests.h
+++ b/tv/tuner/aidl/vts/functional/FrontendTests.h
@@ -27,6 +27,7 @@
 
 #include "DvrTests.h"
 #include "VtsHalTvTunerTestConfigurations.h"
+#include "utils/IpStreamer.h"
 
 #define WAIT_TIMEOUT 3000000000
 #define INVALID_ID -1
diff --git a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp
index 766814f..671d079 100644
--- a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp
+++ b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp
@@ -684,6 +684,10 @@
     if (!live.hasFrontendConnection) {
         return;
     }
+    // Do not execute tests for IPTV Frontend
+    if (frontendMap[live.frontendId].type == FrontendType::IPTV) {
+        return;
+    }
     auto live_configs = generateLiveConfigurations();
     for (auto& configuration : live_configs) {
         live = configuration;
@@ -780,6 +784,10 @@
     if (!live.hasFrontendConnection) {
         return;
     }
+    // Do not execute tests for IPTV Frontend
+    if (frontendMap[live.frontendId].type == FrontendType::IPTV) {
+        return;
+    }
     // TODO use parameterized tests
     auto live_configs = generateLiveConfigurations();
     for (auto& configuration : live_configs) {
@@ -794,6 +802,10 @@
     if (!live.hasFrontendConnection) {
         return;
     }
+    // Do not execute tests for IPTV Frontend
+    if (frontendMap[live.frontendId].type == FrontendType::IPTV) {
+        return;
+    }
     auto live_configs = generateLiveConfigurations();
     for (auto& configuration : live_configs) {
         live = configuration;
@@ -809,6 +821,10 @@
     if (!live.hasFrontendConnection) {
         return;
     }
+    // Do not execute tests for IPTV Frontend
+    if (frontendMap[live.frontendId].type == FrontendType::IPTV) {
+        return;
+    }
     // TODO use parameterized tests
     auto live_configs = generateLiveConfigurations();
     for (auto& configuration : live_configs) {
@@ -1112,6 +1128,10 @@
     if (!record.support) {
         return;
     }
+    // Do not execute tests for IPTV Frontend
+    if (frontendMap[live.frontendId].type == FrontendType::IPTV) {
+        return;
+    }
     auto record_configs = generateRecordConfigurations();
     for (auto& configuration : record_configs) {
         record = configuration;
@@ -1126,6 +1146,10 @@
     if (!record.support) {
         return;
     }
+    // Do not execute tests for IPTV Frontend
+    if (frontendMap[live.frontendId].type == FrontendType::IPTV) {
+        return;
+    }
     auto record_configs = generateRecordConfigurations();
     for (auto& configuration : record_configs) {
         record = configuration;
@@ -1158,6 +1182,10 @@
     if (!record.support) {
         return;
     }
+    // Do not execute tests for IPTV Frontend
+    if (frontendMap[live.frontendId].type == FrontendType::IPTV) {
+        return;
+    }
     auto record_configs = generateRecordConfigurations();
     for (auto& configuration : record_configs) {
         record = configuration;
@@ -1195,6 +1223,10 @@
     if (!scan.hasFrontendConnection) {
         return;
     }
+    // Blind scan is not applicable for IPTV frontend
+    if (frontendMap[live.frontendId].type == FrontendType::IPTV) {
+        return;
+    }
     vector<ScanHardwareConnections> scan_configs = generateScanConfigurations();
     for (auto& configuration : scan_configs) {
         scan = configuration;
@@ -1223,6 +1255,10 @@
     if (!scan.hasFrontendConnection) {
         return;
     }
+    // Blind scan is not application for IPTV frontend
+    if (frontendMap[live.frontendId].type == FrontendType::IPTV) {
+        return;
+    }
     vector<ScanHardwareConnections> scan_configs = generateScanConfigurations();
     for (auto& configuration : scan_configs) {
         scan = configuration;
@@ -1251,6 +1287,10 @@
 
 TEST_P(TunerFrontendAidlTest, getHardwareInfo) {
     description("Test Frontend get hardware info");
+    // Do not execute tests for IPTV Frontend
+    if (frontendMap[live.frontendId].type == FrontendType::IPTV) {
+        return;
+    }
     if (!live.hasFrontendConnection) {
         return;
     }
@@ -1298,6 +1338,10 @@
     if (!live.hasFrontendConnection) {
         return;
     }
+    // Do not execute tests for IPTV Frontend
+    if (frontendMap[live.frontendId].type == FrontendType::IPTV) {
+        return;
+    }
     auto live_configs = generateLiveConfigurations();
     for (auto& configuration : live_configs) {
         live = configuration;
@@ -1325,6 +1369,10 @@
     if (!live.hasFrontendConnection) {
         return;
     }
+    // Do not execute tests for IPTV Frontend
+    if (frontendMap[live.frontendId].type == FrontendType::IPTV) {
+        return;
+    }
     auto live_configs = generateLiveConfigurations();
     for (auto& configuration : live_configs) {
         live = configuration;
@@ -1354,6 +1402,10 @@
     if (!live.hasFrontendConnection) {
         return;
     }
+    // Do not execute tests for IPTV Frontend
+    if (frontendMap[live.frontendId].type == FrontendType::IPTV) {
+        return;
+    }
     auto live_configs = generateLiveConfigurations();
     for (auto& configuration : live_configs) {
         live = configuration;
@@ -1367,6 +1419,10 @@
     if (!descrambling.support) {
         return;
     }
+    // Do not execute tests for IPTV Frontend
+    if (frontendMap[live.frontendId].type == FrontendType::IPTV) {
+        return;
+    }
     vector<DescramblingHardwareConnections> descrambling_configs =
             generateDescramblingConfigurations();
     if (descrambling_configs.empty()) {
@@ -1403,6 +1459,10 @@
     if (!descrambling.support) {
         return;
     }
+    // Do not execute tests for IPTV Frontend
+    if (frontendMap[live.frontendId].type == FrontendType::IPTV) {
+        return;
+    }
     vector<DescramblingHardwareConnections> descrambling_configs =
             generateDescramblingConfigurations();
     if (descrambling_configs.empty()) {
diff --git a/tv/tuner/aidl/vts/functional/utils/IpStreamer.cpp b/tv/tuner/aidl/vts/functional/utils/IpStreamer.cpp
new file mode 100644
index 0000000..02b2633
--- /dev/null
+++ b/tv/tuner/aidl/vts/functional/utils/IpStreamer.cpp
@@ -0,0 +1,57 @@
+#include "IpStreamer.h"
+
+IpStreamer::IpStreamer() {}
+
+IpStreamer::~IpStreamer() {}
+
+void IpStreamer::startIpStream() {
+    ALOGI("Starting IP Stream thread");
+    mFp = fopen(mFilePath.c_str(), "rb");
+    if (mFp == nullptr) {
+        ALOGE("Failed to open file at path: %s", mFilePath.c_str());
+        return;
+    }
+    mIpStreamerThread = std::thread(&IpStreamer::ipStreamThreadLoop, this, mFp);
+}
+
+void IpStreamer::stopIpStream() {
+    ALOGI("Stopping IP Stream thread");
+    close(mSockfd);
+    if (mFp != nullptr) fclose(mFp);
+    if (mIpStreamerThread.joinable()) {
+        mIpStreamerThread.join();
+    }
+}
+
+void IpStreamer::ipStreamThreadLoop(FILE* fp) {
+    mSockfd = socket(AF_INET, SOCK_DGRAM, 0);
+    if (mSockfd < 0) {
+        ALOGE("IpStreamer::ipStreamThreadLoop: Socket creation failed (%s)", strerror(errno));
+        exit(1);
+    }
+
+    if (mFp == NULL) {
+        ALOGE("IpStreamer::ipStreamThreadLoop: Cannot open file %s: (%s)", mFilePath.c_str(),
+              strerror(errno));
+        exit(1);
+    }
+
+    struct sockaddr_in destaddr;
+    memset(&destaddr, 0, sizeof(destaddr));
+    destaddr.sin_family = mIsIpV4 ? AF_INET : AF_INET6;
+    destaddr.sin_port = htons(mPort);
+    destaddr.sin_addr.s_addr = inet_addr(mIpAddress.c_str());
+
+    char buf[mBufferSize];
+    int n;
+    while (1) {
+        if (fp == nullptr) break;
+        n = fread(buf, 1, mBufferSize, fp);
+        ALOGI("IpStreamer::ipStreamThreadLoop: Bytes read from fread(): %d\n", n);
+        if (n <= 0) {
+            break;
+        }
+        sendto(mSockfd, buf, n, 0, (struct sockaddr*)&destaddr, sizeof(destaddr));
+        sleep(mSleepTime);
+    }
+}
diff --git a/tv/tuner/aidl/vts/functional/utils/IpStreamer.h b/tv/tuner/aidl/vts/functional/utils/IpStreamer.h
new file mode 100644
index 0000000..8ac2ddb
--- /dev/null
+++ b/tv/tuner/aidl/vts/functional/utils/IpStreamer.h
@@ -0,0 +1,48 @@
+#pragma once
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <log/log.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <string>
+#include <thread>
+
+/**
+ * IP Streamer class to send TS data to a specified socket for testing IPTV frontend functions
+ * e.g. tuning and playback.
+ */
+
+class IpStreamer {
+  public:
+    // Constructor for IP Streamer object
+    IpStreamer();
+
+    // Destructor for IP Streamer object
+    ~IpStreamer();
+
+    // Starts a thread to read data from a socket
+    void startIpStream();
+
+    // Stops the reading thread started by startIpStream
+    void stopIpStream();
+
+    // Thread function that consumes data from a socket
+    void ipStreamThreadLoop(FILE* fp);
+
+    std::string getFilePath() { return mFilePath; };
+
+  private:
+    int mSockfd = -1;
+    FILE* mFp = nullptr;
+    bool mIsIpV4 = true;                                         // By default, set to IPV4
+    int mPort = 12345;                                           // default port
+    int mBufferSize = 188;                                       // bytes
+    int mSleepTime = 1;                                          // second
+    std::string mIpAddress = "127.0.0.1";                        // default IP address
+    std::string mFilePath = "/data/local/tmp/segment000000.ts";  // default path for TS file
+    std::thread mIpStreamerThread;
+};
\ No newline at end of file
diff --git a/tv/tuner/config/OWNERS b/tv/tuner/config/OWNERS
deleted file mode 100644
index bf2b609..0000000
--- a/tv/tuner/config/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-hgchen@google.com
-shubang@google.com
-quxiangfang@google.com
diff --git a/usb/OWNERS b/usb/OWNERS
index 2b1d34d..3611b4d 100644
--- a/usb/OWNERS
+++ b/usb/OWNERS
@@ -1,4 +1,8 @@
 # Bug component: 175220
 
+aprasath@google.com
+kumarashishg@google.com
+sarup@google.com
+anothermark@google.com
 albertccwang@google.com
 badhri@google.com
diff --git a/usb/aidl/Android.bp b/usb/aidl/Android.bp
index b82f6d5..b61576d 100644
--- a/usb/aidl/Android.bp
+++ b/usb/aidl/Android.bp
@@ -45,6 +45,6 @@
         },
 
     ],
-    frozen: true,
+    frozen: false,
 
 }
diff --git a/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/ComplianceWarning.aidl b/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/ComplianceWarning.aidl
index 8b67070..c7c9103 100644
--- a/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/ComplianceWarning.aidl
+++ b/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/ComplianceWarning.aidl
@@ -38,4 +38,9 @@
   DEBUG_ACCESSORY = 2,
   BC_1_2 = 3,
   MISSING_RP = 4,
+  INPUT_POWER_LIMITED = 5,
+  MISSING_DATA_LINES = 6,
+  ENUMERATION_FAIL = 7,
+  FLAKY_CONNECTION = 8,
+  UNRELIABLE_IO = 9,
 }
diff --git a/usb/aidl/android/hardware/usb/ComplianceWarning.aidl b/usb/aidl/android/hardware/usb/ComplianceWarning.aidl
index 4c18a31..bf79399 100644
--- a/usb/aidl/android/hardware/usb/ComplianceWarning.aidl
+++ b/usb/aidl/android/hardware/usb/ComplianceWarning.aidl
@@ -56,4 +56,29 @@
      * Type-C Cable and Connector Specification.
      */
     MISSING_RP = 4,
+    /**
+     * Used to indicate the charging setups on the USB ports are unable to
+     * deliver negotiated power.
+     */
+    INPUT_POWER_LIMITED = 5,
+    /**
+     * Used to indicate the cable/connector on the USB ports are missing
+     * the required wires on the data pins to make data transfer.
+     */
+    MISSING_DATA_LINES = 6,
+    /**
+     * Used to indicate enumeration failures on the USB ports, potentially due to
+     * signal integrity issues or other causes.
+     */
+    ENUMERATION_FAIL = 7,
+    /**
+     * Used to indicate unexpected data disconnection on the USB ports,
+     * potentially due to signal integrity issues or other causes.
+     */
+    FLAKY_CONNECTION = 8,
+    /**
+     * Used to indicate unreliable or slow data transfer on the USB ports,
+     * potentially due to signal integrity issues or other causes.
+     */
+    UNRELIABLE_IO = 9,
 }
diff --git a/usb/aidl/default/Android.bp b/usb/aidl/default/Android.bp
index 472e732..ee8e479 100644
--- a/usb/aidl/default/Android.bp
+++ b/usb/aidl/default/Android.bp
@@ -34,7 +34,7 @@
         "Usb.cpp",
     ],
     shared_libs: [
-        "android.hardware.usb-V2-ndk",
+        "android.hardware.usb-V3-ndk",
         "libbase",
         "libbinder_ndk",
         "libcutils",
@@ -43,9 +43,11 @@
     ],
 }
 
-filegroup {
+prebuilt_etc {
     name: "android.hardware.usb-service.example.xml",
-    srcs: ["android.hardware.usb-service.example.xml"],
+    src: "android.hardware.usb-service.example.xml",
+    sub_dir: "vintf",
+    installable: false,
 }
 
 filegroup {
diff --git a/usb/aidl/default/android.hardware.usb-service.example.xml b/usb/aidl/default/android.hardware.usb-service.example.xml
index c3f07f5..7ac2067 100644
--- a/usb/aidl/default/android.hardware.usb-service.example.xml
+++ b/usb/aidl/default/android.hardware.usb-service.example.xml
@@ -1,7 +1,7 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.usb</name>
-        <version>2</version>
+        <version>3</version>
         <interface>
             <name>IUsb</name>
             <instance>default</instance>
diff --git a/usb/aidl/default/apex/Android.bp b/usb/aidl/default/apex/Android.bp
new file mode 100644
index 0000000..29278dd
--- /dev/null
+++ b/usb/aidl/default/apex/Android.bp
@@ -0,0 +1,49 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+apex {
+    name: "com.android.hardware.usb",
+    manifest: "manifest.json",
+    file_contexts: "file_contexts",
+    key: "com.android.hardware.key",
+    certificate: ":com.android.hardware.certificate",
+    updatable: false,
+    vendor: true,
+
+    binaries: ["android.hardware.usb-service.example"],
+    prebuilts: [
+        "com.android.hardware.usb.rc", // init .rc
+        "android.hardware.usb.accessory.prebuilt.xml",
+        "android.hardware.usb.host.prebuilt.xml",
+        "android.hardware.usb-service.example.xml",
+    ],
+}
+
+// Replace the binary path from /vendor/bin to /apex/{name}/bin in the init .rc file
+genrule {
+    name: "com.android.hardware.usb.rc-gen",
+    srcs: [":android.hardware.usb-service.example.rc"],
+    out: ["com.android.hardware.usb.rc"],
+    cmd: "sed -E 's@/vendor/bin@/apex/com.android.hardware.usb/bin@' $(in) > $(out)",
+}
+
+prebuilt_etc {
+    name: "com.android.hardware.usb.rc",
+    src: ":com.android.hardware.usb.rc-gen",
+    installable: false,
+}
diff --git a/usb/aidl/default/apex/file_contexts b/usb/aidl/default/apex/file_contexts
new file mode 100644
index 0000000..53404f7
--- /dev/null
+++ b/usb/aidl/default/apex/file_contexts
@@ -0,0 +1,3 @@
+(/.*)?                                                 u:object_r:vendor_file:s0
+/etc(/.*)?                                             u:object_r:vendor_configs_file:s0
+/bin/hw/android\.hardware\.usb-service\.example        u:object_r:hal_usb_default_exec:s0
\ No newline at end of file
diff --git a/usb/apex/manifest.json b/usb/aidl/default/apex/manifest.json
similarity index 100%
rename from usb/apex/manifest.json
rename to usb/aidl/default/apex/manifest.json
diff --git a/usb/aidl/vts/Android.bp b/usb/aidl/vts/Android.bp
index d0e0eec..cf9299e 100644
--- a/usb/aidl/vts/Android.bp
+++ b/usb/aidl/vts/Android.bp
@@ -34,7 +34,7 @@
         "libbinder_ndk",
     ],
     static_libs: [
-        "android.hardware.usb-V2-ndk",
+        "android.hardware.usb-V3-ndk",
     ],
     test_suites: [
         "general-tests",
diff --git a/usb/aidl/vts/VtsAidlUsbTargetTest.cpp b/usb/aidl/vts/VtsAidlUsbTargetTest.cpp
index e9aa65b..7b7269d 100644
--- a/usb/aidl/vts/VtsAidlUsbTargetTest.cpp
+++ b/usb/aidl/vts/VtsAidlUsbTargetTest.cpp
@@ -654,11 +654,18 @@
   EXPECT_EQ(2, usb_last_cookie);
   EXPECT_EQ(transactionId, last_transactionId);
 
-  // Current compliance values range from [1, 4]
   if (usb_last_port_status.supportsComplianceWarnings) {
     for (auto warning : usb_last_port_status.complianceWarnings) {
       EXPECT_TRUE((int)warning >= (int)ComplianceWarning::OTHER);
-      EXPECT_TRUE((int)warning <= (int)ComplianceWarning::MISSING_RP);
+      /*
+       * Version 2 compliance values range from [1, 4]
+       * Version 3 compliance values range from [1, 9]
+       */
+      if (usb_version < 3) {
+        EXPECT_TRUE((int)warning <= (int)ComplianceWarning::MISSING_RP);
+      } else {
+        EXPECT_TRUE((int)warning <= (int)ComplianceWarning::UNRELIABLE_IO);
+      }
     }
   }
 
diff --git a/usb/apex/Android.bp b/usb/apex/Android.bp
deleted file mode 100644
index 765aa21..0000000
--- a/usb/apex/Android.bp
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright (C) 2021 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package {
-    default_applicable_licenses: ["hardware_interfaces_license"],
-}
-
-apex_key {
-    name: "com.android.hardware.usb.key",
-    public_key: "com.android.hardware.usb.avbpubkey",
-    private_key: "com.android.hardware.usb.pem",
-}
-
-android_app_certificate {
-    name: "com.android.hardware.usb.certificate",
-    certificate: "com.android.hardware.usb",
-}
-
-apex {
-    name: "com.android.hardware.usb",
-    manifest: "manifest.json",
-    file_contexts: "file_contexts",
-    key: "com.android.hardware.usb.key",
-    certificate: ":com.android.hardware.usb.certificate",
-    updatable: false,
-    soc_specific: true,
-    use_vndk_as_stable: true,
-    binaries: ["android.hardware.usb-service.example"],
-    prebuilts: [
-        "com.android.hardware.usb.rc", // init .rc
-        "android.hardware.usb.accessory.prebuilt.xml",
-        "android.hardware.usb.host.prebuilt.xml",
-    ],
-    vintf_fragments: [":android.hardware.usb-service.example.xml"],
-}
-
-// Replace the binary path from /vendor/bin to /apex/{name}/bin in the init .rc file
-genrule {
-    name: "com.android.hardware.usb.rc-gen",
-    srcs: [":android.hardware.usb-service.example.rc"],
-    out: ["com.android.hardware.usb.rc"],
-    cmd: "sed -E 's/\\/vendor/\\/apex\\/com.android.hardware.usb/' $(in) > $(out)",
-}
-
-prebuilt_etc {
-    name: "com.android.hardware.usb.rc",
-    src: ":com.android.hardware.usb.rc-gen",
-    installable: false,
-}
diff --git a/usb/apex/com.android.hardware.usb.avbpubkey b/usb/apex/com.android.hardware.usb.avbpubkey
deleted file mode 100644
index 0302d63..0000000
--- a/usb/apex/com.android.hardware.usb.avbpubkey
+++ /dev/null
Binary files differ
diff --git a/usb/apex/com.android.hardware.usb.pem b/usb/apex/com.android.hardware.usb.pem
deleted file mode 100644
index e1e57da..0000000
--- a/usb/apex/com.android.hardware.usb.pem
+++ /dev/null
@@ -1,51 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIIJKQIBAAKCAgEAwdimmHgIZHrep3H3YfVaNYEAGg45LUEPIiwHV6aIC9V7zjBS
-SftD30Z21jGyk7hmtas6WMI2vRBDNGrZWDgPeiEQoxXQinuU4Ug5S5X2F8LpWs0y
-ZeNFwQkqZwqGdQlkmy8upfb6T7rDxqRv+C0AtGP1r4r36+Xh5ld5stVaMK0UNhZt
-VW0nQAxyeJL3tm0zfiEA9Zu7FF2IyHm+bo9+eJ7WXfjiJfkclLgqlX3ec2cvVqAf
-NHisj18PEd/qtC64b+FnkgbsdHzWbo8HW5x4STkGXNnH+O3dvkWBX60MOfywfZFw
-+yaz5mt7K+ft/V4UA7zKiAEFM+J1lND9/UMJnd0XMYYtcRQF8lmu4dlcjfbbAm0k
-VgoUEsizIeMPLrMj837uVloKKzIXmPsVsfMarP/MrX6TJfzdUhdm01pVO1g0wtHJ
-J3eYQsEnOI7RjL+uZDQvPWAnr71pvacn66PAJC1UPulEEla5lhd30RDItbJkngXp
-3UggW32ZOQt3Oc8P0eo9SCnBlHtCVr8wfxAbxCoPR9qIdX3azkQRqcKqGbBbPnkc
-hSCzeIofUkYGibfbZg4k1yY82xEqZuN7J1zycoGP4wyhXeRLTRWxfPR5dxxmQZaS
-67A1LWrYvAzF8Rd44VMRlI/Qk6zuBsL01j2dfBqit+le+viQmTYb3BpV+1kCAwEA
-AQKCAgAmSfX2LddyiXaLWo6DsePkp5tuihqvHqevl0TIAmPi+oMe4hqO9GueoZt9
-iYl9djILdkvrFkmbpKexpd1SeJhOBlPz8q4jfG+W5B41GOToIp7XSarHx1GS5I2U
-ltaiLX3KzVIIhDVDJF/hT7+yJKl7+DaiOu/nj5vEVMj8EvpinP1eBaYI9quHEi5W
-NKlrRjyikEBRQzZ7ulH3T1zXF87iYnVzUGLTH1aO5aW7q4YSA3KtSKmBQsjK9PrU
-DAefGY9iwgIkLOvtwm7UnbnVVZ3I0NO56WZ/e/SNzcrVLCg7F/eAhgbsBOQKAnbs
-4D35CuknJ9ZVcOYnLncNMw7IRMKULKYLAuLLN1X33y22qaVxYA42rq13mZrijlua
-CMQ2Ur+GNcq8OI3mRDO38yKeJ5b4885LQdlrXXyoGnSjlkU5n8U9Jw6q2rZGiWlk
-4Q71g+KUl0rtXSnFSIJLNTK6Cd3ETStxswLvvCvfLTrRQcO8f2SdVxblmsc9eCDs
-JUxz6Sahkpb9hsY8fozu6laXC/5Ezy0TinRgGjQM/DQqbXtFXgse56mDxzSho5oh
-Spy3X7Q/v4VUtrSKsEZEIEVWCpplzVULpHenCDbU58rHyEcS7ew+kwlfHC73iEhX
-HPujSIKvStO7yCEeY6IdhON8iVX34uvQeAgEe4+rehQHLZUg0QKCAQEA9AS3imKF
-yEt0yNRLcdXSqYkak+OM2kfhBBcLndCT7Terr6yluv/SkPGYjUbmr2XiygMv8IwO
-8f+KbWsNwYCaB22HVYVGL0oUYAlCvWhnia3Iwn6ZZuXuJv5mmfqt/GMlaIfohNLy
-zI2OlcpcAuRfNlenjNyd+inxwdXL28Z86kbabnUlijgqpu4KFOYOlxbTRv93IlfM
-Ico1pZkLS1glDMFLetF+IWq4zqpXrdgNUk1KX3sofOCfZQnlWFrrHbXJPCgPAtlv
-xP4dmJQgtWkWwxUlelfz34LcCUVX2aTlgKjuvgvyCt2ZPWixXbDtjsCBTn3xBhoY
-kDp2OyMC+d543QKCAQEAy11GpYOQvTMKbV07EmN9jTRYg7gRrxsT3Kd4Xy+NpIY8
-v6J5Keeppk9t6WBrJi2cQU/EoHcd3fRkWMnWMNorZDiCu34VG5bfa4pTqnSLdLC4
-/e5UHdHqCy9deAwhlHYWbAx0KnxXWGxkq05dXvQsVuOtAs528NcujnLpwDONQt5P
-e3RIZmOOjr+7rqGp3vA9SuNOINOQpeKxQT6GRGw4mlYofdwOPaE1wCsO8vQCNmCJ
-DEfdm+hWjTLAV2IBCfi5BKRsIAXrABPzkzDeLGDmaQkJTDpK8UQcrFnqItGeo+yl
-fDjxA0zAPWYGcyXcXbtvayX+zCk/SKwQABqUtaumrQKCAQEA0mdizwsGqd8OMsCC
-0QP64j4a0Zvqbqh9yCYK2Sfo9SkEe7SVLnm5WUtIK8EP1fs3ItK+ul454MZj2Nbv
-BINbzL3PbJk/HDV2/hveFS154UgcjD/XC9eEktDXLTvuW2ot7kUJ48V0n5YLdPMI
-hWHfCx9nlFkCSptyHp23aqhqOyOe4pFWLikh9c/Yl46K1BJVWKmcUtt7Y0NVIJWn
-HG9Dew0MhTkv1aaM9X4Bnh9l1SpZz5yFG7AfIGL5A0dZ5cNCYgF0eBN+gVBPuqk2
-ztVvUATizOwblwThr4jAKCU70sVXHj10lZPftwiXrt6I54brt/92HLnRpkMSgQk+
-Xq9KbQKCAQAXxPM47UPBmXGijr8UyyQlmPSvkJggi12q8LgVCA3aKQZ4r5jR2Q3v
-LmF+YZKkh7g3ugcValbHVoVUC2NJmnZv5FsDZx04eE3s1+Inji+ul+lHZM/YHGzq
-mcKnAWP7YkIEpv/850OeRi0OCL7JFmkITtwt88vbIouCgtPnbx8XrbxEhbbgoMpM
-zQQ2yRZ9xD6lviOnmpLRkMl/ArvWy39iKqfY7huMAIezylSY+QQ5LtdV5CB21JUp
-M8FfdUkBzVxyunUY2Rg6jhpuHcwaC8lihXfcvQN9Z6SiUHAZWb7dEg/VkSI6bIIb
-qw0d8FLtcbb4IxzA6CFJcTL9kB3JjiKRAoIBAQC15t3mQHb9iCM4P4U9fpR4syvN
-46vDMhtj3vejerzOro2R7UUCJDvT59DrCQvtKO/ZCyhdTyuyResu6r1vbwq3KWiB
-i0RIeW87cKgJRr6w+KivB+a805WfI9zNRz778b7ajEpBkOs4vRPWu6S1306tdvgM
-Dhj7GT9UFh/k7pNuoSbiuaPUqgZRP55nzgj/FoIN985wnxo/ugckSqZ1bFGFXhYt
-zfIdFvPkf1BlLCnLTE8yESsJ3P37Gfj2XRv9h2I2/8qAGZniKtbVWHlu+5LDJf6V
-x9VpDAH2ZQAqRC3za3gfTjMsglYi7mUDeMYlB4osURNt7jDtElEmsto7AAkI
------END RSA PRIVATE KEY-----
diff --git a/usb/apex/com.android.hardware.usb.pk8 b/usb/apex/com.android.hardware.usb.pk8
deleted file mode 100644
index 9f3f39b..0000000
--- a/usb/apex/com.android.hardware.usb.pk8
+++ /dev/null
Binary files differ
diff --git a/usb/apex/com.android.hardware.usb.x509.pem b/usb/apex/com.android.hardware.usb.x509.pem
deleted file mode 100644
index 210c30d..0000000
--- a/usb/apex/com.android.hardware.usb.x509.pem
+++ /dev/null
@@ -1,34 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIF1TCCA70CFFEdsyLGoTRk+VIzqb6aDl1tXeuZMA0GCSqGSIb3DQEBCwUAMIGl
-MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91
-bnRhaW4gVmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UECwwHQW5kcm9pZDEi
-MCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTEhMB8GA1UEAwwYY29t
-LmFuZHJvaWQuaGFyZHdhcmUudXNiMCAXDTIxMTExNzIyMzAwM1oYDzQ3NTkxMDE0
-MjIzMDAzWjCBpTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAU
-BgNVBAcMDU1vdW50YWluIFZpZXcxEDAOBgNVBAoMB0FuZHJvaWQxEDAOBgNVBAsM
-B0FuZHJvaWQxIjAgBgkqhkiG9w0BCQEWE2FuZHJvaWRAYW5kcm9pZC5jb20xITAf
-BgNVBAMMGGNvbS5hbmRyb2lkLmhhcmR3YXJlLnVzYjCCAiIwDQYJKoZIhvcNAQEB
-BQADggIPADCCAgoCggIBAM2E0E9ubNU/or7r9UIcFrC4l7CeM0HwtwSjTUKV1Z9K
-7rPFoUPE3cQ+cResnWQay8IGnomLYptAIMe8sLCC83LwU1ucTihxX87qq2W3V14w
-U4AkqDzNvYqKiD3yz9WofKxcu7ut8+1O4Pvp11X8UXuy5kNzf8WGpGB04k6U6KtA
-q8+U8+4h9h1Uvhaa0AeG9Yp22LzRLTb3J+eCoGHJnjoXYsd9T/gvedyXKkuf0lWB
-b3Aor3/CQrpdCW2/iJbuASdBdfilpQShaagxy2wmQsYxnT8ZWf+tIDYjg3xqqVPl
-GChFwCQBdaTuLI/k9gbaXkSxuzRkp5wc/ELhYbkhIS25yefAF2C6num++AHQBh1+
-qO0fHztsK80c5cVoDPWu17/nP7y3QloRyLFUrL3hVW1RQaFwE2Hmv4H0UwVAsleU
-ZIsz2ifTjiSl/tnkFTx0I6BVk7T87QhO3WXN4v6VDYZKeD4gQYS0NfwplahejrFw
-s3EcwKgt6f0KlIpzoEQBmNQBXxsRgL31GWCwCszb7+VrTMzgUpO41R3PyewbeaZk
-S/SHyEOwyf0WIvnZhZ/5CNd9qirClu6jS8kdLvwC2qA25VqSPw126EX1e2xUqm02
-C/6c7JDVocuQhvsJOnnpZt68Iwgw9g/xLCLA9RszH9ccRctZqRnzHB1AjTrBOq0P
-AgMBAAEwDQYJKoZIhvcNAQELBQADggIBAELbSot2Io/JZIYLTxgeReI4lk1KUzf8
-fGlDNlRm+goxOHXWQgvXgiftwM9IOB+H+EtNHAA9Q6ojAmfRe6rZC4p0ZxWOamtR
-V+pQj0c6Zvx8HJPMQdyoHx538iNXM093s2wnf+QuACb3BnvkK7uuLGAlIzWdImtL
-DKKFN05nppViY04tGP5HgT57b7YGwdkEp6euCJcyWIKjlyEH/bwTWM8ws/Px6uhw
-+5W2K7KrBsdRKPBF7qwXoS8Ak8pS5de9Xd7mbGBLaUtjsZ0pJbq0aFpuT0GbLWUm
-wiD5Ljq3ea/2GZxbHGiXQ2yNjFSd/jpuxDnnm99t7+HGw1v5Jld+hUVqXXfVNhWe
-hUKIv5TOk1nttNdsaLyDtxyt22JX7NnoPM0MqrkYwA8Xqrbv0VC8D/CVjiBC9Tce
-crhpCISNfQSkdEn/c+q/naFUvQy8oYqXkg1TjeGlcxwJOpGliYbbYT6VAwuI/ssI
-yX3Fkr8f5KhfN2aFnOpidknmLp9EyL2j5bxAtSD9xAHtczMn10uCUdLELjRB1L4f
-1qY+EjpIgK0NIFuEt9K5uZXirXq3K3eixKeJFNji3x/X8NgDALSdnT8JIlSg4DMg
-iWupLrQ9CSHMlgh5P43ALamiRIHQNqEwgj8OIGzsvQTSLbRjbPWYcDZa+Q1hosiA
-Fv7vjDI6oySM
------END CERTIFICATE-----
diff --git a/usb/apex/file_contexts b/usb/apex/file_contexts
deleted file mode 100644
index f223a56..0000000
--- a/usb/apex/file_contexts
+++ /dev/null
@@ -1,5 +0,0 @@
-(/.*)?                                         u:object_r:vendor_file:s0
-# Permission XMLs
-/etc/permissions(/.*)?                         u:object_r:vendor_configs_file:s0
-# binary
-/bin/hw/android\.hardware\.usb-service\.example        u:object_r:hal_usb_default_exec:s0
\ No newline at end of file
diff --git a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
index 25d704e..58919d1 100644
--- a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
+++ b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
@@ -34,23 +34,26 @@
 package android.hardware.uwb.fira_android;
 @Backing(type="int") @VintfStability
 enum UwbVendorCapabilityTlvTypes {
-  SUPPORTED_POWER_STATS_QUERY = 192,
-  CCC_SUPPORTED_CHAPS_PER_SLOT = 160,
-  CCC_SUPPORTED_SYNC_CODES = 161,
-  CCC_SUPPORTED_HOPPING_CONFIG_MODES_AND_SEQUENCES = 162,
-  CCC_SUPPORTED_CHANNELS = 163,
-  CCC_SUPPORTED_VERSIONS = 164,
-  CCC_SUPPORTED_UWB_CONFIGS = 165,
-  CCC_SUPPORTED_PULSE_SHAPE_COMBOS = 166,
-  CCC_SUPPORTED_RAN_MULTIPLIER = 167,
-  CCC_SUPPORTED_MAX_RANGING_SESSION_NUMBER = 168,
-  CCC_SUPPORTED_MIN_UWB_INITIATION_TIME_MS = 169,
-  SUPPORTED_AOA_RESULT_REQ_ANTENNA_INTERLEAVING = 227,
-  SUPPORTED_MIN_RANGING_INTERVAL_MS = 228,
-  SUPPORTED_RANGE_DATA_NTF_CONFIG = 229,
-  SUPPORTED_RSSI_REPORTING = 230,
-  SUPPORTED_DIAGNOSTICS = 231,
-  SUPPORTED_MIN_SLOT_DURATION_RSTU = 232,
-  SUPPORTED_MAX_RANGING_SESSION_NUMBER = 233,
-  SUPPORTED_CHANNELS_AOA = 234,
+  SUPPORTED_POWER_STATS_QUERY = 0xC0,
+  CCC_SUPPORTED_CHAPS_PER_SLOT = 0xA0,
+  CCC_SUPPORTED_SYNC_CODES = 0xA1,
+  CCC_SUPPORTED_HOPPING_CONFIG_MODES_AND_SEQUENCES = 0xA2,
+  CCC_SUPPORTED_CHANNELS = 0xA3,
+  CCC_SUPPORTED_VERSIONS = 0xA4,
+  CCC_SUPPORTED_UWB_CONFIGS = 0xA5,
+  CCC_SUPPORTED_PULSE_SHAPE_COMBOS = 0xA6,
+  CCC_SUPPORTED_RAN_MULTIPLIER = 0xA7,
+  CCC_SUPPORTED_MAX_RANGING_SESSION_NUMBER = 0xA8,
+  CCC_SUPPORTED_MIN_UWB_INITIATION_TIME_MS = 0xA9,
+  CCC_PRIORITIZED_CHANNEL_LIST = 0xAA,
+  CCC_SUPPORTED_UWBS_MAX_PPM = 0xAB,
+  RADAR_SUPPORT = 0xB0,
+  SUPPORTED_AOA_RESULT_REQ_ANTENNA_INTERLEAVING = 0xE3,
+  SUPPORTED_MIN_RANGING_INTERVAL_MS = 0xE4,
+  SUPPORTED_RANGE_DATA_NTF_CONFIG = 0xE5,
+  SUPPORTED_RSSI_REPORTING = 0xE6,
+  SUPPORTED_DIAGNOSTICS = 0xE7,
+  SUPPORTED_MIN_SLOT_DURATION_RSTU = 0xE8,
+  SUPPORTED_MAX_RANGING_SESSION_NUMBER = 0xE9,
+  SUPPORTED_CHANNELS_AOA = 0xEA,
 }
diff --git a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvValues.aidl b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvValues.aidl
index 0e33f70..702e561 100644
--- a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvValues.aidl
+++ b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvValues.aidl
@@ -40,17 +40,19 @@
   PULSE_SHAPE_PRECURSOR_FREE = 1,
   PULSE_SHAPE_PRECURSOR_FREE_SPECIAL = 2,
   CHAPS_PER_SLOT_3 = 1,
-  CHAPS_PER_SLOT_4 = 2,
-  CHAPS_PER_SLOT_6 = 4,
-  CHAPS_PER_SLOT_8 = 8,
-  CHAPS_PER_SLOT_9 = 16,
-  CHAPS_PER_SLOT_12 = 32,
-  CHAPS_PER_SLOT_24 = 64,
-  HOPPING_SEQUENCE_DEFAULT = 16,
-  HOPPING_SEQUENCE_AES = 8,
-  HOPPING_CONFIG_MODE_NONE = 128,
-  HOPPING_CONFIG_MODE_CONTINUOUS = 64,
-  HOPPING_CONFIG_MODE_ADAPTIVE = 32,
+  CHAPS_PER_SLOT_4 = (1 << 1) /* 2 */,
+  CHAPS_PER_SLOT_6 = (1 << 2) /* 4 */,
+  CHAPS_PER_SLOT_8 = (1 << 3) /* 8 */,
+  CHAPS_PER_SLOT_9 = (1 << 4) /* 16 */,
+  CHAPS_PER_SLOT_12 = (1 << 5) /* 32 */,
+  CHAPS_PER_SLOT_24 = (1 << 6) /* 64 */,
+  HOPPING_SEQUENCE_DEFAULT = (1 << 4) /* 16 */,
+  HOPPING_SEQUENCE_AES = (1 << 3) /* 8 */,
+  HOPPING_CONFIG_MODE_NONE = (1 << 7) /* 128 */,
+  HOPPING_CONFIG_MODE_CONTINUOUS = (1 << 6) /* 64 */,
+  HOPPING_CONFIG_MODE_ADAPTIVE = (1 << 5) /* 32 */,
   CCC_CHANNEL_5 = 1,
-  CCC_CHANNEL_9 = 2,
+  CCC_CHANNEL_9 = (1 << 1) /* 2 */,
+  RADAR_NOT_SUPPORTED = 0,
+  RADAR_SWEEP_SAMPLES_SUPPORTED = 1,
 }
diff --git a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorDataPacketFormat.aidl b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorDataPacketFormat.aidl
new file mode 100644
index 0000000..efafa32
--- /dev/null
+++ b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorDataPacketFormat.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.uwb.fira_android;
+@Backing(type="byte") @VintfStability
+enum UwbVendorDataPacketFormat {
+  RADAR_DATA_MESSAGE = 0xF,
+}
diff --git a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl
index fbcfbff..1506406 100644
--- a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl
+++ b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl
@@ -34,7 +34,9 @@
 package android.hardware.uwb.fira_android;
 @Backing(type="byte") @VintfStability
 enum UwbVendorGidAndroidOids {
-  ANDROID_GET_POWER_STATS = 0,
-  ANDROID_SET_COUNTRY_CODE = 1,
-  ANDROID_RANGE_DIAGNOSTICS = 2,
+  ANDROID_GET_POWER_STATS = 0x0,
+  ANDROID_SET_COUNTRY_CODE = 0x1,
+  ANDROID_RANGE_DIAGNOSTICS = 0x2,
+  RADAR_SET_APP_CONFIG = 0x11,
+  RADAR_GET_APP_CONFIG = 0x12,
 }
diff --git a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorGids.aidl b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorGids.aidl
index 5515c67..f02ed70 100644
--- a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorGids.aidl
+++ b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorGids.aidl
@@ -34,5 +34,5 @@
 package android.hardware.uwb.fira_android;
 @Backing(type="byte") @VintfStability
 enum UwbVendorGids {
-  ANDROID = 12,
+  ANDROID = 0xC,
 }
diff --git a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorRadarAppConfigTlvTypes.aidl b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorRadarAppConfigTlvTypes.aidl
new file mode 100644
index 0000000..760166c
--- /dev/null
+++ b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorRadarAppConfigTlvTypes.aidl
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.uwb.fira_android;
+@Backing(type="int") @VintfStability
+enum UwbVendorRadarAppConfigTlvTypes {
+  RADAR_TIMING_PARAMS = 0x0,
+  SAMPLES_PER_SWEEP = 0x1,
+  RADAR_CHANNEL_NUMBER = 0x2,
+  SWEEP_OFFSET = 0x3,
+  RADAR_RFRAME_CONFIG = 0x4,
+  RADAR_PREAMBLE_DURATION = 0x5,
+  RADAR_PREAMBLE_CODE_INDEX = 0x6,
+  RADAR_SESSION_PRIORITY = 0x7,
+  BITS_PER_SAMPLE = 0x8,
+  RADAR_PRF_MODE = 0x9,
+  NUMBER_OF_BURSTS = 0xA,
+  RADAR_DATA_TYPE = 0xB,
+}
diff --git a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorRadarAppConfigTlvValues.aidl b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorRadarAppConfigTlvValues.aidl
new file mode 100644
index 0000000..1eb2ce9
--- /dev/null
+++ b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorRadarAppConfigTlvValues.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.uwb.fira_android;
+@Backing(type="int") @VintfStability
+enum UwbVendorRadarAppConfigTlvValues {
+  RADAR_DATA_TYPE_RADAR_SWEEP_SAMPLES = 0x0,
+}
diff --git a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorReasonCodes.aidl b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorReasonCodes.aidl
index a438cbe..db1e0db 100644
--- a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorReasonCodes.aidl
+++ b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorReasonCodes.aidl
@@ -34,7 +34,7 @@
 package android.hardware.uwb.fira_android;
 @Backing(type="int") @VintfStability
 enum UwbVendorReasonCodes {
-  REASON_ERROR_INVALID_CHANNEL_WITH_AOA = 128,
-  REASON_ERROR_STOPPED_DUE_TO_OTHER_SESSION_CONFLICT = 129,
-  REASON_REGULATION_UWB_OFF = 130,
+  REASON_ERROR_INVALID_CHANNEL_WITH_AOA = 0x80,
+  REASON_ERROR_STOPPED_DUE_TO_OTHER_SESSION_CONFLICT = 0x81,
+  REASON_REGULATION_UWB_OFF = 0x82,
 }
diff --git a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorSessionAppConfigTlvTypes.aidl b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorSessionAppConfigTlvTypes.aidl
index c3ac401..d02cf4d 100644
--- a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorSessionAppConfigTlvTypes.aidl
+++ b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorSessionAppConfigTlvTypes.aidl
@@ -34,16 +34,16 @@
 package android.hardware.uwb.fira_android;
 @Backing(type="int") @VintfStability
 enum UwbVendorSessionAppConfigTlvTypes {
-  CCC_HOP_MODE_KEY = 160,
-  CCC_UWB_TIME0 = 161,
-  CCC_RANGING_PROTOCOL_VER = 163,
-  CCC_UWB_CONFIG_ID = 164,
-  CCC_PULSESHAPE_COMBO = 165,
-  CCC_URSK_TTL = 166,
-  CCC_LAST_INDEX_USED = 168,
-  NB_OF_RANGE_MEASUREMENTS = 227,
-  NB_OF_AZIMUTH_MEASUREMENTS = 228,
-  NB_OF_ELEVATION_MEASUREMENTS = 229,
-  ENABLE_DIAGNOSTICS = 232,
-  DIAGRAMS_FRAME_REPORTS_FIELDS = 233,
+  CCC_HOP_MODE_KEY = 0xA0,
+  CCC_UWB_TIME0 = 0xA1,
+  CCC_RANGING_PROTOCOL_VER = 0xA3,
+  CCC_UWB_CONFIG_ID = 0xA4,
+  CCC_PULSESHAPE_COMBO = 0xA5,
+  CCC_URSK_TTL = 0xA6,
+  CCC_LAST_INDEX_USED = 0xA8,
+  NB_OF_RANGE_MEASUREMENTS = 0xE3,
+  NB_OF_AZIMUTH_MEASUREMENTS = 0xE4,
+  NB_OF_ELEVATION_MEASUREMENTS = 0xE5,
+  ENABLE_DIAGNOSTICS = 0xE8,
+  DIAGRAMS_FRAME_REPORTS_FIELDS = 0xE9,
 }
diff --git a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorSessionAppConfigTlvValues.aidl b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorSessionAppConfigTlvValues.aidl
index a7f487b..5216e1f 100644
--- a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorSessionAppConfigTlvValues.aidl
+++ b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorSessionAppConfigTlvValues.aidl
@@ -34,5 +34,5 @@
 package android.hardware.uwb.fira_android;
 @Backing(type="int") @VintfStability
 enum UwbVendorSessionAppConfigTlvValues {
-  AOA_RESULT_REQ_ANTENNA_INTERLEAVING = 240,
+  AOA_RESULT_REQ_ANTENNA_INTERLEAVING = 0xF0,
 }
diff --git a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorSessionInitSessionType.aidl b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorSessionInitSessionType.aidl
index 30a0a1b..bf968bd 100644
--- a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorSessionInitSessionType.aidl
+++ b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorSessionInitSessionType.aidl
@@ -34,5 +34,6 @@
 package android.hardware.uwb.fira_android;
 @Backing(type="int") @VintfStability
 enum UwbVendorSessionInitSessionType {
-  CCC = 160,
+  CCC = 0xA0,
+  RADAR = 0xA1,
 }
diff --git a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorStatusCodes.aidl b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorStatusCodes.aidl
index 28cf7fe..52f1350 100644
--- a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorStatusCodes.aidl
+++ b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorStatusCodes.aidl
@@ -34,8 +34,8 @@
 package android.hardware.uwb.fira_android;
 @Backing(type="byte") @VintfStability
 enum UwbVendorStatusCodes {
-  STATUS_ERROR_CCC_SE_BUSY = 80,
-  STATUS_ERROR_CCC_LIFECYCLE = 81,
-  STATUS_ERROR_STOPPED_DUE_TO_OTHER_SESSION_CONFLICT = 82,
-  STATUS_REGULATION_UWB_OFF = 83,
+  STATUS_ERROR_CCC_SE_BUSY = 0x50,
+  STATUS_ERROR_CCC_LIFECYCLE = 0x51,
+  STATUS_ERROR_STOPPED_DUE_TO_OTHER_SESSION_CONFLICT = 0x52,
+  STATUS_REGULATION_UWB_OFF = 0x53,
 }
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/README.md b/uwb/aidl/android/hardware/uwb/fira_android/README.md
index e658d93..7912bbc 100644
--- a/uwb/aidl/android/hardware/uwb/fira_android/README.md
+++ b/uwb/aidl/android/hardware/uwb/fira_android/README.md
@@ -10,6 +10,3 @@
 All other interactions sent/received over the HAL interface is expected to
 comply with the UCI specification that can be found [here](
 https://groups.firaconsortium.org/wg/Technical/document/folder/127).
-
-TODO([b/196004116](b/196004116)): Link to the published specification.
-
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
index 22b7bfe..4df45b6 100644
--- a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
@@ -149,6 +149,26 @@
      */
     CCC_SUPPORTED_MIN_UWB_INITIATION_TIME_MS = 0xA9,
 
+    /**
+     * Byte array of channels supported by the device, ordered by priority from highest to lowest.
+     */
+    CCC_PRIORITIZED_CHANNEL_LIST = 0xAA,
+
+    /**
+     * Short (2-octet) value to indicate the UWBS Max Clock Skew PPM value.
+     */
+    CCC_SUPPORTED_UWBS_MAX_PPM = 0xAB,
+
+    /*********************************************
+     * RADAR specific
+     ********************************************/
+    /**
+     * 1 byte bitmask to indicate the supported Radar data types.
+     * Each "1" in this bitmap corresponds to a specific radar data type where:
+     * 0x01 = "Radar Sweep Samples",
+     */
+    RADAR_SUPPORT = 0xB0,
+
     /*********************************************
      * FIRA specific
      ********************************************/
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvValues.aidl b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvValues.aidl
index 7c86b79..6ef52fe 100644
--- a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvValues.aidl
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvValues.aidl
@@ -51,4 +51,10 @@
 
     CCC_CHANNEL_5 = 1,
     CCC_CHANNEL_9 = 1 << 1,
+
+    /*********************************************
+     * RADAR specific
+     ********************************************/
+    RADAR_NOT_SUPPORTED = 0,
+    RADAR_SWEEP_SAMPLES_SUPPORTED = 1,
 }
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorDataPacketFormat.aidl b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorDataPacketFormat.aidl
new file mode 100644
index 0000000..7a1b033
--- /dev/null
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorDataPacketFormat.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.uwb.fira_android;
+
+/**
+ * Android specific vendor DPF (Data Packet Format) should be defined here.
+ */
+@VintfStability
+@Backing(type="byte")
+enum UwbVendorDataPacketFormat {
+    // Used to send radar data messages from UWBS to the host.
+    RADAR_DATA_MESSAGE = 0xF,
+}
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl
index 4768f55..95c10a8 100644
--- a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl
@@ -37,4 +37,13 @@
     // Supported only if the UwbVendorCapabilityTlvTypes.SUPPORTED_DIAGNOSTICS set
     // to 1.
     ANDROID_RANGE_DIAGNOSTICS = 0x2,
+
+    /*********************************************
+     * Range 0x10 - 0x1F reserved for RADAR specific
+     * Supported only if the UwbVendorCapabilityTlvTypes.RADAR_SUPPORT is not 0x00.
+     ********************************************/
+    // Used to set application configurations for radar session.
+    RADAR_SET_APP_CONFIG = 0x11,
+    // Used to get application configurations for radar session.
+    RADAR_GET_APP_CONFIG = 0x12,
 }
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorRadarAppConfigTlvTypes.aidl b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorRadarAppConfigTlvTypes.aidl
new file mode 100644
index 0000000..a5ea688
--- /dev/null
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorRadarAppConfigTlvTypes.aidl
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.uwb.fira_android;
+
+/**
+ * Android specific radar app params set/expected in UCI command:
+ * GID: 1100b (Android specific Group)
+ * OID: 010001b (RADAR_SET_APP_CONFIG_CMD)
+ * OID: 010010b (RADAR_GET_APP_CONFIG_CMD)
+ */
+@VintfStability
+@Backing(type="int")
+enum UwbVendorRadarAppConfigTlvTypes {
+    /**
+     * 7 byte data
+     * Radar frame timing parameters:
+     * Octet [3:0] - BURST_PERIOD
+     *   Duration between the start of two consecutive Radar bursts in ms.
+     * Octet [5:4] - SWEEP_PERIOD
+     *   Duration between the start times of two consecutive Radar sweeps in
+     *   RSTU.
+     * Octet [6] - SWEEPS_PER_BURST
+     *   Number of Radar sweeps within the Radar burst.
+     */
+    RADAR_TIMING_PARAMS = 0x0,
+    /**
+     * 1 byte data
+     * The number of samples captured for each radar sweep. (default = 64)
+     */
+    SAMPLES_PER_SWEEP = 0x1,
+    /**
+     * 1 byte data
+     * Same as in FiRa UCI Session App Config.
+     * (default = 9)
+     */
+    RADAR_CHANNEL_NUMBER = 0x2,
+    /**
+     * 2 byte data
+     * Defines the start offset with respect to 0cm distance to limit the sweep
+     * range. Signed value and unit in samples.
+     * (default = 0)
+     */
+    SWEEP_OFFSET = 0x3,
+    /**
+     * 1 byte data
+     * Same as in FiRa UCI Session App Config.
+     * (default = 0x0)
+     */
+    RADAR_RFRAME_CONFIG = 0x4,
+    /**
+     * 1 byte data
+     * Same as in FiRa UCI Session App Config, but extended to 0xA.
+     * (default = 0x2 : 128 symbols)
+     */
+    RADAR_PREAMBLE_DURATION = 0x5,
+    /**
+     * 1 byte data
+     * Same as in FiRa UCI Session App Config, but extended to 127.
+     * (default = 25)
+     */
+    RADAR_PREAMBLE_CODE_INDEX = 0x6,
+    /**
+     * 1 byte data
+     * Same as in FiRa UCI Session App Config.
+     * (default = 50)
+     */
+    RADAR_SESSION_PRIORITY = 0x7,
+    /**
+     * 1 byte data
+     * Bits per sample in the radar sweep.
+     * 0x00 = 32 bits per sample (default)
+     * 0x01 = 48 bits per sample
+     * 0x02 = 64 bits per sample
+     */
+    BITS_PER_SAMPLE = 0x8,
+    /**
+     * 1 byte data
+     * Same as in FiRa UCI Session App Config.
+     * (default = 0x1)
+     */
+    RADAR_PRF_MODE = 0x9,
+    /**
+     * 2 byte data
+     * Maximum number of Radar bursts to be executed in the session. The
+     * session is stopped and moved to SESSION_STATE_IDLE Session State when
+     * configured radar bursts are elapsed.
+     * 0x00 = Unlimited (default)
+     */
+    NUMBER_OF_BURSTS = 0xA,
+    /**
+     * 2 byte data
+     * Type of radar data to be reported.
+     * 0x00: Radar Sweep Samples. Reported in RADAR_DATA_NTF. (default)
+     */
+    RADAR_DATA_TYPE = 0xB,
+}
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorRadarAppConfigTlvValues.aidl b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorRadarAppConfigTlvValues.aidl
new file mode 100644
index 0000000..81c0a4d
--- /dev/null
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorRadarAppConfigTlvValues.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.uwb.fira_android;
+
+/**
+ * Android specific radar app config values set/expected in UCI command:
+ * GID: 1100b (Android specific Group)
+ * OID: 010001b (RADAR_SET_APP_CONFIG_CMD)
+ * OID: 010010b (RADAR_GET_APP_CONFIG_CMD)
+ */
+@VintfStability
+@Backing(type="int")
+enum UwbVendorRadarAppConfigTlvValues {
+    RADAR_DATA_TYPE_RADAR_SWEEP_SAMPLES = 0x0,
+}
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorSessionInitSessionType.aidl b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorSessionInitSessionType.aidl
index 1e2c817..d3df672 100644
--- a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorSessionInitSessionType.aidl
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorSessionInitSessionType.aidl
@@ -29,4 +29,5 @@
 enum UwbVendorSessionInitSessionType {
     /** Added in vendor version 0. */
     CCC = 0xA0,
+    RADAR = 0xA1,
 }
diff --git a/uwb/aidl/default/Android.bp b/uwb/aidl/default/Android.bp
index 9621f2c..8af1678 100644
--- a/uwb/aidl/default/Android.bp
+++ b/uwb/aidl/default/Android.bp
@@ -11,17 +11,21 @@
     name: "android.hardware.uwb-service",
     crate_name: "uwb_default_hal",
     relative_install_path: "hw",
-    vintf_fragments: ["uwb-service.xml"],
     vendor: true,
+    prefer_rlib: true,
     rustlibs: [
         "android.hardware.uwb-V1-rust",
+        "liblibc",
         "liblogger",
         "liblog_rust",
         "libbinder_rs",
         "libbinder_tokio_rs",
         "libtokio",
+        "libtokio_util",
         "libnix",
         "libanyhow",
+        "libpdl_runtime",
+        "libuwb_uci_packets",
     ],
     proc_macros: [
         "libasync_trait",
@@ -30,3 +34,36 @@
         "src/service.rs",
     ],
 }
+
+prebuilt_etc {
+    name: "uwb-service.rc",
+    src: "uwb-service.rc",
+    vendor: true,
+    installable: false,
+}
+
+prebuilt_etc {
+    name: "uwb-service.xml",
+    src: "uwb-service.xml",
+    sub_dir: "vintf",
+    vendor: true,
+    installable: false,
+}
+
+apex {
+    name: "com.android.hardware.uwb",
+    manifest: "manifest.json",
+    file_contexts: "file_contexts",
+    key: "com.android.hardware.key",
+    certificate: ":com.android.hardware.certificate",
+    updatable: false,
+    vendor: true,
+
+    binaries: [
+        "android.hardware.uwb-service",
+    ],
+    prebuilts: [
+        "uwb-service.rc", // init_rc
+        "uwb-service.xml", // vintf_fragments
+    ],
+}
diff --git a/uwb/aidl/default/file_contexts b/uwb/aidl/default/file_contexts
new file mode 100644
index 0000000..6ec53ed
--- /dev/null
+++ b/uwb/aidl/default/file_contexts
@@ -0,0 +1,3 @@
+(/.*)?                                          u:object_r:vendor_file:s0
+/etc(/.*)?                                      u:object_r:vendor_configs_file:s0
+/bin/hw/android\.hardware\.uwb-service          u:object_r:hal_uwb_default_exec:s0
\ No newline at end of file
diff --git a/uwb/aidl/default/manifest.json b/uwb/aidl/default/manifest.json
new file mode 100644
index 0000000..3f2f911
--- /dev/null
+++ b/uwb/aidl/default/manifest.json
@@ -0,0 +1,4 @@
+{
+    "name": "com.android.hardware.uwb",
+    "version": 1
+}
diff --git a/uwb/aidl/default/src/uwb_chip.rs b/uwb/aidl/default/src/uwb_chip.rs
index 7c2c300..d1c3c67 100644
--- a/uwb/aidl/default/src/uwb_chip.rs
+++ b/uwb/aidl/default/src/uwb_chip.rs
@@ -4,32 +4,36 @@
 };
 use android_hardware_uwb::binder;
 use async_trait::async_trait;
-use binder::{Result, Strong};
+use binder::{DeathRecipient, IBinder, Result, Strong};
 
-use tokio::fs::File;
-use tokio::io::{AsyncReadExt, AsyncWriteExt};
+use std::sync::Arc;
+use tokio::io::unix::AsyncFd;
+use tokio::select;
 use tokio::sync::Mutex;
+use tokio_util::sync::CancellationToken;
 
-use std::os::fd::AsRawFd;
+use std::fs::{File, OpenOptions};
+use std::io::{self, Read, Write};
+use std::os::unix::fs::OpenOptionsExt;
 
-use std::io;
-
-use nix::sys::termios;
+use pdl_runtime::Packet;
+use uwb_uci_packets::{DeviceResetCmdBuilder, ResetConfig, UciControlPacket, UciControlPacketHal};
 
 enum State {
     Closed,
     Opened {
         callbacks: Strong<dyn IUwbClientCallback>,
-        #[allow(dead_code)]
-        tasks: tokio::task::JoinSet<()>,
-        write: File,
+        handle: tokio::task::JoinHandle<()>,
+        serial: File,
+        death_recipient: DeathRecipient,
+        token: CancellationToken,
     },
 }
 
 pub struct UwbChip {
     name: String,
     path: String,
-    state: Mutex<State>,
+    state: Arc<Mutex<State>>,
 }
 
 impl UwbChip {
@@ -37,23 +41,92 @@
         Self {
             name,
             path,
-            state: Mutex::new(State::Closed),
+            state: Arc::new(Mutex::new(State::Closed)),
         }
     }
 }
 
+impl State {
+    /// Terminate the reader task.
+    async fn close(&mut self) -> Result<()> {
+        if let State::Opened {
+            ref mut token,
+            ref callbacks,
+            ref mut death_recipient,
+            ref mut handle,
+            ref mut serial,
+        } = *self
+        {
+            log::info!("waiting for task cancellation");
+            callbacks.as_binder().unlink_to_death(death_recipient)?;
+            token.cancel();
+            handle.await.unwrap();
+            let packet: UciControlPacket = DeviceResetCmdBuilder {
+                reset_config: ResetConfig::UwbsReset,
+            }
+            .build()
+            .into();
+            // DeviceResetCmd need to be send to reset the device to stop all running
+            // activities on UWBS.
+            let packet_vec: Vec<UciControlPacketHal> = packet.into();
+            for hal_packet in packet_vec.into_iter() {
+                serial
+                    .write(&hal_packet.to_vec())
+                    .map(|written| written as i32)
+                    .map_err(|_| binder::StatusCode::UNKNOWN_ERROR)?;
+            }
+            consume_device_reset_rsp_and_ntf(
+                &mut serial
+                    .try_clone()
+                    .map_err(|_| binder::StatusCode::UNKNOWN_ERROR)?,
+            );
+            log::info!("task successfully cancelled");
+            callbacks.onHalEvent(UwbEvent::CLOSE_CPLT, UwbStatus::OK)?;
+            *self = State::Closed;
+        }
+        Ok(())
+    }
+}
+
+fn consume_device_reset_rsp_and_ntf(reader: &mut File) {
+    // Poll the DeviceResetRsp and DeviceStatusNtf before hal is closed to prevent
+    // the host from getting response and notifications from a 'powered down' UWBS.
+    // Do nothing when these packets are received.
+    const DEVICE_RESET_RSP: [u8; 5] = [64, 0, 0, 1, 0];
+    const DEVICE_STATUS_NTF: [u8; 5] = [96, 1, 0, 1, 1];
+    let mut buffer = vec![0; DEVICE_RESET_RSP.len() + DEVICE_STATUS_NTF.len()];
+    read_exact(reader, &mut buffer).unwrap();
+
+    // Make sure received packets are the expected ones.
+    assert_eq!(&buffer[0..DEVICE_RESET_RSP.len()], &DEVICE_RESET_RSP);
+    assert_eq!(&buffer[DEVICE_RESET_RSP.len()..], &DEVICE_STATUS_NTF);
+}
+
 pub fn makeraw(file: File) -> io::Result<File> {
-    let fd = file.as_raw_fd();
-
-    let mut attrs = termios::tcgetattr(fd)?;
-
-    termios::cfmakeraw(&mut attrs);
-
-    termios::tcsetattr(fd, termios::SetArg::TCSANOW, &attrs)?;
+    // Configure the file descriptor as raw fd.
+    use nix::sys::termios::*;
+    let mut attrs = tcgetattr(&file)?;
+    cfmakeraw(&mut attrs);
+    tcsetattr(&file, SetArg::TCSANOW, &attrs)?;
 
     Ok(file)
 }
 
+/// Wrapper around Read::read to handle EWOULDBLOCK.
+/// /!\ will actively wait for more data, make sure to call
+/// this method only when data is immediately expected.
+fn read_exact(file: &mut File, mut buf: &mut [u8]) -> io::Result<()> {
+    while buf.len() > 0 {
+        match file.read(buf) {
+            Ok(0) => panic!("unexpectedly reached end of file"),
+            Ok(read_len) => buf = &mut buf[read_len..],
+            Err(err) if err.kind() == io::ErrorKind::WouldBlock => continue,
+            Err(err) => return Err(err),
+        }
+    }
+    Ok(())
+}
+
 impl binder::Interface for UwbChip {}
 
 #[async_trait]
@@ -65,56 +138,113 @@
     async fn open(&self, callbacks: &Strong<dyn IUwbClientCallback>) -> Result<()> {
         log::debug!("open: {:?}", &self.path);
 
-        let serial = File::open(&self.path)
-            .await
+        let mut state = self.state.lock().await;
+
+        if matches!(*state, State::Opened { .. }) {
+            log::error!("the state is already opened");
+            return Err(binder::ExceptionCode::ILLEGAL_STATE.into());
+        }
+
+        let serial = OpenOptions::new()
+            .read(true)
+            .write(true)
+            .create(false)
+            .custom_flags(libc::O_NONBLOCK)
+            .open(&self.path)
             .and_then(makeraw)
             .map_err(|_| binder::StatusCode::UNKNOWN_ERROR)?;
 
-        let mut read = serial
+        let state_death_recipient = self.state.clone();
+        let mut death_recipient = DeathRecipient::new(move || {
+            let mut state = state_death_recipient.blocking_lock();
+            log::info!("Uwb service has died");
+            if let State::Opened { ref mut token, .. } = *state {
+                token.cancel();
+                *state = State::Closed;
+            }
+        });
+
+        callbacks.as_binder().link_to_death(&mut death_recipient)?;
+
+        let token = CancellationToken::new();
+        let cloned_token = token.clone();
+
+        let client_callbacks = callbacks.clone();
+
+        let reader = serial
             .try_clone()
-            .await
             .map_err(|_| binder::StatusCode::UNKNOWN_ERROR)?;
-        let write = serial;
 
-        let mut state = self.state.lock().await;
+        let join_handle = tokio::task::spawn(async move {
+            log::info!("UCI reader task started");
+            let mut reader = AsyncFd::new(reader).unwrap();
 
-        if let State::Closed = *state {
-            let client_callbacks = callbacks.clone();
+            loop {
+                const UWB_HEADER_SIZE: usize = 4;
+                let mut buffer = vec![0; UWB_HEADER_SIZE];
 
-            let mut tasks = tokio::task::JoinSet::new();
+                // The only time where the task can be safely
+                // cancelled is when no packet bytes have been read.
+                //
+                // - read_exact() cannot be used here since it is not
+                //   cancellation safe.
+                // - read() cannot be used because it cannot be cancelled:
+                //   the syscall is executed blocking on the threadpool
+                //   and completes after termination of the task when
+                //   the pipe receives more data.
+                let read_len = loop {
+                    // On some platforms, the readiness detecting mechanism
+                    // relies on edge-triggered notifications. This means that
+                    // the OS will only notify Tokio when the file descriptor
+                    // transitions from not-ready to ready. For this to work
+                    // you should first try to read or write and only poll for
+                    // readiness if that fails with an error of
+                    // std::io::ErrorKind::WouldBlock.
+                    match reader.get_mut().read(&mut buffer) {
+                        Ok(0) => {
+                            log::error!("file unexpectedly closed");
+                            return;
+                        }
+                        Ok(read_len) => break read_len,
+                        Err(err) if err.kind() == io::ErrorKind::WouldBlock => (),
+                        Err(_) => panic!("unexpected read failure"),
+                    }
 
-            tasks.spawn(async move {
-                loop {
-                    const UWB_HEADER_SIZE: usize = 4;
+                    let mut guard = select! {
+                        _ = cloned_token.cancelled() => {
+                            log::info!("task is cancelled!");
+                            return;
+                        },
+                        result = reader.readable() => result.unwrap()
+                    };
 
-                    let mut buffer = vec![0; UWB_HEADER_SIZE];
-                    read.read_exact(&mut buffer[0..UWB_HEADER_SIZE])
-                        .await
-                        .unwrap();
+                    guard.clear_ready();
+                };
 
-                    let length = buffer[3] as usize + UWB_HEADER_SIZE;
+                // Read the remaining header bytes, if truncated.
+                read_exact(reader.get_mut(), &mut buffer[read_len..]).unwrap();
 
-                    buffer.resize(length, 0);
-                    read.read_exact(&mut buffer[UWB_HEADER_SIZE..length])
-                        .await
-                        .unwrap();
+                let length = buffer[3] as usize + UWB_HEADER_SIZE;
+                buffer.resize(length, 0);
 
-                    client_callbacks.onUciMessage(&buffer[..]).unwrap();
-                }
-            });
+                // Read the payload bytes.
+                read_exact(reader.get_mut(), &mut buffer[UWB_HEADER_SIZE..]).unwrap();
 
-            callbacks.onHalEvent(UwbEvent::OPEN_CPLT, UwbStatus::OK)?;
+                client_callbacks.onUciMessage(&buffer).unwrap();
+            }
+        });
 
-            *state = State::Opened {
-                callbacks: callbacks.clone(),
-                tasks,
-                write,
-            };
+        callbacks.onHalEvent(UwbEvent::OPEN_CPLT, UwbStatus::OK)?;
 
-            Ok(())
-        } else {
-            Err(binder::ExceptionCode::ILLEGAL_STATE.into())
-        }
+        *state = State::Opened {
+            callbacks: callbacks.clone(),
+            handle: join_handle,
+            serial,
+            death_recipient,
+            token,
+        };
+
+        Ok(())
     }
 
     async fn close(&self) -> Result<()> {
@@ -122,10 +252,8 @@
 
         let mut state = self.state.lock().await;
 
-        if let State::Opened { ref callbacks, .. } = *state {
-            callbacks.onHalEvent(UwbEvent::CLOSE_CPLT, UwbStatus::OK)?;
-            *state = State::Closed;
-            Ok(())
+        if let State::Opened { .. } = *state {
+            state.close().await
         } else {
             Err(binder::ExceptionCode::ILLEGAL_STATE.into())
         }
@@ -155,10 +283,9 @@
     async fn sendUciMessage(&self, data: &[u8]) -> Result<i32> {
         log::debug!("sendUciMessage");
 
-        if let State::Opened { write, .. } = &mut *self.state.lock().await {
-            write
+        if let State::Opened { ref mut serial, .. } = &mut *self.state.lock().await {
+            serial
                 .write(data)
-                .await
                 .map(|written| written as i32)
                 .map_err(|_| binder::StatusCode::UNKNOWN_ERROR.into())
         } else {
diff --git a/uwb/aidl/default/uwb-service.rc b/uwb/aidl/default/uwb-service.rc
new file mode 100644
index 0000000..d6a8eda
--- /dev/null
+++ b/uwb/aidl/default/uwb-service.rc
@@ -0,0 +1,3 @@
+service vendor.uwb_hal /apex/com.android.hardware.uwb/bin/hw/android.hardware.uwb-service ${ro.vendor.uwb.dev}
+    class hal
+    user uwb
diff --git a/vibrator/OWNERS b/vibrator/OWNERS
index 62a567e..c4de58a 100644
--- a/vibrator/OWNERS
+++ b/vibrator/OWNERS
@@ -1,8 +1,2 @@
 # Bug component: 345036
-
 include platform/frameworks/base:/services/core/java/com/android/server/vibrator/OWNERS
-
-chrispaulo@google.com
-michaelwr@google.com
-nathankulczak@google.com
-taikuo@google.com
diff --git a/vibrator/aidl/default/Android.bp b/vibrator/aidl/default/Android.bp
index 78bb4ed..fb71a82 100644
--- a/vibrator/aidl/default/Android.bp
+++ b/vibrator/aidl/default/Android.bp
@@ -32,9 +32,11 @@
     },
 }
 
-filegroup {
+prebuilt_etc {
     name: "android.hardware.vibrator.xml",
-    srcs: ["android.hardware.vibrator.xml"],
+    src: "android.hardware.vibrator.xml",
+    sub_dir: "vintf",
+    installable: false,
 }
 
 cc_binary {
diff --git a/vibrator/aidl/default/apex/Android.bp b/vibrator/aidl/default/apex/Android.bp
index 7949057..39626bf 100644
--- a/vibrator/aidl/default/apex/Android.bp
+++ b/vibrator/aidl/default/apex/Android.bp
@@ -2,17 +2,6 @@
     default_applicable_licenses: ["hardware_interfaces_license"],
 }
 
-apex_key {
-    name: "com.android.hardware.vibrator.key",
-    public_key: "com.android.hardware.vibrator.avbpubkey",
-    private_key: "com.android.hardware.vibrator.pem",
-}
-
-android_app_certificate {
-    name: "com.android.hardware.vibrator.certificate",
-    certificate: "com.android.hardware.vibrator",
-}
-
 prebuilt_etc {
     name: "com.android.hardware.vibrator.rc",
     src: "com.android.hardware.vibrator.rc",
@@ -22,20 +11,19 @@
 apex {
     name: "com.android.hardware.vibrator",
     manifest: "apex_manifest.json",
-    key: "com.android.hardware.vibrator.key",
-    certificate: ":com.android.hardware.vibrator.certificate",
+    key: "com.android.hardware.key",
+    certificate: ":com.android.hardware.certificate",
     file_contexts: "file_contexts",
-    use_vndk_as_stable: true,
     updatable: false,
-    // Install the apex in /vendor/apex
-    soc_specific: true,
+    vendor: true,
+
     binaries: [
         "android.hardware.vibrator-service.example",
     ],
     prebuilts: [
         "com.android.hardware.vibrator.rc",
+        "android.hardware.vibrator.xml",
     ],
-    vintf_fragments: [":android.hardware.vibrator.xml"],
     // vibrator.default.so is not needed by the AIDL service binary.
     overrides: ["vibrator.default"],
 }
diff --git a/vibrator/aidl/default/apex/com.android.hardware.vibrator.avbpubkey b/vibrator/aidl/default/apex/com.android.hardware.vibrator.avbpubkey
deleted file mode 100644
index a6ca630..0000000
--- a/vibrator/aidl/default/apex/com.android.hardware.vibrator.avbpubkey
+++ /dev/null
Binary files differ
diff --git a/vibrator/aidl/default/apex/com.android.hardware.vibrator.pem b/vibrator/aidl/default/apex/com.android.hardware.vibrator.pem
deleted file mode 100644
index c0f5c50..0000000
--- a/vibrator/aidl/default/apex/com.android.hardware.vibrator.pem
+++ /dev/null
@@ -1,51 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIIJKAIBAAKCAgEAnIEo7HGpVc62cFPmwT3MOiHQANHVbawHpbp//x3xK7acK6So
-rUu8XJnsO0kAA/Vwtfqqo5GgmBVUr4ahW+MJ/W/X7NP5hAetQWQcGFc0Yhqmoi1g
-vTDRon2i6+mhfUFJqqy8t3vLFehqgkQCe8gGiEVl43+PODtfIae+AaPbTl8R9ErQ
-l3ESBfRElkMQo2beC7e8k5joLEA3q85Q7rdSFUdhoUSXMVRHmBVJxezYI/3SLFtj
-7ULKaGtOgUFlj5R9akr9y8+sG9NBJI5HJZgqz46l+ZuNkdkPlDK6arD5eL9lkpxt
-GeXhtwBPdgZIuSTe/tFeYU65MmwLxVnStDJ67k3AFKC0Zg7ISVemCRofSOEhyUm3
-DoB1G9UiBj3pNmhwPNYiohW3pFZuLgBArAT8nTi4txmCBMNStz7kNVW8sv8nlBEz
-D+nOuoB8tGAF7+fsaBKVQI6yJd2tgkpRM5E8NNrLYL+ignRztzfHjNDtw5Xn4QHA
-Ds1GrNqq25uBxvrH5cDa2HFvZryuejlzvGp6YAkPUwZrYJ/ij7i+98EvXowgED/7
-gFnXmkkyW1LQ0BUxJtKKEjnSno8leGbcospSUDt8uiBF7Vnn3atokRpl6rr2k0qa
-5ELx+vrQT+LUUo0MuZkAW9qKfYLBF8UOCiK1Ytvs9bxK3Jb93E+lJAe/HQkCAwEA
-AQKCAgADnZA+dhm9W7snOSj5id3v8dwGSNKvZ+v9TiOq1xw9MEjHUVR8PGWrlfq5
-G+SeMstZyOKsSK73FHcSXv/XSZVvf2fzlqoK/Mpp2lAz17/kDE2RLY8wj7IoGNLs
-tEcAx8NV6AusCXYVmXrsa3nLNkHAYCoMaWP7npOCCYgALbLhSpz1kczj0r7h2FTF
-S+NUgwnaJ3J5zmx+qTUgCPIhsaZ5y15cBWOgxhupTcSYh/IuUqzKTYovbv2SD/iO
-T95yxLFpBTZ7wN5u/iBhIdBO9Ab5KIh5Dbjlh6guekWINXJt8a39BxQWJxNh0OYF
-CfwgGtPz+w49HT52Bbz34C1X8FqaoXxJUHaJ7e83Y/1qzENNPOsmdscMuzrjlVox
-gyQPIS5HzASD2NktnShwE2QUMhZcovkPIhFxos7JDMvOTXf6LVMXKWGa4HZqb4Z2
-dBp/bZzuV+OOHXq9emCkRwO5aor2qfefSf+xcycDWzaWTJfvnEXulFXYtqiGOEL7
-hyvr38Tll6dOLO8KkwvHaf51wZl/jCTo+7akdpokUh0Klg3/KKRiaScHQotkrVuD
-MGL+kWSZqZ6sZKs8z3xh4oj2d6P1qHEeu85+DY/GyHJ2Ek4athcT0jmqb4A/0Tq9
-1zr5IXo+ps20YjW5bFvXbvKVZYggsJyacw6WhTFD9eN8fn+UoQKCAQEAzwrs/QWv
-yWoWLOaF39bL6JSdq8juynswdb2NjcHV/b7dzhgf0aDnA6WtJcHlfRcnA8haeoEQ
-n0qzPAirexz2AtWfJm41gYTqWTwaaNkbwxGMMvLV/IQebk3pHdAdONFYpLloJvlt
-4ys8W1gdMKwzSRvR4VPYwIfIqb/vYxZhme0JBF0X5iPFkID9Q1cJeaRx9PhCvX4o
-LBb6impUkeTIhxbGgbuudGyhcyvKrPdcx1ts69r6NOme2hvBhrbZGVaUEtlHvEu0
-1JvNvPJyK2XvHI3EtERzjUPm3s+Gh5REvdXXaz1GC4HUSFZkOG8/HgSZoEYVkSJH
-QoCnfXc4VG4jrQKCAQEAwYL4KvpltG85DNoYava71adQfYwitQah8omGU+dqWjjQ
-m8WLKo1cjEO6tfIp7UFSz4mJvwhxj9aqdwu2RyGoeZHKOhxluZIH9mcoPggL7Kgj
-xEJfkwy5zbReujM71n5FOhR2zOltXXa5YrN9983fZeZK8FRchEBDwyUf73dkwRri
-uvyY793OIqYjuJXO/9dtSyK1jEmDUTLoquM610RLLK4j8hXQ9C/sMlDfHzlUzXff
-ZsvWL5U4D3e6cL55cP7lr8cYR1z+AcZsjd7eNlNXO1v4o50B7bOayr7/zsTlfXss
-ZoP7yJcYeXEpcIx5KPS44CAaDeZfQkOFcz7DzFQqTQKCAQEAx2aQZAdsC6GehdPm
-r3PhorgvOlkkkeIfA+ZxREug2udOG8VkL7K1iu+vWKPrb5QywRPfAAj5h1CcWn9H
-GCUGUiiHRK3z3i+yvAqErOIcOLzXt+HkcXSVEkr67vmWizgkFVFzm8WyLY1gbeDp
-DA1sv0aJ1me4Y4Tin4n49geCLIr7mjZGZCGjjs6MHKTgvUTBc9r9/B5adkwTM+fA
-V1puPpySxjOJixtsSs2sPvVlZ6MHvgeB3h/6G7mLo0DKyfp2Vcjpq9GF8RW1Cfq+
-NknQBkILZkpet3jkC0b3G/CSW/ptpBy5Ly/00U5S639I3JI1mwSklMjctJHPvahq
-mfYRaQKCAQAnMzzKmAbaUl2gON4RbQIH+ejYRfcR7NIJq8pGXO6ycCfyJkZWzGQf
-FelQykmsAjugRyBcTn2Swc2uZ/T429yhI+NveikxOl/ajnMcfczMmBMGwttRkpZh
-EVTPK2nHvbSQW2zlfbPl5xMO54VxGYdTwR8VKEHFmK8hbPfXLrx+Uc/0SQ9CKBCF
-/FnoHpDcSuuc+N8GGC492K5BT96vlOoVlwE5HSpDDSIv3yoTzS1cohfjXw94fCXr
-HDnsdOls9nXY8d/9NN1Pxr5ezvL81k0pfSwVGM03Ndb5k0+Gt2Q10ynfaoUq0VDn
-6QCYCBzTKx/4ZwhgIHbTmZIDEoffcH1RAoIBACIpqVGAa2/t3c0BCN7PLPGIsC/w
-5YwxqVNUM0FK220RoO0vbSEGvba8NJyBKSaokgPwhmNlmVE+r17B78oLfP8GFtAx
-Jz52WkjVULNb07WSIHCUxeoNZf9qEANdvfMwW4effjkrmxEtVLHdGC72Lg+am30s
-QaJqLmKsRZeE6Js2+ZXeRKoXN8wLLGp/CDVnDdLUEK6SdsujI4jXEq3DT+9eGh6X
-mXl7vWFzbPrAGcHM4Ad8uY2BHznCGxvJn4E4u+EH+l4OX334Q4gM+gOIRt0xkHVG
-9OXFRrjPVCWZCH1dOdkC5DomKCgyKBHLObtBv3dHXXDtEbeZ8fGbJFuoBhA=
------END RSA PRIVATE KEY-----
diff --git a/vibrator/aidl/default/apex/com.android.hardware.vibrator.pk8 b/vibrator/aidl/default/apex/com.android.hardware.vibrator.pk8
deleted file mode 100644
index d20cc33..0000000
--- a/vibrator/aidl/default/apex/com.android.hardware.vibrator.pk8
+++ /dev/null
Binary files differ
diff --git a/vibrator/aidl/default/apex/com.android.hardware.vibrator.x509.pem b/vibrator/aidl/default/apex/com.android.hardware.vibrator.x509.pem
deleted file mode 100644
index 993245b..0000000
--- a/vibrator/aidl/default/apex/com.android.hardware.vibrator.x509.pem
+++ /dev/null
@@ -1,34 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIF3zCCA8cCFBJmLB9vGtl8nENMVa8g51Y2vRhPMA0GCSqGSIb3DQEBCwUAMIGq
-MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91
-bnRhaW4gVmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UECwwHQW5kcm9pZDEi
-MCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTEmMCQGA1UEAwwdY29t
-LmFuZHJvaWQuaGFyZHdhcmUudmlicmF0b3IwIBcNMjEwOTE2MTcyOTA5WhgPNDc1
-OTA4MTMxNzI5MDlaMIGqMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5p
-YTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4G
-A1UECwwHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNv
-bTEmMCQGA1UEAwwdY29tLmFuZHJvaWQuaGFyZHdhcmUudmlicmF0b3IwggIiMA0G
-CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDV857uzUSXWQNWIuiNRwt1zd/eSB8P
-iVNq0qTexlZvamXr6h5VwX45iJeDVCxlx3uktXXP2NH7U01A5gl8Hix6iodNe3sJ
-fFIhzUiqdMfAn+6RWcJcb3v6J58D6R+htgtaSgv8WOLkIZyhbmU3NToc7dNe2j0U
-wh6xfYhpj/s0RManSTZW19C2H8g5eNfhEZgDT+KOUIgepv/x6Y5IR147JPh8Ha7g
-vxM87ceErSvr3e8uXDWUZtQ6IDfF2NkxJJGJos4IAteXbkG60q76V8pmWLCqIsMM
-tRcIpTEJUIbnbxAqSu+crZqQowu9HrJMYnqunlmXASeluxXdl8VKOVNMZHy3ipj7
-HjoTUJoiEVDLYeT7db76k2lDFH/JRtnoe3BBinUEKvGT3rOjy55C4E2DSMSM1Laz
-zkRcJ4hlzFQLXD5/iwWgW6me1lmnOEqFJZolc1fEc+VfEdZdwJmZF6Clm5av2hDm
-Oq09qL02nXy0OyAoCI6IcrrAlFFolgel32nWp1R7c+N2+6vLMP3KR50TgSiwHNNQ
-weZhpP1GrXDyVj+ilL5T/2ionvjIvDBgOi8B0IwiqeHY7lqsSyMOuKTi5WPrJ86E
-GNJ+PlivA/P9MAatem4kzCT2t3DbVC+dtybiUAmVFb2Ls+dVK4nHcbGTW9AuBijD
-COEHQgi4Xs6lnwIDAQABMA0GCSqGSIb3DQEBCwUAA4ICAQDGvq99QUxMh+DaI2Pd
-s4fQ9MmYxGDxULhjqgGAjDbL3jQMG2FxPTu1Z2VJgg4n+PTNsgsqgn1JgQM3gvFp
-8FKhoxtzM5V8pPxphCG7U/f3ZsmXdLl69sbVkMRhorhQ8H54q0O/T3Ig/ULZgblE
-xCRT1REB693tUQOCYgWgnsOpvySfujYhNBirl48Hw9zrRmQNTsO20dKwkZUvkVow
-/pawucYrHibgwgKWz8kB3Dl4DODiLybek0hGzr59Joul9eMsxTuQsHAIUv0KO2Ny
-5WT7GIX6qYc+VrnXsO+PHtx5GTUjrJiue3aggoW6X7gu3Z6KuIOiVTVLVp6wSJtt
-VHv90HTu2lYxtPyPSOpFfwFOTicN+5VmLTQwPvPRqsnCaYc+K2iWyEhN/PnSfFNc
-t/TX9HT3ljXq9yfshQmQJ27pdUiYs9Avt7fEXpJjQ0Tn9w8jRS5gsrnTUXTG6HXf
-I4lsMSAApFZa112PwU7xAIIaipBauuMjQCabD/thBzB6d29Rlbz3cjBzoky9h2vb
-XNIVo5O2Jiz7OJQ/7mubvJqIBngiaDK78n2hSdYglI1hgcf0KaQIJUridzmjt0kp
-xXcwIz7nJxhNpbsYnDnqwqz9en8a4N+KeoQleYROo2kEtE434AJkzdABV4IKRafj
-cbPWuY6F2faWAjkSOEhBfGOKOw==
------END CERTIFICATE-----
diff --git a/vibrator/aidl/default/apex/file_contexts b/vibrator/aidl/default/apex/file_contexts
index f811656..f061caa 100644
--- a/vibrator/aidl/default/apex/file_contexts
+++ b/vibrator/aidl/default/apex/file_contexts
@@ -1,3 +1,4 @@
-(/.*)? 							u:object_r:vendor_file:s0
-/bin/hw/android\.hardware\.vibrator-service\.example	u:object_r:hal_vibrator_default_exec:s0
+(/.*)?                                                  u:object_r:vendor_file:s0
+/etc(/.*)?                                              u:object_r:vendor_configs_file:s0
+/bin/hw/android\.hardware\.vibrator-service\.example    u:object_r:hal_vibrator_default_exec:s0
 
diff --git a/vr/1.0/vts/functional/VtsHalVrV1_0TargetTest.cpp b/vr/1.0/vts/functional/VtsHalVrV1_0TargetTest.cpp
index 049ec73..00943fd 100644
--- a/vr/1.0/vts/functional/VtsHalVrV1_0TargetTest.cpp
+++ b/vr/1.0/vts/functional/VtsHalVrV1_0TargetTest.cpp
@@ -18,7 +18,6 @@
 #include <android-base/logging.h>
 #include <android/hardware/vr/1.0/IVr.h>
 #include <gtest/gtest.h>
-#include <hardware/vr.h>
 #include <hidl/GtestPrinter.h>
 #include <hidl/ServiceManagement.h>
 #include <log/log.h>
diff --git a/vr/OWNERS b/vr/OWNERS
new file mode 100644
index 0000000..a07824e
--- /dev/null
+++ b/vr/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 298954331
+
+include platform/hardware/interfaces:/OWNERS
diff --git a/weaver/aidl/android/hardware/weaver/IWeaver.aidl b/weaver/aidl/android/hardware/weaver/IWeaver.aidl
index f51034a..30168e3 100644
--- a/weaver/aidl/android/hardware/weaver/IWeaver.aidl
+++ b/weaver/aidl/android/hardware/weaver/IWeaver.aidl
@@ -20,8 +20,8 @@
 import android.hardware.weaver.WeaverReadResponse;
 
 /**
- * Weaver provides secure storage of secret values that may only be read if the
- * corresponding key has been presented.
+ * Weaver provides secure persistent storage of secret values that may only be
+ * read if the corresponding key has been presented.
  *
  * The storage must be secure as the device's user authentication and encryption
  * relies on the security of these values. The cardinality of the domains of the
@@ -58,7 +58,9 @@
      * Throttling must be used to limit the frequency of failed read attempts.
      * The value is only returned when throttling is not active, even if the
      * correct key is provided. If called when throttling is active, the time
-     * until the next attempt can be made is returned.
+     * until the next attempt can be made is returned. Throttling must be
+     * applied on a per-slot basis so that a successful read from one slot does
+     * not reset the throttling state of any other slot.
      *
      * Service status return:
      *
@@ -76,7 +78,8 @@
     WeaverReadResponse read(in int slotId, in byte[] key);
 
     /**
-     * Overwrites the identified slot with the provided key and value.
+     * Overwrites the identified slot with the provided key and value, rendering
+     * the previous contents of the slot permanently unrecoverable.
      *
      * The new values are written regardless of the current state of the slot in
      * order to remain idempotent.
diff --git a/wifi/1.0/Android.bp b/wifi/1.0/Android.bp
index 94f8462..21a5d15 100644
--- a/wifi/1.0/Android.bp
+++ b/wifi/1.0/Android.bp
@@ -33,4 +33,8 @@
     ],
     gen_java: true,
     gen_java_constants: true,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.wifi",
+    ],
 }
diff --git a/wifi/1.1/Android.bp b/wifi/1.1/Android.bp
index 7b4116a..b5e4105 100644
--- a/wifi/1.1/Android.bp
+++ b/wifi/1.1/Android.bp
@@ -21,4 +21,8 @@
         "android.hidl.base@1.0",
     ],
     gen_java: true,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.wifi",
+    ],
 }
diff --git a/wifi/1.2/Android.bp b/wifi/1.2/Android.bp
index f0edb81..83b156e 100644
--- a/wifi/1.2/Android.bp
+++ b/wifi/1.2/Android.bp
@@ -27,4 +27,8 @@
         "android.hidl.base@1.0",
     ],
     gen_java: true,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.wifi",
+    ],
 }
diff --git a/wifi/1.3/Android.bp b/wifi/1.3/Android.bp
index 030d7f6..2ba612e 100644
--- a/wifi/1.3/Android.bp
+++ b/wifi/1.3/Android.bp
@@ -25,4 +25,8 @@
         "android.hidl.base@1.0",
     ],
     gen_java: true,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.wifi",
+    ],
 }
diff --git a/wifi/1.4/Android.bp b/wifi/1.4/Android.bp
index 1523f79..48578f8 100644
--- a/wifi/1.4/Android.bp
+++ b/wifi/1.4/Android.bp
@@ -30,4 +30,8 @@
         "android.hidl.base@1.0",
     ],
     gen_java: true,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.wifi",
+    ],
 }
diff --git a/wifi/aidl/Android.bp b/wifi/aidl/Android.bp
index 7bc8ae7..ac95f85 100644
--- a/wifi/aidl/Android.bp
+++ b/wifi/aidl/Android.bp
@@ -27,6 +27,9 @@
     srcs: [
         "android/hardware/wifi/*.aidl",
     ],
+    imports: [
+        "android.hardware.wifi.common-V1",
+    ],
     stability: "vintf",
     backend: {
         java: {
@@ -42,6 +45,9 @@
                 enabled: false,
             },
         },
+        cpp: {
+            enabled: false,
+        },
     },
     versions_with_info: [
         {
@@ -49,6 +55,5 @@
             imports: [],
         },
     ],
-    frozen: true,
-
+    frozen: false,
 }
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/CachedScanData.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/CachedScanData.aidl
new file mode 100644
index 0000000..cd4a456
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/CachedScanData.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable CachedScanData {
+  int[] scannedFrequenciesMhz;
+  android.hardware.wifi.CachedScanResult[] cachedScanResults;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/CachedScanResult.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/CachedScanResult.aidl
new file mode 100644
index 0000000..1806b0f
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/CachedScanResult.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable CachedScanResult {
+  long timeStampInUs;
+  byte[] ssid;
+  byte[6] bssid;
+  int rssiDbm;
+  int frequencyMhz;
+  android.hardware.wifi.WifiChannelWidthInMhz channelWidthMhz;
+  android.hardware.wifi.WifiRatePreamble preambleType;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiChip.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiChip.aidl
index 4ea2081..5ed7517 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiChip.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiChip.aidl
@@ -83,6 +83,8 @@
   void triggerSubsystemRestart();
   void enableStaChannelForPeerNetwork(in int channelCategoryEnableFlag);
   void setMloMode(in android.hardware.wifi.IWifiChip.ChipMloMode mode);
+  @PropagateAllowBlocking android.hardware.wifi.IWifiApIface createApOrBridgedApIface(in android.hardware.wifi.IfaceConcurrencyType iface, in android.hardware.wifi.common.OuiKeyedData[] vendorData);
+  void setVoipMode(in android.hardware.wifi.IWifiChip.VoipMode mode);
   const int NO_POWER_CAP_CONSTANT = 0x7FFFFFFF;
   @Backing(type="int") @VintfStability
   enum FeatureSetMask {
@@ -95,6 +97,7 @@
     WIGIG = (1 << 6) /* 64 */,
     SET_AFC_CHANNEL_ALLOWANCE = (1 << 7) /* 128 */,
     T2LM_NEGOTIATION = (1 << 8) /* 256 */,
+    SET_VOIP_MODE = (1 << 9) /* 512 */,
   }
   @VintfStability
   parcelable ChipConcurrencyCombinationLimit {
@@ -161,6 +164,11 @@
     NAN_INSTANT_MODE = (1 << 2) /* 4 */,
   }
   @Backing(type="int") @VintfStability
+  enum VoipMode {
+    OFF = 0,
+    VOICE = 1,
+  }
+  @Backing(type="int") @VintfStability
   enum ChannelCategoryMask {
     INDOOR_CHANNEL = (1 << 0) /* 1 */,
     DFS_CHANNEL = (1 << 1) /* 2 */,
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiStaIface.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiStaIface.aidl
index 923deff..ccb7876 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiStaIface.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiStaIface.aidl
@@ -61,6 +61,14 @@
   void stopRssiMonitoring(in int cmdId);
   void stopSendingKeepAlivePackets(in int cmdId);
   void setDtimMultiplier(in int multiplier);
+  android.hardware.wifi.CachedScanData getCachedScanData();
+  android.hardware.wifi.TwtCapabilities twtGetCapabilities();
+  void twtSessionSetup(in int cmdId, in android.hardware.wifi.TwtRequest twtRequest);
+  void twtSessionUpdate(in int cmdId, in int sessionId, in android.hardware.wifi.TwtRequest twtRequest);
+  void twtSessionSuspend(in int cmdId, in int sessionId);
+  void twtSessionResume(in int cmdId, in int sessionId);
+  void twtSessionTeardown(in int cmdId, in int sessionId);
+  void twtSessionGetStats(in int cmdId, in int sessionId);
   @Backing(type="int") @VintfStability
   enum FeatureSetMask {
     APF = (1 << 0) /* 1 */,
@@ -77,5 +85,7 @@
     TDLS_OFFCHANNEL = (1 << 11) /* 2048 */,
     ND_OFFLOAD = (1 << 12) /* 4096 */,
     KEEP_ALIVE = (1 << 13) /* 8192 */,
+    ROAMING_MODE_CONTROL = (1 << 14) /* 16384 */,
+    CACHED_SCAN_DATA = (1 << 15) /* 32768 */,
   }
 }
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiStaIfaceEventCallback.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiStaIfaceEventCallback.aidl
index 48b85b0..629ca3d 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiStaIfaceEventCallback.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiStaIfaceEventCallback.aidl
@@ -38,4 +38,31 @@
   oneway void onBackgroundScanFailure(in int cmdId);
   oneway void onBackgroundScanResults(in int cmdId, in android.hardware.wifi.StaScanData[] scanDatas);
   oneway void onRssiThresholdBreached(in int cmdId, in byte[6] currBssid, in int currRssi);
+  oneway void onTwtFailure(in int cmdId, in android.hardware.wifi.IWifiStaIfaceEventCallback.TwtErrorCode error);
+  oneway void onTwtSessionCreate(in int cmdId, in android.hardware.wifi.TwtSession twtSession);
+  oneway void onTwtSessionUpdate(in int cmdId, in android.hardware.wifi.TwtSession twtSession);
+  oneway void onTwtSessionTeardown(in int cmdId, in int twtSessionId, in android.hardware.wifi.IWifiStaIfaceEventCallback.TwtTeardownReasonCode reasonCode);
+  oneway void onTwtSessionStats(in int cmdId, in int twtSessionId, in android.hardware.wifi.TwtSessionStats twtSessionStats);
+  oneway void onTwtSessionSuspend(in int cmdId, in int twtSessionId);
+  oneway void onTwtSessionResume(in int cmdId, in int twtSessionId);
+  @Backing(type="byte") @VintfStability
+  enum TwtErrorCode {
+    FAILURE_UNKNOWN,
+    ALREADY_RESUMED,
+    ALREADY_SUSPENDED,
+    INVALID_PARAMS,
+    MAX_SESSION_REACHED,
+    NOT_AVAILABLE,
+    NOT_SUPPORTED,
+    PEER_NOT_SUPPORTED,
+    PEER_REJECTED,
+    TIMEOUT,
+  }
+  @Backing(type="byte") @VintfStability
+  enum TwtTeardownReasonCode {
+    UNKNOWN,
+    LOCALLY_REQUESTED,
+    INTERNALLY_INITIATED,
+    PEER_INITIATED,
+  }
 }
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanBootstrappingRequest.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanBootstrappingRequest.aidl
index dd0a5ed..b5f78b0 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanBootstrappingRequest.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanBootstrappingRequest.aidl
@@ -38,4 +38,6 @@
   byte[6] peerDiscMacAddr;
   android.hardware.wifi.NanBootstrappingMethod requestBootstrappingMethod;
   byte[] cookie;
+  boolean isComeback;
+  byte discoverySessionId;
 }
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanBootstrappingResponse.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanBootstrappingResponse.aidl
index 6dd9b26..7b17493 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanBootstrappingResponse.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanBootstrappingResponse.aidl
@@ -36,4 +36,5 @@
 parcelable NanBootstrappingResponse {
   int bootstrappingInstanceId;
   boolean acceptRequest;
+  byte discoverySessionId;
 }
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanConfigRequest.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanConfigRequest.aidl
index 5ead651..a3693d6 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanConfigRequest.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanConfigRequest.aidl
@@ -45,4 +45,5 @@
   char rssiWindowSize;
   int macAddressRandomizationIntervalSec;
   android.hardware.wifi.NanBandSpecificConfig[3] bandSpecificConfig;
+  @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData;
 }
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanDataPathSecurityConfig.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanDataPathSecurityConfig.aidl
index 635dbce..48e9501 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanDataPathSecurityConfig.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanDataPathSecurityConfig.aidl
@@ -39,4 +39,10 @@
   byte[32] pmk;
   byte[] passphrase;
   byte[16] scid;
+  boolean enable16ReplyCountersForTksa;
+  boolean enable16ReplyCountersForGtksa;
+  boolean supportGtkAndIgtk;
+  boolean supportBigtksa;
+  boolean enableNcsBip256;
+  boolean requiresEnhancedFrameProtection;
 }
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanMatchInd.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanMatchInd.aidl
index 317489f..4acc773 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanMatchInd.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanMatchInd.aidl
@@ -51,4 +51,5 @@
   byte[] scid;
   android.hardware.wifi.NanPairingConfig peerPairingConfig;
   android.hardware.wifi.NanIdentityResolutionAttribute peerNira;
+  @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData;
 }
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPairingConfirmInd.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPairingConfirmInd.aidl
index 8ecf22a..699ecdc 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPairingConfirmInd.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPairingConfirmInd.aidl
@@ -40,4 +40,5 @@
   android.hardware.wifi.NanPairingRequestType requestType;
   boolean enablePairingCache;
   android.hardware.wifi.NpkSecurityAssociation npksa;
+  @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData;
 }
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPairingRequest.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPairingRequest.aidl
index 2a644ae..121b038 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPairingRequest.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPairingRequest.aidl
@@ -40,4 +40,5 @@
   boolean enablePairingCache;
   byte[16] pairingIdentityKey;
   android.hardware.wifi.NanPairingSecurityConfig securityConfig;
+  @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData;
 }
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPairingRequestInd.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPairingRequestInd.aidl
index 66762b9..57072c0 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPairingRequestInd.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPairingRequestInd.aidl
@@ -41,4 +41,5 @@
   android.hardware.wifi.NanPairingRequestType requestType;
   boolean enablePairingCache;
   android.hardware.wifi.NanIdentityResolutionAttribute peerNira;
+  @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData;
 }
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPublishRequest.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPublishRequest.aidl
index c49f5f9..bdc8357 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPublishRequest.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPublishRequest.aidl
@@ -40,4 +40,5 @@
   boolean autoAcceptDataPathRequests;
   android.hardware.wifi.NanPairingConfig pairingConfig;
   byte[16] identityKey;
+  @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData;
 }
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanRespondToPairingIndicationRequest.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanRespondToPairingIndicationRequest.aidl
index a58890c..da81c39 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanRespondToPairingIndicationRequest.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanRespondToPairingIndicationRequest.aidl
@@ -40,4 +40,5 @@
   boolean enablePairingCache;
   byte[16] pairingIdentityKey;
   android.hardware.wifi.NanPairingSecurityConfig securityConfig;
+  @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData;
 }
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanSubscribeRequest.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanSubscribeRequest.aidl
index 96be096..bf525a9 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanSubscribeRequest.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanSubscribeRequest.aidl
@@ -43,4 +43,5 @@
   android.hardware.wifi.MacAddress[] intfAddr;
   android.hardware.wifi.NanPairingConfig pairingConfig;
   byte[16] identityKey;
+  @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData;
 }
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttCapabilities.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttCapabilities.aidl
index cf64687..6c64084 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttCapabilities.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttCapabilities.aidl
@@ -42,4 +42,9 @@
   android.hardware.wifi.RttPreamble preambleSupport;
   android.hardware.wifi.RttBw bwSupport;
   byte mcVersion;
+  int azPreambleSupport;
+  int azBwSupport;
+  boolean ntbInitiatorSupported;
+  boolean ntbResponderSupported;
+  @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData;
 }
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttConfig.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttConfig.aidl
index ccdf2ce..3613616 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttConfig.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttConfig.aidl
@@ -48,4 +48,7 @@
   int burstDuration;
   android.hardware.wifi.RttPreamble preamble;
   android.hardware.wifi.RttBw bw;
+  long ntbMinMeasurementTime;
+  long ntbMaxMeasurementTime;
+  @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData;
 }
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttPreamble.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttPreamble.aidl
index de26f28..2802464 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttPreamble.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttPreamble.aidl
@@ -34,6 +34,7 @@
 package android.hardware.wifi;
 @Backing(type="int") @VintfStability
 enum RttPreamble {
+  INVALID = 0,
   LEGACY = 0x1,
   HT = 0x2,
   VHT = 0x4,
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttResult.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttResult.aidl
index 8375dcb..13202ba 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttResult.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttResult.aidl
@@ -59,4 +59,11 @@
   android.hardware.wifi.WifiInformationElement lcr;
   int channelFreqMHz;
   android.hardware.wifi.RttBw packetBw;
+  byte i2rTxLtfRepetitionCount;
+  byte r2iTxLtfRepetitionCount;
+  long ntbMinMeasurementTime;
+  long ntbMaxMeasurementTime;
+  byte numTxSpatialStreams;
+  byte numRxSpatialStreams;
+  @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData;
 }
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttType.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttType.aidl
index 2b6087a..cb25673 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttType.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttType.aidl
@@ -36,4 +36,6 @@
 enum RttType {
   ONE_SIDED = 1,
   TWO_SIDED = 2,
+  TWO_SIDED_11MC = TWO_SIDED /* 2 */,
+  TWO_SIDED_11AZ_NTB = 3,
 }
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaRoamingState.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaRoamingState.aidl
index 1f3d91f..fd7d567 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaRoamingState.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaRoamingState.aidl
@@ -36,4 +36,5 @@
 enum StaRoamingState {
   DISABLED = 0,
   ENABLED = 1,
+  AGGRESSIVE = 2,
 }
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/TwtCapabilities.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/TwtCapabilities.aidl
new file mode 100644
index 0000000..75f3e83
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/TwtCapabilities.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable TwtCapabilities {
+  boolean isTwtRequesterSupported;
+  boolean isTwtResponderSupported;
+  boolean isBroadcastTwtSupported;
+  boolean isFlexibleTwtScheduleSupported;
+  int minWakeDurationUs;
+  int maxWakeDurationUs;
+  long minWakeIntervalUs;
+  long maxWakeIntervalUs;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/TwtRequest.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/TwtRequest.aidl
new file mode 100644
index 0000000..1e1c39a
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/TwtRequest.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable TwtRequest {
+  int mloLinkId;
+  int minWakeDurationUs;
+  int maxWakeDurationUs;
+  long minWakeIntervalUs;
+  long maxWakeIntervalUs;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/TwtSession.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/TwtSession.aidl
new file mode 100644
index 0000000..0b88d8e
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/TwtSession.aidl
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable TwtSession {
+  int sessionId;
+  int mloLinkId;
+  int wakeDurationUs;
+  long wakeIntervalUs;
+  android.hardware.wifi.TwtSession.TwtNegotiationType negotiationType;
+  boolean isTriggerEnabled;
+  boolean isAnnounced;
+  boolean isImplicit;
+  boolean isProtected;
+  boolean isUpdatable;
+  boolean isSuspendable;
+  boolean isResponderPmModeEnabled;
+  @Backing(type="byte") @VintfStability
+  enum TwtNegotiationType {
+    INDIVIDUAL = 0,
+    BROADCAST = 1,
+  }
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/TwtSessionStats.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/TwtSessionStats.aidl
new file mode 100644
index 0000000..f62b614
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/TwtSessionStats.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable TwtSessionStats {
+  int avgTxPktCount;
+  int avgRxPktCount;
+  int avgTxPktSize;
+  int avgRxPktSize;
+  int avgEospDurationUs;
+  int eospCount;
+}
diff --git a/wifi/aidl/android/hardware/wifi/CachedScanData.aidl b/wifi/aidl/android/hardware/wifi/CachedScanData.aidl
new file mode 100644
index 0000000..feda079
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/CachedScanData.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.CachedScanResult;
+
+/**
+ * Scan data cached in Wifi firmware
+ */
+@VintfStability
+parcelable CachedScanData {
+    /**
+     * List of scanned frequencies in MHz.
+     */
+    int[] scannedFrequenciesMhz;
+
+    /**
+     * List of scan results.
+     */
+    CachedScanResult[] cachedScanResults;
+}
diff --git a/wifi/aidl/android/hardware/wifi/CachedScanResult.aidl b/wifi/aidl/android/hardware/wifi/CachedScanResult.aidl
new file mode 100644
index 0000000..9c9dbc7
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/CachedScanResult.aidl
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.WifiChannelWidthInMhz;
+import android.hardware.wifi.WifiRatePreamble;
+
+/**
+ * Scan result cached in Wifi firmware
+ */
+@VintfStability
+parcelable CachedScanResult {
+    /**
+     * Time in micro seconds since boot when the scan was done
+     */
+    long timeStampInUs;
+    /**
+     * SSID of beacon excluding null.
+     */
+    byte[] ssid;
+    /**
+     * BSSID of beacon
+     */
+    byte[6] bssid;
+    /**
+     * Beacon received signal stength indicatior (RSSI), in dbm
+     */
+    int rssiDbm;
+    /**
+     * Frequency of beacon, in MHz
+     */
+    int frequencyMhz;
+    /**
+     * Channel bandwidth of found network
+     */
+    WifiChannelWidthInMhz channelWidthMhz;
+    /**
+     * Supported rate and preamble type
+     */
+    WifiRatePreamble preambleType;
+}
diff --git a/wifi/aidl/android/hardware/wifi/IWifiChip.aidl b/wifi/aidl/android/hardware/wifi/IWifiChip.aidl
index c1caa7e..d12d26c 100644
--- a/wifi/aidl/android/hardware/wifi/IWifiChip.aidl
+++ b/wifi/aidl/android/hardware/wifi/IWifiChip.aidl
@@ -33,6 +33,7 @@
 import android.hardware.wifi.WifiIfaceMode;
 import android.hardware.wifi.WifiRadioCombination;
 import android.hardware.wifi.WifiUsableChannel;
+import android.hardware.wifi.common.OuiKeyedData;
 
 /**
  * Interface that represents a chip that must be configured as a single unit.
@@ -82,6 +83,10 @@
          * Chip supports Tid-To-Link mapping negotiation.
          */
         T2LM_NEGOTIATION = 1 << 8,
+        /**
+         * Chip supports voip mode setting.
+         */
+        SET_VOIP_MODE = 1 << 9,
     }
 
     /**
@@ -384,6 +389,16 @@
     }
 
     /**
+     * This enum represents the different VoIP mode that can be set through |setVoipMode|.
+     */
+    @VintfStability
+    @Backing(type="int")
+    enum VoipMode {
+        OFF = 0,
+        VOICE = 1,
+    }
+
+    /**
      * Configure the Chip.
      * This may NOT be called to reconfigure a chip due to an internal
      * limitation. Calling this when chip is already configured in a different
@@ -1149,4 +1164,46 @@
      *
      */
     void setMloMode(in ChipMloMode mode);
+
+    /**
+     * Create an AP or bridged AP iface on the chip using vendor-provided configuration parameters.
+     *
+     * Depending on the mode the chip is configured in, the interface creation
+     * may fail (code: |WifiStatusCode.ERROR_NOT_AVAILABLE|) if we've already
+     * reached the maximum allowed (specified in |ChipIfaceCombination|) number
+     * of ifaces of the AP or AP_BRIDGED type.
+     *
+     * @param  iface IfaceConcurrencyType to be created. Takes one of
+               |IfaceConcurrencyType.AP| or |IfaceConcurrencyType.AP_BRIDGED|
+     * @param  vendorData Vendor-provided configuration data as a list of |OuiKeyedData|.
+     * @return AIDL interface object representing the iface if
+     *         successful, null otherwise.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+     *         |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+     *         |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+     *         |WifiStatusCode.ERROR_INVALID_ARGS|
+     */
+    @PropagateAllowBlocking
+    IWifiApIface createApOrBridgedApIface(
+            in IfaceConcurrencyType iface, in OuiKeyedData[] vendorData);
+
+    /**
+     * API to set the wifi VoIP mode.
+     *
+     * The VoIP mode is a hint to the HAL to enable or disable Wi-Fi VoIP
+     * optimization. The optimization should be enabled if the mode is NOT set to |OFF|.
+     * Furthermore, HAL should implement relevant optimization techniques based on the
+     * current operational mode.
+     *
+     * Note: Wi-Fi VoIP optimization may trade-off power against Wi-Fi
+     * performance but it provides better voice quility.
+     *
+     * @param mode Voip mode as defined by the enum |VoipMode|
+     * @throws ServiceSpecificException with one of the following values:
+     *         |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+     *         |WifiStatusCode.ERROR_INVALID_ARGS|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     */
+    void setVoipMode(in VoipMode mode);
 }
diff --git a/wifi/aidl/android/hardware/wifi/IWifiStaIface.aidl b/wifi/aidl/android/hardware/wifi/IWifiStaIface.aidl
index 6d6afaf..6c5451b 100644
--- a/wifi/aidl/android/hardware/wifi/IWifiStaIface.aidl
+++ b/wifi/aidl/android/hardware/wifi/IWifiStaIface.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.wifi;
 
+import android.hardware.wifi.CachedScanData;
 import android.hardware.wifi.IWifiStaIfaceEventCallback;
 import android.hardware.wifi.StaApfPacketFilterCapabilities;
 import android.hardware.wifi.StaBackgroundScanCapabilities;
@@ -24,6 +25,8 @@
 import android.hardware.wifi.StaRoamingCapabilities;
 import android.hardware.wifi.StaRoamingConfig;
 import android.hardware.wifi.StaRoamingState;
+import android.hardware.wifi.TwtCapabilities;
+import android.hardware.wifi.TwtRequest;
 import android.hardware.wifi.WifiBand;
 import android.hardware.wifi.WifiDebugRxPacketFateReport;
 import android.hardware.wifi.WifiDebugTxPacketFateReport;
@@ -99,6 +102,14 @@
          * Support for keep alive packet offload.
          */
         KEEP_ALIVE = 1 << 13,
+        /**
+         * Support for configuring roaming mode.
+         */
+        ROAMING_MODE_CONTROL = 1 << 14,
+        /**
+         * Support for cached scan data report.
+         */
+        CACHED_SCAN_DATA = 1 << 15,
     }
 
     /**
@@ -552,4 +563,125 @@
      *         |WifiStatusCode.ERROR_UNKNOWN|
      */
     void setDtimMultiplier(in int multiplier);
+
+    /**
+     * Get the cached scan data.
+     *
+     * @return Instance of |CachedScanData|.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+     *         |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+     *         |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     */
+    CachedScanData getCachedScanData();
+
+    /**
+     * Get Target Wake Time (TWT) local device capabilities for the station interface.
+     *
+     * @return Instance of |TwtCapabilities|.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+     *         |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+     *         |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     */
+    TwtCapabilities twtGetCapabilities();
+
+    /**
+     * Setup a Target Wake Time (TWT) session.
+     *
+     * Supported only if |TwtCapabilities.isTwtRequesterSupported| is set. Results in asynchronous
+     * callback |IWifiStaIfaceEventCallback.onTwtSessionCreate| on success or
+     * |IWifiStaIfaceEventCallback.onTwtFailure| on failure.
+     *
+     * @param cmdId Command Id to use for this invocation. The value 0 is reserved.
+     * @param twtRequest TWT Request parameters.
+     *  @throws ServiceSpecificException with one of the following values:
+     *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+     *         |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     */
+    void twtSessionSetup(in int cmdId, in TwtRequest twtRequest);
+
+    /**
+     * Update a Target Wake Time (TWT) session.
+     *
+     * Supported only if the TWT session can be updated. See |TwtSession.isUpdatable|. Results in
+     * asynchronous callback |IWifiStaIfaceEventCallback.onTwtSessionUpdate| on success or
+     * |IWifiStaIfaceEventCallback.onTwtFailure| on failure.
+     *
+     * @param cmdId Command Id to use for this invocation. The value 0 is reserved.
+     * @param sessionId TWT session id.
+     * @param twtRequest TWT Request parameters.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+     *         |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     */
+    void twtSessionUpdate(in int cmdId, in int sessionId, in TwtRequest twtRequest);
+
+    /**
+     * Suspend a Target Wake Time (TWT) session until a resume is called.
+     *
+     * Supported only if the TWT session supports suspend and resume. See
+     * |TwtSession.isSuspendable|. Results in asynchronous callback
+     * |IWifiStaIfaceEventCallback.onTwtSessionSuspend| on success or
+     * |IWifiStaIfaceEventCallback.onTwtFailure| on failure.
+     *
+     * @param cmdId Command Id to use for this invocation. The value 0 is reserved.
+     * @param sessionId TWT session id.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+     *         |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     */
+    void twtSessionSuspend(in int cmdId, in int sessionId);
+
+    /**
+     * Resume a Target Wake Time (TWT) session which is suspended.
+     *
+     * Supported only if the TWT session supports suspend and resume. See
+     * |TwtSession.isSuspendable|. Results in asynchronous callback
+     * |IWifiStaIfaceEventCallback.onTwtSessionResume| on success or
+     * |IWifiStaIfaceEventCallback.onTwtFailure| on failure.
+     *
+     * @param cmdId Command Id to use for this invocation. The value 0 is reserved.
+     * @param sessionId TWT session id.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+     *         |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     */
+    void twtSessionResume(in int cmdId, in int sessionId);
+
+    /**
+     * Teardown a Target Wake Time (TWT) session.
+     *
+     * Results in asynchronous callback |IWifiStaIfaceEventCallback.onTwtSessionTeardown| on
+     * success or |IWifiStaIfaceEventCallback.onTwtFailure| on failure.
+     *
+     * @param cmdId Command Id to use for this invocation. The value 0 is reserved.
+     * @param sessionId TWT session id.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+     *         |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     */
+    void twtSessionTeardown(in int cmdId, in int sessionId);
+
+    /**
+     * Get stats for a Target Wake Time (TWT) session.
+     *
+     * Results in asynchronous callback |IWifiStaIfaceEventCallback.onTwtSessionStats| on success
+     * or |IWifiStaIfaceEventCallback.onTwtFailure| on failure.
+     *
+     * @param cmdId Command Id to use for this invocation. The value 0 is reserved.
+     * @param sessionId TWT session id.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+     *         |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     */
+    void twtSessionGetStats(in int cmdId, in int sessionId);
 }
diff --git a/wifi/aidl/android/hardware/wifi/IWifiStaIfaceEventCallback.aidl b/wifi/aidl/android/hardware/wifi/IWifiStaIfaceEventCallback.aidl
index 93a255f..dda7c77 100644
--- a/wifi/aidl/android/hardware/wifi/IWifiStaIfaceEventCallback.aidl
+++ b/wifi/aidl/android/hardware/wifi/IWifiStaIfaceEventCallback.aidl
@@ -18,6 +18,8 @@
 
 import android.hardware.wifi.StaScanData;
 import android.hardware.wifi.StaScanResult;
+import android.hardware.wifi.TwtSession;
+import android.hardware.wifi.TwtSessionStats;
 
 @VintfStability
 oneway interface IWifiStaIfaceEventCallback {
@@ -61,4 +63,104 @@
      * @param currRssi RSSI of the currently connected access point.
      */
     void onRssiThresholdBreached(in int cmdId, in byte[6] currBssid, in int currRssi);
+
+    @VintfStability
+    @Backing(type="byte")
+    enum TwtErrorCode {
+        /** Unknown failure */
+        FAILURE_UNKNOWN,
+        /** TWT session is already resumed */
+        ALREADY_RESUMED,
+        /** TWT session is already suspended */
+        ALREADY_SUSPENDED,
+        /** Invalid parameters */
+        INVALID_PARAMS,
+        /** Maximum number of sessions reached */
+        MAX_SESSION_REACHED,
+        /** Requested operation is not available */
+        NOT_AVAILABLE,
+        /** Requested operation is not supported */
+        NOT_SUPPORTED,
+        /** Requested operation is not supported by the peer */
+        PEER_NOT_SUPPORTED,
+        /** Requested operation is rejected by the peer */
+        PEER_REJECTED,
+        /** Requested operation is timed out */
+        TIMEOUT,
+    }
+
+    @VintfStability
+    @Backing(type="byte")
+    enum TwtTeardownReasonCode {
+        /** Unknown reason */
+        UNKNOWN,
+        /** Teardown requested by the framework */
+        LOCALLY_REQUESTED,
+        /** Teardown initiated internally by the firmware or driver */
+        INTERNALLY_INITIATED,
+        /** Teardown initiated by the peer */
+        PEER_INITIATED,
+    }
+
+    /**
+     * Called to indicate a TWT failure. If there is no command associated with this failure cmdId
+     * will be 0.
+     *
+     * @param cmdId Id used to identify the command. The value 0 indicates no associated command.
+     * @param error error code.
+     */
+    void onTwtFailure(in int cmdId, in TwtErrorCode error);
+
+    /**
+     * Called when a Target Wake Time session is created. See |IWifiStaIface.twtSessionSetup|.
+     *
+     * @param cmdId Id used to identify the command.
+     * @param twtSession TWT session.
+     */
+    void onTwtSessionCreate(in int cmdId, in TwtSession twtSession);
+
+    /**
+     * Called when a Target Wake Time session is updated. See |IWifiStaIface.twtSessionUpdate|.
+     *
+     * @param cmdId Id used to identify the command.
+     * @param twtSession TWT session.
+     */
+    void onTwtSessionUpdate(in int cmdId, in TwtSession twtSession);
+
+    /**
+     * Called when the Target Wake Time session is torndown.
+     * See |IWifiStaIface.twtSessionTeardown|.
+     *
+     * @param cmdId Id used to identify the command. The value 0 indicates no associated command.
+     * @param twtSessionId TWT session id.
+     * @param reasonCode reason code for the TWT teardown.
+     */
+    void onTwtSessionTeardown(
+            in int cmdId, in int twtSessionId, in TwtTeardownReasonCode reasonCode);
+
+    /**
+     * Called when TWT session stats available. See |IWifiStaIface.twtSessionGetStats|.
+     *
+     * @param cmdId Id used to identify the command.
+     * @param twtSessionId TWT session id.
+     * @param twtSessionStats TWT session stats.
+     */
+    void onTwtSessionStats(in int cmdId, in int twtSessionId, in TwtSessionStats twtSessionStats);
+
+    /**
+     * Called when the Target Wake Time session is suspended.
+     * See |IWifiStaIface.twtSessionSuspend|.
+     *
+     * @param cmdId Id used to identify the command. The value 0 indicates no associated command.
+     * @param twtSessionId TWT session id.
+     */
+    void onTwtSessionSuspend(in int cmdId, in int twtSessionId);
+
+    /**
+     * Called when the Target Wake Time session is resumed. See |IWifiStaIface.twtSessionResume|.
+     *
+     * @param cmdId Id used to identify the command. The value 0 indicates no associated command.
+     * @param twtSessionId TWT session id.
+     */
+    void onTwtSessionResume(in int cmdId, in int twtSessionId);
 }
diff --git a/wifi/aidl/android/hardware/wifi/NanBootstrappingRequest.aidl b/wifi/aidl/android/hardware/wifi/NanBootstrappingRequest.aidl
index 4b74cd9..e23bd23 100644
--- a/wifi/aidl/android/hardware/wifi/NanBootstrappingRequest.aidl
+++ b/wifi/aidl/android/hardware/wifi/NanBootstrappingRequest.aidl
@@ -45,4 +45,16 @@
      * Cookie received from previous |NanBootstrappingConfirmInd| for comeback request.
      */
     byte[] cookie;
+
+    /**
+     * Identify if it is a request for come back response
+     */
+    boolean isComeback;
+
+    /**
+     * ID of an active publish or subscribe discovery session. Follow-up message is transmitted in
+     * the context of the discovery session. NAN Spec: Service Descriptor Attribute (SDA) / Instance
+     * ID
+     */
+    byte discoverySessionId;
 }
diff --git a/wifi/aidl/android/hardware/wifi/NanBootstrappingResponse.aidl b/wifi/aidl/android/hardware/wifi/NanBootstrappingResponse.aidl
index dbe8923..a2ee0e6 100644
--- a/wifi/aidl/android/hardware/wifi/NanBootstrappingResponse.aidl
+++ b/wifi/aidl/android/hardware/wifi/NanBootstrappingResponse.aidl
@@ -29,4 +29,11 @@
      * True if accept the request, false otherwise.
      */
     boolean acceptRequest;
+
+    /**
+     * ID of an active publish or subscribe discovery session. Follow-up message is transmitted in
+     * the context of the discovery session. NAN Spec: Service Descriptor Attribute (SDA) / Instance
+     * ID
+     */
+    byte discoverySessionId;
 }
diff --git a/wifi/aidl/android/hardware/wifi/NanConfigRequest.aidl b/wifi/aidl/android/hardware/wifi/NanConfigRequest.aidl
index 82a7b6e..47561dc 100644
--- a/wifi/aidl/android/hardware/wifi/NanConfigRequest.aidl
+++ b/wifi/aidl/android/hardware/wifi/NanConfigRequest.aidl
@@ -17,6 +17,7 @@
 package android.hardware.wifi;
 
 import android.hardware.wifi.NanBandSpecificConfig;
+import android.hardware.wifi.common.OuiKeyedData;
 
 /**
  * Configuration parameters of NAN. Used when enabling and re-configuring a NAN cluster.
@@ -79,4 +80,9 @@
      * Additional configuration provided per band. Indexed by |NanBandIndex|.
      */
     NanBandSpecificConfig[3] bandSpecificConfig;
+    /**
+     * Optional vendor-specific parameters. Null value indicates
+     * that no vendor data is provided.
+     */
+    @nullable OuiKeyedData[] vendorData;
 }
diff --git a/wifi/aidl/android/hardware/wifi/NanDataPathSecurityConfig.aidl b/wifi/aidl/android/hardware/wifi/NanDataPathSecurityConfig.aidl
index 9a2013b..b6c5eef 100644
--- a/wifi/aidl/android/hardware/wifi/NanDataPathSecurityConfig.aidl
+++ b/wifi/aidl/android/hardware/wifi/NanDataPathSecurityConfig.aidl
@@ -58,4 +58,49 @@
      * setting up the Secure Data Path.
      */
     byte[16] scid;
+
+    /**
+     * Enables the 16 replay counter for ND-TKSA(NAN Data Pairwise Security Association) and
+     * NM-TKSA(NAN managerment Pairwise Security Association), if set to false will use 4 replay
+     * counter as default
+     * Wi-Fi Aware spec 4.0: 9.5.21.2 Cipher Suite Information attribute
+     */
+    boolean enable16ReplyCountersForTksa;
+
+    /**
+     * Enables the 16 replay counter for GTKSA(Group Transient Key security associations), if set to
+     * false will use 4 replay counter as default.
+     * Wi-Fi Aware spec 4.0: 9.5.21.2 Cipher Suite Information attribute
+     */
+    boolean enable16ReplyCountersForGtksa;
+
+    /**
+     * GTK(Group Transient Key) used to protect group addressed data frames,
+     * IGTK(Integrity Group Transient Key) used to protect multicast management frames, set to true
+     * if supported.
+     * Wi-Fi Aware spec 4.0: 9.5.21.2 Cipher Suite Information attribute
+     */
+    boolean supportGtkAndIgtk;
+
+    /**
+     * BIGTK(Beacon Integrity Group Transient Key) used to protect Beacon frames, set to true if
+     * supported.
+     * Ref: Wi-Fi Aware spec 4.0: 9.5.21.2 Cipher Suite Information attribute
+     */
+    boolean supportBigtksa;
+
+    /**
+     * Enables NCS-BIP-256 for IGTKSA(Integrity Group Transient Key security associations)
+     * and BIGTK(Beacon Integrity Group Transient Key security associations), if set to false will
+     * use NCS-BIP-128 as default
+     * Wi-Fi Aware spec 4.0: 9.5.21.2 Cipher Suite Information attribute
+     */
+    boolean enableNcsBip256;
+
+    /**
+     * Require enhanced frame protection if supported, which includes multicast management frame
+     * protection, group addressed data protection and beacon frame protection.
+     * Wi-Fi Aware spec 4.0: 7.3 frame protection
+     */
+    boolean requiresEnhancedFrameProtection;
 }
diff --git a/wifi/aidl/android/hardware/wifi/NanDiscoveryCommonConfig.aidl b/wifi/aidl/android/hardware/wifi/NanDiscoveryCommonConfig.aidl
index 58777c5..4bedce0 100644
--- a/wifi/aidl/android/hardware/wifi/NanDiscoveryCommonConfig.aidl
+++ b/wifi/aidl/android/hardware/wifi/NanDiscoveryCommonConfig.aidl
@@ -73,8 +73,9 @@
     /**
      * Arbitrary information communicated in discovery packets - there is no semantic meaning to
      * these bytes. They are passed-through from publisher to subscriber as-is with no parsing. Max
-     * length: |NanCapabilities.maxExtendedServiceSpecificInfoLen|. Spec: Service Descriptor
-     * Extension Attribute (SDEA) / Service Info
+     * length: |NanCapabilities.maxExtendedServiceSpecificInfoLen|. This info is using Generic
+     * Service Protocol with setting Service Info type to 2 (Generic). NAN Spec: Service
+     * Descriptor Extension Attribute (SDEA) / Service Info
      */
     byte[] extendedServiceSpecificInfo;
     /**
diff --git a/wifi/aidl/android/hardware/wifi/NanMatchInd.aidl b/wifi/aidl/android/hardware/wifi/NanMatchInd.aidl
index 5a04376..622213c 100644
--- a/wifi/aidl/android/hardware/wifi/NanMatchInd.aidl
+++ b/wifi/aidl/android/hardware/wifi/NanMatchInd.aidl
@@ -19,6 +19,7 @@
 import android.hardware.wifi.NanCipherSuiteType;
 import android.hardware.wifi.NanIdentityResolutionAttribute;
 import android.hardware.wifi.NanPairingConfig;
+import android.hardware.wifi.common.OuiKeyedData;
 
 /**
  * Match indication structure.
@@ -137,4 +138,9 @@
      * The NIRA from peer for NAN pairing verification
      */
     NanIdentityResolutionAttribute peerNira;
+    /**
+     * Optional vendor-specific parameters. Null value indicates
+     * that no vendor data is provided.
+     */
+    @nullable OuiKeyedData[] vendorData;
 }
diff --git a/wifi/aidl/android/hardware/wifi/NanPairingConfirmInd.aidl b/wifi/aidl/android/hardware/wifi/NanPairingConfirmInd.aidl
index a5670ec..692d3d6 100644
--- a/wifi/aidl/android/hardware/wifi/NanPairingConfirmInd.aidl
+++ b/wifi/aidl/android/hardware/wifi/NanPairingConfirmInd.aidl
@@ -19,6 +19,7 @@
 import android.hardware.wifi.NanPairingRequestType;
 import android.hardware.wifi.NanStatus;
 import android.hardware.wifi.NpkSecurityAssociation;
+import android.hardware.wifi.common.OuiKeyedData;
 
 /**
  * NAN pairing confirmation indication structure. Event indication is
@@ -51,4 +52,9 @@
      * The security association negotiated for the pairing, can be cached for future verification
      */
     NpkSecurityAssociation npksa;
+    /**
+     * Optional vendor-specific parameters. Null value indicates
+     * that no vendor data is provided.
+     */
+    @nullable OuiKeyedData[] vendorData;
 }
diff --git a/wifi/aidl/android/hardware/wifi/NanPairingRequest.aidl b/wifi/aidl/android/hardware/wifi/NanPairingRequest.aidl
index 0c2080b..950d1e2 100644
--- a/wifi/aidl/android/hardware/wifi/NanPairingRequest.aidl
+++ b/wifi/aidl/android/hardware/wifi/NanPairingRequest.aidl
@@ -18,6 +18,7 @@
 
 import android.hardware.wifi.NanPairingRequestType;
 import android.hardware.wifi.NanPairingSecurityConfig;
+import android.hardware.wifi.common.OuiKeyedData;
 
 /**
  * NAN pairing initiate request.
@@ -54,4 +55,9 @@
      * Security config used for the pairing
      */
     NanPairingSecurityConfig securityConfig;
+    /**
+     * Optional vendor-specific parameters. Null value indicates
+     * that no vendor data is provided.
+     */
+    @nullable OuiKeyedData[] vendorData;
 }
diff --git a/wifi/aidl/android/hardware/wifi/NanPairingRequestInd.aidl b/wifi/aidl/android/hardware/wifi/NanPairingRequestInd.aidl
index ec8548f..7e98bac 100644
--- a/wifi/aidl/android/hardware/wifi/NanPairingRequestInd.aidl
+++ b/wifi/aidl/android/hardware/wifi/NanPairingRequestInd.aidl
@@ -18,6 +18,7 @@
 
 import android.hardware.wifi.NanIdentityResolutionAttribute;
 import android.hardware.wifi.NanPairingRequestType;
+import android.hardware.wifi.common.OuiKeyedData;
 
 /**
  * NAN pairing request indication message structure.
@@ -58,4 +59,9 @@
      * The NIRA from peer for NAN pairing verification
      */
     NanIdentityResolutionAttribute peerNira;
+    /**
+     * Optional vendor-specific parameters. Null value indicates
+     * that no vendor data is provided.
+     */
+    @nullable OuiKeyedData[] vendorData;
 }
diff --git a/wifi/aidl/android/hardware/wifi/NanPublishRequest.aidl b/wifi/aidl/android/hardware/wifi/NanPublishRequest.aidl
index 956a7df..ae75caf 100644
--- a/wifi/aidl/android/hardware/wifi/NanPublishRequest.aidl
+++ b/wifi/aidl/android/hardware/wifi/NanPublishRequest.aidl
@@ -20,6 +20,7 @@
 import android.hardware.wifi.NanPairingConfig;
 import android.hardware.wifi.NanPublishType;
 import android.hardware.wifi.NanTxType;
+import android.hardware.wifi.common.OuiKeyedData;
 
 /**
  * Publish request. Specifies a publish discovery operation.
@@ -55,4 +56,9 @@
      * The Identity key for pairing, will generate NIRA for verification by the peer
      */
     byte[16] identityKey;
+    /**
+     * Optional vendor-specific parameters. Null value indicates
+     * that no vendor data is provided.
+     */
+    @nullable OuiKeyedData[] vendorData;
 }
diff --git a/wifi/aidl/android/hardware/wifi/NanRespondToPairingIndicationRequest.aidl b/wifi/aidl/android/hardware/wifi/NanRespondToPairingIndicationRequest.aidl
index fab2a40..0527f06 100644
--- a/wifi/aidl/android/hardware/wifi/NanRespondToPairingIndicationRequest.aidl
+++ b/wifi/aidl/android/hardware/wifi/NanRespondToPairingIndicationRequest.aidl
@@ -18,6 +18,7 @@
 
 import android.hardware.wifi.NanPairingRequestType;
 import android.hardware.wifi.NanPairingSecurityConfig;
+import android.hardware.wifi.common.OuiKeyedData;
 
 /**
  * Response to a pairing request from a peer.
@@ -51,4 +52,9 @@
      * Security config used for the pairing
      */
     NanPairingSecurityConfig securityConfig;
+    /**
+     * Optional vendor-specific parameters. Null value indicates
+     * that no vendor data is provided.
+     */
+    @nullable OuiKeyedData[] vendorData;
 }
diff --git a/wifi/aidl/android/hardware/wifi/NanSubscribeRequest.aidl b/wifi/aidl/android/hardware/wifi/NanSubscribeRequest.aidl
index 0b246ed..e7094bf 100644
--- a/wifi/aidl/android/hardware/wifi/NanSubscribeRequest.aidl
+++ b/wifi/aidl/android/hardware/wifi/NanSubscribeRequest.aidl
@@ -21,6 +21,7 @@
 import android.hardware.wifi.NanPairingConfig;
 import android.hardware.wifi.NanSrfType;
 import android.hardware.wifi.NanSubscribeType;
+import android.hardware.wifi.common.OuiKeyedData;
 
 /**
  * Subscribe request. Specifies a subscribe discovery operation.
@@ -76,4 +77,9 @@
      * The Identity key for pairing, will generate NIRA for verification by the peer
      */
     byte[16] identityKey;
+    /**
+     * Optional vendor-specific parameters. Null value indicates
+     * that no vendor data is provided.
+     */
+    @nullable OuiKeyedData[] vendorData;
 }
diff --git a/wifi/aidl/android/hardware/wifi/RttCapabilities.aidl b/wifi/aidl/android/hardware/wifi/RttCapabilities.aidl
index 7c47ed5..c193924 100644
--- a/wifi/aidl/android/hardware/wifi/RttCapabilities.aidl
+++ b/wifi/aidl/android/hardware/wifi/RttCapabilities.aidl
@@ -18,6 +18,7 @@
 
 import android.hardware.wifi.RttBw;
 import android.hardware.wifi.RttPreamble;
+import android.hardware.wifi.common.OuiKeyedData;
 
 /**
  * RTT Capabilities.
@@ -33,24 +34,25 @@
      */
     boolean rttFtmSupported;
     /**
-     * Whether initiator supports LCI request. Applies to 2-sided RTT.
+     * Whether initiator supports Location Configuration Information (LCI) request. Applies to
+     * 2-sided RTT.
      */
     boolean lciSupported;
     /**
-     * Whether initiator supports LCR request. Applies to 2-sided RTT.
+     * Whether initiator supports Location Civic Report (LCR) request. Applies to 2-sided RTT.
      */
     boolean lcrSupported;
     /**
-     * Whether 11mc responder mode is supported.
+     * Whether IEEE 802.11mc responder mode is supported.
      */
     boolean responderSupported;
     /**
-     * Bit mask indicating what preamble is supported by initiator.
+     * Bit mask indicating what preamble is supported by IEEE 802.11mc initiator.
      * Combination of |RttPreamble| values.
      */
     RttPreamble preambleSupport;
     /**
-     * Bit mask indicating what BW is supported by initiator.
+     * Bit mask indicating what BW is supported by IEEE 802.11mc initiator.
      * Combination of |RttBw| values.
      */
     RttBw bwSupport;
@@ -59,4 +61,27 @@
      * For instance, version 4.0 must be 40 and version 4.3 must be 43 etc.
      */
     byte mcVersion;
+    /**
+     * Bit mask indicating what preamble is supported by IEEE 802.11az initiator.
+     * Combination of |RttPreamble| values.
+     */
+    int azPreambleSupport;
+    /**
+     * Bit mask indicating what BW is supported by IEEE 802.11az initiator.
+     * Combination of |RttBw| values.
+     */
+    int azBwSupport;
+    /**
+     * Whether the initiator supports IEEE 802.11az Non-Trigger-based (non-TB) measurement.
+     */
+    boolean ntbInitiatorSupported;
+    /**
+     * Whether IEEE 802.11az Non-Trigger-based (non-TB) responder mode is supported.
+     */
+    boolean ntbResponderSupported;
+    /**
+     * Optional vendor-specific parameters. Null value indicates
+     * that no vendor data is provided.
+     */
+    @nullable OuiKeyedData[] vendorData;
 }
diff --git a/wifi/aidl/android/hardware/wifi/RttConfig.aidl b/wifi/aidl/android/hardware/wifi/RttConfig.aidl
index fc2c2e0..496ffd2 100644
--- a/wifi/aidl/android/hardware/wifi/RttConfig.aidl
+++ b/wifi/aidl/android/hardware/wifi/RttConfig.aidl
@@ -21,6 +21,7 @@
 import android.hardware.wifi.RttPreamble;
 import android.hardware.wifi.RttType;
 import android.hardware.wifi.WifiChannelInfo;
+import android.hardware.wifi.common.OuiKeyedData;
 
 /**
  * RTT configuration.
@@ -32,7 +33,7 @@
      */
     byte[6] addr;
     /**
-     * 1-sided or 2-sided RTT.
+     * 1-sided or 2-sided RTT (IEEE 802.11mc or IEEE 802. 11az).
      */
     RttType type;
     /**
@@ -47,6 +48,8 @@
      * Time interval between bursts (units: 100 ms).
      * Applies to 1-sided and 2-sided RTT multi-burst requests.
      * Range: 0-31, 0: no preference by initiator (2-sided RTT).
+     *
+     * Note: Applicable to IEEE 802.11mc only.
      */
     int burstPeriod;
     /**
@@ -60,6 +63,9 @@
      * number of RTT results is the following:
      * for 1-sided RTT: max num of RTT results = (2^num_burst)*(num_frames_per_burst)
      * for 2-sided RTT: max num of RTT results = (2^num_burst)*(num_frames_per_burst - 1)
+     *
+     * Note: Applicable to IEEE 802.11mc only. For IEEE 802.11az refer
+     * |RttConfig.txLtfRepetitionCount|.
      */
     int numBurst;
     /**
@@ -70,6 +76,8 @@
      * equals the number of FTM frames that the
      * initiator will request that the responder sends
      * in a single frame.
+     *
+     * Note: Applicable to IEEE 802.11mc only.
      */
     int numFramesPerBurst;
     /**
@@ -95,8 +103,8 @@
      */
     boolean mustRequestLcr;
     /**
-     * Applies to 1-sided and 2-sided RTT. Valid values will
-     * be 2-11 and 15 as specified by the 802.11mc std for
+     * Applies to 1-sided and 2-sided IEEE 802.11mc RTT. Valid values will
+     * be 2-11 and 15 as specified by the IEEE 802.11mc std for
      * the FTM parameter burst duration. In a multi-burst
      * request, if responder overrides with larger value,
      * the initiator will return failure. In a single-burst
@@ -113,4 +121,23 @@
      * RTT BW to be used in the RTT frames.
      */
     RttBw bw;
+    /**
+     * IEEE 802.11az Non-Trigger-based (non-TB) minimum measurement time in units of 100
+     * microseconds.
+     *
+     * Reference: IEEE Std 802.11az-2022 spec, section 9.4.2.298 Ranging Parameters element.
+     */
+    long ntbMinMeasurementTime;
+    /**
+     * IEEE 802.11az Non-Trigger-based (non-TB) maximum measurement time in units of 10
+     * milliseconds.
+     *
+     * Reference: IEEE Std 802.11az-2022 spec, section 9.4.2.298 Ranging Parameters element.
+     */
+    long ntbMaxMeasurementTime;
+    /**
+     * Optional vendor-specific parameters. Null value indicates
+     * that no vendor data is provided.
+     */
+    @nullable OuiKeyedData[] vendorData;
 }
diff --git a/wifi/aidl/android/hardware/wifi/RttPreamble.aidl b/wifi/aidl/android/hardware/wifi/RttPreamble.aidl
index e460a94..21df171 100644
--- a/wifi/aidl/android/hardware/wifi/RttPreamble.aidl
+++ b/wifi/aidl/android/hardware/wifi/RttPreamble.aidl
@@ -22,6 +22,7 @@
 @VintfStability
 @Backing(type="int")
 enum RttPreamble {
+    INVALID = 0,
     LEGACY = 0x1,
     HT = 0x2,
     VHT = 0x4,
diff --git a/wifi/aidl/android/hardware/wifi/RttResult.aidl b/wifi/aidl/android/hardware/wifi/RttResult.aidl
index 6c45e2c..2f9aefe 100644
--- a/wifi/aidl/android/hardware/wifi/RttResult.aidl
+++ b/wifi/aidl/android/hardware/wifi/RttResult.aidl
@@ -21,6 +21,7 @@
 import android.hardware.wifi.RttType;
 import android.hardware.wifi.WifiInformationElement;
 import android.hardware.wifi.WifiRateInfo;
+import android.hardware.wifi.common.OuiKeyedData;
 
 /**
  * RTT results.
@@ -33,6 +34,8 @@
     byte[6] addr;
     /**
      * Burst number in a multi-burst request.
+     *
+     * Note: Applicable to 1-sided RTT and 2-sided IEEE 802.11mc only.
      */
     int burstNum;
     /**
@@ -45,7 +48,7 @@
     int successNumber;
     /**
      * Maximum number of "FTM frames per burst" supported by
-     * the responder STA. Applies to 2-sided RTT only.
+     * the responder STA. Applies to 2-sided IEEE 802.11mc RTT only.
      * If reponder overrides with larger value:
      * - for single-burst request, initiator will truncate the
      * larger value and send a TMR_STOP after receiving as
@@ -59,10 +62,8 @@
      */
     RttStatus status;
     /**
-     * If status is RTT_STATUS_FAIL_BUSY_TRY_LATER,
-     * this will be the time provided by the responder as to
-     * when the request can be tried again. Applies to 2-sided
-     * RTT only. In sec, 1-31 sec.
+     * If status is RTT_STATUS_FAIL_BUSY_TRY_LATER, this will be the time provided by the responder
+     * as to when the request can be tried again. Applies to 2-sided RTT only. In sec, 1-31 sec.
      */
     byte retryAfterDuration;
     /**
@@ -104,11 +105,13 @@
      */
     int distanceInMm;
     /**
-     * Standard deviation in mm (optional).
+     * Standard deviation in mm.
      */
     int distanceSdInMm;
     /**
      * Difference between max and min distance recorded in mm (optional).
+     *
+     * Note: Only applicable for IEEE 802.11mc
      */
     int distanceSpreadInMm;
     /**
@@ -116,21 +119,20 @@
      */
     long timeStampInUs;
     /**
-     * Actual time taken by the FW to finish one burst
-     * measurement (in ms). Applies to 1-sided and 2-sided RTT.
+     * Actual time taken by the FW to finish one burst measurement (in ms). Applies to 1-sided
+     * and 2-sided IEEE 802.11mc RTT.
      */
     int burstDurationInMs;
     /**
-     * Number of bursts allowed by the responder. Applies
-     * to 2-sided RTT only.
+     * Number of bursts allowed by the responder. Applies to 2-sided IEEE 802.11mc RTT only.
      */
     int negotiatedBurstNum;
     /**
-     * For 11mc only.
+     * For IEEE 802.11mc and IEEE 802.11az only.
      */
     WifiInformationElement lci;
     /**
-     * For 11mc only.
+     * For IEEE 802.11mc and IEEE 802.11az only.
      */
     WifiInformationElement lcr;
     /**
@@ -140,8 +142,75 @@
     int channelFreqMHz;
     /**
      * RTT packet bandwidth.
-     * This value is an average bandwidth of the bandwidths of measurement
-     * frames. Cap the average close to a specific valid RttBw.
+     * This value is an average bandwidth of the bandwidths of measurement frames. Cap the average
+     * close to a specific valid RttBw.
      */
     RttBw packetBw;
+    /**
+     * Multiple transmissions of HE-LTF symbols in an HE (I2R) Ranging NDP. An HE-LTF repetition
+     * value of 1 indicates no repetitions.
+     *
+     * Note: A required field for IEEE 802.11az result.
+     */
+    byte i2rTxLtfRepetitionCount;
+    /**
+     * Multiple transmissions of HE-LTF symbols in an HE (R2I) Ranging NDP. An HE-LTF repetition
+     * value of 1 indicates no repetitions.
+     *
+     * Note: A required field for IEEE 802.11az result.
+     */
+    byte r2iTxLtfRepetitionCount;
+    /**
+     * Minimum non-trigger based (non-TB) dynamic measurement time in units of 100 microseconds
+     * assigned by the IEEE 802.11az responder.
+     *
+     * After initial non-TB negotiation, if the next ranging request for this peer comes in between
+     * [ntbMinMeasurementTime, ntbMaxMeasurementTime], vendor software shall do the NDPA sounding
+     * sequence for dynamic non-TB measurement.
+     *
+     * If the ranging request for this peer comes sooner than minimum measurement time, vendor
+     * software shall return the cached result of the last measurement including the time stamp
+     * |RttResult.timestamp|.
+     *
+     * Reference: IEEE Std 802.11az-2022 spec, section 9.4.2.298 Ranging Parameters element.
+     *
+     * Note: A required field for IEEE 802.11az result.
+     */
+    long ntbMinMeasurementTime;
+    /**
+     * Maximum non-trigger based (non-TB) dynamic measurement time in units of 10 milliseconds
+     * assigned by the IEEE 802.11az responder.
+     *
+     * After initial non-TB negotiation, if the next ranging request for this peer comes in between
+     * [ntbMinMeasurementTime, ntbMaxMeasurementTime], vendor software shall do the NDPA sounding
+     * sequence for dynamic non-TB measurement.
+     *
+     * If the ranging request for this peer comes later than the maximum measurement time, vendor
+     * software shall clean up any existing IEEE 802.11ax non-TB ranging session and re-do the
+     * non-TB ranging negotiation.
+     *
+     * Reference: IEEE Std 802.11az-2022 spec, section 9.4.2.298 Ranging Parameters element.
+     *
+     * Note: A required field for IEEE 802.11az result.
+     */
+    long ntbMaxMeasurementTime;
+    /**
+     * Number of transmit space-time streams used. Value is in the range 1 to 8.
+     *
+     * Note: Maximum limit is ultimately defined by the number of antennas that can be supported.
+     * A required field for IEEE 802.11az result.
+     */
+    byte numTxSpatialStreams;
+    /**
+     * Number of receive space-time streams used. Value is in the range 1 to 8.
+     *
+     * Note: Maximum limit is ultimately defined by the number of antennas that can be supported.
+     * A required field for IEEE 802.11az result.
+     */
+    byte numRxSpatialStreams;
+    /**
+     * Optional vendor-specific parameters. Null value indicates
+     * that no vendor data is provided.
+     */
+    @nullable OuiKeyedData[] vendorData;
 }
diff --git a/wifi/aidl/android/hardware/wifi/RttType.aidl b/wifi/aidl/android/hardware/wifi/RttType.aidl
index e95a928..3f1a2f1 100644
--- a/wifi/aidl/android/hardware/wifi/RttType.aidl
+++ b/wifi/aidl/android/hardware/wifi/RttType.aidl
@@ -23,5 +23,18 @@
 @Backing(type="int")
 enum RttType {
     ONE_SIDED = 1,
+    /**
+     * Two-sided RTT 11mc type.
+     *
+     * Note: TWO_SIDED was used for IEEE 802.11mc. Use TWO_SIDED_11MC for IEEE 802.11mc instead.
+     */
     TWO_SIDED = 2,
+    /**
+     * Two-sided RTT 11mc type is same as two-sided.
+     */
+    TWO_SIDED_11MC = TWO_SIDED,
+    /**
+     * Two-sided RTT 11az non trigger based (non-TB) type.
+     */
+    TWO_SIDED_11AZ_NTB = 3,
 }
diff --git a/wifi/aidl/android/hardware/wifi/StaRoamingState.aidl b/wifi/aidl/android/hardware/wifi/StaRoamingState.aidl
index d75d323..6872a17 100644
--- a/wifi/aidl/android/hardware/wifi/StaRoamingState.aidl
+++ b/wifi/aidl/android/hardware/wifi/StaRoamingState.aidl
@@ -32,4 +32,9 @@
      * the |StaRoamingConfig| parameters set using |configureRoaming|.
      */
     ENABLED = 1,
+    /**
+     * Driver/Firmware is allowed to roam more aggressively. For instance,
+     * roaming can be triggered at higher RSSI thresholds than normal.
+     */
+    AGGRESSIVE = 2,
 }
diff --git a/wifi/aidl/android/hardware/wifi/TwtCapabilities.aidl b/wifi/aidl/android/hardware/wifi/TwtCapabilities.aidl
new file mode 100644
index 0000000..28d16f0
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/TwtCapabilities.aidl
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Target Wake Time (TWT) Capabilities supported.
+ *
+ * TWT allows Wi-Fi stations to manage activity in a network by scheduling to operate at different
+ * times. This minimizes the contention and reduces the required amount of time that a station
+ * utilizing a power management mode needs to be awake.
+ *
+ * IEEE 802.11ax standard defines two modes of TWT operation:
+ *  - Individual TWT (default mode of operation if TWT requester is supported)
+ *  - Broadcast TWT
+ */
+@VintfStability
+parcelable TwtCapabilities {
+    /**
+     * Whether the TWT requester mode supported.
+     */
+    boolean isTwtRequesterSupported;
+    /**
+     * Whether the TWT responder mode supported.
+     */
+    boolean isTwtResponderSupported;
+    /**
+     * Whether the Broadcast TWT mode (TWT scheduling STA) supported.
+     */
+    boolean isBroadcastTwtSupported;
+    /**
+     * Whether supports Flexible TWT schedules.
+     */
+    boolean isFlexibleTwtScheduleSupported;
+    /**
+     * Minimum TWT wake duration in microseconds.
+     */
+    int minWakeDurationUs;
+    /**
+     * Maximum TWT wake duration in microseconds.
+     */
+    int maxWakeDurationUs;
+    /**
+     * Minimum TWT wake interval in microseconds.
+     */
+    long minWakeIntervalUs;
+    /**
+     * Maximum TWT wake interval in microseconds.
+     */
+    long maxWakeIntervalUs;
+}
diff --git a/wifi/aidl/android/hardware/wifi/TwtRequest.aidl b/wifi/aidl/android/hardware/wifi/TwtRequest.aidl
new file mode 100644
index 0000000..6964a39
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/TwtRequest.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Target Wake Time (TWT) Request
+ */
+@VintfStability
+parcelable TwtRequest {
+    /**
+     * MLO Link id in case TWT is requesting for MLO connection. Otherwise -1.
+     */
+    int mloLinkId;
+    /**
+     * Minimum TWT wake duration in microseconds.
+     */
+    int minWakeDurationUs;
+    /**
+     * Maximum TWT wake duration in microseconds.
+     *
+     * As per IEEE 802.11ax spec, section 9.4.2.199 TWT element, the maximum wake duration is
+     * 65280 microseconds.
+     */
+    int maxWakeDurationUs;
+    /**
+     * Minimum TWT wake interval in microseconds.
+     */
+    long minWakeIntervalUs;
+    /**
+     * Maximum TWT wake interval in microseconds.
+     *
+     * As per IEEE 802.11ax spec, section 9.4.2.199 TWT element, the maximum wake interval is
+     * 65535 * 2^31 microseconds.
+     */
+    long maxWakeIntervalUs;
+}
diff --git a/wifi/aidl/android/hardware/wifi/TwtSession.aidl b/wifi/aidl/android/hardware/wifi/TwtSession.aidl
new file mode 100644
index 0000000..2d7e819
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/TwtSession.aidl
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Target Wake Time (TWT) Session
+ */
+@VintfStability
+parcelable TwtSession {
+    @VintfStability
+    @Backing(type="byte")
+    enum TwtNegotiationType {
+        INDIVIDUAL = 0,
+        BROADCAST = 1,
+    }
+
+    /**
+     * An unique identifier for the session.
+     */
+    int sessionId;
+
+    /**
+     * MLO Link id in case of MLO connection. Otherwise -1.
+     */
+    int mloLinkId;
+
+    /**
+     * TWT service period in microseconds.
+     */
+    int wakeDurationUs;
+
+    /**
+     * Time interval in microseconds between two successive TWT service periods.
+     */
+    long wakeIntervalUs;
+
+    /**
+     * TWT negotiation type.
+     */
+    TwtNegotiationType negotiationType;
+
+    /**
+     * Whether the TWT session is trigger enabled or non-trigger enabled.
+     */
+    boolean isTriggerEnabled;
+
+    /**
+     * Whether the TWT session is announced or unannounced.
+     */
+    boolean isAnnounced;
+
+    /**
+     * Whether the TWT session is implicit or explicit.
+     */
+    boolean isImplicit;
+
+    /**
+     * Whether the TWT session is protected or not.
+     */
+    boolean isProtected;
+
+    /**
+     * Whether the TWT session can be updated.
+     */
+    boolean isUpdatable;
+
+    /**
+     * Whether the TWT session can be suspended and then resumed.
+     */
+    boolean isSuspendable;
+
+    /**
+     * Whether AP (TWT responder) intends to go to doze state outside of TWT Service Periods.
+     *
+     * Refer IEEE 802.11 spec, Section 10.47.7 (TWT Sleep Setup).
+     */
+    boolean isResponderPmModeEnabled;
+}
diff --git a/wifi/aidl/android/hardware/wifi/TwtSessionStats.aidl b/wifi/aidl/android/hardware/wifi/TwtSessionStats.aidl
new file mode 100644
index 0000000..ba70426
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/TwtSessionStats.aidl
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Target Wake Time (TWT) Session Stats
+ */
+@VintfStability
+parcelable TwtSessionStats {
+    /**
+     * Average number of Tx packets in each wake duration.
+     */
+    int avgTxPktCount;
+
+    /**
+     * Average number of Rx packets in each wake duration.
+     */
+    int avgRxPktCount;
+
+    /**
+     * Average bytes per Tx packets in each wake duration.
+     */
+    int avgTxPktSize;
+
+    /**
+     * Average bytes per Rx packets in each wake duration.
+     */
+    int avgRxPktSize;
+
+    /**
+     * Average End of Service period in microseconds.
+     */
+    int avgEospDurationUs;
+
+    /**
+     * Count of early terminations.
+     */
+    int eospCount;
+}
diff --git a/wifi/aidl/default/Android.bp b/wifi/aidl/default/Android.bp
index 91d609d..31a3531 100644
--- a/wifi/aidl/default/Android.bp
+++ b/wifi/aidl/default/Android.bp
@@ -105,7 +105,7 @@
         "libwifi-hal",
         "libwifi-system-iface",
         "libxml2",
-        "android.hardware.wifi-V1-ndk",
+        "android.hardware.wifi-V2-ndk",
     ],
 
     export_include_dirs: ["."],
@@ -132,7 +132,7 @@
         "libwifi-hal",
         "libwifi-system-iface",
         "libxml2",
-        "android.hardware.wifi-V1-ndk",
+        "android.hardware.wifi-V2-ndk",
     ],
     static_libs: ["android.hardware.wifi-service-lib"],
     init_rc: ["android.hardware.wifi-service.rc"],
@@ -161,7 +161,7 @@
         "libwifi-hal",
         "libwifi-system-iface",
         "libxml2",
-        "android.hardware.wifi-V1-ndk",
+        "android.hardware.wifi-V2-ndk",
     ],
     static_libs: ["android.hardware.wifi-service-lib"],
     init_rc: ["android.hardware.wifi-service-lazy.rc"],
@@ -192,7 +192,8 @@
     static_libs: [
         "libgmock",
         "libgtest",
-        "android.hardware.wifi-V1-ndk",
+        "android.hardware.wifi-V2-ndk",
+        "android.hardware.wifi.common-V1-ndk",
         "android.hardware.wifi-service-lib",
     ],
     shared_libs: [
diff --git a/wifi/aidl/default/aidl_struct_util.cpp b/wifi/aidl/default/aidl_struct_util.cpp
index 83e1193..0f0c77e 100644
--- a/wifi/aidl/default/aidl_struct_util.cpp
+++ b/wifi/aidl/default/aidl_struct_util.cpp
@@ -59,6 +59,8 @@
             return IWifiChip::FeatureSetMask::P2P_RAND_MAC;
         case WIFI_FEATURE_AFC_CHANNEL:
             return IWifiChip::FeatureSetMask::SET_AFC_CHANNEL_ALLOWANCE;
+        case WIFI_FEATURE_SET_VOIP_MODE:
+            return IWifiChip::FeatureSetMask::SET_VOIP_MODE;
     };
     CHECK(false) << "Unknown legacy feature: " << feature;
     return {};
@@ -92,6 +94,10 @@
             return IWifiStaIface::FeatureSetMask::ND_OFFLOAD;
         case WIFI_FEATURE_MKEEP_ALIVE:
             return IWifiStaIface::FeatureSetMask::KEEP_ALIVE;
+        case WIFI_FEATURE_ROAMING_MODE_CONTROL:
+            return IWifiStaIface::FeatureSetMask::ROAMING_MODE_CONTROL;
+        case WIFI_FEATURE_CACHED_SCAN_RESULTS:
+            return IWifiStaIface::FeatureSetMask::CACHED_SCAN_DATA;
     };
     CHECK(false) << "Unknown legacy feature: " << feature;
     return {};
@@ -109,7 +115,8 @@
                                       WIFI_FEATURE_INFRA_60G,
                                       WIFI_FEATURE_SET_LATENCY_MODE,
                                       WIFI_FEATURE_P2P_RAND_MAC,
-                                      WIFI_FEATURE_AFC_CHANNEL};
+                                      WIFI_FEATURE_AFC_CHANNEL,
+                                      WIFI_FEATURE_SET_VOIP_MODE};
     for (const auto feature : features) {
         if (feature & legacy_feature_set) {
             *aidl_feature_set |= static_cast<uint32_t>(convertLegacyChipFeatureToAidl(feature));
@@ -457,7 +464,8 @@
          {WIFI_FEATURE_GSCAN, WIFI_FEATURE_LINK_LAYER_STATS, WIFI_FEATURE_RSSI_MONITOR,
           WIFI_FEATURE_CONTROL_ROAMING, WIFI_FEATURE_IE_WHITELIST, WIFI_FEATURE_SCAN_RAND,
           WIFI_FEATURE_INFRA_5G, WIFI_FEATURE_HOTSPOT, WIFI_FEATURE_PNO, WIFI_FEATURE_TDLS,
-          WIFI_FEATURE_TDLS_OFFCHANNEL, WIFI_FEATURE_CONFIG_NDO, WIFI_FEATURE_MKEEP_ALIVE}) {
+          WIFI_FEATURE_TDLS_OFFCHANNEL, WIFI_FEATURE_CONFIG_NDO, WIFI_FEATURE_MKEEP_ALIVE,
+          WIFI_FEATURE_ROAMING_MODE_CONTROL, WIFI_FEATURE_CACHED_SCAN_RESULTS}) {
         if (feature & legacy_feature_set) {
             *aidl_feature_set |= static_cast<uint32_t>(convertLegacyStaIfaceFeatureToAidl(feature));
         }
@@ -1147,6 +1155,8 @@
             return legacy_hal::ROAMING_ENABLE;
         case StaRoamingState::DISABLED:
             return legacy_hal::ROAMING_DISABLE;
+        case StaRoamingState::AGGRESSIVE:
+            return legacy_hal::ROAMING_AGGRESSIVE;
     };
     CHECK(false);
 }
@@ -2088,6 +2098,17 @@
     memcpy(legacy_request->scid, aidl_request.securityConfig.scid.data(), legacy_request->scid_len);
     legacy_request->publish_subscribe_id = static_cast<uint8_t>(aidl_request.discoverySessionId);
 
+    legacy_request->csia_capabilities |=
+            aidl_request.securityConfig.enable16ReplyCountersForTksa ? 0x1 : 0x0;
+    legacy_request->csia_capabilities |=
+            aidl_request.securityConfig.enable16ReplyCountersForGtksa ? 0x8 : 0x0;
+    if (aidl_request.securityConfig.supportGtkAndIgtk) {
+        legacy_request->csia_capabilities |= aidl_request.securityConfig.supportBigtksa ? 0x4 : 0x2;
+    }
+    legacy_request->csia_capabilities |= aidl_request.securityConfig.enableNcsBip256 ? 0x16 : 0x0;
+    legacy_request->gtk_protection =
+            aidl_request.securityConfig.requiresEnhancedFrameProtection ? 1 : 0;
+
     return true;
 }
 
@@ -2170,6 +2191,17 @@
     memcpy(legacy_request->scid, aidl_request.securityConfig.scid.data(), legacy_request->scid_len);
     legacy_request->publish_subscribe_id = static_cast<uint8_t>(aidl_request.discoverySessionId);
 
+    legacy_request->csia_capabilities |=
+            aidl_request.securityConfig.enable16ReplyCountersForTksa ? 0x1 : 0x0;
+    legacy_request->csia_capabilities |=
+            aidl_request.securityConfig.enable16ReplyCountersForGtksa ? 0x8 : 0x0;
+    if (aidl_request.securityConfig.supportGtkAndIgtk) {
+        legacy_request->csia_capabilities |= aidl_request.securityConfig.supportBigtksa ? 0x4 : 0x2;
+    }
+    legacy_request->csia_capabilities |= aidl_request.securityConfig.enableNcsBip256 ? 0x16 : 0x0;
+    legacy_request->gtk_protection =
+            aidl_request.securityConfig.requiresEnhancedFrameProtection ? 1 : 0;
+
     return true;
 }
 
@@ -2394,8 +2426,11 @@
     switch (type) {
         case RttType::ONE_SIDED:
             return legacy_hal::RTT_TYPE_1_SIDED;
-        case RttType::TWO_SIDED:
-            return legacy_hal::RTT_TYPE_2_SIDED;
+        case RttType::TWO_SIDED_11MC:
+            // Same as RttType::TWO_SIDED
+            return legacy_hal::RTT_TYPE_2_SIDED_11MC;
+        case RttType::TWO_SIDED_11AZ_NTB:
+            return legacy_hal::RTT_TYPE_2_SIDED_11AZ_NTB;
     };
     CHECK(false);
 }
@@ -2404,8 +2439,11 @@
     switch (type) {
         case legacy_hal::RTT_TYPE_1_SIDED:
             return RttType::ONE_SIDED;
-        case legacy_hal::RTT_TYPE_2_SIDED:
-            return RttType::TWO_SIDED;
+        case legacy_hal::RTT_TYPE_2_SIDED_11MC:
+            // Same as legacy_hal::RTT_TYPE_2_SIDED
+            return RttType::TWO_SIDED_11MC;
+        case legacy_hal::RTT_TYPE_2_SIDED_11AZ_NTB:
+            return RttType::TWO_SIDED_11AZ_NTB;
     };
     CHECK(false) << "Unknown legacy type: " << type;
 }
@@ -2485,6 +2523,8 @@
             return legacy_hal::WIFI_RTT_PREAMBLE_HE;
         case RttPreamble::EHT:
             return legacy_hal::WIFI_RTT_PREAMBLE_EHT;
+        case RttPreamble::INVALID:
+            return legacy_hal::WIFI_RTT_PREAMBLE_INVALID;
     };
     CHECK(false);
 }
@@ -2501,6 +2541,8 @@
             return RttPreamble::HE;
         case legacy_hal::WIFI_RTT_PREAMBLE_EHT:
             return RttPreamble::EHT;
+        case legacy_hal::WIFI_RTT_PREAMBLE_INVALID:
+            return RttPreamble::INVALID;
     };
     CHECK(false) << "Unknown legacy type: " << type;
 }
@@ -2690,6 +2732,20 @@
     return true;
 }
 
+bool convertAidlRttConfigToLegacyV3(const RttConfig& aidl_config,
+                                    legacy_hal::wifi_rtt_config_v3* legacy_config) {
+    if (!legacy_config) {
+        return false;
+    }
+    *legacy_config = {};
+    if (!convertAidlRttConfigToLegacy(aidl_config, &(legacy_config->rtt_config))) {
+        return false;
+    }
+    legacy_config->ntb_min_measurement_time = aidl_config.ntbMinMeasurementTime;
+    legacy_config->ntb_max_measurement_time = aidl_config.ntbMaxMeasurementTime;
+    return true;
+}
+
 bool convertAidlVectorOfRttConfigToLegacy(
         const std::vector<RttConfig>& aidl_configs,
         std::vector<legacy_hal::wifi_rtt_config>* legacy_configs) {
@@ -2699,7 +2755,24 @@
     *legacy_configs = {};
     for (const auto& aidl_config : aidl_configs) {
         legacy_hal::wifi_rtt_config legacy_config;
-        if (!convertAidlRttConfigToLegacy(aidl_config, &legacy_config)) {
+        if (!convertAidlRttConfigToLegacy(aidl_config, &(legacy_config))) {
+            return false;
+        }
+        legacy_configs->push_back(legacy_config);
+    }
+    return true;
+}
+
+bool convertAidlVectorOfRttConfigToLegacyV3(
+        const std::vector<RttConfig>& aidl_configs,
+        std::vector<legacy_hal::wifi_rtt_config_v3>* legacy_configs) {
+    if (!legacy_configs) {
+        return false;
+    }
+    *legacy_configs = {};
+    for (const auto& aidl_config : aidl_configs) {
+        legacy_hal::wifi_rtt_config_v3 legacy_config;
+        if (!convertAidlRttConfigToLegacyV3(aidl_config, &legacy_config)) {
             return false;
         }
         legacy_configs->push_back(legacy_config);
@@ -2768,6 +2841,34 @@
     return true;
 }
 
+RttPreamble convertLegacyRttPreambleBitmapToAidl(byte legacyPreambleBitmap) {
+    int32_t aidlPreambleBitmap = 0;
+    for (const auto flag : {legacy_hal::WIFI_RTT_PREAMBLE_LEGACY, legacy_hal::WIFI_RTT_PREAMBLE_HT,
+                            legacy_hal::WIFI_RTT_PREAMBLE_VHT, legacy_hal::WIFI_RTT_PREAMBLE_HE,
+                            legacy_hal::WIFI_RTT_PREAMBLE_EHT}) {
+        if (legacyPreambleBitmap & flag) {
+            aidlPreambleBitmap |= static_cast<std::underlying_type<RttPreamble>::type>(
+                    convertLegacyRttPreambleToAidl(flag));
+        }
+    }
+
+    return static_cast<RttPreamble>(aidlPreambleBitmap);
+}
+
+RttBw convertLegacyRttBwBitmapToAidl(byte legacyBwBitmap) {
+    int32_t aidlBwBitmap = 0;
+    for (const auto flag :
+         {legacy_hal::WIFI_RTT_BW_5, legacy_hal::WIFI_RTT_BW_10, legacy_hal::WIFI_RTT_BW_20,
+          legacy_hal::WIFI_RTT_BW_40, legacy_hal::WIFI_RTT_BW_80, legacy_hal::WIFI_RTT_BW_160,
+          legacy_hal::WIFI_RTT_BW_320}) {
+        if (legacyBwBitmap & flag) {
+            aidlBwBitmap |=
+                    static_cast<std::underlying_type<RttBw>::type>(convertLegacyRttBwToAidl(flag));
+        }
+    }
+    return static_cast<RttBw>(aidlBwBitmap);
+}
+
 bool convertLegacyRttCapabilitiesToAidl(
         const legacy_hal::wifi_rtt_capabilities& legacy_capabilities,
         RttCapabilities* aidl_capabilities) {
@@ -2780,28 +2881,42 @@
     aidl_capabilities->lciSupported = legacy_capabilities.lci_support;
     aidl_capabilities->lcrSupported = legacy_capabilities.lcr_support;
     aidl_capabilities->responderSupported = legacy_capabilities.responder_supported;
-    int32_t preambleSupport = 0;
-    for (const auto flag : {legacy_hal::WIFI_RTT_PREAMBLE_LEGACY, legacy_hal::WIFI_RTT_PREAMBLE_HT,
-                            legacy_hal::WIFI_RTT_PREAMBLE_VHT, legacy_hal::WIFI_RTT_PREAMBLE_HE,
-                            legacy_hal::WIFI_RTT_PREAMBLE_EHT}) {
-        if (legacy_capabilities.preamble_support & flag) {
-            preambleSupport |= static_cast<std::underlying_type<RttPreamble>::type>(
-                    convertLegacyRttPreambleToAidl(flag));
-        }
-    }
-    aidl_capabilities->preambleSupport = static_cast<RttPreamble>(preambleSupport);
-    int32_t bwSupport = 0;
-    for (const auto flag :
-         {legacy_hal::WIFI_RTT_BW_5, legacy_hal::WIFI_RTT_BW_10, legacy_hal::WIFI_RTT_BW_20,
-          legacy_hal::WIFI_RTT_BW_40, legacy_hal::WIFI_RTT_BW_80, legacy_hal::WIFI_RTT_BW_160,
-          legacy_hal::WIFI_RTT_BW_320}) {
-        if (legacy_capabilities.bw_support & flag) {
-            bwSupport |=
-                    static_cast<std::underlying_type<RttBw>::type>(convertLegacyRttBwToAidl(flag));
-        }
-    }
-    aidl_capabilities->bwSupport = static_cast<RttBw>(bwSupport);
+    aidl_capabilities->preambleSupport =
+            convertLegacyRttPreambleBitmapToAidl(legacy_capabilities.preamble_support);
+    aidl_capabilities->bwSupport = convertLegacyRttBwBitmapToAidl(legacy_capabilities.bw_support);
     aidl_capabilities->mcVersion = legacy_capabilities.mc_version;
+    // Initialize 11az parameters to default
+    aidl_capabilities->azPreambleSupport = (int)RttPreamble::INVALID;
+    aidl_capabilities->azBwSupport = (int)RttBw::BW_UNSPECIFIED;
+    aidl_capabilities->ntbInitiatorSupported = false;
+    aidl_capabilities->ntbResponderSupported = false;
+    return true;
+}
+
+bool convertLegacyRttCapabilitiesV3ToAidl(
+        const legacy_hal::wifi_rtt_capabilities_v3& legacy_capabilities_v3,
+        RttCapabilities* aidl_capabilities) {
+    if (!aidl_capabilities) {
+        return false;
+    }
+    *aidl_capabilities = {};
+    aidl_capabilities->rttOneSidedSupported =
+            legacy_capabilities_v3.rtt_capab.rtt_one_sided_supported;
+    aidl_capabilities->rttFtmSupported = legacy_capabilities_v3.rtt_capab.rtt_ftm_supported;
+    aidl_capabilities->lciSupported = legacy_capabilities_v3.rtt_capab.lci_support;
+    aidl_capabilities->lcrSupported = legacy_capabilities_v3.rtt_capab.lcr_support;
+    aidl_capabilities->responderSupported = legacy_capabilities_v3.rtt_capab.responder_supported;
+    aidl_capabilities->preambleSupport =
+            convertLegacyRttPreambleBitmapToAidl(legacy_capabilities_v3.rtt_capab.preamble_support);
+    aidl_capabilities->bwSupport =
+            convertLegacyRttBwBitmapToAidl(legacy_capabilities_v3.rtt_capab.bw_support);
+    aidl_capabilities->mcVersion = legacy_capabilities_v3.rtt_capab.mc_version;
+    aidl_capabilities->azPreambleSupport =
+            (int)convertLegacyRttPreambleBitmapToAidl(legacy_capabilities_v3.az_preamble_support);
+    aidl_capabilities->azBwSupport =
+            (int)convertLegacyRttBwBitmapToAidl(legacy_capabilities_v3.az_bw_support);
+    aidl_capabilities->ntbInitiatorSupported = legacy_capabilities_v3.ntb_initiator_supported;
+    aidl_capabilities->ntbResponderSupported = legacy_capabilities_v3.ntb_responder_supported;
     return true;
 }
 
@@ -2876,6 +2991,12 @@
         }
         aidl_result.channelFreqMHz = 0;
         aidl_result.packetBw = RttBw::BW_UNSPECIFIED;
+        aidl_result.i2rTxLtfRepetitionCount = 0;
+        aidl_result.r2iTxLtfRepetitionCount = 0;
+        aidl_result.ntbMinMeasurementTime = 0;
+        aidl_result.ntbMaxMeasurementTime = 0;
+        aidl_result.numTxSpatialStreams = 0;
+        aidl_result.numRxSpatialStreams = 0;
         aidl_results->push_back(aidl_result);
     }
     return true;
@@ -2896,6 +3017,39 @@
         aidl_result.channelFreqMHz =
                 legacy_result->frequency != UNSPECIFIED ? legacy_result->frequency : 0;
         aidl_result.packetBw = convertLegacyRttBwToAidl(legacy_result->packet_bw);
+        aidl_result.i2rTxLtfRepetitionCount = 0;
+        aidl_result.r2iTxLtfRepetitionCount = 0;
+        aidl_result.ntbMinMeasurementTime = 0;
+        aidl_result.ntbMaxMeasurementTime = 0;
+        aidl_result.numTxSpatialStreams = 0;
+        aidl_result.numRxSpatialStreams = 0;
+        aidl_results->push_back(aidl_result);
+    }
+    return true;
+}
+
+bool convertLegacyVectorOfRttResultV3ToAidl(
+        const std::vector<const legacy_hal::wifi_rtt_result_v3*>& legacy_results,
+        std::vector<RttResult>* aidl_results) {
+    if (!aidl_results) {
+        return false;
+    }
+    *aidl_results = {};
+    for (const auto legacy_result : legacy_results) {
+        RttResult aidl_result;
+        if (!convertLegacyRttResultToAidl(legacy_result->rtt_result.rtt_result, &aidl_result)) {
+            return false;
+        }
+        aidl_result.channelFreqMHz = legacy_result->rtt_result.frequency != UNSPECIFIED
+                                             ? legacy_result->rtt_result.frequency
+                                             : 0;
+        aidl_result.packetBw = convertLegacyRttBwToAidl(legacy_result->rtt_result.packet_bw);
+        aidl_result.i2rTxLtfRepetitionCount = legacy_result->i2r_tx_ltf_repetition_count;
+        aidl_result.r2iTxLtfRepetitionCount = legacy_result->r2i_tx_ltf_repetition_count;
+        aidl_result.ntbMinMeasurementTime = legacy_result->ntb_min_measurement_time;
+        aidl_result.ntbMaxMeasurementTime = legacy_result->ntb_max_measurement_time;
+        aidl_result.numTxSpatialStreams = legacy_result->num_tx_sts;
+        aidl_result.numRxSpatialStreams = legacy_result->num_rx_sts;
         aidl_results->push_back(aidl_result);
     }
     return true;
@@ -3178,6 +3332,8 @@
     legacy_request->cookie_length = aidl_request.cookie.size();
 
     memcpy(legacy_request->cookie, aidl_request.cookie.data(), legacy_request->cookie_length);
+    legacy_request->publish_subscribe_id = static_cast<uint8_t>(aidl_request.discoverySessionId);
+    legacy_request->comeback = aidl_request.isComeback ? 0x1 : 0x0;
 
     return true;
 }
@@ -3195,6 +3351,7 @@
     legacy_request->service_instance_id = aidl_request.bootstrappingInstanceId;
     legacy_request->rsp_code = aidl_request.acceptRequest ? NAN_BOOTSTRAPPING_REQUEST_ACCEPT
                                                           : NAN_BOOTSTRAPPING_REQUEST_REJECT;
+    legacy_request->publish_subscribe_id = static_cast<uint8_t>(aidl_request.discoverySessionId);
 
     return true;
 }
@@ -3362,6 +3519,195 @@
     return true;
 }
 
+bool convertCachedScanReportToAidl(const legacy_hal::WifiCachedScanReport& report,
+                                   CachedScanData* aidl_scan_data) {
+    if (!aidl_scan_data) {
+        return false;
+    }
+    *aidl_scan_data = {};
+
+    std::vector<CachedScanResult> aidl_scan_results;
+    for (const auto& result : report.results) {
+        CachedScanResult aidl_scan_result;
+        if (!convertCachedScanResultToAidl(result, report.ts, &aidl_scan_result)) {
+            return false;
+        }
+        aidl_scan_results.push_back(aidl_scan_result);
+    }
+    aidl_scan_data->cachedScanResults = aidl_scan_results;
+
+    aidl_scan_data->scannedFrequenciesMhz = report.scanned_freqs;
+    return true;
+}
+
+bool convertCachedScanResultToAidl(const legacy_hal::wifi_cached_scan_result& legacy_scan_result,
+                                   uint64_t ts_us, CachedScanResult* aidl_scan_result) {
+    if (!aidl_scan_result) {
+        return false;
+    }
+    *aidl_scan_result = {};
+    aidl_scan_result->timeStampInUs = ts_us - legacy_scan_result.age_ms * 1000;
+    if (aidl_scan_result->timeStampInUs < 0) {
+        aidl_scan_result->timeStampInUs = 0;
+        return false;
+    }
+    size_t max_len_excluding_null = sizeof(legacy_scan_result.ssid) - 1;
+    size_t ssid_len = strnlen((const char*)legacy_scan_result.ssid, max_len_excluding_null);
+    aidl_scan_result->ssid =
+            std::vector<uint8_t>(legacy_scan_result.ssid, legacy_scan_result.ssid + ssid_len);
+    aidl_scan_result->bssid = std::array<uint8_t, 6>();
+    std::copy(legacy_scan_result.bssid, legacy_scan_result.bssid + 6,
+              std::begin(aidl_scan_result->bssid));
+    aidl_scan_result->frequencyMhz = legacy_scan_result.chanspec.primary_frequency;
+    aidl_scan_result->channelWidthMhz =
+            convertLegacyWifiChannelWidthToAidl(legacy_scan_result.chanspec.width);
+    aidl_scan_result->rssiDbm = legacy_scan_result.rssi;
+    aidl_scan_result->preambleType = convertScanResultFlagsToPreambleType(legacy_scan_result.flags);
+    return true;
+}
+
+WifiRatePreamble convertScanResultFlagsToPreambleType(int flags) {
+    if ((flags & WIFI_CACHED_SCAN_RESULT_FLAGS_EHT_OPS_PRESENT) > 0) {
+        return WifiRatePreamble::EHT;
+    }
+    if ((flags & WIFI_CACHED_SCAN_RESULT_FLAGS_HE_OPS_PRESENT) > 0) {
+        return WifiRatePreamble::HE;
+    }
+    if ((flags & WIFI_CACHED_SCAN_RESULT_FLAGS_VHT_OPS_PRESENT) > 0) {
+        return WifiRatePreamble::VHT;
+    }
+    if ((flags & WIFI_CACHED_SCAN_RESULT_FLAGS_HT_OPS_PRESENT) > 0) {
+        return WifiRatePreamble::HT;
+    }
+    return WifiRatePreamble::OFDM;
+}
+
+bool convertTwtCapabilitiesToAidl(legacy_hal::wifi_twt_capabilities legacy_twt_capabs,
+                                  TwtCapabilities* aidl_twt_capabs) {
+    if (!aidl_twt_capabs) {
+        return false;
+    }
+    aidl_twt_capabs->isTwtRequesterSupported = legacy_twt_capabs.is_twt_requester_supported;
+    aidl_twt_capabs->isTwtResponderSupported = legacy_twt_capabs.is_twt_responder_supported;
+    aidl_twt_capabs->isBroadcastTwtSupported = legacy_twt_capabs.is_flexible_twt_supported;
+    if (legacy_twt_capabs.min_wake_duration_micros > legacy_twt_capabs.max_wake_duration_micros) {
+        return false;
+    }
+    aidl_twt_capabs->minWakeDurationUs = legacy_twt_capabs.min_wake_duration_micros;
+    aidl_twt_capabs->maxWakeDurationUs = legacy_twt_capabs.max_wake_duration_micros;
+    if (legacy_twt_capabs.min_wake_interval_micros > legacy_twt_capabs.max_wake_interval_micros) {
+        return false;
+    }
+    aidl_twt_capabs->minWakeIntervalUs = legacy_twt_capabs.min_wake_interval_micros;
+    aidl_twt_capabs->maxWakeIntervalUs = legacy_twt_capabs.max_wake_interval_micros;
+    return true;
+}
+
+bool convertAidlTwtRequestToLegacy(const TwtRequest aidl_twt_request,
+                                   legacy_hal::wifi_twt_request* legacy_twt_request) {
+    if (legacy_twt_request == nullptr) {
+        return false;
+    }
+    legacy_twt_request->mlo_link_id = aidl_twt_request.mloLinkId;
+    if (aidl_twt_request.minWakeDurationUs > aidl_twt_request.maxWakeDurationUs) {
+        return false;
+    }
+    legacy_twt_request->min_wake_duration_micros = aidl_twt_request.minWakeDurationUs;
+    legacy_twt_request->max_wake_duration_micros = aidl_twt_request.maxWakeDurationUs;
+    if (aidl_twt_request.minWakeIntervalUs > aidl_twt_request.maxWakeIntervalUs) {
+        return false;
+    }
+    legacy_twt_request->min_wake_interval_micros = aidl_twt_request.minWakeIntervalUs;
+    legacy_twt_request->max_wake_interval_micros = aidl_twt_request.maxWakeIntervalUs;
+    return true;
+}
+
+IWifiStaIfaceEventCallback::TwtErrorCode convertLegacyHalTwtErrorCodeToAidl(
+        legacy_hal::wifi_twt_error_code legacy_error_code) {
+    switch (legacy_error_code) {
+        case WIFI_TWT_ERROR_CODE_TIMEOUT:
+            return IWifiStaIfaceEventCallback::TwtErrorCode::TIMEOUT;
+        case WIFI_TWT_ERROR_CODE_PEER_REJECTED:
+            return IWifiStaIfaceEventCallback::TwtErrorCode::PEER_REJECTED;
+        case WIFI_TWT_ERROR_CODE_PEER_NOT_SUPPORTED:
+            return IWifiStaIfaceEventCallback::TwtErrorCode::PEER_NOT_SUPPORTED;
+        case WIFI_TWT_ERROR_CODE_NOT_SUPPORTED:
+            return IWifiStaIfaceEventCallback::TwtErrorCode::NOT_SUPPORTED;
+        case WIFI_TWT_ERROR_CODE_NOT_AVAILABLE:
+            return IWifiStaIfaceEventCallback::TwtErrorCode::NOT_AVAILABLE;
+        case WIFI_TWT_ERROR_CODE_MAX_SESSION_REACHED:
+            return IWifiStaIfaceEventCallback::TwtErrorCode::MAX_SESSION_REACHED;
+        case WIFI_TWT_ERROR_CODE_INVALID_PARAMS:
+            return IWifiStaIfaceEventCallback::TwtErrorCode::INVALID_PARAMS;
+        case WIFI_TWT_ERROR_CODE_ALREADY_SUSPENDED:
+            return IWifiStaIfaceEventCallback::TwtErrorCode::ALREADY_SUSPENDED;
+        case WIFI_TWT_ERROR_CODE_ALREADY_RESUMED:
+            return IWifiStaIfaceEventCallback::TwtErrorCode::ALREADY_RESUMED;
+        default:
+            return IWifiStaIfaceEventCallback::TwtErrorCode::FAILURE_UNKNOWN;
+    }
+}
+
+IWifiStaIfaceEventCallback::TwtTeardownReasonCode convertLegacyHalTwtReasonCodeToAidl(
+        legacy_hal::wifi_twt_teardown_reason_code legacy_reason_code) {
+    switch (legacy_reason_code) {
+        case WIFI_TWT_TEARDOWN_REASON_CODE_LOCALLY_REQUESTED:
+            return IWifiStaIfaceEventCallback::TwtTeardownReasonCode::LOCALLY_REQUESTED;
+        case WIFI_TWT_TEARDOWN_REASON_CODE_INTERNALLY_INITIATED:
+            return IWifiStaIfaceEventCallback::TwtTeardownReasonCode::INTERNALLY_INITIATED;
+        case WIFI_TWT_TEARDOWN_REASON_CODE_PEER_INITIATED:
+            return IWifiStaIfaceEventCallback::TwtTeardownReasonCode::PEER_INITIATED;
+        default:
+            return IWifiStaIfaceEventCallback::TwtTeardownReasonCode::UNKNOWN;
+    }
+}
+
+bool convertLegacyHalTwtSessionToAidl(legacy_hal::wifi_twt_session twt_session,
+                                      TwtSession* aidl_twt_session) {
+    if (aidl_twt_session == nullptr) {
+        return false;
+    }
+
+    aidl_twt_session->sessionId = twt_session.session_id;
+    aidl_twt_session->mloLinkId = twt_session.mlo_link_id;
+    aidl_twt_session->wakeDurationUs = twt_session.wake_duration_micros;
+    aidl_twt_session->wakeIntervalUs = twt_session.wake_interval_micros;
+    switch (twt_session.negotiation_type) {
+        case WIFI_TWT_NEGO_TYPE_INDIVIDUAL:
+            aidl_twt_session->negotiationType = TwtSession::TwtNegotiationType::INDIVIDUAL;
+            break;
+        case WIFI_TWT_NEGO_TYPE_BROADCAST:
+            aidl_twt_session->negotiationType = TwtSession::TwtNegotiationType::BROADCAST;
+            break;
+        default:
+            return false;
+    }
+    aidl_twt_session->isTriggerEnabled = twt_session.is_trigger_enabled;
+    aidl_twt_session->isAnnounced = twt_session.is_announced;
+    aidl_twt_session->isImplicit = twt_session.is_implicit;
+    aidl_twt_session->isProtected = twt_session.is_protected;
+    aidl_twt_session->isUpdatable = twt_session.is_updatable;
+    aidl_twt_session->isSuspendable = twt_session.is_suspendable;
+    aidl_twt_session->isResponderPmModeEnabled = twt_session.is_responder_pm_mode_enabled;
+    return true;
+}
+
+bool convertLegacyHalTwtSessionStatsToAidl(legacy_hal::wifi_twt_session_stats twt_stats,
+                                           TwtSessionStats* aidl_twt_stats) {
+    if (aidl_twt_stats == nullptr) {
+        return false;
+    }
+
+    aidl_twt_stats->avgTxPktCount = twt_stats.avg_pkt_num_tx;
+    aidl_twt_stats->avgRxPktCount = twt_stats.avg_pkt_num_rx;
+    aidl_twt_stats->avgTxPktSize = twt_stats.avg_tx_pkt_size;
+    aidl_twt_stats->avgRxPktSize = twt_stats.avg_rx_pkt_size;
+    aidl_twt_stats->avgEospDurationUs = twt_stats.avg_eosp_dur_us;
+    aidl_twt_stats->eospCount = twt_stats.eosp_count;
+
+    return true;
+}
+
 }  // namespace aidl_struct_util
 }  // namespace wifi
 }  // namespace hardware
diff --git a/wifi/aidl/default/aidl_struct_util.h b/wifi/aidl/default/aidl_struct_util.h
index e4ff963..7089363 100644
--- a/wifi/aidl/default/aidl_struct_util.h
+++ b/wifi/aidl/default/aidl_struct_util.h
@@ -148,6 +148,10 @@
 // RTT controller conversion methods.
 bool convertAidlVectorOfRttConfigToLegacy(const std::vector<RttConfig>& aidl_configs,
                                           std::vector<legacy_hal::wifi_rtt_config>* legacy_configs);
+bool convertAidlVectorOfRttConfigToLegacyV3(
+        const std::vector<RttConfig>& aidl_configs,
+        std::vector<legacy_hal::wifi_rtt_config_v3>* legacy_configs);
+
 bool convertAidlRttLciInformationToLegacy(const RttLciInformation& aidl_info,
                                           legacy_hal::wifi_lci_information* legacy_info);
 bool convertAidlRttLcrInformationToLegacy(const RttLcrInformation& aidl_info,
@@ -161,12 +165,19 @@
 bool convertLegacyRttCapabilitiesToAidl(
         const legacy_hal::wifi_rtt_capabilities& legacy_capabilities,
         RttCapabilities* aidl_capabilities);
+bool convertLegacyRttCapabilitiesV3ToAidl(
+        const legacy_hal::wifi_rtt_capabilities_v3& legacy_capabilities_v3,
+        RttCapabilities* aidl_capabilities);
+
 bool convertLegacyVectorOfRttResultToAidl(
         const std::vector<const legacy_hal::wifi_rtt_result*>& legacy_results,
         std::vector<RttResult>* aidl_results);
 bool convertLegacyVectorOfRttResultV2ToAidl(
         const std::vector<const legacy_hal::wifi_rtt_result_v2*>& legacy_results,
         std::vector<RttResult>* aidl_results);
+bool convertLegacyVectorOfRttResultV3ToAidl(
+        const std::vector<const legacy_hal::wifi_rtt_result_v3*>& legacy_results,
+        std::vector<RttResult>* aidl_results);
 uint32_t convertAidlWifiBandToLegacyMacBand(WifiBand band);
 uint32_t convertAidlWifiIfaceModeToLegacy(uint32_t aidl_iface_mask);
 uint32_t convertAidlUsableChannelFilterToLegacy(uint32_t aidl_filter_mask);
@@ -202,6 +213,23 @@
         const legacy_hal::NanBootstrappingConfirmInd& legacy_ind,
         NanBootstrappingConfirmInd* aidl_ind);
 uint32_t convertAidlChannelCategoryToLegacy(uint32_t aidl_channel_category_mask);
+bool convertCachedScanReportToAidl(const legacy_hal::WifiCachedScanReport& report,
+                                   CachedScanData* aidl_scan_data);
+bool convertCachedScanResultToAidl(const legacy_hal::wifi_cached_scan_result& legacy_scan_result,
+                                   uint64_t ts_us, CachedScanResult* aidl_scan_result);
+WifiRatePreamble convertScanResultFlagsToPreambleType(int flags);
+bool convertTwtCapabilitiesToAidl(const legacy_hal::wifi_twt_capabilities legacy_twt_capabs,
+                                  TwtCapabilities* aidl_twt_capabs);
+bool convertAidlTwtRequestToLegacy(const TwtRequest aidl_twt_request,
+                                   legacy_hal::wifi_twt_request* legacy_twt_request);
+IWifiStaIfaceEventCallback::TwtErrorCode convertLegacyHalTwtErrorCodeToAidl(
+        legacy_hal::wifi_twt_error_code legacy_error_code);
+IWifiStaIfaceEventCallback::TwtTeardownReasonCode convertLegacyHalTwtReasonCodeToAidl(
+        legacy_hal::wifi_twt_teardown_reason_code legacy_reason_code);
+bool convertLegacyHalTwtSessionToAidl(legacy_hal::wifi_twt_session twt_session,
+                                      TwtSession* aidl_twt_session);
+bool convertLegacyHalTwtSessionStatsToAidl(legacy_hal::wifi_twt_session_stats twt_stats,
+                                           TwtSessionStats* aidl_twt_stats);
 }  // namespace aidl_struct_util
 }  // namespace wifi
 }  // namespace hardware
diff --git a/wifi/aidl/default/android.hardware.wifi-service.xml b/wifi/aidl/default/android.hardware.wifi-service.xml
index 5398ee7..3b68c8e 100644
--- a/wifi/aidl/default/android.hardware.wifi-service.xml
+++ b/wifi/aidl/default/android.hardware.wifi-service.xml
@@ -1,6 +1,7 @@
 <manifest version="1.0" type="device">
 	<hal format="aidl">
 		<name>android.hardware.wifi</name>
+		<version>2</version>
 		<fqname>IWifi/default</fqname>
 	</hal>
 </manifest>
diff --git a/wifi/aidl/default/tests/aidl_struct_util_unit_tests.cpp b/wifi/aidl/default/tests/aidl_struct_util_unit_tests.cpp
index 995a13d..2a030ee 100644
--- a/wifi/aidl/default/tests/aidl_struct_util_unit_tests.cpp
+++ b/wifi/aidl/default/tests/aidl_struct_util_unit_tests.cpp
@@ -35,6 +35,12 @@
               0x2c, 0x00, 0x00, 0x41, 0x06, 0x03, 0x06, 0x00, 0x80};
 byte LCR[] = {0x27, 0xE,  0x1,  0x00, 0xB,  0x01, 0x00, 0x0b, 0x00, 0x09,
               0x55, 0x53, 0x18, 0x05, 0x39, 0x34, 0x30, 0x34, 0x33};
+
+constexpr int kNumScanResult = 2;
+constexpr int kRssi[] = {-60, -70};
+constexpr uint8_t kBssid[] = {0x12, 0x34, 0x56, 0x78, 0x9a, 0};
+constexpr uint8_t kSsidLen = 6;
+constexpr char kSsid[] = {'a', 'b', 'c', 'd', 'e', '\0'};
 }  // namespace
 
 namespace aidl {
@@ -883,6 +889,51 @@
     }
 }
 
+TEST_F(AidlStructUtilTest, convertCachedScanReportToAidl) {
+    legacy_hal::WifiCachedScanReport hw_report;
+
+    hw_report.ts = 10000000;
+    std::vector<int> scanned_freqs{5260, 2437, 5200};
+    std::vector<wifi_cached_scan_result> results;
+    hw_report.scanned_freqs = scanned_freqs;
+
+    for (int i = 0; i < kNumScanResult; i++) {
+        wifi_cached_scan_result result;
+        result.age_ms = i * 1000;
+        result.capability = i;
+        memcpy(result.ssid, kSsid, kSsidLen);
+        result.ssid_len = kSsidLen;
+        memcpy(result.bssid, kBssid, 6);
+        result.flags = WIFI_CACHED_SCAN_RESULT_FLAGS_HE_OPS_PRESENT;
+        result.rssi = kRssi[i];
+        result.chanspec = {legacy_hal::WIFI_CHAN_WIDTH_40, 0, 0, i};
+        results.push_back(result);
+    }
+    hw_report.results = results;
+
+    CachedScanData aidl_data;
+    aidl_struct_util::convertCachedScanReportToAidl(hw_report, &aidl_data);
+
+    EXPECT_EQ(scanned_freqs.size(), aidl_data.scannedFrequenciesMhz.size());
+    EXPECT_EQ(scanned_freqs[2], aidl_data.scannedFrequenciesMhz[2]);
+    EXPECT_EQ(5260, aidl_data.scannedFrequenciesMhz[0]);
+    EXPECT_EQ(kNumScanResult, (int)aidl_data.cachedScanResults.size());
+    for (int i = 0; i < kNumScanResult; i++) {
+        EXPECT_EQ(hw_report.results[i].rssi, aidl_data.cachedScanResults[i].rssiDbm);
+        EXPECT_EQ(i, aidl_data.cachedScanResults[i].frequencyMhz);
+        int64_t expected_ts = 10000000 - i * 1000 * 1000;
+        EXPECT_EQ(expected_ts, aidl_data.cachedScanResults[i].timeStampInUs);
+        EXPECT_EQ(WifiRatePreamble::HE, aidl_data.cachedScanResults[i].preambleType);
+        EXPECT_EQ(WifiChannelWidthInMhz::WIDTH_40, aidl_data.cachedScanResults[i].channelWidthMhz);
+        for (int k = 0; k < 6; k++) {
+            EXPECT_EQ(kBssid[k], aidl_data.cachedScanResults[i].bssid[k]);
+        }
+        for (int k = 0; k < kSsidLen; k++) {
+            EXPECT_EQ(kSsid[k], aidl_data.cachedScanResults[i].ssid[k]);
+        }
+    }
+}
+
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/aidl/default/wifi.cpp b/wifi/aidl/default/wifi.cpp
index 34a7f35..12017b6 100644
--- a/wifi/aidl/default/wifi.cpp
+++ b/wifi/aidl/default/wifi.cpp
@@ -16,15 +16,153 @@
 
 #include "wifi.h"
 
+#include <android-base/file.h>
 #include <android-base/logging.h>
+#include <cutils/properties.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
 
 #include "aidl_return_util.h"
 #include "aidl_sync_util.h"
 #include "wifi_status_util.h"
 
 namespace {
+using android::base::unique_fd;
+
 // Starting Chip ID, will be assigned to primary chip
 static constexpr int32_t kPrimaryChipId = 0;
+constexpr char kCpioMagic[] = "070701";
+constexpr char kTombstoneFolderPath[] = "/data/vendor/tombstones/wifi/";
+
+// Helper function for |cpioArchiveFilesInDir|
+bool cpioWriteHeader(int out_fd, struct stat& st, const char* file_name, size_t file_name_len) {
+    const int buf_size = 32 * 1024;
+    std::array<char, buf_size> read_buf;
+    ssize_t llen = snprintf(
+            read_buf.data(), buf_size, "%s%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X",
+            kCpioMagic, static_cast<int>(st.st_ino), st.st_mode, st.st_uid, st.st_gid,
+            static_cast<int>(st.st_nlink), static_cast<int>(st.st_mtime),
+            static_cast<int>(st.st_size), major(st.st_dev), minor(st.st_dev), major(st.st_rdev),
+            minor(st.st_rdev), static_cast<uint32_t>(file_name_len), 0);
+    if (write(out_fd, read_buf.data(), llen < buf_size ? llen : buf_size - 1) == -1) {
+        PLOG(ERROR) << "Error writing cpio header to file " << file_name;
+        return false;
+    }
+    if (write(out_fd, file_name, file_name_len) == -1) {
+        PLOG(ERROR) << "Error writing filename to file " << file_name;
+        return false;
+    }
+
+    // NUL Pad header up to 4 multiple bytes.
+    llen = (llen + file_name_len) % 4;
+    if (llen != 0) {
+        const uint32_t zero = 0;
+        if (write(out_fd, &zero, 4 - llen) == -1) {
+            PLOG(ERROR) << "Error padding 0s to file " << file_name;
+            return false;
+        }
+    }
+    return true;
+}
+
+// Helper function for |cpioArchiveFilesInDir|
+size_t cpioWriteFileContent(int fd_read, int out_fd, struct stat& st) {
+    // writing content of file
+    std::array<char, 32 * 1024> read_buf;
+    ssize_t llen = st.st_size;
+    size_t n_error = 0;
+    while (llen > 0) {
+        ssize_t bytes_read = read(fd_read, read_buf.data(), read_buf.size());
+        if (bytes_read == -1) {
+            PLOG(ERROR) << "Error reading file";
+            return ++n_error;
+        }
+        llen -= bytes_read;
+        if (write(out_fd, read_buf.data(), bytes_read) == -1) {
+            PLOG(ERROR) << "Error writing data to file";
+            return ++n_error;
+        }
+        if (bytes_read == 0) {  // this should never happen, but just in case
+                                // to unstuck from while loop
+            PLOG(ERROR) << "Unexpected read result";
+            n_error++;
+            break;
+        }
+    }
+    llen = st.st_size % 4;
+    if (llen != 0) {
+        const uint32_t zero = 0;
+        if (write(out_fd, &zero, 4 - llen) == -1) {
+            PLOG(ERROR) << "Error padding 0s to file";
+            return ++n_error;
+        }
+    }
+    return n_error;
+}
+
+// Helper function for |cpioArchiveFilesInDir|
+bool cpioWriteFileTrailer(int out_fd) {
+    const int buf_size = 4096;
+    std::array<char, buf_size> read_buf;
+    read_buf.fill(0);
+    ssize_t llen = snprintf(read_buf.data(), 4096, "070701%040X%056X%08XTRAILER!!!", 1, 0x0b, 0);
+    if (write(out_fd, read_buf.data(), (llen < buf_size ? llen : buf_size - 1) + 4) == -1) {
+        PLOG(ERROR) << "Error writing trailing bytes";
+        return false;
+    }
+    return true;
+}
+
+// Archives all files in |input_dir| and writes result into |out_fd|
+// Logic obtained from //external/toybox/toys/posix/cpio.c "Output cpio archive"
+// portion
+size_t cpioArchiveFilesInDir(int out_fd, const char* input_dir) {
+    struct dirent* dp;
+    size_t n_error = 0;
+    std::unique_ptr<DIR, decltype(&closedir)> dir_dump(opendir(input_dir), closedir);
+    if (!dir_dump) {
+        PLOG(ERROR) << "Failed to open directory";
+        return ++n_error;
+    }
+    while ((dp = readdir(dir_dump.get()))) {
+        if (dp->d_type != DT_REG) {
+            continue;
+        }
+        std::string cur_file_name(dp->d_name);
+        struct stat st;
+        const std::string cur_file_path = kTombstoneFolderPath + cur_file_name;
+        if (stat(cur_file_path.c_str(), &st) == -1) {
+            PLOG(ERROR) << "Failed to get file stat for " << cur_file_path;
+            n_error++;
+            continue;
+        }
+        const int fd_read = open(cur_file_path.c_str(), O_RDONLY);
+        if (fd_read == -1) {
+            PLOG(ERROR) << "Failed to open file " << cur_file_path;
+            n_error++;
+            continue;
+        }
+        std::string file_name_with_last_modified_time =
+                cur_file_name + "-" + std::to_string(st.st_mtime);
+        // string.size() does not include the null terminator. The cpio FreeBSD
+        // file header expects the null character to be included in the length.
+        const size_t file_name_len = file_name_with_last_modified_time.size() + 1;
+        unique_fd file_auto_closer(fd_read);
+        if (!cpioWriteHeader(out_fd, st, file_name_with_last_modified_time.c_str(),
+                             file_name_len)) {
+            return ++n_error;
+        }
+        size_t write_error = cpioWriteFileContent(fd_read, out_fd, st);
+        if (write_error) {
+            return n_error + write_error;
+        }
+    }
+    if (!cpioWriteFileTrailer(out_fd)) {
+        return ++n_error;
+    }
+    return n_error;
+}
+
 }  // namespace
 
 namespace aidl {
@@ -82,15 +220,18 @@
 binder_status_t Wifi::dump(int fd, const char** args, uint32_t numArgs) {
     const auto lock = acquireGlobalLock();
     LOG(INFO) << "-----------Debug was called----------------";
-    if (chips_.size() == 0) {
-        LOG(INFO) << "No chips to display.";
-        return STATUS_OK;
+    if (chips_.size() != 0) {
+        for (std::shared_ptr<WifiChip> chip : chips_) {
+            if (!chip.get()) continue;
+            chip->dump(fd, args, numArgs);
+        }
     }
-
-    for (std::shared_ptr<WifiChip> chip : chips_) {
-        if (!chip.get()) continue;
-        chip->dump(fd, args, numArgs);
+    uint32_t n_error = cpioArchiveFilesInDir(fd, kTombstoneFolderPath);
+    if (n_error != 0) {
+        LOG(ERROR) << n_error << " errors occurred in cpio function";
     }
+    ::android::base::WriteStringToFd("\n", fd);
+    fsync(fd);
     return STATUS_OK;
 }
 
diff --git a/wifi/aidl/default/wifi_chip.cpp b/wifi/aidl/default/wifi_chip.cpp
index 8265e5b..9b9c565 100644
--- a/wifi/aidl/default/wifi_chip.cpp
+++ b/wifi/aidl/default/wifi_chip.cpp
@@ -20,6 +20,7 @@
 #include <android-base/unique_fd.h>
 #include <cutils/properties.h>
 #include <fcntl.h>
+#include <hardware_legacy/wifi_hal.h>
 #include <net/if.h>
 #include <sys/stat.h>
 #include <sys/sysmacros.h>
@@ -32,13 +33,8 @@
 #define P2P_MGMT_DEVICE_PREFIX "p2p-dev-"
 
 namespace {
-using aidl::android::hardware::wifi::IfaceType;
-using aidl::android::hardware::wifi::IWifiChip;
-using CoexRestriction = aidl::android::hardware::wifi::IWifiChip::CoexRestriction;
-using ChannelCategoryMask = aidl::android::hardware::wifi::IWifiChip::ChannelCategoryMask;
 using android::base::unique_fd;
 
-constexpr char kCpioMagic[] = "070701";
 constexpr size_t kMaxBufferSizeBytes = 1024 * 1024 * 3;
 constexpr uint32_t kMaxRingBufferFileAgeSeconds = 60 * 60 * 10;
 constexpr uint32_t kMaxRingBufferFileNum = 20;
@@ -215,135 +211,6 @@
     return success;
 }
 
-// Helper function for |cpioArchiveFilesInDir|
-bool cpioWriteHeader(int out_fd, struct stat& st, const char* file_name, size_t file_name_len) {
-    const int buf_size = 32 * 1024;
-    std::array<char, buf_size> read_buf;
-    ssize_t llen = snprintf(
-            read_buf.data(), buf_size, "%s%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X",
-            kCpioMagic, static_cast<int>(st.st_ino), st.st_mode, st.st_uid, st.st_gid,
-            static_cast<int>(st.st_nlink), static_cast<int>(st.st_mtime),
-            static_cast<int>(st.st_size), major(st.st_dev), minor(st.st_dev), major(st.st_rdev),
-            minor(st.st_rdev), static_cast<uint32_t>(file_name_len), 0);
-    if (write(out_fd, read_buf.data(), llen < buf_size ? llen : buf_size - 1) == -1) {
-        PLOG(ERROR) << "Error writing cpio header to file " << file_name;
-        return false;
-    }
-    if (write(out_fd, file_name, file_name_len) == -1) {
-        PLOG(ERROR) << "Error writing filename to file " << file_name;
-        return false;
-    }
-
-    // NUL Pad header up to 4 multiple bytes.
-    llen = (llen + file_name_len) % 4;
-    if (llen != 0) {
-        const uint32_t zero = 0;
-        if (write(out_fd, &zero, 4 - llen) == -1) {
-            PLOG(ERROR) << "Error padding 0s to file " << file_name;
-            return false;
-        }
-    }
-    return true;
-}
-
-// Helper function for |cpioArchiveFilesInDir|
-size_t cpioWriteFileContent(int fd_read, int out_fd, struct stat& st) {
-    // writing content of file
-    std::array<char, 32 * 1024> read_buf;
-    ssize_t llen = st.st_size;
-    size_t n_error = 0;
-    while (llen > 0) {
-        ssize_t bytes_read = read(fd_read, read_buf.data(), read_buf.size());
-        if (bytes_read == -1) {
-            PLOG(ERROR) << "Error reading file";
-            return ++n_error;
-        }
-        llen -= bytes_read;
-        if (write(out_fd, read_buf.data(), bytes_read) == -1) {
-            PLOG(ERROR) << "Error writing data to file";
-            return ++n_error;
-        }
-        if (bytes_read == 0) {  // this should never happen, but just in case
-                                // to unstuck from while loop
-            PLOG(ERROR) << "Unexpected read result";
-            n_error++;
-            break;
-        }
-    }
-    llen = st.st_size % 4;
-    if (llen != 0) {
-        const uint32_t zero = 0;
-        if (write(out_fd, &zero, 4 - llen) == -1) {
-            PLOG(ERROR) << "Error padding 0s to file";
-            return ++n_error;
-        }
-    }
-    return n_error;
-}
-
-// Helper function for |cpioArchiveFilesInDir|
-bool cpioWriteFileTrailer(int out_fd) {
-    const int buf_size = 4096;
-    std::array<char, buf_size> read_buf;
-    read_buf.fill(0);
-    ssize_t llen = snprintf(read_buf.data(), 4096, "070701%040X%056X%08XTRAILER!!!", 1, 0x0b, 0);
-    if (write(out_fd, read_buf.data(), (llen < buf_size ? llen : buf_size - 1) + 4) == -1) {
-        PLOG(ERROR) << "Error writing trailing bytes";
-        return false;
-    }
-    return true;
-}
-
-// Archives all files in |input_dir| and writes result into |out_fd|
-// Logic obtained from //external/toybox/toys/posix/cpio.c "Output cpio archive"
-// portion
-size_t cpioArchiveFilesInDir(int out_fd, const char* input_dir) {
-    struct dirent* dp;
-    size_t n_error = 0;
-    std::unique_ptr<DIR, decltype(&closedir)> dir_dump(opendir(input_dir), closedir);
-    if (!dir_dump) {
-        PLOG(ERROR) << "Failed to open directory";
-        return ++n_error;
-    }
-    while ((dp = readdir(dir_dump.get()))) {
-        if (dp->d_type != DT_REG) {
-            continue;
-        }
-        std::string cur_file_name(dp->d_name);
-        struct stat st;
-        const std::string cur_file_path = kTombstoneFolderPath + cur_file_name;
-        if (stat(cur_file_path.c_str(), &st) == -1) {
-            PLOG(ERROR) << "Failed to get file stat for " << cur_file_path;
-            n_error++;
-            continue;
-        }
-        const int fd_read = open(cur_file_path.c_str(), O_RDONLY);
-        if (fd_read == -1) {
-            PLOG(ERROR) << "Failed to open file " << cur_file_path;
-            n_error++;
-            continue;
-        }
-        std::string file_name_with_last_modified_time =
-                cur_file_name + "-" + std::to_string(st.st_mtime);
-        // string.size() does not include the null terminator. The cpio FreeBSD
-        // file header expects the null character to be included in the length.
-        const size_t file_name_len = file_name_with_last_modified_time.size() + 1;
-        unique_fd file_auto_closer(fd_read);
-        if (!cpioWriteHeader(out_fd, st, file_name_with_last_modified_time.c_str(),
-                             file_name_len)) {
-            return ++n_error;
-        }
-        size_t write_error = cpioWriteFileContent(fd_read, out_fd, st);
-        if (write_error) {
-            return n_error + write_error;
-        }
-    }
-    if (!cpioWriteFileTrailer(out_fd)) {
-        return ++n_error;
-    }
-    return n_error;
-}
-
 // Helper function to create a non-const char*.
 std::vector<char> makeCharVec(const std::string& str) {
     std::vector<char> vec(str.size() + 1);
@@ -503,6 +370,14 @@
                            &WifiChip::createBridgedApIfaceInternal, _aidl_return);
 }
 
+ndk::ScopedAStatus WifiChip::createApOrBridgedApIface(
+        IfaceConcurrencyType in_ifaceType, const std::vector<common::OuiKeyedData>& in_vendorData,
+        std::shared_ptr<IWifiApIface>* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::createApOrBridgedApIfaceInternal, _aidl_return, in_ifaceType,
+                           in_vendorData);
+}
+
 ndk::ScopedAStatus WifiChip::getApIfaceNames(std::vector<std::string>* _aidl_return) {
     return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
                            &WifiChip::getApIfaceNamesInternal, _aidl_return);
@@ -651,7 +526,7 @@
                            &WifiChip::setLatencyModeInternal, in_mode);
 }
 
-binder_status_t WifiChip::dump(int fd, const char**, uint32_t) {
+binder_status_t WifiChip::dump(int fd __unused, const char**, uint32_t) {
     {
         std::unique_lock<std::mutex> lk(lock_t);
         for (const auto& item : ringbuffer_map_) {
@@ -664,11 +539,6 @@
     if (!writeRingbufferFilesInternal()) {
         LOG(ERROR) << "Error writing files to flash";
     }
-    uint32_t n_error = cpioArchiveFilesInDir(fd, kTombstoneFolderPath);
-    if (n_error != 0) {
-        LOG(ERROR) << n_error << " errors occurred in cpio function";
-    }
-    fsync(fd);
     return STATUS_OK;
 }
 
@@ -736,6 +606,11 @@
                            &WifiChip::setMloModeInternal, in_mode);
 }
 
+ndk::ScopedAStatus WifiChip::setVoipMode(const VoipMode in_mode) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::setVoipModeInternal, in_mode);
+}
+
 void WifiChip::invalidateAndRemoveAllIfaces() {
     invalidateAndClearBridgedApAll();
     invalidateAndClearAll(ap_ifaces_);
@@ -993,6 +868,18 @@
     return {iface, ndk::ScopedAStatus::ok()};
 }
 
+std::pair<std::shared_ptr<IWifiApIface>, ndk::ScopedAStatus>
+WifiChip::createApOrBridgedApIfaceInternal(
+        IfaceConcurrencyType ifaceType, const std::vector<common::OuiKeyedData>& /* vendorData */) {
+    if (ifaceType == IfaceConcurrencyType::AP) {
+        return createApIfaceInternal();
+    } else if (ifaceType == IfaceConcurrencyType::AP_BRIDGED) {
+        return createBridgedApIfaceInternal();
+    } else {
+        return {nullptr, createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS)};
+    }
+}
+
 std::pair<std::vector<std::string>, ndk::ScopedAStatus> WifiChip::getApIfaceNamesInternal() {
     if (ap_ifaces_.empty()) {
         return {std::vector<std::string>(), ndk::ScopedAStatus::ok()};
@@ -2032,6 +1919,23 @@
     return createWifiStatusFromLegacyError(legacy_hal_.lock()->setMloMode(mode));
 }
 
+ndk::ScopedAStatus WifiChip::setVoipModeInternal(const WifiChip::VoipMode in_mode) {
+    const auto ifname = getFirstActiveWlanIfaceName();
+    wifi_voip_mode mode;
+    switch (in_mode) {
+        case WifiChip::VoipMode::VOICE:
+            mode = wifi_voip_mode::WIFI_VOIP_MODE_VOICE;
+            break;
+        case WifiChip::VoipMode::OFF:
+            mode = wifi_voip_mode::WIFI_VOIP_MODE_OFF;
+            break;
+        default:
+            PLOG(ERROR) << "Error: invalid mode: " << toString(in_mode);
+            return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    return createWifiStatusFromLegacyError(legacy_hal_.lock()->setVoipMode(ifname, mode));
+}
+
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/aidl/default/wifi_chip.h b/wifi/aidl/default/wifi_chip.h
index 1a36032..ffd507f 100644
--- a/wifi/aidl/default/wifi_chip.h
+++ b/wifi/aidl/default/wifi_chip.h
@@ -19,6 +19,7 @@
 
 #include <aidl/android/hardware/wifi/BnWifiChip.h>
 #include <aidl/android/hardware/wifi/IWifiRttController.h>
+#include <aidl/android/hardware/wifi/common/OuiKeyedData.h>
 #include <android-base/macros.h>
 
 #include <list>
@@ -96,6 +97,10 @@
     ndk::ScopedAStatus requestFirmwareDebugDump(std::vector<uint8_t>* _aidl_return) override;
     ndk::ScopedAStatus createApIface(std::shared_ptr<IWifiApIface>* _aidl_return) override;
     ndk::ScopedAStatus createBridgedApIface(std::shared_ptr<IWifiApIface>* _aidl_return) override;
+    ndk::ScopedAStatus createApOrBridgedApIface(
+            IfaceConcurrencyType in_ifaceType,
+            const std::vector<common::OuiKeyedData>& in_vendorData,
+            std::shared_ptr<IWifiApIface>* _aidl_return) override;
     ndk::ScopedAStatus getApIfaceNames(std::vector<std::string>* _aidl_return) override;
     ndk::ScopedAStatus getApIface(const std::string& in_ifname,
                                   std::shared_ptr<IWifiApIface>* _aidl_return) override;
@@ -153,6 +158,7 @@
             int32_t in_channelCategoryEnableFlag) override;
     binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
     ndk::ScopedAStatus setMloMode(const ChipMloMode in_mode) override;
+    ndk::ScopedAStatus setVoipMode(const VoipMode in_mode) override;
 
   private:
     void invalidateAndRemoveAllIfaces();
@@ -176,6 +182,8 @@
     ndk::ScopedAStatus createVirtualApInterface(const std::string& apVirtIf);
     std::pair<std::shared_ptr<IWifiApIface>, ndk::ScopedAStatus> createApIfaceInternal();
     std::pair<std::shared_ptr<IWifiApIface>, ndk::ScopedAStatus> createBridgedApIfaceInternal();
+    std::pair<std::shared_ptr<IWifiApIface>, ndk::ScopedAStatus> createApOrBridgedApIfaceInternal(
+            IfaceConcurrencyType ifaceType, const std::vector<common::OuiKeyedData>& vendorData);
     std::pair<std::vector<std::string>, ndk::ScopedAStatus> getApIfaceNamesInternal();
     std::pair<std::shared_ptr<IWifiApIface>, ndk::ScopedAStatus> getApIfaceInternal(
             const std::string& ifname);
@@ -262,6 +270,7 @@
     getSupportedRadioCombinationsInternal();
     std::pair<WifiChipCapabilities, ndk::ScopedAStatus> getWifiChipCapabilitiesInternal();
     ndk::ScopedAStatus setMloModeInternal(const ChipMloMode in_mode);
+    ndk::ScopedAStatus setVoipModeInternal(const VoipMode in_mode);
     void retrieveDynamicIfaceCombination();
     void setWeakPtr(std::weak_ptr<WifiChip> ptr);
 
diff --git a/wifi/aidl/default/wifi_feature_flags.cpp b/wifi/aidl/default/wifi_feature_flags.cpp
index 3c9f042..35b4b4a 100644
--- a/wifi/aidl/default/wifi_feature_flags.cpp
+++ b/wifi/aidl/default/wifi_feature_flags.cpp
@@ -122,6 +122,7 @@
 #define AP IfaceConcurrencyType::AP
 #define AP_BRIDGED IfaceConcurrencyType::AP_BRIDGED
 #define P2P IfaceConcurrencyType::P2P
+#undef NAN  // undefine NAN from math.h
 #define NAN IfaceConcurrencyType::NAN_IFACE
 static const std::vector<IWifiChip::ChipMode> kChipModesPrimary{
         {kMainModeId, legacyToChipConcurrencyComboList({WIFI_HAL_INTERFACE_COMBINATIONS})},
diff --git a/wifi/aidl/default/wifi_legacy_hal.cpp b/wifi/aidl/default/wifi_legacy_hal.cpp
index 209670b..55d6f59 100644
--- a/wifi/aidl/default/wifi_legacy_hal.cpp
+++ b/wifi/aidl/default/wifi_legacy_hal.cpp
@@ -183,10 +183,13 @@
         on_rtt_results_internal_callback;
 std::function<void(wifi_request_id, unsigned num_results, wifi_rtt_result_v2* rtt_results_v2[])>
         on_rtt_results_internal_callback_v2;
+std::function<void(wifi_request_id, unsigned num_results, wifi_rtt_result_v3* rtt_results_v3[])>
+        on_rtt_results_internal_callback_v3;
 
 void invalidateRttResultsCallbacks() {
     on_rtt_results_internal_callback = nullptr;
     on_rtt_results_internal_callback_v2 = nullptr;
+    on_rtt_results_internal_callback_v3 = nullptr;
 };
 
 void onAsyncRttResults(wifi_request_id id, unsigned num_results, wifi_rtt_result* rtt_results[]) {
@@ -206,6 +209,15 @@
     }
 }
 
+void onAsyncRttResultsV3(wifi_request_id id, unsigned num_results,
+                         wifi_rtt_result_v3* rtt_results_v3[]) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_rtt_results_internal_callback_v3) {
+        on_rtt_results_internal_callback_v3(id, num_results, rtt_results_v3);
+        invalidateRttResultsCallbacks();
+    }
+}
+
 // Callbacks for the various NAN operations.
 // NOTE: These have very little conversions to perform before invoking the user
 // callbacks.
@@ -439,11 +451,82 @@
 // Callback to report cached scan results
 std::function<void(wifi_cached_scan_report*)> on_cached_scan_results_internal_callback;
 void onSyncCachedScanResults(wifi_cached_scan_report* cache_report) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
     if (on_cached_scan_results_internal_callback) {
         on_cached_scan_results_internal_callback(cache_report);
     }
 }
 
+// Callback to be invoked for TWT failure
+std::function<void((wifi_request_id, wifi_twt_error_code error_code))>
+        on_twt_failure_internal_callback;
+void onAsyncTwtError(wifi_request_id id, wifi_twt_error_code error_code) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_twt_failure_internal_callback) {
+        on_twt_failure_internal_callback(id, error_code);
+    }
+}
+
+// Callback to be invoked for TWT session creation
+std::function<void((wifi_request_id, wifi_twt_session twt_session))>
+        on_twt_session_create_internal_callback;
+void onAsyncTwtSessionCreate(wifi_request_id id, wifi_twt_session twt_session) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_twt_session_create_internal_callback) {
+        on_twt_session_create_internal_callback(id, twt_session);
+    }
+}
+
+// Callback to be invoked for TWT session update
+std::function<void((wifi_request_id, wifi_twt_session twt_session))>
+        on_twt_session_update_internal_callback;
+void onAsyncTwtSessionUpdate(wifi_request_id id, wifi_twt_session twt_session) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_twt_session_update_internal_callback) {
+        on_twt_session_update_internal_callback(id, twt_session);
+    }
+}
+
+// Callback to be invoked for TWT session teardown
+std::function<void(
+        (wifi_request_id, int twt_session_id, wifi_twt_teardown_reason_code reason_code))>
+        on_twt_session_teardown_internal_callback;
+void onAsyncTwtSessionTeardown(wifi_request_id id, int twt_session_id,
+                               wifi_twt_teardown_reason_code reason_code) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_twt_session_teardown_internal_callback) {
+        on_twt_session_teardown_internal_callback(id, twt_session_id, reason_code);
+    }
+}
+
+// Callback to be invoked for TWT session get stats
+std::function<void((wifi_request_id, int twt_session_id, wifi_twt_session_stats stats))>
+        on_twt_session_stats_internal_callback;
+void onAsyncTwtSessionStats(wifi_request_id id, int twt_session_id, wifi_twt_session_stats stats) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_twt_session_stats_internal_callback) {
+        on_twt_session_stats_internal_callback(id, twt_session_id, stats);
+    }
+}
+
+// Callback to be invoked for TWT session suspend
+std::function<void((wifi_request_id, int twt_session_id))> on_twt_session_suspend_internal_callback;
+void onAsyncTwtSessionSuspend(wifi_request_id id, int twt_session_id) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_twt_session_suspend_internal_callback) {
+        on_twt_session_suspend_internal_callback(id, twt_session_id);
+    }
+}
+
+// Callback to be invoked for TWT session resume
+std::function<void((wifi_request_id, int twt_session_id))> on_twt_session_resume_internal_callback;
+void onAsyncTwtSessionResume(wifi_request_id id, int twt_session_id) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_twt_session_resume_internal_callback) {
+        on_twt_session_resume_internal_callback(id, twt_session_id);
+    }
+}
+
 // End of the free-standing "C" style callbacks.
 
 WifiLegacyHal::WifiLegacyHal(const std::weak_ptr<::android::wifi_system::InterfaceTool> iface_tool,
@@ -1251,6 +1334,38 @@
     return status;
 }
 
+wifi_error WifiLegacyHal::startRttRangeRequestV3(
+        const std::string& iface_name, wifi_request_id id,
+        const std::vector<wifi_rtt_config_v3>& rtt_configs,
+        const on_rtt_results_callback_v3& on_results_user_callback_v3) {
+    if (on_rtt_results_internal_callback_v3) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+
+    on_rtt_results_internal_callback_v3 = [on_results_user_callback_v3](
+                                                  wifi_request_id id, unsigned num_results,
+                                                  wifi_rtt_result_v3* rtt_results_v3[]) {
+        if (num_results > 0 && !rtt_results_v3) {
+            LOG(ERROR) << "Unexpected nullptr in RTT v3 results";
+            return;
+        }
+        std::vector<const wifi_rtt_result_v3*> rtt_results_vec_v3;
+        std::copy_if(rtt_results_v3, rtt_results_v3 + num_results,
+                     back_inserter(rtt_results_vec_v3),
+                     [](wifi_rtt_result_v3* rtt_result_v3) { return rtt_result_v3 != nullptr; });
+        on_results_user_callback_v3(id, rtt_results_vec_v3);
+    };
+
+    std::vector<wifi_rtt_config_v3> rtt_configs_internal(rtt_configs);
+    wifi_error status = global_func_table_.wifi_rtt_range_request_v3(
+            id, getIfaceHandle(iface_name), rtt_configs.size(), rtt_configs_internal.data(),
+            {onAsyncRttResultsV3});
+    if (status != WIFI_SUCCESS) {
+        invalidateRttResultsCallbacks();
+    }
+    return status;
+}
+
 wifi_error WifiLegacyHal::startRttRangeRequest(
         const std::string& iface_name, wifi_request_id id,
         const std::vector<wifi_rtt_config>& rtt_configs,
@@ -1327,6 +1442,14 @@
     return {status, rtt_caps};
 }
 
+std::pair<wifi_error, wifi_rtt_capabilities_v3> WifiLegacyHal::getRttCapabilitiesV3(
+        const std::string& iface_name) {
+    wifi_rtt_capabilities_v3 rtt_caps_v3;
+    wifi_error status = global_func_table_.wifi_get_rtt_capabilities_v3(getIfaceHandle(iface_name),
+                                                                        &rtt_caps_v3);
+    return {status, rtt_caps_v3};
+}
+
 std::pair<wifi_error, wifi_rtt_responder> WifiLegacyHal::getRttResponderInfo(
         const std::string& iface_name) {
     wifi_rtt_responder rtt_responder;
@@ -1736,6 +1859,103 @@
     return global_func_table_.wifi_set_voip_mode(getIfaceHandle(iface_name), mode);
 }
 
+std::pair<wifi_twt_capabilities, wifi_error> WifiLegacyHal::twtGetCapabilities(
+        const std::string& ifaceName) {
+    wifi_twt_capabilities capabs = {};
+    wifi_error status =
+            global_func_table_.wifi_twt_get_capabilities(getIfaceHandle(ifaceName), &capabs);
+    return {capabs, status};
+}
+
+wifi_error WifiLegacyHal::twtSessionSetup(
+        const std::string& ifaceName, uint32_t cmdId, const wifi_twt_request& request,
+        const on_twt_failure& on_twt_failure_user_callback,
+        const on_twt_session_create& on_twt_session_create_user_callback,
+        const on_twt_session_update& on_twt_session_update_user_callback,
+        const on_twt_session_teardown& on_twt_session_teardown_user_callback,
+        const on_twt_session_stats& on_twt_session_stats_user_callback,
+        const on_twt_session_suspend& on_twt_session_suspend_user_callback,
+        const on_twt_session_resume& on_twt_session_resume_user_callback) {
+    if (on_twt_failure_internal_callback || on_twt_session_create_internal_callback ||
+        on_twt_session_update_internal_callback || on_twt_session_teardown_internal_callback ||
+        on_twt_session_stats_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+
+    on_twt_failure_internal_callback = [on_twt_failure_user_callback](
+                                               wifi_request_id id, wifi_twt_error_code error_code) {
+        on_twt_failure_user_callback(id, error_code);
+    };
+
+    on_twt_session_create_internal_callback = [on_twt_session_create_user_callback](
+                                                      wifi_request_id id,
+                                                      wifi_twt_session twt_session) {
+        on_twt_session_create_user_callback(id, twt_session);
+    };
+
+    on_twt_session_update_internal_callback = [on_twt_session_update_user_callback](
+                                                      wifi_request_id id,
+                                                      wifi_twt_session twt_session) {
+        on_twt_session_update_user_callback(id, twt_session);
+    };
+
+    on_twt_session_teardown_internal_callback = [on_twt_session_teardown_user_callback](
+                                                        wifi_request_id id, int session_id,
+                                                        wifi_twt_teardown_reason_code reason_code) {
+        on_twt_session_teardown_user_callback(id, session_id, reason_code);
+    };
+
+    on_twt_session_stats_internal_callback = [on_twt_session_stats_user_callback](
+                                                     wifi_request_id id, int session_id,
+                                                     wifi_twt_session_stats stats) {
+        on_twt_session_stats_user_callback(id, session_id, stats);
+    };
+
+    on_twt_session_suspend_internal_callback = [on_twt_session_suspend_user_callback](
+                                                       wifi_request_id id, int session_id) {
+        on_twt_session_suspend_user_callback(id, session_id);
+    };
+
+    on_twt_session_resume_internal_callback = [on_twt_session_resume_user_callback](
+                                                      wifi_request_id id, int session_id) {
+        on_twt_session_resume_user_callback(id, session_id);
+    };
+
+    return global_func_table_.wifi_twt_session_setup(
+            cmdId, getIfaceHandle(ifaceName), request,
+            {onAsyncTwtError, onAsyncTwtSessionCreate, onAsyncTwtSessionUpdate,
+             onAsyncTwtSessionTeardown, onAsyncTwtSessionStats, onAsyncTwtSessionSuspend,
+             onAsyncTwtSessionResume});
+}
+
+wifi_error WifiLegacyHal::twtSessionUpdate(const std::string& ifaceName, uint32_t cmdId,
+                                           uint32_t sessionId, const wifi_twt_request& request) {
+    return global_func_table_.wifi_twt_session_update(cmdId, getIfaceHandle(ifaceName), sessionId,
+                                                      request);
+}
+
+wifi_error WifiLegacyHal::twtSessionSuspend(const std::string& ifaceName, uint32_t cmdId,
+                                            uint32_t sessionId) {
+    return global_func_table_.wifi_twt_session_suspend(cmdId, getIfaceHandle(ifaceName), sessionId);
+}
+
+wifi_error WifiLegacyHal::twtSessionResume(const std::string& ifaceName, uint32_t cmdId,
+                                           uint32_t sessionId) {
+    return global_func_table_.wifi_twt_session_resume(cmdId, getIfaceHandle(ifaceName), sessionId);
+}
+
+wifi_error WifiLegacyHal::twtSessionTeardown(const std::string& ifaceName, uint32_t cmdId,
+                                             uint32_t sessionId) {
+    return global_func_table_.wifi_twt_session_teardown(cmdId, getIfaceHandle(ifaceName),
+                                                        sessionId);
+}
+
+wifi_error WifiLegacyHal::twtSessionGetStats(const std::string& ifaceName, uint32_t cmdId,
+                                             uint32_t sessionId) {
+    return global_func_table_.wifi_twt_session_get_stats(cmdId, getIfaceHandle(ifaceName),
+                                                         sessionId);
+}
+
 wifi_error WifiLegacyHal::twtRegisterHandler(const std::string& iface_name,
                                              const TwtCallbackHandlers& user_callbacks) {
     on_twt_event_setup_response_callback = user_callbacks.on_setup_response;
@@ -1858,13 +2078,16 @@
     return global_func_table_.wifi_enable_tx_power_limits(getIfaceHandle(iface_name), enable);
 }
 
-wifi_error WifiLegacyHal::getWifiCachedScanResults(
-        const std::string& iface_name, const CachedScanResultsCallbackHandlers& handler) {
-    on_cached_scan_results_internal_callback = handler.on_cached_scan_results;
-
+wifi_error WifiLegacyHal::getWifiCachedScanResults(const std::string& iface_name,
+                                                   WifiCachedScanReport& report) {
+    on_cached_scan_results_internal_callback = [&report](wifi_cached_scan_report* report_ptr) {
+        report.results.assign(report_ptr->results, report_ptr->results + report_ptr->result_cnt);
+        report.scanned_freqs.assign(report_ptr->scanned_freq_list,
+                                    report_ptr->scanned_freq_list + report_ptr->scanned_freq_num);
+        report.ts = report_ptr->ts;
+    };
     wifi_error status = global_func_table_.wifi_get_cached_scan_results(getIfaceHandle(iface_name),
                                                                         {onSyncCachedScanResults});
-
     on_cached_scan_results_internal_callback = nullptr;
     return status;
 }
@@ -1934,6 +2157,7 @@
     on_twt_event_info_frame_received_callback = nullptr;
     on_twt_event_device_notify_callback = nullptr;
     on_chre_nan_rtt_internal_callback = nullptr;
+    on_cached_scan_results_internal_callback = nullptr;
 }
 
 }  // namespace legacy_hal
diff --git a/wifi/aidl/default/wifi_legacy_hal.h b/wifi/aidl/default/wifi_legacy_hal.h
index 5168a8b..121d1b5 100644
--- a/wifi/aidl/default/wifi_legacy_hal.h
+++ b/wifi/aidl/default/wifi_legacy_hal.h
@@ -186,6 +186,7 @@
 using ::NanTxType;
 using ::NpkSecurityAssociation;
 using ::PASN;
+using ::ROAMING_AGGRESSIVE;
 using ::ROAMING_DISABLE;
 using ::ROAMING_ENABLE;
 using ::RTT_PEER_AP;
@@ -214,6 +215,8 @@
 using ::RTT_STATUS_SUCCESS;
 using ::RTT_TYPE_1_SIDED;
 using ::RTT_TYPE_2_SIDED;
+using ::RTT_TYPE_2_SIDED_11AZ_NTB;
+using ::RTT_TYPE_2_SIDED_11MC;
 using ::RX_PKT_FATE_DRV_DROP_FILTER;
 using ::RX_PKT_FATE_DRV_DROP_INVALID;
 using ::RX_PKT_FATE_DRV_DROP_NOBUFS;
@@ -256,6 +259,7 @@
 using ::WIFI_BAND_BG;
 using ::WIFI_BAND_UNSPECIFIED;
 using ::wifi_cached_scan_report;
+using ::wifi_cached_scan_result;
 using ::wifi_cached_scan_results;
 using ::WIFI_CHAN_WIDTH_10;
 using ::WIFI_CHAN_WIDTH_160;
@@ -349,16 +353,20 @@
 using ::WIFI_RTT_BW_80;
 using ::WIFI_RTT_BW_UNSPECIFIED;
 using ::wifi_rtt_capabilities;
+using ::wifi_rtt_capabilities_v3;
 using ::wifi_rtt_config;
+using ::wifi_rtt_config_v3;
 using ::wifi_rtt_preamble;
 using ::WIFI_RTT_PREAMBLE_EHT;
 using ::WIFI_RTT_PREAMBLE_HE;
 using ::WIFI_RTT_PREAMBLE_HT;
+using ::WIFI_RTT_PREAMBLE_INVALID;
 using ::WIFI_RTT_PREAMBLE_LEGACY;
 using ::WIFI_RTT_PREAMBLE_VHT;
 using ::wifi_rtt_responder;
 using ::wifi_rtt_result;
 using ::wifi_rtt_result_v2;
+using ::wifi_rtt_result_v3;
 using ::wifi_rtt_status;
 using ::wifi_rtt_type;
 using ::wifi_rx_packet_fate;
@@ -368,6 +376,13 @@
 using ::WIFI_SCAN_FLAG_INTERRUPTED;
 using ::wifi_scan_result;
 using ::WIFI_SUCCESS;
+using ::wifi_twt_capabilities;
+using ::wifi_twt_error_code;
+using ::wifi_twt_events;
+using ::wifi_twt_request;
+using ::wifi_twt_session;
+using ::wifi_twt_session_stats;
+using ::wifi_twt_teardown_reason_code;
 using ::wifi_tx_packet_fate;
 using ::wifi_tx_report;
 using ::wifi_usable_channel;
@@ -422,6 +437,12 @@
     bool valid;
 };
 
+struct WifiCachedScanReport {
+    uint64_t ts;
+    std::vector<int> scanned_freqs;
+    std::vector<wifi_cached_scan_result> results;
+};
+
 #pragma GCC diagnostic pop
 
 // The |WLAN_DRIVER_WAKE_REASON_CNT.cmd_event_wake_cnt| and
@@ -485,6 +506,8 @@
         std::function<void(wifi_request_id, const std::vector<const wifi_rtt_result*>&)>;
 using on_rtt_results_callback_v2 =
         std::function<void(wifi_request_id, const std::vector<const wifi_rtt_result_v2*>&)>;
+using on_rtt_results_callback_v3 =
+        std::function<void(wifi_request_id, const std::vector<const wifi_rtt_result_v3*>&)>;
 
 // Callback for ring buffer data.
 using on_ring_buffer_data_callback = std::function<void(
@@ -532,12 +555,23 @@
     std::function<void(chre_nan_rtt_state)> on_wifi_chre_nan_rtt_state;
 };
 
-// Cached Scan Results response and event callbacks struct.
-struct CachedScanResultsCallbackHandlers {
+using on_cached_scan_results_callback = std::function<void(wifi_cached_scan_report*)>;
+
+struct CachedScanResultsCallbfackHandlers {
     // Callback for Cached Scan Results
     std::function<void(wifi_cached_scan_report*)> on_cached_scan_results;
 };
 
+using on_twt_failure = std::function<void(wifi_request_id id, wifi_twt_error_code error_code)>;
+using on_twt_session_create = std::function<void(wifi_request_id id, wifi_twt_session twt_session)>;
+using on_twt_session_update = std::function<void(wifi_request_id id, wifi_twt_session twt_session)>;
+using on_twt_session_teardown = std::function<void(wifi_request_id id, int session_id,
+                                                   wifi_twt_teardown_reason_code reason_code)>;
+using on_twt_session_stats =
+        std::function<void(wifi_request_id id, int session_id, wifi_twt_session_stats stats)>;
+using on_twt_session_suspend = std::function<void(wifi_request_id id, int session_id)>;
+using on_twt_session_resume = std::function<void(wifi_request_id id, int session_id)>;
+
 /**
  * Class that encapsulates all legacy HAL interactions.
  * This class manages the lifetime of the event loop thread used by legacy HAL.
@@ -659,9 +693,15 @@
                                     const std::vector<wifi_rtt_config>& rtt_configs,
                                     const on_rtt_results_callback& on_results_callback,
                                     const on_rtt_results_callback_v2& on_results_callback_v2);
+    wifi_error startRttRangeRequestV3(const std::string& iface_name, wifi_request_id id,
+                                      const std::vector<wifi_rtt_config_v3>& rtt_configs,
+                                      const on_rtt_results_callback_v3& on_results_callback);
+
     wifi_error cancelRttRangeRequest(const std::string& iface_name, wifi_request_id id,
                                      const std::vector<std::array<uint8_t, ETH_ALEN>>& mac_addrs);
     std::pair<wifi_error, wifi_rtt_capabilities> getRttCapabilities(const std::string& iface_name);
+    std::pair<wifi_error, wifi_rtt_capabilities_v3> getRttCapabilitiesV3(
+            const std::string& iface_name);
     std::pair<wifi_error, wifi_rtt_responder> getRttResponderInfo(const std::string& iface_name);
     wifi_error enableRttResponder(const std::string& iface_name, wifi_request_id id,
                                   const wifi_channel_info& channel_hint, uint32_t max_duration_secs,
@@ -738,19 +778,39 @@
 
     wifi_error setVoipMode(const std::string& iface_name, wifi_voip_mode mode);
 
+    // TWT functions
+    std::pair<wifi_twt_capabilities, wifi_error> twtGetCapabilities(const std::string& ifaceName);
+    wifi_error twtSessionSetup(const std::string& ifaceName, uint32_t cmdId,
+                               const wifi_twt_request& request,
+                               const on_twt_failure& on_twt_failure_user_callback,
+                               const on_twt_session_create& on_twt_session_create_user_callback,
+                               const on_twt_session_update& on_twt_session_update_user_callback,
+                               const on_twt_session_teardown& on_twt_session_teardown_user_callback,
+                               const on_twt_session_stats& on_twt_session_stats_user_callback,
+                               const on_twt_session_suspend& on_twt_session_suspend_user_callback,
+                               const on_twt_session_resume& on_twt_session_resume_user_callback);
+    wifi_error twtSessionUpdate(const std::string& ifaceName, uint32_t cmdId, uint32_t sessionId,
+                                const wifi_twt_request& request);
+    wifi_error twtSessionSuspend(const std::string& ifaceName, uint32_t cmdId, uint32_t sessionId);
+    wifi_error twtSessionResume(const std::string& ifaceName, uint32_t cmdId, uint32_t sessionId);
+    wifi_error twtSessionTeardown(const std::string& ifaceName, uint32_t cmdId, uint32_t sessionId);
+    wifi_error twtSessionGetStats(const std::string& ifaceName, uint32_t cmdId, uint32_t sessionId);
+
+    // Note: Following TWT functions are deprecated
+    // Deprecated
     wifi_error twtRegisterHandler(const std::string& iface_name,
                                   const TwtCallbackHandlers& handler);
-
+    // Deprecated by twtGetCapabilities
     std::pair<wifi_error, TwtCapabilitySet> twtGetCapability(const std::string& iface_name);
-
+    // Deprecated by twtSessionSetup
     wifi_error twtSetupRequest(const std::string& iface_name, const TwtSetupRequest& msg);
-
+    // Deprecated by twtSessionTeardown
     wifi_error twtTearDownRequest(const std::string& iface_name, const TwtTeardownRequest& msg);
-
+    // Deprecated by twtSessionSuspend and twtSessionResume
     wifi_error twtInfoFrameRequest(const std::string& iface_name, const TwtInfoFrameRequest& msg);
-
+    // Deprecated by twtSessionGetStats
     std::pair<wifi_error, TwtStats> twtGetStats(const std::string& iface_name, uint8_t configId);
-
+    // Deprecated
     wifi_error twtClearStats(const std::string& iface_name, uint8_t configId);
 
     wifi_error setScanMode(const std::string& iface_name, bool enable);
@@ -776,7 +836,7 @@
 
     wifi_error enableWifiTxPowerLimits(const std::string& iface_name, bool enable);
     wifi_error getWifiCachedScanResults(const std::string& iface_name,
-                                        const CachedScanResultsCallbackHandlers& handler);
+                                        WifiCachedScanReport& report);
     std::pair<wifi_error, wifi_chip_capabilities> getWifiChipCapabilities();
     wifi_error enableStaChannelForPeerNetwork(uint32_t channelCategoryEnableFlag);
     wifi_error setMloMode(wifi_mlo_mode mode);
diff --git a/wifi/aidl/default/wifi_legacy_hal_stubs.cpp b/wifi/aidl/default/wifi_legacy_hal_stubs.cpp
index b5196c9..3e4afd0 100644
--- a/wifi/aidl/default/wifi_legacy_hal_stubs.cpp
+++ b/wifi/aidl/default/wifi_legacy_hal_stubs.cpp
@@ -179,6 +179,15 @@
     populateStubFor(&hal_fn->wifi_set_scan_mode);
     populateStubFor(&hal_fn->wifi_set_mlo_mode);
     populateStubFor(&hal_fn->wifi_get_supported_iface_concurrency_matrix);
+    populateStubFor(&hal_fn->wifi_get_rtt_capabilities_v3);
+    populateStubFor(&hal_fn->wifi_rtt_range_request_v3);
+    populateStubFor(&hal_fn->wifi_twt_get_capabilities);
+    populateStubFor(&hal_fn->wifi_twt_session_setup);
+    populateStubFor(&hal_fn->wifi_twt_session_update);
+    populateStubFor(&hal_fn->wifi_twt_session_suspend);
+    populateStubFor(&hal_fn->wifi_twt_session_resume);
+    populateStubFor(&hal_fn->wifi_twt_session_teardown);
+    populateStubFor(&hal_fn->wifi_twt_session_get_stats);
     return true;
 }
 
diff --git a/wifi/aidl/default/wifi_rtt_controller.cpp b/wifi/aidl/default/wifi_rtt_controller.cpp
index a5f6768..9dee45c 100644
--- a/wifi/aidl/default/wifi_rtt_controller.cpp
+++ b/wifi/aidl/default/wifi_rtt_controller.cpp
@@ -136,11 +136,45 @@
 
 ndk::ScopedAStatus WifiRttController::rangeRequestInternal(
         int32_t cmd_id, const std::vector<RttConfig>& rtt_configs) {
+    // Try 11mc & 11az ranging (v3)
+    std::vector<legacy_hal::wifi_rtt_config_v3> legacy_configs_v3;
+    if (!aidl_struct_util::convertAidlVectorOfRttConfigToLegacyV3(rtt_configs,
+                                                                  &legacy_configs_v3)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    std::weak_ptr<WifiRttController> weak_ptr_this = weak_ptr_this_;
+    const auto& on_results_callback_v3 =
+            [weak_ptr_this](legacy_hal::wifi_request_id id,
+                            const std::vector<const legacy_hal::wifi_rtt_result_v3*>& results) {
+                const auto shared_ptr_this = weak_ptr_this.lock();
+                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                    LOG(ERROR) << "v3 Callback invoked on an invalid object";
+                    return;
+                }
+                std::vector<RttResult> aidl_results;
+                if (!aidl_struct_util::convertLegacyVectorOfRttResultV3ToAidl(results,
+                                                                              &aidl_results)) {
+                    LOG(ERROR) << "Failed to convert rtt results v3 to AIDL structs";
+                    return;
+                }
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->onResults(id, aidl_results).isOk()) {
+                        LOG(ERROR) << "Failed to invoke the v3 callback";
+                    }
+                }
+            };
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->startRttRangeRequestV3(
+            ifname_, cmd_id, legacy_configs_v3, on_results_callback_v3);
+
+    if (legacy_status != legacy_hal::WIFI_ERROR_NOT_SUPPORTED) {
+        return createWifiStatusFromLegacyError(legacy_status);
+    }
+
+    // Fallback to 11mc ranging.
     std::vector<legacy_hal::wifi_rtt_config> legacy_configs;
     if (!aidl_struct_util::convertAidlVectorOfRttConfigToLegacy(rtt_configs, &legacy_configs)) {
         return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
     }
-    std::weak_ptr<WifiRttController> weak_ptr_this = weak_ptr_this_;
     const auto& on_results_callback =
             [weak_ptr_this](legacy_hal::wifi_request_id id,
                             const std::vector<const legacy_hal::wifi_rtt_result*>& results) {
@@ -181,7 +215,7 @@
                     }
                 }
             };
-    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->startRttRangeRequest(
+    legacy_status = legacy_hal_.lock()->startRttRangeRequest(
             ifname_, cmd_id, legacy_configs, on_results_callback, on_results_callback_v2);
     return createWifiStatusFromLegacyError(legacy_status);
 }
@@ -201,13 +235,29 @@
 
 std::pair<RttCapabilities, ndk::ScopedAStatus> WifiRttController::getCapabilitiesInternal() {
     legacy_hal::wifi_error legacy_status;
-    legacy_hal::wifi_rtt_capabilities legacy_caps;
-    std::tie(legacy_status, legacy_caps) = legacy_hal_.lock()->getRttCapabilities(ifname_);
+    legacy_hal::wifi_rtt_capabilities_v3 legacy_caps_v3;
+    std::tie(legacy_status, legacy_caps_v3) = legacy_hal_.lock()->getRttCapabilitiesV3(ifname_);
+    // Try v3 API first, if it is not supported fallback.
+    if (legacy_status == legacy_hal::WIFI_ERROR_NOT_SUPPORTED) {
+        legacy_hal::wifi_rtt_capabilities legacy_caps;
+        std::tie(legacy_status, legacy_caps) = legacy_hal_.lock()->getRttCapabilities(ifname_);
+        if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+            return {RttCapabilities{}, createWifiStatusFromLegacyError(legacy_status)};
+        }
+
+        RttCapabilities aidl_caps;
+        if (!aidl_struct_util::convertLegacyRttCapabilitiesToAidl(legacy_caps, &aidl_caps)) {
+            return {RttCapabilities{}, createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)};
+        }
+        return {aidl_caps, ndk::ScopedAStatus::ok()};
+    }
+
     if (legacy_status != legacy_hal::WIFI_SUCCESS) {
         return {RttCapabilities{}, createWifiStatusFromLegacyError(legacy_status)};
     }
+
     RttCapabilities aidl_caps;
-    if (!aidl_struct_util::convertLegacyRttCapabilitiesToAidl(legacy_caps, &aidl_caps)) {
+    if (!aidl_struct_util::convertLegacyRttCapabilitiesV3ToAidl(legacy_caps_v3, &aidl_caps)) {
         return {RttCapabilities{}, createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)};
     }
     return {aidl_caps, ndk::ScopedAStatus::ok()};
diff --git a/wifi/aidl/default/wifi_sta_iface.cpp b/wifi/aidl/default/wifi_sta_iface.cpp
index 800813f..f0509dc 100644
--- a/wifi/aidl/default/wifi_sta_iface.cpp
+++ b/wifi/aidl/default/wifi_sta_iface.cpp
@@ -219,6 +219,49 @@
                            &WifiStaIface::setDtimMultiplierInternal, in_multiplier);
 }
 
+ndk::ScopedAStatus WifiStaIface::getCachedScanData(CachedScanData* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getCachedScanDataInternal, _aidl_return);
+}
+
+ndk::ScopedAStatus WifiStaIface::twtGetCapabilities(TwtCapabilities* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::twtGetCapabilitiesInternal, _aidl_return);
+}
+
+ndk::ScopedAStatus WifiStaIface::twtSessionSetup(int32_t in_cmdId,
+                                                 const TwtRequest& in_twtRequest) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::twtSessionSetupInternal, in_cmdId, in_twtRequest);
+}
+
+ndk::ScopedAStatus WifiStaIface::twtSessionUpdate(int32_t in_cmdId, int32_t in_sessionId,
+                                                  const TwtRequest& in_twtRequest) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::twtSessionUpdateInternal, in_cmdId, in_sessionId,
+                           in_twtRequest);
+}
+
+ndk::ScopedAStatus WifiStaIface::twtSessionSuspend(int32_t in_cmdId, int32_t in_sessionId) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::twtSessionSuspendInternal, in_cmdId, in_sessionId);
+}
+
+ndk::ScopedAStatus WifiStaIface::twtSessionResume(int32_t in_cmdId, int32_t in_sessionId) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::twtSessionResumeInternal, in_cmdId, in_sessionId);
+}
+
+ndk::ScopedAStatus WifiStaIface::twtSessionTeardown(int32_t in_cmdId, int32_t in_sessionId) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::twtSessionTeardownInternal, in_cmdId, in_sessionId);
+}
+
+ndk::ScopedAStatus WifiStaIface::twtSessionGetStats(int32_t in_cmdId, int32_t in_sessionId) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::twtSessionGetStatsInternal, in_cmdId, in_sessionId);
+}
+
 std::pair<std::string, ndk::ScopedAStatus> WifiStaIface::getNameInternal() {
     return {ifname_, ndk::ScopedAStatus::ok()};
 }
@@ -540,6 +583,209 @@
     return createWifiStatusFromLegacyError(legacy_status);
 }
 
+std::pair<CachedScanData, ndk::ScopedAStatus> WifiStaIface::getCachedScanDataInternal() {
+    legacy_hal::WifiCachedScanReport cached_scan_report;
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->getWifiCachedScanResults(ifname_, cached_scan_report);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {CachedScanData{}, createWifiStatusFromLegacyError(legacy_status)};
+    }
+    CachedScanData aidl_scan_data;
+    if (!aidl_struct_util::convertCachedScanReportToAidl(cached_scan_report, &aidl_scan_data)) {
+        return {CachedScanData{}, createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)};
+    }
+
+    return {aidl_scan_data, ndk::ScopedAStatus::ok()};
+}
+
+std::pair<TwtCapabilities, ndk::ScopedAStatus> WifiStaIface::twtGetCapabilitiesInternal() {
+    legacy_hal::wifi_twt_capabilities legacyHaltwtCapabilities;
+    legacy_hal::wifi_error legacy_status;
+    std::tie(legacyHaltwtCapabilities, legacy_status) =
+            legacy_hal_.lock()->twtGetCapabilities(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {TwtCapabilities{}, createWifiStatusFromLegacyError(legacy_status)};
+    }
+    TwtCapabilities aidlTwtCapabilities;
+    if (!aidl_struct_util::convertTwtCapabilitiesToAidl(legacyHaltwtCapabilities,
+                                                        &aidlTwtCapabilities)) {
+        return {TwtCapabilities{}, createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS)};
+    }
+    return {aidlTwtCapabilities, ndk::ScopedAStatus::ok()};
+}
+
+ndk::ScopedAStatus WifiStaIface::twtSessionSetupInternal(int32_t cmdId,
+                                                         const TwtRequest& aidlTwtRequest) {
+    legacy_hal::wifi_twt_request legacyHalTwtRequest;
+    if (!aidl_struct_util::convertAidlTwtRequestToLegacy(aidlTwtRequest, &legacyHalTwtRequest)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    std::weak_ptr<WifiStaIface> weak_ptr_this = weak_ptr_this_;
+
+    // onTwtFailure callback
+    const auto& on_twt_failure = [weak_ptr_this](legacy_hal::wifi_request_id id,
+                                                 legacy_hal::wifi_twt_error_code error_code) {
+        const auto shared_ptr_this = weak_ptr_this.lock();
+        IWifiStaIfaceEventCallback::TwtErrorCode aidl_error_code =
+                aidl_struct_util::convertLegacyHalTwtErrorCodeToAidl(error_code);
+        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+            LOG(ERROR) << "Callback invoked on an invalid object";
+            return;
+        }
+        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+            if (!callback->onTwtFailure(id, aidl_error_code).isOk()) {
+                LOG(ERROR) << "Failed to invoke onTwtFailure callback";
+            }
+        }
+    };
+    // onTwtSessionCreate callback
+    const auto& on_twt_session_create = [weak_ptr_this](legacy_hal::wifi_request_id id,
+                                                        legacy_hal::wifi_twt_session twt_session) {
+        const auto shared_ptr_this = weak_ptr_this.lock();
+        TwtSession aidl_twt_session;
+        if (!aidl_struct_util::convertLegacyHalTwtSessionToAidl(twt_session, &aidl_twt_session)) {
+            LOG(ERROR) << "convertLegacyHalTwtSessionToAidl failed";
+            return;
+        }
+
+        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+            LOG(ERROR) << "Callback invoked on an invalid object";
+            return;
+        }
+        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+            if (!callback->onTwtSessionCreate(id, aidl_twt_session).isOk()) {
+                LOG(ERROR) << "Failed to invoke onTwtSessionCreate callback";
+            }
+        }
+    };
+    // onTwtSessionUpdate callback
+    const auto& on_twt_session_update = [weak_ptr_this](legacy_hal::wifi_request_id id,
+                                                        legacy_hal::wifi_twt_session twt_session) {
+        const auto shared_ptr_this = weak_ptr_this.lock();
+        TwtSession aidl_twt_session;
+        if (!aidl_struct_util::convertLegacyHalTwtSessionToAidl(twt_session, &aidl_twt_session)) {
+            LOG(ERROR) << "convertLegacyHalTwtSessionToAidl failed";
+            return;
+        }
+
+        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+            LOG(ERROR) << "Callback invoked on an invalid object";
+            return;
+        }
+        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+            if (!callback->onTwtSessionUpdate(id, aidl_twt_session).isOk()) {
+                LOG(ERROR) << "Failed to invoke onTwtSessionUpdate callback";
+            }
+        }
+    };
+    // onTwtSessionTeardown callback
+    const auto& on_twt_session_teardown =
+            [weak_ptr_this](legacy_hal::wifi_request_id id, int session_id,
+                            legacy_hal::wifi_twt_teardown_reason_code reason_code) {
+                const auto shared_ptr_this = weak_ptr_this.lock();
+                IWifiStaIfaceEventCallback::TwtTeardownReasonCode aidl_reason_code =
+                        aidl_struct_util::convertLegacyHalTwtReasonCodeToAidl(reason_code);
+                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                    LOG(ERROR) << "Callback invoked on an invalid object";
+                    return;
+                }
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->onTwtSessionTeardown(id, session_id, aidl_reason_code).isOk()) {
+                        LOG(ERROR) << "Failed to invoke onTwtSessionTeardown callback";
+                    }
+                }
+            };
+    // onTwtSessionStats callback
+    const auto& on_twt_session_stats = [weak_ptr_this](legacy_hal::wifi_request_id id,
+                                                       int session_id,
+                                                       legacy_hal::wifi_twt_session_stats stats) {
+        const auto shared_ptr_this = weak_ptr_this.lock();
+        TwtSessionStats aidl_session_stats;
+        if (!aidl_struct_util::convertLegacyHalTwtSessionStatsToAidl(stats, &aidl_session_stats)) {
+            LOG(ERROR) << "convertLegacyHalTwtSessionStatsToAidl failed";
+            return;
+        }
+        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+            LOG(ERROR) << "Callback invoked on an invalid object";
+            return;
+        }
+        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+            if (!callback->onTwtSessionStats(id, session_id, aidl_session_stats).isOk()) {
+                LOG(ERROR) << "Failed to invoke onTwtSessionStats callback";
+            }
+        }
+    };
+    // onTwtSessionSuspend callback
+    const auto& on_twt_session_suspend = [weak_ptr_this](legacy_hal::wifi_request_id id,
+                                                         int session_id) {
+        const auto shared_ptr_this = weak_ptr_this.lock();
+        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+            LOG(ERROR) << "Callback invoked on an invalid object";
+            return;
+        }
+        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+            if (!callback->onTwtSessionSuspend(id, session_id).isOk()) {
+                LOG(ERROR) << "Failed to invoke onTwtSessionSuspend callback";
+            }
+        }
+    };
+    // onTwtSessionResume callback
+    const auto& on_twt_session_resume = [weak_ptr_this](legacy_hal::wifi_request_id id,
+                                                        int session_id) {
+        const auto shared_ptr_this = weak_ptr_this.lock();
+        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+            LOG(ERROR) << "Callback invoked on an invalid object";
+            return;
+        }
+        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+            if (!callback->onTwtSessionResume(id, session_id).isOk()) {
+                LOG(ERROR) << "Failed to invoke onTwtSessionResume callback";
+            }
+        }
+    };
+
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->twtSessionSetup(
+            ifname_, cmdId, legacyHalTwtRequest, on_twt_failure, on_twt_session_create,
+            on_twt_session_update, on_twt_session_teardown, on_twt_session_stats,
+            on_twt_session_suspend, on_twt_session_resume);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+ndk::ScopedAStatus WifiStaIface::twtSessionUpdateInternal(int32_t cmdId, int32_t sessionId,
+                                                          const TwtRequest& aidlTwtRequest) {
+    legacy_hal::wifi_twt_request legacyHalTwtRequest;
+    if (!aidl_struct_util::convertAidlTwtRequestToLegacy(aidlTwtRequest, &legacyHalTwtRequest)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->twtSessionUpdate(ifname_, cmdId, sessionId, legacyHalTwtRequest);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+ndk::ScopedAStatus WifiStaIface::twtSessionSuspendInternal(int32_t cmdId, int32_t sessionId) {
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->twtSessionSuspend(ifname_, cmdId, sessionId);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+ndk::ScopedAStatus WifiStaIface::twtSessionResumeInternal(int32_t cmdId, int32_t sessionId) {
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->twtSessionResume(ifname_, cmdId, sessionId);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+ndk::ScopedAStatus WifiStaIface::twtSessionTeardownInternal(int32_t cmdId, int32_t sessionId) {
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->twtSessionTeardown(ifname_, cmdId, sessionId);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+ndk::ScopedAStatus WifiStaIface::twtSessionGetStatsInternal(int32_t cmdId, int32_t sessionId) {
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->twtSessionGetStats(ifname_, cmdId, sessionId);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/aidl/default/wifi_sta_iface.h b/wifi/aidl/default/wifi_sta_iface.h
index 3d7ec4d..eb8f745 100644
--- a/wifi/aidl/default/wifi_sta_iface.h
+++ b/wifi/aidl/default/wifi_sta_iface.h
@@ -90,6 +90,15 @@
     ndk::ScopedAStatus getFactoryMacAddress(std::array<uint8_t, 6>* _aidl_return) override;
     ndk::ScopedAStatus setScanMode(bool in_enable) override;
     ndk::ScopedAStatus setDtimMultiplier(int32_t in_multiplier) override;
+    ndk::ScopedAStatus getCachedScanData(CachedScanData* _aidl_return) override;
+    ndk::ScopedAStatus twtGetCapabilities(TwtCapabilities* _aidl_return) override;
+    ndk::ScopedAStatus twtSessionSetup(int in_cmdId, const TwtRequest& in_twtRequest) override;
+    ndk::ScopedAStatus twtSessionUpdate(int in_cmdId, int32_t in_sessionId,
+                                        const TwtRequest& in_twtRequest) override;
+    ndk::ScopedAStatus twtSessionSuspend(int in_cmdId, int32_t in_sessionId) override;
+    ndk::ScopedAStatus twtSessionResume(int in_cmdId, int32_t in_sessionId) override;
+    ndk::ScopedAStatus twtSessionTeardown(int in_cmdId, int32_t in_sessionId) override;
+    ndk::ScopedAStatus twtSessionGetStats(int in_cmdId, int32_t in_sessionId) override;
 
   private:
     // Corresponding worker functions for the AIDL methods.
@@ -130,6 +139,15 @@
     std::pair<std::array<uint8_t, 6>, ndk::ScopedAStatus> getFactoryMacAddressInternal();
     ndk::ScopedAStatus setScanModeInternal(bool enable);
     ndk::ScopedAStatus setDtimMultiplierInternal(const int multiplier);
+    std::pair<CachedScanData, ndk::ScopedAStatus> getCachedScanDataInternal();
+    std::pair<TwtCapabilities, ndk::ScopedAStatus> twtGetCapabilitiesInternal();
+    ndk::ScopedAStatus twtSessionSetupInternal(int cmdId, const TwtRequest& twtRequest);
+    ndk::ScopedAStatus twtSessionUpdateInternal(int cmdId, int32_t sessionId,
+                                                const TwtRequest& twtRequest);
+    ndk::ScopedAStatus twtSessionSuspendInternal(int cmdId, int32_t sessionId);
+    ndk::ScopedAStatus twtSessionResumeInternal(int cmdId, int32_t sessionId);
+    ndk::ScopedAStatus twtSessionTeardownInternal(int cmdId, int32_t sessionId);
+    ndk::ScopedAStatus twtSessionGetStatsInternal(int cmdId, int32_t sessionId);
 
     void setWeakPtr(std::weak_ptr<WifiStaIface> ptr);
 
diff --git a/wifi/aidl/vts/functional/Android.bp b/wifi/aidl/vts/functional/Android.bp
index 1277182..6896110 100644
--- a/wifi/aidl/vts/functional/Android.bp
+++ b/wifi/aidl/vts/functional/Android.bp
@@ -39,7 +39,8 @@
     ],
     static_libs: [
         "VtsHalWifiTargetTestUtil",
-        "android.hardware.wifi-V1-ndk",
+        "android.hardware.wifi.common-V1-ndk",
+        "android.hardware.wifi-V2-ndk",
         "libwifi-system-iface",
     ],
     test_suites: [
@@ -64,7 +65,8 @@
     ],
     static_libs: [
         "VtsHalWifiTargetTestUtil",
-        "android.hardware.wifi-V1-ndk",
+        "android.hardware.wifi.common-V1-ndk",
+        "android.hardware.wifi-V2-ndk",
         "libwifi-system-iface",
     ],
     test_suites: [
@@ -89,7 +91,8 @@
     ],
     static_libs: [
         "VtsHalWifiTargetTestUtil",
-        "android.hardware.wifi-V1-ndk",
+        "android.hardware.wifi.common-V1-ndk",
+        "android.hardware.wifi-V2-ndk",
         "libwifi-system-iface",
     ],
     test_suites: [
@@ -114,7 +117,8 @@
     ],
     static_libs: [
         "VtsHalWifiTargetTestUtil",
-        "android.hardware.wifi-V1-ndk",
+        "android.hardware.wifi.common-V1-ndk",
+        "android.hardware.wifi-V2-ndk",
         "libwifi-system-iface",
     ],
     test_suites: [
@@ -139,7 +143,8 @@
     ],
     static_libs: [
         "VtsHalWifiTargetTestUtil",
-        "android.hardware.wifi-V1-ndk",
+        "android.hardware.wifi.common-V1-ndk",
+        "android.hardware.wifi-V2-ndk",
         "libwifi-system-iface",
     ],
     test_suites: [
@@ -163,7 +168,8 @@
         "libnativehelper",
     ],
     static_libs: [
-        "android.hardware.wifi-V1-ndk",
+        "android.hardware.wifi.common-V1-ndk",
+        "android.hardware.wifi-V2-ndk",
         "libwifi-system-iface",
     ],
 }
diff --git a/wifi/aidl/vts/functional/wifi_aidl_test_utils.cpp b/wifi/aidl/vts/functional/wifi_aidl_test_utils.cpp
index ca3c4b7..986e3a8 100644
--- a/wifi/aidl/vts/functional/wifi_aidl_test_utils.cpp
+++ b/wifi/aidl/vts/functional/wifi_aidl_test_utils.cpp
@@ -197,9 +197,26 @@
 
 bool configureChipToSupportConcurrencyType(const std::shared_ptr<IWifiChip>& wifi_chip,
                                            IfaceConcurrencyType type, int* configured_mode_id) {
+    if (!wifi_chip.get()) {
+        return false;
+    }
     return configureChipToSupportConcurrencyTypeInternal(wifi_chip, type, configured_mode_id);
 }
 
+bool doesChipSupportConcurrencyType(const std::shared_ptr<IWifiChip>& wifi_chip,
+                                    IfaceConcurrencyType type) {
+    if (!wifi_chip.get()) {
+        return false;
+    }
+    std::vector<IWifiChip::ChipMode> chip_modes;
+    auto status = wifi_chip->getAvailableModes(&chip_modes);
+    if (!status.isOk()) {
+        return false;
+    }
+    int mode_id;
+    return findAnyModeSupportingConcurrencyType(type, chip_modes, &mode_id);
+}
+
 void stopWifiService(const char* instance_name) {
     std::shared_ptr<IWifi> wifi = getWifi(instance_name);
     if (wifi != nullptr) {
@@ -208,6 +225,9 @@
 }
 
 int32_t getChipFeatureSet(const std::shared_ptr<IWifiChip>& wifi_chip) {
+    if (!wifi_chip.get()) {
+        return 0;
+    }
     int32_t features = 0;
     if (wifi_chip->getFeatureSet(&features).isOk()) {
         return features;
diff --git a/wifi/aidl/vts/functional/wifi_aidl_test_utils.h b/wifi/aidl/vts/functional/wifi_aidl_test_utils.h
index 0d70c3b..921d689 100644
--- a/wifi/aidl/vts/functional/wifi_aidl_test_utils.h
+++ b/wifi/aidl/vts/functional/wifi_aidl_test_utils.h
@@ -42,6 +42,9 @@
 // Configure the chip in a mode to support the creation of the provided iface type.
 bool configureChipToSupportConcurrencyType(const std::shared_ptr<IWifiChip>& wifi_chip,
                                            IfaceConcurrencyType type, int* configured_mode_id);
+// Check whether the chip supports the creation of the provided iface type.
+bool doesChipSupportConcurrencyType(const std::shared_ptr<IWifiChip>& wifi_chip,
+                                    IfaceConcurrencyType type);
 // Used to trigger IWifi.stop() at the end of every test.
 void stopWifiService(const char* instance_name);
 int32_t getChipFeatureSet(const std::shared_ptr<IWifiChip>& wifi_chip);
diff --git a/wifi/aidl/vts/functional/wifi_chip_aidl_test.cpp b/wifi/aidl/vts/functional/wifi_chip_aidl_test.cpp
index bbd27f9..a1b9ce1 100644
--- a/wifi/aidl/vts/functional/wifi_chip_aidl_test.cpp
+++ b/wifi/aidl/vts/functional/wifi_chip_aidl_test.cpp
@@ -63,6 +63,10 @@
         return mode_id;
     }
 
+    bool isConcurrencyTypeSupported(IfaceConcurrencyType type) {
+        return doesChipSupportConcurrencyType(wifi_chip_, type);
+    }
+
     std::shared_ptr<IWifiStaIface> configureChipForStaAndGetIface() {
         std::shared_ptr<IWifiStaIface> iface;
         configureChipForConcurrencyType(IfaceConcurrencyType::STA);
@@ -532,6 +536,9 @@
  * CreateApIface
  */
 TEST_P(WifiChipAidlTest, CreateApIface) {
+    if (!isConcurrencyTypeSupported(IfaceConcurrencyType::AP)) {
+        GTEST_SKIP() << "AP is not supported";
+    }
     configureChipForApAndGetIface();
 }
 
@@ -549,6 +556,9 @@
  * CreateP2pIface
  */
 TEST_P(WifiChipAidlTest, CreateP2pIface) {
+    if (!isConcurrencyTypeSupported(IfaceConcurrencyType::P2P)) {
+        GTEST_SKIP() << "P2P is not supported";
+    }
     configureChipForP2pAndGetIface();
 }
 
@@ -583,6 +593,9 @@
  * GetP2pIfaceNames
  */
 TEST_P(WifiChipAidlTest, GetP2pIfaceNames) {
+    if (!isConcurrencyTypeSupported(IfaceConcurrencyType::P2P)) {
+        GTEST_SKIP() << "P2P is not supported";
+    }
     configureChipForConcurrencyType(IfaceConcurrencyType::P2P);
 
     std::vector<std::string> iface_names;
@@ -607,6 +620,9 @@
  * GetApIfaceNames
  */
 TEST_P(WifiChipAidlTest, GetApIfaceNames) {
+    if (!isConcurrencyTypeSupported(IfaceConcurrencyType::AP)) {
+        GTEST_SKIP() << "AP is not supported";
+    }
     configureChipForConcurrencyType(IfaceConcurrencyType::AP);
 
     std::vector<std::string> iface_names;
@@ -679,6 +695,9 @@
  * GetP2pIface
  */
 TEST_P(WifiChipAidlTest, GetP2pIface) {
+    if (!isConcurrencyTypeSupported(IfaceConcurrencyType::P2P)) {
+        GTEST_SKIP() << "P2P is not supported";
+    }
     std::shared_ptr<IWifiP2pIface> iface = configureChipForP2pAndGetIface();
     std::string iface_name = getP2pIfaceName(iface);
 
@@ -697,6 +716,9 @@
  * GetApIface
  */
 TEST_P(WifiChipAidlTest, GetApIface) {
+    if (!isConcurrencyTypeSupported(IfaceConcurrencyType::AP)) {
+        GTEST_SKIP() << "AP is not supported";
+    }
     std::shared_ptr<IWifiApIface> iface = configureChipForApAndGetIface();
     std::string iface_name = getApIfaceName(iface);
 
@@ -755,6 +777,9 @@
  * RemoveP2pIface
  */
 TEST_P(WifiChipAidlTest, RemoveP2pIface) {
+    if (!isConcurrencyTypeSupported(IfaceConcurrencyType::P2P)) {
+        GTEST_SKIP() << "P2P is not supported";
+    }
     std::shared_ptr<IWifiP2pIface> iface = configureChipForP2pAndGetIface();
     std::string iface_name = getP2pIfaceName(iface);
 
@@ -771,6 +796,9 @@
  * RemoveApIface
  */
 TEST_P(WifiChipAidlTest, RemoveApIface) {
+    if (!isConcurrencyTypeSupported(IfaceConcurrencyType::AP)) {
+        GTEST_SKIP() << "AP is not supported";
+    }
     std::shared_ptr<IWifiApIface> iface = configureChipForApAndGetIface();
     std::string iface_name = getApIfaceName(iface);
 
@@ -844,6 +872,36 @@
     EXPECT_EQ(instances_after_remove.size(), 1);
 }
 
+/*
+ * SetVoipMode_off
+ * Tests the setVoipMode() API with VoIP mode OFF.
+ */
+TEST_P(WifiChipAidlTest, SetVoipMode_off) {
+    configureChipForConcurrencyType(IfaceConcurrencyType::STA);
+    int32_t features = getChipFeatureSet(wifi_chip_);
+    if (features & static_cast<int32_t>(IWifiChip::FeatureSetMask::SET_VOIP_MODE)) {
+        auto status = wifi_chip_->setVoipMode(IWifiChip::VoipMode::OFF);
+        EXPECT_TRUE(status.isOk());
+    } else {
+        GTEST_SKIP() << "setVoipMode() is not supported by vendor.";
+    }
+}
+
+/*
+ * SetVoipMode_voice
+ * Tests the setVoipMode() API with VoIP mode VOICE.
+ */
+TEST_P(WifiChipAidlTest, SetVoipMode_voice) {
+    configureChipForConcurrencyType(IfaceConcurrencyType::STA);
+    int32_t features = getChipFeatureSet(wifi_chip_);
+    if (features & static_cast<int32_t>(IWifiChip::FeatureSetMask::SET_VOIP_MODE)) {
+        auto status = wifi_chip_->setVoipMode(IWifiChip::VoipMode::VOICE);
+        EXPECT_TRUE(status.isOk());
+    } else {
+        GTEST_SKIP() << "setVoipMode() is not supported by vendor.";
+    }
+}
+
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiChipAidlTest);
 INSTANTIATE_TEST_SUITE_P(WifiTest, WifiChipAidlTest,
                          testing::ValuesIn(android::getAidlHalInstanceNames(IWifi::descriptor)),
diff --git a/wifi/apex/Android.bp b/wifi/apex/Android.bp
index f8ba5c4..f8c8e6f 100644
--- a/wifi/apex/Android.bp
+++ b/wifi/apex/Android.bp
@@ -2,17 +2,6 @@
     default_applicable_licenses: ["hardware_interfaces_license"],
 }
 
-apex_key {
-    name: "com.android.hardware.wifi.key",
-    public_key: "com.android.hardware.wifi.avbpubkey",
-    private_key: "com.android.hardware.wifi.pem",
-}
-
-android_app_certificate {
-    name: "com.android.hardware.wifi.certificate",
-    certificate: "com.android.hardware.wifi",
-}
-
 genrule {
     name: "gen-android.hardware.wifi.rc",
     srcs: [":default-android.hardware.wifi-service.rc"],
@@ -36,12 +25,12 @@
 apex {
     name: "com.android.hardware.wifi",
     manifest: "apex_manifest.json",
-    key: "com.android.hardware.wifi.key",
-    certificate: ":com.android.hardware.wifi.certificate",
+    key: "com.android.hardware.key",
+    certificate: ":com.android.hardware.certificate",
     file_contexts: "file_contexts",
-    use_vndk_as_stable: true,
     updatable: false,
-    soc_specific: true,
+    vendor: true,
+
     binaries: [
         "android.hardware.wifi-service",
     ],
diff --git a/wifi/apex/com.android.hardware.wifi.avbpubkey b/wifi/apex/com.android.hardware.wifi.avbpubkey
deleted file mode 100644
index 63fba77..0000000
--- a/wifi/apex/com.android.hardware.wifi.avbpubkey
+++ /dev/null
Binary files differ
diff --git a/wifi/apex/com.android.hardware.wifi.pem b/wifi/apex/com.android.hardware.wifi.pem
deleted file mode 100644
index 9e589ac..0000000
--- a/wifi/apex/com.android.hardware.wifi.pem
+++ /dev/null
@@ -1,52 +0,0 @@
------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
deleted file mode 100644
index f4481bf..0000000
--- a/wifi/apex/com.android.hardware.wifi.pk8
+++ /dev/null
Binary files differ
diff --git a/wifi/apex/com.android.hardware.wifi.x509.pem b/wifi/apex/com.android.hardware.wifi.x509.pem
deleted file mode 100644
index c942e71..0000000
--- a/wifi/apex/com.android.hardware.wifi.x509.pem
+++ /dev/null
@@ -1,36 +0,0 @@
------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/common/aidl/Android.bp b/wifi/common/aidl/Android.bp
new file mode 100644
index 0000000..1913451
--- /dev/null
+++ b/wifi/common/aidl/Android.bp
@@ -0,0 +1,47 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES 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.wifi.common",
+    vendor_available: true,
+    srcs: [
+        "android/hardware/wifi/common/*.aidl",
+    ],
+    headers: [
+        "PersistableBundle_aidl",
+    ],
+    stability: "vintf",
+    backend: {
+        java: {
+            sdk_version: "module_current",
+            apex_available: [
+                "//apex_available:platform",
+                "com.android.wifi",
+            ],
+            min_sdk_version: "30",
+        },
+        cpp: {
+            enabled: false,
+        },
+    },
+}
diff --git a/wifi/common/aidl/aidl_api/android.hardware.wifi.common/current/android/hardware/wifi/common/OuiKeyedData.aidl b/wifi/common/aidl/aidl_api/android.hardware.wifi.common/current/android/hardware/wifi/common/OuiKeyedData.aidl
new file mode 100644
index 0000000..640a1f6
--- /dev/null
+++ b/wifi/common/aidl/aidl_api/android.hardware.wifi.common/current/android/hardware/wifi/common/OuiKeyedData.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.common;
+@VintfStability
+parcelable OuiKeyedData {
+  int oui;
+  android.os.PersistableBundle vendorData;
+}
diff --git a/wifi/common/aidl/android/hardware/wifi/common/OuiKeyedData.aidl b/wifi/common/aidl/android/hardware/wifi/common/OuiKeyedData.aidl
new file mode 100644
index 0000000..4e6a99f
--- /dev/null
+++ b/wifi/common/aidl/android/hardware/wifi/common/OuiKeyedData.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.common;
+
+import android.os.PersistableBundle;
+
+/**
+ * Data for OUI-based configuration.
+ */
+@VintfStability
+parcelable OuiKeyedData {
+    /**
+     * OUI : 24-bit organizationally unique identifier to identify the vendor/OEM.
+     * See https://standards-oui.ieee.org/ for more information.
+     */
+    int oui;
+    /**
+     * Vendor data. Expected fields should be defined by the vendor.
+     */
+    PersistableBundle vendorData;
+}
diff --git a/wifi/hostapd/1.0/Android.bp b/wifi/hostapd/1.0/Android.bp
index afcd45c..b9a84d6 100644
--- a/wifi/hostapd/1.0/Android.bp
+++ b/wifi/hostapd/1.0/Android.bp
@@ -21,4 +21,8 @@
         "android.hidl.base@1.0",
     ],
     gen_java: true,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.wifi",
+    ],
 }
diff --git a/wifi/hostapd/1.1/Android.bp b/wifi/hostapd/1.1/Android.bp
index f5f2fbe..c90b68d 100644
--- a/wifi/hostapd/1.1/Android.bp
+++ b/wifi/hostapd/1.1/Android.bp
@@ -22,4 +22,8 @@
         "android.hidl.base@1.0",
     ],
     gen_java: true,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.wifi",
+    ],
 }
diff --git a/wifi/hostapd/1.2/Android.bp b/wifi/hostapd/1.2/Android.bp
index 4ca41aa..c8bf2f8 100644
--- a/wifi/hostapd/1.2/Android.bp
+++ b/wifi/hostapd/1.2/Android.bp
@@ -23,4 +23,8 @@
         "android.hidl.base@1.0",
     ],
     gen_java: true,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.wifi",
+    ],
 }
diff --git a/wifi/hostapd/aidl/Android.bp b/wifi/hostapd/aidl/Android.bp
index 54895c1..e5d492a 100644
--- a/wifi/hostapd/aidl/Android.bp
+++ b/wifi/hostapd/aidl/Android.bp
@@ -27,6 +27,9 @@
     srcs: [
         "android/hardware/wifi/hostapd/*.aidl",
     ],
+    imports: [
+        "android.hardware.wifi.common-V1",
+    ],
     stability: "vintf",
     backend: {
         java: {
@@ -36,10 +39,16 @@
                 "com.android.wifi",
             ],
             min_sdk_version: "30",
+            lint: {
+                baseline_filename: "lint-baseline.xml",
+            },
         },
         ndk: {
             gen_trace: true,
         },
+        cpp: {
+            enabled: false,
+        },
     },
     versions_with_info: [
         {
@@ -47,5 +56,4 @@
             imports: [],
         },
     ],
-
 }
diff --git a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/ApInfo.aidl b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/ApInfo.aidl
index ca20f37..1a66105 100644
--- a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/ApInfo.aidl
+++ b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/ApInfo.aidl
@@ -40,4 +40,5 @@
   android.hardware.wifi.hostapd.ChannelBandwidth channelBandwidth;
   android.hardware.wifi.hostapd.Generation generation;
   byte[] apIfaceInstanceMacAddress;
+  @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData;
 }
diff --git a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/IfaceParams.aidl b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/IfaceParams.aidl
index 0c88a39..64367bb 100644
--- a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/IfaceParams.aidl
+++ b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/IfaceParams.aidl
@@ -37,4 +37,5 @@
   String name;
   android.hardware.wifi.hostapd.HwModeParams hwModeParams;
   android.hardware.wifi.hostapd.ChannelParams[] channelParams;
+  @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData;
 }
diff --git a/wifi/hostapd/aidl/android/hardware/wifi/hostapd/ApInfo.aidl b/wifi/hostapd/aidl/android/hardware/wifi/hostapd/ApInfo.aidl
index a6fe63b..f2b2ee6 100644
--- a/wifi/hostapd/aidl/android/hardware/wifi/hostapd/ApInfo.aidl
+++ b/wifi/hostapd/aidl/android/hardware/wifi/hostapd/ApInfo.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.wifi.hostapd;
 
+import android.hardware.wifi.common.OuiKeyedData;
 import android.hardware.wifi.hostapd.ChannelBandwidth;
 import android.hardware.wifi.hostapd.Generation;
 
@@ -57,4 +58,9 @@
      * MAC Address of the apIfaceInstance.
      */
     byte[] apIfaceInstanceMacAddress;
+
+    /**
+     * Optional vendor-specific information.
+     */
+    @nullable OuiKeyedData[] vendorData;
 }
diff --git a/wifi/hostapd/aidl/android/hardware/wifi/hostapd/IfaceParams.aidl b/wifi/hostapd/aidl/android/hardware/wifi/hostapd/IfaceParams.aidl
index a8abec3..3f8ee39 100644
--- a/wifi/hostapd/aidl/android/hardware/wifi/hostapd/IfaceParams.aidl
+++ b/wifi/hostapd/aidl/android/hardware/wifi/hostapd/IfaceParams.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.wifi.hostapd;
 
+import android.hardware.wifi.common.OuiKeyedData;
 import android.hardware.wifi.hostapd.ChannelParams;
 import android.hardware.wifi.hostapd.HwModeParams;
 
@@ -36,4 +37,8 @@
      * The list of the channel params for the dual interfaces.
      */
     ChannelParams[] channelParams;
+    /**
+     * Optional vendor-specific configuration parameters.
+     */
+    @nullable OuiKeyedData[] vendorData;
 }
diff --git a/wifi/hostapd/aidl/lint-baseline.xml b/wifi/hostapd/aidl/lint-baseline.xml
index 657622e..99231fc 100644
--- a/wifi/hostapd/aidl/lint-baseline.xml
+++ b/wifi/hostapd/aidl/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.0.0-dev" type="baseline" dependencies="true" variant="all" version="8.0.0-dev">
+<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01">
 
     <issue
         id="NewApi"
@@ -7,8 +7,8 @@
         errorLine1="      this.markVintfStability();"
         errorLine2="           ~~~~~~~~~~~~~~~~~~">
         <location
-            file="out/.intermediates/hardware/interfaces/wifi/hostapd/aidl/android.hardware.wifi.hostapd-V1-java-source/gen/android/hardware/wifi/hostapd/IHostapd.java"
-            line="55"
+            file="out/soong/.intermediates/hardware/interfaces/wifi/hostapd/aidl/android.hardware.wifi.hostapd-V1-java-source/gen/android/hardware/wifi/hostapd/IHostapd.java"
+            line="57"
             column="12"/>
     </issue>
 
@@ -18,8 +18,8 @@
         errorLine1="      this.markVintfStability();"
         errorLine2="           ~~~~~~~~~~~~~~~~~~">
         <location
-            file="out/.intermediates/hardware/interfaces/wifi/hostapd/aidl/android.hardware.wifi.hostapd-V1-java-source/gen/android/hardware/wifi/hostapd/IHostapdCallback.java"
-            line="46"
+            file="out/soong/.intermediates/hardware/interfaces/wifi/hostapd/aidl/android.hardware.wifi.hostapd-V1-java-source/gen/android/hardware/wifi/hostapd/IHostapdCallback.java"
+            line="48"
             column="12"/>
     </issue>
 
@@ -29,8 +29,8 @@
         errorLine1="      this.markVintfStability();"
         errorLine2="           ~~~~~~~~~~~~~~~~~~">
         <location
-            file="out/.intermediates/hardware/interfaces/wifi/hostapd/aidl/android.hardware.wifi.hostapd-V2-java-source/gen/android/hardware/wifi/hostapd/IHostapd.java"
-            line="117"
+            file="out/soong/.intermediates/hardware/interfaces/wifi/hostapd/aidl/android.hardware.wifi.hostapd-V2-java-source/gen/android/hardware/wifi/hostapd/IHostapd.java"
+            line="119"
             column="12"/>
     </issue>
 
@@ -40,8 +40,8 @@
         errorLine1="      this.markVintfStability();"
         errorLine2="           ~~~~~~~~~~~~~~~~~~">
         <location
-            file="out/.intermediates/hardware/interfaces/wifi/hostapd/aidl/android.hardware.wifi.hostapd-V2-java-source/gen/android/hardware/wifi/hostapd/IHostapdCallback.java"
-            line="62"
+            file="out/soong/.intermediates/hardware/interfaces/wifi/hostapd/aidl/android.hardware.wifi.hostapd-V2-java-source/gen/android/hardware/wifi/hostapd/IHostapdCallback.java"
+            line="64"
             column="12"/>
     </issue>
 
diff --git a/wifi/hostapd/aidl/vts/functional/Android.bp b/wifi/hostapd/aidl/vts/functional/Android.bp
index ff35056..87eee82 100644
--- a/wifi/hostapd/aidl/vts/functional/Android.bp
+++ b/wifi/hostapd/aidl/vts/functional/Android.bp
@@ -36,7 +36,8 @@
         "android.hardware.wifi@1.4",
         "android.hardware.wifi@1.5",
         "android.hardware.wifi@1.6",
-        "android.hardware.wifi-V1-ndk",
+        "android.hardware.wifi.common-V1-ndk",
+        "android.hardware.wifi-V2-ndk",
         "libwifi-system",
         "libwifi-system-iface",
         "VtsHalWifiTargetTestUtil",
diff --git a/wifi/netlinkinterceptor/aidl/default/Android.bp b/wifi/netlinkinterceptor/aidl/default/Android.bp
index 5227e51..c3a0c03 100644
--- a/wifi/netlinkinterceptor/aidl/default/Android.bp
+++ b/wifi/netlinkinterceptor/aidl/default/Android.bp
@@ -25,8 +25,6 @@
 
 cc_binary {
     name: "android.hardware.net.nlinterceptor-service.default",
-    init_rc: ["nlinterceptor-default.rc"],
-    vintf_fragments: ["nlinterceptor-default.xml"],
     vendor: true,
     relative_install_path: "hw",
     defaults: ["nlinterceptor@defaults"],
@@ -45,4 +43,35 @@
         "service.cpp",
         "util.cpp",
     ],
+    installable: false, // installed in APEX
+}
+
+apex {
+    name: "com.android.hardware.net.nlinterceptor",
+    vendor: true,
+    manifest: "apex_manifest.json",
+    file_contexts: "apex_file_contexts",
+    key: "com.android.hardware.key",
+    certificate: ":com.android.hardware.certificate",
+    updatable: false,
+    binaries: [
+        "android.hardware.net.nlinterceptor-service.default",
+    ],
+    prebuilts: [
+        "nlinterceptor.rc",
+        "nlinterceptor.xml",
+    ],
+}
+
+prebuilt_etc {
+    name: "nlinterceptor.rc",
+    src: "nlinterceptor.rc",
+    installable: false,
+}
+
+prebuilt_etc {
+    name: "nlinterceptor.xml",
+    src: "nlinterceptor.xml",
+    sub_dir: "vintf",
+    installable: false,
 }
diff --git a/wifi/netlinkinterceptor/aidl/default/InterceptorRelay.h b/wifi/netlinkinterceptor/aidl/default/InterceptorRelay.h
index 0178c90..915b5ff 100644
--- a/wifi/netlinkinterceptor/aidl/default/InterceptorRelay.h
+++ b/wifi/netlinkinterceptor/aidl/default/InterceptorRelay.h
@@ -18,6 +18,7 @@
 
 #include <libnl++/Socket.h>
 
+#include <atomic>
 #include <mutex>
 #include <thread>
 
diff --git a/wifi/netlinkinterceptor/aidl/default/apex_file_contexts b/wifi/netlinkinterceptor/aidl/default/apex_file_contexts
new file mode 100644
index 0000000..6ee544c
--- /dev/null
+++ b/wifi/netlinkinterceptor/aidl/default/apex_file_contexts
@@ -0,0 +1,3 @@
+(/.*)?                                                          u:object_r:vendor_file:s0
+/etc(/.*)?                                                      u:object_r:vendor_configs_file:s0
+/bin/hw/android\.hardware\.net\.nlinterceptor-service\.default	u:object_r:hal_nlinterceptor_default_exec:s0
diff --git a/wifi/netlinkinterceptor/aidl/default/apex_manifest.json b/wifi/netlinkinterceptor/aidl/default/apex_manifest.json
new file mode 100644
index 0000000..4ffeac5
--- /dev/null
+++ b/wifi/netlinkinterceptor/aidl/default/apex_manifest.json
@@ -0,0 +1,4 @@
+{
+    "name": "com.android.hardware.net.nlinterceptor",
+    "version": 1
+}
diff --git a/wifi/netlinkinterceptor/aidl/default/nlinterceptor-default.rc b/wifi/netlinkinterceptor/aidl/default/nlinterceptor-default.rc
deleted file mode 100644
index 353cb27..0000000
--- a/wifi/netlinkinterceptor/aidl/default/nlinterceptor-default.rc
+++ /dev/null
@@ -1,4 +0,0 @@
-service nlinterceptor /vendor/bin/hw/android.hardware.net.nlinterceptor-service.default
-    class hal
-    user root
-    group system inet
diff --git a/wifi/netlinkinterceptor/aidl/default/nlinterceptor.rc b/wifi/netlinkinterceptor/aidl/default/nlinterceptor.rc
new file mode 100644
index 0000000..ec9baa9
--- /dev/null
+++ b/wifi/netlinkinterceptor/aidl/default/nlinterceptor.rc
@@ -0,0 +1,4 @@
+service nlinterceptor /apex/com.android.hardware.net.nlinterceptor/bin/hw/android.hardware.net.nlinterceptor-service.default
+    class hal
+    user root
+    group system inet
diff --git a/wifi/netlinkinterceptor/aidl/default/nlinterceptor-default.xml b/wifi/netlinkinterceptor/aidl/default/nlinterceptor.xml
similarity index 100%
rename from wifi/netlinkinterceptor/aidl/default/nlinterceptor-default.xml
rename to wifi/netlinkinterceptor/aidl/default/nlinterceptor.xml
diff --git a/wifi/supplicant/1.0/Android.bp b/wifi/supplicant/1.0/Android.bp
index 66e9353..89a0907 100644
--- a/wifi/supplicant/1.0/Android.bp
+++ b/wifi/supplicant/1.0/Android.bp
@@ -31,4 +31,8 @@
         "android.hidl.base@1.0",
     ],
     gen_java: true,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.wifi",
+    ],
 }
diff --git a/wifi/supplicant/1.1/Android.bp b/wifi/supplicant/1.1/Android.bp
index c624374..f925671 100644
--- a/wifi/supplicant/1.1/Android.bp
+++ b/wifi/supplicant/1.1/Android.bp
@@ -23,4 +23,8 @@
         "android.hidl.base@1.0",
     ],
     gen_java: true,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.wifi",
+    ],
 }
diff --git a/wifi/supplicant/1.2/Android.bp b/wifi/supplicant/1.2/Android.bp
index d5d937f..f61d9b9 100644
--- a/wifi/supplicant/1.2/Android.bp
+++ b/wifi/supplicant/1.2/Android.bp
@@ -26,4 +26,8 @@
         "android.hidl.base@1.0",
     ],
     gen_java: true,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.wifi",
+    ],
 }
diff --git a/wifi/supplicant/1.3/Android.bp b/wifi/supplicant/1.3/Android.bp
index fbe7f75..173a1ef 100644
--- a/wifi/supplicant/1.3/Android.bp
+++ b/wifi/supplicant/1.3/Android.bp
@@ -27,4 +27,8 @@
         "android.hidl.base@1.0",
     ],
     gen_java: true,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.wifi",
+    ],
 }
diff --git a/wifi/supplicant/aidl/Android.bp b/wifi/supplicant/aidl/Android.bp
index ac5a952..632927d 100644
--- a/wifi/supplicant/aidl/Android.bp
+++ b/wifi/supplicant/aidl/Android.bp
@@ -27,6 +27,9 @@
     srcs: [
         "android/hardware/wifi/supplicant/*.aidl",
     ],
+    imports: [
+        "android.hardware.wifi.common-V1",
+    ],
     stability: "vintf",
     backend: {
         java: {
@@ -45,6 +48,9 @@
         ndk: {
             gen_trace: true,
         },
+        cpp: {
+            enabled: false,
+        },
     },
     versions_with_info: [
         {
@@ -57,6 +63,5 @@
         },
 
     ],
-    frozen: true,
-
+    frozen: false,
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/AuthAlgMask.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/AuthAlgMask.aidl
index 9cd178d..4421018 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/AuthAlgMask.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/AuthAlgMask.aidl
@@ -34,8 +34,8 @@
 package android.hardware.wifi.supplicant;
 @Backing(type="int") @VintfStability
 enum AuthAlgMask {
-  OPEN = 1,
-  SHARED = 2,
-  LEAP = 4,
-  SAE = 16,
+  OPEN = (1 << 0) /* 1 */,
+  SHARED = (1 << 1) /* 2 */,
+  LEAP = (1 << 2) /* 4 */,
+  SAE = (1 << 4) /* 16 */,
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/AuxiliarySupplicantEventCode.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/AuxiliarySupplicantEventCode.aidl
index 471cfff..a339a92 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/AuxiliarySupplicantEventCode.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/AuxiliarySupplicantEventCode.aidl
@@ -34,7 +34,7 @@
 package android.hardware.wifi.supplicant;
 @Backing(type="int") @VintfStability
 enum AuxiliarySupplicantEventCode {
-  EAP_METHOD_SELECTED = 0,
-  SSID_TEMP_DISABLED = 1,
-  OPEN_SSL_FAILURE = 2,
+  EAP_METHOD_SELECTED,
+  SSID_TEMP_DISABLED,
+  OPEN_SSL_FAILURE,
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/BssTmDataFlagsMask.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/BssTmDataFlagsMask.aidl
index f215f05..6f0045c 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/BssTmDataFlagsMask.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/BssTmDataFlagsMask.aidl
@@ -34,12 +34,12 @@
 package android.hardware.wifi.supplicant;
 @Backing(type="int") @VintfStability
 enum BssTmDataFlagsMask {
-  WNM_MODE_PREFERRED_CANDIDATE_LIST_INCLUDED = 1,
-  WNM_MODE_ABRIDGED = 2,
-  WNM_MODE_DISASSOCIATION_IMMINENT = 4,
-  WNM_MODE_BSS_TERMINATION_INCLUDED = 8,
-  WNM_MODE_ESS_DISASSOCIATION_IMMINENT = 16,
-  MBO_TRANSITION_REASON_CODE_INCLUDED = 32,
-  MBO_ASSOC_RETRY_DELAY_INCLUDED = 64,
-  MBO_CELLULAR_DATA_CONNECTION_PREFERENCE_INCLUDED = 128,
+  WNM_MODE_PREFERRED_CANDIDATE_LIST_INCLUDED = (1 << 0) /* 1 */,
+  WNM_MODE_ABRIDGED = (1 << 1) /* 2 */,
+  WNM_MODE_DISASSOCIATION_IMMINENT = (1 << 2) /* 4 */,
+  WNM_MODE_BSS_TERMINATION_INCLUDED = (1 << 3) /* 8 */,
+  WNM_MODE_ESS_DISASSOCIATION_IMMINENT = (1 << 4) /* 16 */,
+  MBO_TRANSITION_REASON_CODE_INCLUDED = (1 << 5) /* 32 */,
+  MBO_ASSOC_RETRY_DELAY_INCLUDED = (1 << 6) /* 64 */,
+  MBO_CELLULAR_DATA_CONNECTION_PREFERENCE_INCLUDED = (1 << 7) /* 128 */,
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ConnectionCapabilities.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ConnectionCapabilities.aidl
index 553cbc8..a0dd32f 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ConnectionCapabilities.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ConnectionCapabilities.aidl
@@ -40,4 +40,5 @@
   int maxNumberRxSpatialStreams;
   android.hardware.wifi.supplicant.LegacyMode legacyMode;
   boolean apTidToLinkMapNegotiationSupported;
+  @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData;
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppAkm.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppAkm.aidl
index df2aef8..730843d 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppAkm.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppAkm.aidl
@@ -34,8 +34,8 @@
 package android.hardware.wifi.supplicant;
 @Backing(type="int") @VintfStability
 enum DppAkm {
-  PSK = 0,
-  PSK_SAE = 1,
-  SAE = 2,
-  DPP = 3,
+  PSK,
+  PSK_SAE,
+  SAE,
+  DPP,
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppCurve.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppCurve.aidl
index e69da44..14cb49f 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppCurve.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppCurve.aidl
@@ -34,10 +34,10 @@
 package android.hardware.wifi.supplicant;
 @Backing(type="int") @VintfStability
 enum DppCurve {
-  PRIME256V1 = 0,
-  SECP384R1 = 1,
-  SECP521R1 = 2,
-  BRAINPOOLP256R1 = 3,
-  BRAINPOOLP384R1 = 4,
-  BRAINPOOLP512R1 = 5,
+  PRIME256V1,
+  SECP384R1,
+  SECP521R1,
+  BRAINPOOLP256R1,
+  BRAINPOOLP384R1,
+  BRAINPOOLP512R1,
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppEventType.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppEventType.aidl
index 9e394fc..47c8cc0 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppEventType.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppEventType.aidl
@@ -34,6 +34,6 @@
 package android.hardware.wifi.supplicant;
 @Backing(type="int") @VintfStability
 enum DppEventType {
-  CONFIGURATION_SENT = 0,
-  CONFIGURATION_APPLIED = 1,
+  CONFIGURATION_SENT,
+  CONFIGURATION_APPLIED,
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppFailureCode.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppFailureCode.aidl
index 7e7c806..89fbc4b 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppFailureCode.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppFailureCode.aidl
@@ -34,16 +34,16 @@
 package android.hardware.wifi.supplicant;
 @Backing(type="int") @VintfStability
 enum DppFailureCode {
-  INVALID_URI = 0,
-  AUTHENTICATION = 1,
-  NOT_COMPATIBLE = 2,
-  CONFIGURATION = 3,
-  BUSY = 4,
-  TIMEOUT = 5,
-  FAILURE = 6,
-  NOT_SUPPORTED = 7,
-  CONFIGURATION_REJECTED = 8,
-  CANNOT_FIND_NETWORK = 9,
-  ENROLLEE_AUTHENTICATION = 10,
-  URI_GENERATION = 11,
+  INVALID_URI,
+  AUTHENTICATION,
+  NOT_COMPATIBLE,
+  CONFIGURATION,
+  BUSY,
+  TIMEOUT,
+  FAILURE,
+  NOT_SUPPORTED,
+  CONFIGURATION_REJECTED,
+  CANNOT_FIND_NETWORK,
+  ENROLLEE_AUTHENTICATION,
+  URI_GENERATION,
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppNetRole.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppNetRole.aidl
index c6d3522..77a910b 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppNetRole.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppNetRole.aidl
@@ -34,6 +34,6 @@
 package android.hardware.wifi.supplicant;
 @Backing(type="int") @VintfStability
 enum DppNetRole {
-  STA = 0,
-  AP = 1,
+  STA,
+  AP,
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppProgressCode.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppProgressCode.aidl
index f0618a5..ea244de 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppProgressCode.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppProgressCode.aidl
@@ -34,8 +34,8 @@
 package android.hardware.wifi.supplicant;
 @Backing(type="int") @VintfStability
 enum DppProgressCode {
-  AUTHENTICATION_SUCCESS = 0,
-  RESPONSE_PENDING = 1,
-  CONFIGURATION_SENT_WAITING_RESPONSE = 2,
-  CONFIGURATION_ACCEPTED = 3,
+  AUTHENTICATION_SUCCESS,
+  RESPONSE_PENDING,
+  CONFIGURATION_SENT_WAITING_RESPONSE,
+  CONFIGURATION_ACCEPTED,
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppStatusErrorCode.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppStatusErrorCode.aidl
index d72633b..21f07dd 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppStatusErrorCode.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppStatusErrorCode.aidl
@@ -34,7 +34,7 @@
 package android.hardware.wifi.supplicant;
 @Backing(type="int") @VintfStability
 enum DppStatusErrorCode {
-  UNKNOWN = -1,
+  UNKNOWN = (-1) /* -1 */,
   SUCCESS = 0,
   NOT_COMPATIBLE = 1,
   AUTH_FAILURE = 2,
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/GroupCipherMask.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/GroupCipherMask.aidl
index f2da925..d22d3d0 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/GroupCipherMask.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/GroupCipherMask.aidl
@@ -34,12 +34,12 @@
 package android.hardware.wifi.supplicant;
 @Backing(type="int") @VintfStability
 enum GroupCipherMask {
-  WEP40 = 2,
-  WEP104 = 4,
-  TKIP = 8,
-  CCMP = 16,
-  GTK_NOT_USED = 16384,
-  GCMP_256 = 256,
-  SMS4 = 128,
-  GCMP_128 = 64,
+  WEP40 = (1 << 1) /* 2 */,
+  WEP104 = (1 << 2) /* 4 */,
+  TKIP = (1 << 3) /* 8 */,
+  CCMP = (1 << 4) /* 16 */,
+  GTK_NOT_USED = (1 << 14) /* 16384 */,
+  GCMP_256 = (1 << 8) /* 256 */,
+  SMS4 = (1 << 7) /* 128 */,
+  GCMP_128 = (1 << 6) /* 64 */,
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/GroupMgmtCipherMask.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/GroupMgmtCipherMask.aidl
index c24d6cc..23bb04f 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/GroupMgmtCipherMask.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/GroupMgmtCipherMask.aidl
@@ -34,7 +34,7 @@
 package android.hardware.wifi.supplicant;
 @Backing(type="int") @VintfStability
 enum GroupMgmtCipherMask {
-  BIP_GMAC_128 = 2048,
-  BIP_GMAC_256 = 4096,
-  BIP_CMAC_256 = 8192,
+  BIP_GMAC_128 = (1 << 11) /* 2048 */,
+  BIP_GMAC_256 = (1 << 12) /* 4096 */,
+  BIP_CMAC_256 = (1 << 13) /* 8192 */,
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pIface.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pIface.aidl
index 19e6728..0b068e0 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pIface.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pIface.aidl
@@ -35,18 +35,33 @@
 @VintfStability
 interface ISupplicantP2pIface {
   void addBonjourService(in byte[] query, in byte[] response);
+  /**
+   * @deprecated This method is deprecated from AIDL v3, newer HALs should use createGroupOwner.
+   */
   void addGroup(in boolean persistent, in int persistentNetworkId);
+  /**
+   * @deprecated This method is deprecated from AIDL v3, newer HALs should use addGroupWithConfigurationParams.
+   */
   void addGroupWithConfig(in byte[] ssid, in String pskPassphrase, in boolean persistent, in int freq, in byte[] peerAddress, in boolean joinExistingGroup);
   @PropagateAllowBlocking android.hardware.wifi.supplicant.ISupplicantP2pNetwork addNetwork();
   void addUpnpService(in int version, in String serviceName);
   void cancelConnect();
   void cancelServiceDiscovery(in long identifier);
   void cancelWps(in String groupIfName);
+  /**
+   * @deprecated This method is deprecated from AIDL v3, newer HALs should use configureExtListenWithParams.
+   */
   void configureExtListen(in int periodInMillis, in int intervalInMillis);
+  /**
+   * @deprecated This method is deprecated from AIDL v3, newer HALs should use connectWithParams.
+   */
   String connect(in byte[] peerAddress, in android.hardware.wifi.supplicant.WpsProvisionMethod provisionMethod, in String preSelectedPin, in boolean joinExistingGroup, in boolean persistent, in int goIntent);
   byte[] createNfcHandoverRequestMessage();
   byte[] createNfcHandoverSelectMessage();
   void enableWfd(in boolean enable);
+  /**
+   * @deprecated This method is deprecated from AIDL v3, newer HALs should use findWithParams.
+   */
   void find(in int timeoutInSec);
   void flush();
   void flushServices();
@@ -93,8 +108,19 @@
   String startWpsPinDisplay(in String groupIfName, in byte[] bssid);
   void startWpsPinKeypad(in String groupIfName, in String pin);
   void stopFind();
+  /**
+   * @deprecated This method is deprecated from AIDL v3, newer HALs should use findWithParams.
+   */
   void findOnSocialChannels(in int timeoutInSec);
+  /**
+   * @deprecated This method is deprecated from AIDL v3, newer HALs should use findWithParams.
+   */
   void findOnSpecificFrequency(in int freqInHz, in int timeoutInSec);
   void setVendorElements(in android.hardware.wifi.supplicant.P2pFrameTypeMask frameTypeMask, in byte[] vendorElemBytes);
   void configureEapolIpAddressAllocationParams(in int ipAddressGo, in int ipAddressMask, in int ipAddressStart, in int ipAddressEnd);
+  String connectWithParams(in android.hardware.wifi.supplicant.P2pConnectInfo connectInfo);
+  void findWithParams(in android.hardware.wifi.supplicant.P2pDiscoveryInfo discoveryInfo);
+  void configureExtListenWithParams(in android.hardware.wifi.supplicant.P2pExtListenInfo extListenInfo);
+  void addGroupWithConfigurationParams(in android.hardware.wifi.supplicant.P2pAddGroupConfigurationParams groupConfigurationParams);
+  void createGroupOwner(in android.hardware.wifi.supplicant.P2pCreateGroupOwnerInfo groupOwnerInfo);
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl
index da3ca52..65ad4c1 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl
@@ -34,23 +34,50 @@
 package android.hardware.wifi.supplicant;
 @VintfStability
 interface ISupplicantP2pIfaceCallback {
+  /**
+   * @deprecated This callback is deprecated from AIDL v3, newer HAL should call onDeviceFoundWithParams.
+   */
   oneway void onDeviceFound(in byte[] srcAddress, in byte[] p2pDeviceAddress, in byte[] primaryDeviceType, in String deviceName, in android.hardware.wifi.supplicant.WpsConfigMethods configMethods, in byte deviceCapabilities, in android.hardware.wifi.supplicant.P2pGroupCapabilityMask groupCapabilities, in byte[] wfdDeviceInfo);
   oneway void onDeviceLost(in byte[] p2pDeviceAddress);
   oneway void onFindStopped();
   oneway void onGoNegotiationCompleted(in android.hardware.wifi.supplicant.P2pStatusCode status);
+  /**
+   * @deprecated This method is deprecated from AIDL v3, newer HALs should use onGoNegotiationRequestWithParams.
+   */
   oneway void onGoNegotiationRequest(in byte[] srcAddress, in android.hardware.wifi.supplicant.WpsDevPasswordId passwordId);
   oneway void onGroupFormationFailure(in String failureReason);
   oneway void onGroupFormationSuccess();
   oneway void onGroupRemoved(in String groupIfname, in boolean isGroupOwner);
   oneway void onGroupStarted(in String groupIfname, in boolean isGroupOwner, in byte[] ssid, in int frequency, in byte[] psk, in String passphrase, in byte[] goDeviceAddress, in boolean isPersistent);
+  /**
+   * @deprecated This method is deprecated from AIDL v3, newer HALs should use onInvitationReceivedWithParams.
+   */
   oneway void onInvitationReceived(in byte[] srcAddress, in byte[] goDeviceAddress, in byte[] bssid, in int persistentNetworkId, in int operatingFrequency);
   oneway void onInvitationResult(in byte[] bssid, in android.hardware.wifi.supplicant.P2pStatusCode status);
+  /**
+   * @deprecated This callback is deprecated from AIDL v3, newer HAL should call onProvisionDiscoveryCompletedEvent.
+   */
   oneway void onProvisionDiscoveryCompleted(in byte[] p2pDeviceAddress, in boolean isRequest, in android.hardware.wifi.supplicant.P2pProvDiscStatusCode status, in android.hardware.wifi.supplicant.WpsConfigMethods configMethods, in String generatedPin);
   oneway void onR2DeviceFound(in byte[] srcAddress, in byte[] p2pDeviceAddress, in byte[] primaryDeviceType, in String deviceName, in android.hardware.wifi.supplicant.WpsConfigMethods configMethods, in byte deviceCapabilities, in android.hardware.wifi.supplicant.P2pGroupCapabilityMask groupCapabilities, in byte[] wfdDeviceInfo, in byte[] wfdR2DeviceInfo);
   oneway void onServiceDiscoveryResponse(in byte[] srcAddress, in char updateIndicator, in byte[] tlvs);
+  /**
+   * @deprecated This callback is deprecated from AIDL v3, newer HAL should call onPeerClientJoined()
+   */
   oneway void onStaAuthorized(in byte[] srcAddress, in byte[] p2pDeviceAddress);
+  /**
+   * @deprecated This callback is deprecated from AIDL v3, newer HAL should call onPeerClientDisconnected()
+   */
   oneway void onStaDeauthorized(in byte[] srcAddress, in byte[] p2pDeviceAddress);
   oneway void onGroupFrequencyChanged(in String groupIfname, in int frequency);
+  /**
+   * @deprecated This callback is deprecated from AIDL v3, newer HAL should call onDeviceFoundWithParams.
+   */
   oneway void onDeviceFoundWithVendorElements(in byte[] srcAddress, in byte[] p2pDeviceAddress, in byte[] primaryDeviceType, in String deviceName, in android.hardware.wifi.supplicant.WpsConfigMethods configMethods, in byte deviceCapabilities, in android.hardware.wifi.supplicant.P2pGroupCapabilityMask groupCapabilities, in byte[] wfdDeviceInfo, in byte[] wfdR2DeviceInfo, in byte[] vendorElemBytes);
   oneway void onGroupStartedWithParams(in android.hardware.wifi.supplicant.P2pGroupStartedEventParams groupStartedEventParams);
+  oneway void onPeerClientJoined(in android.hardware.wifi.supplicant.P2pPeerClientJoinedEventParams clientJoinedEventParams);
+  oneway void onPeerClientDisconnected(in android.hardware.wifi.supplicant.P2pPeerClientDisconnectedEventParams clientDisconnectedEventParams);
+  oneway void onProvisionDiscoveryCompletedEvent(in android.hardware.wifi.supplicant.P2pProvisionDiscoveryCompletedEventParams provisionDiscoveryCompletedEventParams);
+  oneway void onDeviceFoundWithParams(in android.hardware.wifi.supplicant.P2pDeviceFoundEventParams deviceFoundEventParams);
+  oneway void onGoNegotiationRequestWithParams(in android.hardware.wifi.supplicant.P2pGoNegotiationReqEventParams params);
+  oneway void onInvitationReceivedWithParams(in android.hardware.wifi.supplicant.P2pInvitationEventParams params);
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl
index 1616b26..917668e 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl
@@ -54,6 +54,9 @@
   android.hardware.wifi.supplicant.IfaceType getType();
   android.hardware.wifi.supplicant.WpaDriverCapabilitiesMask getWpaDriverCapabilities();
   void initiateAnqpQuery(in byte[] macAddress, in android.hardware.wifi.supplicant.AnqpInfoId[] infoElements, in android.hardware.wifi.supplicant.Hs20AnqpSubtypes[] subTypes);
+  /**
+   * @deprecated No longer in use.
+   */
   void initiateHs20IconQuery(in byte[] macAddress, in String fileName);
   void initiateTdlsDiscover(in byte[] macAddress);
   void initiateTdlsSetup(in byte[] macAddress);
@@ -98,5 +101,7 @@
   android.hardware.wifi.supplicant.SignalPollResult[] getSignalPollResults();
   android.hardware.wifi.supplicant.QosPolicyScsRequestStatus[] addQosPolicyRequestForScs(in android.hardware.wifi.supplicant.QosPolicyScsData[] qosPolicyData);
   android.hardware.wifi.supplicant.QosPolicyScsRequestStatus[] removeQosPolicyForScs(in byte[] scsPolicyIds);
+  void configureMscs(in android.hardware.wifi.supplicant.MscsParams params);
+  void disableMscs();
   const int MAX_POLICIES_PER_QOS_SCS_REQUEST = 16;
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
index 1c23223..9fa8f56 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
@@ -53,6 +53,9 @@
   oneway void onExtRadioWorkStart(in int id);
   oneway void onExtRadioWorkTimeout(in int id);
   oneway void onHs20DeauthImminentNotice(in byte[] bssid, in int reasonCode, in int reAuthDelayInSec, in String url);
+  /**
+   * @deprecated This callback is deprecated from AIDL v3.
+   */
   oneway void onHs20IconQueryDone(in byte[] bssid, in String fileName, in byte[] data);
   oneway void onHs20SubscriptionRemediation(in byte[] bssid, in android.hardware.wifi.supplicant.OsuMethod osuMethod, in String url);
   oneway void onHs20TermsAndConditionsAcceptanceRequestedNotification(in byte[] bssid, in String url);
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl
index bfc05a4..488037f 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl
@@ -129,6 +129,8 @@
   void setRoamingConsortiumSelection(in byte[] selectedRcoi);
   void setMinimumTlsVersionEapPhase1Param(android.hardware.wifi.supplicant.TlsVersion tlsVersion);
   void setStrictConservativePeerMode(in boolean enable);
+  void disableEht();
+  void setVendorData(in android.hardware.wifi.common.OuiKeyedData[] vendorData);
   const int SSID_MAX_LEN_IN_BYTES = 32;
   const int PSK_PASSPHRASE_MIN_LEN_IN_BYTES = 8;
   const int PSK_PASSPHRASE_MAX_LEN_IN_BYTES = 63;
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/IfaceType.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/IfaceType.aidl
index 557dbd7..e11c2f7 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/IfaceType.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/IfaceType.aidl
@@ -34,6 +34,6 @@
 package android.hardware.wifi.supplicant;
 @Backing(type="int") @VintfStability
 enum IfaceType {
-  STA = 0,
-  P2P = 1,
+  STA,
+  P2P,
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/IpVersion.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/IpVersion.aidl
index f571b44..9580314 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/IpVersion.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/IpVersion.aidl
@@ -34,6 +34,6 @@
 package android.hardware.wifi.supplicant;
 @Backing(type="byte") @VintfStability
 enum IpVersion {
-  VERSION_4 = 0,
-  VERSION_6 = 1,
+  VERSION_4,
+  VERSION_6,
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/KeyMgmtMask.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/KeyMgmtMask.aidl
index 7228480..06c22cb 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/KeyMgmtMask.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/KeyMgmtMask.aidl
@@ -34,21 +34,22 @@
 package android.hardware.wifi.supplicant;
 @Backing(type="int") @VintfStability
 enum KeyMgmtMask {
-  WPA_EAP = 1,
-  WPA_PSK = 2,
-  NONE = 4,
-  IEEE8021X = 8,
-  FT_EAP = 32,
-  FT_PSK = 64,
-  OSEN = 32768,
-  WPA_EAP_SHA256 = 128,
-  WPA_PSK_SHA256 = 256,
-  SAE = 1024,
-  SUITE_B_192 = 131072,
-  OWE = 4194304,
-  DPP = 8388608,
-  WAPI_PSK = 4096,
-  WAPI_CERT = 8192,
-  FILS_SHA256 = 262144,
-  FILS_SHA384 = 524288,
+  WPA_EAP = (1 << 0) /* 1 */,
+  WPA_PSK = (1 << 1) /* 2 */,
+  NONE = (1 << 2) /* 4 */,
+  IEEE8021X = (1 << 3) /* 8 */,
+  FT_EAP = (1 << 5) /* 32 */,
+  FT_PSK = (1 << 6) /* 64 */,
+  OSEN = (1 << 15) /* 32768 */,
+  WPA_EAP_SHA256 = (1 << 7) /* 128 */,
+  WPA_PSK_SHA256 = (1 << 8) /* 256 */,
+  SAE = (1 << 10) /* 1024 */,
+  SUITE_B_192 = (1 << 17) /* 131072 */,
+  OWE = (1 << 22) /* 4194304 */,
+  DPP = (1 << 23) /* 8388608 */,
+  WAPI_PSK = (1 << 12) /* 4096 */,
+  WAPI_CERT = (1 << 13) /* 8192 */,
+  FILS_SHA256 = (1 << 18) /* 262144 */,
+  FILS_SHA384 = (1 << 19) /* 524288 */,
+  PASN = (1 << 25) /* 33554432 */,
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/MscsParams.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/MscsParams.aidl
new file mode 100644
index 0000000..aeed408
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/MscsParams.aidl
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@VintfStability
+parcelable MscsParams {
+  byte upBitmap;
+  byte upLimit;
+  int streamTimeoutUs;
+  byte frameClassifierMask;
+  @Backing(type="int") @VintfStability
+  enum FrameClassifierFields {
+    IP_VERSION = (1 << 0) /* 1 */,
+    SRC_IP_ADDR = (1 << 1) /* 2 */,
+    DST_IP_ADDR = (1 << 2) /* 4 */,
+    SRC_PORT = (1 << 3) /* 8 */,
+    DST_PORT = (1 << 4) /* 16 */,
+    DSCP = (1 << 5) /* 32 */,
+    PROTOCOL_NEXT_HDR = (1 << 6) /* 64 */,
+    FLOW_LABEL = (1 << 7) /* 128 */,
+  }
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/MsduDeliveryInfo.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/MsduDeliveryInfo.aidl
new file mode 100644
index 0000000..792e08d
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/MsduDeliveryInfo.aidl
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@VintfStability
+parcelable MsduDeliveryInfo {
+  android.hardware.wifi.supplicant.MsduDeliveryInfo.DeliveryRatio deliveryRatio;
+  byte countExponent;
+  @Backing(type="byte") @VintfStability
+  enum DeliveryRatio {
+    RATIO_95 = 1,
+    RATIO_96 = 2,
+    RATIO_97 = 3,
+    RATIO_98 = 4,
+    RATIO_99 = 5,
+    RATIO_99_9 = 6,
+    RATIO_99_99 = 7,
+    RATIO_99_999 = 8,
+    RATIO_99_9999 = 9,
+  }
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/OcspType.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/OcspType.aidl
index 89de811..d5ed084 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/OcspType.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/OcspType.aidl
@@ -34,8 +34,8 @@
 package android.hardware.wifi.supplicant;
 @Backing(type="int") @VintfStability
 enum OcspType {
-  NONE = 0,
-  REQUEST_CERT_STATUS = 1,
-  REQUIRE_CERT_STATUS = 2,
-  REQUIRE_ALL_CERTS_STATUS = 3,
+  NONE,
+  REQUEST_CERT_STATUS,
+  REQUIRE_CERT_STATUS,
+  REQUIRE_ALL_CERTS_STATUS,
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pAddGroupConfigurationParams.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pAddGroupConfigurationParams.aidl
new file mode 100644
index 0000000..ff73f84
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pAddGroupConfigurationParams.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@VintfStability
+parcelable P2pAddGroupConfigurationParams {
+  byte[] ssid;
+  String passphrase;
+  boolean isPersistent;
+  int frequencyMHzOrBand;
+  byte[6] goInterfaceAddress;
+  boolean joinExistingGroup;
+  int keyMgmtMask;
+  @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData;
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pConnectInfo.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pConnectInfo.aidl
new file mode 100644
index 0000000..f4662de
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pConnectInfo.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@VintfStability
+parcelable P2pConnectInfo {
+  byte[6] peerAddress;
+  android.hardware.wifi.supplicant.WpsProvisionMethod provisionMethod;
+  String preSelectedPin;
+  boolean joinExistingGroup;
+  boolean persistent;
+  int goIntent;
+  @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData;
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pCreateGroupOwnerInfo.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pCreateGroupOwnerInfo.aidl
new file mode 100644
index 0000000..4451fb5
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pCreateGroupOwnerInfo.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@VintfStability
+parcelable P2pCreateGroupOwnerInfo {
+  boolean persistent;
+  int persistentNetworkId;
+  @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData;
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pDeviceFoundEventParams.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pDeviceFoundEventParams.aidl
new file mode 100644
index 0000000..ee8e6dc
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pDeviceFoundEventParams.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@VintfStability
+parcelable P2pDeviceFoundEventParams {
+  byte[6] srcAddress;
+  byte[6] p2pDeviceAddress;
+  byte[] primaryDeviceType;
+  String deviceName;
+  int configMethods;
+  byte deviceCapabilities;
+  int groupCapabilities;
+  byte[] wfdDeviceInfo;
+  byte[] wfdR2DeviceInfo;
+  byte[] vendorElemBytes;
+  @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData;
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pDiscoveryInfo.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pDiscoveryInfo.aidl
new file mode 100644
index 0000000..5b7dd3f
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pDiscoveryInfo.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@VintfStability
+parcelable P2pDiscoveryInfo {
+  android.hardware.wifi.supplicant.P2pScanType scanType;
+  int frequencyMhz;
+  int timeoutInSec;
+  @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData;
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pExtListenInfo.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pExtListenInfo.aidl
new file mode 100644
index 0000000..b4d8e9d
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pExtListenInfo.aidl
@@ -0,0 +1,40 @@
+/**
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@VintfStability
+parcelable P2pExtListenInfo {
+  int periodMs;
+  int intervalMs;
+  @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData;
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pFrameTypeMask.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pFrameTypeMask.aidl
index 6e1b957..3c6f8ed 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pFrameTypeMask.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pFrameTypeMask.aidl
@@ -34,17 +34,17 @@
 package android.hardware.wifi.supplicant;
 @Backing(type="int") @VintfStability
 enum P2pFrameTypeMask {
-  P2P_FRAME_PROBE_REQ_P2P = 1,
-  P2P_FRAME_PROBE_RESP_P2P = 2,
-  P2P_FRAME_PROBE_RESP_P2P_GO = 4,
-  P2P_FRAME_BEACON_P2P_GO = 8,
-  P2P_FRAME_P2P_PD_REQ = 16,
-  P2P_FRAME_P2P_PD_RESP = 32,
-  P2P_FRAME_P2P_GO_NEG_REQ = 64,
-  P2P_FRAME_P2P_GO_NEG_RESP = 128,
-  P2P_FRAME_P2P_GO_NEG_CONF = 256,
-  P2P_FRAME_P2P_INV_REQ = 512,
-  P2P_FRAME_P2P_INV_RESP = 1024,
-  P2P_FRAME_P2P_ASSOC_REQ = 2048,
-  P2P_FRAME_P2P_ASSOC_RESP = 4096,
+  P2P_FRAME_PROBE_REQ_P2P = (1 << 0) /* 1 */,
+  P2P_FRAME_PROBE_RESP_P2P = (1 << 1) /* 2 */,
+  P2P_FRAME_PROBE_RESP_P2P_GO = (1 << 2) /* 4 */,
+  P2P_FRAME_BEACON_P2P_GO = (1 << 3) /* 8 */,
+  P2P_FRAME_P2P_PD_REQ = (1 << 4) /* 16 */,
+  P2P_FRAME_P2P_PD_RESP = (1 << 5) /* 32 */,
+  P2P_FRAME_P2P_GO_NEG_REQ = (1 << 6) /* 64 */,
+  P2P_FRAME_P2P_GO_NEG_RESP = (1 << 7) /* 128 */,
+  P2P_FRAME_P2P_GO_NEG_CONF = (1 << 8) /* 256 */,
+  P2P_FRAME_P2P_INV_REQ = (1 << 9) /* 512 */,
+  P2P_FRAME_P2P_INV_RESP = (1 << 10) /* 1024 */,
+  P2P_FRAME_P2P_ASSOC_REQ = (1 << 11) /* 2048 */,
+  P2P_FRAME_P2P_ASSOC_RESP = (1 << 12) /* 4096 */,
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pGoNegotiationReqEventParams.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pGoNegotiationReqEventParams.aidl
new file mode 100644
index 0000000..ba10b3e
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pGoNegotiationReqEventParams.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@VintfStability
+parcelable P2pGoNegotiationReqEventParams {
+  byte[6] srcAddress;
+  android.hardware.wifi.supplicant.WpsDevPasswordId passwordId;
+  @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData;
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pGroupCapabilityMask.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pGroupCapabilityMask.aidl
index ffee12c..e477131 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pGroupCapabilityMask.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pGroupCapabilityMask.aidl
@@ -34,11 +34,11 @@
 package android.hardware.wifi.supplicant;
 @Backing(type="int") @VintfStability
 enum P2pGroupCapabilityMask {
-  GROUP_OWNER = 1,
-  PERSISTENT_GROUP = 2,
-  GROUP_LIMIT = 4,
-  INTRA_BSS_DIST = 8,
-  CROSS_CONN = 16,
-  PERSISTENT_RECONN = 32,
-  GROUP_FORMATION = 64,
+  GROUP_OWNER = (1 << 0) /* 1 */,
+  PERSISTENT_GROUP = (1 << 1) /* 2 */,
+  GROUP_LIMIT = (1 << 2) /* 4 */,
+  INTRA_BSS_DIST = (1 << 3) /* 8 */,
+  CROSS_CONN = (1 << 4) /* 16 */,
+  PERSISTENT_RECONN = (1 << 5) /* 32 */,
+  GROUP_FORMATION = (1 << 6) /* 64 */,
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pGroupStartedEventParams.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pGroupStartedEventParams.aidl
index 5465a86..e19ae44 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pGroupStartedEventParams.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pGroupStartedEventParams.aidl
@@ -45,4 +45,5 @@
   byte[6] goInterfaceAddress;
   boolean isP2pClientEapolIpAddressInfoPresent;
   android.hardware.wifi.supplicant.P2pClientEapolIpAddressInfo p2pClientIpInfo;
+  @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData;
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pInvitationEventParams.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pInvitationEventParams.aidl
new file mode 100644
index 0000000..541ee4f
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pInvitationEventParams.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@VintfStability
+parcelable P2pInvitationEventParams {
+  byte[6] srcAddress;
+  byte[6] goDeviceAddress;
+  byte[6] bssid;
+  int persistentNetworkId;
+  int operatingFrequencyMHz;
+  @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData;
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pPeerClientDisconnectedEventParams.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pPeerClientDisconnectedEventParams.aidl
new file mode 100644
index 0000000..5c7c393
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pPeerClientDisconnectedEventParams.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@VintfStability
+parcelable P2pPeerClientDisconnectedEventParams {
+  String groupInterfaceName;
+  byte[6] clientInterfaceAddress;
+  byte[6] clientDeviceAddress;
+  @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData;
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pPeerClientJoinedEventParams.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pPeerClientJoinedEventParams.aidl
new file mode 100644
index 0000000..40c8ff6
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pPeerClientJoinedEventParams.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@VintfStability
+parcelable P2pPeerClientJoinedEventParams {
+  String groupInterfaceName;
+  byte[6] clientInterfaceAddress;
+  byte[6] clientDeviceAddress;
+  int clientIpAddress;
+  @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData;
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pProvisionDiscoveryCompletedEventParams.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pProvisionDiscoveryCompletedEventParams.aidl
new file mode 100644
index 0000000..46366cc
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pProvisionDiscoveryCompletedEventParams.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@VintfStability
+parcelable P2pProvisionDiscoveryCompletedEventParams {
+  byte[6] p2pDeviceAddress;
+  boolean isRequest;
+  android.hardware.wifi.supplicant.P2pProvDiscStatusCode status;
+  int configMethods;
+  String generatedPin;
+  String groupInterfaceName;
+  @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData;
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pScanType.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pScanType.aidl
new file mode 100644
index 0000000..ff3efd2
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pScanType.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@Backing(type="int") @VintfStability
+enum P2pScanType {
+  FULL,
+  SOCIAL,
+  SPECIFIC_FREQ,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/PairwiseCipherMask.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/PairwiseCipherMask.aidl
index d9b00e1..a4c7b60 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/PairwiseCipherMask.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/PairwiseCipherMask.aidl
@@ -34,10 +34,10 @@
 package android.hardware.wifi.supplicant;
 @Backing(type="int") @VintfStability
 enum PairwiseCipherMask {
-  NONE = 1,
-  TKIP = 8,
-  CCMP = 16,
-  GCMP_128 = 64,
-  SMS4 = 128,
-  GCMP_256 = 256,
+  NONE = (1 << 0) /* 1 */,
+  TKIP = (1 << 3) /* 8 */,
+  CCMP = (1 << 4) /* 16 */,
+  GCMP_128 = (1 << 6) /* 64 */,
+  SMS4 = (1 << 7) /* 128 */,
+  GCMP_256 = (1 << 8) /* 256 */,
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ProtoMask.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ProtoMask.aidl
index de92428..ba79025 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ProtoMask.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ProtoMask.aidl
@@ -34,8 +34,8 @@
 package android.hardware.wifi.supplicant;
 @Backing(type="int") @VintfStability
 enum ProtoMask {
-  WPA = 1,
-  RSN = 2,
-  WAPI = 4,
-  OSEN = 8,
+  WPA = (1 << 0) /* 1 */,
+  RSN = (1 << 1) /* 2 */,
+  WAPI = (1 << 2) /* 4 */,
+  OSEN = (1 << 3) /* 8 */,
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/QosCharacteristics.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/QosCharacteristics.aidl
new file mode 100644
index 0000000..dacac8c
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/QosCharacteristics.aidl
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi.supplicant;
+@VintfStability
+parcelable QosCharacteristics {
+  int minServiceIntervalUs;
+  int maxServiceIntervalUs;
+  int minDataRateKbps;
+  int delayBoundUs;
+  int optionalFieldMask;
+  char maxMsduSizeOctets;
+  int serviceStartTimeUs;
+  byte serviceStartTimeLinkId;
+  int meanDataRateKbps;
+  int burstSizeOctets;
+  char msduLifetimeMs;
+  android.hardware.wifi.supplicant.MsduDeliveryInfo msduDeliveryInfo;
+  @Backing(type="int") @VintfStability
+  enum QosCharacteristicsMask {
+    MAX_MSDU_SIZE = (1 << 0) /* 1 */,
+    SERVICE_START_TIME = (1 << 1) /* 2 */,
+    SERVICE_START_TIME_LINK_ID = (1 << 2) /* 4 */,
+    MEAN_DATA_RATE = (1 << 3) /* 8 */,
+    BURST_SIZE = (1 << 4) /* 16 */,
+    MSDU_LIFETIME = (1 << 5) /* 32 */,
+    MSDU_DELIVERY_INFO = (1 << 6) /* 64 */,
+  }
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/QosPolicyClassifierParamsMask.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/QosPolicyClassifierParamsMask.aidl
index 9c0c0b6..fda5e3e 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/QosPolicyClassifierParamsMask.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/QosPolicyClassifierParamsMask.aidl
@@ -34,12 +34,12 @@
 package android.hardware.wifi.supplicant;
 @Backing(type="int") @VintfStability
 enum QosPolicyClassifierParamsMask {
-  SRC_IP = 1,
-  DST_IP = 2,
-  SRC_PORT = 4,
-  DST_PORT_RANGE = 8,
-  PROTOCOL_NEXT_HEADER = 16,
-  FLOW_LABEL = 32,
-  DOMAIN_NAME = 64,
-  DSCP = 128,
+  SRC_IP = (1 << 0) /* 1 */,
+  DST_IP = (1 << 1) /* 2 */,
+  SRC_PORT = (1 << 2) /* 4 */,
+  DST_PORT_RANGE = (1 << 3) /* 8 */,
+  PROTOCOL_NEXT_HEADER = (1 << 4) /* 16 */,
+  FLOW_LABEL = (1 << 5) /* 32 */,
+  DOMAIN_NAME = (1 << 6) /* 64 */,
+  DSCP = (1 << 7) /* 128 */,
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/QosPolicyRequestType.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/QosPolicyRequestType.aidl
index 4c1e4fa..fd4e787 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/QosPolicyRequestType.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/QosPolicyRequestType.aidl
@@ -34,6 +34,6 @@
 package android.hardware.wifi.supplicant;
 @Backing(type="byte") @VintfStability
 enum QosPolicyRequestType {
-  QOS_POLICY_ADD = 0,
-  QOS_POLICY_REMOVE = 1,
+  QOS_POLICY_ADD,
+  QOS_POLICY_REMOVE,
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/QosPolicyScsData.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/QosPolicyScsData.aidl
index 4e5e8ae..20be616 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/QosPolicyScsData.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/QosPolicyScsData.aidl
@@ -22,4 +22,11 @@
   byte policyId;
   byte userPriority;
   android.hardware.wifi.supplicant.QosPolicyClassifierParams classifierParams;
+  android.hardware.wifi.supplicant.QosPolicyScsData.LinkDirection direction;
+  @nullable android.hardware.wifi.supplicant.QosCharacteristics QosCharacteristics;
+  @Backing(type="byte") @VintfStability
+  enum LinkDirection {
+    DOWNLINK,
+    UPLINK,
+  }
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/QosPolicyScsRequestStatusCode.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/QosPolicyScsRequestStatusCode.aidl
index 4d81566..8e0467f 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/QosPolicyScsRequestStatusCode.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/QosPolicyScsRequestStatusCode.aidl
@@ -19,8 +19,8 @@
 package android.hardware.wifi.supplicant;
 @Backing(type="int") @VintfStability
 enum QosPolicyScsRequestStatusCode {
-  SENT = 0,
-  ALREADY_ACTIVE = 1,
-  NOT_EXIST = 2,
-  INVALID = 3,
+  SENT,
+  ALREADY_ACTIVE,
+  NOT_EXIST,
+  INVALID,
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/QosPolicyScsResponseStatusCode.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/QosPolicyScsResponseStatusCode.aidl
index 693d3e0..5d460c6 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/QosPolicyScsResponseStatusCode.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/QosPolicyScsResponseStatusCode.aidl
@@ -19,13 +19,13 @@
 package android.hardware.wifi.supplicant;
 @Backing(type="int") @VintfStability
 enum QosPolicyScsResponseStatusCode {
-  SUCCESS = 0,
-  TCLAS_REQUEST_DECLINED = 1,
-  TCLAS_NOT_SUPPORTED_BY_AP = 2,
-  TCLAS_INSUFFICIENT_RESOURCES = 3,
-  TCLAS_RESOURCES_EXHAUSTED = 4,
-  TCLAS_PROCESSING_TERMINATED_INSUFFICIENT_QOS = 5,
-  TCLAS_PROCESSING_TERMINATED_POLICY_CONFLICT = 6,
-  TCLAS_PROCESSING_TERMINATED = 7,
-  TIMEOUT = 8,
+  SUCCESS,
+  TCLAS_REQUEST_DECLINED,
+  TCLAS_NOT_SUPPORTED_BY_AP,
+  TCLAS_INSUFFICIENT_RESOURCES,
+  TCLAS_RESOURCES_EXHAUSTED,
+  TCLAS_PROCESSING_TERMINATED_INSUFFICIENT_QOS,
+  TCLAS_PROCESSING_TERMINATED_POLICY_CONFLICT,
+  TCLAS_PROCESSING_TERMINATED,
+  TIMEOUT,
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/QosPolicyStatusCode.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/QosPolicyStatusCode.aidl
index 4d40edc..9228632 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/QosPolicyStatusCode.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/QosPolicyStatusCode.aidl
@@ -34,8 +34,8 @@
 package android.hardware.wifi.supplicant;
 @Backing(type="byte") @VintfStability
 enum QosPolicyStatusCode {
-  QOS_POLICY_SUCCESS = 0,
-  QOS_POLICY_REQUEST_DECLINED = 1,
-  QOS_POLICY_CLASSIFIER_NOT_SUPPORTED = 2,
-  QOS_POLICY_INSUFFICIENT_RESOURCES = 3,
+  QOS_POLICY_SUCCESS,
+  QOS_POLICY_REQUEST_DECLINED,
+  QOS_POLICY_CLASSIFIER_NOT_SUPPORTED,
+  QOS_POLICY_INSUFFICIENT_RESOURCES,
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/SaeH2eMode.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/SaeH2eMode.aidl
index 978c337..4730d72 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/SaeH2eMode.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/SaeH2eMode.aidl
@@ -34,7 +34,7 @@
 package android.hardware.wifi.supplicant;
 @Backing(type="byte") @VintfStability
 enum SaeH2eMode {
-  DISABLED = 0,
-  H2E_OPTIONAL = 1,
-  H2E_MANDATORY = 2,
+  DISABLED,
+  H2E_OPTIONAL,
+  H2E_MANDATORY,
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/SupplicantStatusCode.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/SupplicantStatusCode.aidl
index d84ff95..d7ff798 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/SupplicantStatusCode.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/SupplicantStatusCode.aidl
@@ -34,16 +34,16 @@
 package android.hardware.wifi.supplicant;
 @Backing(type="int") @VintfStability
 enum SupplicantStatusCode {
-  SUCCESS = 0,
-  FAILURE_UNKNOWN = 1,
-  FAILURE_ARGS_INVALID = 2,
-  FAILURE_IFACE_INVALID = 3,
-  FAILURE_IFACE_UNKNOWN = 4,
-  FAILURE_IFACE_EXISTS = 5,
-  FAILURE_IFACE_DISABLED = 6,
-  FAILURE_IFACE_NOT_DISCONNECTED = 7,
-  FAILURE_NETWORK_INVALID = 8,
-  FAILURE_NETWORK_UNKNOWN = 9,
-  FAILURE_UNSUPPORTED = 10,
-  FAILURE_ONGOING_REQUEST = 11,
+  SUCCESS,
+  FAILURE_UNKNOWN,
+  FAILURE_ARGS_INVALID,
+  FAILURE_IFACE_INVALID,
+  FAILURE_IFACE_UNKNOWN,
+  FAILURE_IFACE_EXISTS,
+  FAILURE_IFACE_DISABLED,
+  FAILURE_IFACE_NOT_DISCONNECTED,
+  FAILURE_NETWORK_INVALID,
+  FAILURE_NETWORK_UNKNOWN,
+  FAILURE_UNSUPPORTED,
+  FAILURE_ONGOING_REQUEST,
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/TlsVersion.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/TlsVersion.aidl
index 22a374f..b31826a 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/TlsVersion.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/TlsVersion.aidl
@@ -34,8 +34,8 @@
 package android.hardware.wifi.supplicant;
 @Backing(type="int") @VintfStability
 enum TlsVersion {
-  TLS_V1_0 = 0,
-  TLS_V1_1 = 1,
-  TLS_V1_2 = 2,
-  TLS_V1_3 = 3,
+  TLS_V1_0,
+  TLS_V1_1,
+  TLS_V1_2,
+  TLS_V1_3,
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/TransitionDisableIndication.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/TransitionDisableIndication.aidl
index 7c63217..f1d7370 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/TransitionDisableIndication.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/TransitionDisableIndication.aidl
@@ -34,8 +34,8 @@
 package android.hardware.wifi.supplicant;
 @Backing(type="int") @VintfStability
 enum TransitionDisableIndication {
-  USE_WPA3_PERSONAL = 1,
-  USE_SAE_PK = 2,
-  USE_WPA3_ENTERPRISE = 4,
-  USE_ENHANCED_OPEN = 8,
+  USE_WPA3_PERSONAL = (1 << 0) /* 1 */,
+  USE_SAE_PK = (1 << 1) /* 2 */,
+  USE_WPA3_ENTERPRISE = (1 << 2) /* 4 */,
+  USE_ENHANCED_OPEN = (1 << 3) /* 8 */,
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpaDriverCapabilitiesMask.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpaDriverCapabilitiesMask.aidl
index 32e1510..330f2aa 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpaDriverCapabilitiesMask.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpaDriverCapabilitiesMask.aidl
@@ -34,11 +34,11 @@
 package android.hardware.wifi.supplicant;
 @Backing(type="int") @VintfStability
 enum WpaDriverCapabilitiesMask {
-  MBO = 1,
-  OCE = 2,
-  SAE_PK = 4,
-  WFD_R2 = 8,
-  TRUST_ON_FIRST_USE = 16,
-  SET_TLS_MINIMUM_VERSION = 32,
-  TLS_V1_3 = 64,
+  MBO = (1 << 0) /* 1 */,
+  OCE = (1 << 1) /* 2 */,
+  SAE_PK = (1 << 2) /* 4 */,
+  WFD_R2 = (1 << 3) /* 8 */,
+  TRUST_ON_FIRST_USE = (1 << 4) /* 16 */,
+  SET_TLS_MINIMUM_VERSION = (1 << 5) /* 32 */,
+  TLS_V1_3 = (1 << 6) /* 64 */,
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpsConfigMethods.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpsConfigMethods.aidl
index c98c479..b9ea211 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpsConfigMethods.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpsConfigMethods.aidl
@@ -34,18 +34,18 @@
 package android.hardware.wifi.supplicant;
 @Backing(type="int") @VintfStability
 enum WpsConfigMethods {
-  USBA = 1,
-  ETHERNET = 2,
-  LABEL = 4,
-  DISPLAY = 8,
-  EXT_NFC_TOKEN = 16,
-  INT_NFC_TOKEN = 32,
-  NFC_INTERFACE = 64,
-  PUSHBUTTON = 128,
-  KEYPAD = 256,
-  VIRT_PUSHBUTTON = 640,
-  PHY_PUSHBUTTON = 1152,
-  P2PS = 4096,
-  VIRT_DISPLAY = 8200,
-  PHY_DISPLAY = 16392,
+  USBA = 0x0001,
+  ETHERNET = 0x0002,
+  LABEL = 0x0004,
+  DISPLAY = 0x0008,
+  EXT_NFC_TOKEN = 0x0010,
+  INT_NFC_TOKEN = 0x0020,
+  NFC_INTERFACE = 0x0040,
+  PUSHBUTTON = 0x0080,
+  KEYPAD = 0x0100,
+  VIRT_PUSHBUTTON = 0x0280,
+  PHY_PUSHBUTTON = 0x0480,
+  P2PS = 0x1000,
+  VIRT_DISPLAY = 0x2008,
+  PHY_DISPLAY = 0x4008,
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpsDevPasswordId.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpsDevPasswordId.aidl
index 975f1ab..9a20187 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpsDevPasswordId.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpsDevPasswordId.aidl
@@ -34,12 +34,12 @@
 package android.hardware.wifi.supplicant;
 @Backing(type="int") @VintfStability
 enum WpsDevPasswordId {
-  DEFAULT = 0,
-  USER_SPECIFIED = 1,
-  MACHINE_SPECIFIED = 2,
-  REKEY = 3,
-  PUSHBUTTON = 4,
-  REGISTRAR_SPECIFIED = 5,
-  NFC_CONNECTION_HANDOVER = 7,
-  P2PS_DEFAULT = 8,
+  DEFAULT = 0x0000,
+  USER_SPECIFIED = 0x0001,
+  MACHINE_SPECIFIED = 0x0002,
+  REKEY = 0x0003,
+  PUSHBUTTON = 0x0004,
+  REGISTRAR_SPECIFIED = 0x0005,
+  NFC_CONNECTION_HANDOVER = 0x0007,
+  P2PS_DEFAULT = 0x0008,
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpsProvisionMethod.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpsProvisionMethod.aidl
index f6dba23..177d218 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpsProvisionMethod.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpsProvisionMethod.aidl
@@ -34,7 +34,7 @@
 package android.hardware.wifi.supplicant;
 @Backing(type="int") @VintfStability
 enum WpsProvisionMethod {
-  PBC = 0,
-  DISPLAY = 1,
-  KEYPAD = 2,
+  PBC,
+  DISPLAY,
+  KEYPAD,
 }
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ConnectionCapabilities.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ConnectionCapabilities.aidl
index 4921a67..64a515f 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ConnectionCapabilities.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ConnectionCapabilities.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.wifi.supplicant;
 
+import android.hardware.wifi.common.OuiKeyedData;
 import android.hardware.wifi.supplicant.LegacyMode;
 import android.hardware.wifi.supplicant.WifiTechnology;
 
@@ -48,4 +49,9 @@
      * Indicates the AP support for TID-to-link mapping negotiation.
      */
     boolean apTidToLinkMapNegotiationSupported;
+    /**
+     * Additional vendor-specific data. Null value indicates
+     * that no vendor data is provided.
+     */
+    @nullable OuiKeyedData[] vendorData;
 }
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIface.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIface.aidl
index e58422c..1230793 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIface.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIface.aidl
@@ -16,11 +16,17 @@
 
 package android.hardware.wifi.supplicant;
 
+import android.hardware.wifi.common.OuiKeyedData;
 import android.hardware.wifi.supplicant.FreqRange;
 import android.hardware.wifi.supplicant.ISupplicantP2pIfaceCallback;
 import android.hardware.wifi.supplicant.ISupplicantP2pNetwork;
 import android.hardware.wifi.supplicant.IfaceType;
 import android.hardware.wifi.supplicant.MiracastMode;
+import android.hardware.wifi.supplicant.P2pAddGroupConfigurationParams;
+import android.hardware.wifi.supplicant.P2pConnectInfo;
+import android.hardware.wifi.supplicant.P2pCreateGroupOwnerInfo;
+import android.hardware.wifi.supplicant.P2pDiscoveryInfo;
+import android.hardware.wifi.supplicant.P2pExtListenInfo;
 import android.hardware.wifi.supplicant.P2pFrameTypeMask;
 import android.hardware.wifi.supplicant.P2pGroupCapabilityMask;
 import android.hardware.wifi.supplicant.WpsConfigMethods;
@@ -48,6 +54,9 @@
      * negotiation with a specific peer). This is also known as autonomous
      * group owner. Optional |persistentNetworkId| may be used to specify
      * restart of a persistent group.
+     * <p>
+     * @deprecated This method is deprecated from AIDL v3, newer HALs should use
+     * createGroupOwner.
      *
      * @param persistent Used to request a persistent group to be formed.
      * @param persistentNetworkId Used to specify the restart of a persistent
@@ -70,6 +79,9 @@
      * whose network name and group owner's MAC address matches the specified SSID
      * and peer address without WPS process. If peerAddress is 00:00:00:00:00:00, the first found
      * group whose network name matches the specified SSID is joined.
+     * <p>
+     * @deprecated This method is deprecated from AIDL v3, newer HALs should use
+     * addGroupWithConfigurationParams.
      *
      * @param ssid The SSID of this group.
      * @param pskPassphrase The passphrase of this group.
@@ -162,6 +174,9 @@
      * (with interval obviously having to be larger than or equal to duration).
      * If the P2P module is not idle at the time the Extended Listen Timing
      * timeout occurs, the Listen State operation must be skipped.
+     * <p>
+     * @deprecated This method is deprecated from AIDL v3, newer HALs should use
+     * configureExtListenWithParams.
      *
      * @param periodInMillis Period in milliseconds.
      * @param intervalInMillis Interval in milliseconds.
@@ -176,6 +191,9 @@
      * Start P2P group formation with a discovered P2P peer. This includes
      * optional group owner negotiation, group interface setup, provisioning,
      * and establishing data connection.
+     * <p>
+     * @deprecated This method is deprecated from AIDL v3, newer HALs should use
+     * connectWithParams.
      *
      * @param peerAddress MAC address of the device to connect to.
      * @param provisionMethod Provisioning method to use.
@@ -236,6 +254,9 @@
 
     /**
      * Initiate a P2P service discovery with an optional timeout.
+     * <p>
+     * @deprecated This method is deprecated from AIDL v3, newer HALs should use
+     * findWithParams.
      *
      * @param timeoutInSec Max time to be spent is performing discovery.
      *        Set to 0 to indefinitely continue discovery until an explicit
@@ -782,8 +803,9 @@
 
     /**
      * Initiate a P2P device discovery only on social channels.
-     *
-     * Full P2P discovery is performed through |ISupplicantP2pIface.find| method.
+     * <p>
+     * @deprecated This method is deprecated from AIDL v3, newer HALs should use
+     * findWithParams.
      *
      * @param timeoutInSec The maximum amount of time that should be spent in performing device
      *         discovery.
@@ -798,8 +820,9 @@
 
     /**
      * Initiate a P2P device discovery on a specific frequency.
-     *
-     * Full P2P discovery is performed through |ISupplicantP2pIface.find| method.
+     * <p>
+     * @deprecated This method is deprecated from AIDL v3, newer HALs should use
+     * findWithParams.
      *
      * @param freqInHz the frequency to be scanned.
      * @param timeoutInSec Max time to be spent is performing discovery.
@@ -845,4 +868,74 @@
      */
     void configureEapolIpAddressAllocationParams(
             in int ipAddressGo, in int ipAddressMask, in int ipAddressStart, in int ipAddressEnd);
+
+    /**
+     * Start P2P group formation with a discovered P2P peer. This includes
+     * optional group owner negotiation, group interface setup, provisioning,
+     * and establishing data connection.
+     *
+     * @param connectInfo Parameters associated with this connection request.
+     * @return Pin generated, if |provisionMethod| uses one of the
+     *         generated |PIN*| methods.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    String connectWithParams(in P2pConnectInfo connectInfo);
+
+    /**
+     * Initiate a P2P service discovery with an optional timeout.
+     *
+     * @param discoveryInfo Parameters associated with this discovery request.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     *         |SupplicantStatusCode.FAILURE_IFACE_DISABLED|
+     */
+    void findWithParams(in P2pDiscoveryInfo discoveryInfo);
+
+    /**
+     * Configure Extended Listen Timing.
+     *
+     * If enabled, listen state must be entered every |intervalMs| for at
+     * least |periodMs|. Both values have acceptable range of 1-65535
+     * (note that the interval must be larger than or equal to the duration).
+     * If the P2P module is not idle at the time the Extended Listen Timing
+     * timeout occurs, the Listen State operation must be skipped.
+     *
+     * @param extListenInfo Parameters to configure extended listening timing.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void configureExtListenWithParams(in P2pExtListenInfo extListenInfo);
+
+    /**
+     * Set up a P2P group owner or join a group as a group client with the
+     * specified configuration. The group configurations required to establish
+     * a connection(SSID, password, channel, etc) are shared out of band.
+     * So the connection process doesn't require a P2P provision discovery or
+     * invitation message exchange.
+     *
+     * @param groupConfigurationParams Parameters associated with this add group operation.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void addGroupWithConfigurationParams(
+            in P2pAddGroupConfigurationParams groupConfigurationParams);
+
+    /**
+     * Set up a P2P group owner on this device. This is also known as autonomous
+     * group owner. The connection process requires P2P provision discovery
+     * message or invitation message exchange.
+     *
+     * @param groupOwnerInfo Parameters associated with this create group owner operation.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    void createGroupOwner(in P2pCreateGroupOwnerInfo groupOwnerInfo);
 }
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl
index 9d6fa67..44a5465 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl
@@ -16,9 +16,15 @@
 
 package android.hardware.wifi.supplicant;
 
+import android.hardware.wifi.supplicant.P2pDeviceFoundEventParams;
+import android.hardware.wifi.supplicant.P2pGoNegotiationReqEventParams;
 import android.hardware.wifi.supplicant.P2pGroupCapabilityMask;
 import android.hardware.wifi.supplicant.P2pGroupStartedEventParams;
+import android.hardware.wifi.supplicant.P2pInvitationEventParams;
+import android.hardware.wifi.supplicant.P2pPeerClientDisconnectedEventParams;
+import android.hardware.wifi.supplicant.P2pPeerClientJoinedEventParams;
 import android.hardware.wifi.supplicant.P2pProvDiscStatusCode;
+import android.hardware.wifi.supplicant.P2pProvisionDiscoveryCompletedEventParams;
 import android.hardware.wifi.supplicant.P2pStatusCode;
 import android.hardware.wifi.supplicant.WpsConfigMethods;
 import android.hardware.wifi.supplicant.WpsDevPasswordId;
@@ -35,6 +41,9 @@
 oneway interface ISupplicantP2pIfaceCallback {
     /**
      * Used to indicate that a P2P device has been found.
+     * <p>
+     * @deprecated This callback is deprecated from AIDL v3, newer HAL should call
+     * onDeviceFoundWithParams.
      *
      * @param srcAddress MAC address of the device found. This must either
      *        be the P2P device address or the P2P interface address.
@@ -81,6 +90,10 @@
      * @param srcAddress MAC address of the device that initiated the GO
      *        negotiation request.
      * @param passwordId Type of password.
+     *
+     * <p>
+     * @deprecated This method is deprecated from AIDL v3, newer HALs should use
+     * onGoNegotiationRequestWithParams.
      */
     void onGoNegotiationRequest(in byte[] srcAddress, in WpsDevPasswordId passwordId);
 
@@ -128,6 +141,9 @@
      * @param bssid Bssid of the group.
      * @param persistentNetworkId Persistent network Id of the group.
      * @param operatingFrequency Frequency on which the invitation was received.
+     * <p>
+     * @deprecated This method is deprecated from AIDL v3, newer HALs should use
+     * onInvitationReceivedWithParams.
      */
     void onInvitationReceived(in byte[] srcAddress, in byte[] goDeviceAddress, in byte[] bssid,
             in int persistentNetworkId, in int operatingFrequency);
@@ -142,6 +158,9 @@
 
     /**
      * Used to indicate the completion of a P2P provision discovery request.
+     * <p>
+     * @deprecated This callback is deprecated from AIDL v3, newer HAL should call
+     * onProvisionDiscoveryCompletedEvent.
      *
      * @param p2pDeviceAddress P2P device address.
      * @param isRequest Whether we received or sent the provision discovery.
@@ -192,6 +211,9 @@
 
     /**
      * Used to indicate when a STA device is connected to this device.
+     * <p>
+     * @deprecated This callback is deprecated from AIDL v3, newer HAL should call
+     * onPeerClientJoined()
      *
      * @param srcAddress MAC address of the device that was authorized.
      * @param p2pDeviceAddress P2P device address.
@@ -200,6 +222,9 @@
 
     /**
      * Used to indicate when a STA device is disconnected from this device.
+     * <p>
+     * @deprecated This callback is deprecated from AIDL v3, newer HAL should call
+     * onPeerClientDisconnected()
      *
      * @param srcAddress MAC address of the device that was deauthorized.
      * @param p2pDeviceAddress P2P device address.
@@ -216,6 +241,9 @@
 
     /**
      * Used to indicate that a P2P device has been found.
+     * <p>
+     * @deprecated This callback is deprecated from AIDL v3, newer HAL should call
+     * onDeviceFoundWithParams.
      *
      * @param srcAddress MAC address of the device found. This must either
      *        be the P2P device address for a peer which is not in a group,
@@ -251,4 +279,50 @@
      * @param groupStartedEventParams Parameters describing the P2P group.
      */
     void onGroupStartedWithParams(in P2pGroupStartedEventParams groupStartedEventParams);
+
+    /**
+     * Used to indicate that a P2P client has joined this device group owner.
+     *
+     * @param clientJoinedEventParams Parameters associated with peer client joined event.
+     */
+    void onPeerClientJoined(in P2pPeerClientJoinedEventParams clientJoinedEventParams);
+
+    /**
+     * Used to indicate that a P2P client has disconnected from this device group owner.
+     *
+     * @param clientDisconnectedEventParams Parameters associated with peer client disconnected
+     *         event.
+     */
+    void onPeerClientDisconnected(
+            in P2pPeerClientDisconnectedEventParams clientDisconnectedEventParams);
+
+    /**
+     * Used to indicate the completion of a P2P provision discovery request.
+     *
+     * @param provisionDiscoveryCompletedEventParams Parameters associated with
+     *        P2P provision discovery frame notification.
+     */
+    void onProvisionDiscoveryCompletedEvent(
+            in P2pProvisionDiscoveryCompletedEventParams provisionDiscoveryCompletedEventParams);
+
+    /**
+     * Used to indicate that a P2P device has been found.
+     *
+     * @param deviceFoundEventParams Parameters associated with the device found event.
+     */
+    void onDeviceFoundWithParams(in P2pDeviceFoundEventParams deviceFoundEventParams);
+
+    /**
+     * Used to indicate the reception of a P2P Group Owner negotiation request.
+     *
+     * @param params Parameters associated with the GO negotiation request event.
+     */
+    void onGoNegotiationRequestWithParams(in P2pGoNegotiationReqEventParams params);
+
+    /**
+     * Used to indicate the reception of a P2P invitation.
+     *
+     * @param params Parameters associated with the invitation request event.
+     */
+    void onInvitationReceivedWithParams(in P2pInvitationEventParams params);
 }
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl
index 06ab8fb..fb1673e 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl
@@ -29,6 +29,7 @@
 import android.hardware.wifi.supplicant.IfaceType;
 import android.hardware.wifi.supplicant.KeyMgmtMask;
 import android.hardware.wifi.supplicant.MloLinksInfo;
+import android.hardware.wifi.supplicant.MscsParams;
 import android.hardware.wifi.supplicant.QosPolicyScsData;
 import android.hardware.wifi.supplicant.QosPolicyScsRequestStatus;
 import android.hardware.wifi.supplicant.QosPolicyStatus;
@@ -304,6 +305,8 @@
      * The icon data fetched must be returned in the
      * |ISupplicantStaIfaceCallback.onHs20IconQueryDone| callback.
      *
+     * @deprecated No longer in use.
+     *
      * @param macAddress MAC address of the access point.
      * @param fileName Name of the file to request from the access point.
      * @throws ServiceSpecificException with one of the following values:
@@ -850,4 +853,28 @@
      *          being processed. Supplicant will only handle one request at a time.
      */
     QosPolicyScsRequestStatus[] removeQosPolicyForScs(in byte[] scsPolicyIds);
+
+    /**
+     * Enable Mirrored Stream Classification Service (MSCS) and configure using
+     * the provided configuration values.
+     *
+     * If MSCS has already been enabled/configured, this will overwrite the
+     * existing configuration.
+     *
+     * @param params |MscsParams| object containing the configuration.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID| if the configuration is invalid.
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN| if the configuration could not be set.
+     */
+    void configureMscs(in MscsParams params);
+
+    /**
+     * Disable Mirrored Stream Classification Service (MSCS).
+     *
+     * If MSCS is enabled/configured, this will send a remove request to the AP.
+     *
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    void disableMscs();
 }
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
index 17a220d..172fcda 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
@@ -198,6 +198,8 @@
     /**
      * Used to indicate the result of Hotspot 2.0 Icon query.
      *
+     * @deprecated This callback is deprecated from AIDL v3.
+     *
      * @param bssid BSSID of the access point.
      * @param fileName Name of the file that was requested.
      * @param data Icon data fetched from the access point.
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl
index 750cf72..fc7babf 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.wifi.supplicant;
 
+import android.hardware.wifi.common.OuiKeyedData;
 import android.hardware.wifi.supplicant.AuthAlgMask;
 import android.hardware.wifi.supplicant.DppConnectionKeys;
 import android.hardware.wifi.supplicant.EapMethod;
@@ -1141,4 +1142,27 @@
      *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
      */
     void setStrictConservativePeerMode(in boolean enable);
+
+    /**
+     * Disables Extremely High Throughput (EHT) mode, aka Wi-Fi 7 support, for the network. When
+     * EHT is disabled, the device ceases to transmit EHT related Information Elements (IEs),
+     * including multi-link IEs and EHT capability, in subsequent messages such as (Re)Association
+     * requests to the Access Point (AP).
+     *
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void disableEht();
+
+    /**
+     * Set additional vendor-provided configuration data.
+     *
+     * @param vendorData List of |OuiKeyedData| containing the vendor-provided
+     *         configuration data.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void setVendorData(in OuiKeyedData[] vendorData);
 }
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/KeyMgmtMask.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/KeyMgmtMask.aidl
index f0c3345..8758645 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/KeyMgmtMask.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/KeyMgmtMask.aidl
@@ -71,4 +71,8 @@
      * FILS shared key authentication with sha-384
      */
     FILS_SHA384 = 1 << 19,
+    /**
+     * Pre-Association Security Negotiation (PASN) Key management
+     */
+    PASN = 1 << 25,
 }
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/MscsParams.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/MscsParams.aidl
new file mode 100644
index 0000000..b1731ac
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/MscsParams.aidl
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * Mirrored Stream Classification Service (MSCS) parameters.
+ * Refer to section 3.1 of the Wi-Fi QoS Management Specification v3.0.
+ */
+@VintfStability
+parcelable MscsParams {
+    /**
+     * Bitmap indicating which User Priorities should be classified using MSCS.
+     * The least significant bit corresponds to UP 0, and the most significant
+     * bit to UP 7. Setting a bit to 1 indicates that UP should be used.
+     */
+    byte upBitmap;
+
+    /**
+     * Maximum user priority that can be assigned using the MSCS service.
+     * Value must be between 0 and 7 (inclusive).
+     */
+    byte upLimit;
+
+    /**
+     * Stream timeout in μs. Must be equivalent to 60 sec or less.
+     */
+    int streamTimeoutUs;
+
+    /**
+     * Bitmask of available fields for a Type 4 TCLAS frame classifier.
+     * See Figures 9-309 and 9-310 in the IEEE Std 802.11-2020 Standard.
+     */
+    @VintfStability
+    @Backing(type="int")
+    enum FrameClassifierFields {
+        IP_VERSION = 1 << 0,
+        SRC_IP_ADDR = 1 << 1,
+        DST_IP_ADDR = 1 << 2,
+        SRC_PORT = 1 << 3,
+        DST_PORT = 1 << 4,
+        DSCP = 1 << 5,
+        /** Indicates Protocol if using IPv4, or Next Header if using IPv6. */
+        PROTOCOL_NEXT_HDR = 1 << 6,
+        /** Only applicable if using IPv6. */
+        FLOW_LABEL = 1 << 7,
+    }
+
+    /**
+     * Bitmask of |FrameClassifierFields| for a Type 4 TCLAS frame classifier.
+     */
+    byte frameClassifierMask;
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/MsduDeliveryInfo.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/MsduDeliveryInfo.aidl
new file mode 100644
index 0000000..8065f63
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/MsduDeliveryInfo.aidl
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * MSDU delivery information.
+ * See Section 9.4.2.316 of the IEEE P802.11be/D4.0 Standard.
+ */
+@VintfStability
+parcelable MsduDeliveryInfo {
+    /**
+     * Enums for the |deliveryRatio| field.
+     * See Table 9-404t of the IEEE P802.11be/D4.0 Standard.
+     */
+    @VintfStability
+    @Backing(type="byte")
+    enum DeliveryRatio {
+        RATIO_95 = 1, // 95%
+        RATIO_96 = 2, // 96%
+        RATIO_97 = 3, // 97%
+        RATIO_98 = 4, // 98%
+        RATIO_99 = 5, // 99%
+        RATIO_99_9 = 6, // 99.9%
+        RATIO_99_99 = 7, // 99.99%
+        RATIO_99_999 = 8, // 99.999%
+        RATIO_99_9999 = 9, // 99.9999%
+    }
+
+    /**
+     * Percentage of the MSDUs that are expected to be delivered successfully.
+     */
+    DeliveryRatio deliveryRatio;
+
+    /**
+     * Exponent from which the number of incoming MSDUs is computed. The number of incoming
+     * MSDUs is 10^countExponent, and is used to determine the MSDU delivery ratio.
+     * Must be a number between 0 and 15 (inclusive).
+     */
+    byte countExponent;
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pAddGroupConfigurationParams.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pAddGroupConfigurationParams.aidl
new file mode 100644
index 0000000..15f2733
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pAddGroupConfigurationParams.aidl
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+import android.hardware.wifi.common.OuiKeyedData;
+import android.hardware.wifi.supplicant.KeyMgmtMask;
+
+/**
+ * Request parameters used for |ISupplicantP2pIface.addGroupWithConfigurationParams|
+ */
+@VintfStability
+parcelable P2pAddGroupConfigurationParams {
+    /** The SSID of the group. */
+    byte[] ssid;
+
+    /** The passphrase used to secure the group. */
+    String passphrase;
+
+    /** Whether this group is persisted. Only applied on the group owner side */
+    boolean isPersistent;
+
+    /**
+     * The required frequency or band of the group.
+     *  Only applied on the group owner side.
+     *  The following values are supported:
+     *      0: automatic channel selection,
+     *      2: for 2.4GHz channels
+     *      5: for 5GHz channels
+     *      6: for 6GHz channels
+     *      specific frequency in MHz, i.e., 2412, 5500, etc.
+     *        If an invalid band or unsupported frequency are specified,
+     *        |ISupplicantP2pIface.addGroupWithConfigurationParams| fails
+     */
+    int frequencyMHzOrBand;
+
+    /**
+     * The MAC Address of the P2P interface of the Peer GO device.
+     *        This field is valid only for the group client side.
+     *        If the MAC is "00:00:00:00:00:00", the device must try to find a peer GO device
+     *        whose network name matches the specified SSID.
+     */
+    byte[6] goInterfaceAddress;
+
+    /*
+     * True if join a group as a group client; false to create a group as a group owner
+     */
+    boolean joinExistingGroup;
+
+    /**
+     * The authentication Key management mask for the connection. Combination of |KeyMgmtMask|
+     * values. The supported authentication key management types are WPA_PSK, SAE and PASN.
+     *
+     */
+    int keyMgmtMask;
+
+    /**
+     * Optional vendor-specific parameters. Null value indicates
+     * that no vendor data is provided.
+     */
+    @nullable OuiKeyedData[] vendorData;
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pConnectInfo.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pConnectInfo.aidl
new file mode 100644
index 0000000..f09b476
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pConnectInfo.aidl
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+import android.hardware.wifi.common.OuiKeyedData;
+import android.hardware.wifi.supplicant.WpsProvisionMethod;
+
+/**
+ * Request parameters used for |ISupplicantP2pIface.connectWithParams|
+ */
+@VintfStability
+parcelable P2pConnectInfo {
+    /**
+     * MAC address of the device to connect to.
+     */
+    byte[6] peerAddress;
+
+    /**
+     * Provisioning method to use.
+     */
+    WpsProvisionMethod provisionMethod;
+
+    /**
+     * Pin to be used, if |provisionMethod| uses one of the
+     * preselected |PIN*| methods.
+     */
+    String preSelectedPin;
+
+    /**
+     * Indicates that this is a command to join an existing group as a client.
+     * This means that the group owner negotiation step can be skipped.
+     * This must send a Provision Discovery Request message to the
+     * target group owner before associating for WPS provisioning.
+     */
+    boolean joinExistingGroup;
+
+    /**
+     * Used to request a persistent group to be formed.
+     */
+    boolean persistent;
+
+    /**
+     * Used to override the default Intent for this group owner
+     * negotiation (Values from 1-15). Refer to section 4.1.6 in
+     * Wi-Fi Peer-to-Peer (P2P) Technical Specification Version 1.7.
+     */
+    int goIntent;
+
+    /**
+     * Optional vendor-specific parameters. Null value indicates
+     * that no vendor data is provided.
+     */
+    @nullable OuiKeyedData[] vendorData;
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pCreateGroupOwnerInfo.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pCreateGroupOwnerInfo.aidl
new file mode 100644
index 0000000..51e6ed9
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pCreateGroupOwnerInfo.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+import android.hardware.wifi.common.OuiKeyedData;
+
+/**
+ * Parameters used for |ISupplicantP2pIface.createGroupOwner|
+ */
+@VintfStability
+parcelable P2pCreateGroupOwnerInfo {
+    /**
+     * Used to request a persistent group to be formed.
+     */
+    boolean persistent;
+
+    /**
+     * Optional parameter. Used to specify the restart of a persistent
+     * group. Set to UINT32_MAX for a non-persistent group.
+     */
+    int persistentNetworkId;
+
+    /**
+     * Optional vendor-specific parameters. Null value indicates
+     * that no vendor data is provided.
+     */
+    @nullable OuiKeyedData[] vendorData;
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pDeviceFoundEventParams.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pDeviceFoundEventParams.aidl
new file mode 100644
index 0000000..15917b6
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pDeviceFoundEventParams.aidl
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+import android.hardware.wifi.common.OuiKeyedData;
+
+/**
+ * Parameters passed as a part of a P2P Device found event.
+ */
+@VintfStability
+parcelable P2pDeviceFoundEventParams {
+    /**
+     * MAC address of the device found. This must either be the P2P device address
+     * for a peer which is not in a group, or the P2P interface address for
+     * a peer which is a Group Owner.
+     */
+    byte[6] srcAddress;
+
+    /**
+     * P2P device address.
+     */
+    byte[6] p2pDeviceAddress;
+
+    /**
+     * Type of device. Refer to section B.1 of the Wifi P2P Technical
+     * specification v1.2.
+     */
+    byte[] primaryDeviceType;
+
+    /**
+     * Name of the device.
+     */
+    String deviceName;
+
+    /**
+     * Mask of |WpsConfigMethods| indicating the WPS configuration methods
+     * supported by the device.
+     */
+    int configMethods;
+
+    /**
+     * Refer to section 4.1.4 of the Wifi P2P Technical specification v1.2.
+     */
+    byte deviceCapabilities;
+
+    /**
+     * Mask of |P2pGroupCapabilityMask| indicating the group capabilities.
+     * Refer to section 4.1.4 of the Wifi P2P Technical specification v1.2.
+     */
+    int groupCapabilities;
+
+    /**
+     * WFD device info as described in section 5.1.2 of the WFD technical
+     * specification v1.0.0.
+     */
+    byte[] wfdDeviceInfo;
+
+    /**
+     * WFD R2 device info as described in section 5.1.12 of WFD technical
+     * specification v2.1.
+     */
+    byte[] wfdR2DeviceInfo;
+
+    /**
+     * Vendor-specific information element bytes. The format of an
+     * information element is EID (1 byte) + Length (1 Byte) + Payload which is
+     * defined in Section 9.4.4 TLV encodings of 802.11-2016 IEEE Standard for
+     * Information technology. The length indicates the size of the payload.
+     * Multiple information elements may be appended within the byte array.
+     */
+    byte[] vendorElemBytes;
+
+    /**
+     * Optional vendor-specific data.
+     * Null value indicates that no vendor data is provided.
+     */
+    @nullable OuiKeyedData[] vendorData;
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pDiscoveryInfo.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pDiscoveryInfo.aidl
new file mode 100644
index 0000000..ddb8a3d
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pDiscoveryInfo.aidl
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+import android.hardware.wifi.common.OuiKeyedData;
+import android.hardware.wifi.supplicant.P2pScanType;
+
+/**
+ * Request parameters used for |ISupplicantP2pIface.findWithParams|
+ */
+@VintfStability
+parcelable P2pDiscoveryInfo {
+    /**
+     * P2P scan type.
+     */
+    P2pScanType scanType;
+
+    /**
+     * Frequency to scan in MHz. Only valid the scan type is |P2pScanType.SPECIFIC_FREQ|
+     */
+    int frequencyMhz;
+
+    /**
+     * Max time, in seconds, to be spent in performing discovery.
+     * Set to 0 to indefinitely continue discovery until an explicit
+     * |stopFind| is sent.
+     */
+    int timeoutInSec;
+
+    /**
+     * Optional vendor-specific parameters. Null value indicates
+     * that no vendor data is provided.
+     */
+    @nullable OuiKeyedData[] vendorData;
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pExtListenInfo.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pExtListenInfo.aidl
new file mode 100644
index 0000000..1086c94
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pExtListenInfo.aidl
@@ -0,0 +1,39 @@
+/**
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+import android.hardware.wifi.common.OuiKeyedData;
+
+/**
+ * Parameters used to configure the P2P Extended Listen Interval.
+ */
+@VintfStability
+parcelable P2pExtListenInfo {
+    /**
+     * Period in milliseconds.
+     */
+    int periodMs;
+    /**
+     * Interval in milliseconds.
+     */
+    int intervalMs;
+    /**
+     * Optional vendor-specific parameters. Null value indicates
+     * that no vendor data is provided.
+     */
+    @nullable OuiKeyedData[] vendorData;
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pGoNegotiationReqEventParams.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pGoNegotiationReqEventParams.aidl
new file mode 100644
index 0000000..3480734
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pGoNegotiationReqEventParams.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+import android.hardware.wifi.common.OuiKeyedData;
+import android.hardware.wifi.supplicant.WpsDevPasswordId;
+
+/**
+ * Parameters used for |ISupplicantP2pIfaceCallback.onGoNegotiationRequestWithParams|
+ */
+@VintfStability
+parcelable P2pGoNegotiationReqEventParams {
+    /**
+     * MAC address of the device that sent the Go negotiation request.
+     */
+    byte[6] srcAddress;
+
+    /**
+     * Type of password.
+     */
+    WpsDevPasswordId passwordId;
+
+    /**
+     * Optional vendor-specific parameters. Null value indicates
+     * that no vendor data is provided.
+     */
+    @nullable OuiKeyedData[] vendorData;
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pGroupStartedEventParams.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pGroupStartedEventParams.aidl
index 96f1e16..9db7a1e 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pGroupStartedEventParams.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pGroupStartedEventParams.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.wifi.supplicant;
 
+import android.hardware.wifi.common.OuiKeyedData;
 import android.hardware.wifi.supplicant.P2pClientEapolIpAddressInfo;
 
 /**
@@ -63,4 +64,10 @@
      * The value is undefined if isP2pClientEapolIpAddressInfoPresent is false.
      */
     P2pClientEapolIpAddressInfo p2pClientIpInfo;
+
+    /**
+     * Optional vendor-specific parameters. Null value indicates
+     * that no vendor data is provided.
+     */
+    @nullable OuiKeyedData[] vendorData;
 }
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pInvitationEventParams.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pInvitationEventParams.aidl
new file mode 100644
index 0000000..4295c40
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pInvitationEventParams.aidl
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+import android.hardware.wifi.common.OuiKeyedData;
+
+/**
+ * Parameters used for |ISupplicantP2pIfaceCallback.onInvitationReceivedWithParams|
+ */
+@VintfStability
+parcelable P2pInvitationEventParams {
+    /**
+     * MAC address of the device that sent the invitation.
+     */
+    byte[6] srcAddress;
+
+    /**
+     * P2P device MAC Address of the group owner.
+     */
+    byte[6] goDeviceAddress;
+
+    /**
+     * BSSID of the group.
+     */
+    byte[6] bssid;
+
+    /**
+     * Persistent network ID of the group.
+     */
+    int persistentNetworkId;
+
+    /**
+     * Frequency on which the invitation was received.
+     */
+    int operatingFrequencyMHz;
+
+    /**
+     * Optional vendor-specific parameters. Null value indicates
+     * that no vendor data is provided.
+     */
+    @nullable OuiKeyedData[] vendorData;
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pPeerClientDisconnectedEventParams.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pPeerClientDisconnectedEventParams.aidl
new file mode 100644
index 0000000..6e3350f
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pPeerClientDisconnectedEventParams.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+import android.hardware.wifi.common.OuiKeyedData;
+
+/**
+ * Parameters passed as a part of P2P peer client disconnected event.
+ */
+@VintfStability
+parcelable P2pPeerClientDisconnectedEventParams {
+    /** Interface name of this device group owner. (For ex: p2p-p2p0-1) */
+    String groupInterfaceName;
+
+    /** P2P group interface MAC address of the client that disconnected. */
+    byte[6] clientInterfaceAddress;
+
+    /** P2P device interface MAC address of the client that disconnected. */
+    byte[6] clientDeviceAddress;
+
+    /**
+     * Optional vendor-specific parameters. Null value indicates
+     * that no vendor data is provided.
+     */
+    @nullable OuiKeyedData[] vendorData;
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pPeerClientJoinedEventParams.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pPeerClientJoinedEventParams.aidl
new file mode 100644
index 0000000..4f46d70
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pPeerClientJoinedEventParams.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+import android.hardware.wifi.common.OuiKeyedData;
+
+/**
+ * Parameters passed as a part of P2P peer client joined event.
+ */
+@VintfStability
+parcelable P2pPeerClientJoinedEventParams {
+    /** Interface name of this device group owner. (For ex: p2p-p2p0-1) */
+    String groupInterfaceName;
+
+    /** P2P group interface MAC address of the client that joined. */
+    byte[6] clientInterfaceAddress;
+
+    /** P2P device interface MAC address of the client that joined. */
+    byte[6] clientDeviceAddress;
+
+    /**
+     * The P2P Client IPV4 address allocated via EAPOL exchange.
+     * The higher-order address bytes are in the lower-order int bytes
+     * (e.g. 1.2.3.4 is represented as 0x04030201).
+     * Refer Wi-Fi P2P Technical Specification v1.7 - Section  4.2.8
+     * "IP Address Allocation in EAPOL-Key Frames (4-Way Handshake)" for more details.
+     * The value is set to zero if the IP address is not allocated via EAPOL exchange.
+     */
+    int clientIpAddress;
+
+    /**
+     * Optional vendor-specific parameters. Null value indicates
+     * that no vendor data is provided.
+     */
+    @nullable OuiKeyedData[] vendorData;
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pProvisionDiscoveryCompletedEventParams.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pProvisionDiscoveryCompletedEventParams.aidl
new file mode 100644
index 0000000..05152a9
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pProvisionDiscoveryCompletedEventParams.aidl
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+import android.hardware.wifi.common.OuiKeyedData;
+import android.hardware.wifi.supplicant.P2pProvDiscStatusCode;
+
+/**
+ * Parameters passed as a part of P2P provision discovery frame notification.
+ */
+@VintfStability
+parcelable P2pProvisionDiscoveryCompletedEventParams {
+    /**
+     * P2P device interface MAC address of the device who sent the request or responded to our
+     * request.
+     */
+    byte[6] p2pDeviceAddress;
+    /** True if this is a request, false if this is a response. */
+    boolean isRequest;
+    /** Status of the provision discovery */
+    P2pProvDiscStatusCode status;
+    /** Mask of |WpsConfigMethods| indicating the supported methods */
+    int configMethods;
+    /** 8-digit pin generated */
+    String generatedPin;
+    /**
+     * Interface name of this device group owner. (For ex: p2p-p2p0-1)
+     * This field is filled only when the provision discovery request is received
+     * with P2P Group ID attribute. i.e., when the peer device is joining this
+     * device operating P2P group.
+     * Refer to WFA Wi-Fi_Direct_Specification_v1.9 section 3.2.1 for more details.
+     */
+    String groupInterfaceName;
+    /**
+     * Optional vendor-specific parameters. Null value indicates
+     * that no vendor data is provided.
+     */
+    @nullable OuiKeyedData[] vendorData;
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pScanType.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pScanType.aidl
new file mode 100644
index 0000000..1ab14c4
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pScanType.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * Scan types used in P2P.
+ */
+@VintfStability
+@Backing(type="int")
+enum P2pScanType {
+    /**
+     * All channels.
+     */
+    FULL,
+    /**
+     * Social channels.
+     */
+    SOCIAL,
+    /**
+     * Specific channel.
+     */
+    SPECIFIC_FREQ,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/QosCharacteristics.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/QosCharacteristics.aidl
new file mode 100644
index 0000000..be5ef91
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/QosCharacteristics.aidl
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+import android.hardware.wifi.supplicant.MsduDeliveryInfo;
+
+/**
+ * Additional QoS parameters as defined in Section 9.4.2.316
+ * of the IEEE P802.11be/D4.0 Standard.
+ */
+@VintfStability
+parcelable QosCharacteristics {
+    /**
+     * Unsigned integer specifying the minimum interval (in microseconds) between the start of
+     * two consecutive service periods (SPs) that are allocated for frame exchanges.
+     * The value must be non-zero.
+     */
+    int minServiceIntervalUs;
+
+    /**
+     * Unsigned integer specifying the maximum interval (in microseconds) between the start of two
+     * consecutive SPs that are allocated for frame exchanges. The value must be non-zero.
+     */
+    int maxServiceIntervalUs;
+
+    /**
+     * Unsigned integer specifying the lowest data rate (in kilobits/sec)
+     * for the transport of MSDUs or A-MSDUs belonging to the traffic flow.
+     * The value must be non-zero.
+     */
+    int minDataRateKbps;
+
+    /**
+     * Unsigned integer specifying the maximum amount of time (in microseconds)
+     * targeted to transport an MSDU or A-MSDU belonging to the traffic flow.
+     * The value must be non-zero.
+     */
+    int delayBoundUs;
+
+    /**
+     * Enum values indicating which optional fields are provided.
+     * See Figure 9-1001au of the IEEE P802.11be/D4.0 Standard.
+     */
+    @VintfStability
+    @Backing(type="int")
+    enum QosCharacteristicsMask {
+        MAX_MSDU_SIZE = 1 << 0,
+        SERVICE_START_TIME = 1 << 1,
+        SERVICE_START_TIME_LINK_ID = 1 << 2,
+        MEAN_DATA_RATE = 1 << 3,
+        BURST_SIZE = 1 << 4,
+        MSDU_LIFETIME = 1 << 5,
+        MSDU_DELIVERY_INFO = 1 << 6,
+    }
+
+    /**
+     * Mask of |QosCharacteristicsMask| indicating which optional fields are provided.
+     */
+    int optionalFieldMask;
+
+    /**
+     * Unsigned 16-bit value specifying the maximum size (in octets) of an MSDU
+     * belonging to the traffic flow. The value must be non-zero if provided.
+     */
+    char maxMsduSizeOctets;
+
+    /**
+     * Unsigned integer specifying the anticipated time (in microseconds) when
+     * the traffic starts for the associated TID.
+     */
+    int serviceStartTimeUs;
+
+    /**
+     * The four LSBs indicate the link identifier that corresponds to the link for which the
+     * TSF timer is used to indicate the Service Start Time. The four MSBs should not be used.
+     * This field is present if |serviceStartTimeUs| is included and is not present otherwise.
+     */
+    byte serviceStartTimeLinkId;
+
+    /**
+     * Unsigned integer indicating the data rate specified (in kilobits/sec) for transport of MSDUs
+     * or A-MSDUs belonging to the traffic flow. The value must be non-zero if provided.
+     */
+    int meanDataRateKbps;
+
+    /**
+     * Unsigned integer specififying the maximum burst (in octets) of the MSDUs or A-MSDUs
+     * belonging to the traffic flow that arrive at the MAC SAP within any time duration equal
+     * to the value specified in the |delayBound| field. The value must be non-zero if provided.
+     */
+    int burstSizeOctets;
+
+    /**
+     * Unsigned 16-bit integer specifying the maximum amount of time (in milliseconds) since the
+     * arrival of the MSDU at the MAC data service interface beyond which the MSDU is not useful
+     * even if received by the receiver. The amount of time specified in this field is larger than
+     * or equal to the amount of time specified in the |delayBound| field, if present. The value
+     * must be non-zero if provided.
+     */
+    char msduLifetimeMs;
+
+    /**
+     * MSDU delivery information. See |MsduDeliveryInfo| for more details.
+     */
+    MsduDeliveryInfo msduDeliveryInfo;
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/QosPolicyScsData.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/QosPolicyScsData.aidl
index 86a4dac..76f5a9a 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/QosPolicyScsData.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/QosPolicyScsData.aidl
@@ -1,5 +1,6 @@
 package android.hardware.wifi.supplicant;
 
+import android.hardware.wifi.supplicant.QosCharacteristics;
 import android.hardware.wifi.supplicant.QosPolicyClassifierParams;
 
 /**
@@ -21,4 +22,24 @@
      * QoS policy SCS classifier type information.
      */
     QosPolicyClassifierParams classifierParams;
+
+    /**
+     * Enum values for the |direction| field.
+     */
+    @VintfStability
+    @Backing(type="byte")
+    enum LinkDirection {
+        DOWNLINK,
+        UPLINK, // Only applies to trigger-based traffic (Wi-Fi 6+)
+    }
+
+    /**
+     * Direction of data described by this element.
+     */
+    LinkDirection direction;
+
+    /**
+     * Additional parameters available in QoS R3.
+     */
+    @nullable QosCharacteristics QosCharacteristics;
 }
diff --git a/wifi/supplicant/aidl/vts/functional/Android.bp b/wifi/supplicant/aidl/vts/functional/Android.bp
index f7c619a..96c13e7 100644
--- a/wifi/supplicant/aidl/vts/functional/Android.bp
+++ b/wifi/supplicant/aidl/vts/functional/Android.bp
@@ -42,15 +42,17 @@
         "android.hardware.wifi@1.3",
         "android.hardware.wifi@1.4",
         "android.hardware.wifi@1.5",
+        "android.hardware.wifi.common-V1-ndk",
         "android.hardware.wifi.supplicant@1.0",
         "android.hardware.wifi.supplicant@1.1",
-        "android.hardware.wifi.supplicant-V2-ndk",
+        "android.hardware.wifi.supplicant-V3-ndk",
         "libwifi-system",
         "libwifi-system-iface",
         "VtsHalWifiV1_0TargetTestUtil",
         "VtsHalWifiV1_5TargetTestUtil",
         "VtsHalWifiSupplicantV1_0TargetTestUtil",
-        "android.hardware.wifi-V1-ndk",
+        "android.hardware.wifi.common-V1-ndk",
+        "android.hardware.wifi-V2-ndk",
         "VtsHalWifiTargetTestUtil",
     ],
     test_suites: [
@@ -78,15 +80,17 @@
         "android.hardware.wifi@1.3",
         "android.hardware.wifi@1.4",
         "android.hardware.wifi@1.5",
+        "android.hardware.wifi.common-V1-ndk",
         "android.hardware.wifi.supplicant@1.0",
         "android.hardware.wifi.supplicant@1.1",
-        "android.hardware.wifi.supplicant-V2-ndk",
+        "android.hardware.wifi.supplicant-V3-ndk",
         "libwifi-system",
         "libwifi-system-iface",
         "VtsHalWifiV1_0TargetTestUtil",
         "VtsHalWifiV1_5TargetTestUtil",
         "VtsHalWifiSupplicantV1_0TargetTestUtil",
-        "android.hardware.wifi-V1-ndk",
+        "android.hardware.wifi.common-V1-ndk",
+        "android.hardware.wifi-V2-ndk",
         "VtsHalWifiTargetTestUtil",
     ],
     test_suites: [
@@ -114,15 +118,17 @@
         "android.hardware.wifi@1.3",
         "android.hardware.wifi@1.4",
         "android.hardware.wifi@1.5",
+        "android.hardware.wifi.common-V1-ndk",
         "android.hardware.wifi.supplicant@1.0",
         "android.hardware.wifi.supplicant@1.1",
-        "android.hardware.wifi.supplicant-V2-ndk",
+        "android.hardware.wifi.supplicant-V3-ndk",
         "libwifi-system",
         "libwifi-system-iface",
         "VtsHalWifiV1_0TargetTestUtil",
         "VtsHalWifiV1_5TargetTestUtil",
         "VtsHalWifiSupplicantV1_0TargetTestUtil",
-        "android.hardware.wifi-V1-ndk",
+        "android.hardware.wifi.common-V1-ndk",
+        "android.hardware.wifi-V2-ndk",
         "VtsHalWifiTargetTestUtil",
     ],
     test_suites: [
diff --git a/wifi/supplicant/aidl/vts/functional/supplicant_p2p_iface_aidl_test.cpp b/wifi/supplicant/aidl/vts/functional/supplicant_p2p_iface_aidl_test.cpp
index a260408..2d6823f 100644
--- a/wifi/supplicant/aidl/vts/functional/supplicant_p2p_iface_aidl_test.cpp
+++ b/wifi/supplicant/aidl/vts/functional/supplicant_p2p_iface_aidl_test.cpp
@@ -35,10 +35,16 @@
 using aidl::android::hardware::wifi::supplicant::ISupplicant;
 using aidl::android::hardware::wifi::supplicant::ISupplicantP2pIface;
 using aidl::android::hardware::wifi::supplicant::MiracastMode;
+using aidl::android::hardware::wifi::supplicant::P2pDeviceFoundEventParams;
 using aidl::android::hardware::wifi::supplicant::P2pFrameTypeMask;
+using aidl::android::hardware::wifi::supplicant::P2pGoNegotiationReqEventParams;
 using aidl::android::hardware::wifi::supplicant::P2pGroupCapabilityMask;
 using aidl::android::hardware::wifi::supplicant::P2pGroupStartedEventParams;
+using aidl::android::hardware::wifi::supplicant::P2pInvitationEventParams;
+using aidl::android::hardware::wifi::supplicant::P2pPeerClientDisconnectedEventParams;
+using aidl::android::hardware::wifi::supplicant::P2pPeerClientJoinedEventParams;
 using aidl::android::hardware::wifi::supplicant::P2pProvDiscStatusCode;
+using aidl::android::hardware::wifi::supplicant::P2pProvisionDiscoveryCompletedEventParams;
 using aidl::android::hardware::wifi::supplicant::P2pStatusCode;
 using aidl::android::hardware::wifi::supplicant::SupplicantStatusCode;
 using aidl::android::hardware::wifi::supplicant::WpsConfigMethods;
@@ -182,6 +188,32 @@
             const P2pGroupStartedEventParams& /* groupStartedEventParams */) override {
         return ndk::ScopedAStatus::ok();
     }
+    ::ndk::ScopedAStatus onPeerClientJoined(
+            const P2pPeerClientJoinedEventParams& /* clientJoinedEventParams */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onPeerClientDisconnected(
+            const P2pPeerClientDisconnectedEventParams& /* clientDisconnectedEventParams */)
+            override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onProvisionDiscoveryCompletedEvent(
+            const P2pProvisionDiscoveryCompletedEventParams&
+            /* provisionDiscoveryCompletedEventParams */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onDeviceFoundWithParams(
+            const P2pDeviceFoundEventParams& /* deviceFoundEventParams */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onGoNegotiationRequestWithParams(
+            const P2pGoNegotiationReqEventParams& /* goNegotiationReqEventParams */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onInvitationReceivedWithParams(
+            const P2pInvitationEventParams& /* invitationEventParams */) override {
+        return ndk::ScopedAStatus::ok();
+    }
 };
 
 class SupplicantP2pIfaceAidlTest : public testing::TestWithParam<std::string> {
diff --git a/wifi/supplicant/aidl/vts/functional/supplicant_sta_network_aidl_test.cpp b/wifi/supplicant/aidl/vts/functional/supplicant_sta_network_aidl_test.cpp
index 973b56a..e5e9735 100644
--- a/wifi/supplicant/aidl/vts/functional/supplicant_sta_network_aidl_test.cpp
+++ b/wifi/supplicant/aidl/vts/functional/supplicant_sta_network_aidl_test.cpp
@@ -110,6 +110,7 @@
         initializeService();
         supplicant_ = getSupplicant(GetParam().c_str());
         ASSERT_NE(supplicant_, nullptr);
+        ASSERT_TRUE(supplicant_->getInterfaceVersion(&interface_version_).isOk());
         ASSERT_TRUE(supplicant_
                         ->setDebugParams(DebugLevel::EXCESSIVE,
                                          true,  // show timestamps
@@ -131,6 +132,7 @@
     std::shared_ptr<ISupplicant> supplicant_;
     std::shared_ptr<ISupplicantStaIface> sta_iface_;
     std::shared_ptr<ISupplicantStaNetwork> sta_network_;
+    int interface_version_;
 
     void removeNetwork() {
         ASSERT_NE(sta_iface_, nullptr);
@@ -822,6 +824,16 @@
               tlsV13Supported);
 }
 
+/*
+ * disableEht
+ */
+TEST_P(SupplicantStaNetworkAidlTest, DisableEht) {
+    if (interface_version_ < 3) {
+        GTEST_SKIP() << "disableEht is available as of Supplicant V3";
+    }
+    EXPECT_TRUE(sta_network_->disableEht().isOk());
+}
+
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SupplicantStaNetworkAidlTest);
 INSTANTIATE_TEST_SUITE_P(Supplicant, SupplicantStaNetworkAidlTest,
                          testing::ValuesIn(android::getAidlHalInstanceNames(