[automerger skipped] Merge "Test: Don't check results when no type-c ports" into android13-tests-dev am: 6ec8db6abe am: 671d743f60 am: f2f4d925e3 -s ours am: 2289aa447c -s ours am: 1e1a774a41 -s ours am: e15ddd2a1d -s ours
am skip reason: Merged-In Ibf599038b542d5d81a2af9ab2097f2f868be0447 with SHA-1 f3a68a04fc is already in history
Original change: https://android-review.googlesource.com/c/platform/hardware/interfaces/+/2635482
Change-Id: Id300642320365823c68385c51e6e62d3c4f1c0da
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
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/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/OWNERS
similarity index 97%
rename from atrace/1.0/vts/functional/OWNERS
rename to atrace/OWNERS
index 31043aa..d76ffa6 100644
--- a/atrace/1.0/vts/functional/OWNERS
+++ b/atrace/OWNERS
@@ -1,2 +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..81c99f7 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"
},
{
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/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..2d4d283 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,20 @@
* @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'.
+ *
+ * @param portId The ID of the audio port that is about to disconnect
+ * @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/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..6ebe0d5
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/Spatializer.aidl
@@ -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 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;
+
+ /**
+ * Head tracking sensor ID.
+ */
+ 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/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..949b654 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,7 +94,7 @@
"audio_policy_engine_configuration_aidl_default",
],
shared_libs: [
- "android.hardware.bluetooth.audio-V3-ndk",
+ "android.hardware.bluetooth.audio-impl",
"libaudio_aidl_conversion_common_ndk",
"libbluetooth_audio_session_aidl",
"libmedia_helper",
@@ -134,15 +119,16 @@
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",
"libmedia_helper",
@@ -172,6 +158,7 @@
"libbase",
"libbinder_ndk",
"libcutils",
+ "libfmq",
"libmedia_helper",
"libstagefright_foundation",
"libutils",
@@ -184,9 +171,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",
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..baaa55f 100644
--- a/audio/aidl/default/Configuration.cpp
+++ b/audio/aidl/default/Configuration.cpp
@@ -32,6 +32,7 @@
using aidl::android::media::audio::common::AudioFormatDescription;
using aidl::android::media::audio::common::AudioFormatType;
using aidl::android::media::audio::common::AudioGainConfig;
+using aidl::android::media::audio::common::AudioInputFlags;
using aidl::android::media::audio::common::AudioIoFlags;
using aidl::android::media::audio::common::AudioOutputFlags;
using aidl::android::media::audio::common::AudioPort;
@@ -41,8 +42,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 +106,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 +118,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 +136,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 +170,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 +186,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 +208,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 +217,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 +254,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 +269,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 +290,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,37 +321,26 @@
// - 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, 192000
+// * "r_submix input", maximum 10 opened streams, maximum 10 active streams
+// - profile PCM 16-bit; STEREO; 8000, 11025, 16000, 32000, 44100, 48000, 192000
+// * "r_submix output direct", DIRECT|IEC958_NONAUDIO, 1 max open, 1 max active
+// - profile PCM 16-bit; STEREO; 8000, 11025, 16000, 32000, 44100, 48000, 192000
+// * "r_submix input direct", DIRECT, 1 max open, 1 max active
+// - profile PCM 16-bit; STEREO; 8000, 11025, 16000, 32000, 44100, 48000, 192000
+
//
// Routes:
-// "r_submix output" -> "Remote Submix Out"
-// "Remote Submix In" -> "r_submix input"
+// "r_submix output", "r_submix output direct" -> "Remote Submix Out"
+// "Remote Submix In" -> "r_submix input", "r_submix input direct"
//
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},
- {8000, 11025, 16000, 32000, 44100, 48000})};
+ const std::vector<AudioProfile> remoteSubmixPcmAudioProfiles{
+ createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO},
+ {8000, 11025, 16000, 32000, 44100, 48000, 192000})};
// Device ports
@@ -333,29 +349,57 @@
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);
+ // Adding a DIRECT flag to rsubmixInMix breaks the mixer paths, so we need separate
+ // non direct and direct paths. It is added because for IEC61937 encapsulated over PCM, we
+ // need the DIRECT and IEC958_NONAUDIO flags as AudioFlinger adds them.
+ AudioPort rsubmixOutDirectMix =
+ createPort(c.nextPortId++, "r_submix output direct",
+ makeBitPositionFlagMask({
+ AudioOutputFlags::DIRECT,
+ AudioOutputFlags::IEC958_NONAUDIO}),
+ false /* isInput */,
+ createPortMixExt(1 /* maxOpenStreamCount */,
+ 1 /* maxActiveStreamCount */));
+ rsubmixOutDirectMix.profiles = remoteSubmixPcmAudioProfiles;
+ c.ports.push_back(rsubmixOutDirectMix);
+
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));
+ // Adding a DIRECT flag to rsubmixInMix breaks the capture paths, so we need separate
+ // non direct and direct paths. It is added because for IEC61937 encapsulated over PCM, we
+ // need the DIRECT flag for the capability so AudioFlinger can find a DIRECT input match.
+ AudioPort rsubmixInDirectMix =
+ createPort(c.nextPortId++, "r_submix input direct",
+ makeBitPositionFlagMask({AudioInputFlags::DIRECT}),
+ true /* isInput */,
+ createPortMixExt(1 /* maxOpenStreamCount */,
+ 1 /* maxActiveStreamCount */));
+ rsubmixInDirectMix.profiles = remoteSubmixPcmAudioProfiles;
+ c.ports.push_back(rsubmixInDirectMix);
+
+ c.routes.push_back(createRoute(
+ {rsubmixOutMix, rsubmixOutDirectMix}, rsubmixOutDevice));
c.routes.push_back(createRoute({rsubmixInDevice}, rsubmixInMix));
+ c.routes.push_back(createRoute({rsubmixInDevice}, rsubmixInDirectMix));
return c;
}();
@@ -385,7 +429,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 +486,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 +506,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 +531,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 +553,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 +567,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 +598,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 +648,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 +698,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 +707,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 +720,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..4a12f8a 100644
--- a/audio/aidl/default/EffectConfig.cpp
+++ b/audio/aidl/default/EffectConfig.cpp
@@ -196,16 +196,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/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..6c4d7ac 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,56 @@
namespace {
+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);
+}
+
+// Note: does not assign an ID to the config.
bool generateDefaultPortConfig(const AudioPort& port, AudioPortConfig* config) {
+ const bool allowDynamicConfig = port.ext.getTag() == AudioPortExt::device;
*config = {};
config->portId = port.id;
- if (port.profiles.empty()) {
- LOG(ERROR) << __func__ << ": port " << port.id << " has no profiles";
- return false;
+ 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;
}
- 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;
+ if (allowDynamicConfig) {
+ config->format = AudioFormatDescription{};
+ config->channelMask = AudioChannelLayout{};
+ config->sampleRate = Int{.value = 0};
+ config->flags = port.flags;
+ config->ext = port.ext;
+ return true;
}
- 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;
+ LOG(ERROR) << __func__ << ": port " << port.id << " only has dynamic profiles";
+ return false;
}
bool findAudioProfile(const AudioPort& port, const AudioFormatDescription& format,
@@ -108,21 +134,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 +185,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 +202,17 @@
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);
// Since this is a private method, it is assumed that
// validity of the portConfigId has already been checked.
+ const int32_t minimumStreamBufferSizeFrames = calculateBufferSizeFrames(
+ getNominalLatencyMs(*portConfigIt), 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) {
@@ -192,11 +240,12 @@
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, getNominalLatencyMs(*portConfigIt),
portConfigIt->ext.get<AudioPortExt::mix>().handle,
std::make_unique<StreamContext::DataMQ>(frameSize * in_bufferSizeFrames),
- asyncCallback, outEventCallback, params);
+ asyncCallback, outEventCallback,
+ std::weak_ptr<sounddose::StreamDataProcessorInterface>{}, params);
if (temp.isValid()) {
*out_context = std::move(temp);
} else {
@@ -279,6 +328,22 @@
return ndk::ScopedAStatus::ok();
}
+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 +357,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 +423,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 +467,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 +593,99 @@
}
}
- 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);
+ 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));
+ } 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 = getConfig().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 +740,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 +823,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 +846,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 +993,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);
@@ -880,13 +1049,14 @@
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()) {
@@ -904,6 +1074,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 +1095,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 +1115,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 +1131,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 {
@@ -1071,7 +1249,7 @@
// Reset master mute if it failed.
onMasterMuteChanged(mMasterMute);
}
- return std::move(result);
+ return result;
}
ndk::ScopedAStatus Module::getMasterVolume(float* _aidl_return) {
@@ -1093,7 +1271,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 +1290,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 +1436,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 +1530,18 @@
return mIsMmapSupported.value();
}
-ndk::ScopedAStatus Module::populateConnectedDevicePort(AudioPort* audioPort __unused) {
+ndk::ScopedAStatus Module::populateConnectedDevicePort(AudioPort* audioPort) {
+ 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 +1559,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 +1574,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/Stream.cpp b/audio/aidl/default/Stream.cpp
index f7298c0..a805b87 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;
}
@@ -307,7 +315,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);
@@ -573,8 +581,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 +601,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 +848,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 +979,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..5e18f1b 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};
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..8512631 100644
--- a/audio/aidl/default/alsa/ModuleAlsa.cpp
+++ b/audio/aidl/default/alsa/ModuleAlsa.cpp
@@ -39,13 +39,14 @@
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.xml b/audio/aidl/default/android.hardware.audio.effect.service-aidl.xml
index fdc53a3..05a825d 100644
--- a/audio/aidl/default/android.hardware.audio.effect.service-aidl.xml
+++ b/audio/aidl/default/android.hardware.audio.effect.service-aidl.xml
@@ -1,7 +1,7 @@
<manifest version="1.0" type="device">
<hal format="aidl">
<name>android.hardware.audio.effect</name>
- <version>1</version>
+ <version>2</version>
<fqname>IFactory/default</fqname>
</hal>
</manifest>
diff --git a/audio/aidl/default/android.hardware.audio.service-aidl.xml b/audio/aidl/default/android.hardware.audio.service-aidl.xml
index 9db6061..2a51876 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,5 @@
<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>
- </hal>
+ -->
</manifest>
diff --git a/audio/aidl/default/audio_effects_config.xml b/audio/aidl/default/audio_effects_config.xml
index 00de797..6f0af21 100644
--- a/audio/aidl/default/audio_effects_config.xml
+++ b/audio/aidl/default/audio_effects_config.xml
@@ -96,8 +96,8 @@
<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"/>
</effects>
<preprocess>
diff --git a/audio/aidl/default/bluetooth/DevicePortProxy.cpp b/audio/aidl/default/bluetooth/DevicePortProxy.cpp
index 12e204a..1be0875 100644
--- a/audio/aidl/default/bluetooth/DevicePortProxy.cpp
+++ b/audio/aidl/default/bluetooth/DevicePortProxy.cpp
@@ -19,11 +19,25 @@
#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:
diff --git a/audio/aidl/default/bluetooth/ModuleBluetooth.cpp b/audio/aidl/default/bluetooth/ModuleBluetooth.cpp
index bfe7ca0..8a1cbbf 100644
--- a/audio/aidl/default/bluetooth/ModuleBluetooth.cpp
+++ b/audio/aidl/default/bluetooth/ModuleBluetooth.cpp
@@ -18,42 +18,71 @@
#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::media::audio::common::AudioDeviceDescription;
+using aidl::android::media::audio::common::AudioDeviceType;
using aidl::android::media::audio::common::AudioOffloadInfo;
+using aidl::android::media::audio::common::AudioPort;
+using aidl::android::media::audio::common::AudioPortExt;
using aidl::android::media::audio::common::MicrophoneInfo;
+using android::bluetooth::audio::aidl::BluetoothAudioPortAidl;
+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 {
+
+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) {
@@ -80,6 +109,54 @@
offloadInfo, getBtProfileManagerHandles());
}
+ndk::ScopedAStatus ModuleBluetooth::populateConnectedDevicePort(AudioPort* audioPort) {
+ 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>();
+ const auto& description = devicePort.device.type;
+ // Since the configuration of the BT module is static, there is nothing to populate here.
+ // However, this method must return an error when the device can not be connected,
+ // this is determined by the status of BT profiles.
+ if (description.connection == AudioDeviceDescription::CONNECTION_BT_A2DP) {
+ bool isA2dpEnabled = false;
+ if (!!mBluetoothA2dp) {
+ RETURN_STATUS_IF_ERROR((*mBluetoothA2dp).isEnabled(&isA2dpEnabled));
+ }
+ LOG(DEBUG) << __func__ << ": isA2dpEnabled: " << isA2dpEnabled;
+ return isA2dpEnabled ? ndk::ScopedAStatus::ok()
+ : 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;
+ return isLeEnabled ? ndk::ScopedAStatus::ok()
+ : 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, thus the only way to check
+ // connectivity is to try to talk to the BT HAL.
+ if (!::aidl::android::hardware::bluetooth::audio::BluetoothAudioSession::
+ IsAidlAvailable()) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+ std::shared_ptr<BluetoothAudioPortAidl> proxy = std::shared_ptr<BluetoothAudioPortAidl>(
+ std::make_shared<BluetoothAudioPortAidlOut>());
+ if (proxy->registerPort(description)) {
+ LOG(DEBUG) << __func__ << ": registered hearing aid port";
+ proxy->unregisterPort();
+ return ndk::ScopedAStatus::ok();
+ }
+ LOG(DEBUG) << __func__ << ": failed to register hearing aid port";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+ LOG(ERROR) << __func__ << ": unsupported device type: " << audioPort->toString();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+}
+
ndk::ScopedAStatus ModuleBluetooth::onMasterMuteChanged(bool) {
LOG(DEBUG) << __func__ << ": is not supported";
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
diff --git a/audio/aidl/default/bluetooth/StreamBluetooth.cpp b/audio/aidl/default/bluetooth/StreamBluetooth.cpp
index 91a33c2..0cee7f4 100644
--- a/audio/aidl/default/bluetooth/StreamBluetooth.cpp
+++ b/audio/aidl/default/bluetooth/StreamBluetooth.cpp
@@ -20,52 +20,49 @@
#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::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;
-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)
: 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))) {
+ mBluetoothA2dp(std::move(std::get<ModuleBluetooth::BtInterface::BTA2DP>(btHandles))),
+ mBluetoothLe(std::move(std::get<ModuleBluetooth::BtInterface::BTLE>(btHandles))) {
mPreferredDataIntervalUs =
- mIsInput ? kBluetoothDefaultInputBufferMs : kBluetoothDefaultOutputBufferMs;
- mPreferredFrameCount = getFrameCount(mPreferredDataIntervalUs, mSampleRate);
+ (mIsInput ? kBluetoothDefaultInputBufferMs : kBluetoothDefaultOutputBufferMs) * 1000;
+ mPreferredFrameCount = frameCountFromDurationUs(mPreferredDataIntervalUs, mSampleRate);
mIsInitialized = false;
mIsReadyToClose = false;
}
@@ -226,7 +223,7 @@
if (config.dataIntervalUs > 0) {
mPreferredDataIntervalUs =
std::min((int32_t)mPreferredDataIntervalUs, config.dataIntervalUs);
- mPreferredFrameCount = getFrameCount(mPreferredDataIntervalUs, mSampleRate);
+ mPreferredFrameCount = frameCountFromDurationUs(mPreferredDataIntervalUs, mSampleRate);
}
return true;
}
@@ -318,7 +315,7 @@
StreamInBluetooth::StreamInBluetooth(StreamContext&& context, const SinkMetadata& sinkMetadata,
const std::vector<MicrophoneInfo>& microphones,
- Module::BtProfileHandles&& btProfileHandles)
+ ModuleBluetooth::BtProfileHandles&& btProfileHandles)
: StreamIn(std::move(context), microphones),
StreamBluetooth(&mContextInstance, sinkMetadata, std::move(btProfileHandles)) {}
@@ -331,7 +328,7 @@
StreamOutBluetooth::StreamOutBluetooth(StreamContext&& context,
const SourceMetadata& sourceMetadata,
const std::optional<AudioOffloadInfo>& offloadInfo,
- Module::BtProfileHandles&& btProfileHandles)
+ ModuleBluetooth::BtProfileHandles&& btProfileHandles)
: StreamOut(std::move(context), offloadInfo),
StreamBluetooth(&mContextInstance, sourceMetadata, std::move(btProfileHandles)) {}
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/dynamicProcessing/DynamicsProcessingSw.cpp b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp
index ed6cfa0..e8f90b2 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,
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..17a8cf3 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 {
@@ -239,4 +238,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..572b597 100644
--- a/audio/aidl/default/include/core-impl/Module.h
+++ b/audio/aidl/default/include/core-impl/Module.h
@@ -19,30 +19,42 @@
#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 +70,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 +140,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 +153,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 +168,7 @@
bool mMicMute = false;
bool mMasterMute = false;
float mMasterVolume = 1.0f;
- ChildInterface<sounddose::ISoundDose> mSoundDose;
+ ChildInterface<sounddose::SoundDose> mSoundDose;
std::optional<bool> mIsMmapSupported;
protected:
@@ -185,11 +196,25 @@
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);
+ int32_t powerOf2 = 1;
+ while (powerOf2 < rawSizeFrames) powerOf2 <<= 1;
+ return powerOf2;
+ }
+
ndk::ScopedAStatus bluetoothParametersUpdated();
void cleanUpPatch(int32_t patchId);
ndk::ScopedAStatus createStreamContext(
@@ -202,16 +227,19 @@
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();
+ 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 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);
diff --git a/audio/aidl/default/include/core-impl/ModuleAlsa.h b/audio/aidl/default/include/core-impl/ModuleAlsa.h
index 5815961..2774fe5 100644
--- a/audio/aidl/default/include/core-impl/ModuleAlsa.h
+++ b/audio/aidl/default/include/core-impl/ModuleAlsa.h
@@ -27,7 +27,8 @@
// 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'.
diff --git a/audio/aidl/default/include/core-impl/ModuleBluetooth.h b/audio/aidl/default/include/core-impl/ModuleBluetooth.h
index 68b4e6b..631b088 100644
--- a/audio/aidl/default/include/core-impl/ModuleBluetooth.h
+++ b/audio/aidl/default/include/core-impl/ModuleBluetooth.h
@@ -23,10 +23,17 @@
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;
+ 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;
@@ -44,11 +51,13 @@
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) override;
ndk::ScopedAStatus onMasterMuteChanged(bool mute) override;
ndk::ScopedAStatus onMasterVolumeChanged(float volume) override;
- ChildInterface<IBluetoothA2dp> mBluetoothA2dp;
- ChildInterface<IBluetoothLe> mBluetoothLe;
+ ChildInterface<BluetoothA2dp> mBluetoothA2dp;
+ ChildInterface<BluetoothLe> mBluetoothLe;
};
-} // 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..9f8acc9 100644
--- a/audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h
+++ b/audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h
@@ -22,7 +22,8 @@
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
@@ -49,6 +50,9 @@
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;
+ // TODO(b/307586684): Report proper minimum stream buffer size by overriding 'setAudioPatch'.
};
} // 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..6ee8f8a 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
diff --git a/audio/aidl/default/include/core-impl/SoundDose.h b/audio/aidl/default/include/core-impl/SoundDose.h
index 2a069d9..c0edc9f 100644
--- a/audio/aidl/default/include/core-impl/SoundDose.h
+++ b/audio/aidl/default/include/core-impl/SoundDose.h
@@ -20,11 +20,23 @@
#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>
namespace aidl::android::hardware::audio::core::sounddose {
+// Interface used for processing the data received by a stream.
+class StreamDataProcessorInterface {
+ public:
+ 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 : public BnSoundDose {
public:
SoundDose() : mRs2Value(DEFAULT_MAX_RS2){};
diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h
index 88fddec..aa9fb19 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()),
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..1258d38 100644
--- a/audio/aidl/default/include/core-impl/StreamBluetooth.h
+++ b/audio/aidl/default/include/core-impl/StreamBluetooth.h
@@ -24,7 +24,7 @@
#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 {
@@ -32,7 +32,7 @@
class StreamBluetooth : public StreamCommonImpl {
public:
StreamBluetooth(StreamContext* context, const Metadata& metadata,
- Module::BtProfileHandles&& btHandles);
+ ModuleBluetooth::BtProfileHandles&& btHandles);
// Methods of 'DriverInterface'.
::android::status_t init() override;
::android::status_t drain(StreamDescriptor::DrainMode) override;
@@ -80,7 +80,7 @@
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);
private:
void onClose(StreamDescriptor::State) override { defaultOnClose(); }
@@ -97,7 +97,7 @@
const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
offloadInfo,
- Module::BtProfileHandles&& btHandles);
+ ModuleBluetooth::BtProfileHandles&& btHandles);
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..145c3c4 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;
+ long 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..ee10abf 100644
--- a/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h
+++ b/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h
@@ -46,7 +46,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);
@@ -71,6 +71,10 @@
static constexpr int kMaxReadFailureAttempts = 3;
// 5ms between two read attempts when pipe is empty
static constexpr int kReadAttemptSleepUs = 5000;
+
+ long mStartTimeNs = 0;
+ long mFramesSinceStart = 0;
+ int mReadErrorCount = 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/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/NoiseSuppressionSw.cpp b/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.cpp
index 9b2cb7c..a3208df 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"}};
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..f3965ba 100644
--- a/audio/aidl/default/r_submix/ModuleRemoteSubmix.cpp
+++ b/audio/aidl/default/r_submix/ModuleRemoteSubmix.cpp
@@ -21,11 +21,13 @@
#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::AudioFormatType;
using aidl::android::media::audio::common::AudioOffloadInfo;
using aidl::android::media::audio::common::AudioPort;
using aidl::android::media::audio::common::AudioPortConfig;
@@ -46,6 +48,10 @@
ndk::ScopedAStatus ModuleRemoteSubmix::createInputStream(
StreamContext&& context, const SinkMetadata& sinkMetadata,
const std::vector<MicrophoneInfo>& microphones, std::shared_ptr<StreamIn>* result) {
+ if (context.getFormat().type != AudioFormatType::PCM) {
+ LOG(DEBUG) << __func__ << ": not supported for format " << context.getFormat().toString();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
return createStreamInstance<StreamInRemoteSubmix>(result, std::move(context), sinkMetadata,
microphones);
}
@@ -53,29 +59,32 @@
ndk::ScopedAStatus ModuleRemoteSubmix::createOutputStream(
StreamContext&& context, const SourceMetadata& sourceMetadata,
const std::optional<AudioOffloadInfo>& offloadInfo, std::shared_ptr<StreamOut>* result) {
+ if (context.getFormat().type != AudioFormatType::PCM) {
+ LOG(DEBUG) << __func__ << ": not supported for format " << context.getFormat().toString();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
return createStreamInstance<StreamOutRemoteSubmix>(result, std::move(context), sourceMetadata,
offloadInfo);
}
ndk::ScopedAStatus ModuleRemoteSubmix::populateConnectedDevicePort(AudioPort* audioPort) {
// Find the corresponding mix port and copy its profiles.
- std::vector<AudioRoute> routes;
// 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;
return ndk::ScopedAStatus::ok();
@@ -107,4 +116,12 @@
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;
+}
+
} // 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..d238aa4 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"
@@ -52,37 +53,31 @@
if (routeItr != sSubmixRoutes.end()) {
mCurrentRoute = routeItr->second;
}
- }
- // If route is not available for this port, add it.
- 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;
- }
- {
- 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";
+ // If route is not available for this port, add it.
+ 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;
}
+ sSubmixRoutes.emplace(mDeviceAddress, mCurrentRoute);
+ }
+ }
+ 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;
}
}
@@ -112,6 +107,8 @@
::android::status_t StreamRemoteSubmix::start() {
mCurrentRoute->exitStandby(mIsInput);
+ mStartTimeNs = ::android::uptimeNanos();
+ mFramesSinceStart = 0;
return ::android::OK;
}
@@ -133,6 +130,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);
@@ -158,30 +157,24 @@
::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 long 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,6 +195,10 @@
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;
@@ -215,12 +212,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 +221,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 +243,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 +264,65 @@
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;
}
+ 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 long 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) {
+ LOG(WARNING) << __func__ << ": read " << actuallyRead << " vs. requested " << frameCount;
}
-
- 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..235c9a3 100644
--- a/audio/aidl/default/r_submix/SubmixRoute.cpp
+++ b/audio/aidl/default/r_submix/SubmixRoute.cpp
@@ -81,11 +81,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 +98,9 @@
}
mStreamInStandby = true;
mReadCounterFrames = 0;
- mReadErrorCount = 0;
+ if (mSink != nullptr) {
+ mSink->shutdown(false);
+ }
} else {
mStreamOutOpen = true;
}
@@ -112,8 +109,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);
@@ -214,9 +210,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 {
diff --git a/audio/aidl/default/r_submix/SubmixRoute.h b/audio/aidl/default/r_submix/SubmixRoute.h
index 1a98df2..252b1c9 100644
--- a/audio/aidl/default/r_submix/SubmixRoute.h
+++ b/audio/aidl/default/r_submix/SubmixRoute.h
@@ -14,16 +14,18 @@
* limitations under the License.
*/
+#pragma once
+
#include <mutex>
+#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/AudioFormatDescription.h>
using aidl::android::media::audio::common::AudioChannelLayout;
using aidl::android::media::audio::common::AudioFormatDescription;
@@ -36,9 +38,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 {
@@ -76,14 +82,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;
@@ -119,9 +117,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/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/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/visualizer/VisualizerSw.cpp b/audio/aidl/default/visualizer/VisualizerSw.cpp
index 0909f25..285c102 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};
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..191f928 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,13 +21,15 @@
"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",
@@ -37,7 +40,10 @@
"general-tests",
"vts",
],
- srcs: [":effectCommonFile"],
+ srcs: [
+ ":effectCommonFile",
+ "TestUtils.cpp",
+ ],
}
cc_test {
@@ -80,6 +86,9 @@
name: "VtsHalDownmixTargetTest",
defaults: ["VtsHalAudioTargetTestDefaults"],
srcs: ["VtsHalDownmixTargetTest.cpp"],
+ shared_libs: [
+ "libaudioutils",
+ ],
}
cc_test {
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/EffectHelper.h b/audio/aidl/vts/EffectHelper.h
index 2c8edf2..d813554 100644
--- a/audio/aidl/vts/EffectHelper.h
+++ b/audio/aidl/vts/EffectHelper.h
@@ -283,4 +283,32 @@
}
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..39168b1 100644
--- a/audio/aidl/vts/VtsHalAECTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAECTargetTest.cpp
@@ -34,6 +34,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 +179,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..6066025 100644
--- a/audio/aidl/vts/VtsHalAGC1TargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAGC1TargetTest.cpp
@@ -28,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,
@@ -189,6 +190,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..8793e4c 100644
--- a/audio/aidl/vts/VtsHalAGC2TargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAGC2TargetTest.cpp
@@ -29,6 +29,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 +195,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..f91795b 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;
@@ -4036,174 +4593,164 @@
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*/));
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/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..aaf9ad4 100644
--- a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
@@ -51,6 +51,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 +596,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));
@@ -907,6 +914,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/VtsHalBassBoostTargetTest.cpp b/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp
index afddb84..2d9a233 100644
--- a/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp
@@ -32,7 +32,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 +155,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..d7db567 100644
--- a/audio/aidl/vts/VtsHalDownmixTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalDownmixTargetTest.cpp
@@ -18,88 +18,114 @@
#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;
-
-/**
- * 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>;
+using android::audio_utils::channels::ChannelMix;
+using android::hardware::audio::common::testing::detail::TestExecutionTracer;
// 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 +134,281 @@
return specific;
}
- private:
- std::vector<std::pair<Downmix::Tag, Downmix>> mTags;
- void CleanUp() { mTags.clear(); }
+ void setDataTestParams(int32_t layoutType) {
+ mInputBuffer.resize(kBufferSize);
+ mOutputBuffer.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;
+ }
+
+ // 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 (!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);
+ // Validate Right channel has audio
+ if (mInputBuffer[j] != 0) {
+ ASSERT_NE(mOutputBuffer[i + 1], 0);
+ } else {
+ // No change in output when input is 0
+ ASSERT_EQ(mOutputBuffer[i + 1], mInputBuffer[j]);
+ }
+ }
+ }
+
+ 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 (!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]);
+ }
+ for (size_t i = mOutputBufferSize; i < kBufferSize; i++) {
+ ASSERT_EQ(mOutputBuffer[i], mInputBuffer[i]);
+ }
+ }
+
+ 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(
@@ -134,8 +427,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..2650f49 100644
--- a/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp
+++ b/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp
@@ -36,6 +36,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 +997,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..474b361 100644
--- a/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp
@@ -28,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;
/**
* Here we focus on specific parameter checking, general IEffect interfaces testing performed in
@@ -536,6 +537,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..09396d1 100644
--- a/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp
@@ -46,6 +46,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 +221,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..5a32398 100644
--- a/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp
@@ -33,6 +33,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 +432,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..925f9ec 100644
--- a/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp
@@ -30,28 +30,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 +52,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 +69,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 +311,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..12d56b0 100644
--- a/audio/aidl/vts/VtsHalNSTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalNSTargetTest.cpp
@@ -32,6 +32,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 +172,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..57eda09 100644
--- a/audio/aidl/vts/VtsHalPresetReverbTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalPresetReverbTargetTest.cpp
@@ -29,6 +29,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 +148,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/VtsHalVirtualizerTargetTest.cpp b/audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp
index 07a9fa4..3e39d3a 100644
--- a/audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp
@@ -28,6 +28,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 +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/VtsHalVisualizerTargetTest.cpp b/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp
index 903ba69..1b8352b 100644
--- a/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp
@@ -31,6 +31,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 +208,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..257100b 100644
--- a/audio/aidl/vts/VtsHalVolumeTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalVolumeTargetTest.cpp
@@ -28,6 +28,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 +160,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/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/OWNERS
similarity index 98%
rename from authsecret/1.0/vts/functional/OWNERS
rename to authsecret/OWNERS
index ec8c304..5a5d074 100644
--- a/authsecret/1.0/vts/functional/OWNERS
+++ b/authsecret/OWNERS
@@ -1,3 +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/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/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/libnetdevice.cpp b/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
index aad07de..fe749f6 100644
--- a/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
+++ b/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
@@ -102,7 +102,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/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/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/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/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/aidl/aidl_test/Android.bp b/automotive/vehicle/aidl/aidl_test/Android.bp
index 44d7445..d752b2a 100644
--- a/automotive/vehicle/aidl/aidl_test/Android.bp
+++ b/automotive/vehicle/aidl/aidl_test/Android.bp
@@ -54,7 +54,7 @@
"android.hardware.automotive.vehicle-V2-java",
"android.hardware.automotive.vehicle.property-V2-java",
"androidx.test.runner",
- "truth-prebuilt",
+ "truth",
],
test_suites: ["general-tests"],
}
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..af1bb1d 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
@@ -99,12 +99,17 @@
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;
@@ -156,8 +161,6 @@
aidl::android::hardware::automotive::vehicle::SetValueRequest>
mPendingSetValueRequests;
- const std::string mDefaultConfigDir;
- const std::string mOverrideConfigDir;
const bool mForceOverride;
bool mAddExtraTestVendorConfigs;
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..250a226 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
@@ -39,7 +39,6 @@
#include <dirent.h>
#include <inttypes.h>
#include <sys/types.h>
-#include <fstream>
#include <regex>
#include <unordered_set>
#include <vector>
@@ -205,9 +204,10 @@
// 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 +240,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 +249,6 @@
[this](const VehiclePropValue& value) { eventFromVehicleBus(value); })),
mPendingGetValueRequests(this),
mPendingSetValueRequests(this),
- mDefaultConfigDir(defaultConfigDir),
- mOverrideConfigDir(overrideConfigDir),
mForceOverride(forceOverride) {
init();
}
@@ -259,11 +259,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;
@@ -938,7 +942,7 @@
<< StringPrintf("failed to get special value: %d, error: %s", value.prop,
getErrorMsg(result).c_str());
} else {
- return std::move(result);
+ return result;
}
}
@@ -953,7 +957,7 @@
}
}
- return std::move(readResult);
+ return readResult;
}
DumpResult FakeVehicleHardware::dump(const std::vector<std::string>& options) {
@@ -1330,9 +1334,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 +1346,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 +1386,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,
@@ -1453,8 +1457,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);
@@ -1525,12 +1530,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(
@@ -1839,8 +1844,9 @@
// 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,
+ .prop = propId,
+ .value = {},
});
if (!result.ok()) {
// Failed to read current value, skip refreshing.
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/utils/common/test/RecurrentTimerTest.cpp b/automotive/vehicle/aidl/impl/utils/common/test/RecurrentTimerTest.cpp
index 141efc1..62046f3 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;
});
}
@@ -54,6 +66,7 @@
}
private:
+ std::condition_variable mCond;
std::mutex mLock;
std::vector<size_t> mCallbacks GUARDED_BY(mLock);
};
@@ -66,12 +79,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 +104,11 @@
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);
}
TEST_F(RecurrentTimerTest, testDestroyTimerWithCallback) {
@@ -114,7 +127,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 +147,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 +171,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,10 +192,9 @@
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);
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/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/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..910ae7c 100644
--- a/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
+++ b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
@@ -888,8 +888,8 @@
}
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/face/aidl/default/Android.bp b/biometrics/face/aidl/default/Android.bp
index 876a91f..82ad917 100644
--- a/biometrics/face/aidl/default/Android.bp
+++ b/biometrics/face/aidl/default/Android.bp
@@ -7,11 +7,21 @@
default_applicable_licenses: ["hardware_interfaces_license"],
}
+filegroup {
+ name: "face-default.rc",
+ srcs: ["face-default.rc"],
+}
+
+filegroup {
+ name: "face-default.xml",
+ srcs: ["face-default.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-default.rc"],
+ vintf_fragments: [":face-default.xml"],
vendor: true,
shared_libs: [
"libbase",
diff --git a/biometrics/face/aidl/default/apex/Android.bp b/biometrics/face/aidl/default/apex/Android.bp
new file mode 100644
index 0000000..0ae1463
--- /dev/null
+++ b/biometrics/face/aidl/default/apex/Android.bp
@@ -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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+apex {
+ name: "com.android.hardware.biometrics.face",
+ 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-default-apex.rc",
+ // vintf_fragment
+ "face-default-apex.xml",
+ // permission
+ "android.hardware.biometrics.face.prebuilt.xml",
+ ],
+
+ overrides: [
+ "android.hardware.biometrics.face-service.example",
+ ],
+}
+
+prebuilt_etc {
+ name: "face-default-apex.rc",
+ src: ":gen-face-default-apex.rc",
+ vendor: true,
+ installable: false,
+}
+
+genrule {
+ name: "gen-face-default-apex.rc",
+ srcs: [":face-default.rc"],
+ out: ["face-default-apex.rc"],
+ cmd: "sed -e 's@/vendor/bin/@/apex/com.android.hardware.biometrics.face/bin/@' $(in) > $(out)",
+}
+
+prebuilt_etc {
+ name: "face-default-apex.xml",
+ src: ":face-default.xml",
+ sub_dir: "vintf",
+ vendor: true,
+ 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..4d46896
--- /dev/null
+++ b/biometrics/face/aidl/default/apex/manifest.json
@@ -0,0 +1,4 @@
+{
+ "name": "com.android.hardware.biometrics.face",
+ "version": 1
+}
diff --git a/biometrics/fingerprint/aidl/default/Android.bp b/biometrics/fingerprint/aidl/default/Android.bp
index 16302eb..a173a00 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",
+ "liblog",
+ ],
+ static_libs: [
+ "libandroid.hardware.biometrics.fingerprint.VirtualProps",
+ "libbase",
"android.hardware.biometrics.fingerprint-V3-ndk",
"android.hardware.biometrics.common-V3-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 {
@@ -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/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/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/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..1049d98
--- /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 minimum;
+ int maximum;
+ }
+ 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..baf0a4e
--- /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 = 0x0003;
+ const int SPATIAL_AUDIO = 0x0004;
+ const int PROVIDE_ASE_METADATA = 0x0005;
+ const int MONO_MIC_CONFIGURATION = 0x0006;
+}
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..f155634 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,154 @@
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);
+ List<android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioAseConfigurationSetting> getLeAudioAseConfiguration(in @nullable List<android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioDeviceCapabilities> remoteSinkAudioCapabilities, in @nullable List<android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioDeviceCapabilities> remoteSourceAudioCapabilities, in List<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 android.hardware.bluetooth.audio.AudioContext context, in android.hardware.bluetooth.audio.LeAudioConfiguration.StreamMap[] streamMap);
+ 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 List<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 context, in android.hardware.bluetooth.audio.LeAudioBroadcastConfiguration.BroadcastStreamMap[] streamMap);
+ @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 List<android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioAseConfigurationSetting.AseDirectionConfiguration> sinkAseConfiguration;
+ @nullable List<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 List<android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioConfigurationRequirement.AseDirectionRequirement> sinkAseRequirement;
+ @nullable List<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 contextType;
+ @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;
+ }
+ @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 context;
+ android.hardware.bluetooth.audio.IBluetoothAudioProvider.BroadcastQuality quality;
+ int bisNumPerSubgroup;
+ }
+ @VintfStability
+ parcelable LeAudioBroadcastConfigurationRequirement {
+ List<android.hardware.bluetooth.audio.IBluetoothAudioProvider.LeAudioBroadcastSubgroupConfigurationRequirement> subgroupConfigurationRequirements;
+ }
+ @VintfStability
+ parcelable LeAudioSubgroupBisConfiguration {
+ int numBis;
+ android.hardware.bluetooth.audio.LeAudioBisConfiguration bisConfiguration;
+ }
+ @VintfStability
+ parcelable LeAudioBroadcastSubgroupConfiguration {
+ List<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;
+ List<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..896a712
--- /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 - Assigned by BT Sig
+ * 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..33f0c04
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecInfo.aidl
@@ -0,0 +1,136 @@
+/*
+ * 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 and human readable name
+ */
+ CodecId id;
+ 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 {
+ /**
+ * Channel configuration: Mono, Dual-Mono or Stereo
+ */
+ ChannelMode[] channelMode;
+
+ /**
+ * Supported sampling frequencies, in Hz.
+ */
+ int[] samplingFrequencyHz;
+
+ /*
+ * FrameDuration 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..ceb90ba
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecSpecificCapabilitiesLtv.aidl
@@ -0,0 +1,80 @@
+/*
+ * 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 {
+ 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;
+ }
+ 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 minimum;
+ int maximum;
+ }
+ 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..57c8be5
--- /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 = 0x0003;
+ /*
+ * Set for the spatial audio configurations
+ */
+ const int SPATIAL_AUDIO = 0x0004;
+ /*
+ * When set, BluetoothAudioProvider requests to receive ASE metadata.
+ * In such case onSinkAseMetadataChanged() and onSourceAseMetadataChanged
+ * will be called.
+ */
+ const int PROVIDE_ASE_METADATA = 0x0005;
+ /*
+ * Set for mono microphone configurations
+ */
+ const int MONO_MIC_CONFIGURATION = 0x0006;
+
+ 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..2e16f4e 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,601 @@
* 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);
+
+ /**
+ * Set specific codec priority
+ *
+ * It should be assumed that the external module will start with all its
+ * integrated codecs priority 0 by default.
+ *
+ * @param codecId: codecId
+ * @param priority: 0 for no priority, -1 for codec disabled,
+ * from 1 to N, where 1 is highest.
+ */
+ 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 List<AseDirectionConfiguration> sinkAseConfiguration;
+ /**
+ * Source ASEs configuration
+ */
+ @nullable List<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 List<AseDirectionRequirement> sinkAseRequirement;
+ /**
+ * Source ASEs configuration setting
+ */
+ @nullable List<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.
+ *
+ * @param remoteSinkAudioCapabilities List of remote sink capabilities
+ * supported by an active group devices.
+ * @param remoteSourceAudioCapabilities List of remote source capabilities
+ * supported by an active group devices.
+ * @param requirements ASE configuration requirements
+ *
+ * @return List<LeAudioAseConfigurationSetting>
+ */
+ List<LeAudioAseConfigurationSetting> getLeAudioAseConfiguration(
+ in @nullable List<LeAudioDeviceCapabilities> remoteSinkAudioCapabilities,
+ in @nullable List<LeAudioDeviceCapabilities> remoteSourceAudioCapabilities,
+ in List<LeAudioConfigurationRequirement> requirements);
+
+ @VintfStability
+ parcelable LeAudioAseQosConfigurationRequirement {
+ /**
+ * Audio Contect Type that this requirements apply to
+ */
+ AudioContext contextType;
+
+ /**
+ * 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.
+ *
+ * @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;
+ }
+
+ /**
+ * 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.
+ */
+ LeAudioDataPathConfigurationPair getLeAudioAseDatapathConfiguration(
+ in AudioContext context, in StreamMap[] streamMap);
+
+ /*
+ * 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 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 ASE is using configurations marked with the
+ * `PROVIDE_ASE_METADATA` flag.
+ */
+ void onSinkAseMetadataChanged(
+ in AseState state, int cigId, int cisId, in @nullable MetadataLtv[] metadata);
+ 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 context;
+ /**
+ * 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 {
+ List<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 {
+ List<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;
+
+ /**
+ * A list of subgroup configurations in the broadcast.
+ */
+ List<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
+ *
+ */
+ LeAudioBroadcastConfigurationSetting getLeAudioBroadcastConfiguration(
+ in @nullable List<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.
+ */
+ LeAudioDataPathConfiguration getLeAudioBroadcastDatapathConfiguration(
+ in AudioContext context, 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..b0befc1
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/MetadataLtv.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.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 must not be interpreted by the BT stack.
+ */
+ parcelable VendorSpecific {
+ int companyId;
+ byte[] opaqueValue;
+ }
+
+ PreferredAudioContexts preferredAudioContexts;
+ StreamingAudioContexts streamingAudioContexts;
+ VendorSpecific vendorSpecific;
+}
diff --git a/staging/c2/aidl/android/hardware/media/c2/ParamField.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/Phy.aidl
similarity index 60%
copy from staging/c2/aidl/android/hardware/media/c2/ParamField.aidl
copy to bluetooth/audio/aidl/android/hardware/bluetooth/audio/Phy.aidl
index 94f737d..cbffdd5 100644
--- a/staging/c2/aidl/android/hardware/media/c2/ParamField.aidl
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/Phy.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * 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.
@@ -14,20 +14,16 @@
* limitations under the License.
*/
-package android.hardware.media.c2;
-
-import android.hardware.media.c2.FieldId;
+package android.hardware.bluetooth.audio;
/**
- * Reference to a field in a C2Param structure.
+ * Used to exchange generic Phy parameter between the stack and the provider.
*/
-parcelable ParamField {
- /**
- * Index of the C2Param structure.
- */
- int index;
- /**
- * Identifier of the field inside the C2Param structure.
- */
- FieldId fieldId;
+@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..f467c95
--- /dev/null
+++ b/bluetooth/audio/aidl/default/A2dpBits.h
@@ -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.
+ */
+
+#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()) {}
+
+ 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..bdba898 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,143 @@
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 ::aidl::android::hardware::bluetooth::audio::AudioContext& in_context,
+ const std::vector<::aidl::android::hardware::bluetooth::audio::
+ LeAudioConfiguration::StreamMap>& in_streamMap,
+ ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+ LeAudioDataPathConfigurationPair* _aidl_return) {
+ /* TODO: Implement */
+ (void)in_context;
+ (void)in_streamMap;
+ (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..5064869 100644
--- a/bluetooth/audio/aidl/default/BluetoothAudioProvider.h
+++ b/bluetooth/audio/aidl/default/BluetoothAudioProvider.h
@@ -41,14 +41,81 @@
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 ::aidl::android::hardware::bluetooth::audio::AudioContext&
+ in_context,
+ const std::vector<::aidl::android::hardware::bluetooth::audio::
+ LeAudioConfiguration::StreamMap>& in_streamMap,
+ ::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..cff3b25 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,644 @@
*_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 == -1)
+ 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.minimum &&
+ cfg_octets.value <= capability_octets.maximum;
+}
+
+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.contextType) 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..88f2f97 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,13 @@
static constexpr ChannelMode a2dp_channel_modes[] = {
ChannelMode::UNKNOWN, ChannelMode::MONO, ChannelMode::STEREO};
static std::vector<LatencyMode> latency_modes = {LatencyMode::FREE};
+
+// 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 +217,13 @@
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_);
+ ASSERT_TRUE(aidl_reval.isOk());
+ }
+
void GetProviderCapabilitiesHelper(const SessionType& session_type) {
temp_provider_capabilities_.clear();
auto aidl_retval = provider_factory_->getProviderCapabilities(
@@ -195,7 +238,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 +300,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 +341,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 +603,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()
@@ -573,6 +623,8 @@
SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
SessionType::A2DP_SOFTWARE_DECODING_DATAPATH,
SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH,
+ SessionType::HFP_SOFTWARE_ENCODING_DATAPATH,
+ SessionType::HFP_SOFTWARE_DECODING_DATAPATH,
};
};
@@ -598,6 +650,794 @@
}
/**
+ * 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::le_audio);
+ }
+ }
+}
+
+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());
+ }
+}
+
+/**
* openProvider A2DP_SOFTWARE_ENCODING_DATAPATH
*/
class BluetoothAudioProviderA2dpEncodingSoftwareAidl
@@ -656,6 +1496,137 @@
}
/**
+ * openProvider HFP_SOFTWARE_ENCODING_DATAPATH
+ */
+class BluetoothAudioProviderHfpSoftwareEncodingAidl
+ : public BluetoothAudioProviderFactoryAidl {
+ public:
+ virtual void SetUp() override {
+ BluetoothAudioProviderFactoryAidl::SetUp();
+ 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();
+ 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
@@ -908,6 +1879,62 @@
}
/**
+ * openProvider HFP_HARDWARE_OFFLOAD_DATAPATH
+ */
+class BluetoothAudioProviderHfpHardwareAidl
+ : public BluetoothAudioProviderFactoryAidl {
+ public:
+ virtual void SetUp() override {
+ BluetoothAudioProviderFactoryAidl::SetUp();
+ 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 +2155,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 +2183,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.minimum = 0;
+ octets.maximum = 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 +2393,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,6 +2414,101 @@
/**
* 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 (!IsOffloadOutputProviderInfoSupported()) {
+ return;
+ }
+
+ 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) {
+ 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) {
+ 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) {
+ IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement requirement;
+ std::vector<IBluetoothAudioProvider::LeAudioAseQosConfiguration>
+ QoSConfigurations;
+ for (auto bitmask : all_context_bitmasks) {
+ requirement.contextType = 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 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,
@@ -1437,6 +2662,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 +2693,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,7 +2701,38 @@
/**
* 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()) {
+ return;
+ }
+
+ 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,
@@ -1505,7 +2763,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
@@ -1623,6 +2881,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 +2909,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 +3006,60 @@
/**
* 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 (!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) {
+ 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,
@@ -2096,6 +3446,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 +3540,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/utils/Android.bp b/bluetooth/audio/utils/Android.bp
index 8cafb47..f5f8163 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,21 @@
"libbinder_ndk",
"libfmq",
"liblog",
- "android.hardware.bluetooth.audio-V3-ndk",
"libhidlbase",
"libxml2",
+ "libflatbuffers-cpp",
],
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 +89,7 @@
shared_libs: [
"libbase",
"libbinder_ndk",
- "android.hardware.bluetooth.audio-V3-ndk",
+ "android.hardware.bluetooth.audio-V4-ndk",
"libxml2",
],
test_suites: [
@@ -94,4 +107,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..216e169 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();
+ auto 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..3519ace 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
@@ -95,6 +95,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 +156,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 +278,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 +288,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 +304,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 +316,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 +451,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
@@ -588,15 +603,32 @@
<< " has NO session";
return std::vector<LatencyMode>();
}
- if (low_latency_allowed_) return latency_modes_;
- std::vector<LatencyMode> modes;
- for (LatencyMode mode : latency_modes_) {
- if (mode == LatencyMode::LOW_LATENCY)
- // ignore those low latency mode if Bluetooth stack doesn't allow
- continue;
- modes.push_back(mode);
+
+ 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);
+ }
}
- return modes;
+ return supported_latency_modes;
}
void BluetoothAudioSession::SetLatencyMode(const LatencyMode& latency_mode) {
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..b6df67e 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"
@@ -50,6 +55,123 @@
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;
+ if (config_codec_info_map_.count(config_name) == 0)
+ config_codec_info_map_[config_name] = CodecInfo();
+
+ // 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;
+
+ 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
+ std::set<std::string> encoding_config, decoding_config, broadcast_config;
+ for (auto& s : supported_scenarios_) {
+ if (s.hasEncode()) encoding_config.insert(s.getEncode());
+ if (s.hasDecode()) decoding_config.insert(s.getDecode());
+ if (s.hasBroadcast()) 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 +180,8 @@
return leAudioCodecCapabilities;
}
+ isInvalidFileContent = true;
+
if (!le_audio_offload_setting.has_value()) {
LOG(ERROR)
<< __func__
@@ -65,40 +189,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 +206,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 +290,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 +389,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 +472,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 +497,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..e606d2d
--- /dev/null
+++ b/bluetooth/finder/aidl/Android.bp
@@ -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 {
+ 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,
+ platform_apis: true,
+ },
+ },
+}
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..ae9b159
--- /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;
+
+/**
+ * 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..615739b
--- /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 the 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/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/staging/threadnetwork/aidl/vts/Android.bp b/bluetooth/ranging/aidl/Android.bp
similarity index 64%
copy from staging/threadnetwork/aidl/vts/Android.bp
copy to bluetooth/ranging/aidl/Android.bp
index e2609ed..9e53ef6 100644
--- a/staging/threadnetwork/aidl/vts/Android.bp
+++ b/bluetooth/ranging/aidl/Android.bp
@@ -1,5 +1,4 @@
-//
-// 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.
@@ -12,7 +11,6 @@
// WITHOUT WARRANTIES 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
@@ -23,25 +21,19 @@
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",
- ],
+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..e7fad4d
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ChannelSoudingRawData.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;
+@VintfStability
+parcelable ChannelSoudingRawData {
+ int procedureCounter;
+ 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..9fe85da
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/ChannelSoundingSingleSideData.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;
+@VintfStability
+parcelable ChannelSoundingSingleSideData {
+ @nullable List<android.hardware.bluetooth.ranging.StepTonePct> stepTonePcts;
+ @nullable byte[] packetQuality;
+ @nullable byte[] packetRssiDbm;
+ @nullable android.hardware.bluetooth.ranging.Nadm[] packetNadm;
+ @nullable List<android.hardware.bluetooth.ranging.ComplexNumber> packetPct1;
+ @nullable List<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..75cdabc
--- /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="int") @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..a51ba37
--- /dev/null
+++ b/bluetooth/ranging/aidl/aidl_api/android.hardware.bluetooth.ranging/current/android/hardware/bluetooth/ranging/StepTonePct.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;
+@VintfStability
+parcelable StepTonePct {
+ List<android.hardware.bluetooth.ranging.ComplexNumber> tonePcts;
+ byte[] toneQualityIndicator;
+ 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;
+}
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..f660c91
--- /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="int") @VintfStability
+enum SubModeType {
+ ONE = 0x01,
+ TWO = 0x02,
+ THREE = 0x03,
+ UNUSED = 0xff,
+}
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..bd03213
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/AddressType.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 AddressType {
+ PUBLIC = 0x00,
+ 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..3c8a62f
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ChannelSoudingRawData.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.ChannelSoundingSingleSideData;
+import android.hardware.bluetooth.ranging.ModeType;
+
+/**
+ * Raw ranging data of Channel Sounding.
+ */
+@VintfStability
+parcelable ChannelSoudingRawData {
+ /**
+ * Procedure counter of the CS procedure.
+ */
+ int procedureCounter;
+ /**
+ * 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..2c3f201
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/ChannelSoundingSingleSideData.aidl
@@ -0,0 +1,58 @@
+/*
+ * 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
+ */
+@VintfStability
+parcelable ChannelSoundingSingleSideData {
+ /**
+ * PCT (complex value) measured from mode-2 or mode-3 steps in a CS procedure (in time order).
+ */
+ @nullable List<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;
+ /**
+ * Packet_PCT1 or packet_PCT2 of mode-1 or mode-3, if sounding sequence is used and sounding
+ * phase-based ranging is supported.
+ */
+ @nullable List<ComplexNumber> packetPct1;
+ @nullable List<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/staging/c2/aidl/android/hardware/media/c2/ParamField.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/DeviceAddress.aidl
similarity index 60%
copy from staging/c2/aidl/android/hardware/media/c2/ParamField.aidl
copy to bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/DeviceAddress.aidl
index 94f737d..c847c30 100644
--- a/staging/c2/aidl/android/hardware/media/c2/ParamField.aidl
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/DeviceAddress.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * 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.
@@ -14,20 +14,15 @@
* limitations under the License.
*/
-package android.hardware.media.c2;
+package android.hardware.bluetooth.ranging;
-import android.hardware.media.c2.FieldId;
+import android.hardware.bluetooth.ranging.AddressType;
/**
- * Reference to a field in a C2Param structure.
+ * Bluetooth address with address type
*/
-parcelable ParamField {
- /**
- * Index of the C2Param structure.
- */
- int index;
- /**
- * Identifier of the field inside the C2Param structure.
- */
- FieldId fieldId;
+@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..2058ae8
--- /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="int")
+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..3cfb22f
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/Nadm.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="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,
+ 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/staging/c2/aidl/android/hardware/media/c2/ParamField.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/SessionType.aidl
similarity index 62%
copy from staging/c2/aidl/android/hardware/media/c2/ParamField.aidl
copy to bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/SessionType.aidl
index 94f737d..4f0d529 100644
--- a/staging/c2/aidl/android/hardware/media/c2/ParamField.aidl
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/SessionType.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * 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.
@@ -14,20 +14,17 @@
* limitations under the License.
*/
-package android.hardware.media.c2;
+package android.hardware.bluetooth.ranging;
-import android.hardware.media.c2.FieldId;
-
-/**
- * Reference to a field in a C2Param structure.
- */
-parcelable ParamField {
+@VintfStability
+@Backing(type="int")
+enum SessionType {
/**
- * Index of the C2Param structure.
+ * Stack parses raw data and passes it to the HAL
*/
- int index;
+ SOFTWARE_STACK_DATA_PARSING = 0,
/**
- * Identifier of the field inside the C2Param structure.
+ * Offloader parses raw data
*/
- FieldId fieldId;
+ 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..99c6d65
--- /dev/null
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/StepTonePct.aidl
@@ -0,0 +1,55 @@
+/*
+ * 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 {
+ 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;
+}
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..ca9bfcb
--- /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="int")
+enum SubModeType {
+ ONE = 0x01,
+ TWO = 0x02,
+ THREE = 0x03,
+ UNUSED = 0xff,
+}
diff --git a/staging/c2/aidl/android/hardware/media/c2/ParamField.aidl b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/VendorSpecificData.aidl
similarity index 60%
copy from staging/c2/aidl/android/hardware/media/c2/ParamField.aidl
copy to bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/VendorSpecificData.aidl
index 94f737d..a8c9a2a 100644
--- a/staging/c2/aidl/android/hardware/media/c2/ParamField.aidl
+++ b/bluetooth/ranging/aidl/android/hardware/bluetooth/ranging/VendorSpecificData.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * 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.
@@ -14,20 +14,13 @@
* limitations under the License.
*/
-package android.hardware.media.c2;
-
-import android.hardware.media.c2.FieldId;
+package android.hardware.bluetooth.ranging;
/**
- * Reference to a field in a C2Param structure.
+ * Vendor specific data for GATT.
*/
-parcelable ParamField {
- /**
- * Index of the C2Param structure.
- */
- int index;
- /**
- * Identifier of the field inside the C2Param structure.
- */
- FieldId fieldId;
+@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.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/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/1.1/vts/OWNERS b/broadcastradio/OWNERS
similarity index 80%
rename from broadcastradio/1.1/vts/OWNERS
rename to broadcastradio/OWNERS
index aa19d6a..7c6aaca 100644
--- a/broadcastradio/1.1/vts/OWNERS
+++ b/broadcastradio/OWNERS
@@ -1,5 +1,5 @@
# Bug component: 533946
-xuweilin@google.com
-oscarazu@google.com
+
ericjeong@google.com
-keunyoung@google.com
+oscarazu@google.com
+xuweilin@google.com
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/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/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/device/default/ExternalCameraDeviceSession.cpp b/camera/device/default/ExternalCameraDeviceSession.cpp
index c962974..88e4b75 100644
--- a/camera/device/default/ExternalCameraDeviceSession.cpp
+++ b/camera/device/default/ExternalCameraDeviceSession.cpp
@@ -786,9 +786,8 @@
outputBuffer.bufferId = buffer.bufferId;
outputBuffer.status = BufferStatus::ERROR;
if (buffer.acquireFence >= 0) {
- native_handle_t* handle = native_handle_create(/*numFds*/ 1, /*numInts*/ 0);
- handle->data[0] = buffer.acquireFence;
- outputBuffer.releaseFence = android::makeToAidl(handle);
+ outputBuffer.releaseFence.fds.resize(1);
+ outputBuffer.releaseFence.fds.at(0).set(buffer.acquireFence);
}
} else {
offlineBuffers.push_back(buffer);
@@ -1769,9 +1768,8 @@
result.outputBuffers[i].bufferId = req->buffers[i].bufferId;
result.outputBuffers[i].status = BufferStatus::ERROR;
if (req->buffers[i].acquireFence >= 0) {
- native_handle_t* handle = native_handle_create(/*numFds*/ 1, /*numInts*/ 0);
- handle->data[0] = req->buffers[i].acquireFence;
- result.outputBuffers[i].releaseFence = ::android::makeToAidl(handle);
+ result.outputBuffers[i].releaseFence.fds.resize(1);
+ result.outputBuffers[i].releaseFence.fds.at(0).set(req->buffers[i].acquireFence);
}
}
@@ -1815,18 +1813,16 @@
if (req->buffers[i].fenceTimeout) {
result.outputBuffers[i].status = BufferStatus::ERROR;
if (req->buffers[i].acquireFence >= 0) {
- native_handle_t* handle = native_handle_create(/*numFds*/ 1, /*numInts*/ 0);
- handle->data[0] = req->buffers[i].acquireFence;
- result.outputBuffers[i].releaseFence = ::android::makeToAidl(handle);
+ result.outputBuffers[i].releaseFence.fds.resize(1);
+ result.outputBuffers[i].releaseFence.fds.at(0).set(req->buffers[i].acquireFence);
}
notifyError(req->frameNumber, req->buffers[i].streamId, ErrorCode::ERROR_BUFFER);
} else {
result.outputBuffers[i].status = BufferStatus::OK;
// TODO: refactor
if (req->buffers[i].acquireFence >= 0) {
- native_handle_t* handle = native_handle_create(/*numFds*/ 1, /*numInts*/ 0);
- handle->data[0] = req->buffers[i].acquireFence;
- result.outputBuffers[i].releaseFence = ::android::makeToAidl(handle);
+ result.outputBuffers[i].releaseFence.fds.resize(1);
+ result.outputBuffers[i].releaseFence.fds.at(0).set(req->buffers[i].acquireFence);
}
}
}
diff --git a/camera/device/default/ExternalCameraUtils.cpp b/camera/device/default/ExternalCameraUtils.cpp
index cfb95f2..30c216f 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;
}
@@ -857,4 +860,4 @@
} // namespace device
} // namespace camera
} // namespace hardware
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp b/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp
index 4fc7437..04db7f3 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,
diff --git a/camera/provider/2.4/default/LegacyCameraProviderImpl_2_4.cpp b/camera/provider/2.4/default/LegacyCameraProviderImpl_2_4.cpp
index 7c3b982..69318c7 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;
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..62ce074 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) {
diff --git a/camera/provider/aidl/vts/Android.bp b/camera/provider/aidl/vts/Android.bp
index 8429b21..59f6c66 100644
--- a/camera/provider/aidl/vts/Android.bp
+++ b/camera/provider/aidl/vts/Android.bp
@@ -68,6 +68,16 @@
"libgralloctypes",
"libaidlcommonsupport",
],
+
+ 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..b6b5206 100644
--- a/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
+++ b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
@@ -242,6 +242,7 @@
verifyCameraCharacteristics(chars);
verifyMonochromeCharacteristics(chars);
verifyRecommendedConfigs(chars);
+ verifyHighSpeedRecordingCharacteristics(name, chars);
verifyLogicalOrUltraHighResCameraMetadata(name, device, chars, cameraDeviceNames);
ASSERT_TRUE(ret.isOk());
diff --git a/camera/provider/aidl/vts/camera_aidl_test.cpp b/camera/provider/aidl/vts/camera_aidl_test.cpp
index 5f9d605..6a17453 100644
--- a/camera/provider/aidl/vts/camera_aidl_test.cpp
+++ b/camera/provider/aidl/vts/camera_aidl_test.cpp
@@ -831,6 +831,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,
diff --git a/camera/provider/aidl/vts/camera_aidl_test.h b/camera/provider/aidl/vts/camera_aidl_test.h
index 6f8f380..3018d5a 100644
--- a/camera/provider/aidl/vts/camera_aidl_test.h
+++ b/camera/provider/aidl/vts/camera_aidl_test.h
@@ -253,6 +253,9 @@
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);
@@ -610,6 +613,8 @@
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 kMaxVideoWidth = 4096;
const int32_t kMaxVideoHeight = 2160;
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..9bee3b9 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.9.xml",
+ stem: "compatibility_matrix.9.xml",
+ srcs: [
+ "compatibility_matrix.9.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..c2ffb84 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.9.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.4.xml b/compatibility_matrices/compatibility_matrix.4.xml
index b9fb3f4..bb7637a 100644
--- a/compatibility_matrices/compatibility_matrix.4.xml
+++ b/compatibility_matrices/compatibility_matrix.4.xml
@@ -281,9 +281,15 @@
<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">
<name>android.hardware.media.omx</name>
@@ -361,6 +367,7 @@
<interface>
<name>ISap</name>
<instance>slot1</instance>
+ <instance>slot2</instance>
</interface>
</hal>
<hal format="hidl" optional="true">
diff --git a/compatibility_matrices/compatibility_matrix.5.xml b/compatibility_matrices/compatibility_matrix.5.xml
index b374c8c..dad1558 100644
--- a/compatibility_matrices/compatibility_matrix.5.xml
+++ b/compatibility_matrices/compatibility_matrix.5.xml
@@ -319,11 +319,21 @@
<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">
+ <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" optional="true">
<name>android.hardware.media.omx</name>
<version>1.0</version>
<interface>
@@ -399,6 +409,7 @@
<interface>
<name>ISap</name>
<instance>slot1</instance>
+ <instance>slot2</instance>
</interface>
</hal>
<hal format="hidl" optional="true">
diff --git a/compatibility_matrices/compatibility_matrix.6.xml b/compatibility_matrices/compatibility_matrix.6.xml
index 40ae655..23f634d 100644
--- a/compatibility_matrices/compatibility_matrix.6.xml
+++ b/compatibility_matrices/compatibility_matrix.6.xml
@@ -368,11 +368,21 @@
<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">
+ <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" optional="true">
<name>android.hardware.media.omx</name>
<version>1.0</version>
<interface>
@@ -454,6 +464,7 @@
<interface>
<name>ISap</name>
<instance>slot1</instance>
+ <instance>slot2</instance>
</interface>
</hal>
<hal format="hidl" optional="true">
diff --git a/compatibility_matrices/compatibility_matrix.7.xml b/compatibility_matrices/compatibility_matrix.7.xml
index bc5a5c4..fe424bd 100644
--- a/compatibility_matrices/compatibility_matrix.7.xml
+++ b/compatibility_matrices/compatibility_matrix.7.xml
@@ -43,6 +43,7 @@
</hal>
<hal format="aidl" optional="true">
<name>android.hardware.automotive.audiocontrol</name>
+ <version>1-2</version>
<interface>
<name>IAudioControl</name>
<instance>default</instance>
@@ -262,22 +263,6 @@
<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">
<name>android.hardware.graphics.allocator</name>
<!-- New, non-Go devices should use 4.0 or the AIDL hal. -->
@@ -430,11 +415,21 @@
<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">
+ <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" optional="true">
<name>android.hardware.media.omx</name>
<version>1.0</version>
<interface>
@@ -582,6 +577,7 @@
<interface>
<name>ISap</name>
<instance>slot1</instance>
+ <instance>slot2</instance>
</interface>
</hal>
<hal format="hidl" optional="true">
diff --git a/compatibility_matrices/compatibility_matrix.8.xml b/compatibility_matrices/compatibility_matrix.8.xml
index 5ea075a..9057788 100644
--- a/compatibility_matrices/compatibility_matrix.8.xml
+++ b/compatibility_matrices/compatibility_matrix.8.xml
@@ -52,7 +52,7 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="aidl" optional="true">
+ <hal format="aidl" optional="true" updatable-via-apex="true">
<name>android.hardware.authsecret</name>
<version>1</version>
<interface>
@@ -114,15 +114,16 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="aidl" optional="true">
+ <hal format="aidl" optional="true" updatable-via-apex="true">
<name>android.hardware.biometrics.face</name>
<version>3</version>
<interface>
<name>IFace</name>
<instance>default</instance>
+ <instance>virtual</instance>
</interface>
</hal>
- <hal format="aidl" optional="true">
+ <hal format="aidl" optional="true" updatable-via-apex="true">
<name>android.hardware.biometrics.fingerprint</name>
<version>3</version>
<interface>
@@ -231,22 +232,6 @@
</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>
@@ -329,7 +314,7 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="aidl" optional="true">
+ <hal format="aidl" optional="true" 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" optional="true" updatable-via-apex="true">
<name>android.hardware.security.keymint</name>
<version>1-3</version>
<interface>
@@ -361,11 +346,21 @@
<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">
+ <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" optional="true">
<name>android.hardware.media.omx</name>
<version>1.0</version>
<interface>
@@ -385,7 +380,7 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="aidl" optional="true">
+ <hal format="aidl" optional="true" updatable-via-apex="true">
<name>android.hardware.neuralnetworks</name>
<version>1-4</version>
<interface>
@@ -393,7 +388,7 @@
<regex-instance>.*</regex-instance>
</interface>
</hal>
- <hal format="aidl" optional="true">
+ <hal format="aidl" optional="true" updatable-via-apex="true">
<name>android.hardware.nfc</name>
<interface>
<name>INfc</name>
@@ -537,7 +532,7 @@
<regex-instance>SIM[1-9][0-9]*</regex-instance>
</interface>
</hal>
- <hal format="aidl" optional="true">
+ <hal format="aidl" optional="true" 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" optional="true" updatable-via-apex="true">
<name>android.hardware.security.sharedsecret</name>
<version>1</version>
<interface>
@@ -697,7 +692,7 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="aidl" optional="true">
+ <hal format="aidl" optional="true" updatable-via-apex="true">
<name>android.hardware.uwb</name>
<version>1</version>
<interface>
diff --git a/compatibility_matrices/compatibility_matrix.9.xml b/compatibility_matrices/compatibility_matrix.9.xml
index 188746d..831cebb 100644
--- a/compatibility_matrices/compatibility_matrix.9.xml
+++ b/compatibility_matrices/compatibility_matrix.9.xml
@@ -1,4 +1,3 @@
-<!-- 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>
@@ -20,7 +19,7 @@
</hal>
<hal format="aidl" optional="true">
<name>android.hardware.audio.core</name>
- <version>1</version>
+ <version>1-2</version>
<interface>
<name>IModule</name>
<instance>default</instance>
@@ -39,7 +38,7 @@
</hal>
<hal format="aidl" optional="true">
<name>android.hardware.audio.effect</name>
- <version>1</version>
+ <version>1-2</version>
<interface>
<name>IFactory</name>
<instance>default</instance>
@@ -47,13 +46,13 @@
</hal>
<hal format="aidl" optional="true">
<name>android.hardware.audio.sounddose</name>
- <version>1</version>
+ <version>1-2</version>
<interface>
<name>ISoundDoseFactory</name>
<instance>default</instance>
</interface>
</hal>
- <hal format="aidl" optional="true">
+ <hal format="aidl" optional="true" updatable-via-apex="true">
<name>android.hardware.authsecret</name>
<version>1</version>
<interface>
@@ -63,7 +62,7 @@
</hal>
<hal format="aidl" optional="true">
<name>android.hardware.automotive.audiocontrol</name>
- <version>2-3</version>
+ <version>2-4</version>
<interface>
<name>IAudioControl</name>
<instance>default</instance>
@@ -115,7 +114,7 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="aidl" optional="true">
+ <hal format="aidl" optional="true" updatable-via-apex="true">
<name>android.hardware.biometrics.face</name>
<version>3</version>
<interface>
@@ -123,7 +122,7 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="aidl" optional="true">
+ <hal format="aidl" optional="true" updatable-via-apex="true">
<name>android.hardware.biometrics.fingerprint</name>
<version>3</version>
<interface>
@@ -132,14 +131,6 @@
<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>
@@ -149,13 +140,29 @@
</hal>
<hal format="aidl" optional="true">
<name>android.hardware.bluetooth.audio</name>
- <version>3</version>
+ <version>3-4</version>
<interface>
<name>IBluetoothAudioProviderFactory</name>
<instance>default</instance>
</interface>
</hal>
<hal format="aidl" optional="true">
+ <name>android.hardware.bluetooth.ranging</name>
+ <version>1</version>
+ <interface>
+ <name>IBluetoothChannelSounding</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+ <hal format="aidl" optional="true">
+ <name>android.hardware.bluetooth.finder</name>
+ <version>1</version>
+ <interface>
+ <name>IBluetoothFinder</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+ <hal format="aidl" optional="true">
<name>android.hardware.boot</name>
<interface>
<name>IBootControl</name>
@@ -232,22 +239,6 @@
</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>
@@ -266,9 +257,6 @@
<!-- 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>
@@ -277,7 +265,7 @@
</hal>
<hal format="aidl" optional="true">
<name>android.hardware.health</name>
- <version>1-2</version>
+ <version>3</version>
<interface>
<name>IHealth</name>
<instance>default</instance>
@@ -331,6 +319,14 @@
</interface>
</hal>
<hal format="aidl" optional="true">
+ <name>android.hardware.security.secretkeeper</name>
+ <version>1</version>
+ <interface>
+ <name>ISecretkeeper</name>
+ <instance>nonsecure</instance>
+ </interface>
+ </hal>
+ <hal format="aidl" optional="true" updatable-via-apex="true">
<name>android.hardware.security.keymint</name>
<version>1-3</version>
<interface>
@@ -339,7 +335,7 @@
<instance>strongbox</instance>
</interface>
</hal>
- <hal format="aidl" optional="true">
+ <hal format="aidl" optional="true" updatable-via-apex="true">
<name>android.hardware.security.keymint</name>
<version>1-3</version>
<interface>
@@ -361,6 +357,25 @@
<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">
+ <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" optional="true">
+ <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>
@@ -373,7 +388,7 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="aidl" optional="true">
+ <hal format="aidl" optional="true" updatable-via-apex="true">
<name>android.hardware.neuralnetworks</name>
<version>1-4</version>
<interface>
@@ -381,7 +396,7 @@
<regex-instance>.*</regex-instance>
</interface>
</hal>
- <hal format="aidl" optional="true">
+ <hal format="aidl" optional="true" updatable-via-apex="true">
<name>android.hardware.nfc</name>
<interface>
<name>INfc</name>
@@ -493,16 +508,6 @@
</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>
@@ -510,14 +515,6 @@
<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>
@@ -535,7 +532,15 @@
<regex-instance>SIM[1-9][0-9]*</regex-instance>
</interface>
</hal>
- <hal format="aidl" optional="true">
+ <hal format="aidl" optional="true" 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" optional="true" updatable-via-apex="true">
<name>android.hardware.security.secureclock</name>
<version>1</version>
<interface>
@@ -543,7 +548,7 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="aidl" optional="true">
+ <hal format="aidl" optional="true" updatable-via-apex="true">
<name>android.hardware.security.sharedsecret</name>
<version>1</version>
<interface>
@@ -560,38 +565,14 @@
<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>
+ <version>1-2</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>
@@ -608,6 +589,22 @@
<instance>default</instance>
</interface>
</hal>
+ <hal format="aidl" optional="true" 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" optional="true">
+ <name>android.hardware.threadnetwork</name>
+ <version>1</version>
+ <interface>
+ <name>IThreadChip</name>
+ <instance>chip0</instance>
+ </interface>
+ </hal>
<hal format="aidl" optional="true">
<name>android.hardware.tv.hdmi.cec</name>
<version>1</version>
@@ -695,7 +692,7 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="aidl" optional="true">
+ <hal format="aidl" optional="true" updatable-via-apex="true">
<name>android.hardware.uwb</name>
<version>1</version>
<interface>
diff --git a/compatibility_matrices/exclude/fcm_exclude.cpp b/compatibility_matrices/exclude/fcm_exclude.cpp
index 3bc1786..2cb4ffa 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,70 @@
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@",
+
+ // 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/OWNERS
similarity index 97%
rename from configstore/1.0/vts/functional/OWNERS
rename to configstore/OWNERS
index edfa1b0..70ad434 100644
--- a/configstore/1.0/vts/functional/OWNERS
+++ b/configstore/OWNERS
@@ -1,2 +1,3 @@
# Bug component: 24939
+
lpy@google.com
diff --git a/contexthub/aidl/Android.bp b/contexthub/aidl/Android.bp
index 814bf3b..a0315d0 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: [
{
diff --git a/contexthub/aidl/default/Android.bp b/contexthub/aidl/default/Android.bp
index 6ee7407..d293e30 100644
--- a/contexthub/aidl/default/Android.bp
+++ b/contexthub/aidl/default/Android.bp
@@ -57,3 +57,34 @@
],
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/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/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.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/1.3/vts/OWNERS b/drm/OWNERS
similarity index 62%
rename from drm/1.3/vts/OWNERS
rename to drm/OWNERS
index 3a0672e..c06472a 100644
--- a/drm/1.3/vts/OWNERS
+++ b/drm/OWNERS
@@ -1,9 +1,12 @@
+# Bug component: 49079
+
conglin@google.com
-edwinwong@google.com
fredgc@google.com
-jtinker@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
index fe69725..e69de29 100644
--- a/drm/aidl/OWNERS
+++ b/drm/aidl/OWNERS
@@ -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
index fe69725..e69de29 100644
--- a/drm/aidl/vts/OWNERS
+++ b/drm/aidl/vts/OWNERS
@@ -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/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/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/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/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/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/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/1.1/vts/OWNERS b/gnss/OWNERS
similarity index 68%
rename from gnss/1.1/vts/OWNERS
rename to gnss/OWNERS
index 3ed36da..57982e7 100644
--- a/gnss/1.1/vts/OWNERS
+++ b/gnss/OWNERS
@@ -1,7 +1,8 @@
-wyattriley@google.com
+# Bug component: 393449
+
gomo@google.com
smalkos@google.com
-yuhany@google.com
-
-# VTS team
+trong@google.com
+wyattriley@google.com
yim@google.com
+yuhany@google.com
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/default/Android.bp b/gnss/aidl/default/Android.bp
index ca5a41f..7310922 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",
@@ -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/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/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/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/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/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/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
index e4a84e1..03d9041 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";
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/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/aidl/OWNERS b/health/OWNERS
similarity index 98%
rename from health/aidl/OWNERS
rename to health/OWNERS
index 0f1bee2..1d4d086 100644
--- a/health/aidl/OWNERS
+++ b/health/OWNERS
@@ -1,5 +1,6 @@
# Bug component: 30545
+
+apelosi@google.com
elsk@google.com
smoreland@google.com
wjack@google.com
-apelosi@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/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..b2c0f0a 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();
}
@@ -272,7 +290,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
}
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/OWNERS
similarity index 79%
rename from health/storage/1.0/vts/functional/OWNERS
rename to health/storage/OWNERS
index 8f66979..7af8d99 100644
--- a/health/storage/1.0/vts/functional/OWNERS
+++ b/health/storage/OWNERS
@@ -1,3 +1,6 @@
# Bug component: 30545
-elsk@google.com
+
+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/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/aidl_api/android.hardware.light/2/.hash b/light/aidl/aidl_api/android.hardware.light/2/.hash
index d27f4ad..2d4e7f0 100644
--- a/light/aidl/aidl_api/android.hardware.light/2/.hash
+++ b/light/aidl/aidl_api/android.hardware.light/2/.hash
@@ -1 +1,2 @@
c8b1e8ebb88c57dcb2c350a8d9b722e77dd864c8
+c7d3d941d303c70d1c22759a0b09e41930c1cddb
diff --git a/light/aidl/aidl_api/android.hardware.light/2/android/hardware/light/HwLight.aidl b/light/aidl/aidl_api/android.hardware.light/2/android/hardware/light/HwLight.aidl
index 25a2dce..5ac2a34 100644
--- a/light/aidl/aidl_api/android.hardware.light/2/android/hardware/light/HwLight.aidl
+++ b/light/aidl/aidl_api/android.hardware.light/2/android/hardware/light/HwLight.aidl
@@ -32,7 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.light;
-@VintfStability
+@RustDerive(Clone=true, Copy=true) @VintfStability
parcelable HwLight {
int id;
int ordinal;
diff --git a/light/aidl/aidl_api/android.hardware.light/2/android/hardware/light/HwLightState.aidl b/light/aidl/aidl_api/android.hardware.light/2/android/hardware/light/HwLightState.aidl
index 40e520b..2878ce2 100644
--- a/light/aidl/aidl_api/android.hardware.light/2/android/hardware/light/HwLightState.aidl
+++ b/light/aidl/aidl_api/android.hardware.light/2/android/hardware/light/HwLightState.aidl
@@ -32,7 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.light;
-@VintfStability
+@RustDerive(Clone=true, Copy=true) @VintfStability
parcelable HwLightState {
int color;
android.hardware.light.FlashMode flashMode;
diff --git a/light/aidl/aidl_api/android.hardware.light/current/android/hardware/light/HwLight.aidl b/light/aidl/aidl_api/android.hardware.light/current/android/hardware/light/HwLight.aidl
index 25a2dce..5ac2a34 100644
--- a/light/aidl/aidl_api/android.hardware.light/current/android/hardware/light/HwLight.aidl
+++ b/light/aidl/aidl_api/android.hardware.light/current/android/hardware/light/HwLight.aidl
@@ -32,7 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.light;
-@VintfStability
+@RustDerive(Clone=true, Copy=true) @VintfStability
parcelable HwLight {
int id;
int ordinal;
diff --git a/light/aidl/aidl_api/android.hardware.light/current/android/hardware/light/HwLightState.aidl b/light/aidl/aidl_api/android.hardware.light/current/android/hardware/light/HwLightState.aidl
index 40e520b..2878ce2 100644
--- a/light/aidl/aidl_api/android.hardware.light/current/android/hardware/light/HwLightState.aidl
+++ b/light/aidl/aidl_api/android.hardware.light/current/android/hardware/light/HwLightState.aidl
@@ -32,7 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.light;
-@VintfStability
+@RustDerive(Clone=true, Copy=true) @VintfStability
parcelable HwLightState {
int color;
android.hardware.light.FlashMode flashMode;
diff --git a/light/aidl/android/hardware/light/HwLight.aidl b/light/aidl/android/hardware/light/HwLight.aidl
index 43fdb4b..8db32cc 100644
--- a/light/aidl/android/hardware/light/HwLight.aidl
+++ b/light/aidl/android/hardware/light/HwLight.aidl
@@ -22,7 +22,7 @@
* A description of a single light. Multiple lights can map to the same physical
* LED. Separate physical LEDs are always represented by separate instances.
*/
-@VintfStability
+@RustDerive(Clone=true, Copy=true) @VintfStability
parcelable HwLight {
/**
* Integer ID used for controlling this light
diff --git a/light/aidl/android/hardware/light/HwLightState.aidl b/light/aidl/android/hardware/light/HwLightState.aidl
index 24d3250..3ba6c78 100644
--- a/light/aidl/android/hardware/light/HwLightState.aidl
+++ b/light/aidl/android/hardware/light/HwLightState.aidl
@@ -25,7 +25,7 @@
* Not all lights must support all parameters. If you
* can do something backward-compatible, do it.
*/
-@VintfStability
+@RustDerive(Clone=true, Copy=true) @VintfStability
parcelable HwLightState {
/**
* The color of the LED in ARGB.
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/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..8e013e0 100644
--- a/media/bufferpool/aidl/Android.bp
+++ b/media/bufferpool/aidl/Android.bp
@@ -46,6 +46,9 @@
],
min_sdk_version: "29",
},
+ rust: {
+ enabled: true,
+ },
},
versions_with_info: [
{
diff --git a/staging/c2/aidl/Android.bp b/media/c2/aidl/Android.bp
similarity index 67%
rename from staging/c2/aidl/Android.bp
rename to media/c2/aidl/Android.bp
index b9da7ad..3c0915d 100644
--- a/staging/c2/aidl/Android.bp
+++ b/media/c2/aidl/Android.bp
@@ -11,17 +11,18 @@
aidl_interface {
name: "android.hardware.media.c2",
+ min_sdk_version: "30",
vendor_available: true,
double_loadable: true,
- unstable: true,
srcs: ["android/hardware/media/c2/*.aidl"],
- include_dirs: [
- "frameworks/native/aidl/gui",
+ headers: [
+ "HardwareBuffer_aidl",
],
imports: [
"android.hardware.common-V2",
"android.hardware.media.bufferpool2-V1",
],
+ stability: "vintf",
backend: {
cpp: {
enabled: false,
@@ -31,9 +32,21 @@
},
ndk: {
enabled: true,
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media.swcodec",
+ "test_com.android.media.swcodec",
+ ],
additional_shared_libraries: [
"libnativewindow",
],
},
+ rust: {
+ min_sdk_version: "31",
+ enabled: true,
+ additional_rustlibs: [
+ "libnativewindow_rs",
+ ],
+ },
},
}
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..7d58340
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IComponent.aidl
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible 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();
+ parcelable BlockPool {
+ long blockPoolId;
+ android.hardware.media.c2.IConfigurable configurable;
+ }
+ parcelable C2AidlGbAllocator {
+ android.hardware.media.c2.IGraphicBufferAllocator igba;
+ ParcelFileDescriptor waitableFd;
+ }
+ union BlockPoolAllocator {
+ int allocatorId;
+ android.hardware.media.c2.IComponent.C2AidlGbAllocator allocator;
+ }
+}
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..d1b5915
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IComponentStore.aidl
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.media.c2;
+@VintfStability
+interface IComponentStore {
+ void copyBuffer(in android.hardware.media.c2.Buffer src, in android.hardware.media.c2.Buffer dst);
+ android.hardware.media.c2.IComponent createComponent(in String name, in android.hardware.media.c2.IComponentListener listener, in android.hardware.media.bufferpool2.IClientManager pool);
+ android.hardware.media.c2.IComponentInterface createInterface(in String name);
+ android.hardware.media.c2.IConfigurable getConfigurable();
+ android.hardware.media.bufferpool2.IClientManager getPoolClientManager();
+ android.hardware.media.c2.StructDescriptor[] getStructDescriptors(in int[] indices);
+ android.hardware.media.c2.IComponentStore.ComponentTraits[] listComponents();
+ @VintfStability
+ parcelable ComponentTraits {
+ String name;
+ android.hardware.media.c2.IComponentStore.ComponentTraits.Domain domain;
+ android.hardware.media.c2.IComponentStore.ComponentTraits.Kind kind;
+ int rank;
+ String mediaType;
+ String[] aliases;
+ @Backing(type="int") @VintfStability
+ enum Kind {
+ OTHER = 0,
+ DECODER,
+ 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..32f5abd
--- /dev/null
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IConfigurable.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.media.c2;
+@VintfStability
+interface IConfigurable {
+ android.hardware.media.c2.IConfigurable.ConfigResult config(in android.hardware.media.c2.Params inParams, in boolean mayBlock);
+ int getId();
+ String getName();
+ android.hardware.media.c2.Params query(in int[] indices, in boolean mayBlock);
+ android.hardware.media.c2.ParamDescriptor[] querySupportedParams(in int start, in int count);
+ android.hardware.media.c2.FieldSupportedValuesQueryResult[] querySupportedValues(in android.hardware.media.c2.FieldSupportedValuesQuery[] inFields, in boolean mayBlock);
+ @VintfStability
+ parcelable ConfigResult {
+ android.hardware.media.c2.Params params;
+ android.hardware.media.c2.SettingResult[] failures;
+ }
+}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/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/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/staging/c2/aidl/android/hardware/media/c2/BaseBlock.aidl b/media/c2/aidl/android/hardware/media/c2/BaseBlock.aidl
similarity index 87%
rename from staging/c2/aidl/android/hardware/media/c2/BaseBlock.aidl
rename to media/c2/aidl/android/hardware/media/c2/BaseBlock.aidl
index 16e7653..7cc041c 100644
--- a/staging/c2/aidl/android/hardware/media/c2/BaseBlock.aidl
+++ b/media/c2/aidl/android/hardware/media/c2/BaseBlock.aidl
@@ -16,6 +16,7 @@
package android.hardware.media.c2;
+import android.hardware.HardwareBuffer;
import android.hardware.common.NativeHandle;
/**
@@ -25,12 +26,17 @@
* 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/staging/c2/aidl/android/hardware/media/c2/Block.aidl b/media/c2/aidl/android/hardware/media/c2/Block.aidl
similarity index 98%
rename from staging/c2/aidl/android/hardware/media/c2/Block.aidl
rename to media/c2/aidl/android/hardware/media/c2/Block.aidl
index 4da8490..34aa7b1 100644
--- a/staging/c2/aidl/android/hardware/media/c2/Block.aidl
+++ b/media/c2/aidl/android/hardware/media/c2/Block.aidl
@@ -26,6 +26,7 @@
* 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
diff --git a/staging/c2/aidl/android/hardware/media/c2/Buffer.aidl b/media/c2/aidl/android/hardware/media/c2/Buffer.aidl
similarity index 98%
rename from staging/c2/aidl/android/hardware/media/c2/Buffer.aidl
rename to media/c2/aidl/android/hardware/media/c2/Buffer.aidl
index fe01b64..d2dcf2d 100644
--- a/staging/c2/aidl/android/hardware/media/c2/Buffer.aidl
+++ b/media/c2/aidl/android/hardware/media/c2/Buffer.aidl
@@ -24,6 +24,7 @@
*
* This is a part of @ref FrameData.
*/
+@VintfStability
parcelable Buffer {
/**
* Metadata associated with the buffer.
diff --git a/staging/c2/aidl/android/hardware/media/c2/FieldDescriptor.aidl b/media/c2/aidl/android/hardware/media/c2/FieldDescriptor.aidl
similarity index 97%
rename from staging/c2/aidl/android/hardware/media/c2/FieldDescriptor.aidl
rename to media/c2/aidl/android/hardware/media/c2/FieldDescriptor.aidl
index 3dd14cd..a2774ec 100644
--- a/staging/c2/aidl/android/hardware/media/c2/FieldDescriptor.aidl
+++ b/media/c2/aidl/android/hardware/media/c2/FieldDescriptor.aidl
@@ -21,10 +21,12 @@
/**
* 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,
@@ -53,6 +55,7 @@
* 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
diff --git a/staging/c2/aidl/android/hardware/media/c2/FieldId.aidl b/media/c2/aidl/android/hardware/media/c2/FieldId.aidl
similarity index 98%
rename from staging/c2/aidl/android/hardware/media/c2/FieldId.aidl
rename to media/c2/aidl/android/hardware/media/c2/FieldId.aidl
index c53f7a5..68bf058 100644
--- a/staging/c2/aidl/android/hardware/media/c2/FieldId.aidl
+++ b/media/c2/aidl/android/hardware/media/c2/FieldId.aidl
@@ -22,6 +22,7 @@
* Within a given C2Param structure, each field is uniquely identified by @ref
* FieldId.
*/
+@VintfStability
parcelable FieldId {
/**
* Offset of the field in bytes.
diff --git a/staging/c2/aidl/android/hardware/media/c2/FieldSupportedValues.aidl b/media/c2/aidl/android/hardware/media/c2/FieldSupportedValues.aidl
similarity index 98%
rename from staging/c2/aidl/android/hardware/media/c2/FieldSupportedValues.aidl
rename to media/c2/aidl/android/hardware/media/c2/FieldSupportedValues.aidl
index 5f4ad2a..6c2033b 100644
--- a/staging/c2/aidl/android/hardware/media/c2/FieldSupportedValues.aidl
+++ b/media/c2/aidl/android/hardware/media/c2/FieldSupportedValues.aidl
@@ -26,6 +26,7 @@
* The intended type of values must be made clear in the context where
* `FieldSupportedValues` is used.
*/
+@VintfStability
union FieldSupportedValues {
/**
* No supported values
diff --git a/staging/c2/aidl/android/hardware/media/c2/FieldSupportedValuesQuery.aidl b/media/c2/aidl/android/hardware/media/c2/FieldSupportedValuesQuery.aidl
similarity index 97%
rename from staging/c2/aidl/android/hardware/media/c2/FieldSupportedValuesQuery.aidl
rename to media/c2/aidl/android/hardware/media/c2/FieldSupportedValuesQuery.aidl
index 33a8170..bdaaef6 100644
--- a/staging/c2/aidl/android/hardware/media/c2/FieldSupportedValuesQuery.aidl
+++ b/media/c2/aidl/android/hardware/media/c2/FieldSupportedValuesQuery.aidl
@@ -22,7 +22,9 @@
* 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 {
/**
diff --git a/staging/c2/aidl/android/hardware/media/c2/FieldSupportedValuesQueryResult.aidl b/media/c2/aidl/android/hardware/media/c2/FieldSupportedValuesQueryResult.aidl
similarity index 98%
rename from staging/c2/aidl/android/hardware/media/c2/FieldSupportedValuesQueryResult.aidl
rename to media/c2/aidl/android/hardware/media/c2/FieldSupportedValuesQueryResult.aidl
index 133712a..b5c28c6 100644
--- a/staging/c2/aidl/android/hardware/media/c2/FieldSupportedValuesQueryResult.aidl
+++ b/media/c2/aidl/android/hardware/media/c2/FieldSupportedValuesQueryResult.aidl
@@ -23,6 +23,7 @@
* This structure is used to hold the result from
* IConfigurable::querySupportedValues().
*/
+@VintfStability
parcelable FieldSupportedValuesQueryResult {
/**
* Result of the query. Possible values are
diff --git a/staging/c2/aidl/android/hardware/media/c2/FrameData.aidl b/media/c2/aidl/android/hardware/media/c2/FrameData.aidl
similarity index 99%
rename from staging/c2/aidl/android/hardware/media/c2/FrameData.aidl
rename to media/c2/aidl/android/hardware/media/c2/FrameData.aidl
index 81c76be..15c1b6d 100644
--- a/staging/c2/aidl/android/hardware/media/c2/FrameData.aidl
+++ b/media/c2/aidl/android/hardware/media/c2/FrameData.aidl
@@ -31,6 +31,7 @@
* @note `FrameData` is the HIDL counterpart of `C2FrameData` in the Codec 2.0
* standard.
*/
+@VintfStability
parcelable FrameData {
/** List of frame flags */
/**
diff --git a/staging/c2/aidl/android/hardware/media/c2/IComponent.aidl b/media/c2/aidl/android/hardware/media/c2/IComponent.aidl
similarity index 92%
rename from staging/c2/aidl/android/hardware/media/c2/IComponent.aidl
rename to media/c2/aidl/android/hardware/media/c2/IComponent.aidl
index bea4b70..e96cae5 100644
--- a/staging/c2/aidl/android/hardware/media/c2/IComponent.aidl
+++ b/media/c2/aidl/android/hardware/media/c2/IComponent.aidl
@@ -17,12 +17,12 @@
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.IGraphicBufferAllocator;
import android.hardware.media.c2.WorkBundle;
-import android.hardware.media.c2.SurfaceSyncObj;
+import android.os.ParcelFileDescriptor;
+
/**
* Interface for an AIDL Codec2 component.
@@ -32,6 +32,7 @@
* 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.
@@ -44,6 +45,30 @@
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 C2AidlGbAllocator {
+ IGraphicBufferAllocator igba;
+ ParcelFileDescriptor waitableFd;
+ }
+
+ /**
+ * Allocator for C2BlockPool.
+ *
+ * C2BlockPool will use a C2Allocator which is specified by an id.
+ * or C2AIDL allocator interface directly.
+ */
+ union BlockPoolAllocator {
+ int allocatorId;
+ C2AidlGbAllocator allocator;
+ }
+
/**
* Configures a component for a tunneled playback mode.
*
@@ -87,7 +112,8 @@
* destroyBlockPool(), reset() or release(). reset() and release() must
* destroy all `C2BlockPool` objects that have been created.
*
- * @param allocatorId Id of a `C2Allocator`.
+ * @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
@@ -98,7 +124,7 @@
* - `Status::TIMED_OUT` - The operation cannot be finished in a timely manner.
* - `Status::CORRUPTED` - Some unknown error occurred.
*/
- BlockPool createBlockPool(in int allocatorId);
+ BlockPool createBlockPool(in BlockPoolAllocator allocator);
/**
* Destroys a local block pool previously created by createBlockPool().
@@ -233,25 +259,6 @@
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.
diff --git a/staging/c2/aidl/android/hardware/media/c2/IComponentInterface.aidl b/media/c2/aidl/android/hardware/media/c2/IComponentInterface.aidl
similarity index 98%
rename from staging/c2/aidl/android/hardware/media/c2/IComponentInterface.aidl
rename to media/c2/aidl/android/hardware/media/c2/IComponentInterface.aidl
index 4589115..9db81e6 100644
--- a/staging/c2/aidl/android/hardware/media/c2/IComponentInterface.aidl
+++ b/media/c2/aidl/android/hardware/media/c2/IComponentInterface.aidl
@@ -26,6 +26,7 @@
*
* An actual component exposes this interface via IComponent::getInterface().
*/
+@VintfStability
interface IComponentInterface {
/**
* Returns the @ref IConfigurable instance associated to this component
diff --git a/staging/c2/aidl/android/hardware/media/c2/IComponentListener.aidl b/media/c2/aidl/android/hardware/media/c2/IComponentListener.aidl
similarity index 98%
rename from staging/c2/aidl/android/hardware/media/c2/IComponentListener.aidl
rename to media/c2/aidl/android/hardware/media/c2/IComponentListener.aidl
index 786c8f1..75500b7 100644
--- a/staging/c2/aidl/android/hardware/media/c2/IComponentListener.aidl
+++ b/media/c2/aidl/android/hardware/media/c2/IComponentListener.aidl
@@ -23,11 +23,13 @@
/**
* 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`
@@ -43,6 +45,7 @@
/**
* Information about rendering of a frame to a `Surface`.
*/
+ @VintfStability
parcelable RenderedFrame {
/**
* Id of the `BufferQueue` containing the rendered buffer.
diff --git a/staging/c2/aidl/android/hardware/media/c2/IComponentStore.aidl b/media/c2/aidl/android/hardware/media/c2/IComponentStore.aidl
similarity index 98%
rename from staging/c2/aidl/android/hardware/media/c2/IComponentStore.aidl
rename to media/c2/aidl/android/hardware/media/c2/IComponentStore.aidl
index d332bd3..1435a7e 100644
--- a/staging/c2/aidl/android/hardware/media/c2/IComponentStore.aidl
+++ b/media/c2/aidl/android/hardware/media/c2/IComponentStore.aidl
@@ -34,17 +34,21 @@
* @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,
diff --git a/staging/c2/aidl/android/hardware/media/c2/IConfigurable.aidl b/media/c2/aidl/android/hardware/media/c2/IConfigurable.aidl
similarity index 99%
rename from staging/c2/aidl/android/hardware/media/c2/IConfigurable.aidl
rename to media/c2/aidl/android/hardware/media/c2/IConfigurable.aidl
index 9f79576..7fdb825 100644
--- a/staging/c2/aidl/android/hardware/media/c2/IConfigurable.aidl
+++ b/media/c2/aidl/android/hardware/media/c2/IConfigurable.aidl
@@ -28,6 +28,7 @@
* 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.
@@ -35,6 +36,7 @@
* This includes the successful config settings along with the failure reasons of
* the specified setting.
*/
+ @VintfStability
parcelable ConfigResult {
Params params;
SettingResult[] failures;
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/staging/c2/aidl/android/hardware/media/c2/InfoBuffer.aidl b/media/c2/aidl/android/hardware/media/c2/InfoBuffer.aidl
similarity index 98%
rename from staging/c2/aidl/android/hardware/media/c2/InfoBuffer.aidl
rename to media/c2/aidl/android/hardware/media/c2/InfoBuffer.aidl
index 7cfabcb..207c4d0 100644
--- a/staging/c2/aidl/android/hardware/media/c2/InfoBuffer.aidl
+++ b/media/c2/aidl/android/hardware/media/c2/InfoBuffer.aidl
@@ -23,6 +23,7 @@
*
* This is a part of @ref FrameData.
*/
+@VintfStability
parcelable InfoBuffer {
/**
* A C2Param structure index.
diff --git a/staging/c2/aidl/android/hardware/media/c2/ParamDescriptor.aidl b/media/c2/aidl/android/hardware/media/c2/ParamDescriptor.aidl
similarity index 98%
rename from staging/c2/aidl/android/hardware/media/c2/ParamDescriptor.aidl
rename to media/c2/aidl/android/hardware/media/c2/ParamDescriptor.aidl
index 716c07e..84c6acc 100644
--- a/staging/c2/aidl/android/hardware/media/c2/ParamDescriptor.aidl
+++ b/media/c2/aidl/android/hardware/media/c2/ParamDescriptor.aidl
@@ -21,6 +21,7 @@
*
* @ref ParamDescriptor is returned by IConfigurable::querySupportedParams().
*/
+@VintfStability
parcelable ParamDescriptor {
/** The list of bit flags for attrib */
/**
diff --git a/staging/c2/aidl/android/hardware/media/c2/ParamField.aidl b/media/c2/aidl/android/hardware/media/c2/ParamField.aidl
similarity index 98%
rename from staging/c2/aidl/android/hardware/media/c2/ParamField.aidl
rename to media/c2/aidl/android/hardware/media/c2/ParamField.aidl
index 94f737d..64a46bb 100644
--- a/staging/c2/aidl/android/hardware/media/c2/ParamField.aidl
+++ b/media/c2/aidl/android/hardware/media/c2/ParamField.aidl
@@ -21,6 +21,7 @@
/**
* Reference to a field in a C2Param structure.
*/
+@VintfStability
parcelable ParamField {
/**
* Index of the C2Param structure.
diff --git a/staging/c2/aidl/android/hardware/media/c2/ParamFieldValues.aidl b/media/c2/aidl/android/hardware/media/c2/ParamFieldValues.aidl
similarity index 98%
rename from staging/c2/aidl/android/hardware/media/c2/ParamFieldValues.aidl
rename to media/c2/aidl/android/hardware/media/c2/ParamFieldValues.aidl
index 4bb9a91..7b74c0e 100644
--- a/staging/c2/aidl/android/hardware/media/c2/ParamFieldValues.aidl
+++ b/media/c2/aidl/android/hardware/media/c2/ParamFieldValues.aidl
@@ -26,6 +26,7 @@
* values object. This structure is used when reporting parameter configuration
* failures and conflicts.
*/
+@VintfStability
parcelable ParamFieldValues {
/**
* Reference to a field or a C2Param structure.
diff --git a/staging/c2/aidl/android/hardware/media/c2/Params.aidl b/media/c2/aidl/android/hardware/media/c2/Params.aidl
similarity index 98%
rename from staging/c2/aidl/android/hardware/media/c2/Params.aidl
rename to media/c2/aidl/android/hardware/media/c2/Params.aidl
index 3c1a321..53b512c 100644
--- a/staging/c2/aidl/android/hardware/media/c2/Params.aidl
+++ b/media/c2/aidl/android/hardware/media/c2/Params.aidl
@@ -30,6 +30,7 @@
* - 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/staging/c2/aidl/android/hardware/media/c2/SettingResult.aidl b/media/c2/aidl/android/hardware/media/c2/SettingResult.aidl
similarity index 98%
rename from staging/c2/aidl/android/hardware/media/c2/SettingResult.aidl
rename to media/c2/aidl/android/hardware/media/c2/SettingResult.aidl
index a270146..c2b9574 100644
--- a/staging/c2/aidl/android/hardware/media/c2/SettingResult.aidl
+++ b/media/c2/aidl/android/hardware/media/c2/SettingResult.aidl
@@ -22,10 +22,12 @@
* Information describing the reason the parameter settings may fail, or may be
* overridden.
*/
+@VintfStability
parcelable SettingResult {
/**
* Failure code
*/
+ @VintfStability
@Backing(type="int")
enum Failure {
/**
diff --git a/staging/c2/aidl/android/hardware/media/c2/Status.aidl b/media/c2/aidl/android/hardware/media/c2/Status.aidl
similarity index 98%
rename from staging/c2/aidl/android/hardware/media/c2/Status.aidl
rename to media/c2/aidl/android/hardware/media/c2/Status.aidl
index 660db57..58a2404 100644
--- a/staging/c2/aidl/android/hardware/media/c2/Status.aidl
+++ b/media/c2/aidl/android/hardware/media/c2/Status.aidl
@@ -19,6 +19,7 @@
/**
* Common return values for Codec2 operations.
*/
+@VintfStability
parcelable Status {
/**
* Operation completed successfully.
diff --git a/staging/c2/aidl/android/hardware/media/c2/StructDescriptor.aidl b/media/c2/aidl/android/hardware/media/c2/StructDescriptor.aidl
similarity index 98%
rename from staging/c2/aidl/android/hardware/media/c2/StructDescriptor.aidl
rename to media/c2/aidl/android/hardware/media/c2/StructDescriptor.aidl
index 5d6d2eb..00359041 100644
--- a/staging/c2/aidl/android/hardware/media/c2/StructDescriptor.aidl
+++ b/media/c2/aidl/android/hardware/media/c2/StructDescriptor.aidl
@@ -22,6 +22,7 @@
* Description of a C2Param structure. It consists of an index and a list of
* `FieldDescriptor`s.
*/
+@VintfStability
parcelable StructDescriptor {
/**
* Index of the structure.
diff --git a/staging/c2/aidl/android/hardware/media/c2/ValueRange.aidl b/media/c2/aidl/android/hardware/media/c2/ValueRange.aidl
similarity index 98%
rename from staging/c2/aidl/android/hardware/media/c2/ValueRange.aidl
rename to media/c2/aidl/android/hardware/media/c2/ValueRange.aidl
index 6707a25..9abcb7d 100644
--- a/staging/c2/aidl/android/hardware/media/c2/ValueRange.aidl
+++ b/media/c2/aidl/android/hardware/media/c2/ValueRange.aidl
@@ -38,6 +38,7 @@
* 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).
diff --git a/staging/c2/aidl/android/hardware/media/c2/Work.aidl b/media/c2/aidl/android/hardware/media/c2/Work.aidl
similarity index 99%
rename from staging/c2/aidl/android/hardware/media/c2/Work.aidl
rename to media/c2/aidl/android/hardware/media/c2/Work.aidl
index 0732479..4b8d696 100644
--- a/staging/c2/aidl/android/hardware/media/c2/Work.aidl
+++ b/media/c2/aidl/android/hardware/media/c2/Work.aidl
@@ -34,6 +34,7 @@
*
* `Work` is a part of @ref WorkBundle.
*/
+@VintfStability
parcelable Work {
/**
* Additional work chain info not part of this work.
diff --git a/staging/c2/aidl/android/hardware/media/c2/WorkBundle.aidl b/media/c2/aidl/android/hardware/media/c2/WorkBundle.aidl
similarity index 98%
rename from staging/c2/aidl/android/hardware/media/c2/WorkBundle.aidl
rename to media/c2/aidl/android/hardware/media/c2/WorkBundle.aidl
index 79b4cdb..2125fda 100644
--- a/staging/c2/aidl/android/hardware/media/c2/WorkBundle.aidl
+++ b/media/c2/aidl/android/hardware/media/c2/WorkBundle.aidl
@@ -35,6 +35,7 @@
* 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.
diff --git a/staging/c2/aidl/android/hardware/media/c2/WorkOrdinal.aidl b/media/c2/aidl/android/hardware/media/c2/WorkOrdinal.aidl
similarity index 98%
rename from staging/c2/aidl/android/hardware/media/c2/WorkOrdinal.aidl
rename to media/c2/aidl/android/hardware/media/c2/WorkOrdinal.aidl
index eb8b244..5708a90 100644
--- a/staging/c2/aidl/android/hardware/media/c2/WorkOrdinal.aidl
+++ b/media/c2/aidl/android/hardware/media/c2/WorkOrdinal.aidl
@@ -31,6 +31,7 @@
* @note `WorkOrdinal` is the HIDL counterpart of `C2WorkOrdinalStruct` in the
* Codec 2.0 standard.
*/
+@VintfStability
parcelable WorkOrdinal {
/**
* Timestamp in microseconds.
diff --git a/staging/c2/aidl/android/hardware/media/c2/Worklet.aidl b/media/c2/aidl/android/hardware/media/c2/Worklet.aidl
similarity index 98%
rename from staging/c2/aidl/android/hardware/media/c2/Worklet.aidl
rename to media/c2/aidl/android/hardware/media/c2/Worklet.aidl
index 04c59c1..6b3ceac 100644
--- a/staging/c2/aidl/android/hardware/media/c2/Worklet.aidl
+++ b/media/c2/aidl/android/hardware/media/c2/Worklet.aidl
@@ -28,6 +28,7 @@
* a @ref Work object for each expected output before calling
* IComponent::queue().
*/
+@VintfStability
parcelable Worklet {
/**
* Component id. (Input)
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/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/authsecret/1.0/vts/functional/OWNERS b/oemlock/OWNERS
similarity index 98%
copy from authsecret/1.0/vts/functional/OWNERS
copy to oemlock/OWNERS
index ec8c304..5a5d074 100644
--- a/authsecret/1.0/vts/functional/OWNERS
+++ b/oemlock/OWNERS
@@ -1,3 +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/default/Android.bp b/power/aidl/default/Android.bp
index da91ee6..64766fc 100644
--- a/power/aidl/default/Android.bp
+++ b/power/aidl/default/Android.bp
@@ -39,9 +39,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/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/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/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/1.0/vts/OWNERS b/radio/OWNERS
similarity index 63%
rename from radio/1.0/vts/OWNERS
rename to radio/OWNERS
index 117692a..8107287 100644
--- a/radio/1.0/vts/OWNERS
+++ b/radio/OWNERS
@@ -1,5 +1,5 @@
# Bug component: 20868
-jminjie@google.com
-sarahchin@google.com
-shuoq@google.com
+
jackyu@google.com
+sarahchin@google.com
+jayachandranc@google.com
\ No newline at end of file
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/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/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/OWNERS
similarity index 84%
rename from renderscript/1.0/vts/functional/OWNERS
rename to renderscript/OWNERS
index d785790..443ebff 100644
--- a/renderscript/1.0/vts/functional/OWNERS
+++ b/renderscript/OWNERS
@@ -1,6 +1,6 @@
# Bug component: 43047
+
butlermichael@google.com
dgross@google.com
-jeanluc@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/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/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
+– whether KeyMint instance or authenticator – 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..3de5617
--- /dev/null
+++ b/security/authgraph/aidl/android/hardware/security/authgraph/ExplicitKeyDiceCertChain.cddl
@@ -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.
+;
+ExplicitKeyDiceCertChain = [
+ 1, ; version, hopefully will never change
+ DiceCertChainInitialPayload,
+ * DiceChainEntry
+]
+
+DiceCertChainInitialPayload = {
+ -4670552 : 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..1f851b2
--- /dev/null
+++ b/security/authgraph/default/src/lib.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.
+ */
+
+//! 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 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> = in_rx.recv().expect("failed to receive next req");
+ let rsp_data = ta.process(&req_data);
+ out_tx.send(rsp_data).expect("failed to send out rsp");
+ }
+ });
+ 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..7ccd246 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.).
@@ -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..d4adab5 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__) {
@@ -8719,6 +8833,19 @@
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];
+ aidl::android::hardware::security::keymint::test::KeyMintAidlTestBase::
+ expect_upgrade =
+ arg == "yes"
+ ? true
+ : (arg == "no" ? false : std::optional<bool>(std::nullopt));
+ ++i;
+ }
}
}
return RUN_ALL_TESTS();
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..2180d0f 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 RPK 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.
\ No newline at end of file
diff --git a/security/rkp/aidl/Android.bp b/security/rkp/aidl/Android.bp
index e2ce649..e9e2021 100644
--- a/security/rkp/aidl/Android.bp
+++ b/security/rkp/aidl/Android.bp
@@ -28,6 +28,10 @@
},
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/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
index 62463eb..a1de93e 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);
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..87d0233
--- /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[] 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..49c3446
--- /dev/null
+++ b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/ISecretkeeper.aidl
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.
+ */
+ 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 a key exchange protocol, which
+ * is critical for establishing the secure channel.
+ *
+ * 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/staging/c2/aidl/android/hardware/media/c2/ParamField.aidl b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/SecretId.aidl
similarity index 62%
copy from staging/c2/aidl/android/hardware/media/c2/ParamField.aidl
copy to security/secretkeeper/aidl/android/hardware/security/secretkeeper/SecretId.aidl
index 94f737d..bd982e7 100644
--- a/staging/c2/aidl/android/hardware/media/c2/ParamField.aidl
+++ b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/SecretId.aidl
@@ -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.
@@ -14,20 +14,16 @@
* limitations under the License.
*/
-package android.hardware.media.c2;
-
-import android.hardware.media.c2.FieldId;
+package android.hardware.security.secretkeeper;
/**
- * Reference to a field in a C2Param structure.
+ * SecretId contains an identifier for a secret held by Secretkeeper.
+ * @hide
*/
-parcelable ParamField {
+@VintfStability
+parcelable SecretId {
/**
- * Index of the C2Param structure.
+ * 64-byte identifier for a secret.
*/
- int index;
- /**
- * Identifier of the field inside the C2Param structure.
- */
- FieldId fieldId;
+ byte[] 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..3d08078
--- /dev/null
+++ b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/SecretManagement.cddl
@@ -0,0 +1,102 @@
+; 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`.
+ProtectedRequestPacket = CryptoPayload<RequestPacket, KeySourceToSink>
+
+CryptoPayload<Payload, Key> = [ ; 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 empty 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.
+
+; 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>
+
+; 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.
+ 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 = (version : uint)
+
+StoreSecretResult = ()
+
+GetSecretResult = (secret : Secret)
diff --git a/security/secretkeeper/aidl/vts/Android.bp b/security/secretkeeper/aidl/vts/Android.bp
new file mode 100644
index 0000000..c130a3a
--- /dev/null
+++ b/security/secretkeeper/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: ["Android-Apache-2.0"],
+}
+
+rust_test {
+ name: "VtsSecretkeeperTargetTest",
+ srcs: ["secretkeeper_test_client.rs"],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+ rustlibs: [
+ "libsecretkeeper_comm_nostd",
+ "libsecretkeeper_core_nostd",
+ "android.hardware.security.secretkeeper-V1-rust",
+ "libauthgraph_boringssl",
+ "libauthgraph_core",
+ "libcoset",
+ "libauthgraph_vts_test",
+ "libbinder_rs",
+ "libcoset",
+ "liblog_rust",
+ ],
+ require_root: true,
+}
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..b5cca27
--- /dev/null
+++ b/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs
@@ -0,0 +1,493 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#[cfg(test)]
+use binder::StatusCode;
+use coset::{CborSerializable, CoseEncrypt0};
+use log::warn;
+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, ID_SIZE, Secret, SECRET_SIZE};
+use secretkeeper_comm::data_types::response::Response;
+use secretkeeper_comm::data_types::packet::{ResponsePacket, ResponseType};
+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;
+
+const SECRETKEEPER_IDENTIFIER: &str =
+ "android.hardware.security.secretkeeper.ISecretkeeper/nonsecure";
+const CURRENT_VERSION: u64 = 1;
+
+// TODO(b/291238565): This will change once libdice_policy switches to Explicit-key DiceCertChain
+// This is generated by patching libdice_policy such that it dumps an example dice chain &
+// a policy, such that the former matches the latter.
+const HYPOTHETICAL_DICE_POLICY: [u8; 43] = [
+ 0x83, 0x01, 0x81, 0x83, 0x01, 0x80, 0xA1, 0x01, 0x00, 0x82, 0x83, 0x01, 0x81, 0x01, 0x73, 0x74,
+ 0x65, 0x73, 0x74, 0x69, 0x6E, 0x67, 0x5F, 0x64, 0x69, 0x63, 0x65, 0x5F, 0x70, 0x6F, 0x6C, 0x69,
+ 0x63, 0x79, 0x83, 0x02, 0x82, 0x03, 0x18, 0x64, 0x19, 0xE9, 0x75,
+];
+
+// Random bytes (of ID_SIZE/SECRET_SIZE) generated for tests.
+const ID_EXAMPLE: [u8; ID_SIZE] = [
+ 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: [u8; ID_SIZE] = [
+ 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: [u8; ID_SIZE] = [
+ 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: [u8; SECRET_SIZE] = [
+ 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_connection() -> Option<binder::Strong<dyn ISecretkeeper>> {
+ match binder::get_interface(SECRETKEEPER_IDENTIFIER) {
+ Ok(sk) => Some(sk),
+ Err(StatusCode::NAME_NOT_FOUND) => None,
+ Err(e) => {
+ panic!(
+ "unexpected error while fetching connection to Secretkeeper {:?}",
+ e
+ );
+ }
+ }
+}
+
+/// Secretkeeper client information.
+struct SkClient {
+ sk: binder::Strong<dyn ISecretkeeper>,
+ aes_keys: [key::AesKey; 2],
+ session_id: Vec<u8>,
+}
+
+impl SkClient {
+ fn new() -> Option<Self> {
+ let sk = get_connection()?;
+ let (aes_keys, session_id) = authgraph_key_exchange(sk.clone());
+ Some(Self {
+ sk,
+ aes_keys,
+ session_id,
+ })
+ }
+ /// Wrapper around `ISecretkeeper::processSecretManagementRequest` that handles
+ /// encryption and decryption.
+ fn secret_management_request(&self, req_data: &[u8]) -> Vec<u8> {
+ let aes_gcm = boring::BoringAes;
+ let rng = boring::BoringRng;
+ let request_bytes = cipher::encrypt_message(
+ &aes_gcm,
+ &rng,
+ &self.aes_keys[0],
+ &self.session_id,
+ &req_data,
+ )
+ .unwrap();
+
+ let response_bytes = self
+ .sk
+ .processSecretManagementRequest(&request_bytes)
+ .unwrap();
+
+ let response_encrypt0 = CoseEncrypt0::from_slice(&response_bytes).unwrap();
+ cipher::decrypt_message(&aes_gcm, &self.aes_keys[1], &response_encrypt0).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.
+#[test]
+fn authgraph_mainline() {
+ let sk = match get_connection() {
+ Some(sk) => sk,
+ None => {
+ warn!("Secretkeeper HAL is unavailable, skipping test");
+ return;
+ }
+ };
+ let (_aes_keys, _session_id) = authgraph_key_exchange(sk);
+}
+
+/// Test that the AuthGraph instance returned by SecretKeeper correctly rejects
+/// a corrupted session ID signature.
+#[test]
+fn authgraph_corrupt_sig() {
+ let sk = match get_connection() {
+ Some(sk) => sk,
+ None => {
+ warn!("Secretkeeper HAL is unavailable, skipping test");
+ return;
+ }
+ };
+ 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.
+#[test]
+fn authgraph_corrupt_keys() {
+ let sk = match get_connection() {
+ Some(sk) => sk,
+ None => {
+ warn!("Secretkeeper HAL is unavailable, skipping test");
+ return;
+ }
+ };
+ 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.
+
+#[test]
+fn secret_management_get_version() {
+ let sk_client = match SkClient::new() {
+ Some(sk) => sk,
+ None => {
+ warn!("Secretkeeper HAL is unavailable, skipping test");
+ return;
+ }
+ };
+
+ 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);
+
+ 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);
+}
+
+#[test]
+fn secret_management_malformed_request() {
+ let sk_client = match SkClient::new() {
+ Some(sk) => sk,
+ None => {
+ warn!("Secretkeeper HAL is unavailable, skipping test");
+ return;
+ }
+ };
+
+ 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);
+
+ 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);
+}
+
+#[test]
+fn secret_management_store_get_secret_found() {
+ let sk_client = match SkClient::new() {
+ Some(sk) => sk,
+ None => {
+ warn!("Secretkeeper HAL is unavailable, skipping test");
+ return;
+ }
+ };
+
+ let store_request = StoreSecretRequest {
+ id: Id(ID_EXAMPLE),
+ secret: Secret(SECRET_EXAMPLE),
+ sealing_policy: HYPOTHETICAL_DICE_POLICY.to_vec(),
+ };
+
+ let store_request = store_request.serialize_to_packet().to_vec().unwrap();
+
+ let store_response = sk_client.secret_management_request(&store_request);
+ let store_response = ResponsePacket::from_slice(&store_response).unwrap();
+
+ assert_eq!(
+ store_response.response_type().unwrap(),
+ ResponseType::Success
+ );
+ // Really just checking that the response is indeed StoreSecretResponse
+ let _ = StoreSecretResponse::deserialize_from_packet(store_response).unwrap();
+
+ // Get the secret that was just stored
+ let get_request = GetSecretRequest {
+ id: Id(ID_EXAMPLE),
+ updated_sealing_policy: None,
+ };
+ let get_request = get_request.serialize_to_packet().to_vec().unwrap();
+
+ let get_response = sk_client.secret_management_request(&get_request);
+ let get_response = ResponsePacket::from_slice(&get_response).unwrap();
+ assert_eq!(get_response.response_type().unwrap(), ResponseType::Success);
+ let get_response = *GetSecretResponse::deserialize_from_packet(get_response).unwrap();
+ assert_eq!(get_response.secret.0, SECRET_EXAMPLE);
+}
+
+#[test]
+fn secret_management_store_get_secret_not_found() {
+ let sk_client = match SkClient::new() {
+ Some(sk) => sk,
+ None => {
+ warn!("Secretkeeper HAL is unavailable, skipping test");
+ return;
+ }
+ };
+
+ // Store a secret (corresponding to an id).
+ let store_request = StoreSecretRequest {
+ id: Id(ID_EXAMPLE),
+ secret: Secret(SECRET_EXAMPLE),
+ sealing_policy: HYPOTHETICAL_DICE_POLICY.to_vec(),
+ };
+
+ let store_request = store_request.serialize_to_packet().to_vec().unwrap();
+ let store_response = sk_client.secret_management_request(&store_request);
+ let store_response = ResponsePacket::from_slice(&store_response).unwrap();
+
+ assert_eq!(
+ store_response.response_type().unwrap(),
+ ResponseType::Success
+ );
+ // Really just checking that the response is indeed StoreSecretResponse
+ let _ = StoreSecretResponse::deserialize_from_packet(store_response).unwrap();
+
+ // Get the secret that was never stored
+ let get_request = GetSecretRequest {
+ id: Id(ID_NOT_STORED),
+ updated_sealing_policy: None,
+ };
+ let get_request = get_request.serialize_to_packet().to_vec().unwrap();
+
+ let get_response = sk_client.secret_management_request(&get_request);
+
+ // Expect the entry not to be found.
+ let get_response = ResponsePacket::from_slice(&get_response).unwrap();
+ assert_eq!(get_response.response_type().unwrap(), ResponseType::Error);
+ let err = *SecretkeeperError::deserialize_from_packet(get_response).unwrap();
+ assert_eq!(err, SecretkeeperError::EntryNotFound);
+}
+
+#[test]
+fn secretkeeper_store_delete_ids() {
+ let sk_client = match SkClient::new() {
+ Some(sk) => sk,
+ None => {
+ warn!("Secretkeeper HAL is unavailable, skipping test");
+ return;
+ }
+ };
+
+ let store_request = StoreSecretRequest {
+ id: Id(ID_EXAMPLE),
+ secret: Secret(SECRET_EXAMPLE),
+ sealing_policy: HYPOTHETICAL_DICE_POLICY.to_vec(),
+ };
+
+ let store_request = store_request.serialize_to_packet().to_vec().unwrap();
+ let store_response = sk_client.secret_management_request(&store_request);
+ let store_response = ResponsePacket::from_slice(&store_response).unwrap();
+
+ assert_eq!(
+ store_response.response_type().unwrap(),
+ ResponseType::Success
+ );
+ // Really just checking that the response is indeed StoreSecretResponse
+ let _ = StoreSecretResponse::deserialize_from_packet(store_response).unwrap();
+
+ sk_client
+ .sk
+ .deleteIds(&[SecretId {
+ id: ID_EXAMPLE.to_vec(),
+ }])
+ .unwrap();
+
+ // Try to get the secret that was just stored & deleted
+ let get_request = GetSecretRequest {
+ id: Id(ID_EXAMPLE),
+ updated_sealing_policy: None,
+ };
+ let get_request = get_request.serialize_to_packet().to_vec().unwrap();
+
+ let get_response = sk_client.secret_management_request(&get_request);
+
+ // Expect the entry not to be found.
+ let get_response = ResponsePacket::from_slice(&get_response).unwrap();
+ assert_eq!(get_response.response_type().unwrap(), ResponseType::Error);
+ let err = *SecretkeeperError::deserialize_from_packet(get_response).unwrap();
+ assert_eq!(err, SecretkeeperError::EntryNotFound);
+}
+
+#[test]
+fn secretkeeper_store_delete_all() {
+ let sk_client = match SkClient::new() {
+ Some(sk) => sk,
+ None => {
+ warn!("Secretkeeper HAL is unavailable, skipping test");
+ return;
+ }
+ };
+
+ let store_request = StoreSecretRequest {
+ id: Id(ID_EXAMPLE),
+ secret: Secret(SECRET_EXAMPLE),
+ sealing_policy: HYPOTHETICAL_DICE_POLICY.to_vec(),
+ };
+
+ let store_request = store_request.serialize_to_packet().to_vec().unwrap();
+ let store_response = sk_client.secret_management_request(&store_request);
+ let store_response = ResponsePacket::from_slice(&store_response).unwrap();
+
+ assert_eq!(
+ store_response.response_type().unwrap(),
+ ResponseType::Success
+ );
+ // Really just checking that the response is indeed StoreSecretResponse
+ let _ = StoreSecretResponse::deserialize_from_packet(store_response).unwrap();
+
+ let store_request = StoreSecretRequest {
+ id: Id(ID_EXAMPLE_2),
+ secret: Secret(SECRET_EXAMPLE),
+ sealing_policy: HYPOTHETICAL_DICE_POLICY.to_vec(),
+ };
+
+ let store_request = store_request.serialize_to_packet().to_vec().unwrap();
+ let store_response = sk_client.secret_management_request(&store_request);
+ let store_response = ResponsePacket::from_slice(&store_response).unwrap();
+
+ assert_eq!(
+ store_response.response_type().unwrap(),
+ ResponseType::Success
+ );
+ // Really just checking that the response is indeed StoreSecretResponse
+ let _ = StoreSecretResponse::deserialize_from_packet(store_response).unwrap();
+
+ sk_client.sk.deleteAll().unwrap();
+
+ // Get the first secret that was just stored before deleteAll
+ let get_request = GetSecretRequest {
+ id: Id(ID_EXAMPLE),
+ updated_sealing_policy: None,
+ };
+ let get_request = get_request.serialize_to_packet().to_vec().unwrap();
+
+ let get_response = sk_client.secret_management_request(&get_request);
+
+ // Expect the entry not to be found.
+ let get_response = ResponsePacket::from_slice(&get_response).unwrap();
+ assert_eq!(get_response.response_type().unwrap(), ResponseType::Error);
+ let err = *SecretkeeperError::deserialize_from_packet(get_response).unwrap();
+ assert_eq!(err, SecretkeeperError::EntryNotFound);
+
+ // Get the second secret that was just stored before deleteAll
+ let get_request = GetSecretRequest {
+ id: Id(ID_EXAMPLE_2),
+ updated_sealing_policy: None,
+ };
+ let get_request = get_request.serialize_to_packet().to_vec().unwrap();
+
+ let get_response = sk_client.secret_management_request(&get_request);
+
+ // Expect the entry not to be found.
+ let get_response = ResponsePacket::from_slice(&get_response).unwrap();
+ assert_eq!(get_response.response_type().unwrap(), ResponseType::Error);
+ let err = *SecretkeeperError::deserialize_from_packet(get_response).unwrap();
+ assert_eq!(err, SecretkeeperError::EntryNotFound);
+
+ // Store a new secret (corresponding to an id).
+ let store_request = StoreSecretRequest {
+ id: Id(ID_EXAMPLE),
+ secret: Secret(SECRET_EXAMPLE),
+ sealing_policy: HYPOTHETICAL_DICE_POLICY.to_vec(),
+ };
+
+ let store_request = store_request.serialize_to_packet().to_vec().unwrap();
+ let store_response = sk_client.secret_management_request(&store_request);
+ let store_response = ResponsePacket::from_slice(&store_response).unwrap();
+
+ assert_eq!(
+ store_response.response_type().unwrap(),
+ ResponseType::Success
+ );
+
+ // Get the restored secret.
+ let get_request = GetSecretRequest {
+ id: Id(ID_EXAMPLE),
+ updated_sealing_policy: None,
+ };
+ let get_request = get_request.serialize_to_packet().to_vec().unwrap();
+
+ let get_response = sk_client.secret_management_request(&get_request);
+ let get_response = ResponsePacket::from_slice(&get_response).unwrap();
+
+ // Get the secret that was just re-stored.
+ assert_eq!(get_response.response_type().unwrap(), ResponseType::Success);
+ let get_response = *GetSecretResponse::deserialize_from_packet(get_response).unwrap();
+ assert_eq!(get_response.secret.0, SECRET_EXAMPLE);
+
+ // (Try to) Get the secret that was never stored
+ let get_request = GetSecretRequest {
+ id: Id(ID_NOT_STORED),
+ updated_sealing_policy: None,
+ };
+ let get_request = get_request.serialize_to_packet().to_vec().unwrap();
+ let get_response = sk_client.secret_management_request(&get_request);
+
+ // Check that response is `SecretkeeperError::EntryNotFound`
+ let get_response = ResponsePacket::from_slice(&get_response).unwrap();
+ assert_eq!(get_response.response_type().unwrap(), ResponseType::Error);
+ let err = *SecretkeeperError::deserialize_from_packet(get_response).unwrap();
+ assert_eq!(err, SecretkeeperError::EntryNotFound);
+}
diff --git a/security/secretkeeper/default/Android.bp b/security/secretkeeper/default/Android.bp
new file mode 100644
index 0000000..08cc67a
--- /dev/null
+++ b/security/secretkeeper/default/Android.bp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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_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",
+ "libauthgraph_boringssl",
+ "libauthgraph_core",
+ "libauthgraph_hal",
+ "libbinder_rs",
+ "liblog_rust",
+ "libsecretkeeper_comm_nostd",
+ "libsecretkeeper_core_nostd",
+ "libsecretkeeper_hal",
+ ],
+ srcs: [
+ "src/main.rs",
+ ],
+}
+
+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/main.rs b/security/secretkeeper/default/src/main.rs
new file mode 100644
index 0000000..c8c1521
--- /dev/null
+++ b/security/secretkeeper/default/src/main.rs
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.
+mod store;
+
+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, info, Level};
+use secretkeeper_core::ta::SecretkeeperTa;
+use secretkeeper_hal::SecretkeeperService;
+use std::sync::Arc;
+use std::sync::Mutex;
+use store::InMemoryStore;
+
+use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper::ISecretkeeper::{
+ BpSecretkeeper, ISecretkeeper,
+};
+use std::cell::RefCell;
+use std::rc::Rc;
+use std::sync::mpsc;
+
+/// 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(InMemoryStore::default());
+ let sk_ta = Rc::new(RefCell::new(
+ SecretkeeperTa::new(&mut crypto_impls, storage_impl)
+ .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> = in_rx.recv().expect("failed to receive next req");
+ 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}!"),
+ };
+ out_tx.send(rsp_data).expect("failed to send out rsp");
+ }
+ });
+ 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(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(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))
+ }
+}
+
+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..a7fb3b7
--- /dev/null
+++ b/security/secretkeeper/default/src/store.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.
+ */
+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` & 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/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/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/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/utils/GrallocWrapper.cpp b/sensors/common/vts/utils/GrallocWrapper.cpp
index e6e0888..a15e7fe 100644
--- a/sensors/common/vts/utils/GrallocWrapper.cpp
+++ b/sensors/common/vts/utils/GrallocWrapper.cpp
@@ -124,7 +124,8 @@
private:
static constexpr uint64_t kBufferUsage =
- static_cast<uint64_t>(BufferUsage::SENSOR_DIRECT_DATA | BufferUsage::CPU_READ_OFTEN);
+ static_cast<uint64_t>(BufferUsage::SENSOR_DIRECT_DATA | BufferUsage::CPU_READ_OFTEN |
+ BufferUsage::CPU_WRITE_RARELY);
AllocatorWrapperT<AllocatorT> mAllocator;
sp<MapperT> mMapper;
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/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/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/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/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/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/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/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/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/default/Android.bp b/thermal/aidl/default/Android.bp
index 49a578b..451e1e2 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: [
- "libbase",
- "libbinder_ndk",
+ stl: "c++_static",
+ static_libs: [
"android.hardware.thermal-V1-ndk",
+ "libbase",
+ ],
+ shared_libs: [
+ "libbinder_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/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/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/staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl b/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl
similarity index 87%
rename from staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl
rename to threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl
index 3c57149..e695623 100644
--- a/staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl
+++ b/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl
@@ -22,6 +22,7 @@
* Controls a Thread radio chip on the device.
*/
+@VintfStability
interface IThreadChip {
/**
* The operation failed for the internal error.
@@ -43,10 +44,10 @@
* 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.
+ * @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.
@@ -55,18 +56,18 @@
/**
* 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.
+ * 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 reset();
+ void hardwareReset();
/**
* This method sends a spinel frame to the Thread HAL.
diff --git a/staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChipCallback.aidl b/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChipCallback.aidl
similarity index 98%
rename from staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChipCallback.aidl
rename to threadnetwork/aidl/android/hardware/threadnetwork/IThreadChipCallback.aidl
index a0fe88c..046edc3 100644
--- a/staging/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChipCallback.aidl
+++ b/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChipCallback.aidl
@@ -16,6 +16,7 @@
package android.hardware.threadnetwork;
+@VintfStability
interface IThreadChipCallback {
/**
* This method is called when a spinel frame is received. Thread network
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/staging/threadnetwork/aidl/default/service.cpp b/threadnetwork/aidl/default/service.cpp
similarity index 75%
rename from staging/threadnetwork/aidl/default/service.cpp
rename to threadnetwork/aidl/default/service.cpp
index 8047214..7f583f4 100644
--- a/staging/threadnetwork/aidl/default/service.cpp
+++ b/threadnetwork/aidl/default/service.cpp
@@ -20,38 +20,24 @@
#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);
+Service::Service(void) : mBinderFd(-1) {
+ binder_status_t status = ABinderProcess_setupPolling(&mBinderFd);
CHECK_EQ(status, ::STATUS_OK);
- CHECK_GE(fd, 0);
- mBinderFd.reset(fd);
+ CHECK_GE(mBinderFd, 0);
}
void Service::Update(otSysMainloopContext& context) {
- FD_SET(mBinderFd.get(), &context.mReadFdSet);
- context.mMaxFd = std::max(context.mMaxFd, mBinderFd.get());
+ FD_SET(mBinderFd, &context.mReadFdSet);
+ context.mMaxFd = std::max(context.mMaxFd, mBinderFd);
}
void Service::Process(const otSysMainloopContext& context) {
- if (FD_ISSET(mBinderFd.get(), &context.mReadFdSet)) {
+ if (FD_ISSET(mBinderFd, &context.mReadFdSet)) {
ABinderProcess_handlePolledCommands();
}
}
diff --git a/staging/threadnetwork/aidl/default/service.hpp b/threadnetwork/aidl/default/service.hpp
similarity index 83%
rename from staging/threadnetwork/aidl/default/service.hpp
rename to threadnetwork/aidl/default/service.hpp
index 6e6e868..6a94791 100644
--- a/staging/threadnetwork/aidl/default/service.hpp
+++ b/threadnetwork/aidl/default/service.hpp
@@ -14,10 +14,7 @@
* limitations under the License.
*/
-#include <android-base/unique_fd.h>
-
#include "mainloop.hpp"
-#include "thread_chip.hpp"
namespace aidl {
namespace android {
@@ -26,15 +23,14 @@
class Service : public ot::Posix::Mainloop::Source {
public:
- Service(char* urls[], int numUrls);
+ Service(void);
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;
+ int mBinderFd;
};
} // namespace threadnetwork
} // namespace hardware
diff --git a/staging/threadnetwork/aidl/default/thread_chip.cpp b/threadnetwork/aidl/default/thread_chip.cpp
similarity index 68%
rename from staging/threadnetwork/aidl/default/thread_chip.cpp
rename to threadnetwork/aidl/default/thread_chip.cpp
index 38abad4..ed34e63 100644
--- a/staging/threadnetwork/aidl/default/thread_chip.cpp
+++ b/threadnetwork/aidl/default/thread_chip.cpp
@@ -23,56 +23,57 @@
#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 {
-static ndk::ScopedAStatus errorStatus(int32_t error, const char* message) {
- return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(error, message));
-}
+ThreadChip::ThreadChip(char* url) : mUrl(), mRxFrameBuffer(), mCallback(nullptr) {
+ const char* interfaceName;
-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);
+
+ 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::onBinderDied));
- AIBinder_DeathRecipient_setOnUnlinked(mDeathRecipient.get(), ThreadChip::onBinderUnlinked);
+ AIBinder_DeathRecipient_new(ThreadChip::onBinderDiedJump));
+ AIBinder_DeathRecipient_setOnUnlinked(mDeathRecipient.get(), ThreadChip::onBinderUnlinkedJump);
}
-ThreadChip::~ThreadChip() {
- AIBinder_DeathRecipient_delete(mDeathRecipient.get());
-}
-
-void ThreadChip::onBinderDied(void* context) {
+void ThreadChip::onBinderDiedJump(void* context) {
reinterpret_cast<ThreadChip*>(context)->onBinderDied();
}
void ThreadChip::onBinderDied(void) {
- ALOGW("Thread Network HAL client is dead.");
+ ALOGW("Thread Network HAL client is dead");
}
-void ThreadChip::onBinderUnlinked(void* context) {
+void ThreadChip::onBinderUnlinkedJump(void* context) {
reinterpret_cast<ThreadChip*>(context)->onBinderUnlinked();
}
void ThreadChip::onBinderUnlinked(void) {
- ALOGW("ThreadChip binder is unlinked.");
+ ALOGW("ThreadChip binder is unlinked");
deinitChip();
}
-void ThreadChip::handleReceivedFrame(void* context) {
- reinterpret_cast<ThreadChip*>(context)->handleReceivedFrame();
+void ThreadChip::handleReceivedFrameJump(void* context) {
+ static_cast<ThreadChip*>(context)->handleReceivedFrame();
}
void ThreadChip::handleReceivedFrame(void) {
@@ -89,9 +90,9 @@
if (status.isOk()) {
AIBinder_linkToDeath(in_callback->asBinder().get(), mDeathRecipient.get(), this);
- ALOGI("Open IThreadChip successfully.");
+ ALOGI("Open IThreadChip successfully");
} else {
- ALOGW("Open IThreadChip failed, error: %s", status.getDescription().c_str());
+ ALOGW("Failed to open IThreadChip: %s", status.getDescription().c_str());
}
return status;
@@ -101,7 +102,8 @@
if (in_callback == nullptr) {
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
} else if (mCallback == nullptr) {
- if (mInterface.Init(mUrl) != OT_ERROR_NONE) {
+ if (mSpinelInterface->Init(handleReceivedFrameJump, this, mRxFrameBuffer) !=
+ OT_ERROR_NONE) {
return errorStatus(ERROR_FAILED, "Failed to initialize the interface");
}
@@ -109,7 +111,7 @@
ot::Posix::Mainloop::Manager::Get().Add(*this);
return ndk::ScopedAStatus::ok();
} else {
- return errorStatus(ERROR_BUSY, "Interface is already opened");
+ return errorStatus(ERROR_BUSY, "Interface has been opened");
}
}
@@ -125,7 +127,7 @@
ALOGI("Close IThreadChip successfully");
} else {
- ALOGW("Close IThreadChip failed, error: %s", status.getDescription().c_str());
+ ALOGW("Failed to close IThreadChip: %s", status.getDescription().c_str());
}
return status;
@@ -133,7 +135,7 @@
ndk::ScopedAStatus ThreadChip::deinitChip() {
if (mCallback != nullptr) {
- mInterface.Deinit();
+ mSpinelInterface->Deinit();
ot::Posix::Mainloop::Manager::Get().Remove(*this);
mCallback = nullptr;
return ndk::ScopedAStatus::ok();
@@ -149,8 +151,8 @@
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());
+ 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) {
@@ -169,28 +171,30 @@
return status;
}
-ndk::ScopedAStatus ThreadChip::reset() {
- mInterface.OnRcpReset();
+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) {
- mInterface.UpdateFdSet(context.mReadFdSet, context.mWriteFdSet, context.mMaxFd,
- context.mTimeout);
+ mSpinelInterface->UpdateFdSet(&context);
}
}
void ThreadChip::Process(const otSysMainloopContext& context) {
- struct RadioProcessContext radioContext;
-
if (mCallback != nullptr) {
- radioContext.mReadFdSet = &context.mReadFdSet;
- radioContext.mWriteFdSet = &context.mWriteFdSet;
- mInterface.Process(radioContext);
+ 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
diff --git a/staging/threadnetwork/aidl/default/thread_chip.hpp b/threadnetwork/aidl/default/thread_chip.hpp
similarity index 82%
rename from staging/threadnetwork/aidl/default/thread_chip.hpp
rename to threadnetwork/aidl/default/thread_chip.hpp
index da5cba7..30046ef 100644
--- a/staging/threadnetwork/aidl/default/thread_chip.hpp
+++ b/threadnetwork/aidl/default/thread_chip.hpp
@@ -19,8 +19,8 @@
#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 "lib/url/url.hpp"
#include "mainloop.hpp"
#include <android/binder_auto_utils.h>
@@ -34,29 +34,29 @@
class ThreadChip : public BnThreadChip, ot::Posix::Mainloop::Source {
public:
- ThreadChip(uint8_t id, char* url);
- ~ThreadChip();
+ 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 reset() override;
+ ndk::ScopedAStatus hardwareReset() override;
void Update(otSysMainloopContext& context) override;
void Process(const otSysMainloopContext& context) override;
private:
- static void onBinderDied(void* context);
+ static void onBinderDiedJump(void* context);
void onBinderDied(void);
- static void onBinderUnlinked(void* context);
+ static void onBinderUnlinkedJump(void* context);
void onBinderUnlinked(void);
- static void handleReceivedFrame(void* context);
+ 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;
- ot::Posix::HdlcInterface mInterface;
+ std::shared_ptr<ot::Spinel::SpinelInterface> mSpinelInterface;
ot::Spinel::SpinelInterface::RxFrameBuffer mRxFrameBuffer;
std::shared_ptr<IThreadChipCallback> mCallback;
::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
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/staging/threadnetwork/aidl/vts/Android.bp b/threadnetwork/aidl/vts/Android.bp
similarity index 71%
rename from staging/threadnetwork/aidl/vts/Android.bp
rename to threadnetwork/aidl/vts/Android.bp
index e2609ed..864e885 100644
--- a/staging/threadnetwork/aidl/vts/Android.bp
+++ b/threadnetwork/aidl/vts/Android.bp
@@ -14,15 +14,6 @@
// 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: [
@@ -38,7 +29,7 @@
"libbinder_ndk",
],
static_libs: [
- "android.hardware.threadnetwork-ndk",
+ "android.hardware.threadnetwork-V1-ndk",
],
test_suites: [
"general-tests",
diff --git a/staging/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp b/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp
similarity index 95%
rename from staging/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp
rename to threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp
index 3e43f9c..5925b54 100644
--- a/staging/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp
+++ b/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp
@@ -76,7 +76,6 @@
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) {
@@ -85,7 +84,6 @@
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) {
@@ -93,7 +91,7 @@
ndk::SharedRefBase::make<ThreadChipCallback>([](auto /* data */) {});
EXPECT_TRUE(thread_chip->open(callback).isOk());
- EXPECT_TRUE(thread_chip->reset().isOk());
+ EXPECT_TRUE(thread_chip->hardwareReset().isOk());
}
TEST_P(ThreadNetworkAidl, SendSpinelFrame) {
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/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/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/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/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/default/Android.bp b/usb/aidl/default/Android.bp
index 472e732..2c6ed07 100644
--- a/usb/aidl/default/Android.bp
+++ b/usb/aidl/default/Android.bp
@@ -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/apex/Android.bp b/usb/aidl/default/apex/Android.bp
similarity index 70%
rename from usb/apex/Android.bp
rename to usb/aidl/default/apex/Android.bp
index 765aa21..29278dd 100644
--- a/usb/apex/Android.bp
+++ b/usb/aidl/default/apex/Android.bp
@@ -16,33 +16,22 @@
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",
+ key: "com.android.hardware.key",
+ certificate: ":com.android.hardware.certificate",
updatable: false,
- soc_specific: true,
- use_vndk_as_stable: true,
+ 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",
],
- vintf_fragments: [":android.hardware.usb-service.example.xml"],
}
// Replace the binary path from /vendor/bin to /apex/{name}/bin in the init .rc file
@@ -50,7 +39,7 @@
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)",
+ cmd: "sed -E 's@/vendor/bin@/apex/com.android.hardware.usb/bin@' $(in) > $(out)",
}
prebuilt_etc {
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/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..21951b6 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,25 @@
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,
+ 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..2141b5a 100644
--- a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
@@ -149,6 +149,21 @@
*/
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,
+
+ /*********************************************
+ * 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..d749147 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,78 @@
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();
+ 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 +124,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 +238,22 @@
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 { ref mut serial, .. } = *state {
+ 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)?;
+ }
+ 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/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/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/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/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